]> granicus.if.org Git - ejabberd/commitdiff
*** empty log message ***
authorAlexey Shchepin <alexey@process-one.net>
Fri, 6 Dec 2002 20:59:19 +0000 (20:59 +0000)
committerAlexey Shchepin <alexey@process-one.net>
Fri, 6 Dec 2002 20:59:19 +0000 (20:59 +0000)
SVN Revision: 12

src/ejabberd_listener.erl
src/ejabberd_s2s_in.erl [new file with mode: 0644]
src/ejabberd_s2s_out.erl [new file with mode: 0644]

index 532a06f3f62b5548d7aeac92db5c700130a4aa73..d9ff728b799e9f8fde86e03c5da6fd7d5b421bde 100644 (file)
 -author('alexey@sevcom.net').
 -vsn('$Revision$ ').
 
--export([start/0, init/0]).
+-export([start/0, init/2]).
 
 start() ->
-    register(ejabberd_listener, spawn(?MODULE, init, [])).
+    register(ejabberd_listener_c2s,
+            spawn(?MODULE, init, [5522, ejabberd_c2s])),
+    register(ejabberd_listener_s2s,
+            spawn(?MODULE, init, [5269, ejabberd_s2s_in])).
 
-init() ->
-    {ok, ListenSocket} = gen_tcp:listen(5522, [binary,
+init(Port, CallbackModule) ->
+    {ok, ListenSocket} = gen_tcp:listen(Port, [binary,
                                               {packet, 0}, 
                                               {active, false},
                                               {reuseaddr, true}]),
-    accept(ListenSocket).
+    accept(ListenSocket, CallbackModule).
 
-accept(ListenSocket) ->
+accept(ListenSocket, CallbackModule) ->
     case gen_tcp:accept(ListenSocket) of
        {ok,Socket} ->
-           ejabberd_c2s:start(Socket),
-           accept(ListenSocket)
-    end.
-
-
-
-do_recv(Sock, Bs) ->
-    case gen_tcp:recv(Sock, 0) of
-        {ok, B} ->
-           do_recv(Sock, [Bs, B]);
-        {error, closed} ->
-           {ok, list_to_binary(Bs)}
+           apply(CallbackModule, start, [Socket]),
+           %ejabberd_c2s:start(Socket),
+           accept(ListenSocket, CallbackModule)
     end.
 
 
diff --git a/src/ejabberd_s2s_in.erl b/src/ejabberd_s2s_in.erl
new file mode 100644 (file)
index 0000000..b0300b8
--- /dev/null
@@ -0,0 +1,274 @@
+%%%----------------------------------------------------------------------
+%%% File    : ejabberd_s2s_in.erl
+%%% Author  : Alexey Shchepin <alexey@sevcom.net>
+%%% Purpose : 
+%%% Created :  6 Dec 2002 by Alexey Shchepin <alexey@sevcom.net>
+%%% Id      : $Id$
+%%%----------------------------------------------------------------------
+
+-module(ejabberd_s2s_in).
+-author('alexey@sevcom.net').
+-vsn('$Revision$ ').
+
+-behaviour(gen_fsm).
+
+%% External exports
+-export([start/1, receiver/2, send_text/2, send_element/2]).
+
+%% gen_fsm callbacks
+-export([init/1, wait_for_stream/2, wait_for_key/2, session_established/2,
+        handle_info/3,
+        terminate/3]).
+
+-record(state, {socket, receiver, streamid,
+               myself = "localhost", server}).
+
+-include("ejabberd.hrl").
+
+-define(DBGFSM, true).
+
+-ifdef(DBGFSM).
+-define(FSMOPTS, [{debug, [trace]}]).
+-else.
+-define(FSMOPTS, []).
+-endif.
+
+-define(STREAM_HEADER,
+       "<?xml version='1.0'?>"
+       "<stream:stream "
+       "xmlns:stream='http://etherx.jabber.org/streams' "
+       "xmlns='jabber:server' "
+       "xmlns:db='jabber:server:dialback'>"
+       ).
+
+-define(STREAM_TRAILER, "</stream:stream>").
+
+-define(INVALID_HEADER_ERR,
+       "<stream:stream>"
+       "<stream:error>Invalid Stream Header</stream:error>"
+       "</stream:stream>"
+       ).
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+start(Socket) ->
+    gen_fsm:start(ejabberd_s2s_in, [Socket], ?FSMOPTS).
+
+%%%----------------------------------------------------------------------
+%%% Callback functions from gen_fsm
+%%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, StateName, StateData}          |
+%%          {ok, StateName, StateData, Timeout} |
+%%          ignore                              |
+%%          {stop, StopReason}                   
+%%----------------------------------------------------------------------
+init([Socket]) ->
+    ReceiverPid = spawn(?MODULE, receiver, [Socket, self()]),
+    {ok, wait_for_stream, #state{socket = Socket,
+                                receiver = ReceiverPid,
+                                streamid = new_id()}}.
+
+%%----------------------------------------------------------------------
+%% Func: StateName/2
+%% Returns: {next_state, NextStateName, NextStateData}          |
+%%          {next_state, NextStateName, NextStateData, Timeout} |
+%%          {stop, Reason, NewStateData}                         
+%%----------------------------------------------------------------------
+state_name(Event, StateData) ->
+    {next_state, state_name, StateData}.
+
+wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
+    % TODO
+    case {xml:get_attr_s("xmlns", Attrs), xml:get_attr_s("xmlns:db", Attrs)} of
+       {"jabber:server", "jabber:server:dialback"} ->
+           send_text(StateData#state.socket, ?STREAM_HEADER),
+           {next_state, wait_for_key, StateData};
+       _ ->
+           send_text(StateData#state.socket, ?INVALID_HEADER_ERR),
+           {stop, normal, StateData}
+    end;
+
+wait_for_stream(closed, StateData) ->
+    {stop, normal, StateData}.
+
+
+wait_for_key({xmlstreamelement, El}, StateData) ->
+    case is_key_packet(El) of
+       {key, To, From, Id, Key} ->
+           io:format("GET KEY: ~p~n", [{To, From, Id, Key}]),
+           % TODO
+           ejabberd_s2s_out:start(From, {verify, self(), Key}),
+           {next_state, wait_for_key, StateData};
+       {verify, To, From, Id, Key} ->
+           io:format("VERIFY KEY: ~p~n", [{To, From, Id, Key}]),
+           % TODO
+           {next_state, wait_for_key, StateData};
+       _ ->
+           {next_state, wait_for_key, StateData}
+    end;
+
+wait_for_key({xmlstreamend, Name}, StateData) ->
+    % TODO
+    {stop, normal, StateData};
+
+wait_for_key(closed, StateData) ->
+    {stop, normal, StateData}.
+
+session_established({xmlstreamelement, El}, StateData) ->
+    {xmlelement, Name, Attrs, Els} = El,
+    % TODO
+    FromJID = {StateData#state.server},
+    To = xml:get_attr_s("to", Attrs),
+    ToJID = case To of
+               "" ->
+                   {"", StateData#state.server, ""};
+               _ ->
+                   jlib:string_to_jid(To)
+           end,
+    case ToJID of
+       error ->
+           % TODO
+           error;
+       _ ->
+           %?DEBUG("FromJID=~w, ToJID=~w, El=~w~n", [FromJID, ToJID, El]),
+           ejabberd_router:route(FromJID, ToJID, El)
+    end,
+    {next_state, session_established, StateData};
+
+session_established(closed, StateData) ->
+    % TODO
+    {stop, normal, StateData}.
+
+
+
+%%----------------------------------------------------------------------
+%% Func: StateName/3
+%% Returns: {next_state, NextStateName, NextStateData}            |
+%%          {next_state, NextStateName, NextStateData, Timeout}   |
+%%          {reply, Reply, NextStateName, NextStateData}          |
+%%          {reply, Reply, NextStateName, NextStateData, Timeout} |
+%%          {stop, Reason, NewStateData}                          |
+%%          {stop, Reason, Reply, NewStateData}                    
+%%----------------------------------------------------------------------
+state_name(Event, From, StateData) ->
+    Reply = ok,
+    {reply, Reply, state_name, StateData}.
+
+%%----------------------------------------------------------------------
+%% Func: handle_event/3
+%% Returns: {next_state, NextStateName, NextStateData}          |
+%%          {next_state, NextStateName, NextStateData, Timeout} |
+%%          {stop, Reason, NewStateData}                         
+%%----------------------------------------------------------------------
+handle_event(Event, StateName, StateData) ->
+    {next_state, StateName, StateData}.
+
+%%----------------------------------------------------------------------
+%% Func: handle_sync_event/4
+%% Returns: {next_state, NextStateName, NextStateData}            |
+%%          {next_state, NextStateName, NextStateData, Timeout}   |
+%%          {reply, Reply, NextStateName, NextStateData}          |
+%%          {reply, Reply, NextStateName, NextStateData, Timeout} |
+%%          {stop, Reason, NewStateData}                          |
+%%          {stop, Reason, Reply, NewStateData}                    
+%%----------------------------------------------------------------------
+handle_sync_event(Event, From, StateName, StateData) ->
+    Reply = ok,
+    {reply, Reply, StateName, StateData}.
+
+%%----------------------------------------------------------------------
+%% Func: handle_info/3
+%% Returns: {next_state, NextStateName, NextStateData}          |
+%%          {next_state, NextStateName, NextStateData, Timeout} |
+%%          {stop, Reason, NewStateData}                         
+%%----------------------------------------------------------------------
+handle_info({send_text, Text}, StateName, StateData) ->
+    send_text(StateData#state.socket, Text),
+    {next_state, StateName, StateData}.
+
+%%----------------------------------------------------------------------
+%% Func: terminate/3
+%% Purpose: Shutdown the fsm
+%% Returns: any
+%%----------------------------------------------------------------------
+terminate(Reason, StateName, StateData) ->
+%    case StateData#state.user of
+%      "" ->
+%          ok;
+%      _ ->
+%          %ejabberd_sm:close_session(StateData#state.user,
+%          %                         StateData#state.resource)
+%    end,
+    gen_tcp:close(StateData#state.socket),
+    ok.
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+
+receiver(Socket, C2SPid) ->
+    XMLStreamPid = xml_stream:start(C2SPid),
+    receiver(Socket, C2SPid, XMLStreamPid).
+
+receiver(Socket, C2SPid, XMLStreamPid) ->
+    case gen_tcp:recv(Socket, 0) of
+        {ok, Text} ->
+           xml_stream:send_text(XMLStreamPid, Text),
+           receiver(Socket, C2SPid, XMLStreamPid);
+        {error, closed} ->
+           exit(XMLStreamPid, closed),
+           gen_fsm:send_event(C2SPid, closed),
+           ok
+    end.
+
+send_text(Socket, Text) ->
+    gen_tcp:send(Socket,Text).
+
+send_element(Socket, El) ->
+    send_text(Socket, xml:element_to_string(El)).
+
+new_id() ->
+    lists:flatten(io_lib:format("~p", [random:uniform(65536*65536)])).
+
+
+is_key_packet({xmlelement, Name, Attrs, Els}) when Name == "db:result" ->
+    {key,
+     xml:get_attr_s("to", Attrs),
+     xml:get_attr_s("from", Attrs),
+     xml:get_attr_s("id", Attrs),
+     xml:get_cdata(Els)};
+is_key_packet({xmlelement, Name, Attrs, Els}) when Name == "db:verify" ->
+    {verify,
+     xml:get_attr_s("to", Attrs),
+     xml:get_attr_s("from", Attrs),
+     xml:get_attr_s("id", Attrs),
+     xml:get_cdata(Els)};
+is_key_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}.
+
+
+
+
diff --git a/src/ejabberd_s2s_out.erl b/src/ejabberd_s2s_out.erl
new file mode 100644 (file)
index 0000000..b51a61d
--- /dev/null
@@ -0,0 +1,341 @@
+%%%----------------------------------------------------------------------
+%%% File    : ejabberd_s2s_out.erl
+%%% Author  : Alexey Shchepin <alexey@sevcom.net>
+%%% Purpose : 
+%%% Created :  6 Dec 2002 by Alexey Shchepin <alexey@sevcom.net>
+%%% Id      : $Id$
+%%%----------------------------------------------------------------------
+
+-module(ejabberd_s2s_out).
+-author('alexey@sevcom.net').
+-vsn('$Revision$ ').
+
+-behaviour(gen_fsm).
+
+%% External exports
+-export([start/2, receiver/2, send_text/2, send_element/2]).
+
+%% gen_fsm callbacks
+-export([init/1,
+        wait_for_stream/2,
+        wait_for_key/2,
+        wait_for_verification/2,
+        session_established/2,
+        handle_info/3,
+        terminate/3]).
+
+-record(state, {socket, receiver, streamid,
+               myself = "localhost", server, type, xmlpid}).
+
+-include("ejabberd.hrl").
+
+-define(DBGFSM, true).
+
+-ifdef(DBGFSM).
+-define(FSMOPTS, [{debug, [trace]}]).
+-else.
+-define(FSMOPTS, []).
+-endif.
+
+-define(STREAM_HEADER,
+       "<?xml version='1.0'?>"
+       "<stream:stream "
+       "xmlns:stream='http://etherx.jabber.org/streams' "
+       "xmlns='jabber:server' "
+       "xmlns:db='jabber:server:dialback'>"
+       ).
+
+-define(STREAM_TRAILER, "</stream:stream>").
+
+-define(INVALID_HEADER_ERR,
+       "<stream:stream>"
+       "<stream:error>Invalid Stream Header</stream:error>"
+       "</stream:stream>"
+       ).
+
+%%%----------------------------------------------------------------------
+%%% API
+%%%----------------------------------------------------------------------
+start(Host, Type) ->
+    gen_fsm:start(ejabberd_s2s_out, [Host, Type], ?FSMOPTS).
+
+%%%----------------------------------------------------------------------
+%%% Callback functions from gen_fsm
+%%%----------------------------------------------------------------------
+
+%%----------------------------------------------------------------------
+%% Func: init/1
+%% Returns: {ok, StateName, StateData}          |
+%%          {ok, StateName, StateData, Timeout} |
+%%          ignore                              |
+%%          {stop, StopReason}                   
+%%----------------------------------------------------------------------
+init([Host, Type]) ->
+    {ok, Socket} = gen_tcp:connect(Host, 5569,
+                                  [binary, {packet, 0}]),
+    XMLStreamPid = xml_stream:start(self()),
+    %ReceiverPid = spawn(?MODULE, receiver, [Socket, self()]),
+    send_text(Socket, ?STREAM_HEADER),
+    {ok, wait_for_stream, #state{socket = Socket,
+                                xmlpid = XMLStreamPid,
+                                streamid = new_id(),
+                                server = Host,
+                                type = Type}}.
+
+%%----------------------------------------------------------------------
+%% Func: StateName/2
+%% Returns: {next_state, NextStateName, NextStateData}          |
+%%          {next_state, NextStateName, NextStateData, Timeout} |
+%%          {stop, Reason, NewStateData}                         
+%%----------------------------------------------------------------------
+state_name(Event, StateData) ->
+    {next_state, state_name, StateData}.
+
+wait_for_stream({xmlstreamstart, Name, Attrs}, StateData) ->
+    % TODO
+    case {xml:get_attr_s("xmlns", Attrs), xml:get_attr_s("xmlns:db", Attrs)} of
+       {"jabber:server", "jabber:server:dialback"} ->
+           case StateData#state.type of
+               new ->
+                   % TODO
+                   {next_state, wait_for_key, StateData};
+               {verify, Pid, Key} ->
+                   send_element(StateData#state.socket,
+                                {xmlelement,
+                                 "db:verify",
+                                 [{"from", "127.0.0.1"},
+                                  {"to", StateData#state.server}],
+                                 [{xmlcdata, Key}]}),
+                   {next_state, wait_for_verification, StateData}
+               end;
+       _ ->
+           send_text(StateData#state.socket, ?INVALID_HEADER_ERR),
+           {stop, normal, StateData}
+    end;
+
+wait_for_stream(closed, StateData) ->
+    {stop, normal, StateData}.
+
+
+wait_for_key({xmlstreamelement, El}, StateData) ->
+    case is_key_packet(El) of
+       {key, To, From, Id, Key} ->
+           io:format("GET KEY: ~p~n", [{To, From, Id, Key}]),
+           % TODO
+           {next_state, wait_for_key, StateData};
+       {verify, To, From, Id, Key} ->
+           io:format("VERIFY KEY: ~p~n", [{To, From, Id, Key}]),
+           % TODO
+           {next_state, wait_for_key, StateData};
+       _ ->
+           {next_state, wait_for_key, StateData}
+    end;
+
+wait_for_key({xmlstreamend, Name}, StateData) ->
+    % TODO
+    {stop, normal, StateData};
+
+wait_for_key(closed, StateData) ->
+    {stop, normal, StateData}.
+
+wait_for_verification({xmlstreamelement, El}, StateData) ->
+    case is_verify_res(El) of
+       {result, To, From, Id, Type} ->
+           case Type of
+               "valid" ->
+                   io:format("VALID KEY~n", []);
+                   % TODO
+               _ ->
+                   % TODO
+                   ok
+           end,
+           {stop, normal, StateData};
+       _ ->
+           {next_state, wait_for_verification, StateData}
+    end;
+
+wait_for_verification({xmlstreamend, Name}, StateData) ->
+    % TODO
+    {stop, normal, StateData};
+
+wait_for_verification(closed, StateData) ->
+    {stop, normal, StateData}.
+
+session_established({xmlstreamelement, El}, StateData) ->
+    {xmlelement, Name, Attrs, Els} = El,
+    % TODO
+    FromJID = {StateData#state.server},
+    To = xml:get_attr_s("to", Attrs),
+    ToJID = case To of
+               "" ->
+                   {"", StateData#state.server, ""};
+               _ ->
+                   jlib:string_to_jid(To)
+           end,
+    case ToJID of
+       error ->
+           % TODO
+           error;
+       _ ->
+           %?DEBUG("FromJID=~w, ToJID=~w, El=~w~n", [FromJID, ToJID, El]),
+           ejabberd_router:route(FromJID, ToJID, El)
+    end,
+    {next_state, session_established, StateData};
+
+session_established(closed, StateData) ->
+    % TODO
+    {stop, normal, StateData}.
+
+
+
+%%----------------------------------------------------------------------
+%% Func: StateName/3
+%% Returns: {next_state, NextStateName, NextStateData}            |
+%%          {next_state, NextStateName, NextStateData, Timeout}   |
+%%          {reply, Reply, NextStateName, NextStateData}          |
+%%          {reply, Reply, NextStateName, NextStateData, Timeout} |
+%%          {stop, Reason, NewStateData}                          |
+%%          {stop, Reason, Reply, NewStateData}                    
+%%----------------------------------------------------------------------
+state_name(Event, From, StateData) ->
+    Reply = ok,
+    {reply, Reply, state_name, StateData}.
+
+%%----------------------------------------------------------------------
+%% Func: handle_event/3
+%% Returns: {next_state, NextStateName, NextStateData}          |
+%%          {next_state, NextStateName, NextStateData, Timeout} |
+%%          {stop, Reason, NewStateData}                         
+%%----------------------------------------------------------------------
+handle_event(Event, StateName, StateData) ->
+    {next_state, StateName, StateData}.
+
+%%----------------------------------------------------------------------
+%% Func: handle_sync_event/4
+%% Returns: {next_state, NextStateName, NextStateData}            |
+%%          {next_state, NextStateName, NextStateData, Timeout}   |
+%%          {reply, Reply, NextStateName, NextStateData}          |
+%%          {reply, Reply, NextStateName, NextStateData, Timeout} |
+%%          {stop, Reason, NewStateData}                          |
+%%          {stop, Reason, Reply, NewStateData}                    
+%%----------------------------------------------------------------------
+handle_sync_event(Event, From, StateName, StateData) ->
+    Reply = ok,
+    {reply, Reply, StateName, StateData}.
+
+%%----------------------------------------------------------------------
+%% Func: handle_info/3
+%% Returns: {next_state, NextStateName, NextStateData}          |
+%%          {next_state, NextStateName, NextStateData, Timeout} |
+%%          {stop, Reason, NewStateData}                         
+%%----------------------------------------------------------------------
+handle_info({send_text, Text}, StateName, StateData) ->
+    send_text(StateData#state.socket, Text),
+    {next_state, StateName, StateData};
+handle_info({tcp, Socket, Data}, StateName, StateData) ->
+    xml_stream:send_text(StateData#state.xmlpid, Data),
+    {next_state, StateName, StateData};
+handle_info({tcp_closed, Socket}, StateName, StateData) ->
+    self() ! closed,
+    {next_state, StateName, StateData};
+handle_info({tcp_error, Socket, Reason}, StateName, StateData) ->
+    self() ! closed,
+    {next_state, StateName, StateData}.
+
+%%----------------------------------------------------------------------
+%% Func: terminate/3
+%% Purpose: Shutdown the fsm
+%% Returns: any
+%%----------------------------------------------------------------------
+terminate(Reason, StateName, StateData) ->
+%    case StateData#state.user of
+%      "" ->
+%          ok;
+%      _ ->
+%          %ejabberd_sm:close_session(StateData#state.user,
+%          %                         StateData#state.resource)
+%    end,
+    gen_tcp:close(StateData#state.socket),
+    ok.
+
+%%%----------------------------------------------------------------------
+%%% Internal functions
+%%%----------------------------------------------------------------------
+
+receiver(Socket, C2SPid) ->
+    XMLStreamPid = xml_stream:start(C2SPid),
+    receiver(Socket, C2SPid, XMLStreamPid).
+
+receiver(Socket, C2SPid, XMLStreamPid) ->
+    case gen_tcp:recv(Socket, 0) of
+        {ok, Text} ->
+           xml_stream:send_text(XMLStreamPid, Text),
+           receiver(Socket, C2SPid, XMLStreamPid);
+        {error, closed} ->
+           exit(XMLStreamPid, closed),
+           gen_fsm:send_event(C2SPid, closed),
+           ok
+    end.
+
+send_text(Socket, Text) ->
+    gen_tcp:send(Socket,Text).
+
+send_element(Socket, El) ->
+    send_text(Socket, xml:element_to_string(El)).
+
+new_id() ->
+    lists:flatten(io_lib:format("~p", [random:uniform(65536*65536)])).
+
+
+is_key_packet({xmlelement, Name, Attrs, Els}) when Name == "db:result" ->
+    {key,
+     xml:get_attr_s("to", Attrs),
+     xml:get_attr_s("from", Attrs),
+     xml:get_attr_s("id", Attrs),
+     xml:get_cdata(Els)};
+is_key_packet({xmlelement, Name, Attrs, Els}) when Name == "db:verify" ->
+    {verify,
+     xml:get_attr_s("to", Attrs),
+     xml:get_attr_s("from", Attrs),
+     xml:get_attr_s("id", Attrs),
+     xml:get_cdata(Els)};
+is_key_packet(_) ->
+    false.
+
+is_verify_res({xmlelement, Name, Attrs, Els}) when Name == "db:result" ->
+    {result,
+     xml:get_attr_s("to", Attrs),
+     xml:get_attr_s("from", Attrs),
+     xml:get_attr_s("id", Attrs),
+     xml:get_attr_s("type", Attrs)};
+is_verify_res({xmlelement, Name, Attrs, Els}) when Name == "db:verify" ->
+    {result,
+     xml:get_attr_s("to", Attrs),
+     xml:get_attr_s("from", Attrs),
+     xml:get_attr_s("id", Attrs),
+     xml:get_attr_s("type", Attrs)};
+is_verify_res(_) ->
+    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}.
+
+
+
+