io:format("AUTH: ~p~n", [{U, P, D, R}]),
case ejabberd_auth:check_password(U, P) of
true ->
+ % TODO
{next_state, session_established, StateData};
_ ->
- {xmlelement, _, _, SubTags} = El,
- Err = {xmlelement, "iq",
- [{"id", "0"}, {"type", "error"}],
- SubTags ++ [{xmlelement, "error",
- [{"code", "404"}],
- [{xmlcdata, "Unauthorized"}]}]},
+ Err = xml:make_error_iq_reply(El, "404", "Unauthorized"),
send_element(StateData#state.sender, Err),
{next_state, wait_for_auth, StateData}
end;
true ->
false
end;
-
is_auth_packet(_) ->
false.
--- /dev/null
+%%%----------------------------------------------------------------------
+%%% File : ejabberd_sm.erl
+%%% Author : Alexey Shchepin <alexey@sevcom.net>
+%%% Purpose :
+%%% Created : 24 Nov 2002 by Alexey Shchepin <alexey@sevcom.net>
+%%% Id : $Id$
+%%%----------------------------------------------------------------------
+
+-module(ejabberd_sm).
+-author('alexey@sevcom.net').
+
+-export([start/0, init/0, open_session/2]).
+
+-include_lib("mnemosyne/include/mnemosyne.hrl").
+
+-record(user_resource, {id, user, resource}).
+-record(user_resource_id_seq, {name = value, id}).
+-record(session, {id, node}).
+-record(mysession, {id, info}).
+
+-record(mysession_info, {pid}).
+
+
+start() ->
+ spawn(ejabberd_sm, init, []).
+
+init() ->
+ register(ejabberd_sm, self()),
+ mnesia:create_table(user_resource_id_seq,
+ [{ram_copies, [node()]},
+ {attributes,
+ record_info(fields, user_resource_id_seq)}]),
+ init_seq(),
+ mnesia:create_table(user_resource,[{ram_copies, [node()]},
+ {attributes,
+ record_info(fields, user_resource)}]),
+ mnesia:add_table_index(user_resource, user),
+ mnesia:create_table(session,[{ram_copies, [node()]},
+ {attributes, record_info(fields, session)}]),
+ mnesia:add_table_index(session, node),
+ mnesia:create_table(mysession,
+ [{ram_copies, [node()]},
+ {local_content, true},
+ {attributes, record_info(fields, mysession)}]),
+ mnesia:subscribe(system),
+ loop().
+
+loop() ->
+ receive
+ {open_session, User, Resource, From} ->
+ replace_and_register_my_connection(User, Resource, From),
+ replace_alien_connection(User, Resource),
+ loop();
+ {replace, User, Resource} ->
+ replace_my_connection(User, Resource),
+ loop();
+ {mnesia_system_event, {mnesia_down, Node}} ->
+ clean_table_from_bad_node(Node),
+ loop();
+ _ ->
+ loop()
+ end.
+
+
+open_session(User, Resource) ->
+ ejabberd_sm ! {open_session, User, Resource, self()}.
+
+replace_alien_connection(User, Resource) ->
+ F = fun() ->
+ [ID] = mnemosyne:eval(query [X.id || X <- table(user_resource),
+ X.user = User,
+ X.resource = Resource]
+ end),
+ Es = mnesia:read({session, ID}),
+ mnesia:write(#session{id = ID, node = node()}),
+ Es
+ end,
+ case mnesia:transaction(F) of
+ {atomic, Rs} ->
+ lists:foreach(
+ fun(R) ->
+ if R#session.node /= node() ->
+ {ejabberd_sm, R#session.node} !
+ {replace, User, Resource};
+ true ->
+ ok
+ end
+ end, Rs);
+ _ ->
+ false
+ end.
+
+
+replace_my_connection(User, Resource) ->
+ F = fun() ->
+ [ID] = mnemosyne:eval(query [X.id || X <- table(user_resource),
+ X.user = User,
+ X.resource = Resource]
+ end),
+
+ Es = mnesia:read({mysession, ID}),
+ mnesia:delete({mysession, ID}),
+ Es
+ end,
+ case mnesia:transaction(F) of
+ {atomic, Rs} ->
+ lists:foreach(
+ fun(R) ->
+ (R#mysession.info)#mysession_info.pid ! replaced
+ end, Rs);
+ _ ->
+ false
+ end.
+
+replace_and_register_my_connection(User, Resource, Pid) ->
+ F = fun() ->
+ IDs = mnemosyne:eval(query [X.id || X <- table(user_resource),
+ X.user = User,
+ X.resource = Resource]
+ end),
+
+ ID = case IDs of
+ [Id] -> Id;
+ [] ->
+ [CurID] =
+ mnemosyne:eval(
+ query [X.id ||
+ X <- table(user_resource_id_seq)]
+ end),
+ mnesia:write(
+ #user_resource_id_seq{id = CurID + 1}),
+ mnesia:write(
+ #user_resource{id = CurID,
+ user = User,
+ resource = Resource}),
+ CurID
+ end,
+ Es = mnesia:read({mysession, ID}),
+ mnesia:write(#mysession{id = ID,
+ info = #mysession_info{pid = Pid}}),
+ Es
+ end,
+ case mnesia:transaction(F) of
+ {atomic, Rs} ->
+ lists:foreach(
+ fun(R) ->
+ (R#mysession.info)#mysession_info.pid ! replaced
+ end, Rs);
+ _ ->
+ false
+ end.
+
+
+clean_table_from_bad_node(Node) ->
+ F = fun() ->
+ Es = mnesia:index_read(session, Node, #session.node),
+ lists:foreach(fun(E) ->
+ mnesia:delete_object(session, E, write),
+ mnesia:delete(
+ {user_resource, E#session.id})
+ end, Es)
+ end,
+ mnesia:transaction(F).
+
+init_seq() ->
+ F = fun() ->
+ [] = mnesia:read({user_resource_id_seq, value}),
+ mnesia:write(#user_resource_id_seq{id = 0})
+ end,
+ mnesia:transaction(F).
+
-vsn('$Revision$ ').
-export([element_to_string/1, crypt/1, remove_cdata/1, get_cdata/1,
- get_attr/2, get_attr_s/2]).
+ get_attr/2, get_attr_s/2, make_error_iq_reply/3]).
element_to_string(El) ->
case El of
""
end.
+
+make_error_iq_reply({xmlelement, Name, Attrs, SubTags}, Code, Desc)
+ when Name == "iq" ->
+ NewAttrs = make_error_iq_reply_attrs(Attrs),
+ {xmlelement, Name, NewAttrs, SubTags ++ [{xmlelement, "error",
+ [{"code", Code}],
+ [{xmlcdata, Desc}]}]}.
+
+make_error_iq_reply_attrs(Attrs) ->
+ To = get_attr("to", Attrs),
+ From = get_attr("from", Attrs),
+ Attrs1 = lists:keydelete("to", 1, Attrs),
+ Attrs2 = lists:keydelete("from", 1, Attrs1),
+ Attrs3 = case To of
+ {value, ToVal} ->
+ [{"from", ToVal} | Attrs2];
+ _ ->
+ Attrs2
+ end,
+ Attrs4 = case From of
+ {value, FromVal} ->
+ [{"to", FromVal} | Attrs3];
+ _ ->
+ Attrs3
+ end,
+ Attrs5 = lists:keydelete("type", 1, Attrs4),
+ Attrs6 = [{"type", "error"} | Attrs5],
+ Attrs6.