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
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}}},
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.
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)};
_ ->
{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.