From c5db012fc80a23cb5e77e7c0fb5da622ca600f75 Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Tue, 20 Jan 2015 09:40:52 +0100 Subject: [PATCH] Improve privacy parsing and API. Add NumberUtil Make 'order' an long Parse fall-through case's child elements (message, iq, presence-in, presence-out) Remove privacy.addExtension(new DefaultPacketExtension(parser.getName(), parser.getNamespace())); at the beginning of PrivacyProvider. Was there since day one for an unknown reason. --- .../jivesoftware/smack/util/NumberUtil.java | 34 +++++++ .../smackx/privacy/packet/PrivacyItem.java | 16 ++-- .../privacy/provider/PrivacyProvider.java | 90 +++++++++++-------- .../packet/ValidateElement.java | 13 +-- .../privacy/provider/PrivacyProviderTest.java | 41 +++++++++ .../DataValidationHelperTest.java | 2 +- 6 files changed, 145 insertions(+), 51 deletions(-) create mode 100644 smack-core/src/main/java/org/jivesoftware/smack/util/NumberUtil.java diff --git a/smack-core/src/main/java/org/jivesoftware/smack/util/NumberUtil.java b/smack-core/src/main/java/org/jivesoftware/smack/util/NumberUtil.java new file mode 100644 index 000000000..8ca973370 --- /dev/null +++ b/smack-core/src/main/java/org/jivesoftware/smack/util/NumberUtil.java @@ -0,0 +1,34 @@ +/** + * + * Copyright © 2015 Florian Schmaus + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.jivesoftware.smack.util; + +public class NumberUtil { + + /** + * Checks if the given long is within the range of an unsigned 32-bit integer, the XML type "xs:unsignedInt". + * + * @param value + */ + public static void checkIfInUInt32Range(long value) { + if (value < 0) { + throw new IllegalArgumentException("unsigned 32-bit integers can't be negative"); + } + if (value > ((1L << 32) - 1)) { + throw new IllegalArgumentException("unsigned 32-bit integers can't be greater then 2^32 - 1"); + } + } +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/privacy/packet/PrivacyItem.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/privacy/packet/PrivacyItem.java index 2b8d2af55..02d138f93 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/privacy/packet/PrivacyItem.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/privacy/packet/PrivacyItem.java @@ -16,6 +16,8 @@ */ package org.jivesoftware.smackx.privacy.packet; +import org.jivesoftware.smack.util.NumberUtil; + /** * A privacy item acts a rule that when matched defines if a packet should be blocked or not. * @@ -40,8 +42,11 @@ public class PrivacyItem { /** allow is the action associated with the item, it can allow or deny the communication. */ private final boolean allow; - /** order is a non-negative integer that is unique among all items in the list. */ - private final int order; + + /** + * order is a unsigned 32-bit integer that is unique among all items in the list. + **/ + private final long order; /** * Type defines if the rule is based on JIDs, roster groups or presence subscription types. @@ -75,7 +80,7 @@ public class PrivacyItem { * @param allow true if this is an allow item * @param order the order of this privacy item */ - public PrivacyItem(boolean allow, int order) { + public PrivacyItem(boolean allow, long order) { this(null, null, allow, order); } @@ -93,7 +98,8 @@ public class PrivacyItem { * @param allow true if this is an allow item * @param order the order of this privacy item */ - public PrivacyItem(Type type, String value, boolean allow, int order) { + public PrivacyItem(Type type, String value, boolean allow, long order) { + NumberUtil.checkIfInUInt32Range(order); this.type = type; this.value = value; this.allow = allow; @@ -191,7 +197,7 @@ public class PrivacyItem { * * @return the order number. */ - public int getOrder() { + public long getOrder() { return order; } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/privacy/provider/PrivacyProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/privacy/provider/PrivacyProvider.java index 8f78dcb8d..89e2159b2 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/privacy/provider/PrivacyProvider.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/privacy/provider/PrivacyProvider.java @@ -16,8 +16,9 @@ */ package org.jivesoftware.smackx.privacy.provider; -import org.jivesoftware.smack.packet.DefaultPacketExtension; +import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.provider.IQProvider; +import org.jivesoftware.smack.util.ParserUtils; import org.jivesoftware.smackx.privacy.packet.Privacy; import org.jivesoftware.smackx.privacy.packet.PrivacyItem; import org.xmlpull.v1.XmlPullParser; @@ -38,11 +39,8 @@ public class PrivacyProvider extends IQProvider { @Override public Privacy parse(XmlPullParser parser, int initialDepth) - throws XmlPullParserException, IOException { + throws XmlPullParserException, IOException, SmackException { Privacy privacy = new Privacy(); - /* privacy.addExtension(PacketParserUtils.parsePacketExtension(parser - .getName(), parser.getNamespace(), parser)); */ - privacy.addExtension(new DefaultPacketExtension(parser.getName(), parser.getNamespace())); boolean done = false; while (!done) { int eventType = parser.next(); @@ -78,7 +76,7 @@ public class PrivacyProvider extends IQProvider { } // Parse the list complex type - public void parseList(XmlPullParser parser, Privacy privacy) throws XmlPullParserException, IOException { + private static void parseList(XmlPullParser parser, Privacy privacy) throws XmlPullParserException, IOException, SmackException { boolean done = false; String listName = parser.getAttributeValue("", "name"); ArrayList items = new ArrayList(); @@ -100,59 +98,73 @@ public class PrivacyProvider extends IQProvider { } // Parse the list complex type - public PrivacyItem parseItem(XmlPullParser parser) throws XmlPullParserException, IOException { - boolean done = false; + private static PrivacyItem parseItem(XmlPullParser parser) throws XmlPullParserException, IOException, SmackException { // Retrieves the required attributes String actionValue = parser.getAttributeValue("", "action"); - String orderValue = parser.getAttributeValue("", "order"); + // Set the order number, this attribute is required + long order = ParserUtils.getLongAttribute(parser, "order"); + + // If type is not set, then it's the fall-through case String type = parser.getAttributeValue("", "type"); /* * According the action value it sets the allow status. The fall-through action is assumed * to be "allow" */ - boolean allow = true; - if ("allow".equalsIgnoreCase(actionValue)) { - allow = true; - } else if ("deny".equalsIgnoreCase(actionValue)) { - allow = false; + boolean allow; + switch (actionValue) { + case "allow": + allow = true; + break; + case "deny": + allow = false; + break; + default: + throw new SmackException("Unkown action value '" + actionValue + "'"); } - // Set the order number - int order = Integer.parseInt(orderValue); PrivacyItem item; if (type != null) { // If the type is not null, then we are dealing with a standard privacy item String value = parser.getAttributeValue("", "value"); item = new PrivacyItem(PrivacyItem.Type.valueOf(type), value, allow, order); - - while (!done) { - int eventType = parser.next(); - if (eventType == XmlPullParser.START_TAG) { - if (parser.getName().equals("iq")) { - item.setFilterIQ(true); - } - if (parser.getName().equals("message")) { - item.setFilterMessage(true); - } - if (parser.getName().equals("presence-in")) { - item.setFilterPresenceIn(true); - } - if (parser.getName().equals("presence-out")) { - item.setFilterPresenceOut(true); - } - } - else if (eventType == XmlPullParser.END_TAG) { - if (parser.getName().equals("item")) { - done = true; - } - } - } } else { // If the type is null, then we are dealing with the fall-through privacy item. item = new PrivacyItem(allow, order); } + parseItemChildElements(parser, item); return item; } + + private static void parseItemChildElements(XmlPullParser parser, PrivacyItem privacyItem) throws XmlPullParserException, IOException { + final int initialDepth = parser.getDepth(); + + outerloop: while (true) { + int eventType = parser.next(); + switch (eventType) { + case XmlPullParser.START_TAG: + String name = parser.getName(); + switch (name) { + case "iq": + privacyItem.setFilterIQ(true); + break; + case "message": + privacyItem.setFilterMessage(true); + break; + case "presence-in": + privacyItem.setFilterPresenceIn(true); + break; + case "presence-out": + privacyItem.setFilterPresenceOut(true); + break; + } + break; + case XmlPullParser.END_TAG: + if (parser.getDepth() == initialDepth) { + break outerloop; + } + } + } + } } diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdatavalidation/packet/ValidateElement.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdatavalidation/packet/ValidateElement.java index 4825077e7..abe765ebb 100644 --- a/smack-extensions/src/main/java/org/jivesoftware/smackx/xdatavalidation/packet/ValidateElement.java +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/xdatavalidation/packet/ValidateElement.java @@ -18,6 +18,7 @@ package org.jivesoftware.smackx.xdatavalidation.packet; import org.jivesoftware.smack.packet.NamedElement; import org.jivesoftware.smack.packet.PacketExtension; +import org.jivesoftware.smack.util.NumberUtil; import org.jivesoftware.smack.util.StringUtils; import org.jivesoftware.smack.util.XmlStringBuilder; import org.jivesoftware.smackx.xdata.FormField; @@ -313,18 +314,18 @@ public abstract class ValidateElement implements PacketExtension { /** * The 'max' attribute specifies the maximum allowable number of selected/entered values. The 'min' attribute - * specifies the minimum allowable number of selected/entered values. Both attributes are optional and must be a - * positive integer. + * specifies the minimum allowable number of selected/entered values. Both attributes are optional, but at + * least one must bet set, and the value must be within the range of a unsigned 32-bit integer. * * @param min * @param max */ public ListRange(Long min, Long max) { - if (min != null && min < 0) { - throw new IllegalArgumentException("min must not be negative"); + if (min != null) { + NumberUtil.checkIfInUInt32Range(min); } - if (max != null && max < 0) { - throw new IllegalArgumentException("max must not be negative"); + if (max != null) { + NumberUtil.checkIfInUInt32Range(max); } if (max == null && min == null) { throw new IllegalArgumentException("Either min or max must be given"); diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/privacy/provider/PrivacyProviderTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/privacy/provider/PrivacyProviderTest.java index 3dc4e01fe..04cdffc63 100644 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/privacy/provider/PrivacyProviderTest.java +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/privacy/provider/PrivacyProviderTest.java @@ -17,6 +17,7 @@ package org.jivesoftware.smackx.privacy.provider; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.List; @@ -62,4 +63,44 @@ public class PrivacyProviderTest extends InitExtensions { assertEquals(true, second.isAllow()); assertEquals(2, second.getOrder()); } + + @Test + public void parsePrivacyListWithFallThroughInclChildElements() throws Exception { + // @formatter:off + final String xmlPrivacyList = + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + "" + + ""; + // @formatter:on + IQ iqPrivacyList = (IQ) PacketParserUtils.parseStanza(xmlPrivacyList); + assertTrue(iqPrivacyList instanceof Privacy); + + Privacy privacyList = (Privacy) iqPrivacyList; + List pl = privacyList.getPrivacyList("public"); + + PrivacyItem first = pl.get(0); + assertEquals(PrivacyItem.Type.jid, first.getType()); + assertEquals("tybalt@example.com", first.getValue()); + assertEquals(false, first.isAllow()); + assertEquals(1, first.getOrder()); + + PrivacyItem second = pl.get(1); + assertTrue(second.isAllow()); + assertEquals(2, second.getOrder()); + assertTrue(second.isFilterMessage()); + assertTrue(second.isFilterPresenceIn()); + assertFalse(second.isFilterPresenceOut()); + assertFalse(second.isFilterIQ()); + } } diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/xdatavalidation/DataValidationHelperTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/xdatavalidation/DataValidationHelperTest.java index 3f28e8dde..e463a6d31 100644 --- a/smack-extensions/src/test/java/org/jivesoftware/smackx/xdatavalidation/DataValidationHelperTest.java +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/xdatavalidation/DataValidationHelperTest.java @@ -54,7 +54,7 @@ public class DataValidationHelperTest { fail("No correct check on consistency"); } catch (IllegalArgumentException e) { - assertEquals("min must not be negative", e.getMessage()); + assertEquals("unsigned 32-bit integers can't be negative", e.getMessage()); } element.setListRange(new ListRange(10L, 100L));