-behaviour(gen_server).
%% External exports
--export([start/0, start_link/0, set_password/2, check_password/2]).
+-export([start/0, start_link/0,
+ set_password/2,
+ check_password/2,
+ try_register/2]).
%% gen_server callbacks
-export([init/1, handle_call/3, handle_cast/2, handle_info/2, terminate/2]).
-record(state, {}).
--record(passwd, {jid, password}).
+-record(passwd, {user, password}).
%%%----------------------------------------------------------------------
%%% API
%%% Internal functions
%%%----------------------------------------------------------------------
-check_password(Jid, Password) ->
+% TODO: lowercase user name
+
+check_password(User, Password) ->
F = fun() ->
- case mnesia:read({passwd, Jid}) of
+ case mnesia:read({passwd, User}) of
[E] ->
E#passwd.password
end
end.
-set_password(Jid, Password) ->
+set_password(User, Password) ->
+ F = fun() ->
+ mnesia:write(#passwd{user = User, password = Password})
+ end,
+ mnesia:transaction(F).
+
+try_register(User, Password) ->
F = fun() ->
- case mnesia:read({passwd, Jid}) of
+ case mnesia:read({passwd, User}) of
[] ->
- New = #passwd{jid = Jid, password = Password},
- mnesia:write(New);
+ mnesia:write(#passwd{user = User, password = Password}),
+ ok;
[E] ->
- New = E#passwd{password = Password},
- mnesia:write(New)
+ exists
end
end,
mnesia:transaction(F).
-
+
{next_state, wait_for_auth, StateData}
end;
_ ->
- {next_state, wait_for_auth, StateData}
+ case jlib:iq_query_info(El) of
+ {iq, ID, Type, "jabber:iq:register", SubEl} ->
+ ResIQ = mod_register:process_iq(
+ {"", "", ""}, {"", ?MYNAME, ""},
+ {iq, ID, Type, "jabber:iq:register", SubEl}),
+ Res1 = jlib:replace_from_to({"", ?MYNAME, ""},
+ {"", "", ""},
+ jlib:iq_to_xml(ResIQ)),
+ Res = jlib:remove_attr("to", Res1),
+ send_element(StateData#state.sender, Res),
+ {next_state, wait_for_auth, StateData};
+ _ ->
+ {next_state, wait_for_auth, StateData}
+ end
end;
wait_for_auth({xmlstreamend, Name}, StateData) ->
make_error_reply/3,
make_correct_from_to_attrs/3,
replace_from_to_attrs/3,
+ replace_from_to/3,
+ remove_attr/2,
string_to_jid/1,
jid_to_string/1,
- tolower/1]).
+ tolower/1,
+ get_iq_namespace/1,
+ iq_query_info/1,
+ iq_to_xml/1,
+ get_subtag/2]).
%send_iq(From, To, ID, SubTags) ->
Attrs4 = [{"from", From} | Attrs3],
Attrs4.
+replace_from_to(From, To, {xmlelement, Name, Attrs, Els}) ->
+ NewAttrs = replace_from_to_attrs(jlib:jid_to_string(From),
+ jlib:jid_to_string(To),
+ Attrs),
+ {xmlelement, Name, NewAttrs, Els}.
+
+
+remove_attr(Attr, {xmlelement, Name, Attrs, Els}) ->
+ NewAttrs = lists:keydelete(Attr, 1, Attrs),
+ {xmlelement, Name, NewAttrs, Els}.
string_to_jid(J) ->
string_to_jid1(J, "").
tolower(S) ->
lists:map(fun tolower_c/1, S).
+
+
+get_iq_namespace({xmlelement, Name, Attrs, Els}) when Name == "iq" ->
+ case xml:remove_cdata(Els) of
+ [{xmlelement, Name2, Attrs2, Els2}] ->
+ xml:get_attr_s("xmlns", Attrs2);
+ _ ->
+ ""
+ end;
+get_iq_namespace(_) ->
+ "".
+
+iq_query_info({xmlelement, Name, Attrs, Els}) when Name == "iq" ->
+ ID = xml:get_attr_s("id", Attrs),
+ Type = xml:get_attr_s("type", Attrs),
+ case xml:remove_cdata(Els) of
+ [{xmlelement, Name2, Attrs2, Els2}] ->
+ XMLNS = xml:get_attr_s("xmlns", Attrs2),
+ Type1 = case Type of
+ "set" -> set;
+ "get" -> get;
+ _ -> invalid
+ end,
+ if
+ (Type1 /= invalid) and (XMLNS /= "") ->
+ {iq, ID, Type1, XMLNS, {xmlelement, Name2, Attrs2, Els2}};
+ true ->
+ invalid
+ end;
+ _ ->
+ invalid
+ end;
+iq_query_info(_) ->
+ not_iq.
+
+iq_type_to_string(set) -> "set";
+iq_type_to_string(get) -> "get";
+iq_type_to_string(result) -> "result";
+iq_type_to_string(error) -> "error";
+iq_type_to_string(_) -> invalid.
+
+
+iq_to_xml({iq, ID, Type, _, SubEl}) ->
+ if
+ ID /= "" ->
+ {xmlelement, "iq",
+ [{"id", ID}, {"type", iq_type_to_string(Type)}], SubEl};
+ true ->
+ {xmlelement, "iq",
+ [{"type", iq_type_to_string(Type)}], SubEl}
+ end.
+
+
+get_subtag({xmlelement, _, _, Els}, Name) ->
+ get_subtag1(Els, Name).
+
+get_subtag1([El | Els], Name) ->
+ case El of
+ {xmlelement, Name, _, _} ->
+ El;
+ _ ->
+ get_subtag1(Els, Name)
+ end;
+get_subtag1([], _) ->
+ false.
+
+
--- /dev/null
+%%%----------------------------------------------------------------------
+%%% File : mod_register.erl
+%%% Author : Alexey Shchepin <alexey@sevcom.net>
+%%% Purpose :
+%%% Created : 8 Dec 2002 by Alexey Shchepin <alexey@sevcom.net>
+%%% Id : $Id$
+%%%----------------------------------------------------------------------
+
+-module(mod_register).
+-author('alexey@sevcom.net').
+-vsn('$Revision$ ').
+
+-export([process_iq/3]).
+
+-include("ejabberd.hrl").
+
+process_iq(From, To, {iq, ID, Type, XMLNS, SubEl}) ->
+ case Type of
+ set ->
+ UTag = jlib:get_subtag(SubEl, "username"),
+ PTag = jlib:get_subtag(SubEl, "password"),
+ RTag = jlib:get_subtag(SubEl, "remove"),
+ if
+ (UTag /= false) and (RTag /= false) ->
+ {iq, ID, error, XMLNS,
+ [SubEl, {xmlelement,
+ "error",
+ [{"code", "501"}],
+ [{xmlcdata, "Not Implemented"}]}]};
+ (UTag /= false) and (PTag /= false) ->
+ User = xml:get_tag_cdata(UTag),
+ Password = xml:get_tag_cdata(PTag),
+ Server = ?MYNAME,
+ case From of
+ {User, Server, _} ->
+ ejabberd_auth:set_password(User, Password),
+ {iq, ID, result, XMLNS, [SubEl]};
+ _ ->
+ case try_register(User, Password) of
+ ok ->
+ {iq, ID, result, XMLNS, [SubEl]};
+ {error, Code, Reason} ->
+ {iq, ID, error, XMLNS,
+ [SubEl, {xmlelement,
+ "error",
+ [{"code", Code}],
+ [{xmlcdata, Reason}]}]}
+ end
+ end
+ end;
+ get ->
+ {iq, ID, error, XMLNS, [{xmlelement,
+ "query",
+ [{"xmlns", "jabber:iq:register"}],
+ [{xmlelement, "instructions", [],
+ {xmlcdata,
+ "Choose a username and password "
+ "to register with this server."}},
+ {xmlelement, "username", [], []},
+ {xmlelement, "password", [], []}]}]}
+ end.
+
+
+try_register(User, Password) ->
+ case ejabberd_auth:try_register(User, Password) of
+ {atomic, ok} ->
+ ok;
+ {atomic, exists} ->
+ {error, "400", "Bad Request"};
+ {error, Reason} ->
+ {error, "500", "Internal Server Error"}
+ end.
+
+
+
-author('alexey@sevcom.net').
-vsn('$Revision$ ').
--export([element_to_string/1, crypt/1, remove_cdata/1, get_cdata/1,
+-export([element_to_string/1, crypt/1, remove_cdata/1,
+ get_cdata/1, get_tag_cdata/1,
get_attr/2, get_attr_s/2]).
element_to_string(El) ->
get_cdata(L, S);
get_cdata([], S) ->
S.
-
+
+get_tag_cdata({xmlelement, Name, Attrs, Els}) ->
+ get_cdata(Els).
get_attr(AttrName, Attrs) ->
case lists:keysearch(AttrName, 1, Attrs) of