]> granicus.if.org Git - ejabberd/commitdiff
Improve interface for adding timestamps
authorHolger Weiss <holger@zedat.fu-berlin.de>
Sun, 7 Dec 2014 14:55:18 +0000 (15:55 +0100)
committerHolger Weiss <holger@zedat.fu-berlin.de>
Sun, 7 Dec 2014 14:55:18 +0000 (15:55 +0100)
Provide a simpler interface for adding <delay/> and <x/> timestamps to
stanzas.  This also makes sure that only one <delay/> tag and one <x/>
tag is added to a given stanza.

src/ejabberd_c2s.erl
src/jlib.erl
src/mod_muc_room.erl
src/mod_offline.erl
src/mod_pubsub.erl
src/mod_pubsub_odbc.erl
test/ejabberd_SUITE.erl

index 3794ac350a0085ec77da96fc392d3c4d1a9b44ae..e52378c6d4d5d88ba59e7855c506d2115e708e1a 100644 (file)
@@ -2049,13 +2049,9 @@ process_presence_probe(From, To, StateData) ->
                 ?SETS:is_element(LBFrom, StateData#state.pres_f)),
            if
                Cond ->
-                   Timestamp = StateData#state.pres_timestamp,
-                   Packet = xml:append_subtags(
-                              StateData#state.pres_last,
-                              %% To is the one sending the presence (the target of the probe)
-                              [jlib:timestamp_to_xml(Timestamp, utc, To, <<"">>),
-                               %% TODO: Delete the next line once XEP-0091 is Obsolete
-                               jlib:timestamp_to_xml(Timestamp)]),
+                   %% To is the one sending the presence (the probe target)
+                   Packet = jlib:add_delay_info(StateData#state.pres_last, To,
+                                                StateData#state.pres_timestamp),
                    case privacy_check_packet(StateData, To, From, Packet, out) of
                        deny ->
                            ok;
@@ -2107,12 +2103,11 @@ presence_update(From, Packet, StateData) ->
                          OldPresence -> get_priority_from_presence(OldPresence)
                        end,
          NewPriority = get_priority_from_presence(Packet),
-         Timestamp = calendar:now_to_universal_time(now()),
          update_priority(NewPriority, Packet, StateData),
          FromUnavail = (StateData#state.pres_last == undefined),
          ?DEBUG("from unavail = ~p~n", [FromUnavail]),
          NewStateData = StateData#state{pres_last = Packet,
-                                        pres_timestamp = Timestamp},
+                                        pres_timestamp = now()},
          NewState = if FromUnavail ->
                            ejabberd_hooks:run(user_available_hook,
                                               NewStateData#state.server,
@@ -3054,14 +3049,9 @@ csi_filter_stanza(#state{csi_state = CsiState, jid = JID} = StateData,
          StateData2#state{csi_state = CsiState}
     end.
 
-csi_queue_add(#state{csi_queue = Queue, server = Host} = StateData,
-             #xmlel{children = Els} = Stanza) ->
+csi_queue_add(#state{csi_queue = Queue, server = Host} = StateData, Stanza) ->
     From = xml:get_tag_attr_s(<<"from">>, Stanza),
-    Time = calendar:now_to_universal_time(os:timestamp()),
-    DelayTag = [jlib:timestamp_to_xml(Time, utc,
-                                     jlib:make_jid(<<"">>, Host, <<"">>),
-                                     <<"Client Inactive">>)],
-    NewStanza = Stanza#xmlel{children = Els ++ DelayTag},
+    NewStanza = jlib:add_delay_info(Stanza, Host, now(), <<"Client Inactive">>),
     case length(StateData#state.csi_queue) >= csi_max_queue(StateData) of
       true -> csi_queue_add(csi_queue_flush(StateData), NewStanza);
       false ->
index be1da3fd091e05cbcd1d3f03543056281142aa6d..74d8503e4a74444d61cfde443635ff0176548ece 100644 (file)
         jid_remove_resource/1, jid_replace_resource/2,
         get_iq_namespace/1, iq_query_info/1,
         iq_query_or_response_info/1, is_iq_request_type/1,
-        iq_to_xml/1, parse_xdata_submit/1, timestamp_to_iso/1,
-        timestamp_to_iso/2, timestamp_to_xml/4,
-        timestamp_to_xml/1, now_to_utc_string/1,
-        now_to_local_string/1, datetime_string_to_timestamp/1,
+        iq_to_xml/1, parse_xdata_submit/1,
+        add_delay_info/3, add_delay_info/4,
+        timestamp_to_iso/1, timestamp_to_iso/2,
+        now_to_utc_string/1, now_to_local_string/1,
+        datetime_string_to_timestamp/1,
         term_to_base64/1, base64_to_term/1,
         decode_base64/1, encode_base64/1, ip_to_list/1,
         rsm_encode/1, rsm_encode/2, rsm_decode/1,
@@ -600,6 +601,78 @@ rsm_encode_count(Count, Arr) ->
            children = [{xmlcdata, i2l(Count)}]}
      | Arr].
 
+-spec add_delay_info(xmlel(), erlang:timestamp(), binary()) -> xmlel().
+
+add_delay_info(El, From, Time) ->
+    add_delay_info(El, From, Time, <<"">>).
+
+-spec add_delay_info(xmlel(), erlang:timestamp(), binary(),
+                    binary()) -> xmlel().
+
+add_delay_info(El, From, Time, Desc) ->
+    %% TODO: Remove support for <x/>, XEP-0091 is obsolete.
+    El1 = add_delay_info(El, From, Time, Desc, <<"delay">>, ?NS_DELAY),
+    El2 = add_delay_info(El1, From, Time, Desc, <<"x">>, ?NS_DELAY91),
+    El2.
+
+-spec add_delay_info(xmlel(), erlang:timestamp(), binary(), binary(), binary(),
+                    binary()) -> xmlel().
+
+add_delay_info(El, From, Time, Desc, Name, XMLNS) ->
+    case xml:get_subtag_with_xmlns(El, Name, XMLNS) of
+      false ->
+         %% Add new tag
+         DelayTag = create_delay_tag(calendar:now_to_universal_time(Time),
+                                     From, Desc, XMLNS),
+         xml:append_subtags(El, [DelayTag]);
+      DelayTag ->
+         %% Update existing tag
+         NewDelayTag =
+             case {xml:get_tag_cdata(DelayTag), Desc} of
+               {<<"">>, <<"">>} ->
+                   DelayTag;
+               {OldDesc, <<"">>} ->
+                   DelayTag#xmlel{children = [{xmlcdata, OldDesc}]};
+               {<<"">>, NewDesc} ->
+                   DelayTag#xmlel{children = [{xmlcdata, NewDesc}]};
+               {OldDesc, NewDesc} ->
+                   case binary:match(OldDesc, NewDesc) of
+                     nomatch ->
+                         FinalDesc = <<OldDesc/binary, ", ", NewDesc/binary>>,
+                         DelayTag#xmlel{children = [{xmlcdata, FinalDesc}]};
+                     _ ->
+                         DelayTag#xmlel{children = [{xmlcdata, OldDesc}]}
+                   end
+             end,
+         NewEl = xml:remove_subtags(El, Name, {<<"xmlns">>, XMLNS}),
+         xml:append_subtags(NewEl, [NewDelayTag])
+    end.
+
+-spec create_delay_tag(calendar:datetime(), jid() | binary(),
+                      binary(), binary()) -> xmlel() | error.
+
+create_delay_tag(DateTime, FromJID, Desc, XMLNS) when is_tuple(FromJID) ->
+    From = jlib:jid_to_string(FromJID),
+    {Name, Stamp} = case XMLNS of
+                     ?NS_DELAY ->
+                         {T, Tz} = timestamp_to_iso(DateTime, utc),
+                         {<<"delay">>, <<T/binary, Tz/binary>>};
+                     ?NS_DELAY91 ->
+                         {<<"x">>, timestamp_to_iso(DateTime)}
+                   end,
+    Children = case Desc of
+                <<"">> -> [];
+                _ -> [{xmlcdata, Desc}]
+              end,
+    #xmlel{name = Name,
+          attrs =
+              [{<<"xmlns">>, XMLNS}, {<<"from">>, From},
+               {<<"stamp">>, Stamp}],
+          children = Children};
+create_delay_tag(DateTime, Host, Desc, XMLNS) when is_binary(Host) ->
+    FromJID = jlib:make_jid(<<"">>, Host, <<"">>),
+    create_delay_tag(DateTime, FromJID, Desc, XMLNS).
+
 -type tz() :: {binary(), {integer(), integer()}} | {integer(), integer()} | utc.
 
 %% Timezone = utc | {Sign::string(), {Hours, Minutes}} | {Hours, Minutes}
@@ -634,33 +707,6 @@ timestamp_to_iso({{Year, Month, Day},
     iolist_to_binary(io_lib:format("~4..0w~2..0w~2..0wT~2..0w:~2..0w:~2..0w",
                                    [Year, Month, Day, Hour, Minute, Second])).
 
--spec timestamp_to_xml(calendar:datetime(), tz(), jid(), binary()) -> xmlel().
-
-timestamp_to_xml(DateTime, Timezone, FromJID, Desc) ->
-    {T_string, Tz_string} = timestamp_to_iso(DateTime,
-                                            Timezone),
-    Text = [{xmlcdata, Desc}],
-    From = jlib:jid_to_string(FromJID),
-%% TODO: Remove this function once XEP-0091 is Obsolete
-    #xmlel{name = <<"delay">>,
-          attrs =
-              [{<<"xmlns">>, ?NS_DELAY}, {<<"from">>, From},
-               {<<"stamp">>, <<T_string/binary, Tz_string/binary>>}],
-          children = Text}.
-
--spec timestamp_to_xml(calendar:datetime()) -> xmlel().
-
-timestamp_to_xml({{Year, Month, Day},
-                 {Hour, Minute, Second}}) ->
-    #xmlel{name = <<"x">>,
-          attrs =
-              [{<<"xmlns">>, ?NS_DELAY91},
-               {<<"stamp">>,
-                iolist_to_binary(io_lib:format("~4..0w~2..0w~2..0wT~2..0w:~2..0w:~2..0w",
-                                               [Year, Month, Day, Hour, Minute,
-                                                Second]))}],
-          children = []}.
-
 -spec now_to_utc_string(erlang:timestamp()) -> binary().
 
 now_to_utc_string({MegaSecs, Secs, MicroSecs}) ->
index 0974950b732ab59614649f107322848cfa87606c..95d437bfc1179fc16de2e9c1afca02e072548345 100644 (file)
@@ -2438,24 +2438,21 @@ add_message_to_history(FromNick, FromJID, Packet, StateData) ->
                    false -> false;
                    _ -> true
                  end,
-    TimeStamp = calendar:now_to_universal_time(now()),
+    TimeStamp = now(),
     SenderJid = case
                  (StateData#state.config)#config.anonymous
                    of
                  true -> StateData#state.jid;
                  false -> FromJID
                end,
-    TSPacket = xml:append_subtags(Packet,
-                                 [jlib:timestamp_to_xml(TimeStamp, utc,
-                                                        SenderJid, <<"">>),
-                                  jlib:timestamp_to_xml(TimeStamp)]),
+    TSPacket = jlib:add_delay_info(Packet, SenderJid, TimeStamp),
     SPacket =
        jlib:replace_from_to(jlib:jid_replace_resource(StateData#state.jid,
                                                       FromNick),
                             StateData#state.jid, TSPacket),
     Size = element_size(SPacket),
     Q1 = lqueue_in({FromNick, TSPacket, HaveSubject,
-                   TimeStamp, Size},
+                   calendar:now_to_universal_time(TimeStamp), Size},
                   StateData#state.history),
     add_to_log(text, {FromNick, Packet}, StateData),
     StateData#state{history = Q1}.
index 91d31a75d0680249f22f7d126fe43acf6bbf7cb7..4ac3f18f840e30a40b087de396b95f8fd1031974 100644 (file)
@@ -215,26 +215,15 @@ store_offline_msg(Host, {User, _Server}, Msgs, Len, MaxOfflineMsgs, odbc) ->
                                         ejabberd_odbc:escape((M#offline_msg.to)#jid.luser),
                                     From = M#offline_msg.from,
                                     To = M#offline_msg.to,
-                                    #xmlel{name = Name, attrs = Attrs,
-                                           children = Els} =
-                                        M#offline_msg.packet,
-                                    Attrs2 =
-                                        jlib:replace_from_to_attrs(jlib:jid_to_string(From),
-                                                                   jlib:jid_to_string(To),
-                                                                   Attrs),
-                                    Packet = #xmlel{name = Name,
-                                                    attrs = Attrs2,
-                                                    children =
-                                                        Els ++
-                                                          [jlib:timestamp_to_xml(calendar:now_to_universal_time(M#offline_msg.timestamp),
-                                                                                 utc,
-                                                                                 jlib:make_jid(<<"">>,
-                                                                                               Host,
-                                                                                               <<"">>),
-                                                                                 <<"Offline Storage">>),
-                                                           jlib:timestamp_to_xml(calendar:now_to_universal_time(M#offline_msg.timestamp))]},
+                                    Packet =
+                                        jlib:replace_from_to(From, To,
+                                                             M#offline_msg.packet),
+                                    NewPacket =
+                                        jlib:add_delay_info(Packet, Host,
+                                                            M#offline_msg.timestamp,
+                                                            <<"Offline Storage">>),
                                     XML =
-                                        ejabberd_odbc:escape(xml:element_to_binary(Packet)),
+                                        ejabberd_odbc:escape(xml:element_to_binary(NewPacket)),
                                     odbc_queries:add_spool_sql(Username, XML)
                             end,
                             Msgs),
@@ -432,15 +421,12 @@ resend_offline_messages(User, Server) ->
     case mnesia:transaction(F) of
       {atomic, Rs} ->
          lists:foreach(fun (R) ->
-                               #xmlel{name = Name, attrs = Attrs,
-                                      children = Els} =
-                                   R#offline_msg.packet,
                                ejabberd_sm !
                                  {route, R#offline_msg.from, R#offline_msg.to,
-                                  #xmlel{name = Name, attrs = Attrs,
-                                         children =
-                                             Els ++
-                                               [jlib:timestamp_to_xml(calendar:now_to_universal_time(R#offline_msg.timestamp))]}}
+                                  jlib:add_delay_info(R#offline_msg.packet,
+                                                      LServer,
+                                                      R#offline_msg.timestamp,
+                                                      <<"Offline Storage">>)}
                        end,
                        lists:keysort(#offline_msg.timestamp, Rs));
       _ -> ok
@@ -686,19 +672,9 @@ get_offline_els(LUser, LServer, odbc) ->
     end.
 
 offline_msg_to_route(LServer, #offline_msg{} = R) ->
-    El = #xmlel{children = Els} = R#offline_msg.packet,
     {route, R#offline_msg.from, R#offline_msg.to,
-     El#xmlel{children =
-                  Els ++
-                  [jlib:timestamp_to_xml(
-                     calendar:now_to_universal_time(
-                       R#offline_msg.timestamp),
-                     utc,
-                     jlib:make_jid(<<"">>, LServer, <<"">>),
-                     <<"Offline Storage">>),
-                   jlib:timestamp_to_xml(
-                     calendar:now_to_universal_time(
-                       R#offline_msg.timestamp))]}};
+     jlib:add_delay_info(R#offline_msg.packet, LServer, R#offline_msg.timestamp,
+                        <<"Offline Storage">>)};
 offline_msg_to_route(_LServer, #xmlel{} = El) ->
     To = jlib:string_to_jid(xml:get_tag_attr_s(<<"to">>, El)),
     From = jlib:string_to_jid(xml:get_tag_attr_s(<<"from">>, El)),
@@ -1109,26 +1085,14 @@ export(_Server) ->
                              packet = Packet})
             when LServer == Host ->
               Username = ejabberd_odbc:escape(LUser),
-              #xmlel{name = Name, attrs = Attrs, children = Els} =
-                  Packet,
-              Attrs2 =
-                  jlib:replace_from_to_attrs(jlib:jid_to_string(From),
-                                             jlib:jid_to_string(To),
-                                             Attrs),
-              NewPacket = #xmlel{name = Name, attrs = Attrs2,
-                                 children =
-                                     Els ++
-                                     [jlib:timestamp_to_xml(
-                                        calendar:now_to_universal_time(TimeStamp),
-                                        utc,
-                                        jlib:make_jid(<<"">>,
-                                                      LServer,
-                                                      <<"">>),
-                                        <<"Offline Storage">>),
-                                      jlib:timestamp_to_xml(
-                                        calendar:now_to_universal_time(TimeStamp))]},
+              Packet1 =
+                  jlib:replace_from_to(jlib:jid_to_string(From),
+                                       jlib:jid_to_string(To), Packet),
+              Packet2 =
+                  jlib:add_delay_info(Packet1, LServer, TimeStamp,
+                                      <<"Offline Storage">>),
               XML =
-                  ejabberd_odbc:escape(xml:element_to_binary(NewPacket)),
+                  ejabberd_odbc:escape(xml:element_to_binary(Packet2)),
               [[<<"delete from spool where username='">>, Username, <<"';">>],
                [<<"insert into spool(username, xml) values ('">>,
                 Username, <<"', '">>, XML, <<"');">>]];
index 5f16fed7e89253e65f19024fbb5b3a3971ce5c84..f7d30558e443a3587b836bce920502f6f88eabdb 100644 (file)
@@ -4275,21 +4275,15 @@ payload_xmlelements([_ | Tail], Count) ->
 %% @spec (Els) -> stanza()
 %%     Els = [xmlelement()]
 %% @doc <p>Build pubsub event stanza</p>
-event_stanza(Els) -> event_stanza_withmoreels(Els, []).
-
-event_stanza_with_delay(Els, ModifNow, ModifUSR) ->
-    DateTime = calendar:now_to_datetime(ModifNow),
-    MoreEls = [jlib:timestamp_to_xml(DateTime, utc,
-                                    ModifUSR, <<"">>)],
-    event_stanza_withmoreels(Els, MoreEls).
-
-event_stanza_withmoreels(Els, MoreEls) ->
+event_stanza(Els) ->
     #xmlel{name = <<"message">>, attrs = [],
           children =
               [#xmlel{name = <<"event">>,
                       attrs = [{<<"xmlns">>, ?NS_PUBSUB_EVENT}],
-                      children = Els}
-               | MoreEls]}.
+                      children = Els}]}.
+
+event_stanza_with_delay(Els, ModifNow, ModifUSR) ->
+    jlib:add_delay_info(event_stanza(Els), ModifUSR, ModifNow).
 
 %%%%%% broadcast functions
 
index c953e26a909fbd6fd6fc6d283fd208de278dfc4b..b3f2db7c05d35d7d9f8634e7744227118295c49f 100644 (file)
@@ -3925,21 +3925,15 @@ payload_xmlelements([_ | Tail], Count) ->
 %% @spec (Els) -> stanza()
 %%     Els = [xmlelement()]
 %% @doc <p>Build pubsub event stanza</p>
-event_stanza(Els) -> event_stanza_withmoreels(Els, []).
-
-event_stanza_with_delay(Els, ModifNow, ModifUSR) ->
-    DateTime = calendar:now_to_datetime(ModifNow),
-    MoreEls = [jlib:timestamp_to_xml(DateTime, utc,
-                                    ModifUSR, <<"">>)],
-    event_stanza_withmoreels(Els, MoreEls).
-
-event_stanza_withmoreels(Els, MoreEls) ->
+event_stanza(Els) ->
     #xmlel{name = <<"message">>, attrs = [],
           children =
               [#xmlel{name = <<"event">>,
                       attrs = [{<<"xmlns">>, ?NS_PUBSUB_EVENT}],
-                      children = Els}
-               | MoreEls]}.
+                      children = Els}]}.
+
+event_stanza_with_delay(Els, ModifNow, ModifUSR) ->
+    jlib:add_delay_info(event_stanza(Els), ModifUSR, ModifNow).
 
 %%%%%% broadcast functions
 
index 50fa70bd915fc809fbe2d22a07f096038304e294..380ed606f64c73c3d9f3c388cc1f1dba805c0c20 100644 (file)
@@ -801,7 +801,7 @@ pubsub(Config) ->
                                       node = Node,
                                       jid = my_jid(Config)}}]}),
     ?recv2(
-       #message{sub_els = [#pubsub_event{}, #delay{}]},
+       #message{sub_els = [#pubsub_event{}, #delay{}, #legacy_delay{}]},
        #iq{type = result, id = I1}),
     %% Get subscriptions
     true = lists:member(?PUBSUB("retrieve-subscriptions"), Features),
@@ -1588,7 +1588,8 @@ client_state_slave(Config) ->
             body = [#text{data = <<"body">>}]} = recv(),
     wait_for_master(Config),
     send(Config, #csi{type = active}),
-    ?recv2(#presence{from = Peer, type = unavailable, sub_els = [#delay{}]},
+    ?recv2(#presence{from = Peer, type = unavailable,
+                    sub_els = [#delay{}, #legacy_delay{}]},
           #message{from = Peer, thread = <<"1">>,
                    sub_els = [#chatstate{type = active}]}),
     disconnect(Config).