private void processRegularMUCStanza( @Nonnull final Packet stanza )
    {
        final Element fmuc = stanza.getElement().element(FMUC);
        if (fmuc == null) {
            throw new IllegalArgumentException( "Provided stanza must have an 'fmuc' child element (but does not).");
        }

        final JID remoteMUC = stanza.getFrom().asBareJID();
        final JID author = new JID( fmuc.attributeValue("from") ); // TODO input validation.
        final MUCOccupant senderOccupantData = room.getOccupantByFullJID( author );
        Log.trace("(room: '{}'): Processing stanza from remote FMUC peer '{}' as regular room traffic. Sender of stanza: {}", room.getJID(), remoteMUC, author );

        // Distribute. Note that this will distribute both to the local node, as well as to all FMUC nodes in the FMUC set.
        if ( stanza instanceof Presence ) {
            RemoteFMUCNode remoteFMUCNode = inboundJoins.get(remoteMUC);
            if ( remoteFMUCNode == null && outboundJoin != null && remoteMUC.equals(outboundJoin.getPeer())) {
                remoteFMUCNode = outboundJoin;
            }
            if ( remoteFMUCNode != null )
            {
                final boolean isLeave = ((Presence) stanza).getType() == Presence.Type.unavailable;
                final boolean isJoin = ((Presence) stanza).isAvailable();

                if ( isLeave )
                {
                    Log.trace("(room: '{}'): Occupant '{}' left room on remote FMUC peer '{}'", room.getJID(), author, remoteMUC );
                    makeRemoteOccupantLeaveRoom( (Presence) stanza );
                    remoteFMUCNode.removeOccupant(author); // Remove occupant only after the leave stanzas have been sent, otherwise the author is (no longer) recognized as an occupant of the particular node when the leave is being processed.

                    // The joined room confirms that the joining room has left the set by sending a presence stanza from the bare JID
                    // of the joined room to the bare JID of the joining room with an FMUC payload containing an element 'left'.
                    if ( remoteFMUCNode instanceof InboundJoin && remoteFMUCNode.occupants.isEmpty() ) {
                        Log.trace("(room: '{}'): Last occupant that joined on remote FMUC peer '{}' has now left the room. The peer has left the FMUC node set.", room.getJID(), remoteMUC );
                        final Presence leaveFMUCSet = new Presence();
                        leaveFMUCSet.setTo( remoteMUC );
                        leaveFMUCSet.setFrom( room.getJID() );
                        leaveFMUCSet.getElement().addElement( FMUC ).addElement( "left" );
                        inboundJoins.remove(remoteMUC);

                        XMPPServer.getInstance().getPacketRouter().route( leaveFMUCSet );
                    }
                } else if ( isJoin ) {
                    Log.trace("(room: '{}'): Occupant '{}' joined room on remote FMUC peer '{}'", room.getJID(), author, remoteMUC );
                    remoteFMUCNode.addOccupant(author);
                    makeRemoteOccupantJoinRoom( (Presence) stanza );
                } else {
                    // FIXME implement sharing of presence.
                    Log.error("Processing of presence stanzas received from other FMUC nodes is pending implementation! Ignored stanza: {}", stanza.toXML(), new UnsupportedOperationException());
                }
            }
            else
            {
                Log.warn( "Unable to process stanza: {}", stanza.toXML() );
            }
        } else {
            // Strip all FMUC data.
            final Packet stripped = createCopyWithoutFMUC( stanza );

            // The 'stripped' stanza is going to be distributed locally. Act as if it originates from a local user, instead of the remote FMUC one.
            final JID from;
            from = senderOccupantData.getOccupantJID();
            stripped.setFrom( from );
            stripped.setTo( room.getJID() );

            room.send( stripped, senderOccupantData );
        }
    }
Processes a stanza that is received from another node in the FMUC set, by translating it into 'regular' MUC data.

The provided input is expected to be a stanza received from another node in the FMUC set. It is stripped from
FMUC data, after which it is distributed to the local users.

Additionally, it is sent out to all (other) FMUC nodes that are known.

@param stanza The data to be processed.
xmppserver/src/main/java/org/jivesoftware/openfire/muc/spi/FMUCHandler.java