summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog11
-rw-r--r--src/ejabberd_auth.erl380
-rw-r--r--src/ejabberd_auth_external.erl67
-rw-r--r--src/ejabberd_auth_internal.erl167
-rw-r--r--src/ejabberd_auth_ldap.erl106
-rw-r--r--src/ejabberd_sm.erl3
-rw-r--r--src/mod_last.erl9
7 files changed, 383 insertions, 360 deletions
diff --git a/ChangeLog b/ChangeLog
index 72b29349..7f57a5a7 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,14 @@
+2004-12-12 Alexey Shchepin <alexey@sevcom.net>
+
+ * src/ejabberd_sm.erl: Added unset_presence_hook
+ * src/mod_last.erl: Use unset_presence_hook instead of direct call
+
+ * src/ejabberd_auth.erl: Splitted into ejabberd_auth_internal.erl,
+ ejabberd_auth_ldap.erl, and ejabberd_auth_external.erl,
+ * src/ejabberd_auth_internal.erl: Likewise
+ * src/ejabberd_auth_ldap.erl: Likewise
+ * src/ejabberd_auth_external.erl: Likewise
+
2004-12-05 Alexey Shchepin <alexey@sevcom.net>
* src/web/ejabberd_web_admin.erl: Changed type of password field
diff --git a/src/ejabberd_auth.erl b/src/ejabberd_auth.erl
index d7f6b366..2c548a33 100644
--- a/src/ejabberd_auth.erl
+++ b/src/ejabberd_auth.erl
@@ -1,7 +1,7 @@
%%%----------------------------------------------------------------------
%%% File : ejabberd_auth.erl
%%% Author : Alexey Shchepin <alexey@sevcom.net>
-%%% Purpose :
+%%% Purpose : Authentification
%%% Created : 23 Nov 2002 by Alexey Shchepin <alexey@sevcom.net>
%%% Id : $Id$
%%%----------------------------------------------------------------------
@@ -10,10 +10,8 @@
-author('alexey@sevcom.net').
-vsn('$Revision$ ').
--behaviour(gen_server).
-
%% External exports
--export([start/0, start_link/0,
+-export([start/0,
set_password/2,
check_password/2,
check_password/4,
@@ -24,387 +22,59 @@
is_user_exists/1,
remove_user/1,
remove_user/2,
- plain_password_required/0,
- check_password_ldap/2, % TODO: remove
- is_user_exists_ldap/1 % TODO: remove
+ plain_password_required/0
]).
-%% gen_server callbacks
--export([init/1,
- handle_call/3,
- handle_cast/2,
- code_change/3,
- handle_info/2,
- terminate/2]).
-
--include("eldap/eldap.hrl").
-
--record(state, {}).
-
--record(passwd, {user, password}).
-
%%%----------------------------------------------------------------------
%%% API
%%%----------------------------------------------------------------------
start() ->
- case auth_method() of
- external ->
- extauth:start(ejabberd_config:get_local_option(extauth_program));
- _ ->
- ok
- end,
- gen_server:start({local, ejabberd_auth}, ejabberd_auth, [], []).
-
-start_link() ->
- gen_server:start_link({local, ejabberd_auth}, ejabberd_auth, [], []).
-
-%%%----------------------------------------------------------------------
-%%% Callback functions from gen_server
-%%%----------------------------------------------------------------------
-
-%%----------------------------------------------------------------------
-%% Func: init/1
-%% Returns: {ok, State} |
-%% {ok, State, Timeout} |
-%% ignore |
-%% {stop, Reason}
-%%----------------------------------------------------------------------
-init([]) ->
- mnesia:create_table(passwd,[{disc_copies, [node()]},
- {attributes, record_info(fields, passwd)}]),
- case auth_method() of
- internal ->
- ok;
- external ->
- ok;
- ldap ->
- LDAPServers = ejabberd_config:get_local_option(ldap_servers),
- RootDN = ejabberd_config:get_local_option(ldap_rootdn),
- Password = ejabberd_config:get_local_option(ldap_password),
- eldap:start_link("ejabberd", LDAPServers, 389, RootDN, Password),
- eldap:start_link("ejabberd_bind", LDAPServers, 389, RootDN, Password)
- end,
- {ok, #state{}}.
-
-%%----------------------------------------------------------------------
-%% Func: handle_call/3
-%% Returns: {reply, Reply, State} |
-%% {reply, Reply, State, Timeout} |
-%% {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, Reply, State} | (terminate/2 is called)
-%% {stop, Reason, State} (terminate/2 is called)
-%%----------------------------------------------------------------------
-handle_call(_Request, _From, State) ->
- Reply = ok,
- {reply, Reply, State}.
-
-%%----------------------------------------------------------------------
-%% Func: handle_cast/2
-%% Returns: {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State} (terminate/2 is called)
-%%----------------------------------------------------------------------
-handle_cast(_Msg, State) ->
- {noreply, State}.
-
-
-code_change(_OldVsn, State, _Extra) ->
- {ok, State}.
-
-%%----------------------------------------------------------------------
-%% Func: handle_info/2
-%% Returns: {noreply, State} |
-%% {noreply, State, Timeout} |
-%% {stop, Reason, State} (terminate/2 is called)
-%%----------------------------------------------------------------------
-handle_info(_Info, State) ->
- {noreply, State}.
-
-%%----------------------------------------------------------------------
-%% Func: terminate/2
-%% Purpose: Shutdown the server
-%% Returns: any (ignored by gen_server)
-%%----------------------------------------------------------------------
-terminate(_Reason, _State) ->
- ok.
-
-%%%----------------------------------------------------------------------
-%%% Internal functions
-%%%----------------------------------------------------------------------
-
-auth_method() ->
- case ejabberd_config:get_local_option(auth_method) of
- external ->
- external;
- ldap ->
- ldap;
- _ ->
- internal
- end.
-
-user_method() ->
- case ejabberd_config:get_local_option(user_method) of
- ldap ->
- ldap;
- _ ->
- internal
- end.
+ (auth_module()):start().
plain_password_required() ->
- case auth_method() of
- internal ->
- false;
- external ->
- true;
- ldap ->
- true
- end.
+ (auth_module()):plain_password_required().
check_password(User, Password) ->
- case auth_method() of
- internal ->
- check_password_internal(User, Password);
- external ->
- check_password_external(User, Password);
- ldap ->
- check_password_ldap(User, Password)
- end.
-
-check_password_external(User, Password) ->
- extauth:check_password(User, Password).
-
-set_password_external(User, Password) ->
- extauth:set_password(User, Password).
-
-is_user_exists_external(User) ->
- extauth:is_user_exists(User).
-
-check_password_internal(User, Password) ->
- LUser = jlib:nodeprep(User),
- case catch mnesia:dirty_read({passwd, LUser}) of
- [#passwd{password = Password}] ->
- true;
- _ ->
- false
- end.
+ (auth_module()):check_password(User, Password).
check_password(User, Password, StreamID, Digest) ->
- case auth_method() of
- internal ->
- check_password_internal(User, Password, StreamID, Digest);
- external ->
- check_password_external(User, Password, StreamID, Digest);
- ldap ->
- check_password_ldap(User, Password, StreamID, Digest)
- end.
-
-check_password_internal(User, Password, StreamID, Digest) ->
- LUser = jlib:nodeprep(User),
- case catch mnesia:dirty_read({passwd, LUser}) of
- [#passwd{password = Passwd}] ->
- DigRes = if
- Digest /= "" ->
- Digest == sha:sha(StreamID ++ Passwd);
- true ->
- false
- end,
- if DigRes ->
- true;
- true ->
- (Passwd == Password) and (Password /= "")
- end;
- _ ->
- false
- end.
+ (auth_module()):check_password(User, Password, StreamID, Digest).
set_password(User, Password) ->
- case auth_method() of
- internal ->
- set_password_internal(User,Password);
- external ->
- set_password_external(User,Password);
- ldap -> {error, not_allowed}
- end.
-
-set_password_internal(User, Password) ->
- case jlib:nodeprep(User) of
- error -> {error, invalid_jid};
- LUser ->
- F = fun() ->
- mnesia:write(#passwd{user = LUser,
- password = Password})
- end,
- mnesia:transaction(F)
- end.
-
+ (auth_module()):set_password(User, Password).
try_register(User, Password) ->
- case auth_method() of
- internal ->
- try_register_internal(User, Password);
- external ->
- {error, not_allowed};
- ldap ->
- {error, not_allowed}
- end.
-
-try_register_internal(User, Password) ->
- case jlib:nodeprep(User) of
- error -> {error, invalid_jid};
- LUser ->
- F = fun() ->
- case mnesia:read({passwd, LUser}) of
- [] ->
- mnesia:write(#passwd{user = LUser,
- password = Password}),
- ok;
- [_E] ->
- exists
- end
- end,
- mnesia:transaction(F)
- end.
+ (auth_module()):try_register(User, Password).
dirty_get_registered_users() ->
- mnesia:dirty_all_keys(passwd).
+ (auth_module()):dirty_get_registered_users().
get_password(User) ->
- LUser = jlib:nodeprep(User),
- case catch mnesia:dirty_read(passwd, LUser) of
- [#passwd{password = Password}] ->
- Password;
- _ ->
- false
- end.
+ (auth_module()):get_password(User).
get_password_s(User) ->
- LUser = jlib:nodeprep(User),
- case catch mnesia:dirty_read(passwd, LUser) of
- [#passwd{password = Password}] ->
- Password;
- _ ->
- []
- end.
+ (auth_module()):get_password_s(User).
is_user_exists(User) ->
- case auth_method() of
- internal ->
- is_user_exists_internal(User);
- external ->
- is_user_exists_external(User);
- ldap ->
- is_user_exists_ldap(User)
- end.
-
-is_user_exists_internal(User) ->
- LUser = jlib:nodeprep(User),
- case catch mnesia:dirty_read({passwd, LUser}) of
- [] ->
- false;
- [_] ->
- true;
- _ ->
- false
- end.
+ (auth_module()):is_user_exists(User).
remove_user(User) ->
- case user_method() of
- internal ->
- remove_user_internal(User);
- ldap ->
- {error, not_allowed}
- end.
-
-remove_user_internal(User) ->
- LUser = jlib:nodeprep(User),
- F = fun() ->
- mnesia:delete({passwd, LUser})
- end,
- mnesia:transaction(F),
- catch mod_roster:remove_user(User),
- catch mod_offline:remove_user(User),
- catch mod_last:remove_user(User),
- catch mod_vcard:remove_user(User),
- catch mod_private:remove_user(User).
+ (auth_module()):remove_user(User).
remove_user(User, Password) ->
- case user_method() of
- internal ->
- remove_user_internal(User, Password);
- ldap ->
- not_allowed
- end.
-
-remove_user_internal(User, Password) ->
- LUser = jlib:nodeprep(User),
- F = fun() ->
- case mnesia:read({passwd, LUser}) of
- [#passwd{password = Password}] ->
- mnesia:delete({passwd, LUser}),
- ok;
- [_] ->
- not_allowed;
- _ ->
- not_exists
- end
- end,
- case mnesia:transaction(F) of
- {atomic, ok} ->
- catch mod_roster:remove_user(User),
- catch mod_offline:remove_user(User),
- catch mod_last:remove_user(User),
- catch mod_vcard:remove_user(User),
- catch mod_private:remove_user(User),
- ok;
- {atomic, Res} ->
- Res;
- _ ->
- bad_request
- end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-check_password_ldap(User, Password, StreamID, Digest) ->
- check_password_ldap(User, Password).
-
-check_password_external(User, Password, StreamID, Digest) ->
- check_password_external(User, Password).
+ (auth_module()):remove_user(User, Password).
-check_password_ldap(User, Password) ->
- case find_user_dn(User) of
- false ->
- false;
- DN ->
- case eldap:bind("ejabberd_bind", DN, Password) of
- ok ->
- true;
- _ ->
- false
- end
- end.
-
-is_user_exists_ldap(User) ->
- case find_user_dn(User) of
- false ->
- false;
- _DN ->
- true
- end.
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
-find_user_dn(User) ->
- Attr = ejabberd_config:get_local_option(ldap_uidattr),
- Filter = eldap:equalityMatch(Attr, User),
- Base = ejabberd_config:get_local_option(ldap_base),
- case eldap:search("ejabberd", [{base, Base},
- {filter, Filter},
- {attributes, []}]) of
- #eldap_search_result{entries = [E | _]} ->
- E#eldap_entry.object_name;
+auth_module() ->
+ case ejabberd_config:get_local_option(auth_method) of
+ external ->
+ ejabberd_auth_external;
+ ldap ->
+ ejabberd_auth_ldap;
_ ->
- false
+ ejabberd_auth_internal
end.
-
-
diff --git a/src/ejabberd_auth_external.erl b/src/ejabberd_auth_external.erl
new file mode 100644
index 00000000..e379fb9d
--- /dev/null
+++ b/src/ejabberd_auth_external.erl
@@ -0,0 +1,67 @@
+%%%----------------------------------------------------------------------
+%%% File : ejabberd_auth_external.erl
+%%% Author : Alexey Shchepin <alexey@sevcom.net>
+%%% Purpose : Authentification via LDAP external script
+%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@sevcom.net>
+%%% Id : $Id$
+%%%----------------------------------------------------------------------
+
+-module(ejabberd_auth_external).
+-author('alexey@sevcom.net').
+-vsn('$Revision$ ').
+
+%% External exports
+-export([start/0,
+ set_password/2,
+ check_password/2,
+ check_password/4,
+ try_register/2,
+ dirty_get_registered_users/0,
+ get_password/1,
+ get_password_s/1,
+ is_user_exists/1,
+ remove_user/1,
+ remove_user/2,
+ plain_password_required/0
+ ]).
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+start() ->
+ extauth:start(ejabberd_config:get_local_option(extauth_program)),
+ ok.
+
+plain_password_required() ->
+ true.
+
+check_password(User, Password) ->
+ extauth:check_password(User, Password).
+
+check_password(User, Password, _StreamID, _Digest) ->
+ check_password(User, Password).
+
+set_password(User, Password) ->
+ extauth:set_password(User, Password).
+
+try_register(_User, _Password) ->
+ {error, not_allowed}.
+
+dirty_get_registered_users() ->
+ [].
+
+get_password(_User) ->
+ false.
+
+get_password_s(_User) ->
+ "".
+
+is_user_exists(User) ->
+ extauth:is_user_exists(User).
+
+remove_user(_User) ->
+ {error, not_allowed}.
+
+remove_user(_User, _Password) ->
+ not_allowed.
+
diff --git a/src/ejabberd_auth_internal.erl b/src/ejabberd_auth_internal.erl
new file mode 100644
index 00000000..b502eaf9
--- /dev/null
+++ b/src/ejabberd_auth_internal.erl
@@ -0,0 +1,167 @@
+%%%----------------------------------------------------------------------
+%%% File : ejabberd_auth_internal.erl
+%%% Author : Alexey Shchepin <alexey@sevcom.net>
+%%% Purpose : Authentification via mnesia
+%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@sevcom.net>
+%%% Id : $Id$
+%%%----------------------------------------------------------------------
+
+-module(ejabberd_auth_internal).
+-author('alexey@sevcom.net').
+-vsn('$Revision$ ').
+
+%% External exports
+-export([start/0,
+ set_password/2,
+ check_password/2,
+ check_password/4,
+ try_register/2,
+ dirty_get_registered_users/0,
+ get_password/1,
+ get_password_s/1,
+ is_user_exists/1,
+ remove_user/1,
+ remove_user/2,
+ plain_password_required/0
+ ]).
+
+-record(passwd, {user, password}).
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+start() ->
+ mnesia:create_table(passwd,[{disc_copies, [node()]},
+ {attributes, record_info(fields, passwd)}]),
+ ok.
+
+plain_password_required() ->
+ false.
+
+check_password(User, Password) ->
+ LUser = jlib:nodeprep(User),
+ case catch mnesia:dirty_read({passwd, LUser}) of
+ [#passwd{password = Password}] ->
+ true;
+ _ ->
+ false
+ end.
+
+check_password(User, Password, StreamID, Digest) ->
+ LUser = jlib:nodeprep(User),
+ case catch mnesia:dirty_read({passwd, LUser}) of
+ [#passwd{password = Passwd}] ->
+ DigRes = if
+ Digest /= "" ->
+ Digest == sha:sha(StreamID ++ Passwd);
+ true ->
+ false
+ end,
+ if DigRes ->
+ true;
+ true ->
+ (Passwd == Password) and (Password /= "")
+ end;
+ _ ->
+ false
+ end.
+
+set_password(User, Password) ->
+ case jlib:nodeprep(User) of
+ error -> {error, invalid_jid};
+ LUser ->
+ F = fun() ->
+ mnesia:write(#passwd{user = LUser,
+ password = Password})
+ end,
+ mnesia:transaction(F)
+ end.
+
+
+try_register(User, Password) ->
+ case jlib:nodeprep(User) of
+ error -> {error, invalid_jid};
+ LUser ->
+ F = fun() ->
+ case mnesia:read({passwd, LUser}) of
+ [] ->
+ mnesia:write(#passwd{user = LUser,
+ password = Password}),
+ ok;
+ [_E] ->
+ exists
+ end
+ end,
+ mnesia:transaction(F)
+ end.
+
+dirty_get_registered_users() ->
+ mnesia:dirty_all_keys(passwd).
+
+get_password(User) ->
+ LUser = jlib:nodeprep(User),
+ case catch mnesia:dirty_read(passwd, LUser) of
+ [#passwd{password = Password}] ->
+ Password;
+ _ ->
+ false
+ end.
+
+get_password_s(User) ->
+ LUser = jlib:nodeprep(User),
+ case catch mnesia:dirty_read(passwd, LUser) of
+ [#passwd{password = Password}] ->
+ Password;
+ _ ->
+ []
+ end.
+
+is_user_exists(User) ->
+ LUser = jlib:nodeprep(User),
+ case catch mnesia:dirty_read({passwd, LUser}) of
+ [] ->
+ false;
+ [_] ->
+ true;
+ _ ->
+ false
+ end.
+
+remove_user(User) ->
+ LUser = jlib:nodeprep(User),
+ F = fun() ->
+ mnesia:delete({passwd, LUser})
+ end,
+ mnesia:transaction(F),
+ catch mod_roster:remove_user(User),
+ catch mod_offline:remove_user(User),
+ catch mod_last:remove_user(User),
+ catch mod_vcard:remove_user(User),
+ catch mod_private:remove_user(User).
+
+remove_user(User, Password) ->
+ LUser = jlib:nodeprep(User),
+ F = fun() ->
+ case mnesia:read({passwd, LUser}) of
+ [#passwd{password = Password}] ->
+ mnesia:delete({passwd, LUser}),
+ ok;
+ [_] ->
+ not_allowed;
+ _ ->
+ not_exists
+ end
+ end,
+ case mnesia:transaction(F) of
+ {atomic, ok} ->
+ catch mod_roster:remove_user(User),
+ catch mod_offline:remove_user(User),
+ catch mod_last:remove_user(User),
+ catch mod_vcard:remove_user(User),
+ catch mod_private:remove_user(User),
+ ok;
+ {atomic, Res} ->
+ Res;
+ _ ->
+ bad_request
+ end.
diff --git a/src/ejabberd_auth_ldap.erl b/src/ejabberd_auth_ldap.erl
new file mode 100644
index 00000000..63c23c70
--- /dev/null
+++ b/src/ejabberd_auth_ldap.erl
@@ -0,0 +1,106 @@
+%%%----------------------------------------------------------------------
+%%% File : ejabberd_auth_ldap.erl
+%%% Author : Alexey Shchepin <alexey@sevcom.net>
+%%% Purpose : Authentification via LDAP
+%%% Created : 12 Dec 2004 by Alexey Shchepin <alexey@sevcom.net>
+%%% Id : $Id$
+%%%----------------------------------------------------------------------
+
+-module(ejabberd_auth_ldap).
+-author('alexey@sevcom.net').
+-vsn('$Revision$ ').
+
+%% External exports
+-export([start/0,
+ set_password/2,
+ check_password/2,
+ check_password/4,
+ try_register/2,
+ dirty_get_registered_users/0,
+ get_password/1,
+ get_password_s/1,
+ is_user_exists/1,
+ remove_user/1,
+ remove_user/2,
+ plain_password_required/0
+ ]).
+
+-include("eldap/eldap.hrl").
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+start() ->
+ LDAPServers = ejabberd_config:get_local_option(ldap_servers),
+ RootDN = ejabberd_config:get_local_option(ldap_rootdn),
+ Password = ejabberd_config:get_local_option(ldap_password),
+ eldap:start_link("ejabberd", LDAPServers, 389, RootDN, Password),
+ eldap:start_link("ejabberd_bind", LDAPServers, 389, RootDN, Password),
+ ok.
+
+plain_password_required() ->
+ true.
+
+check_password(User, Password) ->
+ case find_user_dn(User) of
+ false ->
+ false;
+ DN ->
+ case eldap:bind("ejabberd_bind", DN, Password) of
+ ok ->
+ true;
+ _ ->
+ false
+ end
+ end.
+
+check_password(User, Password, _StreamID, _Digest) ->
+ check_password(User, Password).
+
+set_password(_User, _Password) ->
+ {error, not_allowed}.
+
+try_register(_User, _Password) ->
+ {error, not_allowed}.
+
+dirty_get_registered_users() ->
+ [].
+
+get_password(_User) ->
+ false.
+
+get_password_s(_User) ->
+ "".
+
+is_user_exists(User) ->
+ case find_user_dn(User) of
+ false ->
+ false;
+ _DN ->
+ true
+ end.
+
+remove_user(_User) ->
+ {error, not_allowed}.
+
+remove_user(_User, _Password) ->
+ not_allowed.
+
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+
+find_user_dn(User) ->
+ Attr = ejabberd_config:get_local_option(ldap_uidattr),
+ Filter = eldap:equalityMatch(Attr, User),
+ Base = ejabberd_config:get_local_option(ldap_base),
+ case eldap:search("ejabberd", [{base, Base},
+ {filter, Filter},
+ {attributes, []}]) of
+ #eldap_search_result{entries = [E | _]} ->
+ E#eldap_entry.object_name;
+ _ ->
+ false
+ end.
+
diff --git a/src/ejabberd_sm.erl b/src/ejabberd_sm.erl
index ef0fa1e1..30a49416 100644
--- a/src/ejabberd_sm.erl
+++ b/src/ejabberd_sm.erl
@@ -331,13 +331,12 @@ set_presence(User, Resource, Priority) ->
mnesia:transaction(F).
unset_presence(User, Resource, Status) ->
- LUser = jlib:nodeprep(User),
F = fun() ->
UR = {User, Resource},
mnesia:delete({presence, UR})
end,
mnesia:transaction(F),
- catch mod_last:on_presence_update(LUser, Status).
+ ejabberd_hooks:run(unset_presence_hook, [User, Resource, Status]).
get_user_present_resources(LUser) ->
case catch mnesia:dirty_index_read(presence, LUser, #presence.user) of
diff --git a/src/mod_last.erl b/src/mod_last.erl
index 8f106d9e..3e7a73fd 100644
--- a/src/mod_last.erl
+++ b/src/mod_last.erl
@@ -16,7 +16,7 @@
stop/0,
process_local_iq/3,
process_sm_iq/3,
- on_presence_update/2,
+ on_presence_update/3,
remove_user/1]).
-include("ejabberd.hrl").
@@ -34,7 +34,9 @@ start(Opts) ->
gen_iq_handler:add_iq_handler(ejabberd_local, ?NS_LAST,
?MODULE, process_local_iq, IQDisc),
gen_iq_handler:add_iq_handler(ejabberd_sm, ?NS_LAST,
- ?MODULE, process_sm_iq, IQDisc).
+ ?MODULE, process_sm_iq, IQDisc),
+ ejabberd_hooks:add(unset_presence_hook,
+ ?MODULE, on_presence_update, 50).
stop() ->
gen_iq_handler:remove_iq_handler(ejabberd_local, ?NS_LAST),
@@ -107,7 +109,8 @@ get_last(IQ, SubEl, LUser) ->
-on_presence_update(LUser, Status) ->
+on_presence_update(User, _Resource, Status) ->
+ LUser = jlib:nodeprep(User),
{MegaSecs, Secs, _MicroSecs} = now(),
TimeStamp = MegaSecs * 1000000 + Secs,
F = fun() ->