rpms/ejabberd/devel ejabberd.init, NONE, 1.1 ejabberd.logrotate, NONE, 1.1 ejabberd.spec, NONE, 1.1 ejabberd_auth_ad.erl, NONE, 1.1 inetrc, NONE, 1.1 mod_ctlextra.erl, NONE, 1.1 mod_shared_roster_ad.erl, NONE, 1.1 mod_vcard_ad.erl, NONE, 1.1 .cvsignore, 1.1, 1.2 sources, 1.1, 1.2
Jeffrey C. Ollie (jcollie)
fedora-extras-commits at redhat.com
Fri Jun 23 12:40:03 UTC 2006
Author: jcollie
Update of /cvs/extras/rpms/ejabberd/devel
In directory cvs-int.fedora.redhat.com:/tmp/cvs-serv24618/devel
Modified Files:
.cvsignore sources
Added Files:
ejabberd.init ejabberd.logrotate ejabberd.spec
ejabberd_auth_ad.erl inetrc mod_ctlextra.erl
mod_shared_roster_ad.erl mod_vcard_ad.erl
Log Message:
auto-import ejabberd-1.1.1-7.fc5 on branch devel from ejabberd-1.1.1-7.fc5.src.rpm
--- NEW FILE ejabberd.init ---
#!/bin/bash
#
# ejabberd Starts, Stops and Reloads ejabberd.
#
# chkconfig: - 40 60
# description: ejabberd
# processname: ejabberd
# pidfile: /var/run/ejabberd.pid
. /etc/rc.d/init.d/functions
start() {
echo -n $"Starting ejabberd: "
daemon --user=ejabberd --check=ejabberd \
"erl" "-pa @libdir@/ejabberd- at version@/ebin \
-sname ejabberd \
-s ejabberd \
-ejabberd config \\\"/etc/ejabberd/ejabberd.cfg\\\" \
log_path \\\"/var/log/ejabberd/ejabberd.log\\\" \
-sasl sasl_error_logger \\{file,\\\"/var/log/ejabberd/sasl.log\\\"\\} \
-mnesia dir \\\"/var/lib/ejabberd/spool\\\" \
-kernel inetrc \\\"/etc/ejabberd/inetrc\\\" \
-detached"
RETVAL=$?
[ $RETVAL -eq 0 ] && touch /var/lock/subsys/ejabberd
echo
return $RETVAL
}
stop() {
# Stop daemons.
echo -n "Shutting down ejabberd: "
runuser -s /bin/bash - ejabberd -c "erl -pa @libdir@/ejabberd- at version@/ebin -noinput -sname ejabberdctl -s ejabberd_ctl -extra ejabberd@`hostname -s` stop" && success || failure
RETVAL=$?
[ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/ejabberd
echo
return $RETVAL
}
restart() {
stop
start
}
# See how we were called.
case "$1" in
start)
start
;;
stop)
stop
;;
restart)
restart
;;
condrestart)
[ -f /var/lock/subsys/ejabberd ] && restart || :
;;
status)
runuser -s /bin/bash - ejabberd -c "erl -pa @libdir@/ejabberd- at version@/ebin -noinput -sname ejabberdctl -s ejabberd_ctl -extra ejabberd@`hostname -s` status"
;;
*)
echo "Usage: ejabberd {start|stop|restart|reload|condrestart|status}"
exit 1
esac
exit $?
--- NEW FILE ejabberd.logrotate ---
/var/log/ejabberd/ejabberd.log /var/log/ejabberd/sasl.log {
missingok
notifempty
create 0640 ejabberd ejabberd
sharedscripts
postrotate
runuser -s /bin/bash - ejabberd -c "erl -pa @libdir@/ejabberd- at version@/ebin -noinput -sname ejabberdctl -s ejabberd_ctl -extra ejabberd@`hostname -s` reopen-log >/dev/null 2>/dev/null || true
endscript
}
--- NEW FILE ejabberd.spec ---
Name: ejabberd
Version: 1.1.1
Release: 7%{?dist}
Summary: A distributed, fault-tolerant Jabber/XMPP server
Group: Applications/Internet
License: GPL
URL: http://ejabberd.jabber.ru/
Source0: http://www.process-one.net/en/projects/ejabberd/download/%{version}/ejabberd-%{version}.tar.gz
Source1: ejabberd.init
Source2: ejabberd.logrotate
Source3: inetrc
# http://ejabberd.jabber.ru/ejabberdctl-extra
Source4: http://ejabberd.jabber.ru/files/efiles/mod_ctlextra.erl
# The following were extracted from a patch found on http://realloc.spb.ru/share/ejabberdad.html
Source5: ejabberd_auth_ad.erl
Source6: mod_shared_roster_ad.erl
Source7: mod_vcard_ad.erl
BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
BuildRequires: expat-devel
BuildRequires: openssl-devel
BuildRequires: erlang
BuildRequires: hevea
Requires: erlang
Requires(pre): fedora-usermgmt
Requires(post): /sbin/chkconfig
Requires(preun): /sbin/chkconfig
Requires(preun): /sbin/service
Requires(postun): /sbin/service
%description
ejabberd is a Free and Open Source distributed fault-tolerant
Jabber/XMPP server. It is mostly written in Erlang, and runs on many
platforms (tested on Linux, FreeBSD, NetBSD, Solaris, Mac OS X and
Windows NT/2000/XP).
%package doc
Summary: Documentation for ejabberd
Group: Documentation
%description doc
Documentation for ejabberd.
%pre
/usr/sbin/fedora-groupadd 27 -r ejabberd &>/dev/null || :
/usr/sbin/fedora-useradd 27 -r -s /sbin/nologin -d /var/lib/ejabberd -M \
-c 'ejabberd' -g ejabberd ejabberd &>/dev/null || :
%post
/sbin/chkconfig --add ejabberd
%preun
if [ $1 = 0 ]; then
/sbin/service ejabberd stop >/dev/null 2>&1
/sbin/chkconfig --del ejabberd
fi
%postun
if [ "$1" -ge "1" ]; then
/sbin/service ejabberd condrestart >/dev/null 2>&1
fi
%prep
%setup -q
%{__perl} -pi -e "s!/var/lib/ejabberd!%{_libdir}/ejabberd-%{version}!g" src/Makefile.in
%{__perl} -pi -e "s!/etc!%{_sysconfdir}!g" src/Makefile.in
%{__perl} -pi -e "s!\@prefix\@!!g" src/Makefile.in
cp %{S:4} src
cp %{S:5} src
cp %{S:6} src
cp %{S:7} src
%build
pushd src
%configure --enable-odbc
make %{?_smp_mflags}
popd
pushd doc
make html pdf
popd
%install
rm -rf %{buildroot}
pushd src
make install DESTDIR=%{buildroot}
popd
chmod a+x %{buildroot}%{_libdir}/ejabberd-%{version}/priv/lib/*.so
%{__perl} -pi -e 's!./ssl.pem!/etc/ejabberd/ejabberd.pem!g' %{buildroot}/etc/ejabberd/ejabberd.cfg
mkdir -p %{buildroot}/var/log/ejabberd
mkdir -p %{buildroot}/var/lib/ejabberd/spool
mkdir -p %{buildroot}%{_initrddir}
cp %{S:1} %{buildroot}%{_initrddir}/ejabberd
chmod a+x %{buildroot}%{_initrddir}/ejabberd
mkdir -p %{buildroot}%{_sysconfdir}/logrotate.d
cp %{S:2} %{buildroot}%{_sysconfdir}/logrotate.d/ejabberd
%{__perl} -pi -e 's!\@libdir\@!%{_libdir}!g' %{buildroot}%{_initrddir}/ejabberd %{buildroot}%{_sysconfdir}/logrotate.d/ejabberd
%{__perl} -pi -e 's!\@version\@!%{version}!g' %{buildroot}%{_initrddir}/ejabberd %{buildroot}%{_sysconfdir}/logrotate.d/ejabberd
cp %{S:3} %{buildroot}%{_sysconfdir}/ejabberd/inetrc
%clean
rm -rf %{buildroot}
%files
%defattr(-,root,root,-)
%doc COPYING
%attr(750,ejabberd,ejabberd) %dir %{_sysconfdir}/ejabberd
%attr(640,ejabberd,ejabberd) %config(noreplace) %{_sysconfdir}/ejabberd/ejabberd.cfg
%attr(640,ejabberd,ejabberd) %config(noreplace) %{_sysconfdir}/ejabberd/inetrc
%{_initrddir}/ejabberd
%config(noreplace) %{_sysconfdir}/logrotate.d/ejabberd
%dir %{_libdir}/ejabberd-%{version}
%dir %{_libdir}/ejabberd-%{version}/ebin
%{_libdir}/ejabberd-%{version}/ebin/*.app
%{_libdir}/ejabberd-%{version}/ebin/*.beam
%dir %{_libdir}/ejabberd-%{version}/priv
%dir %{_libdir}/ejabberd-%{version}/priv/lib
%{_libdir}/ejabberd-%{version}/priv/lib/*.so
%dir %{_libdir}/ejabberd-%{version}/priv/msgs
%{_libdir}/ejabberd-%{version}/priv/msgs/*.msg
%attr(750,ejabberd,ejabberd) %dir /var/lib/ejabberd
%attr(750,ejabberd,ejabberd) %dir /var/lib/ejabberd/spool
%attr(750,ejabberd,ejabberd) %dir /var/log/ejabberd
%files doc
%defattr(-,root,root,-)
%doc ChangeLog COPYING TODO doc/*.pdf doc/*.html doc/*.png doc/release_notes_*
%changelog
* Thu Jun 22 2006 Jeffrey C. Ollie <jeff at ocjtech.us> - 1.1.1-7
- Oops drop bad patch.
* Thu Jun 22 2006 Jeffrey C. Ollie <jeff at ocjtech.us> - 1.1.1-6
- Split documentation off to a subpackage.
- Own %{_libdir}/ejabberd-%{version}
- Mark %{_sysconfdir}/logrotate.d/ejabberd as %config
* Thu Jun 8 2006 Jeffrey C. Ollie <jeff at ocjtech.us> - 1.1.1-5
- Patch the makefile so that it adds a soname to shared libs.
* Fri May 26 2006 Jeffrey C. Ollie <jeff at ocjtech.us> - 1.1.1-4
- Modify AD modules not to check for group membership.
* Thu May 25 2006 Jeffrey C. Ollie <jeff at ocjtech.us> - 1.1.1-3
- Add some extra modules
* Wed May 24 2006 Jeffrey C. Ollie <jeff at ocjtech.us> - 1.1.1-2
- Munge Makefile.in a bit more...
- Change ownership/permissions - not *everything* needs to be owned by ejabberd
* Wed May 24 2006 Jeffrey C. Ollie <jeff at ocjtech.us> - 1.1.1-1
- First version for Fedora Extras
--- NEW FILE ejabberd_auth_ad.erl ---
%%%----------------------------------------------------------------------
%%% File : ejabberd_auth_ad.erl
%%% Author : Alexey Shchepin <alexey at sevcom.net>
%%% Author : Alex Gorbachenko <agent_007 at immo.ru>
%%% Author : Stanislav Bogatyrev <realloc at realloc.spb.ru>
%%% Purpose : Authentification via Active Directory
%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey at sevcom.net>
%%% Id : $Id: ejabberd_auth_ad.erl 386 2005-12-20 10:06:37Z agent_007 $
%%%----------------------------------------------------------------------
-module(ejabberd_auth_ad).
-author('alexey at sevcom.net').
-author('agent_007 at immo.ru').
-author('realloc at realloc.spb.ru').
-vsn('$Revision: 386 $ ').
%% External exports
-export([start/1,
set_password/3,
check_password/3,
check_password/5,
try_register/3,
dirty_get_registered_users/0,
get_vh_registered_users/1,
get_password/2,
get_password_s/2,
is_user_exists/2,
remove_user/2,
remove_user/3,
plain_password_required/0
]).
-include("ejabberd.hrl").
-include("eldap/eldap.hrl").
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
start(Host) ->
LDAPServers = ejabberd_config:get_local_option({ad_servers, Host}),
RootDN = ejabberd_config:get_local_option({ad_rootdn, Host}),
Password = ejabberd_config:get_local_option({ad_password, Host}),
eldap:start_link(get_eldap_id(Host, ejabberd),
LDAPServers, 389, RootDN, Password),
eldap:start_link(get_eldap_id(Host, ejabberd_bind),
LDAPServers, 389, RootDN, Password),
ok.
plain_password_required() ->
true.
check_password(User, Server, Password) ->
case find_user_dn(User, Server) of
false ->
false;
DN ->
LServer = jlib:nameprep(Server),
case eldap:bind(get_eldap_id(LServer, ejabberd_bind),
DN, Password) of
ok ->
true;
_ ->
false
end
end.
check_password(User, Server, Password, _StreamID, _Digest) ->
check_password(User, Server, Password).
set_password(_User, _Server, _Password) ->
{error, not_allowed}.
try_register(_User, _Server, _Password) ->
{error, not_allowed}.
dirty_get_registered_users() ->
get_vh_registered_users(?MYNAME).
get_vh_registered_users(Server) ->
LServer = jlib:nameprep(Server),
Attr = ejabberd_config:get_local_option({ad_uidattr, LServer}),
% AdGroup = ejabberd_config:get_local_option({ad_group, LServer}),
FilterPerson = eldap:equalityMatch("objectCategory", "person"),
FilterComp = eldap:equalityMatch("objectClass", "computer"),
FilterHidden = eldap:equalityMatch("description", "hidden"),
% FilterGroup = eldap:equalityMatch("memberOf", AdGroup),
FilterLive = eldap:equalityMatch("userAccountControl", "66050"),
FilterDef = eldap:present(Attr),
Filter = eldap:'and'([
FilterDef,
FilterPerson,
% FilterGroup,
eldap:'not'(FilterComp),
eldap:'not'(FilterHidden),
eldap:'not'(FilterLive)]),
Base = ejabberd_config:get_local_option({ad_base, LServer}),
case eldap:search(get_eldap_id(LServer, ejabberd),
[{base, Base},
{filter, Filter},
{attributes, [Attr]}]) of
#eldap_search_result{entries = Es} ->
lists:flatmap(
fun(E) ->
case lists:keysearch(Attr, 1, E#eldap_entry.attributes) of
{value, {_, [U]}} ->
case jlib:nodeprep(U) of
error ->
[];
LU ->
[{LU, LServer}]
end;
_ ->
[]
end
end, Es);
_ ->
[]
end.
get_password(_User, _Server) ->
false.
get_password_s(_User, _Server) ->
"".
is_user_exists(User, Server) ->
case find_user_dn(User, Server) of
false ->
false;
_DN ->
true
end.
remove_user(_User, _Server) ->
{error, not_allowed}.
remove_user(_User, _Server, _Password) ->
not_allowed.
%%%----------------------------------------------------------------------
%%% Internal functions
%%%----------------------------------------------------------------------
find_user_dn(User, Server) ->
LServer = jlib:nameprep(Server),
AdGroup = ejabberd_config:get_local_option({ad_group, LServer}),
Attr = ejabberd_config:get_local_option({ad_uidattr, LServer}),
FilterAttr = eldap:equalityMatch(Attr, User),
FilterGroup = eldap:equalityMatch("memberOf", AdGroup),
Filter = eldap:'and'([
FilterAttr,
FilterGroup
]),
Base = ejabberd_config:get_local_option({ad_base, LServer}),
case eldap:search(get_eldap_id(LServer, ejabberd),
[{base, Base},
{filter, Filter},
{attributes, []}]) of
#eldap_search_result{entries = [E | _]} ->
E#eldap_entry.object_name;
_ ->
false
end.
get_eldap_id(Host, Name) ->
atom_to_list(gen_mod:get_module_proc(Host, Name)).
--- NEW FILE inetrc ---
{file, resolv, "/etc/resolv.conf"}.
--- NEW FILE mod_ctlextra.erl ---
%%%----------------------------------------------------------------------
%%% File : mod_ctlextra.erl
%%% Author :
%%% Purpose : Adds more options for ejabberd_ctl
%%% Created :
%%% Id :
%%%----------------------------------------------------------------------
%%% mod_ctlextra v0.2.2 for ejabberd 1.1.1 (18/May/2006)
%%%
%%% INSTALL:
%%% 1. Copy mod_ctlextra.erl to your ejabberd/src
%%% 2. Add to your ejabberd.cfg, on the modules section:
%%% {mod_ctlextra, []},
%%% 3. Recompile and restart ejabberd
%%%
%%% USAGE:
%%% - Now you have several new options for ejabberd-ctl
%%% - Example for vcard: ejabberdctl eja at host vcard-get joe myjab.net email
%%% - The file used by 'pushroster' and 'pushroster-all' must be placed on
%%% the same directory where the .beam files are. Example content:
%%% [{"bob", "myserver", "workers", "Bob"},
%%% {"mart", "myserver", "workers", "Mart"},
%%% {"Rich", "myserver", "bosses", "Rich"}].
-module(mod_ctlextra).
-author('').
-vsn('Version 0.2.1').
-behaviour(gen_mod).
-export([
start/2,
stop/1,
ctl_process/2,
ctl_process/3
]).
-include("ejabberd_ctl.hrl").
-include("jlib.hrl").
start(Host, _Opts) ->
ejabberd_ctl:register_commands([
{"compile file", "recompile and reload file"},
{"load-config file", "load config from file"},
{"remove-node nodename", "remove an ejabberd node from the database"},
% ejabberd_auth
{"delete-older-users days", "delete users that have not logged in the last 'days'"},
{"set-password user server password", "set password to user at server"},
% ejd2odbc
{"export2odbc server output", "export all possible tables on server to output"},
% mod_offline
{"delete-older-messages days", "delete offline messages older than 'days'"},
% mod_shared_roster
{"srg-create group host name description display", "create the group with options"},
{"srg-delete group host", "delete the group"},
{"srg-user-add user server group host", "add user at server to group on host"},
{"srg-user-del user server group host", "delete user at server from group on host"},
% mod_vcard
{"vcard-get user host data [data2]", "get data from the vCard of the user"},
{"vcard-set user host data [data2] content", "set data to content on the vCard"},
% mod_announce
% announce_send_online host message
% announce_send_all host, message
% mod_muc
% muc-add room opts
% muc-del room
% muc-del-older 90 : delete rooms older than X days (with no activity (chat, presence, logins) in 6 months)
% mod_roster
{"add-rosteritem user1 server1 user2 server2 nick group subs", "Add user2 at server2 to user1 at server1"},
%{"", "subs= none, from, to or both"},
%{"", "example: add-roster peter localhost mike server.com MiKe Employees both"},
%{"", "will add mike at server.com to peter at localhost roster"},
{"pushroster file user server", "push template roster in file to user at server"},
{"pushroster-all file", "push template roster in file to all those users"},
{"push-alltoall server group", "adds all the users to all the users in Group"},
{"stats registeredusers", "number of registered users"},
{"stats onlineusers", "number of logged users"},
% misc
{"killsession user server resource", "kill a user session"}
], ?MODULE, ctl_process),
ejabberd_ctl:register_commands(Host, [
% mod_last
{"num-active-users days", "number of users active in the last 'days'"},
{"stats registeredusers", "number of registered users"},
{"stats onlineusers", "number of logged users"}
], ?MODULE, ctl_process),
ok.
stop(_Host) ->
ok.
ctl_process(_Val, ["blo"]) ->
FResources = "eeeaaa aaa",
io:format("~s", [FResources]),
?STATUS_SUCCESS;
ctl_process(_Val, ["delete-older-messages", Days]) ->
mod_offline:remove_old_messages(list_to_integer(Days)),
?STATUS_SUCCESS;
ctl_process(_Val, ["delete-older-users", Days]) ->
{removed, N, UR} = delete_older_users(list_to_integer(Days)),
io:format("Deleted ~p users: ~p~n", [N, UR]),
?STATUS_SUCCESS;
ctl_process(_Val, ["export2odbc", Server, Output1]) ->
Output = list_to_atom(Output1),
ejd2odbc:export_passwd(Server, Output),
ejd2odbc:export_roster(Server, Output),
ejd2odbc:export_offline(Server, Output),
ejd2odbc:export_last(Server, Output),
ejd2odbc:export_vcard(Server, Output),
ejd2odbc:export_vcard_search(Server, Output),
?STATUS_SUCCESS;
ctl_process(_Val, ["set-password", User, Server, Password]) ->
ejabberd_auth:set_password(User, Server, Password),
?STATUS_SUCCESS;
ctl_process(_Val, ["vcard-get", User, Server, Data]) ->
{ok, Res} = vcard_get(User, Server, {Data}),
io:format("~s~n", [Res]),
?STATUS_SUCCESS;
ctl_process(_Val, ["vcard-get", User, Server, Data1, Data2]) ->
{ok, Res} = vcard_get(User, Server, {Data1, Data2}),
io:format("~s~n", [Res]),
?STATUS_SUCCESS;
ctl_process(_Val, ["vcard-set", User, Server, Data, Content]) ->
{ok, Res} = vcard_set(User, Server, Data, Content),
io:format("~s~n", [Res]),
?STATUS_SUCCESS;
ctl_process(_Val, ["vcard-set", User, Server, Data1, Data2, Content]) ->
{ok, Res} = vcard_set(User, Server, Data1, Data2, Content),
io:format("~s~n", [Res]),
?STATUS_SUCCESS;
ctl_process(_Val, ["compile", Module]) ->
compile:file(Module),
?STATUS_SUCCESS;
ctl_process(_Val, ["remove-node", Node]) ->
mnesia:del_table_copy(schema, list_to_atom(Node)),
?STATUS_SUCCESS;
ctl_process(_Val, ["srg-create", Group, Host, Name, Description, Display]) ->
Opts = [{name, Name}, {displayed_groups, [Display]}, {description, Description}],
{atomic, ok} = mod_shared_roster:create_group(Host, Group, Opts),
?STATUS_SUCCESS;
ctl_process(_Val, ["srg-delete", Group, Host]) ->
{atomic, ok} = mod_shared_roster:delete_group(Host, Group),
?STATUS_SUCCESS;
ctl_process(_Val, ["srg-user-add", User, Server, Group, Host]) ->
{atomic, ok} = mod_shared_roster:add_user_to_group(Host, {User, Server}, Group),
?STATUS_SUCCESS;
ctl_process(_Val, ["srg-user-del", User, Server, Group, Host]) ->
{atomic, ok} = mod_shared_roster:remove_user_from_group(Host, {User, Server}, Group),
?STATUS_SUCCESS;
ctl_process(_Val, ["add-rosteritem", LocalUser, LocalServer, RemoteUser, RemoteServer, Nick, Group, Subs]) ->
case add_rosteritem(LocalUser, LocalServer, RemoteUser, RemoteServer, Nick, Group, list_to_atom(Subs), []) of
{atomic, ok} ->
?STATUS_SUCCESS;
{error, Reason} ->
io:format("Can't add ~p@~p to ~p@~p: ~p~n",
[RemoteUser, RemoteServer, LocalUser, LocalServer, Reason]),
?STATUS_ERROR;
{badrpc, Reason} ->
io:format("Can't add roster item to user ~p: ~p~n",
[LocalUser, Reason]),
?STATUS_BADRPC
end;
ctl_process(_Val, ["pushroster", File, User, Server]) ->
case pushroster(File, User, Server) of
ok ->
?STATUS_SUCCESS;
{error, Reason} ->
io:format("Can't push roster ~p to ~p@~p: ~p~n",
[File, User, Server, Reason]),
?STATUS_ERROR;
{badrpc, Reason} ->
io:format("Can't push roster ~p: ~p~n",
[File, Reason]),
?STATUS_BADRPC
end;
ctl_process(_Val, ["pushroster-all", File]) ->
case pushroster_all([File]) of
ok ->
?STATUS_SUCCESS;
{error, Reason} ->
io:format("Can't push roster ~p: ~p~n",
[File, Reason]),
?STATUS_ERROR;
{badrpc, Reason} ->
io:format("Can't push roster ~p: ~p~n",
[File, Reason]),
?STATUS_BADRPC
end;
ctl_process(_Val, ["push-alltoall", Server, Group]) ->
case push_alltoall(Server, Group) of
ok ->
?STATUS_SUCCESS;
{error, Reason} ->
io:format("Can't push all to all: ~p~n",
[Reason]),
?STATUS_ERROR;
{badrpc, Reason} ->
io:format("Can't push all to all: ~p~n",
[Reason]),
?STATUS_BADRPC
end;
ctl_process(_Val, ["load-config", Path]) ->
case ejabberd_config:load_file(Path) of
{atomic, ok} ->
?STATUS_SUCCESS;
{error, Reason} ->
io:format("Can't load config file ~p: ~p~n",
[filename:absname(Path), Reason]),
?STATUS_ERROR;
{badrpc, Reason} ->
io:format("Can't load config file ~p: ~p~n",
[filename:absname(Path), Reason]),
?STATUS_BADRPC
end;
ctl_process(_Val, ["stats", Stat]) ->
Res = case Stat of
"registeredusers" -> mnesia:table_info(passwd, size);
"onlineusers" -> mnesia:table_info(session, size)
end,
io:format("~p~n", [Res]),
?STATUS_SUCCESS;
ctl_process(_Val, ["killsession", User, Server, Resource]) ->
ejabberd_router:route(
jlib:make_jid("", "", ""),
jlib:make_jid(User, Server, Resource),
{xmlelement, "broadcast", [], [{exit, "killed"}]}),
?STATUS_SUCCESS;
ctl_process(Val, _Args) ->
Val.
ctl_process(_Val, Host, ["num-active-users", Days]) ->
Number = num_active_users(Host, list_to_integer(Days)),
io:format("~p~n", [Number]),
?STATUS_SUCCESS;
ctl_process(_Val, Host, ["stats", Stat]) ->
Res = case Stat of
"registeredusers" -> length(ejabberd_auth:get_vh_registered_users(Host));
"onlineusers" -> length(ejabberd_sm:get_vh_session_list(Host))
end,
io:format("~p~n", [Res]),
?STATUS_SUCCESS;
ctl_process(Val, _Host, _Args) ->
Val.
%%-------------
%% UTILS
%%-------------
add_rosteritem(LU, LS, RU, RS, Nick, Group, Subscription, Xattrs) ->
subscribe(LU, LS, RU, RS, Nick, Group, Subscription, Xattrs),
% TODO: if the server is not local and Subs=to or both: send subscription request
% TODO: check if the 'remote server' is a virtual host here, else do nothing
%add_rosteritem2(RU, RS, LU, LS, LU, "", invert_subs(Subscription), Xattrs, Host).
subscribe(RU, RS, LU, LS, LU, "", invert_subs(Subscription), Xattrs).
invert_subs(none) -> none;
invert_subs(to) -> none;
invert_subs(from) -> to;
invert_subs(both) -> both.
subscribe(LocalUser, LocalServer, RemoteUser, RemoteServer, Nick, Group, Subscription, Xattrs) ->
mnesia:transaction(
fun() ->
mnesia:write({
roster,
{LocalUser,LocalServer,{RemoteUser,RemoteServer,[]}}, % usj
{LocalUser,LocalServer}, % us
{RemoteUser,RemoteServer,[]}, % jid
Nick, % name: "Mom", []
Subscription, % subscription: none, to=you see him, from=he sees you, both
none, % ask: out=send request, in=somebody requests you, none
[Group], % groups: ["Family"]
Xattrs, % xattrs: [{"category","conference"}]
[] % xs: []
})
end).
pushroster(File, User, Server) ->
{ok, [Roster]} = file:consult(File),
subscribe_roster({User, Server, "", User}, Roster).
pushroster_all(File) ->
{ok, [Roster]} = file:consult(File),
subscribe_all(Roster).
subscribe_all(Roster) ->
subscribe_all(Roster, Roster).
subscribe_all([], _) ->
ok;
subscribe_all([User1 | Users], Roster) ->
subscribe_roster(User1, Roster),
subscribe_all(Users, Roster).
subscribe_roster(_, []) ->
ok;
% Do not subscribe a user to itself
subscribe_roster({Name, Server, Group, Nick}, [{Name, Server, _, _} | Roster]) ->
subscribe_roster({Name, Server, Group, Nick}, Roster);
% Subscribe Name2 to Name1
subscribe_roster({Name1, Server1, Group1, Nick1}, [{Name2, Server2, Group2, Nick2} | Roster]) ->
subscribe(Name1, Server1, Name2, Server2, Nick2, Group2, both, []),
subscribe_roster({Name1, Server1, Group1, Nick1}, Roster).
push_alltoall(S, G) ->
Users = ejabberd_auth:get_vh_registered_users(S),
Users2 = build_list_users(G, Users, []),
subscribe_all(Users2).
build_list_users(_Group, [], Res) ->
Res;
build_list_users(Group, [{User, Server}|Users], Res) ->
build_list_users(Group, Users, [{User, Server, Group, User}|Res]).
vcard_get(User, Server, DataX) ->
[{_, _, A1}] = mnesia:dirty_read(vcard, {User, Server}),
Elem = vcard_get(DataX, A1),
{ok, xml:get_tag_cdata(Elem)}.
vcard_get({Data1, Data2}, A1) ->
A2 = xml:get_subtag(A1, Data1),
A3 = xml:get_subtag(A2, Data2),
case A3 of
"" -> A2;
_ -> A3
end;
vcard_get({Data}, A1) ->
xml:get_subtag(A1, Data).
vcard_set(User, Server, Data1, Data2, Content) ->
Content2 = {xmlelement, Data2, [], [{xmlcdata,Content}]},
R = {xmlelement, Data1, [], [Content2]},
vcard_set2(User, Server, R, Data1).
vcard_set(User, Server, Data, Content) ->
R = {xmlelement, Data, [], [{xmlcdata,Content}]},
vcard_set2(User, Server, R, Data).
vcard_set2(User, Server, R, Data) ->
% Get old vcard
[{_, _, A1}] = mnesia:dirty_read(vcard, {User, Server}),
{_, _, _, A2} = A1,
A3 = lists:keydelete(Data, 2, A2),
A4 = [R | A3],
% Build new vcard
SubEl = {xmlelement, "vCard", [{"xmlns","vcard-temp"}], A4},
IQ = #iq{type=set, sub_el = SubEl},
JID = jlib:make_jid(User, Server, ""),
mod_vcard:process_sm_iq(JID, JID, IQ),
{ok, "done"}.
-record(last_activity, {us, timestamp, status}).
delete_older_users(Days) ->
% Convert older time
SecOlder = Days*24*60*60,
% Get current time
{MegaSecs, Secs, _MicroSecs} = now(),
TimeStamp_now = MegaSecs * 1000000 + Secs,
% Get the list of registered users
Users = ejabberd_auth:dirty_get_registered_users(),
% For a user, remove if required and answer true
F = fun({LUser, LServer}) ->
% Check if the user is logged
case ejabberd_sm:get_user_resources(LUser, LServer) of
% If it isn't
[] ->
% Look for his last_activity
case mnesia:dirty_read(last_activity, {LUser, LServer}) of
% If it is
% existent:
[#last_activity{timestamp = TimeStamp}] ->
% get his age
Sec = TimeStamp_now - TimeStamp,
% If he is
if
% younger than SecOlder:
Sec < SecOlder ->
% do nothing
false;
% older:
true ->
% remove the user
ejabberd_auth:remove_user(LUser, LServer),
true
end;
% nonexistent:
[] ->
% remove the user
ejabberd_auth:remove_user(LUser, LServer),
true
end;
% Else
_ ->
% do nothing
false
end
end,
% Apply the function to every user in the list
Users_removed = lists:filter(F, Users),
{removed, length(Users_removed), Users_removed}.
num_active_users(Host, Days) ->
list_last_activity(Host, true, Days).
% Code based on ejabberd/src/web/ejabberd_web_admin.erl
list_last_activity(Host, Integral, Days) ->
{MegaSecs, Secs, _MicroSecs} = now(),
TimeStamp = MegaSecs * 1000000 + Secs,
TS = TimeStamp - Days * 86400,
case catch mnesia:dirty_select(
last_activity, [{{last_activity, {'_', Host}, '$1', '_'},
[{'>', '$1', TS}],
[{'trunc', {'/',
{'-', TimeStamp, '$1'},
86400}}]}]) of
{'EXIT', _Reason} ->
[];
Vals ->
Hist = histogram(Vals, Integral),
if
Hist == [] ->
0;
true ->
Left = if
Days == infinity ->
0;
true ->
Days - length(Hist)
end,
Tail = if
Integral ->
lists:duplicate(Left, lists:last(Hist));
true ->
lists:duplicate(Left, 0)
end,
lists:nth(Days, Hist ++ Tail)
end
end.
histogram(Values, Integral) ->
histogram(lists:sort(Values), Integral, 0, 0, []).
histogram([H | T], Integral, Current, Count, Hist) when Current == H ->
histogram(T, Integral, Current, Count + 1, Hist);
histogram([H | _] = Values, Integral, Current, Count, Hist) when Current < H ->
if
Integral ->
histogram(Values, Integral, Current + 1, Count, [Count | Hist]);
true ->
histogram(Values, Integral, Current + 1, 0, [Count | Hist])
end;
histogram([], _Integral, _Current, Count, Hist) ->
if
Count > 0 ->
lists:reverse([Count | Hist]);
true ->
lists:reverse(Hist)
end.
--- NEW FILE mod_shared_roster_ad.erl ---
%%%----------------------------------------------------------------------
%%% File : mod_shared_roster.erl
%%% Author : Alexey Shchepin <alexey at sevcom.net>
%%% Author : Stanislav Bogatyrev <realloc at realloc.spb.ru>
%%% Purpose : Shared roster management
%%% Created : 5 Mar 2005 by Alexey Shchepin <alexey at sevcom.net>
%%% Id : $Id: mod_shared_roster.erl 24 2005-04-14 01:15:31Z alexey $
%%%----------------------------------------------------------------------
-module(mod_shared_roster_ad).
-author('alexey at sevcom.net').
-author('realloc at realloc.spb.ru').
-vsn('$Revision: 24 $ ').
-behaviour(gen_mod).
-export([start/2, stop/1,
get_user_roster/2,
get_subscription_lists/3,
get_jid_info/4,
in_subscription/5,
out_subscription/4,
list_groups/1,
create_group/2,
create_group/3,
delete_group/2,
get_group_opts/2,
set_group_opts/3,
get_group_users/2,
get_group_explicit_users/2,
add_user_to_group/3,
remove_user_from_group/3]).
-include("ejabberd.hrl").
-include("jlib.hrl").
-include("mod_roster.hrl").
-include("eldap/eldap.hrl").
-record(sr_group, {group_host, opts}).
-record(sr_user, {us, group_host}).
start(Host, _Opts) ->
mnesia:create_table(sr_group,
[{disc_copies, [node()]},
{attributes, record_info(fields, sr_group)}]),
mnesia:create_table(sr_user,
[{disc_copies, [node()]},
{type, bag},
{attributes, record_info(fields, sr_user)}]),
mnesia:add_table_index(sr_user, group_host),
ejabberd_hooks:add(roster_get, Host,
?MODULE, get_user_roster, 70),
ejabberd_hooks:add(roster_in_subscription, Host,
?MODULE, in_subscription, 30),
ejabberd_hooks:add(roster_out_subscription, Host,
?MODULE, out_subscription, 30),
ejabberd_hooks:add(roster_get_subscription_lists, Host,
?MODULE, get_subscription_lists, 70),
ejabberd_hooks:add(roster_get_jid_info, Host,
?MODULE, get_jid_info, 70),
%ejabberd_hooks:add(remove_user, Host,
% ?MODULE, remove_user, 50),
LDAPServers = ejabberd_config:get_local_option({ad_servers, Host}),
RootDN = ejabberd_config:get_local_option({ad_rootdn, Host}),
Password = ejabberd_config:get_local_option({ad_password, Host}),
eldap:start_link("mod_shared_roster_ad", LDAPServers, 389, RootDN, Password).
stop(Host) ->
ejabberd_hooks:delete(roster_get, Host,
?MODULE, get_user_roster, 70),
ejabberd_hooks:delete(roster_in_subscription, Host,
?MODULE, in_subscription, 30),
ejabberd_hooks:delete(roster_out_subscription, Host,
?MODULE, out_subscription, 30),
ejabberd_hooks:delete(roster_get_subscription_lists, Host,
?MODULE, get_subscription_lists, 70),
ejabberd_hooks:delete(roster_get_jid_info, Host,
?MODULE, get_jid_info, 70).
%ejabberd_hooks:delete(remove_user, Host,
% ?MODULE, remove_user, 50),
get_user_roster(Items, US) ->
{U, S} = US,
DisplayedGroups = get_user_displayed_groups_ad(US),
SRUsers =
lists:foldl(
fun(Group, Acc1) ->
lists:foldl(
fun(User, Acc2) ->
dict:append(User, Group, Acc2)
end, Acc1, get_group_users_ad(S, Group))
end, dict:new(), DisplayedGroups),
{NewItems1, SRUsersRest} =
lists:mapfoldl(
fun(Item, SRUsers1) ->
{_, _, {U1, S1, _}} = Item#roster.usj,
US1 = {U1, S1},
case dict:find(US1, SRUsers1) of
{ok, _GroupNames} ->
{Item#roster{subscription = both, ask = none},
dict:erase(US1, SRUsers1)};
error ->
{Item, SRUsers1}
end
end, SRUsers, Items),
SRItems = [#roster{usj = {U, S, {U1, S1, ""}},
us = US,
jid = {U1, S1, ""},
name = get_user_fn(U1,S1),
subscription = both,
ask = none,
groups = GroupNames} ||
{{U1, S1}, GroupNames} <- dict:to_list(SRUsersRest)],
SRItems ++ NewItems1.
get_subscription_lists({F, T}, User, Server) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
DisplayedGroups = get_user_displayed_groups_ad(US),
SRUsers =
lists:usort(
lists:flatmap(
fun(Group) ->
get_group_users_ad(LServer, Group)
end, DisplayedGroups)),
SRJIDs = [{U1, S1, ""} || {U1, S1} <- SRUsers],
{lists:usort(SRJIDs ++ F), lists:usort(SRJIDs ++ T)}.
get_jid_info({Subscription, Groups}, User, Server, JID) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
{U1, S1, _} = jlib:jid_tolower(JID),
US1 = {U1, S1},
DisplayedGroups = get_user_displayed_groups_ad(US),
SRUsers =
lists:foldl(
fun(Group, Acc1) ->
lists:foldl(
fun(User1, Acc2) ->
dict:append(
User1, Group, Acc2)
end, Acc1, get_group_users_ad(LServer, Group))
end, dict:new(), DisplayedGroups),
case dict:find(US1, SRUsers) of
{ok, GroupNames} ->
NewGroups = if
Groups == [] -> GroupNames;
true -> Groups
end,
{both, NewGroups};
error ->
{Subscription, Groups}
end.
in_subscription(Acc, User, Server, JID, Type) ->
process_subscription(in, User, Server, JID, Type, Acc).
out_subscription(User, Server, JID, Type) ->
process_subscription(out, User, Server, JID, Type, false).
process_subscription(Direction, User, Server, JID, _Type, Acc) ->
LUser = jlib:nodeprep(User),
LServer = jlib:nameprep(Server),
US = {LUser, LServer},
{U1, S1, _} = jlib:jid_tolower(jlib:jid_remove_resource(JID)),
US1 = {U1, S1},
DisplayedGroups = get_user_displayed_groups_ad(US),
SRUsers =
lists:usort(
lists:flatmap(
fun(Group) ->
get_group_users_ad(LServer, Group)
end, DisplayedGroups)),
case lists:member(US1, SRUsers) of
true ->
case Direction of
in ->
{stop, false};
out ->
stop
end;
false ->
Acc
end.
list_groups(Host) ->
get_user_displayed_groups_ad({"",Host}).
create_group(Host, Group) ->
create_group(Host, Group, []).
create_group(Host, Group, Opts) ->
R = #sr_group{group_host = {Group, Host}, opts = Opts},
F = fun() ->
mnesia:write(R)
end,
mnesia:transaction(F).
delete_group(Host, Group) ->
F = fun() ->
mnesia:delete({sr_group, {Group, Host}})
end,
mnesia:transaction(F).
get_group_opts(Host, Group) ->
case catch mnesia:dirty_read(sr_group, {Group, Host}) of
[#sr_group{opts = Opts}] ->
Opts;
_ ->
error
end.
set_group_opts(Host, Group, Opts) ->
R = #sr_group{group_host = {Group, Host}, opts = Opts},
F = fun() ->
mnesia:write(R)
end,
mnesia:transaction(F).
get_user_groups(US) ->
Host = element(2, US),
case catch mnesia:dirty_read(sr_user, US) of
Rs when is_list(Rs) ->
[Group || #sr_user{group_host = {Group, H}} <- Rs, H == Host];
_ ->
[]
end ++ get_all_users_groups(Host).
is_group_enabled(Host, Group) ->
case catch mnesia:dirty_read(sr_group, {Group, Host}) of
[#sr_group{opts = Opts}] ->
not lists:member(disabled, Opts);
_ ->
false
end.
get_group_opt(Host, Group, Opt, Default) ->
case catch mnesia:dirty_read(sr_group, {Group, Host}) of
[#sr_group{opts = Opts}] ->
case lists:keysearch(Opt, 1, Opts) of
{value, {_, Val}} ->
Val;
false ->
Default
end;
_ ->
false
end.
get_group_users(Host, Group) ->
case get_group_opt(Host, Group, all_users, false) of
true ->
ejabberd_auth:get_vh_registered_users(Host);
false ->
[]
end ++ get_group_explicit_users(Host, Group).
get_group_explicit_users(Host, Group) ->
case catch mnesia:dirty_index_read(
sr_user, {Group, Host}, #sr_user.group_host) of
Rs when is_list(Rs) ->
[R#sr_user.us || R <- Rs];
_ ->
[]
end.
get_group_name(Host, Group) ->
get_group_opt(Host, Group, name, Group).
get_all_users_groups(Host) ->
lists:filter(
fun(Group) -> get_group_opt(Host, Group, all_users, false) end,
list_groups(Host)).
get_user_displayed_groups(US) ->
Host = element(2, US),
DisplayedGroups1 =
lists:usort(
lists:flatmap(
fun(Group) ->
case is_group_enabled(Host, Group) of
true ->
get_group_opt(Host, Group, displayed_groups, []);
false ->
[]
end
end, get_user_groups(US))),
[Group || Group <- DisplayedGroups1, is_group_enabled(Host, Group)].
add_user_to_group(Host, US, Group) ->
R = #sr_user{us = US, group_host = {Group, Host}},
F = fun() ->
mnesia:write(R)
end,
mnesia:transaction(F).
remove_user_from_group(Host, US, Group) ->
R = #sr_user{us = US, group_host = {Group, Host}},
F = fun() ->
mnesia:delete_object(R)
end,
mnesia:transaction(F).
find_user_attr(User, Host) ->
Attr = ejabberd_config:get_local_option({ad_uidattr, Host}),
Filter = eldap:equalityMatch(Attr, User),
Base = ejabberd_config:get_local_option({ad_base, Host}),
case eldap:search("mod_shared_roster_ad",
[{base, Base},
{filter, Filter},
{attributes, []}]) of
#eldap_search_result{entries = [E | _]} ->
E;
_ ->
false
end.
get_user_displayed_groups_ad(US) ->
{_, Host} = US,
AdGroup = ejabberd_config:get_local_option({ad_group, Host}),
FilterGroup = eldap:equalityMatch("memberOf", AdGroup),
Base = ejabberd_config:get_local_option({ad_base, Host}),
case eldap:search("mod_shared_roster_ad",
[{base, Base},
{filter, FilterGroup},
{attributes, []}]) of
#eldap_search_result{entries = E} ->
lists:usort(lists:map(
fun(X) ->
case X of
#eldap_entry{attributes = Attributes} ->
ldap_get_value(Attributes,"department");
false ->
""
end
end, E
));
_ ->
[]
end.
get_eldap_id(Host, Name) ->
atom_to_list(gen_mod:get_module_proc(Host, Name)).
get_group_users_ad(Host, Group) ->
Attr = ejabberd_config:get_local_option({ad_uidattr, Host}),
% AdGroup = ejabberd_config:get_local_option({ad_group, Host}),
FilterPerson = eldap:equalityMatch("objectCategory", "person"),
FilterComp = eldap:equalityMatch("objectClass", "computer"),
FilterHidden = eldap:equalityMatch("description", "hidden"),
% FilterGroup = eldap:equalityMatch("memberOf", AdGroup),
FilterDep = eldap:equalityMatch("department", Group),
FilterLive = eldap:equalityMatch("userAccountControl", "66050"),
FilterDef = eldap:present(Attr),
Filter = eldap:'and'([
FilterDef,
FilterPerson,
% FilterGroup,
FilterDep,
eldap:'not'(FilterComp),
eldap:'not'(FilterHidden),
eldap:'not'(FilterLive)]),
Base = ejabberd_config:get_local_option({ad_base, Host}),
case eldap:search(get_eldap_id(Host, ejabberd),
[{base, Base},
{filter, Filter},
{attributes, [Attr]}]) of
#eldap_search_result{entries = Es} ->
lists:flatmap(
fun(E) ->
case lists:keysearch(Attr, 1, E#eldap_entry.attributes) of
{value, {_, [U]}} ->
case jlib:nodeprep(U) of
error ->
[];
LU ->
[{LU, Host}]
end;
_ ->
[]
end
end, Es);
_ ->
[]
end.
ldap_get_value(E,Attribute) ->
case lists:filter(fun({A,_}) ->
string:equal(A,Attribute)
end,E) of
[{_,[Value|_]}] ->
Value;
_ ->
none
end.
get_user_fn(User, Host) ->
case find_user_attr(User,Host) of
#eldap_entry{attributes = Attributes} ->
ldap_get_value(Attributes,"cn");
false ->
""
end.
--- NEW FILE mod_vcard_ad.erl ---
%%%----------------------------------------------------------------------
%%% File : mod_vcard_ad.erl
%%% Author : Stanislav Bogatyrev <realloc at realloc.spb.ru>
%%% Author : Alexey Shchepin <alexey at sevcom.net>
%%% Author : Alex <agent_007> Gorbachenko (agent_007 at immo.ru)
%%% Purpose :
%%% Created : 2 Jan 2003 by Alexey Shchepin <alexey at sevcom.net>
%%% Id : $Id: mod_vcard_ad.erl 437 2005-11-19 01:20:05Z agent_007 $
%%%----------------------------------------------------------------------
-module(mod_vcard_ad).
-author('realloc at realloc.spb.ru').
-author('alexey at sevcom.net').
-author('agent_007 at immo.ru').
-vsn('$Revision: 437 $ ').
-behaviour(gen_mod).
-export([start/2, init/3, stop/1,
get_sm_features/5,
process_local_iq/3,
process_sm_iq/3,
remove_user/1]).
-include("ejabberd.hrl").
-include("eldap/eldap.hrl").
-include("jlib.hrl").
-define(PROCNAME, ejabberd_mod_vcard_ad).
start(Host, Opts) ->
IQDisc = gen_mod:get_opt(iqdisc, Opts, one_queue),
gen_iq_handler:add_iq_handler(ejabberd_local, Host, ?NS_VCARD,
?MODULE, process_local_iq, IQDisc),
gen_iq_handler:add_iq_handler(ejabberd_sm, Host, ?NS_VCARD,
?MODULE, process_sm_iq, IQDisc),
ejabberd_hooks:add(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
LDAPServers = ejabberd_config:get_local_option({ad_servers, Host}),
RootDN = ejabberd_config:get_local_option({ad_rootdn, Host}),
Password = ejabberd_config:get_local_option({ad_password, Host}),
eldap:start_link("mod_vcard_ad", LDAPServers, 389, RootDN, Password),
MyHost = gen_mod:get_opt(host, Opts, "vjud." ++ Host),
Search = gen_mod:get_opt(search, Opts, true),
register(gen_mod:get_module_proc(Host, ?PROCNAME),
spawn(?MODULE, init, [MyHost, Host, Search])).
init(Host, ServerHost, Search) ->
case Search of
false ->
loop(Host, ServerHost);
_ ->
ejabberd_router:register_route(Host),
loop(Host, ServerHost)
end.
loop(Host, ServerHost) ->
receive
{route, From, To, Packet} ->
case catch do_route(ServerHost, From, To, Packet) of
{'EXIT', Reason} ->
?ERROR_MSG("~p", [Reason]);
_ ->
ok
end,
loop(Host, ServerHost);
stop ->
ejabberd_router:unregister_route(Host),
ok;
_ ->
loop(Host, ServerHost)
end.
stop(Host) ->
gen_iq_handler:remove_iq_handler(ejabberd_local, Host, ?NS_VCARD),
gen_iq_handler:remove_iq_handler(ejabberd_sm, Host, ?NS_VCARD),
ejabberd_hooks:delete(disco_sm_features, Host, ?MODULE, get_sm_features, 50),
Proc = gen_mod:get_module_proc(Host, ?PROCNAME),
Proc ! stop,
{wait, Proc}.
get_sm_features({error, _Error} = Acc, _From, _To, _Node, _Lang) ->
Acc;
get_sm_features(Acc, _From, _To, Node, _Lang) ->
case Node of
[] ->
case Acc of
{result, Features} ->
{result, [?NS_VCARD | Features]};
empty ->
{result, [?NS_VCARD]}
end;
_ ->
Acc
end.
process_local_iq(_From, _To, #iq{type = Type, lang = Lang, sub_el = SubEl} = IQ) ->
case Type of
set ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
get ->
IQ#iq{type = result,
sub_el = [{xmlelement, "vCard",
[{"xmlns", ?NS_VCARD}],
[{xmlelement, "FN", [],
[{xmlcdata, "ejabberd"}]},
{xmlelement, "URL", [],
[{xmlcdata,
"http://ejabberd.jabberstudio.org/"}]},
{xmlelement, "DESC", [],
[{xmlcdata,
translate:translate(
Lang,
"Erlang Jabber Server\n"
"Copyright (c) 2002-2005 Alexey Shchepin")}]},
{xmlelement, "BDAY", [],
[{xmlcdata, "2002-11-16"}]}
]}]}
end.
find_ldap_user(Host, User) ->
Attr = ejabberd_config:get_local_option({ad_uidattr, Host}),
Filter = eldap:equalityMatch(Attr, User),
Base = ejabberd_config:get_local_option({ad_base, Host}),
case eldap:search("mod_vcard_ad", [{base, Base},
{filter, Filter},
{attributes, []}]) of
#eldap_search_result{entries = [E | _]} ->
E;
_ ->
false
end.
is_attribute_read_allowed(Name,From,To) ->
true.
ldap_attribute_to_vcard(Prefix,{Name,Values},From,To) ->
case is_attribute_read_allowed(Name,From,To) of
true ->
ldap_lca_to_vcard(Prefix,stringprep:tolower(Name),Values);
_ ->
none
end.
ldap_lca_to_vcard(vCard,"displayname",[Value|_]) ->
{xmlelement,"FN",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(vCard,"cn",[Value|_]) ->
{xmlelement,"NICKNAME",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(vCard,"title",[Value|_]) ->
{xmlelement,"TITLE",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(vCard,"wwwhomepage",[Value|_]) ->
{xmlelement,"URL",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(vCard,"description",[Value|_]) ->
{xmlelement,"DESC",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(vCard,"telephonenumber",[Value|_]) ->
{xmlelement,"TEL",[],[{xmlelement,"VOICE",[],[]},
{xmlelement,"WORK",[],[]},
{xmlelement,"NUMBER",[],[{xmlcdata,Value}]}]};
ldap_lca_to_vcard(vCard,"mail",[Value|_]) ->
{xmlelement,"EMAIL",[],[{xmlelement,"INTERNET",[],[]},
{xmlelement,"PREF",[],[]},
{xmlelement,"USERID",[],[{xmlcdata,Value}]}]};
ldap_lca_to_vcard(vCardN,"sn",[Value|_]) ->
{xmlelement,"FAMILY",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(vCardN,"givenname",[Value|_]) ->
{xmlelement,"GIVEN",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(vCardN,"initials",[Value|_]) ->
{xmlelement,"MIDDLE",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(vCardAdr,"streetaddress",[Value|_]) ->
{xmlelement,"STREET",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(vCardAdr,"co",[Value|_]) ->
{xmlelement,"CTRY",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(vCardAdr,"l",[Value|_]) ->
{xmlelement,"LOCALITY",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(vCardAdr,"st",[Value|_]) ->
{xmlelement,"REGION",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(vCardAdr,"postalcode",[Value|_]) ->
{xmlelement,"PCODE",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(vCardO,"company",[Value|_]) ->
{xmlelement,"ORGNAME",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(vCardO,"department",[Value|_]) ->
{xmlelement,"ORGUNIT",[],[{xmlcdata,Value}]};
ldap_lca_to_vcard(_,_,_) -> none.
ldap_attributes_to_vcard(Attributes,From,To) ->
Elts = lists:map(fun(Attr) ->
ldap_attribute_to_vcard(vCard,Attr,From,To)
end,Attributes),
FElts = [ X || X <- Elts, X /= none ],
NElts = lists:map(fun(Attr) ->
ldap_attribute_to_vcard(vCardN,Attr,From,To)
end,Attributes),
FNElts = [ X || X <- NElts, X /= none ],
ADRElts = lists:map(fun(Attr) ->
ldap_attribute_to_vcard(vCardAdr,Attr,From,To)
end,Attributes),
FADRElts = [ X || X <- ADRElts, X /= none ],
OElts = lists:map(fun(Attr) ->
ldap_attribute_to_vcard(vCardO,Attr,From,To)
end,Attributes),
FOElts = [ X || X <- OElts, X /= none ],
[{xmlelement, "vCard", [{"xmlns", ?NS_VCARD}],
lists:append(FElts,
[{xmlelement,"N",[],FNElts},
{xmlelement,"ADR",[],FADRElts},
{xmlelement,"ORG",[],FOElts}])
}].
process_sm_iq(From, To, #iq{type = Type, sub_el = SubEl} = IQ) ->
case Type of
set ->
IQ#iq{type = error, sub_el = [SubEl, ?ERR_NOT_ALLOWED]};
get ->
#jid{luser = LUser, lserver = LServer} = To,
case find_ldap_user(LServer, LUser) of
#eldap_entry{attributes = Attributes} ->
Vcard = ldap_attributes_to_vcard(Attributes,From,To),
IQ#iq{type = result, sub_el = Vcard};
_ ->
IQ#iq{type = result, sub_el = []}
end
end.
-define(TLFIELD(Type, Label, Var),
{xmlelement, "field", [{"type", Type},
{"label", translate:translate(Lang, Label)},
{"var", Var}], []}).
-define(FORM(JID),
[{xmlelement, "instructions", [],
[{xmlcdata, translate:translate(Lang, "You need an x:data capable client to search")}]},
{xmlelement, "x", [{"xmlns", ?NS_XDATA}, {"type", "form"}],
[{xmlelement, "title", [],
[{xmlcdata, translate:translate(Lang, "Search users in ") ++
jlib:jid_to_string(JID)}]},
{xmlelement, "instructions", [],
[{xmlcdata, translate:translate(Lang, "Fill in fields to search "
"for any matching Jabber User")}]},
?TLFIELD("text-single", "User", "user"),
?TLFIELD("text-single", "Full Name", "fn"),
?TLFIELD("text-single", "Given Name", "given"),
?TLFIELD("text-single", "Middle Name", "middle"),
?TLFIELD("text-single", "Family Name", "family"),
?TLFIELD("text-single", "Nickname", "nickname"),
?TLFIELD("text-single", "Birthday", "bday"),
?TLFIELD("text-single", "Country", "ctry"),
?TLFIELD("text-single", "City", "locality"),
?TLFIELD("text-single", "email", "email"),
?TLFIELD("text-single", "Organization Name", "orgname"),
?TLFIELD("text-single", "Organization Unit", "orgunit")
]}]).
do_route(ServerHost, From, To, Packet) ->
#jid{user = User, resource = Resource} = To,
if
(User /= "") or (Resource /= "") ->
Err = jlib:make_error_reply(Packet, ?ERR_SERVICE_UNAVAILABLE),
ejabberd_router ! {route, To, From, Err};
true ->
IQ = jlib:iq_query_info(Packet),
case IQ of
#iq{type = Type, xmlns = ?NS_SEARCH, lang = Lang, sub_el = SubEl} ->
case Type of
set ->
XDataEl = find_xdata_el(SubEl),
case XDataEl of
false ->
Err = jlib:make_error_reply(
Packet, ?ERR_BAD_REQUEST),
ejabberd_router:route(To, From, Err);
_ ->
XData = jlib:parse_xdata_submit(XDataEl),
case XData of
invalid ->
Err = jlib:make_error_reply(
Packet,
?ERR_BAD_REQUEST),
ejabberd_router:route(To, From,
Err);
_ ->
ResIQ =
IQ#iq{
type = result,
sub_el =
[{xmlelement,
"query",
[{"xmlns", ?NS_SEARCH}],
[{xmlelement, "x",
[{"xmlns", ?NS_XDATA},
{"type", "result"}],
search_result(Lang, To, ServerHost, XData)
}]}]},
ejabberd_router:route(
To, From, jlib:iq_to_xml(ResIQ))
end
end;
get ->
ResIQ = IQ#iq{type = result,
sub_el = [{xmlelement,
"query",
[{"xmlns", ?NS_SEARCH}],
?FORM(To)
}]},
ejabberd_router:route(To,
From,
jlib:iq_to_xml(ResIQ))
end;
#iq{type = Type, xmlns = ?NS_DISCO_INFO, sub_el = SubEl} ->
case Type of
set ->
Err = jlib:make_error_reply(
Packet, ?ERR_NOT_ALLOWED),
ejabberd_router:route(To, From, Err);
get ->
ResIQ =
IQ#iq{type = result,
sub_el = [{xmlelement,
"query",
[{"xmlns", ?NS_DISCO_INFO}],
[{xmlelement, "identity",
[{"category", "directory"},
{"type", "user"},
{"name",
"vCard User Search"}],
[]},
{xmlelement, "feature",
[{"var", ?NS_SEARCH}], []},
{xmlelement, "feature",
[{"var", ?NS_VCARD}], []}
]
}]},
ejabberd_router:route(To,
From,
jlib:iq_to_xml(ResIQ))
end;
#iq{type = Type, xmlns = ?NS_DISCO_ITEMS, sub_el = SubEl} ->
case Type of
set ->
Err = jlib:make_error_reply(
Packet, ?ERR_NOT_ALLOWED),
ejabberd_router:route(To, From, Err);
get ->
ResIQ =
IQ#iq{type = result,
sub_el = [{xmlelement,
"query",
[{"xmlns", ?NS_DISCO_ITEMS}],
[]}]},
ejabberd_router:route(To,
From,
jlib:iq_to_xml(ResIQ))
end;
#iq{type = get, xmlns = ?NS_VCARD, lang = Lang} ->
ResIQ =
IQ#iq{type = result,
sub_el = [{xmlelement,
"vCard",
[{"xmlns", ?NS_VCARD}],
iq_get_vcard(Lang)}]},
ejabberd_router:route(To,
From,
jlib:iq_to_xml(ResIQ));
_ ->
Err = jlib:make_error_reply(Packet,
?ERR_SERVICE_UNAVAILABLE),
ejabberd_router:route(To, From, Err)
end
end.
iq_get_vcard(Lang) ->
[{xmlelement, "FN", [],
[{xmlcdata, "ejabberd/mod_vcard"}]},
{xmlelement, "URL", [],
[{xmlcdata,
"http://ejabberd.jabberstudio.org/"}]},
{xmlelement, "DESC", [],
[{xmlcdata, translate:translate(
Lang,
"ejabberd vCard module\n"
"Copyright (c) 2003-2005 Alexey Shchepin")}]}].
find_xdata_el({xmlelement, _Name, _Attrs, SubEls}) ->
find_xdata_el1(SubEls).
find_xdata_el1([]) ->
false;
find_xdata_el1([{xmlelement, Name, Attrs, SubEls} | Els]) ->
case xml:get_attr_s("xmlns", Attrs) of
?NS_XDATA ->
{xmlelement, Name, Attrs, SubEls};
_ ->
find_xdata_el1(Els)
end;
find_xdata_el1([_ | Els]) ->
find_xdata_el1(Els).
-define(LFIELD(Label, Var),
{xmlelement, "field", [{"label", translate:translate(Lang, Label)},
{"var", Var}], []}).
search_result(Lang, JID, ServerHost, Data) ->
[{xmlelement, "title", [],
[{xmlcdata, translate:translate(Lang, "Results of search in ") ++
jlib:jid_to_string(JID)}]},
{xmlelement, "reported", [],
[?LFIELD("JID", "jid"),
?LFIELD("Full Name", "fn"),
?LFIELD("Given Name", "given"),
?LFIELD("Middle Name", "middle"),
?LFIELD("Family Name", "family"),
?LFIELD("Nickname", "nickname"),
?LFIELD("Birthday", "bday"),
?LFIELD("Country", "ctry"),
?LFIELD("City", "locality"),
?LFIELD("email", "email"),
?LFIELD("Organization Name", "orgname"),
?LFIELD("Organization Unit", "orgunit")
]}] ++ lists:map(fun(E) ->
record_to_item(E#eldap_entry.attributes)
end, search(ServerHost, Data)).
-define(FIELD(Var, Val),
{xmlelement, "field", [{"var", Var}],
[{xmlelement, "value", [],
[{xmlcdata, Val}]}]}).
case_exact_compare(none,_) ->
false;
case_exact_compare(_,none) ->
false;
case_exact_compare(X,Y) ->
X > Y.
ldap_sort_entries(L) ->
lists:sort(fun(E1,E2) ->
case_exact_compare(ldap_get_value(E1,"cn"),ldap_get_value(E2,"cn"))
end,L).
ldap_get_value(E,Attribute) ->
#eldap_entry{attributes = Attributes} = E,
case lists:filter(fun({A,_}) ->
string:equal(A,Attribute)
end,Attributes) of
[{Attr,[Value|_]}] ->
Value;
_ ->
none
end.
ldap_attribute_to_item("samaccountname",Value) ->
[
?FIELD("jid",Value ++ "@" ++ ?MYNAME),
?FIELD("uid",Value)
];
ldap_attribute_to_item("cn",Value) ->
[
?FIELD("nickname",Value)
];
ldap_attribute_to_item("displayname",Value) ->
[
?FIELD("fn",Value)
];
ldap_attribute_to_item("sn",Value) ->
[
?FIELD("family",Value)
];
ldap_attribute_to_item("co",Value) ->
[
?FIELD("ctry",Value)
];
ldap_attribute_to_item("l",Value) ->
[
?FIELD("locality",Value)
];
ldap_attribute_to_item("givenname",Value) ->
[
?FIELD("given",Value)
];
ldap_attribute_to_item("initials",Value) ->
[
?FIELD("middle",Value)
];
ldap_attribute_to_item("mail",Value) ->
[
?FIELD("email",Value)
];
ldap_attribute_to_item("company",Value) ->
[
?FIELD("orgname",Value)
];
ldap_attribute_to_item("department",Value) ->
[
?FIELD("orgunit",Value)
];
ldap_attribute_to_item(_,_) ->
[none].
record_to_item(Attributes) ->
List = lists:append(lists:map(fun({Attr,[Value|_]}) ->
ldap_attribute_to_item(stringprep:tolower(Attr),Value)
end,Attributes)),
FList = [X || X <- List, X /= none],
{xmlelement, "item", [],FList}.
search(LServer, Data) ->
% AdGroup = ejabberd_config:get_local_option({ad_group, LServer}),
FilterDef = make_filter(Data),
FilterPerson = eldap:equalityMatch("objectCategory", "person"),
FilterComp = eldap:equalityMatch("objectClass", "computer"),
FilterHidden = eldap:equalityMatch("description", "hidden"),
% FilterGroup = eldap:equalityMatch("memberOf", AdGroup),
FilterLive = eldap:equalityMatch("userAccountControl", "66050"),
Filter = eldap:'and'([
FilterDef,
FilterPerson,
% FilterGroup,
eldap:'not'(FilterComp),
eldap:'not'(FilterHidden),
eldap:'not'(FilterLive)]),
Base = ejabberd_config:get_local_option({ad_base, LServer}),
UIDAttr = ejabberd_config:get_local_option({ad_uidattr, LServer}),
case eldap:search("mod_vcard_ad",[{base, Base},
{filter, Filter},
{attributes, []}]) of
#eldap_search_result{entries = E} ->
[X || X <- E,
ejabberd_auth:is_user_exists(
ldap_get_value(X, UIDAttr), LServer)];
Err ->
?ERROR_MSG("Bad search: ~p", [[LServer, {base, Base},
{filter, Filter},
{attributes, []}]])
end.
make_filter(Data) ->
Filter = [X || X <- lists:map(fun(R) ->
make_assertion(R)
end, Data),
X /= none ],
case Filter of
[F] ->
F;
_ ->
eldap:'and'(Filter)
end.
make_assertion("givenName",Value) ->
eldap:substrings("givenName",[{any,Value}]);
make_assertion("cn",Value) ->
eldap:substrings("cn",[{any,Value}]);
make_assertion("sn",Value) ->
eldap:substrings("sn",[{any,Value}]);
make_assertion(Attr, Value) ->
eldap:equalityMatch(Attr,Value).
make_assertion({SVar, [Val]}) ->
LAttr = ldap_attribute(SVar),
case LAttr of
none ->
none;
_ ->
if
is_list(Val) and (Val /= "") ->
make_assertion(LAttr,Val);
true ->
none
end
end.
ldap_attribute("user") ->
"samaccountname";
ldap_attribute("fn") ->
"cn";
ldap_attribute("family") ->
"sn";
ldap_attribute("given") ->
"givenName";
ldap_attribute("middle") ->
"initials";
ldap_attribute("email") ->
"mail";
ldap_attribute("orgname") ->
"company";
ldap_attribute("orgunit") ->
"department";
ldap_attribute(_) ->
none.
remove_user(User) ->
true.
Index: .cvsignore
===================================================================
RCS file: /cvs/extras/rpms/ejabberd/devel/.cvsignore,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- .cvsignore 23 Jun 2006 12:38:32 -0000 1.1
+++ .cvsignore 23 Jun 2006 12:40:03 -0000 1.2
@@ -0,0 +1 @@
+ejabberd-1.1.1.tar.gz
Index: sources
===================================================================
RCS file: /cvs/extras/rpms/ejabberd/devel/sources,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -r1.1 -r1.2
--- sources 23 Jun 2006 12:38:32 -0000 1.1
+++ sources 23 Jun 2006 12:40:03 -0000 1.2
@@ -0,0 +1 @@
+ef6fae4a3f9c7f807f21e9cd3dae195b ejabberd-1.1.1.tar.gz
More information about the fedora-extras-commits
mailing list