public void sendInvitation(@Nonnull final JID to, @Nullable final String reason, @Nonnull final Affiliation senderAffiliation, @Nullable final JID senderUserAddress, @Nullable final List<Element> extensions)
        throws ForbiddenException, CannotBeInvitedException {
        if (!isMembersOnly() || canOccupantsInvite()
            || Affiliation.admin == senderAffiliation
            || Affiliation.owner == senderAffiliation) {
            // If the room is not members-only OR if the room is members-only and anyone can send
            // invitations or the sender is an admin or an owner, then send the invitation
            Message message = new Message();
            message.setFrom(selfOccupantData.getOccupantJID());
            message.setTo(to);

            if (mucService.getMUCDelegate() != null) {
                switch(mucService.getMUCDelegate().sendingInvitation(this, to, senderUserAddress, reason)) {
                    case HANDLED_BY_DELEGATE:
                        //if the delegate is taking care of it, there's nothing for us to do
                        return;
                    case HANDLED_BY_OPENFIRE:
                        //continue as normal if we're asked to handle it
                        break;
                    case REJECTED:
                        //we can't invite that person
                        throw new CannotBeInvitedException();
                }
            }

            // Add a list of extensions sent with the original message invitation (if any)
            if (extensions != null) {
                for(Element element : extensions) {
                    element.setParent(null);
                    message.getElement().add(element);
                }
            }
            Element frag = message.addChildElement("x", "http://jabber.org/protocol/muc#user");
            // ChatUser will be null if the room itself (i.e. via admin console) made the request. In that case, use the room JID. See OF-2486.
            final JID from = senderUserAddress != null ? senderUserAddress : getJID();
            frag.addElement("invite").addAttribute("from", from.toBareJID());
            if (reason != null && !reason.isEmpty()) {
                Element invite = frag.element("invite");
                if (invite == null) {
                    invite = frag.addElement("invite");
                }
                invite.addElement("reason").setText(reason);
            }
            if (isPasswordProtected()) {
                frag.addElement("password").setText(getPassword());
            }

            // Include the jabber:x:conference information for backward compatibility
            frag = message.addChildElement("x", "jabber:x:conference");
            frag.addAttribute("jid", selfOccupantData.getOccupantJID().toBareJID());

            // Send the message with the invitation
            XMPPServer.getInstance().getPacketRouter().route(message);
        }
        else {
            throw new ForbiddenException();
        }
    }
Sends an invitation to a user. The invitation will be sent as if the room is inviting the
user. The invitation will include the original occupant that sent the invitation together with
the reason for the invitation if any. Since the invitee could be offline at the moment we
need the originating session so that the offline strategy could potentially bounce the
message with the invitation.

@param to the JID of the user that is being invited.
@param reason the reason of the invitation or null if none.
@param senderAffiliation the room affiliation the user that sent the invitation.
@param senderUserAddress the (real) user address of the user that sent the invitation.
@param extensions the list of extensions sent with the original message invitation or null
       if none.
@throws ForbiddenException If the user is not allowed to send the invitation.
@throws CannotBeInvitedException (Optionally) If the user being invited does not have access to the room
xmppserver/src/main/java/org/jivesoftware/openfire/muc/MUCRoom.java