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.smack.packet;
019
020import org.jivesoftware.smack.util.XmlStringBuilder;
021
022/**
023 * Represents XMPP presence packets. Every presence packet has a type, which is one of
024 * the following values:
025 * <ul>
026 *      <li>{@link Presence.Type#available available} -- (Default) indicates the user is available to
027 *          receive messages.
028 *      <li>{@link Presence.Type#unavailable unavailable} -- the user is unavailable to receive messages.
029 *      <li>{@link Presence.Type#subscribe subscribe} -- request subscription to recipient's presence.
030 *      <li>{@link Presence.Type#subscribed subscribed} -- grant subscription to sender's presence.
031 *      <li>{@link Presence.Type#unsubscribe unsubscribe} -- request removal of subscription to
032 *          sender's presence.
033 *      <li>{@link Presence.Type#unsubscribed unsubscribed} -- grant removal of subscription to
034 *          sender's presence.
035 *      <li>{@link Presence.Type#error error} -- the presence packet contains an error message.
036 * </ul><p>
037 *
038 * A number of attributes are optional:
039 * <ul>
040 *      <li>Status -- free-form text describing a user's presence (i.e., gone to lunch).
041 *      <li>Priority -- non-negative numerical priority of a sender's resource. The
042 *          highest resource priority is the default recipient of packets not addressed
043 *          to a particular resource.
044 *      <li>Mode -- one of five presence modes: {@link Mode#available available} (the default),
045 *          {@link Mode#chat chat}, {@link Mode#away away}, {@link Mode#xa xa} (extended away), and
046 *          {@link Mode#dnd dnd} (do not disturb).
047 * </ul><p>
048 *
049 * Presence packets are used for two purposes. First, to notify the server of
050 * the user's current presence status. Second, they are used to subscribe and
051 * unsubscribe users from the roster.
052 *
053 * @see RosterPacket
054 * @author Matt Tucker
055 */
056public class Presence extends Packet {
057
058    private Type type = Type.available;
059    private String status = null;
060    private int priority = Integer.MIN_VALUE;
061    private Mode mode = null;
062    private String language;
063
064    /**
065     * Creates a new presence update. Status, priority, and mode are left un-set.
066     *
067     * @param type the type.
068     */
069    public Presence(Type type) {
070        setType(type);
071    }
072
073    /**
074     * Creates a new presence update with a specified status, priority, and mode.
075     *
076     * @param type the type.
077     * @param status a text message describing the presence update.
078     * @param priority the priority of this presence update.
079     * @param mode the mode type for this presence update.
080     */
081    public Presence(Type type, String status, int priority, Mode mode) {
082        setType(type);
083        setStatus(status);
084        setPriority(priority);
085        setMode(mode);
086    }
087
088    /**
089     * Returns true if the {@link Type presence type} is available (online) and
090     * false if the user is unavailable (offline), or if this is a presence packet
091     * involved in a subscription operation. This is a convenience method
092     * equivalent to <tt>getType() == Presence.Type.available</tt>. Note that even
093     * when the user is available, their presence mode may be {@link Mode#away away},
094     * {@link Mode#xa extended away} or {@link Mode#dnd do not disturb}. Use
095     * {@link #isAway()} to determine if the user is away.
096     *
097     * @return true if the presence type is available.
098     */
099    public boolean isAvailable() {
100        return type == Type.available;    
101    }
102
103    /**
104     * Returns true if the presence type is {@link Type#available available} and the presence
105     * mode is {@link Mode#away away}, {@link Mode#xa extended away}, or
106     * {@link Mode#dnd do not disturb}. False will be returned when the type or mode
107     * is any other value, including when the presence type is unavailable (offline).
108     * This is a convenience method equivalent to
109     * <tt>type == Type.available && (mode == Mode.away || mode == Mode.xa || mode == Mode.dnd)</tt>.
110     *
111     * @return true if the presence type is available and the presence mode is away, xa, or dnd.
112     */
113    public boolean isAway() {
114        return type == Type.available && (mode == Mode.away || mode == Mode.xa || mode == Mode.dnd); 
115    }
116
117    /**
118     * Returns the type of this presence packet.
119     *
120     * @return the type of the presence packet.
121     */
122    public Type getType() {
123        return type;
124    }
125
126    /**
127     * Sets the type of the presence packet.
128     *
129     * @param type the type of the presence packet.
130     */
131    public void setType(Type type) {
132        if(type == null) {
133            throw new NullPointerException("Type cannot be null");
134        }
135        this.type = type;
136    }
137
138    /**
139     * Returns the status message of the presence update, or <tt>null</tt> if there
140     * is not a status. The status is free-form text describing a user's presence
141     * (i.e., "gone to lunch").
142     *
143     * @return the status message.
144     */
145    public String getStatus() {
146        return status;
147    }
148
149    /**
150     * Sets the status message of the presence update. The status is free-form text
151     * describing a user's presence (i.e., "gone to lunch").
152     *
153     * @param status the status message.
154     */
155    public void setStatus(String status) {
156        this.status = status;
157    }
158
159    /**
160     * Returns the priority of the presence, or Integer.MIN_VALUE if no priority has been set.
161     *
162     * @return the priority.
163     */
164    public int getPriority() {
165        return priority;
166    }
167
168    /**
169     * Sets the priority of the presence. The valid range is -128 through 128.
170     *
171     * @param priority the priority of the presence.
172     * @throws IllegalArgumentException if the priority is outside the valid range.
173     */
174    public void setPriority(int priority) {
175        if (priority < -128 || priority > 128) {
176            throw new IllegalArgumentException("Priority value " + priority +
177                    " is not valid. Valid range is -128 through 128.");
178        }
179        this.priority = priority;
180    }
181
182    /**
183     * Returns the mode of the presence update, or <tt>null</tt> if the mode is not set.
184     * A null presence mode value is interpreted to be the same thing as
185     * {@link Presence.Mode#available}.
186     *
187     * @return the mode.
188     */
189    public Mode getMode() {
190        return mode;
191    }
192
193    /**
194     * Sets the mode of the presence update. A null presence mode value is interpreted
195     * to be the same thing as {@link Presence.Mode#available}.
196     *
197     * @param mode the mode.
198     */
199    public void setMode(Mode mode) {
200        this.mode = mode;
201    }
202
203    /**
204     * Returns the xml:lang of this Presence, or null if one has not been set.
205     *
206     * @return the xml:lang of this Presence, or null if one has not been set.
207     * @since 3.0.2
208     */
209    public String getLanguage() {
210        return language;
211    }
212
213    /**
214     * Sets the xml:lang of this Presence.
215     *
216     * @param language the xml:lang of this Presence.
217     * @since 3.0.2
218     */
219    public void setLanguage(String language) {
220        this.language = language;
221    }
222
223    @Override
224    public XmlStringBuilder toXML() {
225        XmlStringBuilder buf = new XmlStringBuilder();
226        buf.halfOpenElement("presence");
227        buf.xmlnsAttribute(getXmlns());
228        buf.xmllangAttribute(getLanguage());
229        addCommonAttributes(buf);
230        if (type != Type.available) {
231            buf.attribute("type", type);
232        }
233        buf.rightAngelBracket();
234
235        buf.optElement("status", status);
236        if (priority != Integer.MIN_VALUE) {
237            buf.element("priority", Integer.toString(priority));
238        }
239        if (mode != null && mode != Mode.available) {
240            buf.element("show", mode);
241        }
242        buf.append(getExtensionsXML());
243
244        // Add the error sub-packet, if there is one.
245        XMPPError error = getError();
246        if (error != null) {
247            buf.append(error.toXML());
248        }
249        buf.closeElement("presence");
250
251        return buf;
252    }
253
254    public String toString() {
255        StringBuilder buf = new StringBuilder();
256        buf.append(type);
257        if (mode != null) {
258            buf.append(": ").append(mode);
259        }
260        if (getStatus() != null) {
261            buf.append(" (").append(getStatus()).append(")");
262        }
263        return buf.toString();
264    }
265
266    /**
267     * An enum to represent the presence type. Note that presence type is often confused
268     * with presence mode. Generally, if a user is signed in to a server, they have a presence
269     * type of {@link #available available}, even if the mode is {@link Mode#away away},
270     * {@link Mode#dnd dnd}, etc. The presence type is only {@link #unavailable unavailable} when
271     * the user is signing out of the server.
272     */
273    public enum Type {
274
275       /**
276        * The user is available to receive messages (default).
277        */
278        available,
279
280        /**
281         * The user is unavailable to receive messages.
282         */
283        unavailable,
284
285        /**
286         * Request subscription to recipient's presence.
287         */
288        subscribe,
289
290        /**
291         * Grant subscription to sender's presence.
292         */
293        subscribed,
294
295        /**
296         * Request removal of subscription to sender's presence.
297         */
298        unsubscribe,
299
300        /**
301         * Grant removal of subscription to sender's presence.
302         */
303        unsubscribed,
304
305        /**
306         * The presence packet contains an error message.
307         */
308        error
309    }
310
311    /**
312     * An enum to represent the presence mode.
313     */
314    public enum Mode {
315
316        /**
317         * Free to chat.
318         */
319        chat,
320
321        /**
322         * Available (the default).
323         */
324        available,
325
326        /**
327         * Away.
328         */
329        away,
330
331        /**
332         * Away for an extended period of time.
333         */
334        xa,
335
336        /**
337         * Do not disturb.
338         */
339        dnd
340    }
341}