IQAdminHandler.java 14 KB
Newer Older
1 2 3 4 5
/**
 * $RCSfile$
 * $Revision: 1125 $
 * $Date: 2005-03-14 15:59:37 -0300 (Mon, 14 Mar 2005) $
 *
6
 * Copyright (C) 2004-2008 Jive Software. All rights reserved.
7 8
 *
 * This software is published under the terms of the GNU Public License (GPL),
9 10
 * a copy of which is included in this distribution, or a commercial license
 * agreement with Jive.
11 12
 */

13
package org.jivesoftware.openfire.muc.spi;
14 15

import org.dom4j.Element;
16
import org.jivesoftware.openfire.PacketRouter;
17
import org.jivesoftware.openfire.muc.*;
18
import org.jivesoftware.openfire.user.UserNotFoundException;
19 20 21 22 23
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
import org.xmpp.packet.PacketError;
import org.xmpp.packet.Presence;

Gaston Dombiak's avatar
Gaston Dombiak committed
24 25 26
import java.util.ArrayList;
import java.util.List;

27 28 29 30 31 32 33 34 35
/**
 * A handler for the IQ packet with namespace http://jabber.org/protocol/muc#admin. This kind of 
 * packets are usually sent by room admins. So this handler provides the necessary functionality
 * to support administrator requirements such as: managing room members/outcasts/etc., kicking 
 * occupants and banning users.
 *
 * @author Gaston Dombiak
 */
public class IQAdminHandler {
36
    private LocalMUCRoom room;
37 38 39

    private PacketRouter router;

40
    public IQAdminHandler(LocalMUCRoom chatroom, PacketRouter packetRouter) {
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
        this.room = chatroom;
        this.router = packetRouter;
    }

    /**
     * Handles the IQ packet sent by an owner or admin of the room. Possible actions are:
     * <ul>
     * <li>Return the list of participants</li>
     * <li>Return the list of moderators</li>
     * <li>Return the list of members</li>
     * <li>Return the list of outcasts</li>
     * <li>Change user's affiliation to member</li>
     * <li>Change user's affiliation to outcast</li>
     * <li>Change user's affiliation to none</li>
     * <li>Change occupant's affiliation to moderator</li>
     * <li>Change occupant's affiliation to participant</li>
     * <li>Change occupant's affiliation to visitor</li>
     * <li>Kick occupants from the room</li>
     * </ul>
     *
     * @param packet the IQ packet sent by an owner or admin of the room.
     * @param role the role of the user that sent the request packet.
     * @throws ForbiddenException If the user is not allowed to perform his request.
     * @throws ConflictException If the desired room nickname is already reserved for the room or
     *                           if the room was going to lose all of its owners.
     * @throws NotAllowedException Thrown if trying to ban an owner or an administrator.
67
     * @throws CannotBeInvitedException If the user being invited as a result of being added to a members-only room still does not have permission
68 69
     */
    public void handleIQ(IQ packet, MUCRole role) throws ForbiddenException, ConflictException,
70
            NotAllowedException, CannotBeInvitedException {
71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105
        IQ reply = IQ.createResultIQ(packet);
        Element element = packet.getChildElement();

        // Analyze the action to perform based on the included element
        List itemsList = element.elements("item");
        if (!itemsList.isEmpty()) {
            handleItemsElement(role, itemsList, reply);
        }
        else {
            // An unknown and possibly incorrect element was included in the query
            // element so answer a BAD_REQUEST error
            reply.setChildElement(packet.getChildElement().createCopy());
            reply.setError(PacketError.Condition.bad_request);
        }
        if (reply.getTo() != null) {
            // Send a reply only if the sender of the original packet was from a real JID. (i.e. not
            // a packet generated locally)
            router.route(reply);
        }
    }

    /**
     * Handles packets that includes item elements. Depending on the item's attributes the
     * interpretation of the request may differ. For example, an item that only contains the
     * "affiliation" attribute is requesting the list of participants or members. Whilst if the item
     * contains the affiliation together with a jid means that the client is changing the
     * affiliation of the requested jid.
     *
     * @param senderRole the role of the user that sent the request packet.
     * @param itemsList  the list of items sent by the client.
     * @param reply      the iq packet that will be sent back as a reply to the client's request.
     * @throws ForbiddenException If the user is not allowed to perform his request.
     * @throws ConflictException If the desired room nickname is already reserved for the room or
     *                           if the room was going to lose all of its owners.
     * @throws NotAllowedException Thrown if trying to ban an owner or an administrator.
106
     * @throws CannotBeInvitedException If the user being invited as a result of being added to a members-only room still does not have permission
107 108
     */
    private void handleItemsElement(MUCRole senderRole, List itemsList, IQ reply)
109
            throws ForbiddenException, ConflictException, NotAllowedException, CannotBeInvitedException {
110
        Element item;
Gaston Dombiak's avatar
Gaston Dombiak committed
111 112
        String affiliation;
        String roleAttribute;
113 114 115 116 117
        boolean hasJID = ((Element)itemsList.get(0)).attributeValue("jid") != null;
        boolean hasNick = ((Element)itemsList.get(0)).attributeValue("nick") != null;
        // Check if the client is requesting or changing the list of moderators/members/etc.
        if (!hasJID && !hasNick) {
            // The client is requesting the list of moderators/members/participants/outcasts
118 119
            for (Object anItem : itemsList) {
                item = (Element) anItem;
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138
                affiliation = item.attributeValue("affiliation");
                roleAttribute = item.attributeValue("role");
                // Create the result that will hold an item for each
                // moderator/member/participant/outcast
                Element result = reply.setChildElement("query", "http://jabber.org/protocol/muc#admin");

                Element metaData;
                if ("outcast".equals(affiliation)) {
                    // The client is requesting the list of outcasts
                    if (MUCRole.Affiliation.admin != senderRole.getAffiliation()
                            && MUCRole.Affiliation.owner != senderRole.getAffiliation()) {
                        throw new ForbiddenException();
                    }
                    for (String jid : room.getOutcasts()) {
                        metaData = result.addElement("item", "http://jabber.org/protocol/muc#admin");
                        metaData.addAttribute("affiliation", "outcast");
                        metaData.addAttribute("jid", jid);
                    }

139
                } else if ("member".equals(affiliation)) {
140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160
                    // The client is requesting the list of members
                    // In a members-only room members can get the list of members
                    if (!room.isMembersOnly()
                            && MUCRole.Affiliation.admin != senderRole.getAffiliation()
                            && MUCRole.Affiliation.owner != senderRole.getAffiliation()) {
                        throw new ForbiddenException();
                    }
                    for (String jid : room.getMembers()) {
                        metaData = result.addElement("item", "http://jabber.org/protocol/muc#admin");
                        metaData.addAttribute("affiliation", "member");
                        metaData.addAttribute("jid", jid);
                        try {
                            List<MUCRole> roles = room.getOccupantsByBareJID(jid);
                            MUCRole role = roles.get(0);
                            metaData.addAttribute("role", role.getRole().toString());
                            metaData.addAttribute("nick", role.getNickname());
                        }
                        catch (UserNotFoundException e) {
                            // Do nothing
                        }
                    }
161
                } else if ("moderator".equals(roleAttribute)) {
162 163 164 165 166 167 168 169
                    // The client is requesting the list of moderators
                    if (MUCRole.Affiliation.admin != senderRole.getAffiliation()
                            && MUCRole.Affiliation.owner != senderRole.getAffiliation()) {
                        throw new ForbiddenException();
                    }
                    for (MUCRole role : room.getModerators()) {
                        metaData = result.addElement("item", "http://jabber.org/protocol/muc#admin");
                        metaData.addAttribute("role", "moderator");
170
                        metaData.addAttribute("jid", role.getUserAddress().toString());
171 172 173
                        metaData.addAttribute("nick", role.getNickname());
                        metaData.addAttribute("affiliation", role.getAffiliation().toString());
                    }
174
                } else if ("participant".equals(roleAttribute)) {
175 176 177 178 179 180 181
                    // The client is requesting the list of participants
                    if (MUCRole.Role.moderator != senderRole.getRole()) {
                        throw new ForbiddenException();
                    }
                    for (MUCRole role : room.getParticipants()) {
                        metaData = result.addElement("item", "http://jabber.org/protocol/muc#admin");
                        metaData.addAttribute("role", "participant");
182
                        metaData.addAttribute("jid", role.getUserAddress().toString());
183 184 185
                        metaData.addAttribute("nick", role.getNickname());
                        metaData.addAttribute("affiliation", role.getAffiliation().toString());
                    }
186
                } else {
187 188 189 190 191 192
                    reply.setError(PacketError.Condition.bad_request);
                }
            }
        }
        else {
            // The client is modifying the list of moderators/members/participants/outcasts
Gaston Dombiak's avatar
Gaston Dombiak committed
193
            JID jid;
194
            String nick;
Gaston Dombiak's avatar
Gaston Dombiak committed
195
            String target;
196 197 198 199 200 201 202
            boolean hasAffiliation = ((Element) itemsList.get(0)).attributeValue("affiliation") !=
                    null;

            // Keep a registry of the updated presences
            List<Presence> presences = new ArrayList<Presence>(itemsList.size());

            // Collect the new affiliations or roles for the specified jids
203
            for (Object anItem : itemsList) {
204
                try {
205
                    item = (Element) anItem;
206 207 208 209 210 211 212
                    target = (hasAffiliation ? item.attributeValue("affiliation") : item
                            .attributeValue("role"));
                    // jid could be of the form "full JID" or "bare JID" depending if we are
                    // going to change a role or an affiliation
                    if (hasJID) {
                        jid = new JID(item.attributeValue("jid"));
                        nick = null;
213
                    } else {
214 215
                        // Get the JID based on the requested nick
                        nick = item.attributeValue("nick");
216
                        jid = room.getOccupant(nick).getUserAddress();
217 218
                    }

219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245
                    if ("moderator".equals(target)) {
                        // Add the user as a moderator of the room based on the full JID
                        presences.add(room.addModerator(jid, senderRole));
                    } else if ("participant".equals(target)) {
                        // Add the user as a participant of the room based on the full JID
                        presences.add(room.addParticipant(jid,
                                item.elementTextTrim("reason"),
                                senderRole));
                    } else if ("visitor".equals(target)) {
                        // Add the user as a visitor of the room based on the full JID
                        presences.add(room.addVisitor(jid, senderRole));
                    } else if ("member".equals(target)) {
                        // Add the user as a member of the room based on the bare JID
                        boolean hadAffiliation = room.getAffiliation(jid.toBareJID()) != MUCRole.Affiliation.none;
                        presences.addAll(room.addMember(jid.toBareJID(), nick, senderRole));
                        // If the user had an affiliation don't send an invitation. Otherwise
                        // send an invitation if the room is members-only
                        if (!hadAffiliation && room.isMembersOnly()) {
                            room.sendInvitation(jid, null, senderRole, null);
                        }
                    } else if ("outcast".equals(target)) {
                        // Add the user as an outcast of the room based on the bare JID
                        presences.addAll(room.addOutcast(jid.toBareJID(), item.elementTextTrim("reason"), senderRole));
                    } else if ("none".equals(target)) {
                        if (hasAffiliation) {
                            // Set that this jid has a NONE affiliation based on the bare JID
                            presences.addAll(room.addNone(jid.toBareJID(), senderRole));
246
                        } else {
247 248 249 250 251 252
                            // Kick the user from the room
                            if (MUCRole.Role.moderator != senderRole.getRole()) {
                                throw new ForbiddenException();
                            }
                            presences.add(room.kickOccupant(jid, senderRole.getUserAddress(),
                                    item.elementTextTrim("reason")));
253
                        }
254 255
                    } else {
                        reply.setError(PacketError.Condition.bad_request);
256 257 258 259 260 261 262 263 264 265 266 267 268 269
                    }
                }
                catch (UserNotFoundException e) {
                    // Do nothing
                }
            }

            // Send the updated presences to the room occupants
            for (Presence presence : presences) {
                room.send(presence);
            }
        }
    }
}