IQOwnerHandler.java 32.7 KB
Newer Older
Matt Tucker's avatar
Matt Tucker committed
1 2 3 4 5
/**
 * $RCSfile$
 * $Revision$
 * $Date$
 *
Matt Tucker's avatar
Matt Tucker committed
6
 * Copyright (C) 2004 Jive Software. All rights reserved.
Matt Tucker's avatar
Matt Tucker committed
7
 *
Matt Tucker's avatar
Matt Tucker committed
8 9
 * This software is published under the terms of the GNU Public License (GPL),
 * a copy of which is included in this distribution.
Matt Tucker's avatar
Matt Tucker committed
10
 */
Matt Tucker's avatar
Matt Tucker committed
11

Matt Tucker's avatar
Matt Tucker committed
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
package org.jivesoftware.messenger.muc.spi;

import org.jivesoftware.messenger.forms.DataForm;
import org.jivesoftware.messenger.forms.FormField;
import org.jivesoftware.messenger.forms.spi.XDataFormImpl;
import org.jivesoftware.messenger.forms.spi.XFormFieldImpl;
import org.jivesoftware.messenger.muc.ConflictException;
import org.jivesoftware.messenger.muc.ForbiddenException;
import org.jivesoftware.messenger.muc.MUCRole;
import org.jivesoftware.util.LocaleUtils;
import org.jivesoftware.messenger.*;
import org.jivesoftware.messenger.user.UserNotFoundException;
import java.util.*;

import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.QName;
Matt Tucker's avatar
Matt Tucker committed
29 30 31 32
import org.xmpp.packet.Presence;
import org.xmpp.packet.JID;
import org.xmpp.packet.IQ;
import org.xmpp.packet.PacketError;
Matt Tucker's avatar
Matt Tucker committed
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

/**
 * A handler for the IQ packet with namespace http://jabber.org/protocol/muc#owner. This kind of 
 * packets are usually sent by room owners. So this handler provides the necessary functionality
 * to support owner requirements such as: room configuration and room destruction.
 *
 * @author Gaston Dombiak
 */
public class IQOwnerHandler {
    private MUCRoomImpl room;

    private PacketRouter router;

    private XDataFormImpl configurationForm;

Matt Tucker's avatar
Matt Tucker committed
48
    private Element probeResult;
Matt Tucker's avatar
Matt Tucker committed
49 50 51 52 53 54 55

    public IQOwnerHandler(MUCRoomImpl chatroom, PacketRouter packetRouter) {
        this.room = chatroom;
        this.router = packetRouter;
        init();
    }

56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75
    /**
     * Handles the IQ packet sent by an owner of the room. Possible actions are:
     * <ul>
     * <li>Return the list of owners</li>
     * <li>Return the list of admins</li>
     * <li>Change user's affiliation to owner</li>
     * <li>Change user's affiliation to admin</li>
     * <li>Change user's affiliation to member</li>
     * <li>Change user's affiliation to none</li>
     * <li>Destroy the room</li>
     * <li>Return the room configuration within a dataform</li>
     * <li>Update the room configuration based on the sent dataform</li>
     * </ul>
     *
     * @param packet the IQ packet sent by an owner of the room.
     * @param role the role of the user that sent the packet.
     * @throws ForbiddenException if the user does not have enough permissions (ie. is not an owner).
     * @throws ConflictException If the room was going to lose all of its owners.
     */
    public void handleIQ(IQ packet, MUCRole role) throws ForbiddenException, ConflictException {
Matt Tucker's avatar
Matt Tucker committed
76
        // Only owners can send packets with the namespace "http://jabber.org/protocol/muc#owner"
Matt Tucker's avatar
Matt Tucker committed
77
        if (MUCRole.Affiliation.owner != role.getAffiliation()) {
Matt Tucker's avatar
Matt Tucker committed
78 79 80
            throw new ForbiddenException();
        }

Matt Tucker's avatar
Matt Tucker committed
81 82
        IQ reply = IQ.createResultIQ(packet);
        Element element = packet.getChildElement();
Matt Tucker's avatar
Matt Tucker committed
83 84 85 86

        // Analyze the action to perform based on the included element
        Element formElement = element.element(QName.get("x", "jabber:x:data"));
        if (formElement != null) {
87
            handleDataFormElement(role, formElement);
Matt Tucker's avatar
Matt Tucker committed
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104
        }
        else {
            Element destroyElement = element.element("destroy");
            if (destroyElement != null) {
                room.destroyRoom(destroyElement.attributeValue("jid"), destroyElement
                        .elementTextTrim("reason"));
            }
            else {
                List itemsList = element.elements("item");
                if (!itemsList.isEmpty()) {
                    handleItemsElement(itemsList, role, reply);
                }
                else {
                    // If no element was included in the query element then answer the
                    // configuration form
                    if (!element.elementIterator().hasNext()) {
                        refreshConfigurationFormValues();
Matt Tucker's avatar
Matt Tucker committed
105
                        reply.setChildElement(probeResult.createCopy());
Matt Tucker's avatar
Matt Tucker committed
106 107 108 109
                    }
                    // An unknown and possibly incorrect element was included in the query
                    // element so answer a BAD_REQUEST error
                    else {
110
                        reply.setChildElement(packet.getChildElement().createCopy());
Matt Tucker's avatar
Matt Tucker committed
111
                        reply.setError(PacketError.Condition.bad_request);
Matt Tucker's avatar
Matt Tucker committed
112 113 114 115
                    }
                }
            }
        }
Matt Tucker's avatar
Matt Tucker committed
116
        if (reply.getTo() != null) {
117 118 119 120
            // 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);
        }
Matt Tucker's avatar
Matt Tucker committed
121 122 123 124 125 126 127 128 129 130
    }

    /**
     * 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 owners or admins. Whilst if the item
     * contains the affiliation together with a jid means that the client is changing the
     * affiliation of the requested jid.
     *
     * @param itemsList  the list of items sent by the client.
131
     * @param senderRole the role of the user that sent the items.
Matt Tucker's avatar
Matt Tucker committed
132 133
     * @param reply      the iq packet that will be sent back as a reply to the client's request.
     * @throws ForbiddenException if the user does not have enough permissions.
134
     * @throws ConflictException If the room was going to lose all of its owners.
Matt Tucker's avatar
Matt Tucker committed
135 136 137 138 139 140 141 142 143 144 145 146 147 148
     */
    private void handleItemsElement(List itemsList, MUCRole senderRole, IQ reply)
            throws ForbiddenException, ConflictException {
        Element item;
        String affiliation = null;
        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 owners/admin
        if (!hasJID && !hasNick) {
            // The client is requesting the list of owners or admins
            for (Iterator items = itemsList.iterator(); items.hasNext();) {
                item = (Element)items.next();
                affiliation = item.attributeValue("affiliation");
                // Create the result that will hold an item for each owner or admin
Derek DeMoro's avatar
Derek DeMoro committed
149
                Element result = reply.setChildElement("query", "http://jabber.org/protocol/muc#owner");
Matt Tucker's avatar
Matt Tucker committed
150 151 152

                if ("owner".equals(affiliation)) {
                    // The client is requesting the list of owners
Derek DeMoro's avatar
Derek DeMoro committed
153
                    Element ownerMetaData;
Matt Tucker's avatar
Matt Tucker committed
154
                    MUCRole role;
155
                    for (String jid : room.getOwners()) {
Derek DeMoro's avatar
Derek DeMoro committed
156 157 158
                        ownerMetaData = result.addElement("item", "http://jabber.org/protocol/muc#owner");
                        ownerMetaData.addAttribute("affiliation", "owner");
                        ownerMetaData.addAttribute("jid", jid);
Matt Tucker's avatar
Matt Tucker committed
159 160
                        // Add role and nick to the metadata if the user is in the room
                        try {
161 162
                            List<MUCRole> roles = room.getOccupantsByBareJID(jid);
                            role = roles.get(0);
Matt Tucker's avatar
Matt Tucker committed
163
                            ownerMetaData.addAttribute("role", role.getRole().toString());
Derek DeMoro's avatar
Derek DeMoro committed
164
                            ownerMetaData.addAttribute("nick", role.getNickname());
Matt Tucker's avatar
Matt Tucker committed
165 166 167 168 169 170 171 172
                        }
                        catch (UserNotFoundException e) {
                            // Do nothing
                        }
                    }
                }
                else if ("admin".equals(affiliation)) {
                    // The client is requesting the list of admins
Derek DeMoro's avatar
Derek DeMoro committed
173
                    Element adminMetaData;
Matt Tucker's avatar
Matt Tucker committed
174
                    MUCRole role;
175
                    for (String jid : room.getAdmins()) {
Derek DeMoro's avatar
Derek DeMoro committed
176 177 178
                        adminMetaData = result.addElement("item", "http://jabber.org/protocol/muc#owner");
                        adminMetaData.addAttribute("affiliation", "admin");
                        adminMetaData.addAttribute("jid", jid);
Matt Tucker's avatar
Matt Tucker committed
179 180
                        // Add role and nick to the metadata if the user is in the room
                        try {
181 182
                            List<MUCRole> roles = room.getOccupantsByBareJID(jid);
                            role = roles.get(0);
Matt Tucker's avatar
Matt Tucker committed
183
                            adminMetaData.addAttribute("role", role.getRole().toString());
Derek DeMoro's avatar
Derek DeMoro committed
184
                            adminMetaData.addAttribute("nick", role.getNickname());
Matt Tucker's avatar
Matt Tucker committed
185 186 187 188 189 190 191
                        }
                        catch (UserNotFoundException e) {
                            // Do nothing
                        }
                    }
                }
                else {
Derek DeMoro's avatar
Derek DeMoro committed
192
                    reply.setError(PacketError.Condition.bad_request);
Matt Tucker's avatar
Matt Tucker committed
193 194 195 196 197
                }
            }
        }
        else {
            // The client is modifying the list of owners or admins
198
            Map<String,String> jids = new HashMap<String,String>();
Matt Tucker's avatar
Matt Tucker committed
199 200 201 202 203 204 205 206
            String bareJID = null;
            String nick;
            // Collect the new affiliations for the specified jids
            for (Iterator items = itemsList.iterator(); items.hasNext();) {
                try {
                    item = (Element)items.next();
                    affiliation = item.attributeValue("affiliation");
                    if (hasJID) {
Matt Tucker's avatar
Matt Tucker committed
207
                        bareJID = new JID(item.attributeValue("jid")).toBareJID();
Matt Tucker's avatar
Matt Tucker committed
208 209 210 211
                    }
                    else {
                        // Get the bare JID based on the requested nick
                        nick = item.attributeValue("nick");
Matt Tucker's avatar
Matt Tucker committed
212
                        bareJID = room.getOccupant(nick).getChatUser().getAddress().toBareJID();
Matt Tucker's avatar
Matt Tucker committed
213 214 215 216 217 218 219 220 221
                    }
                    jids.put(bareJID, affiliation);
                }
                catch (UserNotFoundException e) {
                    // Do nothing
                }
            }

            // Keep a registry of the updated presences
222
            List<Presence> presences = new ArrayList<Presence>(jids.size());
Matt Tucker's avatar
Matt Tucker committed
223 224 225 226 227 228 229

            room.lock.readLock().lock();
            try {
                // Check if all the existing owners are being removed
                if (jids.keySet().containsAll(room.owners)) {
                    // Answer a conflict error if we are only removing ALL the owners
                    if (!jids.containsValue("owner")) {
230
                        throw new ConflictException();
Matt Tucker's avatar
Matt Tucker committed
231 232 233 234 235 236 237
                    }
                }

                room.lock.readLock().unlock();
                room.lock.writeLock().lock();
                try {
                    String targetAffiliation = null;
238 239 240
                    for (Iterator<String> it = jids.keySet().iterator(); it.hasNext();) {
                        bareJID = it.next();
                        targetAffiliation = jids.get(bareJID);
Matt Tucker's avatar
Matt Tucker committed
241 242 243 244 245 246 247 248 249 250
                        if ("owner".equals(targetAffiliation)) {
                            // Add the new user as an owner of the room
                            presences.addAll(room.addOwner(bareJID, senderRole));
                        }
                        else if ("admin".equals(targetAffiliation)) {
                            // Add the new user as an admin of the room
                            presences.addAll(room.addAdmin(bareJID, senderRole));
                        }
                        else if ("member".equals(targetAffiliation)) {
                            // Add the new user as a member of the room
Matt Tucker's avatar
Matt Tucker committed
251
                            boolean hadAffiliation = room.getAffiliation(bareJID) != MUCRole.Affiliation.none;
Matt Tucker's avatar
Matt Tucker committed
252
                            presences.addAll(room.addMember(bareJID, null, senderRole));
253 254
                            // If the user had an affiliation don't send an invitation. Otherwise
                            // send an invitation if the room is members-only
255
                            if (!hadAffiliation && room.isMembersOnly()) {
256
                                room.sendInvitation(new JID(bareJID), null, senderRole, null);
257
                            }
Matt Tucker's avatar
Matt Tucker committed
258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274
                        }
                        else if ("none".equals(targetAffiliation)) {
                            // Set that this jid has a NONE affiliation
                            presences.addAll(room.addNone(bareJID, senderRole));
                        }
                    }
                }
                finally {
                    room.lock.writeLock().unlock();
                    room.lock.readLock().lock();
                }
            }
            finally {
                room.lock.readLock().unlock();
            }

            // Send the updated presences to the room occupants
275 276
            for (Presence presence : presences) {
                room.send(presence);
Matt Tucker's avatar
Matt Tucker committed
277 278 279 280 281 282 283 284 285 286 287
            }
        }
    }

    /**
     * Handles packets that includes a data form. The data form was sent using an element with name
     * "x" and namespace "jabber:x:data".
     *
     * @param senderRole  the role of the user that sent the data form.
     * @param formElement the element that contains the data form specification.
     * @throws ForbiddenException    if the user does not have enough privileges.
288
     * @throws ConflictException If the room was going to lose all of its owners.
Matt Tucker's avatar
Matt Tucker committed
289
     */
290 291
    private void handleDataFormElement(MUCRole senderRole, Element formElement)
            throws ForbiddenException, ConflictException {
Matt Tucker's avatar
Matt Tucker committed
292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308
        XDataFormImpl completedForm = new XDataFormImpl();
        completedForm.parse(formElement);

        if (DataForm.TYPE_CANCEL.equals(completedForm.getType())) {
            // If the room was just created (i.e. is locked) and the owner cancels the configuration
            // form then destroy the room
            if (room.isLocked()) {
                room.destroyRoom(null, null);
            }
        }
        else if (DataForm.TYPE_SUBMIT.equals(completedForm.getType())) {
            // The owner is requesting an instant room
            if (completedForm.getFieldsSize() == 0) {
                // Do nothing
            }
            // The owner is requesting a reserved room or is changing the current configuration
            else {
309
                processConfigurationForm(completedForm, senderRole);
Matt Tucker's avatar
Matt Tucker committed
310 311 312
            }
            // If the room was locked, unlock it and send to the owner the "room is now unlocked"
            // message
313 314
            if (room.isLocked() && !room.isManuallyLocked()) {
                room.unlock(senderRole);
Matt Tucker's avatar
Matt Tucker committed
315 316 317 318
            }
        }
    }

319 320 321 322 323 324 325 326 327
    /**
     * Processes the completed form sent by an owner of the room. This will modify the room's
     * configuration as well as the list of owners and admins.
     *
     * @param completedForm the completed form sent by an owner of the room.
     * @param senderRole the role of the user that sent the completed form.
     * @throws ForbiddenException if the user does not have enough privileges.
     * @throws ConflictException If the room was going to lose all of its owners.
     */
328
    private void processConfigurationForm(XDataFormImpl completedForm, MUCRole senderRole)
Matt Tucker's avatar
Matt Tucker committed
329
            throws ForbiddenException, ConflictException {
330
        Iterator<String> values;
Matt Tucker's avatar
Matt Tucker committed
331
        String booleanValue;
332
        List<String> list;
Matt Tucker's avatar
Matt Tucker committed
333 334 335
        FormField field;

        // Get the new list of admins
336
        field = completedForm.getField("muc#roomconfig_roomadmins");
337
        boolean adminsSent = field != null;
338
        List<String> admins = new ArrayList<String>();
Matt Tucker's avatar
Matt Tucker committed
339 340 341 342 343 344 345 346
        if (field != null) {
            values = field.getValues();
            while (values.hasNext()) {
                admins.add(values.next());
            }
        }

        // Get the new list of owners
347
        field = completedForm.getField("muc#roomconfig_roomowners");
348
        boolean ownersSent = field != null;
349
        List<String> owners = new ArrayList<String>();
Matt Tucker's avatar
Matt Tucker committed
350 351 352 353 354 355 356 357
        if (field != null) {
            values = field.getValues();
            while (values.hasNext()) {
                owners.add(values.next());
            }
        }

        // Answer a conflic error if all the current owners will be removed
358
        if (ownersSent && owners.isEmpty()) {
359
            throw new ConflictException();
Matt Tucker's avatar
Matt Tucker committed
360 361 362 363 364 365 366
        }

        // Keep a registry of the updated presences
        List presences = new ArrayList(admins.size() + owners.size());

        room.lock.writeLock().lock();
        try {
367
            field = completedForm.getField("muc#roomconfig_roomname");
Matt Tucker's avatar
Matt Tucker committed
368 369
            if (field != null) {
                values = field.getValues();
370
                room.setNaturalLanguageName((values.hasNext() ? values.next() : " "));
Matt Tucker's avatar
Matt Tucker committed
371 372
            }

373
            field = completedForm.getField("muc#roomconfig_roomdesc");
Matt Tucker's avatar
Matt Tucker committed
374 375
            if (field != null) {
                values = field.getValues();
376
                room.setDescription((values.hasNext() ? values.next() : " "));
Matt Tucker's avatar
Matt Tucker committed
377 378
            }

379
            field = completedForm.getField("muc#roomconfig_changesubject");
Matt Tucker's avatar
Matt Tucker committed
380 381
            if (field != null) {
                values = field.getValues();
382
                booleanValue = (values.hasNext() ? values.next() : "1");
Matt Tucker's avatar
Matt Tucker committed
383 384 385
                room.setCanOccupantsChangeSubject(("1".equals(booleanValue) ? true : false));
            }

386
            field = completedForm.getField("muc#roomconfig_maxusers");
Matt Tucker's avatar
Matt Tucker committed
387 388
            if (field != null) {
                values = field.getValues();
389
                room.setMaxUsers((values.hasNext() ? Integer.parseInt(values.next()) : 30));
Matt Tucker's avatar
Matt Tucker committed
390 391
            }

392
            field = completedForm.getField("muc#roomconfig_presencebroadcast");
Matt Tucker's avatar
Matt Tucker committed
393 394
            if (field != null) {
                values = field.getValues();
395
                list = new ArrayList<String>();
Matt Tucker's avatar
Matt Tucker committed
396 397 398 399 400 401
                while (values.hasNext()) {
                    list.add(values.next());
                }
                room.setRolesToBroadcastPresence(list);
            }

402
            field = completedForm.getField("muc#roomconfig_publicroom");
Matt Tucker's avatar
Matt Tucker committed
403 404
            if (field != null) {
                values = field.getValues();
405
                booleanValue = (values.hasNext() ? values.next() : "1");
Matt Tucker's avatar
Matt Tucker committed
406 407 408
                room.setPublicRoom(("1".equals(booleanValue) ? true : false));
            }

409
            field = completedForm.getField("muc#roomconfig_persistentroom");
Matt Tucker's avatar
Matt Tucker committed
410 411
            if (field != null) {
                values = field.getValues();
412
                booleanValue = (values.hasNext() ? values.next() : "1");
Matt Tucker's avatar
Matt Tucker committed
413 414 415 416 417 418 419 420
                boolean isPersistent = ("1".equals(booleanValue) ? true : false);
                // Delete the room from the DB if it's no longer persistent
                if (room.isPersistent() && !isPersistent) {
                    MUCPersistenceManager.deleteFromDB(room);
                }
                room.setPersistent(isPersistent);
            }

421
            field = completedForm.getField("muc#roomconfig_moderatedroom");
Matt Tucker's avatar
Matt Tucker committed
422 423
            if (field != null) {
                values = field.getValues();
424
                booleanValue = (values.hasNext() ? values.next() : "1");
Matt Tucker's avatar
Matt Tucker committed
425 426 427
                room.setModerated(("1".equals(booleanValue) ? true : false));
            }

428
            field = completedForm.getField("muc#roomconfig_membersonly");
Matt Tucker's avatar
Matt Tucker committed
429 430
            if (field != null) {
                values = field.getValues();
431
                booleanValue = (values.hasNext() ? values.next() : "1");
432
                presences.addAll(room.setMembersOnly(("1".equals(booleanValue) ?
433
                        true : false)));
Matt Tucker's avatar
Matt Tucker committed
434 435
            }

436
            field = completedForm.getField("muc#roomconfig_allowinvites");
Matt Tucker's avatar
Matt Tucker committed
437 438
            if (field != null) {
                values = field.getValues();
439
                booleanValue = (values.hasNext() ? values.next() : "1");
Matt Tucker's avatar
Matt Tucker committed
440 441 442
                room.setCanOccupantsInvite(("1".equals(booleanValue) ? true : false));
            }

443
            field = completedForm.getField("muc#roomconfig_passwordprotectedroom");
Matt Tucker's avatar
Matt Tucker committed
444 445
            if (field != null) {
                values = field.getValues();
446
                booleanValue = (values.hasNext() ? values.next() : "1");
447 448 449
                boolean isPasswordProtected = "1".equals(booleanValue);
                if (isPasswordProtected) {
                    // The room is password protected so set the new password
450
                    field = completedForm.getField("muc#roomconfig_roomsecret");
451
                    if (field != null) {
452
                        values = completedForm.getField("muc#roomconfig_roomsecret").getValues();
453
                        room.setPassword((values.hasNext() ? values.next() : null));
454 455 456 457 458 459
                    }
                }
                else {
                    // The room is not password protected so remove any previous password
                    room.setPassword(null);
                }
Matt Tucker's avatar
Matt Tucker committed
460 461
            }

462
            field = completedForm.getField("muc#roomconfig_whois");
Matt Tucker's avatar
Matt Tucker committed
463 464
            if (field != null) {
                values = field.getValues();
465
                booleanValue = (values.hasNext() ? values.next() : "1");
Matt Tucker's avatar
Matt Tucker committed
466 467 468
                room.setCanAnyoneDiscoverJID(("anyone".equals(booleanValue) ? true : false));
            }

469
            field = completedForm.getField("muc#roomconfig_enablelogging");
Matt Tucker's avatar
Matt Tucker committed
470 471
            if (field != null) {
                values = field.getValues();
472
                booleanValue = (values.hasNext() ? values.next() : "1");
Matt Tucker's avatar
Matt Tucker committed
473 474
                room.setLogEnabled(("1".equals(booleanValue) ? true : false));
            }
475 476 477 478 479

            // Update the modification date to reflect the last time when the room's configuration
            // was modified
            room.setModificationDate(new Date());

Matt Tucker's avatar
Matt Tucker committed
480 481 482 483 484 485 486 487
            if (room.isPersistent()) {
                room.saveToDB();
            }

            // Set the new owners and admins of the room
            presences.addAll(room.addOwners(owners, senderRole));
            presences.addAll(room.addAdmins(admins, senderRole));

488 489 490 491 492 493 494 495 496
            if (ownersSent) {
                // Change the affiliation to "member" for the current owners that won't be neither
                // owner nor admin (if the form included the owners field)
                List<String> ownersToRemove = new ArrayList<String>(room.owners);
                ownersToRemove.removeAll(admins);
                ownersToRemove.removeAll(owners);
                for (String jid : ownersToRemove) {
                    presences.addAll(room.addMember(jid, null, senderRole));
                }
Matt Tucker's avatar
Matt Tucker committed
497 498
            }

499 500 501 502 503 504 505 506 507
            if (adminsSent) {
                // Change the affiliation to "member" for the current admins that won't be neither
                // owner nor admin (if the form included the admins field)
                List<String> adminsToRemove = new ArrayList<String>(room.admins);
                adminsToRemove.removeAll(admins);
                adminsToRemove.removeAll(owners);
                for (String jid : adminsToRemove) {
                    presences.addAll(room.addMember(jid, null, senderRole));
                }
Matt Tucker's avatar
Matt Tucker committed
508 509
            }

510 511 512
            // Destroy the room if the room is no longer persistent and there are no occupants in
            // the room
            if (!room.isPersistent() && room.getOccupantsCount() == 0) {
513
                room.destroyRoom(null, null);
514 515
            }

Matt Tucker's avatar
Matt Tucker committed
516 517 518 519 520 521
        }
        finally {
            room.lock.writeLock().unlock();
        }

        // Send the updated presences to the room occupants
522 523
        for (Iterator it = presences.iterator(); it.hasNext();) {
            room.send((Presence)it.next());
Matt Tucker's avatar
Matt Tucker committed
524 525 526 527 528 529
        }
    }

    private void refreshConfigurationFormValues() {
        room.lock.readLock().lock();
        try {
530
            FormField field = configurationForm.getField("muc#roomconfig_roomname");
Matt Tucker's avatar
Matt Tucker committed
531
            field.clearValues();
532
            field.addValue(room.getNaturalLanguageName());
Matt Tucker's avatar
Matt Tucker committed
533

534
            field = configurationForm.getField("muc#roomconfig_roomdesc");
Matt Tucker's avatar
Matt Tucker committed
535 536 537
            field.clearValues();
            field.addValue(room.getDescription());

538
            field = configurationForm.getField("muc#roomconfig_changesubject");
Matt Tucker's avatar
Matt Tucker committed
539 540 541
            field.clearValues();
            field.addValue((room.canOccupantsChangeSubject() ? "1" : "0"));

542
            field = configurationForm.getField("muc#roomconfig_maxusers");
Matt Tucker's avatar
Matt Tucker committed
543 544 545
            field.clearValues();
            field.addValue(Integer.toString(room.getMaxUsers()));

546
            field = configurationForm.getField("muc#roomconfig_presencebroadcast");
Matt Tucker's avatar
Matt Tucker committed
547
            field.clearValues();
548 549
            for (String roleToBroadcast : room.getRolesToBroadcastPresence()) {
                field.addValue(roleToBroadcast);
Matt Tucker's avatar
Matt Tucker committed
550 551
            }

552
            field = configurationForm.getField("muc#roomconfig_publicroom");
Matt Tucker's avatar
Matt Tucker committed
553 554 555
            field.clearValues();
            field.addValue((room.isPublicRoom() ? "1" : "0"));

556
            field = configurationForm.getField("muc#roomconfig_persistentroom");
Matt Tucker's avatar
Matt Tucker committed
557 558 559
            field.clearValues();
            field.addValue((room.isPersistent() ? "1" : "0"));

560
            field = configurationForm.getField("muc#roomconfig_moderatedroom");
Matt Tucker's avatar
Matt Tucker committed
561 562 563
            field.clearValues();
            field.addValue((room.isModerated() ? "1" : "0"));

564
            field = configurationForm.getField("muc#roomconfig_membersonly");
Matt Tucker's avatar
Matt Tucker committed
565
            field.clearValues();
566
            field.addValue((room.isMembersOnly() ? "1" : "0"));
Matt Tucker's avatar
Matt Tucker committed
567

568
            field = configurationForm.getField("muc#roomconfig_allowinvites");
Matt Tucker's avatar
Matt Tucker committed
569 570 571
            field.clearValues();
            field.addValue((room.canOccupantsInvite() ? "1" : "0"));

572
            field = configurationForm.getField("muc#roomconfig_passwordprotectedroom");
Matt Tucker's avatar
Matt Tucker committed
573 574 575
            field.clearValues();
            field.addValue((room.isPasswordProtected() ? "1" : "0"));

576
            field = configurationForm.getField("muc#roomconfig_roomsecret");
Matt Tucker's avatar
Matt Tucker committed
577 578 579
            field.clearValues();
            field.addValue(room.getPassword());

580
            field = configurationForm.getField("muc#roomconfig_whois");
Matt Tucker's avatar
Matt Tucker committed
581 582 583
            field.clearValues();
            field.addValue((room.canAnyoneDiscoverJID() ? "anyone" : "moderators"));

584
            field = configurationForm.getField("muc#roomconfig_enablelogging");
Matt Tucker's avatar
Matt Tucker committed
585 586 587
            field.clearValues();
            field.addValue((room.isLogEnabled() ? "1" : "0"));

588
            field = configurationForm.getField("muc#roomconfig_roomadmins");
Matt Tucker's avatar
Matt Tucker committed
589
            field.clearValues();
590 591
            for (String jid : room.getAdmins()) {
                field.addValue(jid);
Matt Tucker's avatar
Matt Tucker committed
592 593
            }

594
            field = configurationForm.getField("muc#roomconfig_roomowners");
Matt Tucker's avatar
Matt Tucker committed
595
            field.clearValues();
596 597
            for (String jid : room.getOwners()) {
                field.addValue(jid);
Matt Tucker's avatar
Matt Tucker committed
598
            }
Gaston Dombiak's avatar
Gaston Dombiak committed
599 600 601 602 603 604

            // Remove the old element
            probeResult.remove(probeResult.element(QName.get("x", "jabber:x:data")));
            // Add the new representation of configurationForm as an element 
            probeResult.add(configurationForm.asXMLElement());

Matt Tucker's avatar
Matt Tucker committed
605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
        }
        finally {
            room.lock.readLock().unlock();
        }
    }

    private void init() {
        Element element = DocumentHelper.createElement(QName.get("query",
                "http://jabber.org/protocol/muc#owner"));

        configurationForm = new XDataFormImpl(DataForm.TYPE_FORM);
        configurationForm.setTitle(LocaleUtils.getLocalizedString("muc.form.conf.title"));
        List params = new ArrayList();
        params.add(room.getName());
        configurationForm.addInstruction(LocaleUtils.getLocalizedString("muc.form.conf.instruction", params));

        XFormFieldImpl field = new XFormFieldImpl("FORM_TYPE");
        field.setType(FormField.TYPE_HIDDEN);
623
        field.addValue("http://jabber.org/protocol/muc#roomconfig");
Matt Tucker's avatar
Matt Tucker committed
624 625
        configurationForm.addField(field);

626
        field = new XFormFieldImpl("muc#roomconfig_roomname");
Matt Tucker's avatar
Matt Tucker committed
627 628 629 630
        field.setType(FormField.TYPE_TEXT_SINGLE);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_roomname"));
        configurationForm.addField(field);

631
        field = new XFormFieldImpl("muc#roomconfig_roomdesc");
Matt Tucker's avatar
Matt Tucker committed
632 633 634 635
        field.setType(FormField.TYPE_TEXT_SINGLE);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_roomdesc"));
        configurationForm.addField(field);

636
        field = new XFormFieldImpl("muc#roomconfig_changesubject");
Matt Tucker's avatar
Matt Tucker committed
637 638 639 640
        field.setType(FormField.TYPE_BOOLEAN);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_changesubject"));
        configurationForm.addField(field);

641
        field = new XFormFieldImpl("muc#roomconfig_maxusers");
Matt Tucker's avatar
Matt Tucker committed
642 643 644 645 646 647 648 649 650 651
        field.setType(FormField.TYPE_LIST_SINGLE);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_maxusers"));
        field.addOption("10", "10");
        field.addOption("20", "20");
        field.addOption("30", "30");
        field.addOption("40", "40");
        field.addOption("50", "50");
        field.addOption(LocaleUtils.getLocalizedString("muc.form.conf.none"), "0");
        configurationForm.addField(field);

652
        field = new XFormFieldImpl("muc#roomconfig_presencebroadcast");
Matt Tucker's avatar
Matt Tucker committed
653 654 655 656 657 658 659
        field.setType(FormField.TYPE_LIST_MULTI);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_presencebroadcast"));
        field.addOption(LocaleUtils.getLocalizedString("muc.form.conf.moderator"), "moderator");
        field.addOption(LocaleUtils.getLocalizedString("muc.form.conf.participant"), "participant");
        field.addOption(LocaleUtils.getLocalizedString("muc.form.conf.visitor"), "visitor");
        configurationForm.addField(field);

660
        field = new XFormFieldImpl("muc#roomconfig_publicroom");
Matt Tucker's avatar
Matt Tucker committed
661 662 663 664
        field.setType(FormField.TYPE_BOOLEAN);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_publicroom"));
        configurationForm.addField(field);

665
        field = new XFormFieldImpl("muc#roomconfig_persistentroom");
Matt Tucker's avatar
Matt Tucker committed
666 667 668 669
        field.setType(FormField.TYPE_BOOLEAN);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_persistentroom"));
        configurationForm.addField(field);

670
        field = new XFormFieldImpl("muc#roomconfig_moderatedroom");
Matt Tucker's avatar
Matt Tucker committed
671 672 673 674
        field.setType(FormField.TYPE_BOOLEAN);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_moderatedroom"));
        configurationForm.addField(field);

675
        field = new XFormFieldImpl("muc#roomconfig_membersonly");
Matt Tucker's avatar
Matt Tucker committed
676
        field.setType(FormField.TYPE_BOOLEAN);
677
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_membersonly"));
Matt Tucker's avatar
Matt Tucker committed
678 679 680 681 682 683 684
        configurationForm.addField(field);

        field = new XFormFieldImpl();
        field.setType(FormField.TYPE_FIXED);
        field.addValue(LocaleUtils.getLocalizedString("muc.form.conf.allowinvitesfixed"));
        configurationForm.addField(field);

685
        field = new XFormFieldImpl("muc#roomconfig_allowinvites");
Matt Tucker's avatar
Matt Tucker committed
686 687 688 689
        field.setType(FormField.TYPE_BOOLEAN);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_allowinvites"));
        configurationForm.addField(field);

690
        field = new XFormFieldImpl("muc#roomconfig_passwordprotectedroom");
Matt Tucker's avatar
Matt Tucker committed
691 692 693 694 695 696 697 698 699
        field.setType(FormField.TYPE_BOOLEAN);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_passwordprotectedroom"));
        configurationForm.addField(field);

        field = new XFormFieldImpl();
        field.setType(FormField.TYPE_FIXED);
        field.addValue(LocaleUtils.getLocalizedString("muc.form.conf.roomsecretfixed"));
        configurationForm.addField(field);

700
        field = new XFormFieldImpl("muc#roomconfig_roomsecret");
Matt Tucker's avatar
Matt Tucker committed
701 702 703 704
        field.setType(FormField.TYPE_TEXT_PRIVATE);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_roomsecret"));
        configurationForm.addField(field);

705
        field = new XFormFieldImpl("muc#roomconfig_whois");
Matt Tucker's avatar
Matt Tucker committed
706 707 708 709 710 711
        field.setType(FormField.TYPE_LIST_SINGLE);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_whois"));
        field.addOption(LocaleUtils.getLocalizedString("muc.form.conf.moderator"), "moderators");
        field.addOption(LocaleUtils.getLocalizedString("muc.form.conf.anyone"), "anyone");
        configurationForm.addField(field);

712
        field = new XFormFieldImpl("muc#roomconfig_enablelogging");
Matt Tucker's avatar
Matt Tucker committed
713 714 715 716 717 718 719 720 721
        field.setType(FormField.TYPE_BOOLEAN);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_enablelogging"));
        configurationForm.addField(field);

        field = new XFormFieldImpl();
        field.setType(FormField.TYPE_FIXED);
        field.addValue(LocaleUtils.getLocalizedString("muc.form.conf.roomadminsfixed"));
        configurationForm.addField(field);

722
        field = new XFormFieldImpl("muc#roomconfig_roomadmins");
Matt Tucker's avatar
Matt Tucker committed
723 724 725 726 727 728 729 730 731
        field.setType(FormField.TYPE_JID_MULTI);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_roomadmins"));
        configurationForm.addField(field);

        field = new XFormFieldImpl();
        field.setType(FormField.TYPE_FIXED);
        field.addValue(LocaleUtils.getLocalizedString("muc.form.conf.roomownersfixed"));
        configurationForm.addField(field);

732
        field = new XFormFieldImpl("muc#roomconfig_roomowners");
Matt Tucker's avatar
Matt Tucker committed
733 734 735 736 737
        field.setType(FormField.TYPE_JID_MULTI);
        field.setLabel(LocaleUtils.getLocalizedString("muc.form.conf.owner_roomowners"));
        configurationForm.addField(field);

        // Create the probeResult and add the basic info together with the configuration form
Derek DeMoro's avatar
Derek DeMoro committed
738 739
        probeResult = element;
        probeResult.add(configurationForm.asXMLElement());
Matt Tucker's avatar
Matt Tucker committed
740 741
    }
}