001/**
002 *
003 * Copyright 2006-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 */
017package org.jivesoftware.smackx.privacy.packet;
018
019import java.util.HashMap;
020import java.util.Iterator;
021import java.util.List;
022import java.util.Map;
023import java.util.Set;
024
025import org.jivesoftware.smack.packet.IQ;
026
027/**
028 * A Privacy IQ Packet, is used by the {@link org.jivesoftware.smackx.privacy.PrivacyListManager}
029 * and {@link org.jivesoftware.smackx.privacy.provider.PrivacyProvider} to allow and block
030 * communications from other users. It contains the appropriate structure to suit
031 * user-defined privacy lists. Different configured Privacy packages are used in the
032 * server and manager communication in order to:
033 * <ul>
034 * <li>Retrieving one's privacy lists. 
035 * <li>Adding, removing, and editing one's privacy lists. 
036 * <li>Setting, changing, or declining active lists. 
037 * <li>Setting, changing, or declining the default list (i.e., the list that is active by default). 
038 * </ul>
039 * Privacy Items can handle different kind of blocking communications based on JID, group, 
040 * subscription type or globally {@link PrivacyItem}
041 * 
042 * @author Francisco Vives
043 */
044public class Privacy extends IQ {
045    public static final String ELEMENT = QUERY_ELEMENT;
046    public static final String NAMESPACE = "jabber:iq:privacy";
047
048    /** declineActiveList is true when the user declines the use of the active list **/
049    private boolean declineActiveList = false;
050    /** activeName is the name associated with the active list set for the session **/
051    private String activeName;
052    /** declineDefaultList is true when the user declines the use of the default list **/
053    private boolean declineDefaultList = false;
054    /** defaultName is the name of the default list that applies to the user as a whole **/
055    private String defaultName;
056    /** itemLists holds the set of privacy items classified in lists. It is a map where the 
057     * key is the name of the list and the value a collection with privacy items. **/
058    private final Map<String, List<PrivacyItem>> itemLists = new HashMap<>();
059
060    public Privacy() {
061        super(ELEMENT, NAMESPACE);
062    }
063
064    /**
065     * Set or update a privacy list with privacy items.
066     *
067     * @param listName the name of the new privacy list.
068     * @param listItem the {@link PrivacyItem} that rules the list.
069     * @return the privacy List.
070     */
071    public List<PrivacyItem> setPrivacyList(String listName, List<PrivacyItem> listItem) {
072        // Add new list to the itemLists
073        this.getItemLists().put(listName, listItem);
074        return listItem;
075    }
076
077    /**
078     * Set the active list based on the default list.
079     *
080     * @return the active List.
081     */
082    public List<PrivacyItem> setActivePrivacyList() {
083        this.setActiveName(this.getDefaultName());
084        return this.getItemLists().get(this.getActiveName());
085    }
086
087    /**
088     * Deletes an existing privacy list. If the privacy list being deleted was the default list 
089     * then the user will end up with no default list. Therefore, the user will have to set a new 
090     * default list.
091     *
092     * @param listName the name of the list being deleted.
093     */
094    public void deletePrivacyList(String listName) {
095        // Remove the list from the cache
096        // CHECKSTYLE:OFF
097        this.getItemLists().remove(listName);
098        // CHECKSTYLE:ON
099
100        // Check if deleted list was the default list
101        if (this.getDefaultName() != null && listName.equals(this.getDefaultName())) {
102        // CHECKSTYLE:OFF
103            this.setDefaultName(null);
104        // CHECKSTYLE:ON
105        }
106    }
107
108    /**
109     * Returns the active privacy list or <tt>null</tt> if none was found.
110     *
111     * @return list with {@link PrivacyItem} or <tt>null</tt> if none was found.
112     */
113    public List<PrivacyItem> getActivePrivacyList() {
114        // Check if we have the default list
115        // CHECKSTYLE:OFF
116        if (this.getActiveName() == null) {
117            return null;
118        } else {
119            return this.getItemLists().get(this.getActiveName());
120        }
121        // CHECKSTYLE:ON
122    }
123
124    /**
125     * Returns the default privacy list or <tt>null</tt> if none was found.
126     *
127     * @return list with {@link PrivacyItem} or <tt>null</tt> if none was found.
128     */
129    public List<PrivacyItem> getDefaultPrivacyList() {
130        // Check if we have the default list
131        // CHECKSTYLE:OFF
132        if (this.getDefaultName() == null) {
133            return null;
134        } else {
135            return this.getItemLists().get(this.getDefaultName());
136        }
137        // CHECKSTYLE:ON
138    }
139
140    /**
141     * Returns a specific privacy list.
142     *
143     * @param listName the name of the list to get.
144     * @return a List with {@link PrivacyItem}
145     */
146    public List<PrivacyItem> getPrivacyList(String listName) {
147        return this.getItemLists().get(listName);
148    }
149
150    /**
151     * Returns the privacy item in the specified order.
152     *
153     * @param listName the name of the privacy list.
154     * @param order the order of the element.
155     * @return a List with {@link PrivacyItem}
156     */
157    public PrivacyItem getItem(String listName, int order) {
158        // CHECKSTYLE:OFF
159        Iterator<PrivacyItem> values = getPrivacyList(listName).iterator();
160        PrivacyItem itemFound = null;
161        while (itemFound == null && values.hasNext()) {
162            PrivacyItem element = values.next();
163            if (element.getOrder() == order) {
164                itemFound = element;
165            }
166        }
167        return itemFound;
168        // CHECKSTYLE:ON
169    }
170
171    /**
172     * Sets a given privacy list as the new user default list.
173     *
174     * @param newDefault the new default privacy list.
175     * @return if the default list was changed.
176     */
177    public boolean changeDefaultList(String newDefault) {
178        if (this.getItemLists().containsKey(newDefault)) {
179           this.setDefaultName(newDefault);
180           return true;
181        } else {
182            // CHECKSTYLE:OFF
183            return false; 
184            // CHECKSTYLE:ON
185        }
186    }
187
188    /**
189     * Remove the list.
190     *
191     * @param listName name of the list to remove.
192     */
193     public void deleteList(String listName) {
194     // CHECKSTYLE:OFF
195         this.getItemLists().remove(listName);
196     // CHECKSTYLE:ON
197     }
198
199    /**
200     * Returns the name associated with the active list set for the session. Communications
201     * will be verified against the active list.
202     *
203     * @return the name of the active list.
204     */
205    // CHECKSTYLE:OFF
206    public String getActiveName() {
207        return activeName;
208    }
209    // CHECKSTYLE:ON
210
211    /**
212     * Sets the name associated with the active list set for the session. Communications
213     * will be verified against the active list.
214     * 
215     * @param activeName is the name of the active list.
216     */
217    // CHECKSTYLE:OFF
218    public void setActiveName(String activeName) {
219        this.activeName = activeName;
220    }
221    // CHECKSTYLE:ON
222
223    /**
224     * Returns the name of the default list that applies to the user as a whole. Default list is 
225     * processed if there is no active list set for the target session/resource to which a stanza 
226     * is addressed, or if there are no current sessions for the user.
227     * 
228     * @return the name of the default list.
229     */
230    // CHECKSTYLE:OFF
231    public String getDefaultName() {
232        return defaultName;
233    }
234    // CHECKSTYLE:ON
235
236    /**
237     * Sets the name of the default list that applies to the user as a whole. Default list is 
238     * processed if there is no active list set for the target session/resource to which a stanza 
239     * is addressed, or if there are no current sessions for the user.
240     * 
241     * If there is no default list set, then all Privacy Items are processed.
242     * 
243     * @param defaultName is the name of the default list.
244     */
245    // CHECKSTYLE:OFF
246    public void setDefaultName(String defaultName) {
247        this.defaultName = defaultName;
248    }
249    // CHECKSTYLE:ON
250
251    /**
252     * Returns the collection of privacy list that the user holds. A Privacy List contains a set of 
253     * rules that define if communication with the list owner is allowed or denied. 
254     * Users may have zero, one or more privacy items.
255     * 
256     * @return a map where the key is the name of the list and the value the 
257     * collection of privacy items.
258     */
259    // CHECKSTYLE:OFF
260    public Map<String, List<PrivacyItem>> getItemLists() {
261        return itemLists;
262    }
263    // CHECKSTYLE:ON
264
265    /** 
266     * Returns whether the receiver allows or declines the use of an active list.
267     * 
268     * @return the decline status of the list.
269     */
270    // CHECKSTYLE:OFF
271    public boolean isDeclineActiveList() {
272        return declineActiveList;
273    }
274    // CHECKSTYLE:ON
275
276    /** 
277     * Sets whether the receiver allows or declines the use of an active list.
278     * 
279     * @param declineActiveList indicates if the receiver declines the use of an active list.
280     */
281    // CHECKSTYLE:OFF
282    public void setDeclineActiveList(boolean declineActiveList) {
283        this.declineActiveList = declineActiveList;
284    }
285    // CHECKSTYLE:ON
286
287    /** 
288     * Returns whether the receiver allows or declines the use of a default list.
289     * 
290     * @return the decline status of the list.
291     */
292    // CHECKSTYLE:OFF
293    public boolean isDeclineDefaultList() {
294        return declineDefaultList;
295    }
296    // CHECKSTYLE:ON
297
298    /** 
299     * Sets whether the receiver allows or declines the use of a default list.
300     * 
301     * @param declineDefaultList indicates if the receiver declines the use of a default list.
302     */
303    // CHECKSTYLE:OFF
304    public void setDeclineDefaultList(boolean declineDefaultList) {
305        this.declineDefaultList = declineDefaultList;
306    }
307
308    /** 
309     * Returns all the list names the user has defined to group restrictions.
310     * 
311     * @return a Set with Strings containing every list names.
312     */
313    public Set<String> getPrivacyListNames() {
314        return this.itemLists.keySet();
315    }
316    // CHECKSTYLE:ON
317
318    @Override
319    protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder buf) {
320        buf.rightAngleBracket();
321        // CHECKSTYLE:OFF
322
323        // Add the active tag
324        if (this.isDeclineActiveList()) {
325            buf.append("<active/>");
326        } else {
327            if (this.getActiveName() != null) {
328                buf.append("<active name=\"").escape(getActiveName()).append("\"/>");
329            }
330        }
331        // Add the default tag
332        if (this.isDeclineDefaultList()) {
333            buf.append("<default/>");
334        } else {
335            if (this.getDefaultName() != null) {
336                buf.append("<default name=\"").escape(getDefaultName()).append("\"/>");
337            }
338        }
339
340        // Add the list with their privacy items
341        for (Map.Entry<String, List<PrivacyItem>> entry : this.getItemLists().entrySet()) {
342          String listName = entry.getKey();
343          List<PrivacyItem> items = entry.getValue();
344            // Begin the list tag
345            if (items.isEmpty()) {
346                buf.append("<list name=\"").escape(listName).append("\"/>");
347            } else {
348                buf.append("<list name=\"").escape(listName).append("\">");
349            }
350            for (PrivacyItem item : items) {
351                // Append the item xml representation
352                buf.append(item.toXML());
353            }
354            // Close the list tag
355            if (!items.isEmpty()) {
356                buf.append("</list>");
357            }
358        }
359    // CHECKSTYLE:ON
360        return buf;
361    }
362
363}