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.provider;
018
019import java.io.IOException;
020import java.util.ArrayList;
021
022import org.jivesoftware.smack.datatypes.UInt32;
023import org.jivesoftware.smack.packet.IqData;
024import org.jivesoftware.smack.packet.XmlEnvironment;
025import org.jivesoftware.smack.provider.IqProvider;
026import org.jivesoftware.smack.util.ParserUtils;
027import org.jivesoftware.smack.xml.XmlPullParser;
028import org.jivesoftware.smack.xml.XmlPullParserException;
029
030import org.jivesoftware.smackx.privacy.packet.Privacy;
031import org.jivesoftware.smackx.privacy.packet.PrivacyItem;
032
033import org.jxmpp.JxmppContext;
034
035/**
036 * The PrivacyProvider parses {@link Privacy} packets. {@link Privacy}
037 * Parses the <code>query</code> sub-document and creates an instance of {@link Privacy}.
038 * For each <code>item</code> in the <code>list</code> element, it creates an instance
039 * of {@link PrivacyItem}.
040 *
041 * @author Francisco Vives
042 */
043public class PrivacyProvider extends IqProvider<Privacy> {
044
045    @Override
046    public Privacy parse(XmlPullParser parser, int initialDepth, IqData iqData, XmlEnvironment xmlEnvironment, JxmppContext jxmppContext)
047                    throws XmlPullParserException, IOException {
048        Privacy privacy = new Privacy();
049        boolean done = false;
050        while (!done) {
051            XmlPullParser.Event eventType = parser.next();
052            if (eventType == XmlPullParser.Event.START_ELEMENT) {
053                // CHECKSTYLE:OFF
054                if (parser.getName().equals("active")) {
055                    String activeName = parser.getAttributeValue("", "name");
056                    if (activeName == null) {
057                        privacy.setDeclineActiveList(true);
058                    } else {
059                        privacy.setActiveName(activeName);
060                    }
061                }
062                else if (parser.getName().equals("default")) {
063                    String defaultName = parser.getAttributeValue("", "name");
064                    if (defaultName == null) {
065                        privacy.setDeclineDefaultList(true);
066                    } else {
067                        privacy.setDefaultName(defaultName);
068                    }
069                }
070                // CHECKSTYLE:ON
071                else if (parser.getName().equals("list")) {
072                    parseList(parser, privacy);
073                }
074            }
075            else if (eventType == XmlPullParser.Event.END_ELEMENT) {
076                if (parser.getName().equals("query")) {
077                    done = true;
078                }
079            }
080        }
081
082        return privacy;
083    }
084
085    // Parse the list complex type
086    private static void parseList(XmlPullParser parser, Privacy privacy) throws XmlPullParserException, IOException {
087        boolean done = false;
088        String listName = parser.getAttributeValue("", "name");
089        ArrayList<PrivacyItem> items = new ArrayList<>();
090        while (!done) {
091            XmlPullParser.Event eventType = parser.next();
092            if (eventType == XmlPullParser.Event.START_ELEMENT) {
093                if (parser.getName().equals("item")) {
094                    // CHECKSTYLE:OFF
095                    items.add(parseItem(parser));
096                    // CHECKSTYLE:ON
097                }
098            }
099            else if (eventType == XmlPullParser.Event.END_ELEMENT) {
100                if (parser.getName().equals("list")) {
101                    done = true;
102                }
103            }
104        }
105
106        privacy.setPrivacyList(listName, items);
107    // CHECKSTYLE:OFF
108    }
109
110    // Parse the list complex type
111    private static PrivacyItem parseItem(XmlPullParser parser) throws XmlPullParserException, IOException {
112    // CHECKSTYLE:ON
113        // Retrieves the required attributes
114        String actionValue = parser.getAttributeValue("", "action");
115        // Set the order number, this attribute is required
116        UInt32 order = ParserUtils.getUInt32Attribute(parser, "order");
117
118        // If type is not set, then it's the fall-through case
119        String type = parser.getAttributeValue("", "type");
120
121        /*
122         * According the action value it sets the allow status. The fall-through action is assumed
123         * to be "allow"
124         */
125        boolean allow;
126        switch (actionValue) {
127        case "allow":
128            allow = true;
129            break;
130        case "deny":
131            allow = false;
132            break;
133        default:
134            // TODO: Should be SmackParsingException.
135            throw new IOException("Unknown action value '" + actionValue + "'");
136        }
137
138        PrivacyItem item;
139        if (type != null) {
140            // If the type is not null, then we are dealing with a standard privacy item
141            String value = parser.getAttributeValue("", "value");
142            item = new PrivacyItem(PrivacyItem.Type.valueOf(type), value, allow, order);
143        }
144        else {
145            // If the type is null, then we are dealing with the fall-through privacy item.
146            item = new PrivacyItem(allow, order);
147        }
148        parseItemChildElements(parser, item);
149        return item;
150    // CHECKSTYLE:OFF
151    }
152    // CHECKSTYLE:ON
153
154    private static void parseItemChildElements(XmlPullParser parser, PrivacyItem privacyItem) throws XmlPullParserException, IOException {
155        final int initialDepth = parser.getDepth();
156
157        outerloop: while (true) {
158            XmlPullParser.Event eventType = parser.next();
159            switch (eventType) {
160            case START_ELEMENT:
161                String name = parser.getName();
162                switch (name) {
163                case "iq":
164                    privacyItem.setFilterIQ(true);
165                    break;
166                case "message":
167                    privacyItem.setFilterMessage(true);
168                    break;
169                case "presence-in":
170                    privacyItem.setFilterPresenceIn(true);
171                    break;
172                case "presence-out":
173                    privacyItem.setFilterPresenceOut(true);
174                    break;
175                }
176                break;
177            case END_ELEMENT:
178                if (parser.getDepth() == initialDepth) {
179                    break outerloop;
180                }
181                break;
182            default:
183                // Catch all for incomplete switch (MissingCasesInEnumSwitch) statement.
184                break;
185            }
186        }
187    }
188}