Hi there,
Along with my other bugs related to MUC rooms[1] and private conversations associated with them[2] I have found that if a user is signed in to multiple sessions and has multiple PMs open, when they receive a PM in one of them all other chat tabs will have their participant taken over, making them all a conversation with the person who sent the PM.
This is due to incorrect filtering/handling of carbon copy packets. They are never checked or filtered to check they are appropriate for the current conversation.
Brief overview of the two types of carbon copy (CC) packets:
First is a <sent>
type CC. This is sent to all of my other sessions when I send dan@example.com
a message. This is so that you can see both sides of my conversation. In this instance, I sent a message from alex@example.com/Dev-PC
to dan@example.com
. Openfire then sends a CC <message>
to my other session at alex@example.com/Alex-PC
containing the original <message>
.
Note: it is not possible to determine which conversation this message is for from the outer <message>
. This is where the fault lies.
<message type="chat" from="alex@example.com" to="alex@example.com/Alex-PC">
<sent xmlns="urn:xmpp:carbons:2">
<forwarded xmlns="urn:xmpp:forward:0">
<message xmlns="jabber:client" to="dan@example.com" id="2tN7T-183" type="chat" from="alex@example.com/Dev-PC">
<thread>cMRwMB</thread>
<body>ping?</body>
<x xmlns="jabber:x:event">
<offline/>
<composing/>
</x>
<active xmlns="http://jabber.org/protocol/chatstates"/>
</message>
</forwarded>
</sent>
</message>
Next is a <received>
type CC. This is sent to all of my other sessions when dan@example.com
sends me a message. This is so that all sessions get a copy of incoming messages. In this instance dan sent me a message from dan@example.com/Dan-PC
to alex@example.com/Dev-PC
. Openfire then sent a CC <message>
to my other session at alex@example.com/Alex-PC
which contains the original <message>
.
Note: it is not possible to determine which conversation this message is for from the outer <message>
. This is where the fault lies.
<message type="chat" from="alex@example.com" to="alex@example.com/Alex-PC">
<received xmlns="urn:xmpp:carbons:2">
<forwarded xmlns="urn:xmpp:forward:0">
<message xmlns="jabber:client" to="alex@example.com/Dev-PC" id="Ijnm8-213" type="chat" from="dan@example.com/Dan-PC">
<thread>cMRwMB</thread>
<body>pong</body>
<x xmlns="jabber:x:event">
<offline/>
<composing/>
</x>
<active xmlns="http://jabber.org/protocol/chatstates"/>
</message>
</forwarded>
</received>
</message>
The only way to determine if the CC <message>
is appropriate to the current window is to check whether the inner <message>
has a from
that matches the participant (for a <received>
CC) or that the inner <message>
has a to
that matches the participant (for a <sent>
CC).
This match needs to be a full JID match for a MUC PM or a bare JID match for a normal PM.
In ChatRoomImpl.java
all filtering is done on the outer <message>
with a small security check done specifically on CC messages. This means that any open chatroom window will receive and parse all CC <message>
packets, and because of a setParticipantJID
call in the handling code, the window has it’s participant overwritten by the participant in the CC message.
I cannot find any examples of using filters on a <message>
within a <message>
so I have put the checking logic in the processStanza
function as follows.
final CarbonExtension carbon = (CarbonExtension) message.getExtension( CarbonExtension.NAMESPACE );
if ( carbon != null )
{
// Is the a carbon copy?
final Message forwardedStanza = (Message) carbon.getForwarded().getForwardedStanza();
if ( forwardedStanza.getBody() != null )
{
if ( carbon.getDirection() == CarbonExtension.Direction.received )
{
if ((forwardedStanza.getFrom().equals(getJid()) && privateChat) || //private chat from MUC, match the full JID
(forwardedStanza.getFrom().asBareJid().equals(getJid().asBareJid()) && !privateChat)) //person to person chat, match bare jids
{
// This is a stanza that we received from someone on one of our other clients.
setParticipantJID(forwardedStanza.getFrom());
insertMessage( forwardedStanza );
}
}
else
{
if ((forwardedStanza.getTo().equals(getJid()) && privateChat) || //private chat from MUC, match full JID
(forwardedStanza.getTo().asBareJid().equals(getJid().asBareJid()) && !privateChat)) //person to person chat, match bare jids
{
// This is a stanza that one of our own clients sent.
setParticipantJID(forwardedStanza.getTo());
displaySendMessage( forwardedStanza );
}
}
showTyping( false );
}
}
This will be simplified a bit when I make the change to getParticipantJID()
mentioned in my other post[2].
I’m not overly happy with this solution as it breaks away from the norm of using filters. But I don’t have the knowledge to make my own filter at this time.
[1] - MUC rooms and carbon copies sending duplicate messages when connected with multiple sessions
[2] - MUC and JIDs vs BareJIDs - involves SPARK-2223
Thanks,
Alex 2