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.xevent.packet; 019 020import java.util.ArrayList; 021import java.util.List; 022 023import org.jivesoftware.smack.packet.ExtensionElement; 024 025/** 026 * Represents message events relating to the delivery, display, composition and cancellation of 027 * messages.<p> 028 * 029 * There are four message events currently defined in this namespace: 030 * <ol> 031 * <li>Offline<br> 032 * Indicates that the message has been stored offline by the intended recipient's server. This 033 * event is triggered only if the intended recipient's server supports offline storage, has that 034 * support enabled, and the recipient is offline when the server receives the message for delivery.</li> 035 * 036 * <li>Delivered<br> 037 * Indicates that the message has been delivered to the recipient. This signifies that the message 038 * has reached the recipient's XMPP client, but does not necessarily mean that the message has 039 * been displayed. This event is to be raised by the XMPP client.</li> 040 * 041 * <li>Displayed<br> 042 * Once the message has been received by the recipient's XMPP client, it may be displayed to the 043 * user. This event indicates that the message has been displayed, and is to be raised by the 044 * XMPP client. Even if a message is displayed multiple times, this event should be raised only 045 * once.</li> 046 * 047 * <li>Composing<br> 048 * In threaded chat conversations, this indicates that the recipient is composing a reply to a 049 * message. The event is to be raised by the recipient's XMPP client. A XMPP client is allowed 050 * to raise this event multiple times in response to the same request, providing the original 051 * event is cancelled first.</li> 052 * </ol> 053 * 054 * @author Gaston Dombiak 055 */ 056public class MessageEvent implements ExtensionElement { 057 058 public static final String NAMESPACE = "jabber:x:event"; 059 public static final String ELEMENT = "x"; 060 061 public static final String OFFLINE = "offline"; 062 public static final String COMPOSING = "composing"; 063 public static final String DISPLAYED = "displayed"; 064 public static final String DELIVERED = "delivered"; 065 public static final String CANCELLED = "cancelled"; 066 067 private boolean offline = false; 068 private boolean delivered = false; 069 private boolean displayed = false; 070 private boolean composing = false; 071 private boolean cancelled = true; 072 073 private String packetID = null; 074 075 /** 076 * Returns the XML element name of the extension sub-packet root element. 077 * Always returns "x" 078 * 079 * @return the XML element name of the stanza extension. 080 */ 081 @Override 082 public String getElementName() { 083 return ELEMENT; 084 } 085 086 /** 087 * Returns the XML namespace of the extension sub-packet root element. 088 * According the specification the namespace is always "jabber:x:event" 089 * 090 * @return the XML namespace of the stanza extension. 091 */ 092 @Override 093 public String getNamespace() { 094 return NAMESPACE; 095 } 096 097 /** 098 * When the message is a request returns if the sender of the message requests to be notified 099 * when the receiver is composing a reply. 100 * When the message is a notification returns if the receiver of the message is composing a 101 * reply. 102 * 103 * @return true if the sender is requesting to be notified when composing or when notifying 104 * that the receiver of the message is composing a reply 105 */ 106 public boolean isComposing() { 107 return composing; 108 } 109 110 /** 111 * When the message is a request returns if the sender of the message requests to be notified 112 * when the message is delivered. 113 * When the message is a notification returns if the message was delivered or not. 114 * 115 * @return true if the sender is requesting to be notified when delivered or when notifying 116 * that the message was delivered 117 */ 118 public boolean isDelivered() { 119 return delivered; 120 } 121 122 /** 123 * When the message is a request returns if the sender of the message requests to be notified 124 * when the message is displayed. 125 * When the message is a notification returns if the message was displayed or not. 126 * 127 * @return true if the sender is requesting to be notified when displayed or when notifying 128 * that the message was displayed 129 */ 130 public boolean isDisplayed() { 131 return displayed; 132 } 133 134 /** 135 * When the message is a request returns if the sender of the message requests to be notified 136 * when the receiver of the message is offline. 137 * When the message is a notification returns if the receiver of the message was offline. 138 * 139 * @return true if the sender is requesting to be notified when offline or when notifying 140 * that the receiver of the message is offline 141 */ 142 public boolean isOffline() { 143 return offline; 144 } 145 146 /** 147 * When the message is a notification returns if the receiver of the message cancelled 148 * composing a reply. 149 * 150 * @return true if the receiver of the message cancelled composing a reply 151 */ 152 public boolean isCancelled() { 153 return cancelled; 154 } 155 156 /** 157 * Returns the unique ID of the message that requested to be notified of the event. 158 * The stanza id is not used when the message is a request for notifications 159 * 160 * @return the message id that requested to be notified of the event. 161 */ 162 public String getStanzaId() { 163 return packetID; 164 } 165 166 /** 167 * Returns the types of events. The type of event could be: 168 * "offline", "composing","delivered","displayed", "offline" 169 * 170 * @return a List of all the types of events of the MessageEvent. 171 */ 172 public List<String> getEventTypes() { 173 ArrayList<String> allEvents = new ArrayList<>(); 174 if (isDelivered()) { 175 allEvents.add(MessageEvent.DELIVERED); 176 } 177 if (!isMessageEventRequest() && isCancelled()) { 178 allEvents.add(MessageEvent.CANCELLED); 179 } 180 if (isComposing()) { 181 allEvents.add(MessageEvent.COMPOSING); 182 } 183 if (isDisplayed()) { 184 allEvents.add(MessageEvent.DISPLAYED); 185 } 186 if (isOffline()) { 187 allEvents.add(MessageEvent.OFFLINE); 188 } 189 return allEvents; 190 } 191 192 /** 193 * When the message is a request sets if the sender of the message requests to be notified 194 * when the receiver is composing a reply. 195 * When the message is a notification sets if the receiver of the message is composing a 196 * reply. 197 * 198 * @param composing sets if the sender is requesting to be notified when composing or when 199 * notifying that the receiver of the message is composing a reply 200 */ 201 public void setComposing(boolean composing) { 202 this.composing = composing; 203 setCancelled(false); 204 } 205 206 /** 207 * When the message is a request sets if the sender of the message requests to be notified 208 * when the message is delivered. 209 * When the message is a notification sets if the message was delivered or not. 210 * 211 * @param delivered sets if the sender is requesting to be notified when delivered or when 212 * notifying that the message was delivered 213 */ 214 public void setDelivered(boolean delivered) { 215 this.delivered = delivered; 216 setCancelled(false); 217 } 218 219 /** 220 * When the message is a request sets if the sender of the message requests to be notified 221 * when the message is displayed. 222 * When the message is a notification sets if the message was displayed or not. 223 * 224 * @param displayed sets if the sender is requesting to be notified when displayed or when 225 * notifying that the message was displayed 226 */ 227 public void setDisplayed(boolean displayed) { 228 this.displayed = displayed; 229 setCancelled(false); 230 } 231 232 /** 233 * When the message is a request sets if the sender of the message requests to be notified 234 * when the receiver of the message is offline. 235 * When the message is a notification sets if the receiver of the message was offline. 236 * 237 * @param offline sets if the sender is requesting to be notified when offline or when 238 * notifying that the receiver of the message is offline 239 */ 240 public void setOffline(boolean offline) { 241 this.offline = offline; 242 setCancelled(false); 243 } 244 245 /** 246 * When the message is a notification sets if the receiver of the message cancelled 247 * composing a reply. 248 * The Cancelled event is never requested explicitly. It is requested implicitly when 249 * requesting to be notified of the Composing event. 250 * 251 * @param cancelled sets if the receiver of the message cancelled composing a reply 252 */ 253 public void setCancelled(boolean cancelled) { 254 this.cancelled = cancelled; 255 } 256 257 /** 258 * Sets the unique ID of the message that requested to be notified of the event. 259 * The stanza id is not used when the message is a request for notifications 260 * 261 * @param packetID the message id that requested to be notified of the event. 262 */ 263 public void setStanzaId(String packetID) { 264 this.packetID = packetID; 265 } 266 267 /** 268 * Returns true if this MessageEvent is a request for notifications. 269 * Returns false if this MessageEvent is a notification of an event. 270 * 271 * @return true if this message is a request for notifications. 272 */ 273 public boolean isMessageEventRequest() { 274 return this.packetID == null; 275 } 276 277 /** 278 * Returns the XML representation of a Message Event according the specification. 279 * 280 * Usually the XML representation will be inside of a Message XML representation like 281 * in the following examples:<p> 282 * 283 * Request to be notified when displayed: 284 * <pre> 285 * <message 286 * to='romeo@montague.net/orchard' 287 * from='juliet@capulet.com/balcony' 288 * id='message22'> 289 * <x xmlns='jabber:x:event'> 290 * <displayed/> 291 * </x> 292 * </message> 293 * </pre> 294 * 295 * Notification of displayed: 296 * <pre> 297 * <message 298 * from='romeo@montague.net/orchard' 299 * to='juliet@capulet.com/balcony'> 300 * <x xmlns='jabber:x:event'> 301 * <displayed/> 302 * <id>message22</id> 303 * </x> 304 * </message> 305 * </pre> 306 * 307 */ 308 @Override 309 public String toXML(org.jivesoftware.smack.packet.XmlEnvironment enclosingNamespace) { 310 StringBuilder buf = new StringBuilder(); 311 buf.append('<').append(getElementName()).append(" xmlns=\"").append(getNamespace()).append( 312 "\">"); 313 // Note: Cancellation events don't specify any tag. They just send the packetID 314 315 // Add the offline tag if the sender requests to be notified of offline events or if 316 // the target is offline 317 if (isOffline()) 318 buf.append('<').append(MessageEvent.OFFLINE).append("/>"); 319 // Add the delivered tag if the sender requests to be notified when the message is 320 // delivered or if the target notifies that the message has been delivered 321 if (isDelivered()) 322 buf.append('<').append(MessageEvent.DELIVERED).append("/>"); 323 // Add the displayed tag if the sender requests to be notified when the message is 324 // displayed or if the target notifies that the message has been displayed 325 if (isDisplayed()) 326 buf.append('<').append(MessageEvent.DISPLAYED).append("/>"); 327 // Add the composing tag if the sender requests to be notified when the target is 328 // composing a reply or if the target notifies that he/she is composing a reply 329 if (isComposing()) 330 buf.append('<').append(MessageEvent.COMPOSING).append("/>"); 331 // Add the id tag only if the MessageEvent is a notification message (not a request) 332 if (getStanzaId() != null) 333 buf.append("<id>").append(getStanzaId()).append("</id>"); 334 buf.append("</").append(getElementName()).append('>'); 335 return buf.toString(); 336 } 337 338}