1/**
2 * $RCSfile$
3 * $Revision$
4 * $Date$
5 *
6 * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 *     http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18package org.jivesoftware.smack.packet;
19
20/**
21 * A privacy item acts a rule that when matched defines if a packet should be blocked or not.
22 *
23 * Privacy Items can handle different kind of blocking communications based on JID, group,
24 * subscription type or globally by:<ul>
25 * <li>Allowing or blocking messages.
26 * <li>Allowing or blocking inbound presence notifications.
27 * <li>Allowing or blocking outbound presence notifications.
28 * <li>Allowing or blocking IQ stanzas.
29 * <li>Allowing or blocking all communications.
30 * </ul>
31 * @author Francisco Vives
32 */
33public class PrivacyItem {
34	/** allow is the action associated with the item, it can allow or deny the communication. */
35	private boolean allow;
36	/** order is a non-negative integer that is unique among all items in the list. */
37    private int order;
38    /** rule hold the kind of communication ([jid|group|subscription]) it will allow or block and
39     * identifier to apply the action.
40     * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
41     * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
42     * in the user's roster.
43     * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
44     * "from", or "none". */
45    private PrivacyRule rule;
46
47    /** blocks incoming IQ stanzas. */
48    private boolean filterIQ = false;
49    /** filterMessage blocks incoming message stanzas. */
50    private boolean filterMessage = false;
51    /** blocks incoming presence notifications. */
52    private boolean filterPresence_in = false;
53    /** blocks outgoing presence notifications. */
54    private boolean filterPresence_out = false;
55
56    /**
57     * Creates a new privacy item.
58     *
59     * @param type the type.
60     */
61    public PrivacyItem(String type, boolean allow, int order) {
62        this.setRule(PrivacyRule.fromString(type));
63        this.setAllow(allow);
64        this.setOrder(order);
65    }
66
67    /**
68     * Returns the action associated with the item, it MUST be filled and will allow or deny
69     * the communication.
70     *
71     * @return the allow communication status.
72     */
73    public boolean isAllow() {
74		return allow;
75	}
76
77    /**
78     * Sets the action associated with the item, it can allow or deny the communication.
79     *
80     * @param allow indicates if the receiver allow or deny the communication.
81     */
82    private void setAllow(boolean allow) {
83		this.allow = allow;
84	}
85
86
87    /**
88     * Returns whether the receiver allow or deny incoming IQ stanzas or not.
89     *
90     * @return the iq filtering status.
91     */
92    public boolean isFilterIQ() {
93		return filterIQ;
94	}
95
96
97    /**
98     * Sets whether the receiver allows or denies incoming IQ stanzas or not.
99     *
100     * @param filterIQ indicates if the receiver allows or denies incoming IQ stanzas.
101     */
102    public void setFilterIQ(boolean filterIQ) {
103		this.filterIQ = filterIQ;
104	}
105
106
107    /**
108     * Returns whether the receiver allows or denies incoming messages or not.
109     *
110     * @return the message filtering status.
111     */
112    public boolean isFilterMessage() {
113		return filterMessage;
114	}
115
116
117    /**
118     * Sets wheather the receiver allows or denies incoming messages or not.
119     *
120     * @param filterMessage indicates if the receiver allows or denies incoming messages or not.
121     */
122    public void setFilterMessage(boolean filterMessage) {
123		this.filterMessage = filterMessage;
124	}
125
126
127    /**
128     * Returns whether the receiver allows or denies incoming presence or not.
129     *
130     * @return the iq filtering incoming presence status.
131     */
132    public boolean isFilterPresence_in() {
133		return filterPresence_in;
134	}
135
136
137    /**
138     * Sets whether the receiver allows or denies incoming presence or not.
139     *
140     * @param filterPresence_in indicates if the receiver allows or denies filtering incoming presence.
141     */
142    public void setFilterPresence_in(boolean filterPresence_in) {
143		this.filterPresence_in = filterPresence_in;
144	}
145
146
147    /**
148     * Returns whether the receiver allows or denies incoming presence or not.
149     *
150     * @return the iq filtering incoming presence status.
151     */
152    public boolean isFilterPresence_out() {
153		return filterPresence_out;
154	}
155
156
157    /**
158     * Sets whether the receiver allows or denies outgoing presence or not.
159     *
160     * @param filterPresence_out indicates if the receiver allows or denies filtering outgoing presence
161     */
162    public void setFilterPresence_out(boolean filterPresence_out) {
163		this.filterPresence_out = filterPresence_out;
164	}
165
166
167    /**
168     * Returns the order where the receiver is processed. List items are processed in
169     * ascending order.
170     *
171     * The order MUST be filled and its value MUST be a non-negative integer
172     * that is unique among all items in the list.
173     *
174     * @return the order number.
175     */
176    public int getOrder() {
177		return order;
178	}
179
180
181    /**
182     * Sets the order where the receiver is processed.
183     *
184     * The order MUST be filled and its value MUST be a non-negative integer
185     * that is unique among all items in the list.
186     *
187     * @param order indicates the order in the list.
188     */
189    public void setOrder(int order) {
190		this.order = order;
191	}
192
193    /**
194     * Sets the element identifier to apply the action.
195     *
196     * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
197     * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
198     * in the user's roster.
199     * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
200     * "from", or "none".
201     *
202     * @param value is the identifier to apply the action.
203     */
204    public void setValue(String value) {
205    	if (!(this.getRule() == null && value == null)) {
206    		this.getRule().setValue(value);
207    	}
208	}
209
210    /**
211     * Returns the type hold the kind of communication it will allow or block.
212     * It MUST be filled with one of these values: jid, group or subscription.
213     *
214     * @return the type of communication it represent.
215     */
216    public Type getType() {
217    	if (this.getRule() == null) {
218    		return null;
219    	} else {
220		return this.getRule().getType();
221    	}
222	}
223
224    /**
225     * Returns the element identifier to apply the action.
226     *
227     * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
228     * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
229     * in the user's roster.
230     * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
231     * "from", or "none".
232     *
233     * @return the identifier to apply the action.
234     */
235    public String getValue() {
236    	if (this.getRule() == null) {
237    		return null;
238    	} else {
239		return this.getRule().getValue();
240    	}
241	}
242
243
244    /**
245     * Returns whether the receiver allows or denies every kind of communication.
246     *
247     * When filterIQ, filterMessage, filterPresence_in and filterPresence_out are not set
248     * the receiver will block all communications.
249     *
250     * @return the all communications status.
251     */
252    public boolean isFilterEverything() {
253		return !(this.isFilterIQ() || this.isFilterMessage() || this.isFilterPresence_in()
254				|| this.isFilterPresence_out());
255	}
256
257
258	private PrivacyRule getRule() {
259		return rule;
260	}
261
262	private void setRule(PrivacyRule rule) {
263		this.rule = rule;
264	}
265	/**
266	 * Answer an xml representation of the receiver according to the RFC 3921.
267	 *
268	 * @return the text xml representation.
269     */
270    public String toXML() {
271        StringBuilder buf = new StringBuilder();
272        buf.append("<item");
273        if (this.isAllow()) {
274        	buf.append(" action=\"allow\"");
275        } else {
276        	buf.append(" action=\"deny\"");
277        }
278        buf.append(" order=\"").append(getOrder()).append("\"");
279        if (getType() != null) {
280            buf.append(" type=\"").append(getType()).append("\"");
281        }
282        if (getValue() != null) {
283            buf.append(" value=\"").append(getValue()).append("\"");
284        }
285        if (isFilterEverything()) {
286        	buf.append("/>");
287        } else {
288        	buf.append(">");
289        	if (this.isFilterIQ()) {
290            	buf.append("<iq/>");
291            }
292        	if (this.isFilterMessage()) {
293            	buf.append("<message/>");
294            }
295        	if (this.isFilterPresence_in()) {
296            	buf.append("<presence-in/>");
297            }
298        	if (this.isFilterPresence_out()) {
299            	buf.append("<presence-out/>");
300            }
301        	buf.append("</item>");
302        }
303        return buf.toString();
304    }
305
306
307    /**
308     * Privacy Rule represents the kind of action to apply.
309     * It holds the kind of communication ([jid|group|subscription]) it will allow or block and
310     * identifier to apply the action.
311     */
312
313	public static class PrivacyRule {
314    	 /**
315    	  * Type defines if the rule is based on JIDs, roster groups or presence subscription types.
316    	  * Available values are: [jid|group|subscription]
317    	  */
318         private Type type;
319         /**
320          * The value hold the element identifier to apply the action.
321          * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
322          * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
323          * in the user's roster.
324          * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
325          * "from", or "none".
326          */
327         private String value;
328
329         /**
330     	 * If the type is "subscription", then the 'value' attribute MUST be one of "both",
331     	 * "to", "from", or "none"
332     	 */
333     	public static final String SUBSCRIPTION_BOTH = "both";
334     	public static final String SUBSCRIPTION_TO = "to";
335     	public static final String SUBSCRIPTION_FROM = "from";
336     	public static final String SUBSCRIPTION_NONE = "none";
337
338         /**
339          * Returns the type constant associated with the String value.
340          */
341         protected static PrivacyRule fromString(String value) {
342             if (value == null) {
343                 return null;
344             }
345             PrivacyRule rule = new PrivacyRule();
346             rule.setType(Type.valueOf(value.toLowerCase()));
347             return rule;
348         }
349
350         /**
351          * Returns the type hold the kind of communication it will allow or block.
352          * It MUST be filled with one of these values: jid, group or subscription.
353          *
354          * @return the type of communication it represent.
355          */
356         public Type getType() {
357     		return type;
358     	}
359
360         /**
361          * Sets the action associated with the item, it can allow or deny the communication.
362          *
363          * @param type indicates if the receiver allows or denies the communication.
364          */
365         private void setType(Type type) {
366     		this.type = type;
367     	}
368
369         /**
370          * Returns the element identifier to apply the action.
371          *
372          * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
373          * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
374          * in the user's roster.
375          * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
376          * "from", or "none".
377          *
378          * @return the identifier to apply the action.
379          */
380         public String getValue() {
381     		return value;
382     	}
383
384         /**
385          * Sets the element identifier to apply the action.
386          *
387          * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
388          * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
389          * in the user's roster.
390          * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
391          * "from", or "none".
392          *
393          * @param value is the identifier to apply the action.
394          */
395         protected void setValue(String value) {
396        	 if (this.isSuscription()) {
397        		 setSuscriptionValue(value);
398        	 } else {
399        		 this.value = value;
400        	 }
401     	}
402
403         /**
404          * Sets the element identifier to apply the action.
405          *
406          * The 'value' attribute MUST be one of "both", "to", "from", or "none".
407          *
408          * @param value is the identifier to apply the action.
409          */
410         private void setSuscriptionValue(String value) {
411        	 String setValue;
412             if (value == null) {
413            	 // Do nothing
414             }
415             if (SUBSCRIPTION_BOTH.equalsIgnoreCase(value)) {
416            	 setValue = SUBSCRIPTION_BOTH;
417             }
418             else if (SUBSCRIPTION_TO.equalsIgnoreCase(value)) {
419            	 setValue = SUBSCRIPTION_TO;
420             }
421             else if (SUBSCRIPTION_FROM.equalsIgnoreCase(value)) {
422            	 setValue = SUBSCRIPTION_FROM;
423             }
424             else if (SUBSCRIPTION_NONE.equalsIgnoreCase(value)) {
425            	 setValue = SUBSCRIPTION_NONE;
426             }
427             // Default to available.
428             else {
429            	 setValue = null;
430             }
431     		this.value = setValue;
432     	}
433
434         /**
435          * Returns if the receiver represents a subscription rule.
436          *
437          * @return if the receiver represents a subscription rule.
438          */
439         public boolean isSuscription () {
440     		return this.getType() == Type.subscription;
441     	}
442    }
443
444    /**
445     * Type defines if the rule is based on JIDs, roster groups or presence subscription types.
446     */
447    public static enum Type {
448        /**
449         * JID being analyzed should belong to a roster group of the list's owner.
450         */
451        group,
452        /**
453         * JID being analyzed should have a resource match, domain match or bare JID match.
454         */
455        jid,
456        /**
457         * JID being analyzed should belong to a contact present in the owner's roster with
458         * the specified subscription status.
459         */
460        subscription
461    }
462}
463