]> granicus.if.org Git - ejabberd/commitdiff
* src/ejabberd_ctl.erl: Added commands for backup processing
authorAlexey Shchepin <alexey@process-one.net>
Sun, 18 Jan 2004 20:42:09 +0000 (20:42 +0000)
committerAlexey Shchepin <alexey@process-one.net>
Sun, 18 Jan 2004 20:42:09 +0000 (20:42 +0000)
* src/ejabberd_c2s.erl: Added processing of xml:lang according to
latest XMPP-IM draft

* src/xml.erl: Added replace_tag_attr/3 function

* src/mod_roster.erl: Added auto-reply on incoming subscription
request according to latest XMPP-IM draft

* src/mod_offline.erl: Added pop_offline_messages/1 function
* src/ejabberd_c2s.erl: Updated sending of offline messages

SVN Revision: 200

ChangeLog
src/ejabberd_c2s.erl
src/ejabberd_ctl.erl
src/mod_offline.erl
src/mod_roster.erl
src/xml.erl

index be9539f4d3a4dae15898678c0e48c26f363de636..29c078b74365c332217acfb2d57713d847370dd8 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,18 @@
+2004-01-18  Alexey Shchepin  <alexey@sevcom.net>
+
+       * src/ejabberd_ctl.erl: Added commands for backup processing
+
+       * src/ejabberd_c2s.erl: Added processing of xml:lang according to
+       latest XMPP-IM draft
+
+       * src/xml.erl: Added replace_tag_attr/3 function
+
+       * src/mod_roster.erl: Added auto-reply on incoming subscription
+       request according to latest XMPP-IM draft
+
+       * src/mod_offline.erl: Added pop_offline_messages/1 function
+       * src/ejabberd_c2s.erl: Updated sending of offline messages
+
 2004-01-17  Alexey Shchepin  <alexey@sevcom.net>
 
        * src/mod_muc/mod_muc_room.erl: Bugfix, updated error codes
index 09ab2a7b7dff799396625c50db9862d385113002..44da28c0e4c6f58f2d682f613db297e5e4bcaeae 100644 (file)
@@ -54,7 +54,8 @@
                pres_last, pres_pri,
                pres_timestamp,
                pres_invis = false,
-               privacy_list = none}).
+               privacy_list = none,
+               lang}).
 
 %-define(DBGFSM, true).
 
@@ -127,6 +128,7 @@ init([{SockMod, Socket}, Opts]) ->
 wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
     case xml:get_attr_s("xmlns:stream", Attrs) of
        ?NS_STREAM ->
+           Lang = xml:get_attr_s("xml:lang", Attrs),
            case xml:get_attr_s("version", Attrs) of
                "1.0" ->
                    Header = io_lib:format(?STREAM_HEADER,
@@ -149,7 +151,8 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
                                            [{"xmlns", ?NS_SASL}],
                                            Mechs}]}),
                            {next_state, wait_for_sasl_auth,
-                            StateData#state{sasl_state = SASLState}};
+                            StateData#state{sasl_state = SASLState,
+                                            lang = Lang}};
                        _ ->
                            case StateData#state.resource of
                                "" ->
@@ -158,12 +161,14 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
                                      {xmlelement, "stream:features", [],
                                       [{xmlelement, "bind",
                                         [{"xmlns", ?NS_BIND}], []}]}),
-                                   {next_state, wait_for_bind, StateData};
+                                   {next_state, wait_for_bind,
+                                    StateData#state{lang = Lang}};
                                _ ->
                                    send_element(
                                      StateData,
                                      {xmlelement, "stream:features", [], []}),
-                                   {next_state, wait_for_session, StateData}
+                                   {next_state, wait_for_session,
+                                    StateData#state{lang = Lang}}
                            end
                    end;
                _ ->
@@ -171,7 +176,7 @@ wait_for_stream({xmlstreamstart, _Name, Attrs}, StateData) ->
                               ?STREAM_HEADER,
                               [StateData#state.streamid, ?MYNAME, ""]),
                    send_text(StateData, Header),
-                   {next_state, wait_for_auth, StateData}
+                   {next_state, wait_for_auth, StateData#state{lang = Lang}}
            end;
        _ ->
            Header = io_lib:format(
@@ -541,9 +546,7 @@ session_established({xmlstreamelement, El}, StateData) ->
     {xmlelement, Name, Attrs, _Els} = El,
     User = StateData#state.user,
     Server = StateData#state.server,
-    %FromJID = {User,
-    %           Server,
-    %           StateData#state.resource},
+    % TODO: check 'from' attribute in stanza
     FromJID = StateData#state.jid,
     To = xml:get_attr_s("to", Attrs),
     ToJID = case To of
@@ -552,6 +555,16 @@ session_established({xmlstreamelement, El}, StateData) ->
                _ ->
                    jlib:string_to_jid(To)
            end,
+    NewEl = case xml:get_attr_s("xml:lang", Attrs) of
+               "" ->
+                   case StateData#state.lang of
+                       "" -> El;
+                       Lang ->
+                           xml:replace_tag_attr("xml:lang", Lang, El)
+                   end;
+               _ ->
+                   El
+           end,
     NewState =
        case ToJID of
            error ->
@@ -559,7 +572,7 @@ session_established({xmlstreamelement, El}, StateData) ->
                    "error" -> StateData;
                    "result" -> StateData;
                    _ ->
-                       Err = jlib:make_error_reply(El, ?ERR_JID_MALFORMED),
+                       Err = jlib:make_error_reply(NewEl, ?ERR_JID_MALFORMED),
                        send_element(StateData, Err),
                        StateData
                end;
@@ -571,29 +584,29 @@ session_established({xmlstreamelement, El}, StateData) ->
                                 server = Server,
                                 resource = ""} ->
                                ?DEBUG("presence_update(~p,~n\t~p,~n\t~p)",
-                                      [FromJID, El, StateData]),
-                               presence_update(FromJID, El, StateData);
+                                      [FromJID, NewEl, StateData]),
+                               presence_update(FromJID, NewEl, StateData);
                            _ ->
-                               presence_track(FromJID, ToJID, El, StateData)
+                               presence_track(FromJID, ToJID, NewEl, StateData)
                        end;
                    "iq" ->
                        case StateData#state.privacy_list of
                            none ->
-                               ejabberd_router:route(FromJID, ToJID, El),
+                               ejabberd_router:route(FromJID, ToJID, NewEl),
                                StateData;
                            _PrivList ->
-                               case jlib:iq_query_info(El) of
+                               case jlib:iq_query_info(NewEl) of
                                    #iq{xmlns = ?NS_PRIVACY} = IQ ->
                                        process_privacy_iq(
                                          FromJID, ToJID, IQ, StateData);
                                    _ ->
                                        ejabberd_router:route(
-                                         FromJID, ToJID, El),
+                                         FromJID, ToJID, NewEl),
                                        StateData
                                end
                        end;
                    "message" ->
-                       ejabberd_router:route(FromJID, ToJID, El),
+                       ejabberd_router:route(FromJID, ToJID, NewEl),
                        StateData;
                    _ ->
                        StateData
@@ -987,8 +1000,7 @@ presence_update(From, Packet, StateData) ->
                    FromUnavail ->
                        % TODO: watching ourself
                        
-                       catch mod_offline:resend_offline_messages(
-                               StateData#state.user),
+                       resend_offline_messages(StateData),
                        presence_broadcast_first(
                          From, StateData#state{pres_last = Packet,
                                                pres_invis = false
@@ -1271,3 +1283,19 @@ process_privacy_iq(From, To,
     NewStateData.
 
 
+resend_offline_messages(StateData) ->
+    case catch mod_offline:pop_offline_messages(StateData#state.user) of
+       {'EXIT', _Reason} ->
+           ok;
+       Rs when list(Rs) ->
+           lists:foreach(
+             fun({route, From, To, {xmlelement, Name, Attrs, Els}}) ->
+                     Attrs2 = jlib:replace_from_to_attrs(
+                                jlib:jid_to_string(From),
+                                jlib:jid_to_string(To),
+                                Attrs),
+                     send_element(StateData, {xmlelement, Name, Attrs2, Els})
+             end, Rs)
+    end.
+
+
index 39141f3a66ac1927acf83bd875b9d9d7535aceab..ea71f7575e37902572bd62b83037e4ee3dbb3caa 100644 (file)
@@ -67,6 +67,43 @@ process(Node, ["unregister", User]) ->
                      [User, Node, Reason])
     end;
 
+process(Node, ["backup", Path]) ->
+    case rpc:call(Node, mnesia, backup, [Path]) of
+       {atomic, ok} ->
+           ok;
+       {error, Reason} ->
+           io:format("Can't store backup in ~p on node ~p: ~p~n",
+                     [Path, Node, Reason]);
+       {badrpc, Reason} ->
+           io:format("Can't store backup in ~p on node ~p: ~p~n",
+                     [Path, Node, Reason])
+    end;
+
+process(Node, ["restore", Path]) ->
+    case rpc:call(Node,
+                 mnesia, restore, [Path, [{default_op, keep_tables}]]) of
+       {atomic, ok} ->
+           ok;
+       {error, Reason} ->
+           io:format("Can't restore backup from ~p on node ~p: ~p~n",
+                     [Path, Node, Reason]);
+       {badrpc, Reason} ->
+           io:format("Can't restore backup from ~p on node ~p: ~p~n",
+                     [Path, Node, Reason])
+    end;
+
+process(Node, ["install-fallback", Path]) ->
+    case rpc:call(Node, mnesia, install_fallback, [Path]) of
+       {atomic, ok} ->
+           ok;
+       {error, Reason} ->
+           io:format("Can't install fallback from ~p on node ~p: ~p~n",
+                     [Path, Node, Reason]);
+       {badrpc, Reason} ->
+           io:format("Can't install fallback from ~p on node ~p: ~p~n",
+                     [Path, Node, Reason])
+    end;
+
 process(_Node, _Args) ->
     print_usage().
 
@@ -78,8 +115,11 @@ print_usage() ->
              "Available commands:~n"
              "  stop\t\t\t\tstop ejabberd~n"
              "  restart\t\t\trestart ejabberd~n"
-             "  register user password\tregister user~n"
-             "  unregister user\t\tunregister user~n"
+             "  register user password\tregister a user~n"
+             "  unregister user\t\tunregister a user~n"
+             "  backup file\t\t\tstore a backup in file~n"
+             "  restore file\t\t\trestore a backup from file~n"
+             "  install-fallback file\t\tinstall a fallback from file~n"
              "~n"
              "Example:~n"
              "  ejabberdctl ejabberd@host restart~n"
index fbd8dfbff7362db9dec8838fa500e0e679debae9..7af72442b063be4d5f9921c70bec7aeffd22c9d1 100644 (file)
@@ -16,6 +16,7 @@
         stop/0,
         store_packet/3,
         resend_offline_messages/1,
+        pop_offline_messages/1,
         remove_old_messages/1,
         remove_user/1]).
 
@@ -129,7 +130,7 @@ find_x_event([El | Els]) ->
 resend_offline_messages(User) ->
     LUser = jlib:nodeprep(User),
     F = fun() ->
-               Rs = mnesia:read({offline_msg, LUser}),
+               Rs = mnesia:wread({offline_msg, LUser}),
                mnesia:delete({offline_msg, LUser}),
                Rs
        end,
@@ -153,6 +154,32 @@ resend_offline_messages(User) ->
            ok
     end.
 
+pop_offline_messages(User) ->
+    LUser = jlib:nodeprep(User),
+    F = fun() ->
+               Rs = mnesia:wread({offline_msg, LUser}),
+               mnesia:delete({offline_msg, LUser}),
+               Rs
+       end,
+    case mnesia:transaction(F) of
+       {atomic, Rs} ->
+           lists:map(
+             fun(R) ->
+                     {xmlelement, Name, Attrs, Els} = R#offline_msg.packet,
+                     {route,
+                      R#offline_msg.from,
+                      R#offline_msg.to,
+                      {xmlelement, Name, Attrs,
+                       Els ++
+                       [jlib:timestamp_to_xml(
+                          calendar:now_to_universal_time(
+                            R#offline_msg.timestamp))]}}
+             end,
+             lists:keysort(#offline_msg.timestamp, Rs));
+       _ ->
+           []
+    end.
+
 remove_old_messages(Days) ->
     {MegaSecs, Secs, _MicroSecs} = now(),
     S = MegaSecs * 1000000 + Secs - 60 * 60 * 24 * Days,
index cbb6085abb328c8867d41e486137673720bfb330..836dbdba1604d3a033874796785f87c428654fa4 100644 (file)
@@ -375,22 +375,45 @@ process_subscription(Direction, User, JID1, Type) ->
                                                   Item#roster.ask,
                                                   Type)
                           end,
+               AutoReply = case Direction of
+                               out ->
+                                   none;
+                               in ->
+                                   in_auto_reply(Item#roster.subscription,
+                                                 Item#roster.ask,
+                                                 Type)
+                           end,
                case NewState of
                    none ->
-                       none;
+                       {none, AutoReply};
                    {Subscription, Pending} ->
                        NewItem = Item#roster{subscription = Subscription,
                                              ask = Pending},
                        mnesia:write(NewItem),
-                       {push, NewItem}
+                       {{push, NewItem}, AutoReply}
                end
        end,
     case mnesia:transaction(F) of
-       {atomic, ok} ->
-           false;
-       {atomic, {push, Item}} ->
-           push_item(User, {"", ?MYNAME, ""}, Item),
-           true;
+       {atomic, {Push, AutoReply}} ->
+           case AutoReply of
+               none ->
+                   ok;
+               _ ->
+                   T = case AutoReply of
+                           subscribed -> "subscribed";
+                           unsubscribed -> "unsubscribed"
+                       end,
+                   ejabberd_router:route(
+                     {User, ?MYNAME, ""}, JID1,
+                     {xmlelement, "presence", [{"type", T}], []})
+           end,
+           case Push of
+               {push, Item} ->
+                   push_item(User, {"", ?MYNAME, ""}, Item),
+                   true;
+               none ->
+                   false
+           end;
        _ ->
            false
     end.
@@ -474,6 +497,17 @@ out_state_change(both, none, subscribed)   -> none;
 out_state_change(both, none, unsubscribe)  -> {from, none};
 out_state_change(both, none, unsubscribed) -> {to, none}.
 
+in_auto_reply(from, none, subscribe)    -> subscribed;
+in_auto_reply(from, out,  subscribe)    -> subscribed;
+in_auto_reply(both, none, subscribe)    -> subscribed;
+in_auto_reply(none, in,   unsubscribe)  -> unsubscribed;
+in_auto_reply(none, both, unsubscribe)  -> unsubscribed;
+in_auto_reply(to,   in,   unsubscribe)  -> unsubscribed;
+in_auto_reply(from, none, unsubscribe)  -> unsubscribed;
+in_auto_reply(from, out,  unsubscribe)  -> unsubscribed;
+in_auto_reply(both, none, unsubscribe)  -> unsubscribed;
+in_auto_reply(_,    _,    _)  ->           none.
+
 
 remove_user(User) ->
     LUser = jlib:nodeprep(User),
index 9f047c825df81c72261b6f49a432f2e444812f5b..e14f54c154e2e7246b708ca03e81976b67dbe493 100644 (file)
@@ -17,7 +17,8 @@
         get_attr/2, get_attr_s/2,
         get_tag_attr/2, get_tag_attr_s/2,
         get_subtag/2,
-        get_path_s/2]).
+        get_path_s/2,
+        replace_tag_attr/3]).
 
 element_to_string(El) ->
     case El of
@@ -190,3 +191,10 @@ get_path_s(El, [{attr, Name}]) ->
 get_path_s(El, [cdata]) ->
     get_tag_cdata(El).
 
+
+replace_tag_attr(Attr, Value, {xmlelement, Name, Attrs, Els}) ->
+    Attrs1 = lists:keydelete(Attr, 1, Attrs),
+    Attrs2 = [{Attr, Value} | Attrs1],
+    {xmlelement, Name, Attrs2, Els}.
+
+