I want to find message element in ejabberd packet. The packet itself is a message element but sometimes (delayed messages or other cases) the actual message is nested inside the packet:
Normal messages:
<message from="[email protected]"
to="[email protected]"
type="groupchat">
<body>Test</body>
</message>
Other structures example:
<message from="[email protected]"
to="[email protected]/pda">
<event xmlns="http://jabber.org/protocol/pubsub#event">
<items node="urn:xmpp:mucsub:nodes:messages">
<item id="18277869892147515942">
<message from="[email protected]/secondwitch"
to="[email protected]/pda"
type="groupchat"
xmlns="jabber:client">
<archived xmlns="urn:xmpp:mam:tmp"
by="muc.shakespeare.example"
id="1467896732929849" />
<stanza-id xmlns="urn:xmpp:sid:0"
by="muc.shakespeare.example"
id="1467896732929849" />
<body>Hello from the MUC room !</body>
</message>
</item>
</items>
</event>
</message>
Which in second example I would like to find the inner message element. The second case structure is not always the same. So I need to traverse trough the packet and try to find any sub element with name message. It cannot be two message subelements so if I found the first I don't need to continue anymore. If there were no sub elements with name message I would like to return the original packet.
This is the code I have till now:
get_message(Packet) ->
Els = xmpp:get_els(Packet),
Found =
case Els of
[] ->
<<>>;
_ ->
El = find_file(Els, fun(El) ->
ElementName = io_lib:format("~s",[xmpp:get_name(El)]),
string:equal(ElementName,"message") end, <<>>),
Fe =
case El of
<<>> ->
Elements = xmpp:get_els(El),
lists:foreach(fun(Element) ->
FoundElement = get_message(Element),
case FoundElement of
<<>> ->
ok;
_ ->
% stop foreach and return FoundElement
FoundElement
end
end, Elements);
_ ->
El
end,
Fe
end,
Found.
find_file(L, Condition, Default) ->
case lists:dropwhile(fun(E) -> not Condition(E) end, L) of
[] -> Default;
[F | _] -> F
end.
Turned out I don't need to do all these calculations. these is a method called unwrap_mucsub_message which do exactly what I needed.
get_message(Packet) ->
case misc:unwrap_mucsub_message(Packet) of
#message{} = Msg ->
Msg;
_ ->
Packet
end.