1 /* 2 * Copyright (C) 2004-2008 Jive Software. All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package org.jivesoftware.openfire.muc.spi; 18 19 import java.util.ArrayList; 20 import java.util.List; 21 import java.util.concurrent.locks.Lock; 22 23 import org.dom4j.DocumentHelper; 24 import org.dom4j.Element; 25 import org.dom4j.QName; 26 import org.jivesoftware.openfire.muc.ConflictException; 27 import org.jivesoftware.openfire.muc.ForbiddenException; 28 import org.jivesoftware.openfire.muc.MUCRole; 29 import org.jivesoftware.openfire.muc.MUCRoom; 30 import org.jivesoftware.openfire.muc.MultiUserChatService; 31 import org.jivesoftware.util.ElementUtil; 32 import org.jivesoftware.util.LocaleUtils; 33 import org.slf4j.Logger; 34 import org.slf4j.LoggerFactory; 35 import org.xmpp.forms.DataForm; 36 import org.xmpp.forms.FormField; 37 import org.xmpp.packet.IQ; 38 import org.xmpp.packet.PacketError; 39 import org.xmpp.packet.Presence; 40 41 /** 42 * This class is responsible for handling packets with namespace jabber:iq:register that were 43 * sent to the MUC service. MultiUserChatServer will receive all the IQ packets and if the 44 * namespace of the IQ is jabber:iq:register then this class will handle the packet. 45 * 46 * @author Gaston Dombiak 47 */ 48 class IQMUCRegisterHandler { 49 50 private static final Logger Log = LoggerFactory.getLogger(IQMUCRegisterHandler.class); 51 52 private static final Element probeResult; 53 54 static { 55 // Create the registration form of the room which contains information 56 // such as: first name, last name and nickname. 57 final DataForm registrationForm = new DataForm(DataForm.Type.form); 58 registrationForm.setTitle(LocaleUtils.getLocalizedString("muc.form.reg.title")); registrationForm.addInstruction(LocaleUtils .getLocalizedString(R))59 registrationForm.addInstruction(LocaleUtils 60 .getLocalizedString("muc.form.reg.instruction")); 61 62 final FormField fieldForm = registrationForm.addField(); 63 fieldForm.setVariable("FORM_TYPE"); 64 fieldForm.setType(FormField.Type.hidden); 65 fieldForm.addValue("http://jabber.org/protocol/muc#register"); 66 67 final FormField fieldReg = registrationForm.addField(); 68 fieldReg.setVariable("muc#register_first"); 69 fieldReg.setType(FormField.Type.text_single); 70 fieldReg.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.first-name")); 71 fieldReg.setRequired(true); 72 73 final FormField fieldLast = registrationForm.addField(); 74 fieldLast.setVariable("muc#register_last"); 75 fieldLast.setType(FormField.Type.text_single); 76 fieldLast.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.last-name")); 77 fieldLast.setRequired(true); 78 79 final FormField fieldNick = registrationForm.addField(); 80 fieldNick.setVariable("muc#register_roomnick"); 81 fieldNick.setType(FormField.Type.text_single); 82 fieldNick.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.nickname")); 83 fieldNick.setRequired(true); 84 85 final FormField fieldUrl = registrationForm.addField(); 86 fieldUrl.setVariable("muc#register_url"); 87 fieldUrl.setType(FormField.Type.text_single); 88 fieldUrl.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.url")); 89 90 final FormField fieldMail = registrationForm.addField(); 91 fieldMail.setVariable("muc#register_email"); 92 fieldMail.setType(FormField.Type.text_single); 93 fieldMail.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.email")); 94 95 final FormField fieldFaq = registrationForm.addField(); 96 fieldFaq.setVariable("muc#register_faqentry"); 97 fieldFaq.setType(FormField.Type.text_single); 98 fieldFaq.setLabel(LocaleUtils.getLocalizedString("muc.form.reg.faqentry")); 99 100 // Create the probeResult and add the registration form 101 probeResult = DocumentHelper.createElement(QName.get("query", "jabber:iq:register")); registrationForm.getElement()102 probeResult.add(registrationForm.getElement()); 103 } 104 105 private final MultiUserChatService mucService; 106 IQMUCRegisterHandler(MultiUserChatService mucService)107 public IQMUCRegisterHandler(MultiUserChatService mucService) { 108 this.mucService = mucService; 109 } 110 handleIQ(IQ packet)111 public IQ handleIQ(IQ packet) { 112 IQ reply = null; 113 // Get the target room 114 MUCRoom room = null; 115 String name = packet.getTo().getNode(); 116 if (name == null) { 117 // Can't register with the service itself, so answer a feature-not-implemented error 118 reply = IQ.createResultIQ(packet); 119 reply.setChildElement(packet.getChildElement().createCopy()); 120 reply.setError(PacketError.Condition.feature_not_implemented); 121 return reply; 122 } 123 124 final Lock lock = mucService.getChatRoomLock(name); 125 lock.lock(); 126 try { 127 room = mucService.getChatRoom(name); 128 if (room == null) { 129 // The room doesn't exist so answer a NOT_FOUND error 130 reply = IQ.createResultIQ(packet); 131 reply.setChildElement(packet.getChildElement().createCopy()); 132 reply.setError(PacketError.Condition.item_not_found); 133 return reply; 134 } 135 else if (!room.isRegistrationEnabled() || 136 (packet.getFrom() != null && 137 MUCRole.Affiliation.outcast == room.getAffiliation(packet.getFrom().asBareJID()))) { 138 // The room does not accept users to register or 139 // the user is an outcast and is not allowed to register 140 reply = IQ.createResultIQ(packet); 141 reply.setChildElement(packet.getChildElement().createCopy()); 142 reply.setError(PacketError.Condition.not_allowed); 143 return reply; 144 } 145 146 if (IQ.Type.get == packet.getType()) { 147 reply = IQ.createResultIQ(packet); 148 String nickname = room.getReservedNickname(packet.getFrom()); 149 Element currentRegistration = probeResult.createCopy(); 150 if (nickname != null) { 151 // The user is already registered with the room so answer a completed form 152 ElementUtil.setProperty(currentRegistration, "query.registered", null); 153 currentRegistration.addElement("username").addText(nickname); 154 155 Element form = currentRegistration.element(QName.get("x", "jabber:x:data")); 156 currentRegistration.remove(form); 157 // @SuppressWarnings("unchecked") 158 // Iterator<Element> fields = form.elementIterator("field"); 159 // 160 // Element field; 161 // while (fields.hasNext()) { 162 // field = fields.next(); 163 // if ("muc#register_roomnick".equals(field.attributeValue("var"))) { 164 // field.addElement("value").addText(nickname); 165 // } 166 // } 167 reply.setChildElement(currentRegistration); 168 } 169 else { 170 // The user is not registered with the room so answer an empty form 171 reply.setChildElement(currentRegistration); 172 } 173 } 174 else if (IQ.Type.set == packet.getType()) { 175 try { 176 // Keep a registry of the updated presences 177 List<Presence> presences = new ArrayList<>(); 178 179 reply = IQ.createResultIQ(packet); 180 Element iq = packet.getChildElement(); 181 182 if (ElementUtil.includesProperty(iq, "query.remove")) { 183 // The user is deleting his registration 184 presences.addAll(room.addNone(packet.getFrom(), room.getRole())); 185 } 186 else { 187 // The user is trying to register with a room 188 Element formElement = iq.element("x"); 189 // Check if a form was used to provide the registration info 190 if (formElement != null) { 191 // Get the sent form 192 final DataForm registrationForm = new DataForm(formElement); 193 // Get the desired nickname sent in the form 194 List<String> values = registrationForm.getField("muc#register_roomnick") 195 .getValues(); 196 String nickname = (!values.isEmpty() ? values.get(0) : null); 197 198 // TODO The rest of the fields of the form are ignored. If we have a 199 // requirement in the future where we need those fields we'll have to change 200 // MUCRoom.addMember in order to receive a RegistrationInfo (new class) 201 202 // Add the new member to the members list 203 presences.addAll(room.addMember(packet.getFrom(), 204 nickname, 205 room.getRole())); 206 } 207 else { 208 reply.setChildElement(packet.getChildElement().createCopy()); 209 reply.setError(PacketError.Condition.bad_request); 210 } 211 } 212 // Send the updated presences to the room occupants 213 for (Presence presence : presences) { 214 room.send(presence, room.getRole()); 215 } 216 217 } 218 catch (ForbiddenException e) { 219 reply = IQ.createResultIQ(packet); 220 reply.setChildElement(packet.getChildElement().createCopy()); 221 reply.setError(PacketError.Condition.forbidden); 222 } 223 catch (ConflictException e) { 224 reply = IQ.createResultIQ(packet); 225 reply.setChildElement(packet.getChildElement().createCopy()); 226 reply.setError(PacketError.Condition.conflict); 227 } 228 catch (Exception e) { 229 Log.error(e.getMessage(), e); 230 } 231 } 232 233 // Ensure that other cluster nodes see the changes applied above. 234 mucService.syncChatRoom(room); 235 } finally { 236 lock.unlock(); 237 } 238 return reply; 239 } 240 } 241