001/** 002 * 003 * Copyright 2003-2007 Jive Software. 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 018package org.jivesoftware.smackx.muc.packet; 019 020import java.util.HashMap; 021import java.util.HashSet; 022import java.util.Map; 023import java.util.Set; 024 025import org.jivesoftware.smack.packet.ExtensionElement; 026import org.jivesoftware.smack.packet.NamedElement; 027import org.jivesoftware.smack.packet.Stanza; 028import org.jivesoftware.smack.util.XmlStringBuilder; 029 030import org.jxmpp.jid.EntityBareJid; 031import org.jxmpp.jid.EntityFullJid; 032import org.jxmpp.jid.EntityJid; 033 034/** 035 * Represents extended presence information about roles, affiliations, full JIDs, 036 * or status codes scoped by the 'http://jabber.org/protocol/muc#user' namespace. 037 * 038 * @author Gaston Dombiak 039 */ 040public class MUCUser implements ExtensionElement { 041 042 public static final String ELEMENT = "x"; 043 public static final String NAMESPACE = MUCInitialPresence.NAMESPACE + "#user"; 044 045 private final Set<Status> statusCodes = new HashSet<>(4); 046 047 private Invite invite; 048 private Decline decline; 049 private MUCItem item; 050 private String password; 051 private Destroy destroy; 052 053 @Override 054 public String getElementName() { 055 return ELEMENT; 056 } 057 058 @Override 059 public String getNamespace() { 060 return NAMESPACE; 061 } 062 063 @Override 064 public XmlStringBuilder toXML(String enclosingNamespace) { 065 XmlStringBuilder xml = new XmlStringBuilder(this); 066 xml.rightAngleBracket(); 067 xml.optElement(getInvite()); 068 xml.optElement(getDecline()); 069 xml.optElement(getItem()); 070 xml.optElement("password", getPassword()); 071 xml.append(statusCodes); 072 xml.optElement(getDestroy()); 073 xml.closeElement(this); 074 return xml; 075 } 076 077 /** 078 * Returns the invitation for another user to a room. The sender of the invitation 079 * must be an occupant of the room. The invitation will be sent to the room which in turn 080 * will forward the invitation to the invitee. 081 * 082 * @return an invitation for another user to a room. 083 */ 084 public Invite getInvite() { 085 return invite; 086 } 087 088 /** 089 * Returns the rejection to an invitation from another user to a room. The rejection will be 090 * sent to the room which in turn will forward the refusal to the inviting user. 091 * 092 * @return a rejection to an invitation from another user to a room. 093 */ 094 public Decline getDecline() { 095 return decline; 096 } 097 098 /** 099 * Returns the item child that holds information about roles, affiliation, jids and nicks. 100 * 101 * @return an item child that holds information about roles, affiliation, jids and nicks. 102 */ 103 public MUCItem getItem() { 104 return item; 105 } 106 107 /** 108 * Returns the password to use to enter Password-Protected Room. A Password-Protected Room is 109 * a room that a user cannot enter without first providing the correct password. 110 * 111 * @return the password to use to enter Password-Protected Room. 112 */ 113 public String getPassword() { 114 return password; 115 } 116 117 /** 118 * Returns a set of status which holds the status code that assist in presenting notification messages. 119 * 120 * @return the set of status which holds the status code that assist in presenting notification messages. 121 */ 122 public Set<Status> getStatus() { 123 return statusCodes; 124 } 125 126 /** 127 * Returns true if this MUCUser instance has also {@link Status} information. 128 * <p> 129 * If <code>true</code> is returned, then {@link #getStatus()} will return a non-empty set. 130 * </p> 131 * 132 * @return true if this MUCUser has status information. 133 * @since 4.1 134 */ 135 public boolean hasStatus() { 136 return !statusCodes.isEmpty(); 137 } 138 139 /** 140 * Returns the notification that the room has been destroyed. After a room has been destroyed, 141 * the room occupants will receive a Presence stanza of type 'unavailable' with the reason for 142 * the room destruction if provided by the room owner. 143 * 144 * @return a notification that the room has been destroyed. 145 */ 146 public Destroy getDestroy() { 147 return destroy; 148 } 149 150 /** 151 * Sets the invitation for another user to a room. The sender of the invitation 152 * must be an occupant of the room. The invitation will be sent to the room which in turn 153 * will forward the invitation to the invitee. 154 * 155 * @param invite the invitation for another user to a room. 156 */ 157 public void setInvite(Invite invite) { 158 this.invite = invite; 159 } 160 161 /** 162 * Sets the rejection to an invitation from another user to a room. The rejection will be 163 * sent to the room which in turn will forward the refusal to the inviting user. 164 * 165 * @param decline the rejection to an invitation from another user to a room. 166 */ 167 public void setDecline(Decline decline) { 168 this.decline = decline; 169 } 170 171 /** 172 * Sets the item child that holds information about roles, affiliation, jids and nicks. 173 * 174 * @param item the item child that holds information about roles, affiliation, jids and nicks. 175 */ 176 public void setItem(MUCItem item) { 177 this.item = item; 178 } 179 180 /** 181 * Sets the password to use to enter Password-Protected Room. A Password-Protected Room is 182 * a room that a user cannot enter without first providing the correct password. 183 * 184 * @param string the password to use to enter Password-Protected Room. 185 */ 186 public void setPassword(String string) { 187 password = string; 188 } 189 190 /** 191 * Add the status codes which holds the codes that assists in presenting notification messages. 192 * 193 * @param statusCodes the status codes which hold the codes that assists in presenting notification 194 * messages. 195 */ 196 public void addStatusCodes(Set<Status> statusCodes) { 197 this.statusCodes.addAll(statusCodes); 198 } 199 200 /** 201 * Add a status code which hold a code that assists in presenting notification messages. 202 * 203 * @param status the status code which olds a code that assists in presenting notification messages. 204 */ 205 public void addStatusCode(Status status) { 206 this.statusCodes.add(status); 207 } 208 209 /** 210 * Sets the notification that the room has been destroyed. After a room has been destroyed, 211 * the room occupants will receive a Presence stanza of type 'unavailable' with the reason for 212 * the room destruction if provided by the room owner. 213 * 214 * @param destroy the notification that the room has been destroyed. 215 */ 216 public void setDestroy(Destroy destroy) { 217 this.destroy = destroy; 218 } 219 220 /** 221 * Retrieve the MUCUser PacketExtension from packet, if any. 222 * 223 * @param packet 224 * @return the MUCUser PacketExtension or {@code null} 225 * @deprecated use {@link #from(Stanza)} instead 226 */ 227 @Deprecated 228 public static MUCUser getFrom(Stanza packet) { 229 return from(packet); 230 } 231 232 /** 233 * Retrieve the MUCUser PacketExtension from packet, if any. 234 * 235 * @param packet 236 * @return the MUCUser PacketExtension or {@code null} 237 */ 238 public static MUCUser from(Stanza packet) { 239 return packet.getExtension(ELEMENT, NAMESPACE); 240 } 241 242 /** 243 * Represents an invitation for another user to a room. The sender of the invitation 244 * must be an occupant of the room. The invitation will be sent to the room which in turn 245 * will forward the invitation to the invitee. 246 * 247 * @author Gaston Dombiak 248 */ 249 public static class Invite implements NamedElement { 250 public static final String ELEMENT = "invite"; 251 252 private final String reason; 253 254 /** 255 * From XEP-0045 § 7.8.2: "… whose value is the bare JID, full JID, or occupant JID of the inviting user …" 256 */ 257 private final EntityJid from; 258 259 private final EntityBareJid to; 260 261 public Invite(String reason, EntityFullJid from) { 262 this(reason, from, null); 263 } 264 265 public Invite(String reason, EntityBareJid to) { 266 this(reason, null, to); 267 } 268 269 public Invite(String reason, EntityJid from, EntityBareJid to) { 270 this.reason = reason; 271 this.from = from; 272 this.to = to; 273 } 274 275 /** 276 * Returns the bare JID of the inviting user or, optionally, the room JID. (e.g. 277 * 'crone1@shakespeare.lit/desktop'). 278 * 279 * @return the room's occupant that sent the invitation. 280 */ 281 public EntityJid getFrom() { 282 return from; 283 } 284 285 /** 286 * Returns the message explaining the invitation. 287 * 288 * @return the message explaining the invitation. 289 */ 290 public String getReason() { 291 return reason; 292 } 293 294 /** 295 * Returns the bare JID of the invitee. (e.g. 'hecate@shakespeare.lit') 296 * 297 * @return the bare JID of the invitee. 298 */ 299 public EntityBareJid getTo() { 300 return to; 301 } 302 303 @Override 304 public XmlStringBuilder toXML(String enclosingNamespace) { 305 XmlStringBuilder xml = new XmlStringBuilder(this); 306 xml.optAttribute("to", getTo()); 307 xml.optAttribute("from", getFrom()); 308 xml.rightAngleBracket(); 309 xml.optElement("reason", getReason()); 310 xml.closeElement(this); 311 return xml; 312 } 313 314 @Override 315 public String getElementName() { 316 return ELEMENT; 317 } 318 } 319 320 /** 321 * Represents a rejection to an invitation from another user to a room. The rejection will be 322 * sent to the room which in turn will forward the refusal to the inviting user. 323 * 324 * @author Gaston Dombiak 325 */ 326 public static class Decline implements NamedElement { 327 public static final String ELEMENT = "decline"; 328 329 private final String reason; 330 private final EntityBareJid from; 331 private final EntityBareJid to; 332 333 public Decline(String reason, EntityBareJid to) { 334 this(reason, null, to); 335 } 336 337 public Decline(String reason, EntityBareJid from, EntityBareJid to) { 338 this.reason = reason; 339 this.from = from; 340 this.to = to; 341 } 342 343 /** 344 * Returns the bare JID of the invitee that rejected the invitation. (e.g. 345 * 'crone1@shakespeare.lit'). 346 * 347 * @return the bare JID of the invitee that rejected the invitation. 348 */ 349 public EntityBareJid getFrom() { 350 return from; 351 } 352 353 /** 354 * Returns the message explaining why the invitation was rejected. 355 * 356 * @return the message explaining the reason for the rejection. 357 */ 358 public String getReason() { 359 return reason; 360 } 361 362 /** 363 * Returns the bare JID of the inviting user. (e.g. 'hecate@shakespeare.lit') 364 * 365 * @return the bare JID of the inviting user. 366 */ 367 public EntityBareJid getTo() { 368 return to; 369 } 370 371 @Override 372 public XmlStringBuilder toXML(String enclosingNamespace) { 373 XmlStringBuilder xml = new XmlStringBuilder(this); 374 xml.optAttribute("to", getTo()); 375 xml.optAttribute("from", getFrom()); 376 xml.rightAngleBracket(); 377 xml.optElement("reason", getReason()); 378 xml.closeElement(this); 379 return xml; 380 } 381 382 @Override 383 public String getElementName() { 384 return ELEMENT; 385 } 386 } 387 388 /** 389 * Status code assists in presenting notification messages. The following link provides the 390 * list of existing error codes <a href="http://xmpp.org/registrar/mucstatus.html">Multi-User Chat Status Codes</a>. 391 * 392 * @author Gaston Dombiak 393 */ 394 public static final class Status implements NamedElement { 395 public static final String ELEMENT = "status"; 396 397 private static final Map<Integer, Status> statusMap = new HashMap<>(8); 398 399 public static final Status PRESENCE_TO_SELF_110 = Status.create(110); 400 public static final Status ROOM_CREATED_201 = Status.create(201); 401 public static final Status BANNED_301 = Status.create(301); 402 public static final Status NEW_NICKNAME_303 = Status.create(303); 403 public static final Status KICKED_307 = Status.create(307); 404 public static final Status REMOVED_AFFIL_CHANGE_321 = Status.create(321); 405 406 private final Integer code; 407 408 public static Status create(String string) { 409 Integer integer = Integer.valueOf(string); 410 return create(integer); 411 } 412 413 public static Status create(Integer i) { 414 Status status = statusMap.get(i); 415 if (status == null) { 416 status = new Status(i); 417 statusMap.put(i, status); 418 } 419 return status; 420 } 421 422 /** 423 * Creates a new instance of Status with the specified code. 424 * 425 * @param code the code that uniquely identifies the reason of the error. 426 */ 427 private Status(int code) { 428 this.code = code; 429 } 430 431 /** 432 * Returns the code that uniquely identifies the reason of the error. The code 433 * assists in presenting notification messages. 434 * 435 * @return the code that uniquely identifies the reason of the error. 436 */ 437 public int getCode() { 438 return code; 439 } 440 441 @Override 442 public XmlStringBuilder toXML(String enclosingNamespace) { 443 XmlStringBuilder xml = new XmlStringBuilder(this); 444 xml.attribute("code", getCode()); 445 xml.closeEmptyElement(); 446 return xml; 447 } 448 449 @Override 450 public String toString() { 451 return code.toString(); 452 } 453 454 @Override 455 public boolean equals(Object other) { 456 if (other == null) { 457 return false; 458 } 459 if (other instanceof Status) { 460 Status otherStatus = (Status) other; 461 return code.equals(otherStatus.getCode()); 462 } 463 return false; 464 } 465 466 @Override 467 public int hashCode() { 468 return code; 469 } 470 471 @Override 472 public String getElementName() { 473 return ELEMENT; 474 } 475 } 476}