MUC Private messages - all other tabs being taken over when signed in to multiple sessions

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

1 Like

About carbon.[SPARK-2164] - Ignite Realtime Jira
I myself faced this bug in my company. Therefore, it was decided that the user could use only one session (using Client Control) - Two simultaneous connections, same user

Hi Alex 2,

Thanks for taking the time to dig into this, and provide all of these details and a fix. I have raised a new ticket for this specific issue: [SPARK-2269] - Ignite Realtime Jira

Can you tempt you to create a pull request against our source repository to introduce your fix?

Thanks for the fix you suggested, I checked when using multiple resources, the message gets into the correct tab!

Feel free to submit your fixes on github or here.