%
-export([init/1, wait_for_stream/2, wait_for_auth/2, terminate/3]).
--record(state, {socket, sender, receiver}).
+-record(state, {socket, sender, receiver, streamid}).
-include("ejabberd.hrl").
-%start_old(Socket) ->
-% spawn(?MODULE, init, [Socket]).
-
-%init_old(Socket) ->
-% SenderPid = spawn(?MODULE, sender, [Socket]),
-% ReceiverPid = spawn(?MODULE, receiver, [Socket, self()]),
-% loop_old(Socket, SenderPid, ReceiverPid).
-%
-%loop_old(Socket, SenderPid, ReceiverPid) ->
-% receive
-% {xmlstreamstart, Name, Attrs} ->
-% ?DEBUG("Socket(~p) -> XML Stream start~n"
-% " Name: ~s~n"
-% " Attrs: ~p~n", [Socket, Name, Attrs]),
-% loop_old(Socket, SenderPid, ReceiverPid);
-% {xmlstreamend, Name} ->
-% ?DEBUG("Socket(~p) -> XML Stream end~n"
-% " Name: ~s~n", [Socket, Name]),
-% loop_old(Socket, SenderPid, ReceiverPid);
-% {xmlstreamelement, El} ->
-% ?DEBUG("Socket(~p) -> XML Stream element~n"
-% " Element: ~p~n", [Socket, El]),
-% loop_old(Socket, SenderPid, ReceiverPid);
-% {xmlstreamerror, Err} ->
-% ?DEBUG("Socket(~p) -> XML Stream error~n"
-% " Error: ~p~n", [Socket, Err]),
-% loop_old(Socket, SenderPid, ReceiverPid)
-% end.
-
-
-%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
-
-define(DBGFSM, true).
-ifdef(DBGFSM).
%%%----------------------------------------------------------------------
start(Socket) ->
gen_fsm:start(ejabberd_c2s, [Socket], ?FSMOPTS).
-%start_old(Socket) ->
-% spawn(?MODULE, init, [Socket]).
%%%----------------------------------------------------------------------
%%% Callback functions from gen_fsm
ReceiverPid = spawn(?MODULE, receiver, [Socket, self()]),
{ok, wait_for_stream, #state{socket = Socket,
receiver = ReceiverPid,
- sender = SenderPid}}.
+ sender = SenderPid,
+ streamid = new_id()}}.
%%----------------------------------------------------------------------
%% Func: StateName/2
wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
% TODO
- Header = io_lib:format(?STREAM_HEADER, ["SID", "localhost"]),
+ Header = io_lib:format(?STREAM_HEADER,
+ [StateData#state.streamid, "localhost"]),
send_text(StateData#state.sender, Header),
case lists:keysearch("xmlns:stream", 1, Attrs) of
{value, {"xmlns:stream", "http://etherx.jabber.org/streams"}} ->
wait_for_auth({xmlstreamelement, El}, StateData) ->
- % TODO
- {next_state, wait_for_auth, StateData};
+ case is_auth_packet(El) of
+ {auth, {U, P, D, R}} ->
+ io:format("AUTH: ~p~n", [{U, P, D, R}]),
+ % TODO
+ {next_state, session_established, StateData};
+ _ ->
+ {next_state, wait_for_auth, StateData}
+end;
wait_for_auth({xmlstreamend, Name}, StateData) ->
% TODO
send_text(Pid, Text) ->
Pid ! {text, Text}.
+new_id() ->
+ io_lib:format("~p", [random:uniform(65536*65536)]).
+
+
+is_auth_packet({xmlelement, Name, Attrs, Els}) when Name == "iq" ->
+ case xml:get_attr_s("type", Attrs) of
+ "set" ->
+ case xml:remove_cdata(Els) of
+ [{xmlelement, "query", Attrs2, Els2}] ->
+ case xml:get_attr_s("xmlns", Attrs2) of
+ "jabber:iq:auth" ->
+ {auth, get_auth_tags(Els2, "", "", "", "")};
+ _ -> false
+ end;
+ _ ->
+ false
+ end;
+ true ->
+ false
+ end;
+
+is_auth_packet(_) ->
+ false.
+
+get_auth_tags([{xmlelement, Name, Attrs, Els}| L], U, P, D, R) ->
+ CData = xml:get_cdata(Els),
+ case Name of
+ "username" ->
+ get_auth_tags(L, CData, P, D, R);
+ "password" ->
+ get_auth_tags(L, U, CData, D, R);
+ "digest" ->
+ get_auth_tags(L, U, P, CData, R);
+ "resource" ->
+ get_auth_tags(L, U, P, D, CData);
+ _ ->
+ get_auth_tags(L, U, P, D, R)
+ end;
+get_auth_tags([_ | L], U, P, D, R) ->
+ get_auth_tags(L, U, P, D, R);
+get_auth_tags([], U, P, D, R) ->
+ {U, P, D, R}.
+
+
--- /dev/null
+%%%----------------------------------------------------------------------
+%%% File : xml.erl
+%%% Author : Alexey Shchepin <alexey@sevcom.net>
+%%% Purpose : XML utils
+%%% Created : 20 Nov 2002 by Alexey Shchepin <alexey@sevcom.net>
+%%% Id : $Id$
+%%%----------------------------------------------------------------------
+
+-module(xml).
+-author('alexey@sevcom.net').
+-vsn('$Revision$ ').
+
+-export([element_to_string/1, crypt/1, remove_cdata/1, get_cdata/1,
+ get_attr/2, get_attr_s/2]).
+
+element_to_string(El) ->
+ case El of
+ {xmlelement, Name, Attrs, Els} ->
+ if length(Els) > 0 ->
+ "<" ++ Name ++ attrs_to_string(Attrs) ++ ">" ++
+ lists:append(
+ lists:map(fun(E) -> element_to_string(E) end, Els))
+ ++ "</" ++ Name ++ ">";
+ true ->
+ "<" ++ Name ++ attrs_to_string(Attrs) ++ "/>"
+ end;
+ {xmlcdata, CData} -> crypt(CData)
+ end.
+
+
+attrs_to_string(Attrs) ->
+ lists:append(lists:map(fun(A) -> attr_to_string(A) end, Attrs)).
+
+attr_to_string({Name, Value}) ->
+ " " ++ crypt(Name) ++ "='" ++ crypt(Value) ++ "'".
+
+crypt(S) ->
+ lists:reverse(crypt(S, "")).
+
+crypt([$& | S], R) ->
+ crypt(S, [$;, $p, $m, $a, $& | R]);
+crypt([$< | S], R) ->
+ crypt(S, [$;, $t, $l, $& | R]);
+crypt([$> | S], R) ->
+ crypt(S, [$;, $t, $g, $& | R]);
+crypt([$" | S], R) ->
+ crypt(S, [$;, $t, $o, $u, $q, $& | R]);
+crypt([$' | S], R) ->
+ crypt(S, [$;, $s, $o, $p, $a, $& | R]);
+crypt([C | S], R) ->
+ crypt(S, [C | R]);
+crypt([], R) ->
+ R.
+
+
+remove_cdata(L) ->
+ lists:reverse(remove_cdata(L, [])).
+
+remove_cdata([{xmlelement, Name, Attrs, Els} | L], R) ->
+ remove_cdata(L, [{xmlelement, Name, Attrs, Els} | R]);
+remove_cdata([{xmlcdata, CData} | L], R) ->
+ remove_cdata(L, R);
+remove_cdata([], R) ->
+ R.
+
+get_cdata(L) ->
+ get_cdata(L, "").
+
+get_cdata([{xmlcdata, CData} | L], S) ->
+ get_cdata(L, S ++ CData);
+get_cdata([_ | L], S) ->
+ get_cdata(L, S);
+get_cdata([], S) ->
+ S.
+
+
+get_attr(AttrName, Attrs) ->
+ case lists:keysearch(AttrName, 1, Attrs) of
+ {value, {_, Val}} ->
+ {value, Val};
+ _ ->
+ false
+ end.
+
+get_attr_s(AttrName, Attrs) ->
+ case lists:keysearch(AttrName, 1, Attrs) of
+ {value, {_, Val}} ->
+ Val;
+ _ ->
+ ""
+ end.
+