From c688acaa0f010447b1af675b6e70077e489ce3ed Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Mon, 2 Jan 2017 16:53:31 +0100 Subject: [PATCH] Add XEP-0231: Bits of Binary implementation Fixes SMACK-737 --- documentation/extensions/index.md | 1 + .../org/jivesoftware/smackx/bob/BoBData.java | 90 ++++++++++ .../org/jivesoftware/smackx/bob/BoBHash.java | 102 +++++++++++ .../jivesoftware/smackx/bob/BoBManager.java | 162 ++++++++++++++++++ .../smackx/bob/BoBSaverManager.java | 33 ++++ .../smackx/bob/DefaultBoBSaverManager.java | 46 +++++ .../smackx/bob/element/BoBExtension.java | 96 +++++++++++ .../smackx/bob/element/BoBIQ.java | 101 +++++++++++ .../smackx/bob/element/package-info.java | 24 +++ .../jivesoftware/smackx/bob/package-info.java | 24 +++ .../bob/provider/BoBExtensionProvider.java | 65 +++++++ .../smackx/bob/provider/BoBIQProvider.java | 70 ++++++++ .../smackx/bob/provider/package-info.java | 24 +++ .../extensions.providers | 12 ++ .../smackx/bob/BoBExtensionTest.java | 67 ++++++++ .../jivesoftware/smackx/bob/BoBIQTest.java | 80 +++++++++ 16 files changed, 997 insertions(+) create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBData.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBHash.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBManager.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBSaverManager.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/bob/DefaultBoBSaverManager.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/bob/element/BoBExtension.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/bob/element/BoBIQ.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/bob/element/package-info.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/bob/package-info.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/bob/provider/BoBExtensionProvider.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/bob/provider/BoBIQProvider.java create mode 100644 smack-extensions/src/main/java/org/jivesoftware/smackx/bob/provider/package-info.java create mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/bob/BoBExtensionTest.java create mode 100644 smack-extensions/src/test/java/org/jivesoftware/smackx/bob/BoBIQTest.java diff --git a/documentation/extensions/index.md b/documentation/extensions/index.md index dd2ca5dfb..1cf51a067 100644 --- a/documentation/extensions/index.md +++ b/documentation/extensions/index.md @@ -68,6 +68,7 @@ Smack Extensions and currently supported XEPs of smack-extensions | Delayed Delivery | [XEP-0203](http://xmpp.org/extensions/xep-0203.html) | Extension for communicating the fact that an XML stanza has been delivered with a delay. | | XMPP Over BOSH | [XEP-0206](http://xmpp.org/extensions/xep-0206.html) | Use Bidirectional-streams Over Synchronous HTTP (BOSH) to transport XMPP stanzas. | | Attention | [XEP-0224](http://xmpp.org/extensions/xep-0224.html) | Getting attention of another user. | +| Bits of Binary | [XEP-0231](http://xmpp.org/extensions/xep-0231.html) | Including or referring to small bits of binary data in an XML stanza. | | Last Message Correction | [XEP-0308](http://xmpp.org/extensions/xep-0308.html) | Provides a method for indicating that a message is a correction of the last sent message. | | [Group Chat Invitations](invitation.md) | n/a | Send invitations to other users to join a group chat room. | | [Jive Properties](properties.md) | n/a | TODO | diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBData.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBData.java new file mode 100644 index 000000000..2a8bf9a81 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBData.java @@ -0,0 +1,90 @@ +/** + * + * Copyright 2016 Fernando Ramirez + * + * 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.smackx.bob; + +import java.io.UnsupportedEncodingException; + +import org.jivesoftware.smack.util.stringencoder.Base64; + +/** + * Bits of Binary data class. + * + * @author Fernando Ramirez + * @see XEP-0231: Bits of + * Binary + */ +public class BoBData { + + private final long maxAge; + private final String type; + private final byte[] content; + + /** + * BoB data constructor. + * + * @param maxAge + * @param type + * @param content + */ + public BoBData(long maxAge, String type, byte[] content) { + this.maxAge = maxAge; + this.type = type; + this.content = content; + } + + /** + * Get the max age. + * + * @return the max age + */ + public long getMaxAge() { + return maxAge; + } + + /** + * Get the type. + * + * @return the type + */ + public String getType() { + return type; + } + + /** + * Get the content. + * + * @return the content + */ + public byte[] getContent() { + return content; + } + + /** + * Get the content in a Base64 encoded String. + * + * @return the content in a Base64 encoded String + */ + public String getBase64Encoded() { + byte[] bytes = Base64.encode(content); + try { + return new String(bytes, "UTF-8"); + } catch (UnsupportedEncodingException e) { + throw new IllegalStateException("UTF-8 is not supported."); + } + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBHash.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBHash.java new file mode 100644 index 000000000..3e9b77fda --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBHash.java @@ -0,0 +1,102 @@ +/** + * + * Copyright 2016 Fernando Ramirez + * + * 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.smackx.bob; + +/** + * Bits of Binary hash class. + * + * @author Fernando Ramirez + * @see XEP-0231: Bits of + * Binary + */ +public class BoBHash { + + private final String hash; + private final String hashType; + + /** + * BoB hash constructor. + * + * @param hash + * @param hashType + */ + public BoBHash(String hash, String hashType) { + this.hash = hash; + this.hashType = hashType; + } + + /** + * Get the hash. + * + * @return the hash + */ + public String getHash() { + return hash; + } + + /** + * Get the hash type. + * + * @return the hash type + */ + public String getHashType() { + return hashType; + } + + /** + * BoB hash to src attribute string. + * + * @return src attribute string + */ + public String toSrc() { + return "cid:" + toCid(); + } + + /** + * BoB hash to cid attribute string. + * + * @return cid attribute string + */ + public String toCid() { + return this.hashType + "+" + this.hash + "@bob.xmpp.org"; + } + + /** + * Get BoB hash from src attribute string. + * + * @param src + * @return the BoB hash + */ + public static BoBHash fromSrc(String src) { + String hashType = src.substring(src.lastIndexOf("cid:") + 4, src.indexOf("+")); + String hash = src.substring(src.indexOf("+") + 1, src.indexOf("@bob.xmpp.org")); + return new BoBHash(hash, hashType); + } + + /** + * Get BoB hash from cid attribute string. + * + * @param cid + * @return the BoB hash + */ + public static BoBHash fromCid(String cid) { + String hashType = cid.substring(0, cid.indexOf("+")); + String hash = cid.substring(cid.indexOf("+") + 1, cid.indexOf("@bob.xmpp.org")); + return new BoBHash(hash, hashType); + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBManager.java new file mode 100644 index 000000000..767cee02c --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBManager.java @@ -0,0 +1,162 @@ +/** + * + * Copyright 2016 Fernando Ramirez + * + * 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.smackx.bob; + +import java.util.Map; +import java.util.WeakHashMap; + +import org.jivesoftware.smack.ConnectionCreationListener; +import org.jivesoftware.smack.Manager; +import org.jivesoftware.smack.SmackException.NoResponseException; +import org.jivesoftware.smack.SmackException.NotConnectedException; +import org.jivesoftware.smack.SmackException.NotLoggedInException; +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smack.XMPPConnectionRegistry; +import org.jivesoftware.smack.XMPPException.XMPPErrorException; +import org.jivesoftware.smack.iqrequest.AbstractIqRequestHandler; +import org.jivesoftware.smack.iqrequest.IQRequestHandler.Mode; +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.packet.IQ.Type; +import org.jivesoftware.smackx.bob.element.BoBIQ; +import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; +import org.jxmpp.jid.Jid; + +/** + * Bits of Binary manager class. + * + * @author Fernando Ramirez + * @see XEP-0231: Bits of + * Binary + */ +public final class BoBManager extends Manager { + + public static final String NAMESPACE = "urn:xmpp:bob"; + public static BoBSaverManager bobSaverManager; + + static { + XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() { + @Override + public void connectionCreated(XMPPConnection connection) { + getInstanceFor(connection, bobSaverManager); + } + }); + } + + private static final Map INSTANCES = new WeakHashMap<>(); + + /** + * Get the singleton instance of BoBManager. + * + * @param connection + * @param saverManager + * @return the instance of BoBManager + */ + public static synchronized BoBManager getInstanceFor(XMPPConnection connection, BoBSaverManager saverManager) { + if (saverManager == null) { + bobSaverManager = new DefaultBoBSaverManager(); + } else { + bobSaverManager = saverManager; + } + + BoBManager bobManager = INSTANCES.get(connection); + if (bobManager == null) { + bobManager = new BoBManager(connection); + INSTANCES.put(connection, bobManager); + } + + return bobManager; + } + + private BoBManager(XMPPConnection connection) { + super(connection); + ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(connection); + serviceDiscoveryManager.addFeature(NAMESPACE); + + connection.registerIQRequestHandler( + new AbstractIqRequestHandler(BoBIQ.ELEMENT, BoBIQ.NAMESPACE, Type.get, Mode.sync) { + @Override + public IQ handleIQRequest(IQ iqRequest) { + BoBIQ getBoBIQ = (BoBIQ) iqRequest; + + BoBData bobData = bobSaverManager.getBoB(getBoBIQ.getBoBHash()); + BoBIQ responseBoBIQ = null; + try { + responseBoBIQ = responseBoB(getBoBIQ, bobData); + } catch (NotConnectedException | NotLoggedInException | InterruptedException e) { + } + + return responseBoBIQ; + } + }); + + connection.registerIQRequestHandler( + new AbstractIqRequestHandler(BoBIQ.ELEMENT, BoBIQ.NAMESPACE, Type.result, Mode.sync) { + @Override + public IQ handleIQRequest(IQ iqRequest) { + BoBIQ resultBoBIQ = (BoBIQ) iqRequest; + bobSaverManager.addBoB(resultBoBIQ.getBoBHash(), resultBoBIQ.getBoBData()); + return null; + } + }); + } + + /** + * Returns true if Bits of Binary is supported by the server. + * + * @return true if Bits of Binary is supported by the server. + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + */ + public boolean isSupportedByServer() + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + return ServiceDiscoveryManager.getInstanceFor(connection()).serverSupportsFeature(NAMESPACE); + } + + /** + * Request BoB data. + * + * @param to + * @param bobHash + * @return the BoB data + * @throws NotLoggedInException + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + */ + public BoBData requestBoB(Jid to, BoBHash bobHash) throws NotLoggedInException, NoResponseException, + XMPPErrorException, NotConnectedException, InterruptedException { + BoBIQ requestBoBIQ = new BoBIQ(bobHash); + requestBoBIQ.setType(Type.get); + requestBoBIQ.setTo(to); + + XMPPConnection connection = getAuthenticatedConnectionOrThrow(); + BoBIQ responseBoBIQ = connection.createPacketCollectorAndSend(requestBoBIQ).nextResultOrThrow(); + return responseBoBIQ.getBoBData(); + } + + private BoBIQ responseBoB(BoBIQ requestBoBIQ, BoBData bobData) + throws NotConnectedException, InterruptedException, NotLoggedInException { + BoBIQ responseBoBIQ = new BoBIQ(requestBoBIQ.getBoBHash(), bobData); + responseBoBIQ.setType(Type.result); + responseBoBIQ.setTo(requestBoBIQ.getFrom()); + return responseBoBIQ; + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBSaverManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBSaverManager.java new file mode 100644 index 000000000..a40b3dd34 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/BoBSaverManager.java @@ -0,0 +1,33 @@ +/** + * + * Copyright 2016 Fernando Ramirez + * + * 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.smackx.bob; + +/** + * Bits of Binary Saver Manager interface. + * + * @author Fernando Ramirez + * + */ +public interface BoBSaverManager { + + public void addBoB(BoBHash bobHash, BoBData bobData); + + public void removeBoB(BoBHash bobHash); + + public BoBData getBoB(BoBHash bobHash); + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/DefaultBoBSaverManager.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/DefaultBoBSaverManager.java new file mode 100644 index 000000000..9dc2eb9b8 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/DefaultBoBSaverManager.java @@ -0,0 +1,46 @@ +/** + * + * Copyright 2016 Fernando Ramirez + * + * 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.smackx.bob; + +import java.util.HashMap; + +/** + * Default Bits of Binary Saver Manager class. + * + * @author Fernando Ramirez + * + */ +public class DefaultBoBSaverManager implements BoBSaverManager { + + HashMap bobs = new HashMap<>(); + + @Override + public void addBoB(BoBHash bobHash, BoBData bobData) { + bobs.put(bobHash, bobData); + } + + @Override + public void removeBoB(BoBHash bobHash) { + bobs.remove(bobHash); + } + + @Override + public BoBData getBoB(BoBHash bobHash) { + return bobs.get(bobHash); + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/element/BoBExtension.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/element/BoBExtension.java new file mode 100644 index 000000000..f10ed5489 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/element/BoBExtension.java @@ -0,0 +1,96 @@ +/** + * + * Copyright 2016 Fernando Ramirez + * + * 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.smackx.bob.element; + +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.util.XmlStringBuilder; +import org.jivesoftware.smackx.bob.BoBHash; +import org.jivesoftware.smackx.xhtmlim.XHTMLText; +import org.jivesoftware.smackx.xhtmlim.packet.XHTMLExtension; + +/** + * Bits of Binary extension element. + * + * @author Fernando Ramirez + * @see XEP-0231: Bits of + * Binary + */ +public class BoBExtension extends XHTMLExtension { + + private final BoBHash bobHash; + private final String alt; + private final String paragraph; + + /** + * Bits of Binary extension constructor. + * + * @param bobHash + * @param alt + * @param paragraph + */ + public BoBExtension(BoBHash bobHash, String alt, String paragraph) { + this.bobHash = bobHash; + this.alt = alt; + this.paragraph = paragraph; + } + + /** + * Get the BoB hash. + * + * @return the BoB hash + */ + public BoBHash getBoBHash() { + return bobHash; + } + + /** + * Get the alt field. + * + * @return the alt field + */ + public String getAlt() { + return alt; + } + + @Override + public XmlStringBuilder toXML() { + XmlStringBuilder xml = new XmlStringBuilder(this); + xml.rightAngleBracket(); + + xml.halfOpenElement(Message.BODY); + xml.xmlnsAttribute(XHTMLText.NAMESPACE); + xml.rightAngleBracket(); + + xml.openElement(XHTMLText.P); + xml.optEscape(paragraph); + + xml.halfOpenElement(XHTMLText.IMG); + xml.optAttribute("alt", alt); + xml.attribute("src", bobHash.toSrc()); + xml.closeEmptyElement(); + + xml.closeElement(XHTMLText.P); + xml.closeElement(Message.BODY); + xml.closeElement(this); + return xml; + } + + public static BoBExtension from(Message message) { + return message.getExtension(ELEMENT, NAMESPACE); + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/element/BoBIQ.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/element/BoBIQ.java new file mode 100644 index 000000000..c741a01b9 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/element/BoBIQ.java @@ -0,0 +1,101 @@ +/** + * + * Copyright 2016 Fernando Ramirez + * + * 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.smackx.bob.element; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smackx.bob.BoBData; +import org.jivesoftware.smackx.bob.BoBHash; +import org.jivesoftware.smackx.bob.BoBManager; + +/** + * Bits of Binary IQ class. + * + * @author Fernando Ramirez + * @see XEP-0231: Bits of + * Binary + */ +public class BoBIQ extends IQ { + + /** + * data element. + */ + public static final String ELEMENT = "data"; + + /** + * the IQ NAMESPACE. + */ + public static final String NAMESPACE = BoBManager.NAMESPACE; + + private final BoBHash bobHash; + private final BoBData bobData; + + /** + * Bits of Binary IQ constructor. + * + * @param bobHash + * @param bobData + */ + public BoBIQ(BoBHash bobHash, BoBData bobData) { + super(ELEMENT, NAMESPACE); + this.bobHash = bobHash; + this.bobData = bobData; + } + + /** + * Bits of Binary IQ constructor. + * + * @param bobHash + */ + public BoBIQ(BoBHash bobHash) { + this(bobHash, null); + } + + /** + * Get the BoB hash. + * + * @return the BoB hash + */ + public BoBHash getBoBHash() { + return bobHash; + } + + /** + * Get the BoB data. + * + * @return the BoB data + */ + public BoBData getBoBData() { + return bobData; + } + + @Override + protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) { + xml.attribute("cid", bobHash.toCid()); + + if (bobData != null) { + xml.attribute("max-age", String.valueOf(bobData.getMaxAge())); + xml.attribute("type", bobData.getType()); + xml.rightAngleBracket(); + xml.escape(bobData.getBase64Encoded()); + } else { + xml.setEmptyElement(); + } + + return xml; + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/element/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/element/package-info.java new file mode 100644 index 000000000..fa044be00 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/element/package-info.java @@ -0,0 +1,24 @@ +/** + * + * Copyright 2016 Fernando Ramirez + * + * 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. + */ +/** + * Bits of Binary elements. + * + * @author Fernando Ramirez + * @see XEP-0231: Bits of + * Binary + */ +package org.jivesoftware.smackx.bob.element; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/package-info.java new file mode 100644 index 000000000..1e03acf76 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/package-info.java @@ -0,0 +1,24 @@ +/** + * + * Copyright 2016 Fernando Ramirez + * + * 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. + */ +/** + * Classes and interfaces of Bits of Binary. + * + * @author Fernando Ramirez + * @see XEP-0231: Bits of + * Binary + */ +package org.jivesoftware.smackx.bob; diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/provider/BoBExtensionProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/provider/BoBExtensionProvider.java new file mode 100644 index 000000000..a8d83b598 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/provider/BoBExtensionProvider.java @@ -0,0 +1,65 @@ +/** + * + * Copyright 2016 Fernando Ramirez + * + * 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.smackx.bob.provider; + +import org.jivesoftware.smack.provider.ExtensionElementProvider; +import org.jivesoftware.smackx.bob.BoBHash; +import org.jivesoftware.smackx.bob.element.BoBExtension; +import org.jivesoftware.smackx.xhtmlim.XHTMLText; +import org.xmlpull.v1.XmlPullParser; + +/** + * Bits of Binary extension provider class. + * + * @author Fernando Ramirez + * @see XEP-0231: Bits of + * Binary + */ +public class BoBExtensionProvider extends ExtensionElementProvider { + + @Override + public BoBExtension parse(XmlPullParser parser, int initialDepth) throws Exception { + BoBHash bobHash = null; + String alt = null; + + outerloop: while (true) { + int eventType = parser.next(); + + switch (eventType) { + + case XmlPullParser.START_TAG: + if (parser.getName().equals(XHTMLText.IMG)) { + alt = parser.getAttributeValue("", "alt"); + + String src = parser.getAttributeValue("", "src"); + bobHash = BoBHash.fromSrc(src); + } + break; + + case XmlPullParser.END_TAG: + if (parser.getDepth() == initialDepth) { + break outerloop; + } + break; + + } + } + + return new BoBExtension(bobHash, alt, null); + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/provider/BoBIQProvider.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/provider/BoBIQProvider.java new file mode 100644 index 000000000..099defe7a --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/provider/BoBIQProvider.java @@ -0,0 +1,70 @@ +/** + * + * Copyright 2016 Fernando Ramirez + * + * 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.smackx.bob.provider; + +import org.jivesoftware.smack.provider.IQProvider; +import org.jivesoftware.smack.util.stringencoder.Base64; +import org.jivesoftware.smackx.bob.BoBData; +import org.jivesoftware.smackx.bob.BoBHash; +import org.jivesoftware.smackx.bob.element.BoBIQ; +import org.xmlpull.v1.XmlPullParser; + +/** + * Bits of Binary IQ provider class. + * + * @author Fernando Ramirez + * @see XEP-0231: Bits of + * Binary + */ +public class BoBIQProvider extends IQProvider { + + @Override + public BoBIQ parse(XmlPullParser parser, int initialDepth) throws Exception { + BoBHash bobHash = null; + BoBData bobData = null; + + parser.next(); + + if (parser.getName().equals(BoBIQ.ELEMENT)) { + String cid = parser.getAttributeValue("", "cid"); + bobHash = BoBHash.fromCid(cid); + + String dataType = parser.getAttributeValue("", "type"); + String maxAgeString = parser.getAttributeValue("", "max-age"); + + long maxAge = 0; + if (maxAgeString != null) { + maxAge = Long.parseLong(maxAgeString); + } + + String base64EncodedData = null; + try { + base64EncodedData = parser.nextText(); + } catch (Exception e) { + } + + if (base64EncodedData != null && dataType != null) { + byte[] base64EncodedDataBytes = base64EncodedData.getBytes(); + bobData = new BoBData(maxAge, dataType, Base64.decode(base64EncodedDataBytes)); + } + + } + + return new BoBIQ(bobHash, bobData); + } + +} diff --git a/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/provider/package-info.java b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/provider/package-info.java new file mode 100644 index 000000000..31d133038 --- /dev/null +++ b/smack-extensions/src/main/java/org/jivesoftware/smackx/bob/provider/package-info.java @@ -0,0 +1,24 @@ +/** + * + * Copyright 2016 Fernando Ramirez + * + * 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. + */ +/** + * Bits of Binary providers. + * + * @author Fernando Ramirez + * @see XEP-0231: Bits of + * Binary + */ +package org.jivesoftware.smackx.bob.provider; diff --git a/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers b/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers index a8267f785..7fde63c7b 100644 --- a/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers +++ b/smack-extensions/src/main/resources/org.jivesoftware.smack.extensions/extensions.providers @@ -537,4 +537,16 @@ org.jivesoftware.smackx.blocking.provider.BlockedErrorExtensionProvider + + + html + http://jabber.org/protocol/xhtml-im + org.jivesoftware.smackx.bob.provider.BoBExtensionProvider + + + data + urn:xmpp:bob + org.jivesoftware.smackx.bob.provider.BoBIQProvider + + diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/bob/BoBExtensionTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/bob/BoBExtensionTest.java new file mode 100644 index 000000000..eedfb9703 --- /dev/null +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/bob/BoBExtensionTest.java @@ -0,0 +1,67 @@ +/** + * + * Copyright 2016 Fernando Ramirez + * + * 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.smackx.bob; + +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Message.Type; +import org.jivesoftware.smack.util.PacketParserUtils; +import org.jivesoftware.smackx.bob.element.BoBExtension; +import org.jivesoftware.smackx.bob.provider.BoBExtensionProvider; +import org.junit.Assert; +import org.junit.Test; +import org.jxmpp.jid.impl.JidCreate; +import org.xmlpull.v1.XmlPullParser; + +public class BoBExtensionTest { + + String sampleMessageWithBoBExtension = "" + + "Yet here's a spot." + "" + + "" + + "A spot" + "" + + "" + ""; + + String sampleBoBExtension = "" + + "" + + "A spot" + "" + + ""; + + @Test + public void checkBoBMessageExtension() throws Exception { + Message message = (Message) PacketParserUtils.parseStanza(sampleMessageWithBoBExtension); + + BoBHash bobHash = new BoBHash("8f35fef110ffc5df08d579a50083ff9308fb6242", "sha1"); + + Message createdMessage = new Message(JidCreate.from("macbeth@chat.shakespeare.lit")); + createdMessage.setStanzaId("sarasa"); + createdMessage.setType(Type.groupchat); + createdMessage.setBody("Yet here's a spot."); + createdMessage.addExtension(new BoBExtension(bobHash, "A spot", null)); + + Assert.assertEquals(message.toXML().toString(), createdMessage.toXML().toString()); + } + + @Test + public void checkBoBExtensionProvider() throws Exception { + XmlPullParser parser = PacketParserUtils.getParserFor(sampleBoBExtension); + BoBExtension bobExtension = new BoBExtensionProvider().parse(parser); + + Assert.assertEquals("A spot", bobExtension.getAlt()); + Assert.assertEquals("sha1", bobExtension.getBoBHash().getHashType()); + Assert.assertEquals("8f35fef110ffc5df08d579a50083ff9308fb6242", bobExtension.getBoBHash().getHash()); + } + +} diff --git a/smack-extensions/src/test/java/org/jivesoftware/smackx/bob/BoBIQTest.java b/smack-extensions/src/test/java/org/jivesoftware/smackx/bob/BoBIQTest.java new file mode 100644 index 000000000..337018e03 --- /dev/null +++ b/smack-extensions/src/test/java/org/jivesoftware/smackx/bob/BoBIQTest.java @@ -0,0 +1,80 @@ +/** + * + * Copyright 2016 Fernando Ramirez + * + * 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.smackx.bob; + +import org.jivesoftware.smack.packet.IQ.Type; +import org.jivesoftware.smack.test.util.SmackTestSuite; +import org.jivesoftware.smack.util.PacketParserUtils; +import org.jivesoftware.smackx.bob.element.BoBIQ; +import org.jivesoftware.smackx.bob.provider.BoBIQProvider; +import org.junit.Assert; +import org.junit.Test; +import org.jxmpp.jid.impl.JidCreate; +import org.xmlpull.v1.XmlPullParser; + +public class BoBIQTest extends SmackTestSuite { + + String sampleBoBIQRequest = "" + + "" + ""; + + String sampleBoBIQResponse = "" + + "" + "c2FyYXNhZGUyMzU0ajI=" + "" + ""; + + @Test + public void checkBoBIQRequest() throws Exception { + XmlPullParser parser = PacketParserUtils.getParserFor(sampleBoBIQRequest); + BoBIQ bobIQ = new BoBIQProvider().parse(parser); + bobIQ.setStanzaId("sarasa"); + bobIQ.setTo(JidCreate.from("ladymacbeth@shakespeare.lit/castle")); + bobIQ.setType(Type.get); + + BoBHash bobHash = new BoBHash("8f35fef110ffc5df08d579a50083ff9308fb6242", "sha1"); + + BoBIQ createdBoBIQ = new BoBIQ(bobHash); + createdBoBIQ.setStanzaId("sarasa"); + createdBoBIQ.setTo(JidCreate.from("ladymacbeth@shakespeare.lit/castle")); + createdBoBIQ.setType(Type.get); + + Assert.assertEquals(sampleBoBIQRequest, createdBoBIQ.toXML().toString()); + } + + @Test + public void checkBoBIQResponse() throws Exception { + XmlPullParser parser = PacketParserUtils.getParserFor(sampleBoBIQResponse); + BoBIQ bobIQ = new BoBIQProvider().parse(parser); + bobIQ.setStanzaId("sarasa"); + bobIQ.setTo(JidCreate.from("doctor@shakespeare.lit/pda")); + bobIQ.setType(Type.result); + + BoBHash bobHash = new BoBHash("8f35fef110ffc5df08d579a50083ff9308fb6242", "sha1"); + BoBData bobData = new BoBData(86400, "image/png", "sarasade2354j2".getBytes()); + + BoBIQ createdBoBIQ = new BoBIQ(bobHash, bobData); + createdBoBIQ.setStanzaId("sarasa"); + createdBoBIQ.setTo(JidCreate.from("doctor@shakespeare.lit/pda")); + createdBoBIQ.setType(Type.result); + + Assert.assertEquals(bobIQ.getBoBHash().getHash(), createdBoBIQ.getBoBHash().getHash()); + Assert.assertEquals(bobIQ.getBoBHash().getHashType(), createdBoBIQ.getBoBHash().getHashType()); + Assert.assertEquals(bobIQ.getBoBData().getMaxAge(), createdBoBIQ.getBoBData().getMaxAge()); + Assert.assertEquals(bobIQ.getBoBData().getType(), createdBoBIQ.getBoBData().getType()); + Assert.assertEquals(bobIQ.getBoBData().getBase64Encoded(), createdBoBIQ.getBoBData().getBase64Encoded()); + Assert.assertEquals(bobIQ.toXML().toString(), createdBoBIQ.toXML().toString()); + } + +}