001/**
002 *
003 * Copyright the original author or authors
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.Objects;
020
021import org.jivesoftware.smack.datatypes.UInt32;
022
023/**
024 * A privacy item acts a rule that when matched defines if a stanza should be blocked or not.
025 *
026 * Privacy Items can handle different kind of blocking communications based on JID, group,
027 * subscription type or globally by:<ul>
028 * <li>Allowing or blocking messages.
029 * <li>Allowing or blocking inbound presence notifications.
030 * <li>Allowing or blocking outbound presence notifications.
031 * <li>Allowing or blocking IQ stanzas.
032 * <li>Allowing or blocking all communications.
033 * </ul>
034 * @author Francisco Vives
035 */
036public class PrivacyItem {
037    /**
038     * Value for subscription type rules.
039     */
040    public static final String SUBSCRIPTION_BOTH = "both";
041    public static final String SUBSCRIPTION_TO = "to";
042    public static final String SUBSCRIPTION_FROM = "from";
043    public static final String SUBSCRIPTION_NONE = "none";
044
045    /** allow is the action associated with the item, it can allow or deny the communication. */
046    private final boolean allow;
047
048    /**
049     * order is a unsigned 32-bit integer that is unique among all items in the list.
050     **/
051    private final UInt32 order;
052
053    /**
054     * Type defines if the rule is based on JIDs, roster groups or presence subscription types.
055     * Available values are: [jid|group|subscription]
056     */
057    private final Type type;
058
059    /**
060     * The value hold the element identifier to apply the action. If the type is "jid", then the
061     * 'value' attribute MUST contain a valid Jabber ID. If the type is "group", then the
062     * 'value' attribute SHOULD contain the name of a group in the user's roster. If the type is
063     * "subscription", then the 'value' attribute MUST be one of "both", "to", "from", or
064     * "none".
065     */
066    private final String value;
067
068    /** blocks incoming IQ stanzas. */
069    private boolean filterIQ = false;
070    /** filterMessage blocks incoming message stanzas. */
071    private boolean filterMessage = false;
072    /** blocks incoming presence notifications. */
073    private boolean filterPresenceIn = false;
074    /** blocks outgoing presence notifications. */
075    private boolean filterPresenceOut = false;
076
077    public PrivacyItem(boolean allow, long order) {
078        this(null, null, allow, UInt32.from(order));
079    }
080
081    /**
082     * Creates a new fall-through privacy item.
083     *
084     * This is usually the last item in a privacy list and has no 'type' attribute.
085     *
086     * @param allow true if this is an allow item
087     * @param order the order of this privacy item
088     */
089    public PrivacyItem(boolean allow, UInt32 order) {
090        this(null, null, allow, order);
091    }
092
093    public PrivacyItem(Type type, String value, boolean allow, long order) {
094        this(type, value, allow, UInt32.from(order));
095    }
096
097    /**
098     * Creates a new privacy item.
099     *
100     * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
101     * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
102     * in the user's roster.
103     * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
104     * "from", or "none".
105     *
106     * @param type the type.
107     * @param value the value of the privacy item
108     * @param allow true if this is an allow item
109     * @param order the order of this privacy item
110     */
111    public PrivacyItem(Type type, String value, boolean allow, UInt32 order) {
112        this.type = type;
113        this.value = value;
114        this.allow = allow;
115        this.order = Objects.requireNonNull(order);
116    }
117
118    /**
119     * Creates a new privacy item.
120     *
121     * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
122     * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
123     * in the user's roster.
124     * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
125     * "from", or "none".
126     *
127     * @param type the type.
128     * @param value the value of the privacy item
129     * @param allow true if this is an allow item
130     * @param order the order of this privacy item
131     */
132    public PrivacyItem(Type type, CharSequence value, boolean allow, long order) {
133        this(type, value != null ? value.toString() : null, allow, order);
134    }
135
136    /**
137     * Returns the action associated with the item, it MUST be filled and will allow or deny
138     * the communication.
139     *
140     * @return the allow communication status.
141     */
142    public boolean isAllow() {
143        return allow;
144    }
145
146    /**
147     * Returns whether the receiver allow or deny incoming IQ stanzas or not.
148     *
149     * @return the iq filtering status.
150     */
151    public boolean isFilterIQ() {
152        return filterIQ;
153    }
154
155    /**
156     * Sets whether the receiver allows or denies incoming IQ stanzas or not.
157     *
158     * @param filterIQ indicates if the receiver allows or denies incoming IQ stanzas.
159     */
160    public void setFilterIQ(boolean filterIQ) {
161        this.filterIQ = filterIQ;
162    }
163
164    /**
165     * Returns whether the receiver allows or denies incoming messages or not.
166     *
167     * @return the message filtering status.
168     */
169    public boolean isFilterMessage() {
170        return filterMessage;
171    }
172
173    /**
174     * Sets wheather the receiver allows or denies incoming messages or not.
175     *
176     * @param filterMessage indicates if the receiver allows or denies incoming messages or not.
177     */
178    public void setFilterMessage(boolean filterMessage) {
179        this.filterMessage = filterMessage;
180    }
181
182    /**
183     * Returns whether the receiver allows or denies incoming presence or not.
184     *
185     * @return the iq filtering incoming presence status.
186     */
187    public boolean isFilterPresenceIn() {
188        return filterPresenceIn;
189    }
190
191    /**
192     * Sets whether the receiver allows or denies incoming presence or not.
193     *
194     * @param filterPresenceIn indicates if the receiver allows or denies filtering incoming presence.
195     */
196    public void setFilterPresenceIn(boolean filterPresenceIn) {
197        this.filterPresenceIn = filterPresenceIn;
198    }
199
200    /**
201     * Returns whether the receiver allows or denies incoming presence or not.
202     *
203     * @return the iq filtering incoming presence status.
204     */
205    public boolean isFilterPresenceOut() {
206        return filterPresenceOut;
207    }
208
209    /**
210     * Sets whether the receiver allows or denies outgoing presence or not.
211     *
212     * @param filterPresenceOut indicates if the receiver allows or denies filtering outgoing presence
213     */
214    public void setFilterPresenceOut(boolean filterPresenceOut) {
215        this.filterPresenceOut = filterPresenceOut;
216    }
217
218    /**
219     * Returns the order where the receiver is processed. List items are processed in
220     * ascending order.
221     *
222     * The order MUST be filled and its value MUST be a non-negative integer
223     * that is unique among all items in the list.
224     *
225     * @return the order number.
226     */
227    public UInt32 getOrder() {
228        return order;
229    }
230
231    /**
232     * Returns the type hold the kind of communication it will allow or block.
233     * It MUST be filled with one of these values: jid, group or subscription.
234     *
235     * @return the type of communication it represent.
236     */
237    public Type getType() {
238        return type;
239    }
240
241    /**
242     * Returns the element identifier to apply the action.
243     *
244     * If the type is "jid", then the 'value' attribute MUST contain a valid Jabber ID.
245     * If the type is "group", then the 'value' attribute SHOULD contain the name of a group
246     * in the user's roster.
247     * If the type is "subscription", then the 'value' attribute MUST be one of "both", "to",
248     * "from", or "none".
249     *
250     * @return the identifier to apply the action.
251     */
252    public String getValue() {
253        return value;
254    }
255
256    /**
257     * Returns whether the receiver allows or denies every kind of communication.
258     *
259     * When filterIQ, filterMessage, filterPresenceIn and filterPresenceOut are not set
260     * the receiver will block all communications.
261     *
262     * @return the all communications status.
263     */
264    public boolean isFilterEverything() {
265        return !(this.isFilterIQ() || this.isFilterMessage() || this.isFilterPresenceIn()
266                || this.isFilterPresenceOut());
267    }
268
269    /**
270     * Answer an xml representation of the receiver according to the RFC 3921.
271     *
272     * @return the text xml representation.
273     */
274    public String toXML() {
275        StringBuilder buf = new StringBuilder();
276        buf.append("<item");
277        if (this.isAllow()) {
278            buf.append(" action=\"allow\"");
279        } else {
280            buf.append(" action=\"deny\"");
281        }
282        buf.append(" order=\"").append(getOrder()).append('"');
283        if (getType() != null) {
284            buf.append(" type=\"").append(getType()).append('"');
285        }
286        if (getValue() != null) {
287            buf.append(" value=\"").append(getValue()).append('"');
288        }
289        if (isFilterEverything()) {
290            buf.append("/>");
291        } else {
292            buf.append('>');
293            if (this.isFilterIQ()) {
294                buf.append("<iq/>");
295            }
296            if (this.isFilterMessage()) {
297                buf.append("<message/>");
298            }
299            if (this.isFilterPresenceIn()) {
300                buf.append("<presence-in/>");
301            }
302            if (this.isFilterPresenceOut()) {
303                buf.append("<presence-out/>");
304            }
305            buf.append("</item>");
306        }
307        return buf.toString();
308    }
309
310    /**
311     * Type defines if the rule is based on JIDs, roster groups or presence subscription types.
312     */
313    public enum Type {
314        /**
315         * JID being analyzed should belong to a roster group of the list's owner.
316         */
317        group,
318        /**
319         * JID being analyzed should have a resource match, domain match or bare JID match.
320         */
321        jid,
322        /**
323         * JID being analyzed should belong to a contact present in the owner's roster with the
324         * specified subscription status.
325         */
326        subscription
327    }
328}