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