]> granicus.if.org Git - ejabberd/commitdiff
Add stanza-id to every archived message (#1477)
authorEvgeniy Khramtsov <ekhramtsov@process-one.net>
Fri, 20 Jan 2017 20:21:06 +0000 (23:21 +0300)
committerEvgeniy Khramtsov <ekhramtsov@process-one.net>
Fri, 20 Jan 2017 20:21:06 +0000 (23:21 +0300)
src/mod_mam.erl
src/mod_mam_mnesia.erl
src/mod_mam_sql.erl

index f55c1ccf2345a157706d0d7df49a4420eb859675..68fe714a0bef3ab71642a0fb1f6ac7b7c63965c0 100644 (file)
@@ -750,14 +750,19 @@ select(_LServer, JidRequestor, JidArchive, Query, RSM,
                  case match_interval(Now, Start, End) and
                      match_rsm(Now, RSM) of
                      true ->
-                         [{integer_to_binary(TS), TS,
-                           msg_to_el(#archive_msg{
-                                        type = groupchat,
-                                        timestamp = Now,
-                                        peer = undefined,
-                                        nick = Nick,
-                                        packet = Pkt},
-                                     MsgType, JidRequestor, JidArchive)}];
+                         case msg_to_el(#archive_msg{
+                                           id = integer_to_binary(TS),
+                                           type = groupchat,
+                                           timestamp = Now,
+                                           peer = undefined,
+                                           nick = Nick,
+                                           packet = Pkt},
+                                        MsgType, JidRequestor, JidArchive) of
+                             {ok, Msg} ->
+                                 [{integer_to_binary(TS), TS, Msg}];
+                             {error, _} ->
+                                 []
+                         end;
                      false ->
                          []
                  end
@@ -776,25 +781,23 @@ select(LServer, JidRequestor, JidArchive, Query, RSM, MsgType) ->
     Mod = gen_mod:db_mod(LServer, ?MODULE),
     Mod:select(LServer, JidRequestor, JidArchive, Query, RSM, MsgType).
 
-msg_to_el(#archive_msg{timestamp = TS, packet = Pkt1, nick = Nick, peer = Peer},
+msg_to_el(#archive_msg{timestamp = TS, packet = El, nick = Nick,
+                      peer = Peer, id = ID},
          MsgType, JidRequestor, #jid{lserver = LServer} = JidArchive) ->
-    Pkt2 = maybe_update_from_to(Pkt1, JidRequestor, JidArchive, Peer, MsgType,
-                               Nick),
-    El = case Pkt2 of
-            #xmlel{attrs = Attrs} ->
-                Attrs1 = lists:keystore(<<"xmlns">>, 1, Attrs,
-                                        {<<"xmlns">>, ?NS_CLIENT}),
-                Pkt2#xmlel{attrs = Attrs1};
-            _ ->
-                xmpp:encode(Pkt2)
-        end,
-    #forwarded{xml_els = [El],
-              delay = #delay{stamp = TS, from = jid:make(LServer)}}.
-
-maybe_update_from_to(#xmlel{} = El, JidRequestor, JidArchive, Peer,
-                    {groupchat, _, _} = MsgType, Nick) ->
-    Pkt = xmpp:decode(El, ?NS_CLIENT, [ignore_els]),
-    maybe_update_from_to(Pkt, JidRequestor, JidArchive, Peer, MsgType, Nick);
+    try xmpp:decode(El, ?NS_CLIENT, [ignore_els]) of
+       Pkt1 ->
+           Pkt2 = set_stanza_id(Pkt1, JidArchive, ID),
+           Pkt3 = maybe_update_from_to(
+                    Pkt2, JidRequestor, JidArchive, Peer, MsgType, Nick),
+           Delay = #delay{stamp = TS, from = jid:make(LServer)},
+           {ok, #forwarded{xml_els = [xmpp:encode(Pkt3)], delay = Delay}}
+    catch _:{xmpp_codec, Why} ->
+           ?ERROR_MSG("Failed to decode raw element ~p from message "
+                      "archive of user ~s: ~s",
+                      [El, jid:to_string(JidArchive), xmpp:format_error(Why)]),
+           {error, invalid_xml}
+    end.
+
 maybe_update_from_to(#message{sub_els = Els} = Pkt, JidRequestor, JidArchive,
                     Peer, {groupchat, Role,
                            #state{config = #config{anonymous = Anon}}},
index 6b296f772688c3c151d64b178e99d98725d4ab59..f498bc3c7a083efafbb6963ad9c5c48a9c44a8ac 100644 (file)
@@ -160,12 +160,17 @@ select(_LServer, JidRequestor,
     SortedMsgs = lists:keysort(#archive_msg.timestamp, Msgs),
     {FilteredMsgs, IsComplete} = filter_by_rsm(SortedMsgs, RSM),
     Count = length(Msgs),
-    Result = {lists:map(
+    Result = {lists:flatmap(
                fun(Msg) ->
-                       {Msg#archive_msg.id,
-                        binary_to_integer(Msg#archive_msg.id),
-                        mod_mam:msg_to_el(Msg, MsgType, JidRequestor,
-                                          JidArchive)}
+                       case mod_mam:msg_to_el(
+                              Msg, MsgType, JidRequestor, JidArchive) of
+                           {ok, El} ->
+                               [{Msg#archive_msg.id,
+                                 binary_to_integer(Msg#archive_msg.id),
+                                 El}];
+                           {error, _} ->
+                               []
+                       end
                end, FilteredMsgs), IsComplete, Count},
     erlang:garbage_collect(),
     Result.
index a99c359c692e9a849e54b5cd4719a102b6dd9b5b..d553c2e640a35f87755656dc5d708675d57dd27f 100644 (file)
@@ -168,28 +168,12 @@ select(LServer, JidRequestor, #jid{luser = LUser} = JidArchive,
                end,
            {lists:flatmap(
               fun([TS, XML, PeerBin, Kind, Nick]) ->
-                      try
-                          #xmlel{} = El = fxml_stream:parse_element(XML),
-                          Now = usec_to_now(binary_to_integer(TS)),
-                          PeerJid = jid:tolower(jid:from_string(PeerBin)),
-                          T = case Kind of
-                                  <<"">> -> chat;
-                                  null -> chat;
-                                  _ -> jlib:binary_to_atom(Kind)
-                              end,
-                          [{TS, binary_to_integer(TS),
-                            mod_mam:msg_to_el(#archive_msg{timestamp = Now,
-                                                           packet = El,
-                                                           type = T,
-                                                           nick = Nick,
-                                                           peer = PeerJid},
-                                              MsgType, JidRequestor, JidArchive)}]
-                      catch _:Err ->
-                              ?ERROR_MSG("failed to parse data from SQL: ~p. "
-                                         "The data was: "
-                                         "timestamp = ~s, xml = ~s, "
-                                         "peer = ~s, kind = ~s, nick = ~s",
-                                         [Err, TS, XML, PeerBin, Kind, Nick]),
+                      case make_archive_el(
+                             TS, XML, PeerBin, Kind, Nick,
+                             MsgType, JidRequestor, JidArchive) of
+                          {ok, El} ->
+                              [{TS, binary_to_integer(TS), El}];
+                          {error, _} ->
                               []
                       end
               end, Res1), IsComplete, binary_to_integer(Count)};
@@ -319,3 +303,51 @@ get_max_direction_id(RSM) ->
        _ ->
            {undefined, undefined, <<>>}
     end.
+
+-spec make_archive_el(binary(), binary(), binary(), binary(),
+                     binary(), _, jid(), jid()) ->
+                            {ok, xmpp_element()} | {error, invalid_jid |
+                                                    invalid_timestamp |
+                                                    invalid_xml}.
+make_archive_el(TS, XML, Peer, Kind, Nick, MsgType, JidRequestor, JidArchive) ->
+    case fxml_stream:parse_element(XML) of
+       #xmlel{} = El ->
+           try binary_to_integer(TS) of
+               TSInt ->
+                   case jid:from_string(Peer) of
+                       #jid{} = PeerJID ->
+                           Now = usec_to_now(TSInt),
+                           PeerLJID = jid:tolower(PeerJID),
+                           T = case Kind of
+                                   <<"">> -> chat;
+                                   null -> chat;
+                                   _ -> jlib:binary_to_atom(Kind)
+                               end,
+                           mod_mam:msg_to_el(
+                             #archive_msg{timestamp = Now,
+                                          id = TS,
+                                          packet = El,
+                                          type = T,
+                                          nick = Nick,
+                                          peer = PeerLJID},
+                             MsgType, JidRequestor, JidArchive);
+                       error ->
+                           ?ERROR_MSG("Malformed 'peer' field with value "
+                                      "'~s' detected for user ~s in table "
+                                      "'archive': invalid JID",
+                                      [Peer, jid:to_string(JidArchive)]),
+                           {error, invalid_jid}
+                   end
+           catch _:_ ->
+                   ?ERROR_MSG("Malformed 'timestamp' field with value '~s' "
+                              "detected for user ~s in table 'archive': "
+                              "not an integer",
+                              [TS, jid:to_string(JidArchive)]),
+                   {error, invalid_timestamp}
+           end;
+       {error, {_, Reason}} ->
+           ?ERROR_MSG("Malformed 'xml' field with value '~s' detected "
+                      "for user ~s in table 'archive': ~s",
+                      [XML, jid:to_string(JidArchive), Reason]),
+           {error, invalid_xml}
+    end.