public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/ejabberd] f45: Ver. 2.1.6
@ 2026-09-23 19:07 Peter Lemenkov
  0 siblings, 0 replies; only message in thread
From: Peter Lemenkov @ 2026-09-23 19:07 UTC (permalink / raw)
  To: git-commits

            A new commit has been pushed.

            Repo   : rpms/ejabberd
            Branch : f45
            Commit : 5c2945ff47a11443f1c33686b8ab24db653fca64
            Author : Peter Lemenkov <lemenkov@gmail.com>
            Date   : 2010-12-14T22:47:28+03:00
            Stats  : +2824/-3062 in 27 file(s)
            URL    : https://src.fedoraproject.org/rpms/ejabberd/c/5c2945ff47a11443f1c33686b8ab24db653fca64?branch=f45

            Log:
            Ver. 2.1.6

Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>

---
diff --git a/.gitignore b/.gitignore
index 0308b93..7794ea3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,3 @@
 ejabberd-2.1.4.tar.gz
 ejabberd-2.1.5.tar.gz
+/ejabberd-2.1.6.tar.gz

diff --git a/ejabberd-0001-Fix-PAM-service-example-name-to-match-actual-one.patch b/ejabberd-0001-Fix-PAM-service-example-name-to-match-actual-one.patch
index 5e9444f..3b0dd34 100644
--- a/ejabberd-0001-Fix-PAM-service-example-name-to-match-actual-one.patch
+++ b/ejabberd-0001-Fix-PAM-service-example-name-to-match-actual-one.patch
@@ -1,4 +1,4 @@
-From 5fdb6557be8b5758856a91e8172acfddc9d04382 Mon Sep 17 00:00:00 2001
+From 9087a0b27b3d56f8fdb28e5190012796f348d43a Mon Sep 17 00:00:00 2001
 From: Peter Lemenkov <lemenkov@gmail.com>
 Date: Tue, 16 Feb 2010 16:03:38 +0300
 Subject: [PATCH 01/10] Fix PAM service example name to match actual one
@@ -9,10 +9,10 @@ Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
  1 files changed, 1 insertions(+), 1 deletions(-)
 
 diff --git a/src/ejabberd.cfg.example b/src/ejabberd.cfg.example
-index 4087947..b351cfc 100644
+index a95689b..005c73c 100644
 --- a/src/ejabberd.cfg.example
 +++ b/src/ejabberd.cfg.example
-@@ -235,7 +235,7 @@
+@@ -236,7 +236,7 @@
  %% Authentication using PAM
  %%
  %%{auth_method, pam}.
@@ -22,5 +22,5 @@ index 4087947..b351cfc 100644
  %%
  %% Authentication using LDAP
 -- 
-1.7.2.1
+1.7.3.3
 

diff --git a/ejabberd-0002-Add-mod_ctlextra-as-an-ejabberd-module.patch b/ejabberd-0002-Add-mod_ctlextra-as-an-ejabberd-module.patch
new file mode 100644
index 0000000..1ebcd1f
--- /dev/null
+++ b/ejabberd-0002-Add-mod_ctlextra-as-an-ejabberd-module.patch
@@ -0,0 +1,936 @@
+From 85b432d0293d867dd5c11ae8e7b5c724b7fad056 Mon Sep 17 00:00:00 2001
+From: Peter Lemenkov <lemenkov@gmail.com>
+Date: Tue, 16 Feb 2010 16:05:53 +0300
+Subject: [PATCH 02/10] Add mod_ctlextra as an ejabberd module
+
+See this link for the details:
+http://www.ejabberd.im/mod_ctlextra
+
+Also note that this module will be removed in the nearest future
+in favor of mod_admin_extra:
+
+svn export -r 1020 https://svn.process-one.net/ejabberd-modules/mod_ctlextra/trunk/src/mod_ctlextra.erl
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+---
+ src/ejabberd.app     |    1 +
+ src/mod_ctlextra.erl |  895 ++++++++++++++++++++++++++++++++++++++++++++++++++
+ 2 files changed, 896 insertions(+), 0 deletions(-)
+ create mode 100644 src/mod_ctlextra.erl
+
+diff --git a/src/ejabberd.app b/src/ejabberd.app
+index c2d282d..6db563c 100644
+--- a/src/ejabberd.app
++++ b/src/ejabberd.app
+@@ -70,6 +70,7 @@
+ 	     mod_caps,
+ 	     mod_configure2,
+ 	     mod_configure,
++	     mod_ctlextra,
+ 	     mod_disco,
+ 	     mod_echo,
+ 	     mod_http_bind,
+diff --git a/src/mod_ctlextra.erl b/src/mod_ctlextra.erl
+new file mode 100644
+index 0000000..bc61024
+--- /dev/null
++++ b/src/mod_ctlextra.erl
+@@ -0,0 +1,895 @@
++%%%----------------------------------------------------------------------
++%%% File    : mod_ctlextra.erl
++%%% Author  : Badlop <badlop@ono.com>
++%%% Purpose : Adds more commands to ejabberd_ctl
++%%% Created : 30 Nov 2006 by Badlop <badlop@ono.com>
++%%% Id      : $Id: mod_ctlextra.erl 1020 2009-08-30 10:13:34Z badlop $
++%%%----------------------------------------------------------------------
++
++-module(mod_ctlextra).
++-author('badlop@ono.com').
++
++-behaviour(gen_mod).
++
++-export([start/2,
++	 stop/1,
++	 ctl_process/2,
++	 ctl_process/3
++	]).
++
++-include("ejabberd.hrl").
++-include("ejabberd_ctl.hrl").
++-include("jlib.hrl").
++-include("mod_roster.hrl").
++
++%% Copied from ejabberd_sm.erl
++-record(session, {sid, usr, us, priority, info}).
++
++-compile(export_all).
++
++%%-------------
++%% gen_mod
++%%-------------
++
++start(Host, _Opts) ->
++    ejabberd_ctl:register_commands(commands_global(), ?MODULE, ctl_process),
++    ejabberd_ctl:register_commands(Host, commands_host(), ?MODULE, ctl_process).
++
++stop(Host) ->
++    ejabberd_ctl:unregister_commands(commands_global(), ?MODULE, ctl_process),
++    ejabberd_ctl:unregister_commands(Host, commands_host(), ?MODULE, ctl_process).
++
++commands_global() ->
++    [
++     {"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'"},
++     {"delete-older-users-vhost host days", "delete users that not logged in last 'days' in 'host'"},
++     {"set-password user server password", "set password to user@server"},
++
++     %% ejd2odbc
++     {"export2odbc server output", "export Mnesia tables on server to files on output directory"},
++
++     %% 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@server to group on host"},
++     {"srg-user-del user server group host", "delete user@server from group on host"},
++     {"srg-list-groups host", "list the shared roster groups from host"},
++     {"srg-get-info group host", "get info of a specific 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_roster
++     {"add-rosteritem user1 server1 user2 server2 nick group subs", "Add user2@server2 to user1@server1's roster"},
++     %%{"", "subs= none, from, to or both"},
++     %%{"", "example: add-roster peter localhost mike server.com MiKe Employees both"},
++     %%{"", "will add mike@server.com to peter@localhost roster"},
++     {"rem-rosteritem user1 server1 user2 server2", "Remove user2@server2 from user1@server1's roster"},
++     {"rosteritem-purge [options]", "Purge all rosteritems that match filtering options"},
++     {"pushroster file user server", "push template roster in file to user@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"},
++
++     {"status-list status", "list the logged users with status"},
++     {"status-num status", "number of logged users with status"},
++
++     {"stats registeredusers", "number of registered users"},
++     {"stats onlineusers", "number of logged users"},
++     {"stats onlineusersnode", "number of logged users in the ejabberd node"},
++     {"stats uptime-seconds", "uptime of ejabberd node in seconds"},
++
++     %% misc
++     {"get-cookie", "get the Erlang cookie of this node"},
++     {"killsession user server resource", "kill a user session"}
++    ].
++
++commands_host() ->
++    [
++     %% mod_last
++     {"num-active-users days", "number of users active in the last 'days'"},
++     {"status-list status", "list the logged users with status"},
++     {"status-num status", "number of logged users with status"},
++     {"stats registeredusers", "number of registered users"},
++     {"stats onlineusers", "number of logged users"},
++
++     %% misc
++     {"ban-account username [reason]", "ban account: kick sessions and change password"}
++    ].
++
++
++%%-------------
++%% Commands global
++%%-------------
++
++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, ["delete-older-users-vhost", Host, Days]) ->
++    {removed, N, UR} = delete_older_users_vhost(Host, list_to_integer(Days)),
++    io:format("Deleted ~p users: ~p~n", [N, UR]),
++    ?STATUS_SUCCESS;
++
++ctl_process(_Val, ["export2odbc", Server, Output]) ->
++    Tables = [
++	      {export_last, last},
++	      {export_offline, offline},
++	      {export_passwd, passwd},
++	      {export_private_storage, private_storage},
++	      {export_roster, roster},
++	      {export_vcard, vcard},
++	      {export_vcard_search, vcard_search}],
++    Export = fun({TableFun, Table}) -> 
++		     Filename = filename:join([Output, atom_to_list(Table)++".txt"]),
++		     io:format("Trying to export Mnesia table '~p' on server '~s' to file '~s'~n", [Table, Server, Filename]),
++		     Res = (catch ejd2odbc:TableFun(Server, Filename)),
++		     io:format("  Result: ~p~n", [Res])
++	     end,
++    lists:foreach(Export, Tables),
++    ?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, Data1, Content]) ->
++    {ok, Res} = vcard_set(User, Server, [Data1], 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;
++
++%% The Display argument can be several groups separated with ,
++%% Example: ejabberdctl srg-create aa localhost Name Desc Display1,Display2,Display3
++ctl_process(_Val, ["srg-create" | Parameters]) ->
++	[Group, Host, Name, Description, Display] = group_parameters(Parameters, "'"),
++    DisplayList = string:tokens(Display, ","),
++    Opts = [{name, Name}, {displayed_groups, DisplayList}, {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, ["srg-list-groups", Host]) ->
++    lists:foreach(
++      fun(SrgGroup) ->
++	      io:format("~s~n",[SrgGroup])
++      end,
++      lists:sort(mod_shared_roster:list_groups(Host))),
++    ?STATUS_SUCCESS;
++
++ctl_process(_Val, ["srg-get-info", Group, Host]) ->
++    Opts = mod_shared_roster:get_group_opts(Host,Group),
++    [io:format("~s: ~p~n", [Title, Value]) || {Title , Value} <- Opts],
++    
++    Members = mod_shared_roster:get_group_explicit_users(Host,Group),
++    Members_string = [ " " ++ jlib:jid_to_string(jlib:make_jid(MUser, MServer, "")) 
++		       || {MUser, MServer} <- Members],
++    io:format("members:~s~n", [Members_string]),
++    
++    ?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, ["rem-rosteritem", LocalUser, LocalServer, RemoteUser, RemoteServer]) ->
++    case rem_rosteritem(LocalUser, LocalServer, RemoteUser, RemoteServer) of
++	{atomic, ok} ->
++	    ?STATUS_SUCCESS;
++	{error, Reason} ->
++	    io:format("Can't remove ~p@~p to ~p@~p: ~p~n",
++		      [RemoteUser, RemoteServer, LocalUser, LocalServer, Reason]),
++	    ?STATUS_ERROR;
++	{badrpc, Reason} ->
++	    io:format("Can't remove roster item to user ~p: ~p~n",
++		      [LocalUser, Reason]),
++	    ?STATUS_BADRPC
++    end;
++
++ctl_process(_Val, ["rosteritem-purge"]) ->
++    io:format("Rosteritems that match all the filtering will be removed.~n"),
++    io:format("Options for filtering:~n"),
++    io:format("~n"),
++    io:format("  -subs none|from|to|both~n"),
++    io:format("       Subscription type. By default all values~n"),
++    io:format("~n"),
++    io:format("  -ask none|out|in~n"),
++    io:format("       Pending subscription. By default all values~n"),
++    io:format("~n"),
++    io:format("  -user JID~n"),
++    io:format("       The JID of the local user.~n"),
++    io:format("       Can use these globs: *, ? and [...].~n"),
++    io:format("       By default it is: * *@*~n"),
++    io:format("~n"),
++    io:format("  -contact JID~n"),
++    io:format("       Similar to 'user', but for the contact JID.~n"),
++    io:format("~n"),
++    io:format("Example:~n"),
++    io:format("  ejabberdctl rosteritem-purge -subs none from to -ask out in -contact *@*icq*~n"),
++    io:format("~n"),
++    ?STATUS_SUCCESS;
++ctl_process(_Val, ["rosteritem-purge" | Options_list]) ->
++    Options_prop_list = lists:foldl(
++			  fun(O, R) ->
++				  case O of
++				      [$- | K] ->
++					  [{K, []} | R];
++				      V ->
++					  [{K, Vs} | RT] = R,
++					  [{K, [V|Vs]} | RT]
++				  end
++			  end,
++			  [],
++			  Options_list),
++    
++    Subs = [list_to_atom(S)
++	    || S <- proplists:get_value("subs", 
++					Options_prop_list, 
++					["none", "from", "to", "both"])],
++    Asks = [list_to_atom(S)
++	    || S <- 
++		   proplists:get_value("ask",
++				       Options_prop_list, 
++				       ["none", "out", "in"])],
++    User = proplists:get_value("user", Options_prop_list, ["*", "*@*"]),
++    Contact = proplists:get_value("contact", Options_prop_list, ["*", "*@*"]),
++    
++    case rosteritem_purge({Subs, Asks, User, Contact}) of
++	{atomic, ok} ->
++	    ?STATUS_SUCCESS;
++	{error, Reason} ->
++	    io:format("Error purging rosteritems: ~p~n",
++		      [Reason]),
++	    ?STATUS_ERROR;
++	{badrpc, Reason} ->
++	    io:format("BadRPC purging rosteritems: ~p~n",
++		      [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 catch ejabberd_config:load_file(Path) of
++        ok ->
++            ?STATUS_SUCCESS;
++        {'EXIT', Reason} ->
++            io:format("Problem loading 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
++	      "uptime-seconds" -> uptime_seconds();
++	      "registeredusers" -> length(ejabberd_auth:dirty_get_registered_users());
++	      "onlineusersnode" -> length(ejabberd_sm:dirty_get_my_sessions_list());
++	      "onlineusers" -> length(ejabberd_sm:dirty_get_sessions_list())
++	  end,
++    io:format("~p~n", [Res]),
++    ?STATUS_SUCCESS;
++
++ctl_process(_Val, ["status-num", Status_required]) ->
++    ctl_process(_Val, "all", ["status-num", Status_required]);
++
++ctl_process(_Val, ["status-list", Status_required]) ->
++    ctl_process(_Val, "all", ["status-list", Status_required]);
++
++ctl_process(_Val, ["get-cookie"]) ->
++    io:format("~s~n", [atom_to_list(erlang:get_cookie())]),
++    ?STATUS_SUCCESS;
++
++ctl_process(_Val, ["killsession", User, Server, Resource | Tail]) ->
++    kick_session(User, Server, Resource, prepare_reason(Tail)),
++    ?STATUS_SUCCESS;
++
++ctl_process(Val, _Args) ->
++    Val.
++
++
++%%-------------
++%% Commands vhost
++%%-------------
++
++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, ["status-num", Status_required]) ->
++    Num = length(get_status_list(Host, Status_required)),
++    io:format("~p~n", [Num]),
++    ?STATUS_SUCCESS;
++
++ctl_process(_Val, Host, ["status-list", Status_required]) ->
++    Res = get_status_list(Host, Status_required),
++    [ io:format("~s@~s ~s ~p \"~s\"~n", [U, S, R, P, St]) || {U, S, R, P, St} <- Res],
++    ?STATUS_SUCCESS;
++
++ctl_process(_Val, Host, ["ban-account", User | Tail]) ->
++    ban_account(User, Host, prepare_reason(Tail)),
++    ?STATUS_SUCCESS;
++
++ctl_process(Val, _Host, _Args) ->
++    Val.
++
++
++%%-------------
++%% Utils
++%%-------------
++
++uptime_seconds() ->
++    trunc(element(1, erlang:statistics(wall_clock))/1000).
++
++get_status_list(Host, Status_required) ->
++    %% Get list of all logged users
++    Sessions = ejabberd_sm:dirty_get_my_sessions_list(),
++    %% Reformat the list
++    Sessions2 = [ {Session#session.usr, Session#session.sid, Session#session.priority} || Session <- Sessions],
++    Fhost = case Host of
++		"all" ->
++		    %% All hosts are requested, so dont filter at all
++		    fun(_, _) -> true end;
++		_ ->
++		    %% Filter the list, only Host is interesting
++		    fun(A, B) -> A == B end
++	    end,
++    Sessions3 = [ {Pid, Server, Priority} || {{_User, Server, _Resource}, {_, Pid}, Priority} <- Sessions2, apply(Fhost, [Server, Host])],
++    %% For each Pid, get its presence
++    Sessions4 = [ {ejabberd_c2s:get_presence(Pid), Server, Priority} || {Pid, Server, Priority} <- Sessions3],
++    %% Filter by status
++    Fstatus = case Status_required of
++		  "all" ->
++		      fun(_, _) -> true end;
++		  _ ->
++		      fun(A, B) -> A == B end
++	      end,
++    [{User, Server, Resource, Priority, stringize(Status_text)} 
++     || {{User, Resource, Status, Status_text}, Server, Priority} <- Sessions4, 
++	apply(Fstatus, [Status, Status_required])].
++
++%% Make string more print-friendly
++stringize(String) ->
++    %% Replace newline characters with other code
++    element(2, regexp:gsub(String, "\n", "\\n")).
++
++add_rosteritem(LU, LS, RU, RS, Nick, Group, Subscription, Xattrs) ->
++    subscribe(LU, LS, RU, RS, Nick, Group, Subscription, Xattrs),
++    route_rosteritem(LU, LS, RU, RS, Nick, Group, Subscription),
++    {atomic, ok}.
++
++subscribe(LocalUser, LocalServer, RemoteUser, RemoteServer, Nick, Group, Subscription, Xattrs) ->
++    R = #roster{usj = {LocalUser,LocalServer,{RemoteUser,RemoteServer,[]}},
++		us = {LocalUser,LocalServer},
++		jid = {RemoteUser,RemoteServer,[]},
++		name = Nick,
++		subscription = Subscription, % none, to=you see him, from=he sees you, both
++		ask = none, % out=send request, in=somebody requests you, none
++		groups = [Group],
++		askmessage = Xattrs, % example: [{"category","conference"}]
++		xs = []},
++    mnesia:transaction(fun() -> mnesia:write(R) end).
++
++rem_rosteritem(LU, LS, RU, RS) ->
++    unsubscribe(LU, LS, RU, RS),
++    route_rosteritem(LU, LS, RU, RS, "", "", "remove"),
++    {atomic, ok}.
++
++unsubscribe(LocalUser, LocalServer, RemoteUser, RemoteServer) ->
++    Key = {{LocalUser,LocalServer,{RemoteUser,RemoteServer,[]}},
++	   {LocalUser,LocalServer}},
++    mnesia:transaction(fun() -> mnesia:delete(roster, Key, write) end).
++
++route_rosteritem(LocalUser, LocalServer, RemoteUser, RemoteServer, Nick, Group, Subscription) ->
++    LJID = jlib:make_jid(LocalUser, LocalServer, ""),
++    RJID = jlib:make_jid(RemoteUser, RemoteServer, ""),
++    ToS = jlib:jid_to_string(LJID),
++    ItemJIDS = jlib:jid_to_string(RJID),
++    GroupXML = {xmlelement, "group", [], [{xmlcdata, Group}]},
++    Item = {xmlelement, "item", 
++	    [{"jid", ItemJIDS},
++	     {"name", Nick},
++	     {"subscription", Subscription}], 
++	    [GroupXML]},
++    Query = {xmlelement, "query", [{"xmlns", ?NS_ROSTER}], [Item]},
++    Packet = {xmlelement, "iq", [{"type", "set"}, {"to", ToS}], [Query]},
++    ejabberd_router:route(LJID, LJID, Packet).
++
++
++%%-----------------------------
++%% Ban user
++%%-----------------------------
++
++ban_account(User, Server, Reason) ->
++    kick_sessions(User, Server, Reason),
++    set_random_password(User, Server, Reason).
++
++kick_sessions(User, Server, Reason) ->
++    lists:map(
++      fun(Resource) ->
++	      kick_session(User, Server, Resource, Reason)
++      end,
++      get_resources(User, Server)).
++
++kick_session(User, Server, Resource, Reason) ->
++    ejabberd_router:route(
++      jlib:make_jid("", "", ""),
++      jlib:make_jid(User, Server, Resource),
++      {xmlelement, "broadcast", [], [{exit, Reason}]}).
++
++get_resources(User, Server) ->
++    lists:map(
++      fun(Session) ->
++	      element(3, Session#session.usr)
++      end,
++      get_sessions(User, Server)).
++
++get_sessions(User, Server) ->
++    LUser = jlib:nodeprep(User),
++    LServer = jlib:nameprep(Server),
++    Sessions =  mnesia:dirty_index_read(session, {LUser, LServer}, #session.us),
++    true = is_list(Sessions),
++    Sessions.
++
++set_random_password(User, Server, Reason) ->
++    NewPass = build_random_password(Reason),
++    set_password(User, Server, NewPass).
++
++build_random_password(Reason) ->
++    Date = jlib:timestamp_to_iso(calendar:universal_time()),
++    RandomString = randoms:get_string(),
++    "BANNED_ACCOUNT--" ++ Date ++ "--" ++ RandomString ++ "--" ++ Reason.
++
++set_password(User, Server, Password) ->
++    {atomic, ok} = ejabberd_auth:set_password(User, Server, Password).
++
++prepare_reason([]) ->
++    "Kicked by administrator";
++prepare_reason([Reason]) ->
++    Reason;
++prepare_reason(StringList) ->
++    string:join(StringList, "_").
++
++
++%%-----------------------------
++%% Purge roster items
++%%-----------------------------
++
++rosteritem_purge(Options) ->
++    Num_rosteritems = mnesia:table_info(roster, size),
++    io:format("There are ~p roster items in total.~n", [Num_rosteritems]),
++    Key = mnesia:dirty_first(roster),
++    ok = rip(Key, Options, {0, Num_rosteritems, 0, 0}),
++    {atomic, ok}.
++
++rip('$end_of_table', _Options, Counters) ->
++    print_progress_line(Counters),
++    ok;
++rip(Key, Options, {Pr, NT, NV, ND}) ->
++    Key_next = mnesia:dirty_next(roster, Key),
++    ND2 = case decide_rip(Key, Options) of
++	      true ->
++		  mnesia:dirty_delete(roster, Key),
++		  ND+1;
++	      false ->
++		  ND
++	  end,
++    NV2 = NV+1,
++    Pr2 = print_progress_line({Pr, NT, NV2, ND2}),
++    rip(Key_next, Options, {Pr2, NT, NV2, ND2}).
++
++print_progress_line({Pr, NT, NV, ND}) ->
++    Pr2 = trunc((NV/NT)*100),
++    case Pr == Pr2 of
++	true ->
++	    ok;
++	false ->
++	    io:format("Progress ~p% - visited ~p - deleted ~p~n", [Pr2, NV, ND])
++    end,
++    Pr2.
++
++decide_rip(Key, {Subs, Asks, User, Contact}) ->
++    case catch mnesia:dirty_read(roster, Key) of
++	[RI] ->
++	    lists:member(RI#roster.subscription, Subs)
++		andalso lists:member(RI#roster.ask, Asks)
++		andalso decide_rip_jid(RI#roster.us, User)
++		andalso decide_rip_jid(RI#roster.jid, Contact);
++	_ ->
++	    false
++    end.
++
++%% Returns true if the server of the JID is included in the servers
++decide_rip_jid({UName, UServer, _UResource}, Match_list) ->
++    decide_rip_jid({UName, UServer}, Match_list);
++decide_rip_jid({UName, UServer}, Match_list) ->
++    lists:any(
++      fun(Match_string) ->
++	      MJID = jlib:string_to_jid(Match_string),
++	      MName = MJID#jid.luser,
++	      MServer = MJID#jid.lserver,
++	      Is_server = is_glob_match(UServer, MServer),
++	      case MName of
++		  [] when UName == [] ->
++		      Is_server;
++		  [] ->
++		      false;
++		  _ ->
++		      Is_server
++			  andalso is_glob_match(UName, MName)
++	      end
++      end,
++      Match_list).
++
++%% Copied from ejabberd-2.0.0/src/acl.erl
++is_regexp_match(String, RegExp) ->
++    case regexp:first_match(String, RegExp) of
++	nomatch ->
++	    false;
++	{match, _, _} ->
++	    true;
++	{error, ErrDesc} ->
++	    io:format(
++	      "Wrong regexp ~p in ACL: ~p",
++	      [RegExp, lists:flatten(regexp:format_error(ErrDesc))]),
++	    false
++    end.
++is_glob_match(String, Glob) ->
++    is_regexp_match(String, regexp:sh_to_awk(Glob)).
++
++
++%%-----------------------------
++%% Push Roster from file 
++%%-----------------------------
++
++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, Data) ->
++    [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}),
++    JID = jlib:make_jid(User, Server, ""),
++    IQ = #iq{type = get, xmlns = ?NS_VCARD},
++    IQr = Module:Function(JID, JID, IQ),
++    Res = case IQr#iq.sub_el of
++	      [A1] ->
++		  case vcard_get(Data, A1) of
++		      false -> no_value;
++		      Elem -> xml:get_tag_cdata(Elem)
++		  end;
++	      [] -> 
++		  no_vcard
++	  end,
++    {ok, Res}.
++
++vcard_get([Data1, Data2], A1) ->
++    case xml:get_subtag(A1, Data1) of
++    	false -> false;
++	A2 -> vcard_get([Data2], A2)
++    end;
++
++vcard_get([Data], A1) ->
++    xml:get_subtag(A1, Data).
++
++vcard_set(User, Server, Data, Content) ->
++    [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}),
++    JID = jlib:make_jid(User, Server, ""),
++    IQ = #iq{type = get, xmlns = ?NS_VCARD},
++    IQr = Module:Function(JID, JID, IQ),
++
++    %% Get old vcard
++    A4 = case IQr#iq.sub_el of
++	     [A1] ->
++		 {_, _, _, A2} = A1,
++		 update_vcard_els(Data, Content, A2);
++	     [] -> 
++		 update_vcard_els(Data, Content, [])
++	 end,
++
++    %% Build new vcard
++    SubEl = {xmlelement, "vCard", [{"xmlns","vcard-temp"}], A4},
++    IQ2 = #iq{type=set, sub_el = SubEl},
++
++    Module:Function(JID, JID, IQ2),
++    {ok, "done"}.
++
++update_vcard_els(Data, Content, Els1) ->
++    Els2 = lists:keysort(2, Els1),
++    [Data1 | Data2] = Data,
++    NewEl = case Data2 of
++		[] ->
++		    {xmlelement, Data1, [], [{xmlcdata,Content}]};
++		[D2] ->
++		    OldEl = case lists:keysearch(Data1, 2, Els2) of
++				{value, A} -> A;
++				false -> {xmlelement, Data1, [], []}
++			    end,
++		    {xmlelement, _, _, ContentOld1} = OldEl,
++		    Content2 = [{xmlelement, D2, [], [{xmlcdata,Content}]}],
++		    ContentOld2 = lists:keysort(2, ContentOld1),
++		    ContentOld3 = lists:keydelete(D2, 2, ContentOld2),
++		    ContentNew = lists:keymerge(2, Content2, ContentOld3),
++		    {xmlelement, Data1, [], ContentNew}
++	    end,
++    Els3 = lists:keydelete(Data1, 2, Els2),
++    lists:keymerge(2, [NewEl], Els3).
++
++-record(last_activity, {us, timestamp, status}).
++
++delete_older_users(Days) ->
++    %% Get the list of registered users
++    Users = ejabberd_auth:dirty_get_registered_users(),
++    delete_older_users(Days, Users).
++
++delete_older_users_vhost(Host, Days) ->
++    %% Get the list of registered users
++    Users = ejabberd_auth:get_vh_registered_users(Host),
++    delete_older_users(Days, Users).
++
++delete_older_users(Days, Users) ->
++    %% Convert older time
++    SecOlder = Days*24*60*60,
++
++    %% Get current time
++    {MegaSecs, Secs, _MicroSecs} = now(),
++    TimeStamp_now = MegaSecs * 1000000 + Secs,
++
++    %% 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 isnt
++		    [] ->
++			%% 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.
++
++group_parameters(Ps, [Char]) ->
++	{none, Grouped_Ps} = lists:foldl(
++		fun(P, {State, Res}) ->
++			case State of
++				none -> 
++					case P of
++						[Char | PTail]->
++							{building, [PTail | Res]};
++						_ ->
++							{none, [P | Res]}
++					end;
++				building -> 
++					[ResHead | ResTail] = Res,
++					case lists:last(P) of
++						Char ->
++							P2 = lists:sublist(P, length(P)-1),
++							{none, [ResHead ++ " " ++ P2 | ResTail]};
++						_ ->
++							{building, [ResHead ++ " " ++ P | ResTail]}
++					end
++			end
++		end,
++		{none, []},
++		Ps),
++	lists:reverse(Grouped_Ps).
+-- 
+1.7.3.3
+

diff --git a/ejabberd-0002-Mention-mod_ctlextra-as-an-ejabberd-module.patch b/ejabberd-0002-Mention-mod_ctlextra-as-an-ejabberd-module.patch
deleted file mode 100644
index 5d14e87..0000000
--- a/ejabberd-0002-Mention-mod_ctlextra-as-an-ejabberd-module.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From ca74de7045b7393b09b53dd02e548e76cab9c849 Mon Sep 17 00:00:00 2001
-From: Peter Lemenkov <lemenkov@gmail.com>
-Date: Tue, 16 Feb 2010 16:05:53 +0300
-Subject: [PATCH 02/10] Mention mod_ctlextra as an ejabberd module
-
-Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
----
- src/ejabberd.app |    1 +
- 1 files changed, 1 insertions(+), 0 deletions(-)
-
-diff --git a/src/ejabberd.app b/src/ejabberd.app
-index 0ebb1aa..3a8d604 100644
---- a/src/ejabberd.app
-+++ b/src/ejabberd.app
-@@ -70,6 +70,7 @@
- 	     mod_caps,
- 	     mod_configure2,
- 	     mod_configure,
-+	     mod_ctlextra,
- 	     mod_disco,
- 	     mod_echo,
- 	     mod_http_bind,
--- 
-1.7.2.1
-

diff --git a/ejabberd-0003-Fixed-delays-in-s2s-connections.patch b/ejabberd-0003-Fixed-delays-in-s2s-connections.patch
index b313ddd..4c4fd48 100644
--- a/ejabberd-0003-Fixed-delays-in-s2s-connections.patch
+++ b/ejabberd-0003-Fixed-delays-in-s2s-connections.patch
@@ -1,4 +1,4 @@
-From 9c8d1d47cf8e8ab98e8063161b04c8beabfc9ce5 Mon Sep 17 00:00:00 2001
+From cf4847224a1180836d1caee3621ff0d562e4e8a7 Mon Sep 17 00:00:00 2001
 From: Sergei Golovan <sgolovan@nes.ru>
 Date: Tue, 16 Feb 2010 16:07:37 +0300
 Subject: [PATCH 03/10] Fixed delays in s2s connections.
@@ -9,27 +9,27 @@ server is down it would be reasonable, but what happens much more often is a
 network split when the delay is inadmissible).
 ---
  src/ejabberd_s2s_in.erl  |    2 +-
- src/ejabberd_s2s_out.erl |    6 +++---
- 2 files changed, 4 insertions(+), 4 deletions(-)
+ src/ejabberd_s2s_out.erl |    5 +++--
+ 2 files changed, 4 insertions(+), 3 deletions(-)
 
 diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl
-index 56086c9..9ab58a7 100644
+index eb8c05a..0ab9d94 100644
 --- a/src/ejabberd_s2s_in.erl
 +++ b/src/ejabberd_s2s_in.erl
-@@ -367,7 +367,7 @@ stream_established({xmlstreamelement, El}, StateData) ->
-             case {ejabberd_s2s:allow_host(To, From),
+@@ -404,7 +404,7 @@ stream_established({xmlstreamelement, El}, StateData) ->
+             case {ejabberd_s2s:allow_host(LTo, LFrom),
                    lists:member(LTo, ejabberd_router:dirty_get_all_domains())} of
                  {true, true} ->
--		    ejabberd_s2s_out:terminate_if_waiting_delay(To, From),
-+		    %%ejabberd_s2s_out:terminate_if_waiting_delay(To, From),
- 		    ejabberd_s2s_out:start(To, From,
+-		    ejabberd_s2s_out:terminate_if_waiting_delay(LTo, LFrom),
++		    %%ejabberd_s2s_out:terminate_if_waiting_delay(LTo, LFrom),
+ 		    ejabberd_s2s_out:start(LTo, LFrom,
  					   {verify, self(),
  					    Key, StateData#state.streamid}),
 diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl
-index a1c6412..b8393cb 100644
+index f59e8ec..1422d3a 100644
 --- a/src/ejabberd_s2s_out.erl
 +++ b/src/ejabberd_s2s_out.erl
-@@ -91,7 +91,7 @@
+@@ -93,7 +93,7 @@
  						 [From, Host, Type])).
  -endif.
  
@@ -38,17 +38,16 @@ index a1c6412..b8393cb 100644
  
  %% We do not block on send anymore.
  -define(TCP_SEND_TIMEOUT, 15000).
-@@ -228,8 +228,8 @@ open_socket(init, StateData) ->
- 	{error, _Reason} ->
- 	    ?INFO_MSG("s2s connection: ~s -> ~s (remote server not found)",
- 		      [StateData#state.myname, StateData#state.server]),
--	    wait_before_reconnect(StateData)
--	    %%{stop, normal, StateData}
-+	    %%wait_before_reconnect(StateData)
-+	    {stop, normal, StateData}
+@@ -245,7 +245,8 @@ open_socket(init, StateData) ->
+ 		    NewStateData = StateData#state{bridge={Mod, Fun}},
+ 		    {next_state, relay_to_bridge, NewStateData};
+ 		_ ->
+-		    wait_before_reconnect(StateData)
++		    %%wait_before_reconnect(StateData)
++		    {stop, normal, StateData}
+ 	    end
      end;
  open_socket(stop, StateData) ->
-     ?INFO_MSG("s2s connection: ~s -> ~s (stopped in open socket)",
 -- 
-1.7.2.1
+1.7.3.3
 

diff --git a/ejabberd-0004-Introducing-mod_admin_extra.patch b/ejabberd-0004-Introducing-mod_admin_extra.patch
index 872e4b7..0e09141 100644
--- a/ejabberd-0004-Introducing-mod_admin_extra.patch
+++ b/ejabberd-0004-Introducing-mod_admin_extra.patch
@@ -1,4 +1,4 @@
-From a0769ced87381fa07c6845d5fda18b5e584d4ed5 Mon Sep 17 00:00:00 2001
+From 9c419c9531e16a1bafcecd3257bfc4646ebdc9d5 Mon Sep 17 00:00:00 2001
 From: Badlop <badlop@process-one.net>
 Date: Tue, 16 Feb 2010 16:12:17 +0300
 Subject: [PATCH 04/10] Introducing mod_admin_extra
@@ -17,7 +17,7 @@ https://forge.process-one.net/browse/ejabberd-modules/mod_admin_extra
  create mode 100644 src/mod_admin_extra.erl
 
 diff --git a/src/ejabberd.app b/src/ejabberd.app
-index 3a8d604..de47a0d 100644
+index 6db563c..57f8a61 100644
 --- a/src/ejabberd.app
 +++ b/src/ejabberd.app
 @@ -105,6 +105,7 @@
@@ -1314,5 +1314,5 @@ index 0000000..9f3ca14
 +is_glob_match(String, Glob) ->
 +    is_regexp_match(String, regexp:sh_to_awk(Glob)).
 -- 
-1.7.2.1
+1.7.3.3
 

diff --git a/ejabberd-0005-Fedora-specific-changes-to-ejabberdctl.patch b/ejabberd-0005-Fedora-specific-changes-to-ejabberdctl.patch
index a76471e..c4c280c 100644
--- a/ejabberd-0005-Fedora-specific-changes-to-ejabberdctl.patch
+++ b/ejabberd-0005-Fedora-specific-changes-to-ejabberdctl.patch
@@ -1,4 +1,4 @@
-From 52209eb6efd83b91d5ad49623d99c53a27ffcbe9 Mon Sep 17 00:00:00 2001
+From e5f84e1f8e62e073be61843cc124f3150e4d2206 Mon Sep 17 00:00:00 2001
 From: Peter Lemenkov <lemenkov@gmail.com>
 Date: Tue, 16 Feb 2010 16:30:05 +0300
 Subject: [PATCH 05/10] Fedora-specific changes to ejabberdctl
@@ -9,7 +9,7 @@ Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
  1 files changed, 4 insertions(+), 4 deletions(-)
 
 diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template
-index fecdecc..bceec28 100644
+index 67eafbf..1665a02 100644
 --- a/src/ejabberdctl.template
 +++ b/src/ejabberdctl.template
 @@ -9,10 +9,10 @@ ERL_MAX_ETS_TABLES=1400
@@ -44,5 +44,5 @@ index fecdecc..bceec28 100644
  done
  if [ "$ID" -eq "$EJID" ] ; then
 -- 
-1.7.2.1
+1.7.3.3
 

diff --git a/ejabberd-0006-Change-directory-to-readable-by-everyone.patch b/ejabberd-0006-Change-directory-to-readable-by-everyone.patch
deleted file mode 100644
index 0567ab7..0000000
--- a/ejabberd-0006-Change-directory-to-readable-by-everyone.patch
+++ /dev/null
@@ -1,33 +0,0 @@
-From ae241feec49dd9b9fc1355e4be37c3f8b268de87 Mon Sep 17 00:00:00 2001
-From: Peter Lemenkov <lemenkov@gmail.com>
-Date: Thu, 18 Mar 2010 14:57:21 +0300
-Subject: [PATCH 06/10] Change directory to readable by everyone
-
-This requires to suppress error messages like
-"File operation error: eacces". See rhbz #564686:
-
-https://bugzilla.redhat.com/564686
-
-Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
----
- src/ejabberdctl.template |    4 ++++
- 1 files changed, 4 insertions(+), 0 deletions(-)
-
-diff --git a/src/ejabberdctl.template b/src/ejabberdctl.template
-index bceec28..ee74650 100644
---- a/src/ejabberdctl.template
-+++ b/src/ejabberdctl.template
-@@ -355,6 +355,10 @@ wait_for_status()
-     return $status
- }
- 
-+# In order to prevent issues with "File operation error: eacces."
-+# See rhbz #564686.
-+cd /
-+
- case $ARGS in
-     ' start') start;;
-     ' debug') debug;;
--- 
-1.7.2.1
-

diff --git a/ejabberd-0006-Install-.so-objects-with-0755-permissions.patch b/ejabberd-0006-Install-.so-objects-with-0755-permissions.patch
new file mode 100644
index 0000000..4366d9b
--- /dev/null
+++ b/ejabberd-0006-Install-.so-objects-with-0755-permissions.patch
@@ -0,0 +1,26 @@
+From de49bf5543375fbccaf112bdd189a71d43acbbf0 Mon Sep 17 00:00:00 2001
+From: Peter Lemenkov <lemenkov@gmail.com>
+Date: Sat, 12 Jun 2010 14:14:52 +0400
+Subject: [PATCH 06/10] Install *.so objects with 0755 permissions
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+---
+ src/Makefile.in |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/src/Makefile.in b/src/Makefile.in
+index 4e56181..ef8a55e 100644
+--- a/src/Makefile.in
++++ b/src/Makefile.in
+@@ -236,7 +236,7 @@ install: all
+ 	#
+ 	# Binary system libraries
+ 	install -d $(SODIR)
+-	install -m 644 *.so $(SODIR)
++	install -m 755 *.so $(SODIR)
+ 	#
+ 	# Translated strings
+ 	install -d $(MSGSDIR)
+-- 
+1.7.3.3
+

diff --git a/ejabberd-0007-Install-.so-objects-with-0755-permissions.patch b/ejabberd-0007-Install-.so-objects-with-0755-permissions.patch
deleted file mode 100644
index be801ae..0000000
--- a/ejabberd-0007-Install-.so-objects-with-0755-permissions.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From c91ddeb5735d2a4cebda364df6419637679a0dbe Mon Sep 17 00:00:00 2001
-From: Peter Lemenkov <lemenkov@gmail.com>
-Date: Sat, 12 Jun 2010 14:14:52 +0400
-Subject: [PATCH 07/10] Install *.so objects with 0755 permissions
-
-Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
----
- src/Makefile.in |    2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-diff --git a/src/Makefile.in b/src/Makefile.in
-index cf600c3..c9492f3 100644
---- a/src/Makefile.in
-+++ b/src/Makefile.in
-@@ -230,7 +230,7 @@ install: all
- 	#
- 	# Binary system libraries
- 	install -d $(SODIR)
--	install -m 644 *.so $(SODIR)
-+	install -m 755 *.so $(SODIR)
- 	#
- 	# Translated strings
- 	install -d $(MSGSDIR)
--- 
-1.7.2.1
-

diff --git a/ejabberd-0007-Use-versioned-directory-for-storing-docs.patch b/ejabberd-0007-Use-versioned-directory-for-storing-docs.patch
new file mode 100644
index 0000000..ffb2ec1
--- /dev/null
+++ b/ejabberd-0007-Use-versioned-directory-for-storing-docs.patch
@@ -0,0 +1,35 @@
+From 3e1eeccdfdd315c4e660e48098cb3a8c8802f75c Mon Sep 17 00:00:00 2001
+From: Peter Lemenkov <lemenkov@gmail.com>
+Date: Sat, 12 Jun 2010 16:12:11 +0400
+Subject: [PATCH 07/10] Use versioned directory for storing docs
+
+It's also a good idea to store doc-files under the versioned directory.
+This may greatly simplify parallel installation of different versions of
+ejabbed.
+
+Note that this may be done in the other way - by changing proper field
+in the AC_INIT macro, see the explanation of the field 'tarname':
+
+http://www.gnu.org/software/autoconf/manual/html_node/Initializing-configure.html
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+---
+ src/Makefile.in |    2 +-
+ 1 files changed, 1 insertions(+), 1 deletions(-)
+
+diff --git a/src/Makefile.in b/src/Makefile.in
+index ef8a55e..d15739c 100644
+--- a/src/Makefile.in
++++ b/src/Makefile.in
+@@ -98,7 +98,7 @@ SBINDIR = $(DESTDIR)@sbindir@
+ EJABBERDDIR = $(DESTDIR)@libdir@/ejabberd
+ 
+ # /share/doc/ejabberd
+-PACKAGE_TARNAME = @PACKAGE_TARNAME@
++PACKAGE_TARNAME = @PACKAGE_TARNAME@-@PACKAGE_VERSION@
+ datarootdir = @datarootdir@
+ DOCDIR = $(DESTDIR)@docdir@
+ 
+-- 
+1.7.3.3
+

diff --git a/ejabberd-0008-Support-SASL-GSSAPI-authentication-thanks-to-Mikael-.patch b/ejabberd-0008-Support-SASL-GSSAPI-authentication-thanks-to-Mikael-.patch
new file mode 100644
index 0000000..df9055f
--- /dev/null
+++ b/ejabberd-0008-Support-SASL-GSSAPI-authentication-thanks-to-Mikael-.patch
@@ -0,0 +1,480 @@
+From 60b08ab02f17070d66558a37fae69a735bda696a Mon Sep 17 00:00:00 2001
+From: Badlop <badlop@process-one.net>
+Date: Thu, 15 Apr 2010 17:20:16 +0200
+Subject: [PATCH 08/10] Support SASL GSSAPI authentication (thanks to Mikael Magnusson)(EJAB-831)
+
+---
+ src/cyrsasl.erl           |   76 +++++++++++++++++----
+ src/cyrsasl.hrl           |   15 ++++
+ src/cyrsasl_anonymous.erl |    6 +-
+ src/cyrsasl_digest.erl    |    6 +-
+ src/cyrsasl_gssapi.erl    |  166 +++++++++++++++++++++++++++++++++++++++++++++
+ src/cyrsasl_plain.erl     |    6 +-
+ src/ejabberd_c2s.erl      |   12 +++-
+ src/ejabberd_socket.erl   |   19 +++++
+ 8 files changed, 283 insertions(+), 23 deletions(-)
+ create mode 100644 src/cyrsasl.hrl
+ create mode 100644 src/cyrsasl_gssapi.erl
+
+diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl
+index 121ef6d..ea358f0 100644
+--- a/src/cyrsasl.erl
++++ b/src/cyrsasl.erl
+@@ -30,19 +30,39 @@
+ -export([start/0,
+ 	 register_mechanism/3,
+ 	 listmech/1,
+-	 server_new/7,
++	 server_new/8,
+ 	 server_start/3,
+ 	 server_step/2]).
+ 
++-include("cyrsasl.hrl").
++-include("ejabberd.hrl").
++
++%% @type saslmechanism() = {sasl_mechanism, Mechanism, Module, Require_Plain}
++%%     Mechanism = string()
++%%     Module = atom()
++%%     Require_Plain = bool().
++%% Registry entry of a supported SASL mechanism.
++
+ -record(sasl_mechanism, {mechanism, module, require_plain_password}).
+--record(sasl_state, {service, myname, realm,
+-		     get_password, check_password, check_password_digest,
+-		     mech_mod, mech_state}).
++
++%% @type saslstate() = {sasl_state, Service, Myname, Realm, GetPassword, CheckPassword, CheckPasswordDigest, Mech_Mod, Mech_State}
++%%     Service = string()
++%%     Myname = string()
++%%     Realm = string()
++%%     GetPassword = function()
++%%     CheckPassword = function()
++%%     CheckPasswordDigest = any()
++%%     Mech_Mod = atom()
++%%     Mech_State = term().
++%% State of this process.
++
++-record(sasl_state, {service, myname,
++		     mech_mod, mech_state, params}).
+ 
+ -export([behaviour_info/1]).
+ 
+ behaviour_info(callbacks) ->
+-    [{mech_new, 4}, {mech_step, 2}];
++    [{mech_new, 1}, {mech_step, 2}];
+ behaviour_info(_Other) ->
+     undefined.
+ 
+@@ -53,8 +73,30 @@ start() ->
+     cyrsasl_plain:start([]),
+     cyrsasl_digest:start([]),
+     cyrsasl_anonymous:start([]),
++    maybe_try_start_gssapi(),
+     ok.
+ 
++maybe_try_start_gssapi() ->
++    case os:getenv("KRB5_KTNAME") of
++        false ->
++	    ok;
++        _String ->
++	    try_start_gssapi()
++    end.
++
++try_start_gssapi() ->
++    case code:load_file(esasl) of
++	{module, _Module} ->
++	    cyrsasl_gssapi:start([]);
++	{error, What} ->
++	    ?ERROR_MSG("Support for GSSAPI not started because esasl.beam was not found: ~p", [What])
++    end.
++
++%% @spec (Mechanism, Module, Require_Plain) -> true
++%%     Mechanism = string()
++%%     Module = atom()
++%%     Require_Plain = bool()
++
+ register_mechanism(Mechanism, Module, RequirePlainPassword) ->
+     ets:insert(sasl_mechanism,
+ 	       #sasl_mechanism{mechanism = Mechanism,
+@@ -113,24 +155,28 @@ listmech(Host) ->
+     filter_anonymous(Host, Mechs).
+ 
+ server_new(Service, ServerFQDN, UserRealm, _SecFlags,
+-	   GetPassword, CheckPassword, CheckPasswordDigest) ->
++	   GetPassword, CheckPassword, CheckPasswordDigest, Socket) ->
++    Params = #sasl_params{
++      host = ServerFQDN,
++      realm = UserRealm,
++      get_password = GetPassword,
++      check_password = CheckPassword,
++      check_password_digest= CheckPasswordDigest,
++      socket = Socket
++     },
++
+     #sasl_state{service = Service,
+ 		myname = ServerFQDN,
+-		realm = UserRealm,
+-		get_password = GetPassword,
+-		check_password = CheckPassword,
+-		check_password_digest= CheckPasswordDigest}.
++		params = Params}.
++
+ 
+ server_start(State, Mech, ClientIn) ->
+     case lists:member(Mech, listmech(State#sasl_state.myname)) of
+ 	true ->
+ 	    case ets:lookup(sasl_mechanism, Mech) of
+ 		[#sasl_mechanism{module = Module}] ->
+-		    {ok, MechState} = Module:mech_new(
+-					State#sasl_state.myname,
+-					State#sasl_state.get_password,
+-					State#sasl_state.check_password,
+-					State#sasl_state.check_password_digest),
++		    {ok, MechState} =
++			Module:mech_new(State#sasl_state.params),
+ 		    server_step(State#sasl_state{mech_mod = Module,
+ 						 mech_state = MechState},
+ 				ClientIn);
+diff --git a/src/cyrsasl.hrl b/src/cyrsasl.hrl
+new file mode 100644
+index 0000000..b4cc3e3
+--- /dev/null
++++ b/src/cyrsasl.hrl
+@@ -0,0 +1,15 @@
++%% @type saslparams() = {sasl_params, Host, Realm, GetPassword, CheckPassword, CheckPasswordDigest}
++%%     Host = string()
++%%     Realm = string()
++%%     GetPassword = function()
++%%     CheckPassword = function()
++%%     CheckPasswordDigest = any().
++%% Parameters for SASL.
++
++-record(sasl_params, {
++	  host,
++	  realm,
++	  get_password,
++	  check_password,
++	  check_password_digest,
++	  socket}).
+diff --git a/src/cyrsasl_anonymous.erl b/src/cyrsasl_anonymous.erl
+index 2b3ba36..2647d28 100644
+--- a/src/cyrsasl_anonymous.erl
++++ b/src/cyrsasl_anonymous.erl
+@@ -27,7 +27,9 @@
+ 
+ -module(cyrsasl_anonymous).
+ 
+--export([start/1, stop/0, mech_new/4, mech_step/2]).
++-export([start/1, stop/0, mech_new/1, mech_step/2]).
++
++-include("cyrsasl.hrl").
+ 
+ -behaviour(cyrsasl).
+ 
+@@ -40,7 +42,7 @@ start(_Opts) ->
+ stop() ->
+     ok.
+ 
+-mech_new(Host, _GetPassword, _CheckPassword, _CheckPasswordDigest) ->
++mech_new(#sasl_params{host=Host}) ->
+     {ok, #state{server = Host}}.
+ 
+ mech_step(State, _ClientIn) ->
+diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl
+index 2a7ce2a..9628137 100644
+--- a/src/cyrsasl_digest.erl
++++ b/src/cyrsasl_digest.erl
+@@ -29,10 +29,11 @@
+ 
+ -export([start/1,
+ 	 stop/0,
+-	 mech_new/4,
++	 mech_new/1,
+ 	 mech_step/2]).
+ 
+ -include("ejabberd.hrl").
++-include("cyrsasl.hrl").
+ 
+ -behaviour(cyrsasl).
+ 
+@@ -45,7 +46,8 @@ start(_Opts) ->
+ stop() ->
+     ok.
+ 
+-mech_new(Host, GetPassword, _CheckPassword, CheckPasswordDigest) ->
++mech_new(#sasl_params{host=Host, get_password=GetPassword,
++		      check_password_digest=CheckPasswordDigest}) ->
+     {ok, #state{step = 1,
+ 		nonce = randoms:get_string(),
+ 		host = Host,
+diff --git a/src/cyrsasl_gssapi.erl b/src/cyrsasl_gssapi.erl
+new file mode 100644
+index 0000000..11d9955
+--- /dev/null
++++ b/src/cyrsasl_gssapi.erl
+@@ -0,0 +1,166 @@
++%%%----------------------------------------------------------------------
++%%% File    : cyrsasl_gssapi.erl
++%%% Author  : Mikael Magnusson <mikma@users.sourceforge.net>
++%%% Purpose : GSSAPI SASL mechanism
++%%% Created : 1 June 2007 by Mikael Magnusson <mikma@users.sourceforge.net>
++%%% Id      : $Id: $
++%%%----------------------------------------------------------------------
++%%%
++%%% Copyright (C) 2007-2009  Mikael Magnusson <mikma@users.sourceforge.net>
++%%%
++%%% Permission is hereby granted, free of charge, to any person
++%%% obtaining a copy of this software and associated documentation
++%%% files (the "Software"), to deal in the Software without
++%%% restriction, including without limitation the rights to use, copy,
++%%% modify, merge, publish, distribute, sublicense, and/or sell copies
++%%% of the Software, and to permit persons to whom the Software is
++%%% furnished to do so, subject to the following conditions:
++%%%
++%%% The above copyright notice and this permission notice shall be
++%%% included in all copies or substantial portions of the Software.
++%%%
++%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
++%%% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
++%%% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
++%%% NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
++%%% BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
++%%% ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
++%%% CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
++%%% SOFTWARE.
++%%%
++
++%%%
++%%% configuration options:
++%%% {sasl_realm, "<Kerberos realm>"}.
++%%%
++%%% environment variables:
++%%% KRB5_KTNAME
++%%%
++
++-module(cyrsasl_gssapi).
++-author('mikma@users.sourceforge.net').
++-vsn('$Revision: $ ').
++
++-export([start/1,
++	 stop/0,
++	 mech_new/1,
++	 mech_step/2]).
++
++-include("ejabberd.hrl").
++-include("cyrsasl.hrl").
++
++-behaviour(cyrsasl).
++
++-define(SERVER, ?MODULE).
++-define(SERVICE, "xmpp").
++
++-record(state, {sasl,
++		needsmore=true,
++		step=0,
++		host,
++		realm,
++		authid,
++		authzid,
++		authrealm,
++		error}).
++
++start(_Opts) ->
++    ChildSpec =
++	{?SERVER,
++	 {esasl, start_link, [{local, ?SERVER}]},
++	 transient,
++	 1000,
++	 worker,
++	 [esasl]},
++
++    case supervisor:start_child(ejabberd_sup, ChildSpec) of
++	{ok, _Pid} ->
++	    cyrsasl:register_mechanism("GSSAPI", ?MODULE, false);
++	{error, Error} = E ->
++	    ?ERROR_MSG("esasl failed: ~p", [Error]),
++	    E
++    end.
++
++
++stop() ->
++    catch esasl:stop(?SERVER),
++    supervisor:terminate_child(ejabberd_sup, ?SERVER),
++    supervisor:delete_child(ejabberd_sup, ?SERVER).
++
++mech_new(#sasl_params{host=Host, realm=Realm, socket=Socket}) ->
++    case ejabberd_socket:gethostname(Socket) of
++	{ok, FQDN} ->
++	    ?DEBUG("mech_new ~p ~p ~p~n", [Host, Realm, FQDN]),
++	    case esasl:server_start(?SERVER, "GSSAPI", ?SERVICE, FQDN) of
++		{ok, Sasl} ->
++		    {ok, #state{sasl=Sasl,host=Host,realm=Realm}};
++		{error, {gsasl_error, Error}} ->
++		    {ok, Str} = esasl:str_error(?SERVER, Error),
++		    ?DEBUG("esasl error: ~p", [Str]),
++		    {ok, #state{needsmore=error,error="internal-server-error"}};
++		{error, Error} ->
++		    ?DEBUG("esasl error: ~p", [Error]),
++		    {ok, #state{needsmore=error,error="internal-server-error"}}
++	    end;
++	{error, Error} ->
++	    ?DEBUG("gethostname error: ~p", [Error]),
++	    {ok, #state{needsmore=error,error="internal-server-error"}}
++    end.
++
++mech_step(State, ClientIn) when is_list(ClientIn) ->
++    catch do_step(State, ClientIn).
++
++do_step(#state{needsmore=error,error=Error}=_State, _) ->
++    {error, Error};
++do_step(#state{needsmore=false}=State, _) ->
++    check_user(State);
++do_step(#state{needsmore=true,sasl=Sasl,step=Step}=State, ClientIn) ->
++    ?DEBUG("mech_step~n", []),
++    case esasl:step(Sasl, list_to_binary(ClientIn)) of
++	{ok, RspAuth} ->
++	    ?DEBUG("ok~n", []),
++	    {ok, Display_name} = esasl:property_get(Sasl, gssapi_display_name),
++	    {ok, Authzid} = esasl:property_get(Sasl, authzid),
++	    {Authid, [$@ | Auth_realm]} =
++		lists:splitwith(fun(E)->E =/= $@ end, Display_name),
++	    State1 = State#state{authid=Authid,
++				 authzid=Authzid,
++				 authrealm=Auth_realm},
++	    handle_step_ok(State1, binary_to_list(RspAuth));
++	{needsmore, RspAuth} ->
++	    ?DEBUG("needsmore~n", []),
++	    if (Step > 0) and (ClientIn =:= []) and (RspAuth =:= <<>>) ->
++		    {error, "not-authorized"};
++		true ->
++		    {continue, binary_to_list(RspAuth),
++		     State#state{step=Step+1}}
++	    end;
++	{error, _} ->
++	    {error, "not-authorized"}
++    end.
++
++handle_step_ok(State, []) ->
++    check_user(State);
++handle_step_ok(#state{step=Step}=State, RspAuth) ->
++    ?DEBUG("continue~n", []),
++    {continue, RspAuth, State#state{needsmore=false,step=Step+1}}.
++
++check_user(#state{authid=Authid,authzid=Authzid,
++		  authrealm=Auth_realm,host=Host,realm=Realm}) ->
++    if Realm =/= Auth_realm ->
++	    ?DEBUG("bad realm ~p (expected ~p)~n",[Auth_realm, Realm]),
++	    throw({error, "not-authorized"});
++       true ->
++	    ok
++    end,
++
++    case ejabberd_auth:is_user_exists(Authid, Host) of
++	false ->
++	    ?DEBUG("bad user ~p~n",[Authid]),
++	    throw({error, "not-authorized"});
++	true ->
++	    ok
++    end,
++
++    ?DEBUG("GSSAPI authenticated ~p ~p~n", [Authid, Authzid]),
++    {ok, [{username, Authid}, {authzid, Authzid}]}.
+diff --git a/src/cyrsasl_plain.erl b/src/cyrsasl_plain.erl
+index 129fb8b..4799a41 100644
+--- a/src/cyrsasl_plain.erl
++++ b/src/cyrsasl_plain.erl
+@@ -27,7 +27,9 @@
+ -module(cyrsasl_plain).
+ -author('alexey@process-one.net').
+ 
+--export([start/1, stop/0, mech_new/4, mech_step/2, parse/1]).
++-export([start/1, stop/0, mech_new/1, mech_step/2, parse/1]).
++
++-include("cyrsasl.hrl").
+ 
+ -behaviour(cyrsasl).
+ 
+@@ -40,7 +42,7 @@ start(_Opts) ->
+ stop() ->
+     ok.
+ 
+-mech_new(_Host, _GetPassword, CheckPassword, _CheckPasswordDigest) ->
++mech_new(#sasl_params{check_password = CheckPassword}) ->
+     {ok, #state{check_password = CheckPassword}}.
+ 
+ mech_step(State, ClientIn) ->
+diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
+index 6dbcd77..8818cfe 100644
+--- a/src/ejabberd_c2s.erl
++++ b/src/ejabberd_c2s.erl
+@@ -305,9 +305,16 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
+ 			    send_header(StateData, Server, "1.0", DefaultLang),
+ 			    case StateData#state.authenticated of
+ 				false ->
++				    Realm =
++					case ejabberd_config:get_local_option({sasl_realm, Server}) of
++					    undefined ->
++						"";
++					    Realm0 ->
++						Realm0
++					end,
+ 				    SASLState =
+ 					cyrsasl:server_new(
+-					  "jabber", Server, "", [],
++					  "jabber", Server, Realm, [],
+ 					  fun(U) ->
+ 						  ejabberd_auth:get_password_with_authmodule(
+ 						    U, Server)
+@@ -319,7 +326,8 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
+ 					  fun(U, P, D, DG) ->
+ 						  ejabberd_auth:check_password_with_authmodule(
+ 						    U, Server, P, D, DG)
+-					  end),
++					  end,
++					  StateData#state.socket),
+ 				    Mechs = lists:map(
+ 					      fun(S) ->
+ 						      {xmlelement, "mechanism", [],
+diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl
+index 4d21e40..66b9c4c 100644
+--- a/src/ejabberd_socket.erl
++++ b/src/ejabberd_socket.erl
+@@ -44,9 +44,11 @@
+ 	 get_peer_certificate/1,
+ 	 get_verify_result/1,
+ 	 close/1,
++	 gethostname/1,
+ 	 sockname/1, peername/1]).
+ 
+ -include("ejabberd.hrl").
++-include_lib("kernel/include/inet.hrl").
+ 
+ -record(socket_state, {sockmod, socket, receiver}).
+ 
+@@ -228,6 +230,23 @@ peername(#socket_state{sockmod = SockMod, socket = Socket}) ->
+ 	    SockMod:peername(Socket)
+     end.
+ 
++gethostname(#socket_state{socket = Socket} = State) ->
++    ?DEBUG("gethostname ~p~n", [Socket]),
++
++    case sockname(State) of
++	{ok, {Addr, _Port}} ->
++	    case inet:gethostbyaddr(Addr) of
++		{ok, HostEnt} when is_record(HostEnt, hostent) ->
++		    ?DEBUG("gethostname result ~p~n",
++			   [HostEnt#hostent.h_name]),
++		    {ok, HostEnt#hostent.h_name};
++		{error, _Reason} = E ->
++		    E
++	    end;
++	{error, _Reason} = E ->
++	    E
++    end.
++
+ %%====================================================================
+ %% Internal functions
+ %%====================================================================
+-- 
+1.7.3.3
+

diff --git a/ejabberd-0008-Use-versioned-directory-for-storing-docs.patch b/ejabberd-0008-Use-versioned-directory-for-storing-docs.patch
deleted file mode 100644
index 4ea23bc..0000000
--- a/ejabberd-0008-Use-versioned-directory-for-storing-docs.patch
+++ /dev/null
@@ -1,35 +0,0 @@
-From 55622d1af9b27028219257ed7e5583c607a91d2e Mon Sep 17 00:00:00 2001
-From: Peter Lemenkov <lemenkov@gmail.com>
-Date: Sat, 12 Jun 2010 16:12:11 +0400
-Subject: [PATCH 08/10] Use versioned directory for storing docs
-
-It's also a good idea to store doc-files under the versioned directory.
-This may greatly simplify parallel installation of different versions of
-ejabbed.
-
-Note that this may be done in the other way - by changing proper field
-in the AC_INIT macro, see the explanation of the field 'tarname':
-
-http://www.gnu.org/software/autoconf/manual/html_node/Initializing-configure.html
-
-Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
----
- src/Makefile.in |    2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-diff --git a/src/Makefile.in b/src/Makefile.in
-index c9492f3..7b585d0 100644
---- a/src/Makefile.in
-+++ b/src/Makefile.in
-@@ -92,7 +92,7 @@ SBINDIR = $(DESTDIR)@sbindir@
- EJABBERDDIR = $(DESTDIR)@libdir@/ejabberd
- 
- # /share/doc/ejabberd
--PACKAGE_TARNAME = @PACKAGE_TARNAME@
-+PACKAGE_TARNAME = @PACKAGE_TARNAME@-@PACKAGE_VERSION@
- datarootdir = @datarootdir@
- DOCDIR = $(DESTDIR)@docdir@
- 
--- 
-1.7.2.1
-

diff --git a/ejabberd-0009-Added-old-modules-for-Active-Directory.patch b/ejabberd-0009-Added-old-modules-for-Active-Directory.patch
new file mode 100644
index 0000000..1261b98
--- /dev/null
+++ b/ejabberd-0009-Added-old-modules-for-Active-Directory.patch
@@ -0,0 +1,1266 @@
+From c28b04f3abf3a4e233115c3d783db356c9567d9b Mon Sep 17 00:00:00 2001
+From: Peter Lemenkov <lemenkov@gmail.com>
+Date: Tue, 14 Dec 2010 18:28:44 +0300
+Subject: [PATCH 09/10] Added old modules for Active Directory
+
+These modules were extracted from a patch found on
+http://realloc.spb.ru/share/ejabberdad.html
+
+Please, note that these are unmaintained and will be removed very
+soon (users should use *_ldap.erl instead).
+---
+ src/ejabberd_auth_ad.erl     |  167 +++++++++++
+ src/mod_shared_roster_ad.erl |  428 ++++++++++++++++++++++++++++
+ src/mod_vcard_ad.erl         |  631 ++++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 1226 insertions(+), 0 deletions(-)
+ create mode 100644 src/ejabberd_auth_ad.erl
+ create mode 100644 src/mod_shared_roster_ad.erl
+ create mode 100644 src/mod_vcard_ad.erl
+
+diff --git a/src/ejabberd_auth_ad.erl b/src/ejabberd_auth_ad.erl
+new file mode 100644
+index 0000000..5e9e452
+--- /dev/null
++++ b/src/ejabberd_auth_ad.erl
+@@ -0,0 +1,167 @@
++%%%----------------------------------------------------------------------
++%%% File    : ejabberd_auth_ad.erl
++%%% Author  : Alexey Shchepin <alexey@sevcom.net>
++%%% Author  : Alex Gorbachenko <agent_007@immo.ru>
++%%% Author  : Stanislav Bogatyrev <realloc@realloc.spb.ru>
++%%% Purpose : Authentification via Active Directory
++%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@sevcom.net>
++%%% Id      : $Id: ejabberd_auth_ad.erl 386 2005-12-20 10:06:37Z agent_007 $
++%%%----------------------------------------------------------------------
++
++-module(ejabberd_auth_ad).
++-author('alexey@sevcom.net').
++-author('agent_007@immo.ru').
++-author('realloc@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)).
+diff --git a/src/mod_shared_roster_ad.erl b/src/mod_shared_roster_ad.erl
+new file mode 100644
+index 0000000..8dc09f1
+--- /dev/null
++++ b/src/mod_shared_roster_ad.erl
+@@ -0,0 +1,428 @@
++%%%----------------------------------------------------------------------
++%%% File    : mod_shared_roster.erl
++%%% Author  : Alexey Shchepin <alexey@sevcom.net>
++%%% Author  : Stanislav Bogatyrev <realloc@realloc.spb.ru>
++%%% Purpose : Shared roster management
++%%% Created :  5 Mar 2005 by Alexey Shchepin <alexey@sevcom.net>
++%%% Id      : $Id: mod_shared_roster_ad.erl,v 1.1 2006/06/23 12:40:03 jcollie Exp $
++%%%----------------------------------------------------------------------
++
++-module(mod_shared_roster_ad).
++-author('alexey@sevcom.net').
++-author('realloc@realloc.spb.ru').
++-vsn('$Revision: 1.1 $ ').
++
++-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.
++
++
+diff --git a/src/mod_vcard_ad.erl b/src/mod_vcard_ad.erl
+new file mode 100644
+index 0000000..52ddbec
+--- /dev/null
++++ b/src/mod_vcard_ad.erl
+@@ -0,0 +1,631 @@
++
++%%%----------------------------------------------------------------------
++%%% File    : mod_vcard_ad.erl
++%%% Author  : Stanislav Bogatyrev <realloc@realloc.spb.ru>
++%%% Author  : Alexey Shchepin <alexey@sevcom.net>
++%%% Author  : Alex <agent_007> Gorbachenko (agent_007@immo.ru)
++%%% Purpose : 
++%%% Created :  2 Jan 2003 by Alexey Shchepin <alexey@sevcom.net>
++%%% Id      : $Id: mod_vcard_ad.erl 437 2005-11-19 01:20:05Z agent_007 $
++%%%----------------------------------------------------------------------
++
++-module(mod_vcard_ad).
++-author('realloc@realloc.spb.ru').
++-author('alexey@sevcom.net').
++-author('agent_007@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.
++
+-- 
+1.7.3.3
+

diff --git a/ejabberd-0009-Support-SASL-GSSAPI-authentication-thanks-to-Mikael-.patch b/ejabberd-0009-Support-SASL-GSSAPI-authentication-thanks-to-Mikael-.patch
deleted file mode 100644
index 435d503..0000000
--- a/ejabberd-0009-Support-SASL-GSSAPI-authentication-thanks-to-Mikael-.patch
+++ /dev/null
@@ -1,480 +0,0 @@
-From 6b258db9aba30218c2d651c2c656bdfce39c48a9 Mon Sep 17 00:00:00 2001
-From: Badlop <badlop@process-one.net>
-Date: Thu, 15 Apr 2010 17:20:16 +0200
-Subject: [PATCH 09/10] Support SASL GSSAPI authentication (thanks to Mikael Magnusson)(EJAB-831)
-
----
- src/cyrsasl.erl           |   76 +++++++++++++++++----
- src/cyrsasl.hrl           |   15 ++++
- src/cyrsasl_anonymous.erl |    6 +-
- src/cyrsasl_digest.erl    |    6 +-
- src/cyrsasl_gssapi.erl    |  166 +++++++++++++++++++++++++++++++++++++++++++++
- src/cyrsasl_plain.erl     |    6 +-
- src/ejabberd_c2s.erl      |   12 +++-
- src/ejabberd_socket.erl   |   19 +++++
- 8 files changed, 283 insertions(+), 23 deletions(-)
- create mode 100644 src/cyrsasl.hrl
- create mode 100644 src/cyrsasl_gssapi.erl
-
-diff --git a/src/cyrsasl.erl b/src/cyrsasl.erl
-index 121ef6d..ea358f0 100644
---- a/src/cyrsasl.erl
-+++ b/src/cyrsasl.erl
-@@ -30,19 +30,39 @@
- -export([start/0,
- 	 register_mechanism/3,
- 	 listmech/1,
--	 server_new/7,
-+	 server_new/8,
- 	 server_start/3,
- 	 server_step/2]).
- 
-+-include("cyrsasl.hrl").
-+-include("ejabberd.hrl").
-+
-+%% @type saslmechanism() = {sasl_mechanism, Mechanism, Module, Require_Plain}
-+%%     Mechanism = string()
-+%%     Module = atom()
-+%%     Require_Plain = bool().
-+%% Registry entry of a supported SASL mechanism.
-+
- -record(sasl_mechanism, {mechanism, module, require_plain_password}).
---record(sasl_state, {service, myname, realm,
--		     get_password, check_password, check_password_digest,
--		     mech_mod, mech_state}).
-+
-+%% @type saslstate() = {sasl_state, Service, Myname, Realm, GetPassword, CheckPassword, CheckPasswordDigest, Mech_Mod, Mech_State}
-+%%     Service = string()
-+%%     Myname = string()
-+%%     Realm = string()
-+%%     GetPassword = function()
-+%%     CheckPassword = function()
-+%%     CheckPasswordDigest = any()
-+%%     Mech_Mod = atom()
-+%%     Mech_State = term().
-+%% State of this process.
-+
-+-record(sasl_state, {service, myname,
-+		     mech_mod, mech_state, params}).
- 
- -export([behaviour_info/1]).
- 
- behaviour_info(callbacks) ->
--    [{mech_new, 4}, {mech_step, 2}];
-+    [{mech_new, 1}, {mech_step, 2}];
- behaviour_info(_Other) ->
-     undefined.
- 
-@@ -53,8 +73,30 @@ start() ->
-     cyrsasl_plain:start([]),
-     cyrsasl_digest:start([]),
-     cyrsasl_anonymous:start([]),
-+    maybe_try_start_gssapi(),
-     ok.
- 
-+maybe_try_start_gssapi() ->
-+    case os:getenv("KRB5_KTNAME") of
-+        false ->
-+	    ok;
-+        _String ->
-+	    try_start_gssapi()
-+    end.
-+
-+try_start_gssapi() ->
-+    case code:load_file(esasl) of
-+	{module, _Module} ->
-+	    cyrsasl_gssapi:start([]);
-+	{error, What} ->
-+	    ?ERROR_MSG("Support for GSSAPI not started because esasl.beam was not found: ~p", [What])
-+    end.
-+
-+%% @spec (Mechanism, Module, Require_Plain) -> true
-+%%     Mechanism = string()
-+%%     Module = atom()
-+%%     Require_Plain = bool()
-+
- register_mechanism(Mechanism, Module, RequirePlainPassword) ->
-     ets:insert(sasl_mechanism,
- 	       #sasl_mechanism{mechanism = Mechanism,
-@@ -113,24 +155,28 @@ listmech(Host) ->
-     filter_anonymous(Host, Mechs).
- 
- server_new(Service, ServerFQDN, UserRealm, _SecFlags,
--	   GetPassword, CheckPassword, CheckPasswordDigest) ->
-+	   GetPassword, CheckPassword, CheckPasswordDigest, Socket) ->
-+    Params = #sasl_params{
-+      host = ServerFQDN,
-+      realm = UserRealm,
-+      get_password = GetPassword,
-+      check_password = CheckPassword,
-+      check_password_digest= CheckPasswordDigest,
-+      socket = Socket
-+     },
-+
-     #sasl_state{service = Service,
- 		myname = ServerFQDN,
--		realm = UserRealm,
--		get_password = GetPassword,
--		check_password = CheckPassword,
--		check_password_digest= CheckPasswordDigest}.
-+		params = Params}.
-+
- 
- server_start(State, Mech, ClientIn) ->
-     case lists:member(Mech, listmech(State#sasl_state.myname)) of
- 	true ->
- 	    case ets:lookup(sasl_mechanism, Mech) of
- 		[#sasl_mechanism{module = Module}] ->
--		    {ok, MechState} = Module:mech_new(
--					State#sasl_state.myname,
--					State#sasl_state.get_password,
--					State#sasl_state.check_password,
--					State#sasl_state.check_password_digest),
-+		    {ok, MechState} =
-+			Module:mech_new(State#sasl_state.params),
- 		    server_step(State#sasl_state{mech_mod = Module,
- 						 mech_state = MechState},
- 				ClientIn);
-diff --git a/src/cyrsasl.hrl b/src/cyrsasl.hrl
-new file mode 100644
-index 0000000..b4cc3e3
---- /dev/null
-+++ b/src/cyrsasl.hrl
-@@ -0,0 +1,15 @@
-+%% @type saslparams() = {sasl_params, Host, Realm, GetPassword, CheckPassword, CheckPasswordDigest}
-+%%     Host = string()
-+%%     Realm = string()
-+%%     GetPassword = function()
-+%%     CheckPassword = function()
-+%%     CheckPasswordDigest = any().
-+%% Parameters for SASL.
-+
-+-record(sasl_params, {
-+	  host,
-+	  realm,
-+	  get_password,
-+	  check_password,
-+	  check_password_digest,
-+	  socket}).
-diff --git a/src/cyrsasl_anonymous.erl b/src/cyrsasl_anonymous.erl
-index 2b3ba36..2647d28 100644
---- a/src/cyrsasl_anonymous.erl
-+++ b/src/cyrsasl_anonymous.erl
-@@ -27,7 +27,9 @@
- 
- -module(cyrsasl_anonymous).
- 
---export([start/1, stop/0, mech_new/4, mech_step/2]).
-+-export([start/1, stop/0, mech_new/1, mech_step/2]).
-+
-+-include("cyrsasl.hrl").
- 
- -behaviour(cyrsasl).
- 
-@@ -40,7 +42,7 @@ start(_Opts) ->
- stop() ->
-     ok.
- 
--mech_new(Host, _GetPassword, _CheckPassword, _CheckPasswordDigest) ->
-+mech_new(#sasl_params{host=Host}) ->
-     {ok, #state{server = Host}}.
- 
- mech_step(State, _ClientIn) ->
-diff --git a/src/cyrsasl_digest.erl b/src/cyrsasl_digest.erl
-index 2a7ce2a..9628137 100644
---- a/src/cyrsasl_digest.erl
-+++ b/src/cyrsasl_digest.erl
-@@ -29,10 +29,11 @@
- 
- -export([start/1,
- 	 stop/0,
--	 mech_new/4,
-+	 mech_new/1,
- 	 mech_step/2]).
- 
- -include("ejabberd.hrl").
-+-include("cyrsasl.hrl").
- 
- -behaviour(cyrsasl).
- 
-@@ -45,7 +46,8 @@ start(_Opts) ->
- stop() ->
-     ok.
- 
--mech_new(Host, GetPassword, _CheckPassword, CheckPasswordDigest) ->
-+mech_new(#sasl_params{host=Host, get_password=GetPassword,
-+		      check_password_digest=CheckPasswordDigest}) ->
-     {ok, #state{step = 1,
- 		nonce = randoms:get_string(),
- 		host = Host,
-diff --git a/src/cyrsasl_gssapi.erl b/src/cyrsasl_gssapi.erl
-new file mode 100644
-index 0000000..11d9955
---- /dev/null
-+++ b/src/cyrsasl_gssapi.erl
-@@ -0,0 +1,166 @@
-+%%%----------------------------------------------------------------------
-+%%% File    : cyrsasl_gssapi.erl
-+%%% Author  : Mikael Magnusson <mikma@users.sourceforge.net>
-+%%% Purpose : GSSAPI SASL mechanism
-+%%% Created : 1 June 2007 by Mikael Magnusson <mikma@users.sourceforge.net>
-+%%% Id      : $Id: $
-+%%%----------------------------------------------------------------------
-+%%%
-+%%% Copyright (C) 2007-2009  Mikael Magnusson <mikma@users.sourceforge.net>
-+%%%
-+%%% Permission is hereby granted, free of charge, to any person
-+%%% obtaining a copy of this software and associated documentation
-+%%% files (the "Software"), to deal in the Software without
-+%%% restriction, including without limitation the rights to use, copy,
-+%%% modify, merge, publish, distribute, sublicense, and/or sell copies
-+%%% of the Software, and to permit persons to whom the Software is
-+%%% furnished to do so, subject to the following conditions:
-+%%%
-+%%% The above copyright notice and this permission notice shall be
-+%%% included in all copies or substantial portions of the Software.
-+%%%
-+%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-+%%% EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-+%%% MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-+%%% NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
-+%%% BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
-+%%% ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
-+%%% CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-+%%% SOFTWARE.
-+%%%
-+
-+%%%
-+%%% configuration options:
-+%%% {sasl_realm, "<Kerberos realm>"}.
-+%%%
-+%%% environment variables:
-+%%% KRB5_KTNAME
-+%%%
-+
-+-module(cyrsasl_gssapi).
-+-author('mikma@users.sourceforge.net').
-+-vsn('$Revision: $ ').
-+
-+-export([start/1,
-+	 stop/0,
-+	 mech_new/1,
-+	 mech_step/2]).
-+
-+-include("ejabberd.hrl").
-+-include("cyrsasl.hrl").
-+
-+-behaviour(cyrsasl).
-+
-+-define(SERVER, ?MODULE).
-+-define(SERVICE, "xmpp").
-+
-+-record(state, {sasl,
-+		needsmore=true,
-+		step=0,
-+		host,
-+		realm,
-+		authid,
-+		authzid,
-+		authrealm,
-+		error}).
-+
-+start(_Opts) ->
-+    ChildSpec =
-+	{?SERVER,
-+	 {esasl, start_link, [{local, ?SERVER}]},
-+	 transient,
-+	 1000,
-+	 worker,
-+	 [esasl]},
-+
-+    case supervisor:start_child(ejabberd_sup, ChildSpec) of
-+	{ok, _Pid} ->
-+	    cyrsasl:register_mechanism("GSSAPI", ?MODULE, false);
-+	{error, Error} = E ->
-+	    ?ERROR_MSG("esasl failed: ~p", [Error]),
-+	    E
-+    end.
-+
-+
-+stop() ->
-+    catch esasl:stop(?SERVER),
-+    supervisor:terminate_child(ejabberd_sup, ?SERVER),
-+    supervisor:delete_child(ejabberd_sup, ?SERVER).
-+
-+mech_new(#sasl_params{host=Host, realm=Realm, socket=Socket}) ->
-+    case ejabberd_socket:gethostname(Socket) of
-+	{ok, FQDN} ->
-+	    ?DEBUG("mech_new ~p ~p ~p~n", [Host, Realm, FQDN]),
-+	    case esasl:server_start(?SERVER, "GSSAPI", ?SERVICE, FQDN) of
-+		{ok, Sasl} ->
-+		    {ok, #state{sasl=Sasl,host=Host,realm=Realm}};
-+		{error, {gsasl_error, Error}} ->
-+		    {ok, Str} = esasl:str_error(?SERVER, Error),
-+		    ?DEBUG("esasl error: ~p", [Str]),
-+		    {ok, #state{needsmore=error,error="internal-server-error"}};
-+		{error, Error} ->
-+		    ?DEBUG("esasl error: ~p", [Error]),
-+		    {ok, #state{needsmore=error,error="internal-server-error"}}
-+	    end;
-+	{error, Error} ->
-+	    ?DEBUG("gethostname error: ~p", [Error]),
-+	    {ok, #state{needsmore=error,error="internal-server-error"}}
-+    end.
-+
-+mech_step(State, ClientIn) when is_list(ClientIn) ->
-+    catch do_step(State, ClientIn).
-+
-+do_step(#state{needsmore=error,error=Error}=_State, _) ->
-+    {error, Error};
-+do_step(#state{needsmore=false}=State, _) ->
-+    check_user(State);
-+do_step(#state{needsmore=true,sasl=Sasl,step=Step}=State, ClientIn) ->
-+    ?DEBUG("mech_step~n", []),
-+    case esasl:step(Sasl, list_to_binary(ClientIn)) of
-+	{ok, RspAuth} ->
-+	    ?DEBUG("ok~n", []),
-+	    {ok, Display_name} = esasl:property_get(Sasl, gssapi_display_name),
-+	    {ok, Authzid} = esasl:property_get(Sasl, authzid),
-+	    {Authid, [$@ | Auth_realm]} =
-+		lists:splitwith(fun(E)->E =/= $@ end, Display_name),
-+	    State1 = State#state{authid=Authid,
-+				 authzid=Authzid,
-+				 authrealm=Auth_realm},
-+	    handle_step_ok(State1, binary_to_list(RspAuth));
-+	{needsmore, RspAuth} ->
-+	    ?DEBUG("needsmore~n", []),
-+	    if (Step > 0) and (ClientIn =:= []) and (RspAuth =:= <<>>) ->
-+		    {error, "not-authorized"};
-+		true ->
-+		    {continue, binary_to_list(RspAuth),
-+		     State#state{step=Step+1}}
-+	    end;
-+	{error, _} ->
-+	    {error, "not-authorized"}
-+    end.
-+
-+handle_step_ok(State, []) ->
-+    check_user(State);
-+handle_step_ok(#state{step=Step}=State, RspAuth) ->
-+    ?DEBUG("continue~n", []),
-+    {continue, RspAuth, State#state{needsmore=false,step=Step+1}}.
-+
-+check_user(#state{authid=Authid,authzid=Authzid,
-+		  authrealm=Auth_realm,host=Host,realm=Realm}) ->
-+    if Realm =/= Auth_realm ->
-+	    ?DEBUG("bad realm ~p (expected ~p)~n",[Auth_realm, Realm]),
-+	    throw({error, "not-authorized"});
-+       true ->
-+	    ok
-+    end,
-+
-+    case ejabberd_auth:is_user_exists(Authid, Host) of
-+	false ->
-+	    ?DEBUG("bad user ~p~n",[Authid]),
-+	    throw({error, "not-authorized"});
-+	true ->
-+	    ok
-+    end,
-+
-+    ?DEBUG("GSSAPI authenticated ~p ~p~n", [Authid, Authzid]),
-+    {ok, [{username, Authid}, {authzid, Authzid}]}.
-diff --git a/src/cyrsasl_plain.erl b/src/cyrsasl_plain.erl
-index 129fb8b..4799a41 100644
---- a/src/cyrsasl_plain.erl
-+++ b/src/cyrsasl_plain.erl
-@@ -27,7 +27,9 @@
- -module(cyrsasl_plain).
- -author('alexey@process-one.net').
- 
---export([start/1, stop/0, mech_new/4, mech_step/2, parse/1]).
-+-export([start/1, stop/0, mech_new/1, mech_step/2, parse/1]).
-+
-+-include("cyrsasl.hrl").
- 
- -behaviour(cyrsasl).
- 
-@@ -40,7 +42,7 @@ start(_Opts) ->
- stop() ->
-     ok.
- 
--mech_new(_Host, _GetPassword, CheckPassword, _CheckPasswordDigest) ->
-+mech_new(#sasl_params{check_password = CheckPassword}) ->
-     {ok, #state{check_password = CheckPassword}}.
- 
- mech_step(State, ClientIn) ->
-diff --git a/src/ejabberd_c2s.erl b/src/ejabberd_c2s.erl
-index d4b6809..3e0a49c 100644
---- a/src/ejabberd_c2s.erl
-+++ b/src/ejabberd_c2s.erl
-@@ -254,9 +254,16 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
- 			    send_header(StateData, Server, "1.0", DefaultLang),
- 			    case StateData#state.authenticated of
- 				false ->
-+				    Realm =
-+					case ejabberd_config:get_local_option({sasl_realm, Server}) of
-+					    undefined ->
-+						"";
-+					    Realm0 ->
-+						Realm0
-+					end,
- 				    SASLState =
- 					cyrsasl:server_new(
--					  "jabber", Server, "", [],
-+					  "jabber", Server, Realm, [],
- 					  fun(U) ->
- 						  ejabberd_auth:get_password_with_authmodule(
- 						    U, Server)
-@@ -268,7 +275,8 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
- 					  fun(U, P, D, DG) ->
- 						  ejabberd_auth:check_password_with_authmodule(
- 						    U, Server, P, D, DG)
--					  end),
-+					  end,
-+					  StateData#state.socket),
- 				    Mechs = lists:map(
- 					      fun(S) ->
- 						      {xmlelement, "mechanism", [],
-diff --git a/src/ejabberd_socket.erl b/src/ejabberd_socket.erl
-index 25ff64c..e8c5fca 100644
---- a/src/ejabberd_socket.erl
-+++ b/src/ejabberd_socket.erl
-@@ -44,9 +44,11 @@
- 	 get_peer_certificate/1,
- 	 get_verify_result/1,
- 	 close/1,
-+	 gethostname/1,
- 	 sockname/1, peername/1]).
- 
- -include("ejabberd.hrl").
-+-include_lib("kernel/include/inet.hrl").
- 
- -record(socket_state, {sockmod, socket, receiver}).
- 
-@@ -222,6 +224,23 @@ peername(#socket_state{sockmod = SockMod, socket = Socket}) ->
- 	    SockMod:peername(Socket)
-     end.
- 
-+gethostname(#socket_state{socket = Socket} = State) ->
-+    ?DEBUG("gethostname ~p~n", [Socket]),
-+
-+    case sockname(State) of
-+	{ok, {Addr, _Port}} ->
-+	    case inet:gethostbyaddr(Addr) of
-+		{ok, HostEnt} when is_record(HostEnt, hostent) ->
-+		    ?DEBUG("gethostname result ~p~n",
-+			   [HostEnt#hostent.h_name]),
-+		    {ok, HostEnt#hostent.h_name};
-+		{error, _Reason} = E ->
-+		    E
-+	    end;
-+	{error, _Reason} = E ->
-+	    E
-+    end.
-+
- %%====================================================================
- %% Internal functions
- %%====================================================================
--- 
-1.7.2.1
-

diff --git a/ejabberd-0010-Loading-ASN.1-driver-explicitly-to-avoid-races-in-LD.patch b/ejabberd-0010-Loading-ASN.1-driver-explicitly-to-avoid-races-in-LD.patch
deleted file mode 100644
index e989690..0000000
--- a/ejabberd-0010-Loading-ASN.1-driver-explicitly-to-avoid-races-in-LD.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From c9ff37027805d1d72446b5bcbc1a60da0f2aaae4 Mon Sep 17 00:00:00 2001
-From: Evgeniy Khramtsov <ekhramtsov@process-one.net>
-Date: Wed, 4 Aug 2010 19:23:52 +1000
-Subject: [PATCH 01/11] Loading ASN.1 driver explicitly to avoid races in LDAP (EJAB-1284)
-
----
- src/ejabberd_app.erl |    2 ++
- 1 files changed, 2 insertions(+), 0 deletions(-)
-
-diff --git a/src/ejabberd_app.erl b/src/ejabberd_app.erl
-index 97ae7fe..2227904 100644
---- a/src/ejabberd_app.erl
-+++ b/src/ejabberd_app.erl
-@@ -57,6 +57,8 @@ start(normal, _Args) ->
-     ejabberd_config:start(),
-     ejabberd_check:config(),
-     connect_nodes(),
-+    %% Loading ASN.1 driver explicitly to avoid races in LDAP
-+    catch asn1rt:load_driver(),
-     Sup = ejabberd_sup:start_link(),
-     ejabberd_rdbms:start(),
-     ejabberd_auth:start(),
--- 
-1.7.2.1
-

diff --git a/ejabberd-0010-last-minute-fix-correct-version-in-configure.patch b/ejabberd-0010-last-minute-fix-correct-version-in-configure.patch
new file mode 100644
index 0000000..31a9d2b
--- /dev/null
+++ b/ejabberd-0010-last-minute-fix-correct-version-in-configure.patch
@@ -0,0 +1,28 @@
+From 244c5ae4bfab64220a1d7ff492bdb67dc6612f51 Mon Sep 17 00:00:00 2001
+From: Peter Lemenkov <lemenkov@gmail.com>
+Date: Tue, 14 Dec 2010 18:52:04 +0300
+Subject: [PATCH 10/10] last minute fix - correct version in configure
+
+Signed-off-by: Peter Lemenkov <lemenkov@gmail.com>
+---
+ src/configure |    4 ++--
+ 1 files changed, 2 insertions(+), 2 deletions(-)
+
+diff --git a/src/configure b/src/configure
+index d515abc..ab0beca 100755
+--- a/src/configure
++++ b/src/configure
+@@ -552,8 +552,8 @@ MAKEFLAGS=
+ # Identity of this package.
+ PACKAGE_NAME='ejabberd'
+ PACKAGE_TARNAME='ejabberd'
+-PACKAGE_VERSION='2.1.x'
+-PACKAGE_STRING='ejabberd 2.1.x'
++PACKAGE_VERSION='2.1.6'
++PACKAGE_STRING='ejabberd 2.1.6'
+ PACKAGE_BUGREPORT='ejabberd@process-one.net'
+ PACKAGE_URL=''
+ 
+-- 
+1.7.3.3
+

diff --git a/ejabberd-0011-Make-xml.c-correctly-compiles-on-R14A-EJAB-1288.patch b/ejabberd-0011-Make-xml.c-correctly-compiles-on-R14A-EJAB-1288.patch
deleted file mode 100644
index c181016..0000000
--- a/ejabberd-0011-Make-xml.c-correctly-compiles-on-R14A-EJAB-1288.patch
+++ /dev/null
@@ -1,157 +0,0 @@
-From 1ea09b09a227d1e630d9dde3db68d46b0cb44f55 Mon Sep 17 00:00:00 2001
-From: Evgeniy Khramtsov <ekhramtsov@process-one.net>
-Date: Sat, 7 Aug 2010 21:06:50 +1000
-Subject: [PATCH 04/11] Make xml.c correctly compiles on R14A (EJAB-1288)
-
----
- src/Makefile.in |    1 +
- src/xml.c       |   60 ++++++++++++++++++++++++++++++++++++++++--------------
- 2 files changed, 45 insertions(+), 16 deletions(-)
-
-diff --git a/src/Makefile.in b/src/Makefile.in
-index cf600c3..7d225f3 100644
---- a/src/Makefile.in
-+++ b/src/Makefile.in
-@@ -31,6 +31,7 @@ else
- endif
- 
- EFLAGS += @ERLANG_SSLVER@ -pa .
-+ERLANG_CFLAGS += @ERLANG_SSLVER@
- 
- # make debug=true to compile Erlang module with debug informations.
- ifdef debug
-diff --git a/src/xml.c b/src/xml.c
-index d1b2b7f..e363fed 100644
---- a/src/xml.c
-+++ b/src/xml.c
-@@ -2,6 +2,23 @@
- #include <string.h>
- #include <stdio.h>
- 
-+#ifdef SSL40
-+#define ENIF_ALLOC(SIZE) enif_alloc(SIZE)
-+#define ENIF_FREE(PTR) enif_free(PTR)
-+#define ENIF_REALLOC(PTR, SIZE) enif_realloc(PTR, SIZE)
-+#define ENIF_ALLOC_BINARY(SIZE, BIN) enif_alloc_binary(SIZE, BIN)
-+#define ENIF_COMPARE(TERM1, TERM2) enif_compare(TERM1, TERM2)
-+#else
-+#define ENIF_ALLOC(SIZE) enif_alloc(env, SIZE)
-+#define ENIF_FREE(PTR) enif_free(env, PTR)
-+#define ENIF_REALLOC(PTR, SIZE) enif_realloc(env, PTR, SIZE)
-+#define ENIF_ALLOC_BINARY(SIZE, BIN) enif_alloc_binary(env, SIZE, BIN)
-+#define ENIF_COMPARE(TERM1, TERM2) enif_compare(env, TERM1, TERM2)
-+#endif
-+
-+static ERL_NIF_TERM atom_xmlelement;
-+static ERL_NIF_TERM atom_xmlcdata;
-+
- struct buf {
-   int limit;
-   int len;
-@@ -10,12 +27,19 @@ struct buf {
- 
- static int make_element(ErlNifEnv* env, struct buf *rbuf, ERL_NIF_TERM el);
- 
-+static int load(ErlNifEnv* env, void** priv, ERL_NIF_TERM load_info)
-+{
-+  atom_xmlelement = enif_make_atom(env, "xmlelement");
-+  atom_xmlcdata = enif_make_atom(env, "xmlcdata");
-+  return 0;
-+}
-+
- static struct buf *init_buf(ErlNifEnv* env)
- {
--  struct buf *rbuf = enif_alloc(env, sizeof(struct buf));
-+  struct buf *rbuf = ENIF_ALLOC(sizeof(struct buf));
-   rbuf->limit = 1024;
-   rbuf->len = 0;
--  rbuf->b = enif_alloc(env, rbuf->limit);
-+  rbuf->b = ENIF_ALLOC(rbuf->limit);
-   return rbuf;
- }
- 
-@@ -23,9 +47,9 @@ static void destroy_buf(ErlNifEnv* env, struct buf *rbuf)
- {
-   if (rbuf) {
-     if (rbuf->b) {
--      enif_free(env, rbuf->b);
-+      ENIF_FREE(rbuf->b);
-     };
--    enif_free(env, rbuf);
-+    ENIF_FREE(rbuf);
-   };
- }
- 
-@@ -35,7 +59,7 @@ inline void resize_buf(ErlNifEnv* env, struct buf *rbuf, int len_to_add)
-   
-   if (new_len >= rbuf->limit) {
-     rbuf->limit = ((new_len / 1024) + 1) * 1024;
--    rbuf->b = enif_realloc(env, rbuf->b, rbuf->limit);
-+    rbuf->b = ENIF_REALLOC(rbuf->b, rbuf->limit);
-   };
- }
- 
-@@ -141,7 +165,7 @@ static int make_element(ErlNifEnv* env, struct buf *rbuf, ERL_NIF_TERM el)
- 
-   if (enif_get_tuple(env, el, &arity, &tuple)) {
-     if (arity == 2) {
--      if (!enif_compare(env, tuple[0], enif_make_atom(env, "xmlcdata"))) {
-+      if (!ENIF_COMPARE(tuple[0], atom_xmlcdata)) {
- 	if (enif_inspect_iolist_as_binary(env, tuple[1], &cdata)) {
- 	  crypt(env, rbuf, cdata.data, cdata.size);
- 	  ret = 1;
-@@ -149,7 +173,7 @@ static int make_element(ErlNifEnv* env, struct buf *rbuf, ERL_NIF_TERM el)
-       };
-     };
-     if (arity == 4) {
--      if (!enif_compare(env, tuple[0], enif_make_atom(env, "xmlelement"))) {
-+      if (!ENIF_COMPARE(tuple[0], atom_xmlelement)) {
- 	if (enif_inspect_iolist_as_binary(env, tuple[1], &name)) {
- 	  buf_add_char(env, rbuf, '<');
- 	  buf_add_str(env, rbuf, (char *)name.data, name.size);
-@@ -192,7 +216,7 @@ static ERL_NIF_TERM element_to(ErlNifEnv* env, int argc,
- 	destroy_buf(env, rbuf);
- 	return result;
-       }	else {
--	if (enif_alloc_binary(env, rbuf->len, &output)) {
-+	if (ENIF_ALLOC_BINARY(rbuf->len, &output)) {
- 	  memcpy(output.data, rbuf->b, rbuf->len);
- 	  result = enif_make_binary(env, &output);
- 	  destroy_buf(env, rbuf);
-@@ -206,11 +230,13 @@ static ERL_NIF_TERM element_to(ErlNifEnv* env, int argc,
-   return enif_make_badarg(env);
- }
- 
--/* static ERL_NIF_TERM element_to_string(ErlNifEnv* env, int argc, */
--/* 				      const ERL_NIF_TERM argv[]) */
--/* { */
--/*   return element_to(env, argc, argv, 1); */
--/* } */
-+#ifdef SSL40
-+static ERL_NIF_TERM element_to_string(ErlNifEnv* env, int argc,
-+				      const ERL_NIF_TERM argv[])
-+{
-+  return element_to(env, argc, argv, 1);
-+}
-+#endif
- 
- static ERL_NIF_TERM element_to_binary(ErlNifEnv* env, int argc,
- 				      const ERL_NIF_TERM argv[])
-@@ -222,9 +248,11 @@ static ErlNifFunc nif_funcs[] =
-   {
-     /* Stupid Erlang bug with enif_make_string() is fixed
-        in R14A only (OTP-8685), so we can't use
--       element_to_string yet.*/
--    /* {"element_to_string", 1, element_to_string}, */
-+       element_to_string in Erlang < R14A.*/
-+#ifdef SSL40
-+    {"element_to_string", 1, element_to_string},
-+#endif
-     {"element_to_binary", 1, element_to_binary}
-   };
- 
--ERL_NIF_INIT(xml, nif_funcs, NULL, NULL, NULL, NULL)
-+ERL_NIF_INIT(xml, nif_funcs, load, NULL, NULL, NULL)
--- 
-1.7.2.1
-

diff --git a/ejabberd-0012-fixes-typo-for-table-copy.patch b/ejabberd-0012-fixes-typo-for-table-copy.patch
deleted file mode 100644
index ac62cc5..0000000
--- a/ejabberd-0012-fixes-typo-for-table-copy.patch
+++ /dev/null
@@ -1,25 +0,0 @@
-From f8dd973373a139b9857720dcb4405509e5e4fc76 Mon Sep 17 00:00:00 2001
-From: Evgeniy Khramtsov <ekhramtsov@process-one.net>
-Date: Tue, 10 Aug 2010 19:42:22 +1000
-Subject: [PATCH 08/11] fixes typo for table copy
-
----
- src/odbc/ejabberd_odbc_sup.erl |    2 +-
- 1 files changed, 1 insertions(+), 1 deletions(-)
-
-diff --git a/src/odbc/ejabberd_odbc_sup.erl b/src/odbc/ejabberd_odbc_sup.erl
-index 45ede18..8fb6e25 100644
---- a/src/odbc/ejabberd_odbc_sup.erl
-+++ b/src/odbc/ejabberd_odbc_sup.erl
-@@ -54,7 +54,7 @@ start_link(Host) ->
- 			 {type, bag},
- 			 {local_content, true},
- 			 {attributes, record_info(fields, sql_pool)}]),
--    mnesia:add_table_copy(local_config, node(), ram_copies),
-+    mnesia:add_table_copy(sql_pool, node(), ram_copies),
-     F = fun() ->
- 		mnesia:delete({sql_pool, Host})
- 	end,
--- 
-1.7.2.1
-

diff --git a/ejabberd-0013-fixes-ampersand-escaping-EJAB-1258.patch b/ejabberd-0013-fixes-ampersand-escaping-EJAB-1258.patch
deleted file mode 100644
index 2db4aba..0000000
--- a/ejabberd-0013-fixes-ampersand-escaping-EJAB-1258.patch
+++ /dev/null
@@ -1,26 +0,0 @@
-From 3024bb0cbf359f3e14b5386ed14ecfb168e8a267 Mon Sep 17 00:00:00 2001
-From: Evgeniy Khramtsov <ekhramtsov@process-one.net>
-Date: Thu, 19 Aug 2010 16:28:31 +1000
-Subject: [PATCH 09/11] fixes ampersand escaping (EJAB-1258)
-
----
- src/eldap/eldap_filter.erl |    4 ++--
- 1 files changed, 2 insertions(+), 2 deletions(-)
-
-diff --git a/src/eldap/eldap_filter.erl b/src/eldap/eldap_filter.erl
-index 51dac5e..341fba1 100644
---- a/src/eldap/eldap_filter.erl
-+++ b/src/eldap/eldap_filter.erl
-@@ -171,7 +171,7 @@ do_sub(S, {RegExp, New, Times}, Iter) ->
-     end.
- 
- replace_amps(String) ->
--    lists:map(
-+    lists:flatmap(
-       fun($&) -> "\\&";
--	 (Chr) -> Chr
-+	 (Chr) -> [Chr]
-       end, String).
--- 
-1.7.2.1
-

diff --git a/ejabberd-0014-Bugfix-http-poll-for-correctly-parsing-binary-thanks.patch b/ejabberd-0014-Bugfix-http-poll-for-correctly-parsing-binary-thanks.patch
deleted file mode 100644
index 6fa5aa8..0000000
--- a/ejabberd-0014-Bugfix-http-poll-for-correctly-parsing-binary-thanks.patch
+++ /dev/null
@@ -1,31 +0,0 @@
-From d87fff1a4c500d9abe3945cbfea792b4eddfa3f2 Mon Sep 17 00:00:00 2001
-From: Badlop <badlop@process-one.net>
-Date: Thu, 19 Aug 2010 17:37:21 +0200
-Subject: [PATCH 10/11] Bugfix http-poll for correctly parsing binary (thanks to Peter Lemenkov)
-
----
- src/web/ejabberd_http_poll.erl |    8 +++++++-
- 1 files changed, 7 insertions(+), 1 deletions(-)
-
-diff --git a/src/web/ejabberd_http_poll.erl b/src/web/ejabberd_http_poll.erl
-index 0bdbc62..faa0f3c 100644
---- a/src/web/ejabberd_http_poll.erl
-+++ b/src/web/ejabberd_http_poll.erl
-@@ -272,7 +272,13 @@ handle_event(_Event, StateName, StateData) ->
- %%          {stop, Reason, Reply, NewStateData}                    
- %%----------------------------------------------------------------------
- handle_sync_event({send, Packet}, _From, StateName, StateData) ->
--    Output = StateData#state.output ++ [lists:flatten(Packet)],
-+    Packet2 = if
-+		  is_binary(Packet) ->
-+		      binary_to_list(Packet);
-+		  true ->
-+		      Packet
-+	      end,
-+    Output = StateData#state.output ++ [lists:flatten(Packet2)],
-     Reply = ok,
-     {reply, Reply, StateName, StateData#state{output = Output}};
- 
--- 
-1.7.2.1
-

diff --git a/ejabberd.spec b/ejabberd.spec
index 9efb71a..b26a5b2 100644
--- a/ejabberd.spec
+++ b/ejabberd.spec
@@ -10,8 +10,8 @@
 %endif
 
 Name:           ejabberd
-Version:        2.1.5
-Release:        6%{?dist}
+Version:        2.1.6
+Release:        1%{?dist}
 Summary:        A distributed, fault-tolerant Jabber/XMPP server
 
 Group:          Applications/Internet
@@ -22,17 +22,6 @@ Source1:        ejabberd.init
 Source2:        ejabberd.logrotate
 Source3:	ejabberd.sysconfig
 
-# http://www.ejabberd.im/mod_ctlextra
-# this module will be removed in the nearest future in favor of mod_admin_extra
-# svn export -r 1020 https://svn.process-one.net/ejabberd-modules/mod_ctlextra/trunk/src/mod_ctlextra.erl
-Source4:        mod_ctlextra.erl
-
-# The following were extracted from a patch found on http://realloc.spb.ru/share/ejabberdad.html
-# These are unmaintained and will be removed soon (users should use *_ldap.erl instead)
-Source5:        ejabberd_auth_ad.erl
-Source6:        mod_shared_roster_ad.erl
-Source7:        mod_vcard_ad.erl
-
 # PAM support
 Source9:        ejabberdctl.pam
 Source10:       ejabberdctl.apps
@@ -40,33 +29,24 @@ Source11:       ejabberd.pam
 
 # Use ejabberd as an example for PAM service name (fedora/epel-specific)
 Patch1: ejabberd-0001-Fix-PAM-service-example-name-to-match-actual-one.patch
-# Mention mod_ctlextra as an ejabberd module
-Patch2: ejabberd-0002-Mention-mod_ctlextra-as-an-ejabberd-module.patch
+# Introducing mod_ctlextra
+Patch2: ejabberd-0002-Add-mod_ctlextra-as-an-ejabberd-module.patch
 # fixed delays in s2s connections
 Patch3: ejabberd-0003-Fixed-delays-in-s2s-connections.patch
 # Introducing mod_admin_extra
 Patch4: ejabberd-0004-Introducing-mod_admin_extra.patch
 # BZ# 439583, 452326, 451554, 465196, 502361 (fedora/epel-specific)
 Patch5: ejabberd-0005-Fedora-specific-changes-to-ejabberdctl.patch
-# Fix issue with "File operation error: eacces"
-Patch6: ejabberd-0006-Change-directory-to-readable-by-everyone.patch
 # Fix so-lib permissions while installing (fedora/epel-specific)
-Patch7:	ejabberd-0007-Install-.so-objects-with-0755-permissions.patch
-# Will be proposed for incusion into upstream
-Patch8: ejabberd-0008-Use-versioned-directory-for-storing-docs.patch
-# Backported from upstream
-Patch9: ejabberd-0009-Support-SASL-GSSAPI-authentication-thanks-to-Mikael-.patch
-# Backported from upstream
-Patch10: ejabberd-0010-Loading-ASN.1-driver-explicitly-to-avoid-races-in-LD.patch
-# Backported from upstream
-Patch11: ejabberd-0011-Make-xml.c-correctly-compiles-on-R14A-EJAB-1288.patch
+Patch6:	ejabberd-0006-Install-.so-objects-with-0755-permissions.patch
+# Will be proposed for inclusion into upstream
+Patch7: ejabberd-0007-Use-versioned-directory-for-storing-docs.patch
 # Backported from upstream
-Patch12: ejabberd-0012-fixes-typo-for-table-copy.patch
-# Backported from upstream
-Patch13: ejabberd-0013-fixes-ampersand-escaping-EJAB-1258.patch
-# Backported from upstream
-Patch14: ejabberd-0014-Bugfix-http-poll-for-correctly-parsing-binary-thanks.patch
-
+Patch8: ejabberd-0008-Support-SASL-GSSAPI-authentication-thanks-to-Mikael-.patch
+# Introduce old AD stuff
+Patch9: ejabberd-0009-Added-old-modules-for-Active-Directory.patch
+# Correct version in configure (DON'T FORGET TO REMOVE IN THE NEXT VERSION)
+Patch10: ejabberd-0010-last-minute-fix-correct-version-in-configure.patch
 
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
 
@@ -127,20 +107,12 @@ Documentation for ejabberd.
 %patch3 -p1 -b .s2s_delays
 %patch4 -p1 -b .mod_admin_extra
 %patch5 -p1 -b .fedora_specific
-%patch6 -p1 -b .fix_access
-%patch7 -p1 -b .fix_perms
-%patch8 -p1 -b .versioned_docdir
-%patch9 -p1 -b .gssapi
-%patch10 -p1 -b .load_asn1
-%patch11 -p1 -b .R14A
-%patch12 -p1 -b .typo
-%patch13 -p1 -b .ldap_ampersand_escaping
-%patch14 -p1 -b .http-poll
-
-cp %{S:4} src
-cp %{S:5} src
-cp %{S:6} src
-cp %{S:7} src
+%patch6 -p1 -b .fix_perms
+%patch7 -p1 -b .versioned_docdir
+%patch8 -p1 -b .gssapi
+%patch9 -p1 -b .ad_stuff
+%patch10 -p1 -b .fix_version
+touch -r src/configure.fix_version src/configure
 
 
 %build
@@ -366,6 +338,9 @@ rm -rf %{buildroot}
 %doc %{_docdir}/%{name}-%{version}/*.txt
 
 %changelog
+* Tue Dec 14 2010 Peter Lemenkov <lemenkov@gmail.com> 2.1.6-1
+- Ver. 2.1.6 (Bugfix release)
+
 * Thu Aug 26 2010 Peter Lemenkov <lemenkov@gmail.com> 2.1.5-6
 - More patches from trunk
 - Rebased patches

diff --git a/ejabberd_auth_ad.erl b/ejabberd_auth_ad.erl
deleted file mode 100644
index 5e9e452..0000000
--- a/ejabberd_auth_ad.erl
+++ /dev/null
@@ -1,167 +0,0 @@
-%%%----------------------------------------------------------------------
-%%% File    : ejabberd_auth_ad.erl
-%%% Author  : Alexey Shchepin <alexey@sevcom.net>
-%%% Author  : Alex Gorbachenko <agent_007@immo.ru>
-%%% Author  : Stanislav Bogatyrev <realloc@realloc.spb.ru>
-%%% Purpose : Authentification via Active Directory
-%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@sevcom.net>
-%%% Id      : $Id: ejabberd_auth_ad.erl 386 2005-12-20 10:06:37Z agent_007 $
-%%%----------------------------------------------------------------------
-
--module(ejabberd_auth_ad).
--author('alexey@sevcom.net').
--author('agent_007@immo.ru').
--author('realloc@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)).

diff --git a/mod_ctlextra.erl b/mod_ctlextra.erl
deleted file mode 100644
index bc61024..0000000
--- a/mod_ctlextra.erl
+++ /dev/null
@@ -1,895 +0,0 @@
-%%%----------------------------------------------------------------------
-%%% File    : mod_ctlextra.erl
-%%% Author  : Badlop <badlop@ono.com>
-%%% Purpose : Adds more commands to ejabberd_ctl
-%%% Created : 30 Nov 2006 by Badlop <badlop@ono.com>
-%%% Id      : $Id: mod_ctlextra.erl 1020 2009-08-30 10:13:34Z badlop $
-%%%----------------------------------------------------------------------
-
--module(mod_ctlextra).
--author('badlop@ono.com').
-
--behaviour(gen_mod).
-
--export([start/2,
-	 stop/1,
-	 ctl_process/2,
-	 ctl_process/3
-	]).
-
--include("ejabberd.hrl").
--include("ejabberd_ctl.hrl").
--include("jlib.hrl").
--include("mod_roster.hrl").
-
-%% Copied from ejabberd_sm.erl
--record(session, {sid, usr, us, priority, info}).
-
--compile(export_all).
-
-%%-------------
-%% gen_mod
-%%-------------
-
-start(Host, _Opts) ->
-    ejabberd_ctl:register_commands(commands_global(), ?MODULE, ctl_process),
-    ejabberd_ctl:register_commands(Host, commands_host(), ?MODULE, ctl_process).
-
-stop(Host) ->
-    ejabberd_ctl:unregister_commands(commands_global(), ?MODULE, ctl_process),
-    ejabberd_ctl:unregister_commands(Host, commands_host(), ?MODULE, ctl_process).
-
-commands_global() ->
-    [
-     {"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'"},
-     {"delete-older-users-vhost host days", "delete users that not logged in last 'days' in 'host'"},
-     {"set-password user server password", "set password to user@server"},
-
-     %% ejd2odbc
-     {"export2odbc server output", "export Mnesia tables on server to files on output directory"},
-
-     %% 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@server to group on host"},
-     {"srg-user-del user server group host", "delete user@server from group on host"},
-     {"srg-list-groups host", "list the shared roster groups from host"},
-     {"srg-get-info group host", "get info of a specific 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_roster
-     {"add-rosteritem user1 server1 user2 server2 nick group subs", "Add user2@server2 to user1@server1's roster"},
-     %%{"", "subs= none, from, to or both"},
-     %%{"", "example: add-roster peter localhost mike server.com MiKe Employees both"},
-     %%{"", "will add mike@server.com to peter@localhost roster"},
-     {"rem-rosteritem user1 server1 user2 server2", "Remove user2@server2 from user1@server1's roster"},
-     {"rosteritem-purge [options]", "Purge all rosteritems that match filtering options"},
-     {"pushroster file user server", "push template roster in file to user@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"},
-
-     {"status-list status", "list the logged users with status"},
-     {"status-num status", "number of logged users with status"},
-
-     {"stats registeredusers", "number of registered users"},
-     {"stats onlineusers", "number of logged users"},
-     {"stats onlineusersnode", "number of logged users in the ejabberd node"},
-     {"stats uptime-seconds", "uptime of ejabberd node in seconds"},
-
-     %% misc
-     {"get-cookie", "get the Erlang cookie of this node"},
-     {"killsession user server resource", "kill a user session"}
-    ].
-
-commands_host() ->
-    [
-     %% mod_last
-     {"num-active-users days", "number of users active in the last 'days'"},
-     {"status-list status", "list the logged users with status"},
-     {"status-num status", "number of logged users with status"},
-     {"stats registeredusers", "number of registered users"},
-     {"stats onlineusers", "number of logged users"},
-
-     %% misc
-     {"ban-account username [reason]", "ban account: kick sessions and change password"}
-    ].
-
-
-%%-------------
-%% Commands global
-%%-------------
-
-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, ["delete-older-users-vhost", Host, Days]) ->
-    {removed, N, UR} = delete_older_users_vhost(Host, list_to_integer(Days)),
-    io:format("Deleted ~p users: ~p~n", [N, UR]),
-    ?STATUS_SUCCESS;
-
-ctl_process(_Val, ["export2odbc", Server, Output]) ->
-    Tables = [
-	      {export_last, last},
-	      {export_offline, offline},
-	      {export_passwd, passwd},
-	      {export_private_storage, private_storage},
-	      {export_roster, roster},
-	      {export_vcard, vcard},
-	      {export_vcard_search, vcard_search}],
-    Export = fun({TableFun, Table}) -> 
-		     Filename = filename:join([Output, atom_to_list(Table)++".txt"]),
-		     io:format("Trying to export Mnesia table '~p' on server '~s' to file '~s'~n", [Table, Server, Filename]),
-		     Res = (catch ejd2odbc:TableFun(Server, Filename)),
-		     io:format("  Result: ~p~n", [Res])
-	     end,
-    lists:foreach(Export, Tables),
-    ?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, Data1, Content]) ->
-    {ok, Res} = vcard_set(User, Server, [Data1], 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;
-
-%% The Display argument can be several groups separated with ,
-%% Example: ejabberdctl srg-create aa localhost Name Desc Display1,Display2,Display3
-ctl_process(_Val, ["srg-create" | Parameters]) ->
-	[Group, Host, Name, Description, Display] = group_parameters(Parameters, "'"),
-    DisplayList = string:tokens(Display, ","),
-    Opts = [{name, Name}, {displayed_groups, DisplayList}, {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, ["srg-list-groups", Host]) ->
-    lists:foreach(
-      fun(SrgGroup) ->
-	      io:format("~s~n",[SrgGroup])
-      end,
-      lists:sort(mod_shared_roster:list_groups(Host))),
-    ?STATUS_SUCCESS;
-
-ctl_process(_Val, ["srg-get-info", Group, Host]) ->
-    Opts = mod_shared_roster:get_group_opts(Host,Group),
-    [io:format("~s: ~p~n", [Title, Value]) || {Title , Value} <- Opts],
-    
-    Members = mod_shared_roster:get_group_explicit_users(Host,Group),
-    Members_string = [ " " ++ jlib:jid_to_string(jlib:make_jid(MUser, MServer, "")) 
-		       || {MUser, MServer} <- Members],
-    io:format("members:~s~n", [Members_string]),
-    
-    ?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, ["rem-rosteritem", LocalUser, LocalServer, RemoteUser, RemoteServer]) ->
-    case rem_rosteritem(LocalUser, LocalServer, RemoteUser, RemoteServer) of
-	{atomic, ok} ->
-	    ?STATUS_SUCCESS;
-	{error, Reason} ->
-	    io:format("Can't remove ~p@~p to ~p@~p: ~p~n",
-		      [RemoteUser, RemoteServer, LocalUser, LocalServer, Reason]),
-	    ?STATUS_ERROR;
-	{badrpc, Reason} ->
-	    io:format("Can't remove roster item to user ~p: ~p~n",
-		      [LocalUser, Reason]),
-	    ?STATUS_BADRPC
-    end;
-
-ctl_process(_Val, ["rosteritem-purge"]) ->
-    io:format("Rosteritems that match all the filtering will be removed.~n"),
-    io:format("Options for filtering:~n"),
-    io:format("~n"),
-    io:format("  -subs none|from|to|both~n"),
-    io:format("       Subscription type. By default all values~n"),
-    io:format("~n"),
-    io:format("  -ask none|out|in~n"),
-    io:format("       Pending subscription. By default all values~n"),
-    io:format("~n"),
-    io:format("  -user JID~n"),
-    io:format("       The JID of the local user.~n"),
-    io:format("       Can use these globs: *, ? and [...].~n"),
-    io:format("       By default it is: * *@*~n"),
-    io:format("~n"),
-    io:format("  -contact JID~n"),
-    io:format("       Similar to 'user', but for the contact JID.~n"),
-    io:format("~n"),
-    io:format("Example:~n"),
-    io:format("  ejabberdctl rosteritem-purge -subs none from to -ask out in -contact *@*icq*~n"),
-    io:format("~n"),
-    ?STATUS_SUCCESS;
-ctl_process(_Val, ["rosteritem-purge" | Options_list]) ->
-    Options_prop_list = lists:foldl(
-			  fun(O, R) ->
-				  case O of
-				      [$- | K] ->
-					  [{K, []} | R];
-				      V ->
-					  [{K, Vs} | RT] = R,
-					  [{K, [V|Vs]} | RT]
-				  end
-			  end,
-			  [],
-			  Options_list),
-    
-    Subs = [list_to_atom(S)
-	    || S <- proplists:get_value("subs", 
-					Options_prop_list, 
-					["none", "from", "to", "both"])],
-    Asks = [list_to_atom(S)
-	    || S <- 
-		   proplists:get_value("ask",
-				       Options_prop_list, 
-				       ["none", "out", "in"])],
-    User = proplists:get_value("user", Options_prop_list, ["*", "*@*"]),
-    Contact = proplists:get_value("contact", Options_prop_list, ["*", "*@*"]),
-    
-    case rosteritem_purge({Subs, Asks, User, Contact}) of
-	{atomic, ok} ->
-	    ?STATUS_SUCCESS;
-	{error, Reason} ->
-	    io:format("Error purging rosteritems: ~p~n",
-		      [Reason]),
-	    ?STATUS_ERROR;
-	{badrpc, Reason} ->
-	    io:format("BadRPC purging rosteritems: ~p~n",
-		      [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 catch ejabberd_config:load_file(Path) of
-        ok ->
-            ?STATUS_SUCCESS;
-        {'EXIT', Reason} ->
-            io:format("Problem loading 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
-	      "uptime-seconds" -> uptime_seconds();
-	      "registeredusers" -> length(ejabberd_auth:dirty_get_registered_users());
-	      "onlineusersnode" -> length(ejabberd_sm:dirty_get_my_sessions_list());
-	      "onlineusers" -> length(ejabberd_sm:dirty_get_sessions_list())
-	  end,
-    io:format("~p~n", [Res]),
-    ?STATUS_SUCCESS;
-
-ctl_process(_Val, ["status-num", Status_required]) ->
-    ctl_process(_Val, "all", ["status-num", Status_required]);
-
-ctl_process(_Val, ["status-list", Status_required]) ->
-    ctl_process(_Val, "all", ["status-list", Status_required]);
-
-ctl_process(_Val, ["get-cookie"]) ->
-    io:format("~s~n", [atom_to_list(erlang:get_cookie())]),
-    ?STATUS_SUCCESS;
-
-ctl_process(_Val, ["killsession", User, Server, Resource | Tail]) ->
-    kick_session(User, Server, Resource, prepare_reason(Tail)),
-    ?STATUS_SUCCESS;
-
-ctl_process(Val, _Args) ->
-    Val.
-
-
-%%-------------
-%% Commands vhost
-%%-------------
-
-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, ["status-num", Status_required]) ->
-    Num = length(get_status_list(Host, Status_required)),
-    io:format("~p~n", [Num]),
-    ?STATUS_SUCCESS;
-
-ctl_process(_Val, Host, ["status-list", Status_required]) ->
-    Res = get_status_list(Host, Status_required),
-    [ io:format("~s@~s ~s ~p \"~s\"~n", [U, S, R, P, St]) || {U, S, R, P, St} <- Res],
-    ?STATUS_SUCCESS;
-
-ctl_process(_Val, Host, ["ban-account", User | Tail]) ->
-    ban_account(User, Host, prepare_reason(Tail)),
-    ?STATUS_SUCCESS;
-
-ctl_process(Val, _Host, _Args) ->
-    Val.
-
-
-%%-------------
-%% Utils
-%%-------------
-
-uptime_seconds() ->
-    trunc(element(1, erlang:statistics(wall_clock))/1000).
-
-get_status_list(Host, Status_required) ->
-    %% Get list of all logged users
-    Sessions = ejabberd_sm:dirty_get_my_sessions_list(),
-    %% Reformat the list
-    Sessions2 = [ {Session#session.usr, Session#session.sid, Session#session.priority} || Session <- Sessions],
-    Fhost = case Host of
-		"all" ->
-		    %% All hosts are requested, so dont filter at all
-		    fun(_, _) -> true end;
-		_ ->
-		    %% Filter the list, only Host is interesting
-		    fun(A, B) -> A == B end
-	    end,
-    Sessions3 = [ {Pid, Server, Priority} || {{_User, Server, _Resource}, {_, Pid}, Priority} <- Sessions2, apply(Fhost, [Server, Host])],
-    %% For each Pid, get its presence
-    Sessions4 = [ {ejabberd_c2s:get_presence(Pid), Server, Priority} || {Pid, Server, Priority} <- Sessions3],
-    %% Filter by status
-    Fstatus = case Status_required of
-		  "all" ->
-		      fun(_, _) -> true end;
-		  _ ->
-		      fun(A, B) -> A == B end
-	      end,
-    [{User, Server, Resource, Priority, stringize(Status_text)} 
-     || {{User, Resource, Status, Status_text}, Server, Priority} <- Sessions4, 
-	apply(Fstatus, [Status, Status_required])].
-
-%% Make string more print-friendly
-stringize(String) ->
-    %% Replace newline characters with other code
-    element(2, regexp:gsub(String, "\n", "\\n")).
-
-add_rosteritem(LU, LS, RU, RS, Nick, Group, Subscription, Xattrs) ->
-    subscribe(LU, LS, RU, RS, Nick, Group, Subscription, Xattrs),
-    route_rosteritem(LU, LS, RU, RS, Nick, Group, Subscription),
-    {atomic, ok}.
-
-subscribe(LocalUser, LocalServer, RemoteUser, RemoteServer, Nick, Group, Subscription, Xattrs) ->
-    R = #roster{usj = {LocalUser,LocalServer,{RemoteUser,RemoteServer,[]}},
-		us = {LocalUser,LocalServer},
-		jid = {RemoteUser,RemoteServer,[]},
-		name = Nick,
-		subscription = Subscription, % none, to=you see him, from=he sees you, both
-		ask = none, % out=send request, in=somebody requests you, none
-		groups = [Group],
-		askmessage = Xattrs, % example: [{"category","conference"}]
-		xs = []},
-    mnesia:transaction(fun() -> mnesia:write(R) end).
-
-rem_rosteritem(LU, LS, RU, RS) ->
-    unsubscribe(LU, LS, RU, RS),
-    route_rosteritem(LU, LS, RU, RS, "", "", "remove"),
-    {atomic, ok}.
-
-unsubscribe(LocalUser, LocalServer, RemoteUser, RemoteServer) ->
-    Key = {{LocalUser,LocalServer,{RemoteUser,RemoteServer,[]}},
-	   {LocalUser,LocalServer}},
-    mnesia:transaction(fun() -> mnesia:delete(roster, Key, write) end).
-
-route_rosteritem(LocalUser, LocalServer, RemoteUser, RemoteServer, Nick, Group, Subscription) ->
-    LJID = jlib:make_jid(LocalUser, LocalServer, ""),
-    RJID = jlib:make_jid(RemoteUser, RemoteServer, ""),
-    ToS = jlib:jid_to_string(LJID),
-    ItemJIDS = jlib:jid_to_string(RJID),
-    GroupXML = {xmlelement, "group", [], [{xmlcdata, Group}]},
-    Item = {xmlelement, "item", 
-	    [{"jid", ItemJIDS},
-	     {"name", Nick},
-	     {"subscription", Subscription}], 
-	    [GroupXML]},
-    Query = {xmlelement, "query", [{"xmlns", ?NS_ROSTER}], [Item]},
-    Packet = {xmlelement, "iq", [{"type", "set"}, {"to", ToS}], [Query]},
-    ejabberd_router:route(LJID, LJID, Packet).
-
-
-%%-----------------------------
-%% Ban user
-%%-----------------------------
-
-ban_account(User, Server, Reason) ->
-    kick_sessions(User, Server, Reason),
-    set_random_password(User, Server, Reason).
-
-kick_sessions(User, Server, Reason) ->
-    lists:map(
-      fun(Resource) ->
-	      kick_session(User, Server, Resource, Reason)
-      end,
-      get_resources(User, Server)).
-
-kick_session(User, Server, Resource, Reason) ->
-    ejabberd_router:route(
-      jlib:make_jid("", "", ""),
-      jlib:make_jid(User, Server, Resource),
-      {xmlelement, "broadcast", [], [{exit, Reason}]}).
-
-get_resources(User, Server) ->
-    lists:map(
-      fun(Session) ->
-	      element(3, Session#session.usr)
-      end,
-      get_sessions(User, Server)).
-
-get_sessions(User, Server) ->
-    LUser = jlib:nodeprep(User),
-    LServer = jlib:nameprep(Server),
-    Sessions =  mnesia:dirty_index_read(session, {LUser, LServer}, #session.us),
-    true = is_list(Sessions),
-    Sessions.
-
-set_random_password(User, Server, Reason) ->
-    NewPass = build_random_password(Reason),
-    set_password(User, Server, NewPass).
-
-build_random_password(Reason) ->
-    Date = jlib:timestamp_to_iso(calendar:universal_time()),
-    RandomString = randoms:get_string(),
-    "BANNED_ACCOUNT--" ++ Date ++ "--" ++ RandomString ++ "--" ++ Reason.
-
-set_password(User, Server, Password) ->
-    {atomic, ok} = ejabberd_auth:set_password(User, Server, Password).
-
-prepare_reason([]) ->
-    "Kicked by administrator";
-prepare_reason([Reason]) ->
-    Reason;
-prepare_reason(StringList) ->
-    string:join(StringList, "_").
-
-
-%%-----------------------------
-%% Purge roster items
-%%-----------------------------
-
-rosteritem_purge(Options) ->
-    Num_rosteritems = mnesia:table_info(roster, size),
-    io:format("There are ~p roster items in total.~n", [Num_rosteritems]),
-    Key = mnesia:dirty_first(roster),
-    ok = rip(Key, Options, {0, Num_rosteritems, 0, 0}),
-    {atomic, ok}.
-
-rip('$end_of_table', _Options, Counters) ->
-    print_progress_line(Counters),
-    ok;
-rip(Key, Options, {Pr, NT, NV, ND}) ->
-    Key_next = mnesia:dirty_next(roster, Key),
-    ND2 = case decide_rip(Key, Options) of
-	      true ->
-		  mnesia:dirty_delete(roster, Key),
-		  ND+1;
-	      false ->
-		  ND
-	  end,
-    NV2 = NV+1,
-    Pr2 = print_progress_line({Pr, NT, NV2, ND2}),
-    rip(Key_next, Options, {Pr2, NT, NV2, ND2}).
-
-print_progress_line({Pr, NT, NV, ND}) ->
-    Pr2 = trunc((NV/NT)*100),
-    case Pr == Pr2 of
-	true ->
-	    ok;
-	false ->
-	    io:format("Progress ~p% - visited ~p - deleted ~p~n", [Pr2, NV, ND])
-    end,
-    Pr2.
-
-decide_rip(Key, {Subs, Asks, User, Contact}) ->
-    case catch mnesia:dirty_read(roster, Key) of
-	[RI] ->
-	    lists:member(RI#roster.subscription, Subs)
-		andalso lists:member(RI#roster.ask, Asks)
-		andalso decide_rip_jid(RI#roster.us, User)
-		andalso decide_rip_jid(RI#roster.jid, Contact);
-	_ ->
-	    false
-    end.
-
-%% Returns true if the server of the JID is included in the servers
-decide_rip_jid({UName, UServer, _UResource}, Match_list) ->
-    decide_rip_jid({UName, UServer}, Match_list);
-decide_rip_jid({UName, UServer}, Match_list) ->
-    lists:any(
-      fun(Match_string) ->
-	      MJID = jlib:string_to_jid(Match_string),
-	      MName = MJID#jid.luser,
-	      MServer = MJID#jid.lserver,
-	      Is_server = is_glob_match(UServer, MServer),
-	      case MName of
-		  [] when UName == [] ->
-		      Is_server;
-		  [] ->
-		      false;
-		  _ ->
-		      Is_server
-			  andalso is_glob_match(UName, MName)
-	      end
-      end,
-      Match_list).
-
-%% Copied from ejabberd-2.0.0/src/acl.erl
-is_regexp_match(String, RegExp) ->
-    case regexp:first_match(String, RegExp) of
-	nomatch ->
-	    false;
-	{match, _, _} ->
-	    true;
-	{error, ErrDesc} ->
-	    io:format(
-	      "Wrong regexp ~p in ACL: ~p",
-	      [RegExp, lists:flatten(regexp:format_error(ErrDesc))]),
-	    false
-    end.
-is_glob_match(String, Glob) ->
-    is_regexp_match(String, regexp:sh_to_awk(Glob)).
-
-
-%%-----------------------------
-%% Push Roster from file 
-%%-----------------------------
-
-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, Data) ->
-    [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}),
-    JID = jlib:make_jid(User, Server, ""),
-    IQ = #iq{type = get, xmlns = ?NS_VCARD},
-    IQr = Module:Function(JID, JID, IQ),
-    Res = case IQr#iq.sub_el of
-	      [A1] ->
-		  case vcard_get(Data, A1) of
-		      false -> no_value;
-		      Elem -> xml:get_tag_cdata(Elem)
-		  end;
-	      [] -> 
-		  no_vcard
-	  end,
-    {ok, Res}.
-
-vcard_get([Data1, Data2], A1) ->
-    case xml:get_subtag(A1, Data1) of
-    	false -> false;
-	A2 -> vcard_get([Data2], A2)
-    end;
-
-vcard_get([Data], A1) ->
-    xml:get_subtag(A1, Data).
-
-vcard_set(User, Server, Data, Content) ->
-    [{_, Module, Function, _Opts}] = ets:lookup(sm_iqtable, {?NS_VCARD, Server}),
-    JID = jlib:make_jid(User, Server, ""),
-    IQ = #iq{type = get, xmlns = ?NS_VCARD},
-    IQr = Module:Function(JID, JID, IQ),
-
-    %% Get old vcard
-    A4 = case IQr#iq.sub_el of
-	     [A1] ->
-		 {_, _, _, A2} = A1,
-		 update_vcard_els(Data, Content, A2);
-	     [] -> 
-		 update_vcard_els(Data, Content, [])
-	 end,
-
-    %% Build new vcard
-    SubEl = {xmlelement, "vCard", [{"xmlns","vcard-temp"}], A4},
-    IQ2 = #iq{type=set, sub_el = SubEl},
-
-    Module:Function(JID, JID, IQ2),
-    {ok, "done"}.
-
-update_vcard_els(Data, Content, Els1) ->
-    Els2 = lists:keysort(2, Els1),
-    [Data1 | Data2] = Data,
-    NewEl = case Data2 of
-		[] ->
-		    {xmlelement, Data1, [], [{xmlcdata,Content}]};
-		[D2] ->
-		    OldEl = case lists:keysearch(Data1, 2, Els2) of
-				{value, A} -> A;
-				false -> {xmlelement, Data1, [], []}
-			    end,
-		    {xmlelement, _, _, ContentOld1} = OldEl,
-		    Content2 = [{xmlelement, D2, [], [{xmlcdata,Content}]}],
-		    ContentOld2 = lists:keysort(2, ContentOld1),
-		    ContentOld3 = lists:keydelete(D2, 2, ContentOld2),
-		    ContentNew = lists:keymerge(2, Content2, ContentOld3),
-		    {xmlelement, Data1, [], ContentNew}
-	    end,
-    Els3 = lists:keydelete(Data1, 2, Els2),
-    lists:keymerge(2, [NewEl], Els3).
-
--record(last_activity, {us, timestamp, status}).
-
-delete_older_users(Days) ->
-    %% Get the list of registered users
-    Users = ejabberd_auth:dirty_get_registered_users(),
-    delete_older_users(Days, Users).
-
-delete_older_users_vhost(Host, Days) ->
-    %% Get the list of registered users
-    Users = ejabberd_auth:get_vh_registered_users(Host),
-    delete_older_users(Days, Users).
-
-delete_older_users(Days, Users) ->
-    %% Convert older time
-    SecOlder = Days*24*60*60,
-
-    %% Get current time
-    {MegaSecs, Secs, _MicroSecs} = now(),
-    TimeStamp_now = MegaSecs * 1000000 + Secs,
-
-    %% 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 isnt
-		    [] ->
-			%% 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.
-
-group_parameters(Ps, [Char]) ->
-	{none, Grouped_Ps} = lists:foldl(
-		fun(P, {State, Res}) ->
-			case State of
-				none -> 
-					case P of
-						[Char | PTail]->
-							{building, [PTail | Res]};
-						_ ->
-							{none, [P | Res]}
-					end;
-				building -> 
-					[ResHead | ResTail] = Res,
-					case lists:last(P) of
-						Char ->
-							P2 = lists:sublist(P, length(P)-1),
-							{none, [ResHead ++ " " ++ P2 | ResTail]};
-						_ ->
-							{building, [ResHead ++ " " ++ P | ResTail]}
-					end
-			end
-		end,
-		{none, []},
-		Ps),
-	lists:reverse(Grouped_Ps).

diff --git a/mod_shared_roster_ad.erl b/mod_shared_roster_ad.erl
deleted file mode 100644
index 8dc09f1..0000000
--- a/mod_shared_roster_ad.erl
+++ /dev/null
@@ -1,428 +0,0 @@
-%%%----------------------------------------------------------------------
-%%% File    : mod_shared_roster.erl
-%%% Author  : Alexey Shchepin <alexey@sevcom.net>
-%%% Author  : Stanislav Bogatyrev <realloc@realloc.spb.ru>
-%%% Purpose : Shared roster management
-%%% Created :  5 Mar 2005 by Alexey Shchepin <alexey@sevcom.net>
-%%% Id      : $Id: mod_shared_roster_ad.erl,v 1.1 2006/06/23 12:40:03 jcollie Exp $
-%%%----------------------------------------------------------------------
-
--module(mod_shared_roster_ad).
--author('alexey@sevcom.net').
--author('realloc@realloc.spb.ru').
--vsn('$Revision: 1.1 $ ').
-
--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.
-
-

diff --git a/mod_vcard_ad.erl b/mod_vcard_ad.erl
deleted file mode 100644
index 52ddbec..0000000
--- a/mod_vcard_ad.erl
+++ /dev/null
@@ -1,631 +0,0 @@
-
-%%%----------------------------------------------------------------------
-%%% File    : mod_vcard_ad.erl
-%%% Author  : Stanislav Bogatyrev <realloc@realloc.spb.ru>
-%%% Author  : Alexey Shchepin <alexey@sevcom.net>
-%%% Author  : Alex <agent_007> Gorbachenko (agent_007@immo.ru)
-%%% Purpose : 
-%%% Created :  2 Jan 2003 by Alexey Shchepin <alexey@sevcom.net>
-%%% Id      : $Id: mod_vcard_ad.erl 437 2005-11-19 01:20:05Z agent_007 $
-%%%----------------------------------------------------------------------
-
--module(mod_vcard_ad).
--author('realloc@realloc.spb.ru').
--author('alexey@sevcom.net').
--author('agent_007@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.
-

diff --git a/sources b/sources
index ef0833a..408014a 100644
--- a/sources
+++ b/sources
@@ -1 +1 @@
-2029ceca45584d704ca821a771d6d928  ejabberd-2.1.5.tar.gz
+f5a41edee2204c414150075331ced506  ejabberd-2.1.6.tar.gz

^ permalink raw reply related	[flat|nested] only message in thread

only message in thread, other threads:[~2026-09-23 19:07 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-23 19:07 [rpms/ejabberd] f45: Ver. 2.1.6 Peter Lemenkov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox