1/**
2 * $RCSfile$
3 * $Revision$
4 * $Date$
5 *
6 * Copyright 2003-2007 Jive Software.
7 *
8 * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 *     http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20
21package org.jivesoftware.smack.packet;
22
23import org.jivesoftware.smack.util.StringUtils;
24
25import java.util.*;
26import java.util.concurrent.CopyOnWriteArraySet;
27
28/**
29 * Represents XMPP roster packets.
30 *
31 * @author Matt Tucker
32 */
33public class RosterPacket extends IQ {
34
35    private final List<Item> rosterItems = new ArrayList<Item>();
36    /*
37     * The ver attribute following XEP-0237
38     */
39    private String version;
40
41    /**
42     * Adds a roster item to the packet.
43     *
44     * @param item a roster item.
45     */
46    public void addRosterItem(Item item) {
47        synchronized (rosterItems) {
48            rosterItems.add(item);
49        }
50    }
51
52    public String getVersion(){
53    	return version;
54    }
55
56    public void setVersion(String version){
57    	this.version = version;
58    }
59
60    /**
61     * Returns the number of roster items in this roster packet.
62     *
63     * @return the number of roster items.
64     */
65    public int getRosterItemCount() {
66        synchronized (rosterItems) {
67            return rosterItems.size();
68        }
69    }
70
71    /**
72     * Returns an unmodifiable collection for the roster items in the packet.
73     *
74     * @return an unmodifiable collection for the roster items in the packet.
75     */
76    public Collection<Item> getRosterItems() {
77        synchronized (rosterItems) {
78            return Collections.unmodifiableList(new ArrayList<Item>(rosterItems));
79        }
80    }
81
82    public String getChildElementXML() {
83        StringBuilder buf = new StringBuilder();
84        buf.append("<query xmlns=\"jabber:iq:roster\" ");
85        if(version!=null){
86        	buf.append(" ver=\""+version+"\" ");
87        }
88        buf.append(">");
89        synchronized (rosterItems) {
90            for (Item entry : rosterItems) {
91                buf.append(entry.toXML());
92            }
93        }
94        buf.append("</query>");
95        return buf.toString();
96    }
97
98    /**
99     * A roster item, which consists of a JID, their name, the type of subscription, and
100     * the groups the roster item belongs to.
101     */
102    public static class Item {
103
104        private String user;
105        private String name;
106        private ItemType itemType;
107        private ItemStatus itemStatus;
108        private final Set<String> groupNames;
109
110        /**
111         * Creates a new roster item.
112         *
113         * @param user the user.
114         * @param name the user's name.
115         */
116        public Item(String user, String name) {
117            this.user = user.toLowerCase();
118            this.name = name;
119            itemType = null;
120            itemStatus = null;
121            groupNames = new CopyOnWriteArraySet<String>();
122        }
123
124        /**
125         * Returns the user.
126         *
127         * @return the user.
128         */
129        public String getUser() {
130            return user;
131        }
132
133        /**
134         * Returns the user's name.
135         *
136         * @return the user's name.
137         */
138        public String getName() {
139            return name;
140        }
141
142        /**
143         * Sets the user's name.
144         *
145         * @param name the user's name.
146         */
147        public void setName(String name) {
148            this.name = name;
149        }
150
151        /**
152         * Returns the roster item type.
153         *
154         * @return the roster item type.
155         */
156        public ItemType getItemType() {
157            return itemType;
158        }
159
160        /**
161         * Sets the roster item type.
162         *
163         * @param itemType the roster item type.
164         */
165        public void setItemType(ItemType itemType) {
166            this.itemType = itemType;
167        }
168
169        /**
170         * Returns the roster item status.
171         *
172         * @return the roster item status.
173         */
174        public ItemStatus getItemStatus() {
175            return itemStatus;
176        }
177
178        /**
179         * Sets the roster item status.
180         *
181         * @param itemStatus the roster item status.
182         */
183        public void setItemStatus(ItemStatus itemStatus) {
184            this.itemStatus = itemStatus;
185        }
186
187        /**
188         * Returns an unmodifiable set of the group names that the roster item
189         * belongs to.
190         *
191         * @return an unmodifiable set of the group names.
192         */
193        public Set<String> getGroupNames() {
194            return Collections.unmodifiableSet(groupNames);
195        }
196
197        /**
198         * Adds a group name.
199         *
200         * @param groupName the group name.
201         */
202        public void addGroupName(String groupName) {
203            groupNames.add(groupName);
204        }
205
206        /**
207         * Removes a group name.
208         *
209         * @param groupName the group name.
210         */
211        public void removeGroupName(String groupName) {
212            groupNames.remove(groupName);
213        }
214
215        public String toXML() {
216            StringBuilder buf = new StringBuilder();
217            buf.append("<item jid=\"").append(user).append("\"");
218            if (name != null) {
219                buf.append(" name=\"").append(StringUtils.escapeForXML(name)).append("\"");
220            }
221            if (itemType != null) {
222                buf.append(" subscription=\"").append(itemType).append("\"");
223            }
224            if (itemStatus != null) {
225                buf.append(" ask=\"").append(itemStatus).append("\"");
226            }
227            buf.append(">");
228            for (String groupName : groupNames) {
229                buf.append("<group>").append(StringUtils.escapeForXML(groupName)).append("</group>");
230            }
231            buf.append("</item>");
232            return buf.toString();
233        }
234    }
235
236    /**
237     * The subscription status of a roster item. An optional element that indicates
238     * the subscription status if a change request is pending.
239     */
240    public static class ItemStatus {
241
242        /**
243         * Request to subcribe.
244         */
245        public static final ItemStatus SUBSCRIPTION_PENDING = new ItemStatus("subscribe");
246
247        /**
248         * Request to unsubscribe.
249         */
250        public static final ItemStatus UNSUBSCRIPTION_PENDING = new ItemStatus("unsubscribe");
251
252        public static ItemStatus fromString(String value) {
253            if (value == null) {
254                return null;
255            }
256            value = value.toLowerCase();
257            if ("unsubscribe".equals(value)) {
258                return UNSUBSCRIPTION_PENDING;
259            }
260            else if ("subscribe".equals(value)) {
261                return SUBSCRIPTION_PENDING;
262            }
263            else {
264                return null;
265            }
266        }
267
268        private String value;
269
270        /**
271         * Returns the item status associated with the specified string.
272         *
273         * @param value the item status.
274         */
275        private ItemStatus(String value) {
276            this.value = value;
277        }
278
279        public String toString() {
280            return value;
281        }
282    }
283
284    public static enum ItemType {
285
286        /**
287         * The user and subscriber have no interest in each other's presence.
288         */
289        none,
290
291        /**
292         * The user is interested in receiving presence updates from the subscriber.
293         */
294        to,
295
296        /**
297         * The subscriber is interested in receiving presence updates from the user.
298         */
299        from,
300
301        /**
302         * The user and subscriber have a mutual interest in each other's presence.
303         */
304        both,
305
306        /**
307         * The user wishes to stop receiving presence updates from the subscriber.
308         */
309        remove
310    }
311}
312