aboutsummaryrefslogtreecommitdiff
path: root/src/org/jivesoftware/smackx/packet/MessageEvent.java
blob: 5e146dc58359957161f1ad719d236c55d579ca99 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
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
67
68
69
70
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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
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
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
/**
 * $RCSfile$
 * $Revision$
 * $Date$
 *
 * Copyright 2003-2007 Jive Software.
 *
 * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.jivesoftware.smackx.packet;

import org.jivesoftware.smack.packet.PacketExtension;

import java.util.ArrayList;
import java.util.Iterator;

/**
 * Represents message events relating to the delivery, display, composition and cancellation of 
 * messages.<p>
 * 
 * There are four message events currently defined in this namespace:
 * <ol>
 * <li>Offline<br>
 * Indicates that the message has been stored offline by the intended recipient's server. This 
 * event is triggered only if the intended recipient's server supports offline storage, has that 
 * support enabled, and the recipient is offline when the server receives the message for delivery.</li>
 * 
 * <li>Delivered<br>
 * Indicates that the message has been delivered to the recipient. This signifies that the message
 * has reached the recipient's XMPP client, but does not necessarily mean that the message has 
 * been displayed. This event is to be raised by the XMPP client.</li>
 * 
 * <li>Displayed<br>
 * Once the message has been received by the recipient's XMPP client, it may be displayed to the
 * user. This event indicates that the message has been displayed, and is to be raised by the 
 * XMPP client. Even if a message is displayed multiple times, this event should be raised only 
 * once.</li>
 * 
 * <li>Composing<br>
 * In threaded chat conversations, this indicates that the recipient is composing a reply to a 
 * message. The event is to be raised by the recipient's XMPP client. A XMPP client is allowed
 * to raise this event multiple times in response to the same request, providing the original 
 * event is cancelled first.</li>
 * </ol>
 *
 * @author Gaston Dombiak
 */
public class MessageEvent implements PacketExtension {

    public static final String OFFLINE = "offline";
    public static final String COMPOSING = "composing";
    public static final String DISPLAYED = "displayed";
    public static final String DELIVERED = "delivered";
    public static final String CANCELLED = "cancelled";

    private boolean offline = false;
    private boolean delivered = false;
    private boolean displayed = false;
    private boolean composing = false;
    private boolean cancelled = true;

    private String packetID = null;

    /**
    * Returns the XML element name of the extension sub-packet root element.
    * Always returns "x"
    *
    * @return the XML element name of the packet extension.
    */
    public String getElementName() {
        return "x";
    }

    /** 
     * Returns the XML namespace of the extension sub-packet root element.
     * According the specification the namespace is always "jabber:x:event"
     *
     * @return the XML namespace of the packet extension.
     */
    public String getNamespace() {
        return "jabber:x:event";
    }

    /**
     * When the message is a request returns if the sender of the message requests to be notified
     * when the receiver is composing a reply.
     * When the message is a notification returns if the receiver of the message is composing a 
     * reply.
     * 
     * @return true if the sender is requesting to be notified when composing or when notifying
     * that the receiver of the message is composing a reply
     */
    public boolean isComposing() {
        return composing;
    }

    /**
     * When the message is a request returns if the sender of the message requests to be notified
     * when the message is delivered.
     * When the message is a notification returns if the message was delivered or not.
     * 
     * @return true if the sender is requesting to be notified when delivered or when notifying 
     * that the message was delivered 
     */
    public boolean isDelivered() {
        return delivered;
    }

    /**
     * When the message is a request returns if the sender of the message requests to be notified
     * when the message is displayed.
     * When the message is a notification returns if the message was displayed or not.
     * 
     * @return true if the sender is requesting to be notified when displayed or when notifying 
     * that the message was displayed
     */
    public boolean isDisplayed() {
        return displayed;
    }

    /**
     * When the message is a request returns if the sender of the message requests to be notified
     * when the receiver of the message is offline.
     * When the message is a notification returns if the receiver of the message was offline.
     * 
     * @return true if the sender is requesting to be notified when offline or when notifying 
     * that the receiver of the message is offline
     */
    public boolean isOffline() {
        return offline;
    }

    /**
     * When the message is a notification returns if the receiver of the message cancelled 
     * composing a reply.
     * 
     * @return true if the receiver of the message cancelled composing a reply
     */
    public boolean isCancelled() {
        return cancelled;
    }

    /**
     * Returns the unique ID of the message that requested to be notified of the event.
     * The packet id is not used when the message is a request for notifications
     *
     * @return the message id that requested to be notified of the event.
     */
    public String getPacketID() {
        return packetID;
    }

    /**
     * Returns the types of events. The type of event could be:
     * "offline", "composing","delivered","displayed", "offline"
     *
     * @return an iterator over all the types of events of the MessageEvent.
     */
    public Iterator<String> getEventTypes() {
        ArrayList<String> allEvents = new ArrayList<String>();
        if (isDelivered()) {
            allEvents.add(MessageEvent.DELIVERED);
        }
        if (!isMessageEventRequest() && isCancelled()) {
            allEvents.add(MessageEvent.CANCELLED);
        }
        if (isComposing()) {
            allEvents.add(MessageEvent.COMPOSING);
        }
        if (isDisplayed()) {
            allEvents.add(MessageEvent.DISPLAYED);
        }
        if (isOffline()) {
            allEvents.add(MessageEvent.OFFLINE);
        }
        return allEvents.iterator();
    }

    /**
     * When the message is a request sets if the sender of the message requests to be notified
     * when the receiver is composing a reply.
     * When the message is a notification sets if the receiver of the message is composing a 
     * reply.
     * 
     * @param composing sets if the sender is requesting to be notified when composing or when 
     * notifying that the receiver of the message is composing a reply
     */
    public void setComposing(boolean composing) {
        this.composing = composing;
        setCancelled(false);
    }

    /**
     * When the message is a request sets if the sender of the message requests to be notified
     * when the message is delivered.
     * When the message is a notification sets if the message was delivered or not.
     * 
     * @param delivered sets if the sender is requesting to be notified when delivered or when 
     * notifying that the message was delivered 
     */
    public void setDelivered(boolean delivered) {
        this.delivered = delivered;
        setCancelled(false);
    }

    /**
     * When the message is a request sets if the sender of the message requests to be notified
     * when the message is displayed.
     * When the message is a notification sets if the message was displayed or not.
     * 
     * @param displayed sets if the sender is requesting to be notified when displayed or when 
     * notifying that the message was displayed
     */
    public void setDisplayed(boolean displayed) {
        this.displayed = displayed;
        setCancelled(false);
    }

    /**
     * When the message is a request sets if the sender of the message requests to be notified
     * when the receiver of the message is offline.
     * When the message is a notification sets if the receiver of the message was offline.
     * 
     * @param offline sets if the sender is requesting to be notified when offline or when 
     * notifying that the receiver of the message is offline
     */
    public void setOffline(boolean offline) {
        this.offline = offline;
        setCancelled(false);
    }

    /**
     * When the message is a notification sets if the receiver of the message cancelled 
     * composing a reply.
     * The Cancelled event is never requested explicitly. It is requested implicitly when
     * requesting to be notified of the Composing event.
     * 
     * @param cancelled sets if the receiver of the message cancelled composing a reply
     */
    public void setCancelled(boolean cancelled) {
        this.cancelled = cancelled;
    }

    /**
     * Sets the unique ID of the message that requested to be notified of the event.
     * The packet id is not used when the message is a request for notifications
     *
     * @param packetID the message id that requested to be notified of the event.
     */
    public void setPacketID(String packetID) {
        this.packetID = packetID;
    }

    /**
     * Returns true if this MessageEvent is a request for notifications.
     * Returns false if this MessageEvent is a notification of an event.
     *
    * @return true if this message is a request for notifications.
     */
    public boolean isMessageEventRequest() {
        return this.packetID == null;
    }

    /**
     * Returns the XML representation of a Message Event according the specification.
     * 
     * Usually the XML representation will be inside of a Message XML representation like
     * in the following examples:<p>
     * 
     * Request to be notified when displayed:
     * <pre>
     * &lt;message
     *    to='romeo@montague.net/orchard'
     *    from='juliet@capulet.com/balcony'
     *    id='message22'&gt;
     * &lt;x xmlns='jabber:x:event'&gt;
     *   &lt;displayed/&gt;
     * &lt;/x&gt;
     * &lt;/message&gt;
     * </pre>
     * 
     * Notification of displayed:
     * <pre>
     * &lt;message
     *    from='romeo@montague.net/orchard'
     *    to='juliet@capulet.com/balcony'&gt;
     * &lt;x xmlns='jabber:x:event'&gt;
     *   &lt;displayed/&gt;
     *   &lt;id&gt;message22&lt;/id&gt;
     * &lt;/x&gt;
     * &lt;/message&gt;
     * </pre>
     * 
     */
    public String toXML() {
        StringBuilder buf = new StringBuilder();
        buf.append("<").append(getElementName()).append(" xmlns=\"").append(getNamespace()).append(
            "\">");
        // Note: Cancellation events don't specify any tag. They just send the packetID

        // Add the offline tag if the sender requests to be notified of offline events or if 
        // the target is offline
        if (isOffline())
            buf.append("<").append(MessageEvent.OFFLINE).append("/>");
        // Add the delivered tag if the sender requests to be notified when the message is 
        // delivered or if the target notifies that the message has been delivered
        if (isDelivered())
            buf.append("<").append(MessageEvent.DELIVERED).append("/>");
        // Add the displayed tag if the sender requests to be notified when the message is 
        // displayed or if the target notifies that the message has been displayed
        if (isDisplayed())
            buf.append("<").append(MessageEvent.DISPLAYED).append("/>");
        // Add the composing tag if the sender requests to be notified when the target is 
        // composing a reply or if the target notifies that he/she is composing a reply
        if (isComposing())
            buf.append("<").append(MessageEvent.COMPOSING).append("/>");
        // Add the id tag only if the MessageEvent is a notification message (not a request)
        if (getPacketID() != null)
            buf.append("<id>").append(getPacketID()).append("</id>");
        buf.append("</").append(getElementName()).append(">");
        return buf.toString();
    }

}