diff --git a/documentation/extensions/index.md b/documentation/extensions/index.md index 28c556c14..274951a34 100644 --- a/documentation/extensions/index.md +++ b/documentation/extensions/index.md @@ -85,6 +85,7 @@ Experimental Smack Extensions and currently supported XEPs of smack-experimental | [Internet of Things - Discovery](iot.md) | [XEP-0347](http://xmpp.org/extensions/xep-0347.html) | Describes how Things can be installed and discovered by their owners. | | Google GCM JSON payload | n/a | Semantically the same as XEP-0335: JSON Containers | | Client State Indication | [XEP-0352](http://xmpp.org/extensions/xep-0352.html) | A way for the client to indicate its active/inactive state. | +| Message Archive Management | [XEP-0313](http://xmpp.org/extensions/xep-0313.html) | Query and control an archive of messages stored on a server. | Legacy Smack Extensions and currently supported XEPs of smack-legacy diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java new file mode 100644 index 000000000..06e2d3dd4 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/MamManager.java @@ -0,0 +1,561 @@ +/** + * + * Copyright © 2016 Florian Schmaus and 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.mam; + +import java.util.ArrayList; +import java.util.Date; +import java.util.List; +import java.util.Map; +import java.util.UUID; +import java.util.WeakHashMap; + +import org.jivesoftware.smack.ConnectionCreationListener; +import org.jivesoftware.smack.Manager; +import org.jivesoftware.smack.PacketCollector; +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.filter.IQReplyFilter; +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.packet.IQ.Type; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; +import org.jivesoftware.smackx.forward.packet.Forwarded; +import org.jivesoftware.smackx.mam.element.MamElements; +import org.jivesoftware.smackx.mam.element.MamFinIQ; +import org.jivesoftware.smackx.mam.element.MamPrefsIQ; +import org.jivesoftware.smackx.mam.element.MamQueryIQ; +import org.jivesoftware.smackx.mam.filter.MamResultFilter; +import org.jivesoftware.smackx.rsm.packet.RSMSet; +import org.jivesoftware.smackx.xdata.FormField; +import org.jivesoftware.smackx.xdata.packet.DataForm; +import org.jxmpp.jid.Jid; +import org.jxmpp.util.XmppDateTime; + +/** + * Message Archive Management Manager class. + * + * @see XEP-0313: Message + * Archive Management + * @author Fernando Ramirez and Florian Schmaus + * + */ +public final class MamManager extends Manager { + + static { + XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() { + @Override + public void connectionCreated(XMPPConnection connection) { + getInstanceFor(connection); + } + }); + } + + private static final Map INSTANCES = new WeakHashMap<>(); + + /** + * Get the singleton instance of MamManager. + * + * @param connection + * @return the instance of MamManager + */ + public static synchronized MamManager getInstanceFor(XMPPConnection connection) { + MamManager mamManager = INSTANCES.get(connection); + + if (mamManager == null) { + mamManager = new MamManager(connection); + INSTANCES.put(connection, mamManager); + } + + return mamManager; + } + + private MamManager(XMPPConnection connection) { + super(connection); + } + + /** + * Query archive with a maximum amount of results. + * + * @param max + * @return the MAM query result + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NotLoggedInException + */ + public MamQueryResult queryArchive(Integer max) throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, NotLoggedInException { + return queryArchive(max, null, null, null, null); + } + + /** + * Query archive with a JID (only messages from/to the JID). + * + * @param withJid + * @return the MAM query result + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NotLoggedInException + */ + public MamQueryResult queryArchive(Jid withJid) throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, NotLoggedInException { + return queryArchive(null, null, null, withJid, null); + } + + /** + * Query archive filtering by start and/or end date. If start == null, the + * value of 'start' will be equal to the date/time of the earliest message + * stored in the archive. If end == null, the value of 'end' will be equal + * to the date/time of the most recent message stored in the archive. + * + * @param start + * @param end + * @return the MAM query result + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NotLoggedInException + */ + public MamQueryResult queryArchive(Date start, Date end) throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, NotLoggedInException { + return queryArchive(null, start, end, null, null); + } + + /** + * Query Archive adding filters with additional fields. + * + * @param additionalFields + * @return the MAM query result + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NotLoggedInException + */ + public MamQueryResult queryArchive(List additionalFields) throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, NotLoggedInException { + return queryArchive(null, null, null, null, additionalFields); + } + + /** + * Query archive filtering by start date. The value of 'end' will be equal + * to the date/time of the most recent message stored in the archive. + * + * @param start + * @return the MAM query result + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NotLoggedInException + */ + public MamQueryResult queryArchiveWithStartDate(Date start) throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, NotLoggedInException { + return queryArchive(null, start, null, null, null); + } + + /** + * Query archive filtering by end date. The value of 'start' will be equal + * to the date/time of the earliest message stored in the archive. + * + * @param end + * @return the MAM query result + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NotLoggedInException + */ + public MamQueryResult queryArchiveWithEndDate(Date end) throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, NotLoggedInException { + return queryArchive(null, null, end, null, null); + } + + /** + * Query archive applying filters: max count, start date, end date, from/to + * JID and with additional fields. + * + * @param max + * @param start + * @param end + * @param withJid + * @param additionalFields + * @return the MAM query result + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NotLoggedInException + */ + public MamQueryResult queryArchive(Integer max, Date start, Date end, Jid withJid, List additionalFields) + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, + NotLoggedInException { + DataForm dataForm = null; + String queryId = UUID.randomUUID().toString(); + + if (start != null || end != null || withJid != null || additionalFields != null) { + dataForm = getNewMamForm(); + addStart(start, dataForm); + addEnd(end, dataForm); + addWithJid(withJid, dataForm); + addAdditionalFields(additionalFields, dataForm); + } + + MamQueryIQ mamQueryIQ = prepareMamQueryIQSet(dataForm, queryId); + addResultsLimit(max, mamQueryIQ); + return queryArchive(mamQueryIQ); + } + + private static void addAdditionalFields(List additionalFields, DataForm dataForm) { + if (additionalFields == null) { + return; + } + for (FormField formField : additionalFields) { + dataForm.addField(formField); + } + } + + private static void addResultsLimit(Integer max, MamQueryIQ mamQueryIQ) { + if (max == null) { + return; + } + RSMSet rsmSet = new RSMSet(max); + mamQueryIQ.addExtension(rsmSet); + + } + + private static void addWithJid(Jid withJid, DataForm dataForm) { + if (withJid == null) { + return; + } + FormField formField = new FormField("with"); + formField.addValue(withJid.toString()); + dataForm.addField(formField); + } + + private static void addEnd(Date end, DataForm dataForm) { + if (end == null) { + return; + } + FormField formField = new FormField("end"); + formField.addValue(XmppDateTime.formatXEP0082Date(end)); + dataForm.addField(formField); + } + + private static void addStart(Date start, DataForm dataForm) { + if (start == null) { + return; + } + FormField formField = new FormField("start"); + formField.addValue(XmppDateTime.formatXEP0082Date(start)); + dataForm.addField(formField); + } + + private void preparePageQuery(MamQueryIQ mamQueryIQ, RSMSet rsmSet) { + mamQueryIQ.setType(IQ.Type.set); + mamQueryIQ.addExtension(rsmSet); + } + + /** + * Returns a page of the archive. + * + * @param dataForm + * @param rsmSet + * @return the MAM query result + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NotLoggedInException + */ + public MamQueryResult page(DataForm dataForm, RSMSet rsmSet) throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, NotLoggedInException { + MamQueryIQ mamQueryIQ = new MamQueryIQ(UUID.randomUUID().toString(), dataForm); + preparePageQuery(mamQueryIQ, rsmSet); + return queryArchive(mamQueryIQ); + } + + /** + * Returns the next page of the archive. + * + * @param mamQueryResult + * is the previous query result + * @param count + * is the amount of messages that a page contains + * @return the MAM query result + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NotLoggedInException + */ + public MamQueryResult pageNext(MamQueryResult mamQueryResult, int count) throws NoResponseException, + XMPPErrorException, NotConnectedException, InterruptedException, NotLoggedInException { + RSMSet previousResultRsmSet = mamQueryResult.mamFin.getRSMSet(); + RSMSet requestRsmSet = new RSMSet(count, previousResultRsmSet.getLast(), RSMSet.PageDirection.after); + return page(mamQueryResult.form, requestRsmSet); + } + + /** + * Obtain page before the first message saved (specific chat). + * + * @param chatJid + * @param firstMessageId + * @param max + * @return the MAM query result + * @throws XMPPErrorException + * @throws NotLoggedInException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NoResponseException + */ + public MamQueryResult pageBefore(Jid chatJid, String firstMessageId, int max) throws XMPPErrorException, + NotLoggedInException, NotConnectedException, InterruptedException, NoResponseException { + RSMSet rsmSet = new RSMSet(null, firstMessageId, -1, -1, null, max, null, -1); + DataForm dataForm = getNewMamForm(); + addWithJid(chatJid, dataForm); + return page(dataForm, rsmSet); + } + + /** + * Obtain page after the last message saved (specific chat). + * + * @param chatJid + * @param lastMessageId + * @param max + * @return the MAM query result + * @throws XMPPErrorException + * @throws NotLoggedInException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NoResponseException + */ + public MamQueryResult pageAfter(Jid chatJid, String lastMessageId, int max) throws XMPPErrorException, + NotLoggedInException, NotConnectedException, InterruptedException, NoResponseException { + RSMSet rsmSet = new RSMSet(lastMessageId, null, -1, -1, null, max, null, -1); + DataForm dataForm = getNewMamForm(); + addWithJid(chatJid, dataForm); + return page(dataForm, rsmSet); + } + + /** + * Get the form fields supported by the server. + * + * @return the list of form fields. + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NotLoggedInException + */ + public List retrieveFormFields() throws NoResponseException, XMPPErrorException, NotConnectedException, + InterruptedException, NotLoggedInException { + String queryId = UUID.randomUUID().toString(); + MamQueryIQ mamQueryIQ = prepareMamQueryIQGet(queryId); + return queryFormFields(mamQueryIQ); + } + + private MamQueryIQ prepareMamQueryIQSet(DataForm dataForm, String queryId) { + MamQueryIQ mamQueryIQ = new MamQueryIQ(queryId, dataForm); + mamQueryIQ.setType(IQ.Type.set); + return mamQueryIQ; + } + + private MamQueryIQ prepareMamQueryIQGet(String queryId) { + MamQueryIQ mamQueryIQ = new MamQueryIQ(queryId, null); + mamQueryIQ.setType(IQ.Type.get); + return mamQueryIQ; + } + + private MamQueryResult queryArchive(MamQueryIQ mamQueryIq) throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, NotLoggedInException { + final XMPPConnection connection = getAuthenticatedConnectionOrThrow(); + MamFinIQ mamFinIQ = null; + + PacketCollector mamFinIQCollector = connection.createPacketCollector(new IQReplyFilter(mamQueryIq, connection)); + + PacketCollector.Configuration resultCollectorConfiguration = PacketCollector.newConfiguration() + .setStanzaFilter(new MamResultFilter(mamQueryIq)).setCollectorToReset(mamFinIQCollector); + PacketCollector resultCollector = connection.createPacketCollector(resultCollectorConfiguration); + + try { + connection.sendStanza(mamQueryIq); + mamFinIQ = mamFinIQCollector.nextResultOrThrow(); + } finally { + mamFinIQCollector.cancel(); + resultCollector.cancel(); + } + + List forwardedMessages = new ArrayList<>(resultCollector.getCollectedCount()); + + for (Message resultMessage = resultCollector + .pollResult(); resultMessage != null; resultMessage = resultCollector.pollResult()) { + MamElements.MamResultExtension mamResultExtension = MamElements.MamResultExtension.from(resultMessage); + forwardedMessages.add(mamResultExtension.getForwarded()); + } + + return new MamQueryResult(forwardedMessages, mamFinIQ, DataForm.from(mamQueryIq)); + } + + /** + * MAM query result class. + * + */ + public final static class MamQueryResult { + public final List forwardedMessages; + public final MamFinIQ mamFin; + private final DataForm form; + + private MamQueryResult(List forwardedMessages, MamFinIQ mamFin, DataForm form) { + this.forwardedMessages = forwardedMessages; + this.mamFin = mamFin; + this.form = form; + } + } + + private List queryFormFields(MamQueryIQ mamQueryIq) throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, NotLoggedInException { + final XMPPConnection connection = connection(); + MamQueryIQ mamResponseQueryIQ = null; + PacketCollector mamResponseQueryIQCollector = connection + .createPacketCollector(new IQReplyFilter(mamQueryIq, connection)); + + try { + connection.sendStanza(mamQueryIq); + mamResponseQueryIQ = mamResponseQueryIQCollector.nextResultOrThrow(); + } finally { + mamResponseQueryIQCollector.cancel(); + } + + return mamResponseQueryIQ.getDataForm().getFields(); + } + + /** + * Returns true if Message Archive Management is supported by the server. + * + * @return true if Message Archive Management is supported by the server. + * @throws NotConnectedException + * @throws XMPPErrorException + * @throws NoResponseException + * @throws InterruptedException + */ + public boolean isSupportedByServer() + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { + return ServiceDiscoveryManager.getInstanceFor(connection()).serverSupportsFeature(MamElements.NAMESPACE); + } + + private DataForm getNewMamForm() { + FormField field = new FormField(FormField.FORM_TYPE); + field.setType(FormField.Type.hidden); + field.addValue(MamElements.NAMESPACE); + DataForm form = new DataForm(DataForm.Type.submit); + form.addField(field); + return form; + } + + /** + * Get the preferences stored in the server. + * + * @return the MAM preferences result + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NotLoggedInException + */ + public MamPrefsResult retrieveArchivingPreferences() throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, NotLoggedInException { + MamPrefsIQ mamPrefIQ = prepareRetrievePreferencesStanza(); + return queryMamPrefs(mamPrefIQ); + } + + private MamPrefsIQ prepareRetrievePreferencesStanza() { + MamPrefsIQ mamPrefIQ = new MamPrefsIQ(Type.get, null, null, null); + return mamPrefIQ; + } + + /** + * Update the preferences in the server. + * + * @param alwaysJids + * is the list of JIDs that should always have messages to/from + * archived in the user's store + * @param neverJids + * is the list of JIDs that should never have messages to/from + * archived in the user's store + * @param defaultField + * can be "roster", "always", "never" (look at the XEP-0313 + * documentation) + * @return the MAM preferences result + * @throws NoResponseException + * @throws XMPPErrorException + * @throws NotConnectedException + * @throws InterruptedException + * @throws NotLoggedInException + */ + public MamPrefsResult updateArchivingPreferences(List alwaysJids, List neverJids, String defaultField) + throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, + NotLoggedInException { + MamPrefsIQ mamPrefIQ = prepareUpdatePreferencesStanza(alwaysJids, neverJids, defaultField); + return queryMamPrefs(mamPrefIQ); + } + + private MamPrefsIQ prepareUpdatePreferencesStanza(List alwaysJids, List neverJids, String defaultField) { + MamPrefsIQ mamPrefIQ = new MamPrefsIQ(Type.set, alwaysJids, neverJids, defaultField); + return mamPrefIQ; + } + + /** + * MAM preferences result class. + * + */ + public final static class MamPrefsResult { + public final MamPrefsIQ mamPrefs; + public final DataForm form; + + private MamPrefsResult(MamPrefsIQ mamPrefs, DataForm form) { + this.mamPrefs = mamPrefs; + this.form = form; + } + } + + private MamPrefsResult queryMamPrefs(MamPrefsIQ mamPrefsIQ) throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, NotLoggedInException { + final XMPPConnection connection = getAuthenticatedConnectionOrThrow(); + MamPrefsIQ mamPrefsResultIQ = null; + PacketCollector prefsResultIQCollector = connection + .createPacketCollector(new IQReplyFilter(mamPrefsIQ, connection)); + + try { + connection.sendStanza(mamPrefsIQ); + mamPrefsResultIQ = prefsResultIQCollector.nextResultOrThrow(); + } finally { + prefsResultIQCollector.cancel(); + } + + return new MamPrefsResult(mamPrefsResultIQ, DataForm.from(mamPrefsIQ)); + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/MamElements.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/MamElements.java new file mode 100644 index 000000000..72e57e93d --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/MamElements.java @@ -0,0 +1,215 @@ +/** + * + * Copyright © 2016 Florian Schmaus and 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.mam.element; + +import java.util.List; + +import org.jivesoftware.smack.packet.Element; +import org.jivesoftware.smack.packet.ExtensionElement; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.util.StringUtils; +import org.jivesoftware.smack.util.XmlStringBuilder; +import org.jivesoftware.smackx.forward.packet.Forwarded; +import org.jxmpp.jid.Jid; + +/** + * MAM elements. + * + * @see XEP-0313: Message + * Archive Management + * @author Fernando Ramirez and Florian Schmaus + * + */ +public class MamElements { + + public static final String NAMESPACE = "urn:xmpp:mam:1"; + + /** + * MAM result extension class. + * + * @see XEP-0313: Message + * Archive Management + * + */ + public static class MamResultExtension implements ExtensionElement { + + /** + * result element. + */ + public static final String ELEMENT = "result"; + + /** + * id of the result. + */ + private final String id; + + /** + * the forwarded element. + */ + private final Forwarded forwarded; + + /** + * the query id. + */ + private String queryId; + + /** + * MAM result extension constructor. + * + * @param queryId + * @param id + * @param forwarded + */ + public MamResultExtension(String queryId, String id, Forwarded forwarded) { + if (StringUtils.isEmpty(id)) { + throw new IllegalArgumentException("id must not be null or empty"); + } + if (forwarded == null) { + throw new IllegalArgumentException("forwarded must no be null"); + } + this.id = id; + this.forwarded = forwarded; + this.queryId = queryId; + } + + /** + * Get the id. + * + * @return the id + */ + public String getId() { + return id; + } + + /** + * Get the forwarded element. + * + * @return the forwarded element + */ + public Forwarded getForwarded() { + return forwarded; + } + + /** + * Get query id. + * + * @return the query id + */ + public final String getQueryId() { + return queryId; + } + + @Override + public String getElementName() { + return ELEMENT; + } + + @Override + public final String getNamespace() { + return NAMESPACE; + } + + @Override + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(); + xml.halfOpenElement(this); + xml.xmlnsAttribute(NAMESPACE); + xml.optAttribute("queryid", getQueryId()); + xml.optAttribute("id", getId()); + xml.rightAngleBracket(); + + xml.element(getForwarded()); + + xml.closeElement(this); + return xml; + } + + public static MamResultExtension from(Message message) { + return (MamResultExtension) message.getExtension(ELEMENT, NAMESPACE); + } + + } + + /** + * Always JID list element class for the MamPrefsIQ. + * + */ + public static class AlwaysJidListElement implements Element { + + /** + * list of JIDs. + */ + private List alwaysJids; + + /** + * Always JID list element constructor. + * + * @param alwaysJids + */ + AlwaysJidListElement(List alwaysJids) { + this.alwaysJids = alwaysJids; + } + + @Override + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(); + xml.openElement("always"); + + for (Jid jid : alwaysJids) { + xml.element("jid", jid); + } + + xml.closeElement("always"); + return xml; + } + } + + /** + * Never JID list element class for the MamPrefsIQ. + * + */ + public static class NeverJidListElement implements Element { + + /** + * list of JIDs + */ + private List neverJids; + + /** + * Never JID list element constructor. + * + * @param neverJids + */ + public NeverJidListElement(List neverJids) { + this.neverJids = neverJids; + } + + @Override + public CharSequence toXML() { + XmlStringBuilder xml = new XmlStringBuilder(); + xml.openElement("never"); + + for (Jid jid : neverJids) { + xml.element("jid", jid); + } + + xml.closeElement("never"); + return xml; + } + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/MamFinIQ.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/MamFinIQ.java new file mode 100644 index 000000000..4b8a61de8 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/MamFinIQ.java @@ -0,0 +1,131 @@ +/** + * + * 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.mam.element; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smackx.rsm.packet.RSMSet; + +/** + * MAM fin IQ class. + * + * @see XEP-0313: Message + * Archive Management + * @author Fernando Ramirez + * + */ +public class MamFinIQ extends IQ { + + /** + * fin element. + */ + public static final String ELEMENT = "fin"; + + /** + * the IQ NAMESPACE. + */ + public static final String NAMESPACE = MamElements.NAMESPACE; + + /** + * RSM set. + */ + private final RSMSet rsmSet; + + /** + * if is complete. + */ + private final boolean complete; + + /** + * if is stable. + */ + private final boolean stable; + + /** + * the query id. + */ + private final String queryId; + + /** + * MamFinIQ constructor. + * + * @param queryId + * @param rsmSet + * @param complete + * @param stable + */ + public MamFinIQ(String queryId, RSMSet rsmSet, boolean complete, boolean stable) { + super(ELEMENT, NAMESPACE); + if (rsmSet == null) { + throw new IllegalArgumentException("rsmSet must not be null"); + } + this.rsmSet = rsmSet; + this.complete = complete; + this.stable = stable; + this.queryId = queryId; + } + + /** + * Get RSM set. + * + * @return the RSM set + */ + public RSMSet getRSMSet() { + return rsmSet; + } + + /** + * Return if it is complete. + * + * @return true if it is complete + */ + public boolean isComplete() { + return complete; + } + + /** + * Return if it is stable. + * + * @return true if it is stable + */ + public boolean isStable() { + return stable; + } + + /** + * Get query id. + * + * @return the query id + */ + public final String getQueryId() { + return queryId; + } + + @Override + protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) { + xml.optAttribute("queryid", queryId); + xml.optBooleanAttribute("complete", complete); + xml.optBooleanAttribute("stable", stable); + if (rsmSet == null) { + xml.setEmptyElement(); + } else { + xml.rightAngleBracket(); + xml.element(rsmSet); + } + return xml; + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/MamPrefsIQ.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/MamPrefsIQ.java new file mode 100644 index 000000000..1c5bedf26 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/MamPrefsIQ.java @@ -0,0 +1,156 @@ +/** + * + * Copyright © 2016 Florian Schmaus and 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.mam.element; + +import java.util.List; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smackx.mam.element.MamElements.AlwaysJidListElement; +import org.jivesoftware.smackx.mam.element.MamElements.NeverJidListElement; +import org.jxmpp.jid.Jid; + +/** + * MAM Preferences IQ class. + * + * @see XEP-0313: Message + * Archive Management + * @author Fernando Ramirez and Florian Schmaus + * + */ +public class MamPrefsIQ extends IQ { + + /** + * the preferences element. + */ + public static final String ELEMENT = "prefs"; + + /** + * the IQ NAMESPACE. + */ + public static final String NAMESPACE = MamElements.NAMESPACE; + + /** + * true if it is a request for update preferences. + */ + private boolean isUpdate; + + /** + * true if it is a result preferences. + */ + private boolean isResult; + + /** + * list of always. + */ + private List alwaysJids; + + /** + * list of never. + */ + private List neverJids; + + /** + * default field. + */ + private String defaultField; + + /** + * MAM preferences IQ constructor. + * + * @param type + * @param alwaysJids + * @param neverJids + * @param defaultField + */ + public MamPrefsIQ(Type type, List alwaysJids, List neverJids, String defaultField) { + super(ELEMENT, NAMESPACE); + this.setType(type); + this.isUpdate = this.getType().equals(Type.set); + this.isResult = this.getType().equals(Type.result); + this.alwaysJids = alwaysJids; + this.neverJids = neverJids; + this.defaultField = defaultField; + } + + /** + * True if it is a request for update preferences. + * + * @return the update preferences boolean + */ + public boolean isUpdate() { + return isUpdate; + } + + /** + * True if it is a result. + * + * @return the result preferences boolean + */ + public boolean isResult() { + return isUpdate; + } + + /** + * Get the list of always store info JIDs. + * + * @return the always list + */ + public List getAlwaysJids() { + return alwaysJids; + } + + /** + * Get the list of never store info JIDs. + * + * @return the never list + */ + public List getNeverJids() { + return neverJids; + } + + /** + * Get the default field. + * + * @return the default field + */ + public String getDefault() { + return defaultField; + } + + @Override + protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) { + + if (isUpdate || isResult) { + xml.attribute("default", defaultField); + } + + xml.rightAngleBracket(); + + if (alwaysJids != null) { + MamElements.AlwaysJidListElement alwaysElement = new AlwaysJidListElement(alwaysJids); + xml.element(alwaysElement); + } + + if (neverJids != null) { + MamElements.NeverJidListElement neverElement = new NeverJidListElement(neverJids); + xml.element(neverElement); + } + + return xml; + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/MamQueryIQ.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/MamQueryIQ.java new file mode 100644 index 000000000..7a6f06678 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/MamQueryIQ.java @@ -0,0 +1,127 @@ +/** + * + * Copyright © 2016 Florian Schmaus and 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.mam.element; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smackx.xdata.FormField; +import org.jivesoftware.smackx.xdata.packet.DataForm; + +/** + * MAM Query IQ class. + * + * @see XEP-0313: Message + * Archive Management + * @author Fernando Ramirez and Florian Schmaus + * + */ +public class MamQueryIQ extends IQ { + + /** + * the MAM query IQ element. + */ + public static final String ELEMENT = QUERY_ELEMENT; + + /** + * the MAM query IQ NAMESPACE. + */ + public static final String NAMESPACE = MamElements.NAMESPACE; + + private final String queryId; + private final String node; + private final DataForm dataForm; + + /** + * MAM query IQ constructor. + * + * @param queryId + */ + public MamQueryIQ(String queryId) { + this(queryId, null, null); + } + + /** + * MAM query IQ constructor. + * + * @param form + */ + public MamQueryIQ(DataForm form) { + this(null, null, form); + } + + /** + * MAM query IQ constructor. + * + * @param queryId + * @param form + */ + public MamQueryIQ(String queryId, DataForm form) { + this(queryId, null, form); + } + + /** + * MAM query IQ constructor. + * + * @param queryId + * @param node + * @param dataForm + */ + public MamQueryIQ(String queryId, String node, DataForm dataForm) { + super(ELEMENT, NAMESPACE); + this.queryId = queryId; + this.node = node; + this.dataForm = dataForm; + + if (dataForm != null) { + FormField field = dataForm.getHiddenFormTypeField(); + if (field == null) { + throw new IllegalArgumentException("If a data form is given it must posses a hidden form type field"); + } + if (!field.getValues().get(0).equals(MamElements.NAMESPACE)) { + throw new IllegalArgumentException( + "Value of the hidden form type field must be '" + MamElements.NAMESPACE + "'"); + } + addExtension(dataForm); + } + } + + /** + * Get query id. + * + * @return the query id + */ + public String getQueryId() { + return queryId; + } + + /** + * Get the data form. + * + * @return the data form + */ + public DataForm getDataForm() { + return dataForm; + } + + @Override + protected IQChildElementXmlStringBuilder getIQChildElementBuilder(IQChildElementXmlStringBuilder xml) { + xml.optAttribute("queryid", queryId); + xml.optAttribute("node", node); + xml.rightAngleBracket(); + return xml; + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/package-info.java new file mode 100644 index 000000000..5c63d8c7c --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/element/package-info.java @@ -0,0 +1,25 @@ +/** + * + * 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. + */ + +/** + * Packet classes and interfaces for Message Archive Management (MAM) XEP-0313. + * + * @see XEP-0313: Message + * Archive Management + * + */ +package org.jivesoftware.smackx.mam.element; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/filter/MamResultFilter.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/filter/MamResultFilter.java new file mode 100644 index 000000000..19e2a1561 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/filter/MamResultFilter.java @@ -0,0 +1,53 @@ +/** + * + * Copyright © 2016 Florian Schmaus and 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.mam.filter; + +import org.jivesoftware.smack.filter.FlexibleStanzaTypeFilter; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smackx.mam.element.MamElements.MamResultExtension; +import org.jivesoftware.smackx.mam.element.MamQueryIQ; + +/** + * MAM result filter class. + * + * @see XEP-0313: Message + * Archive Management + * @author Fernando Ramirez and Florian Schmaus + * + */ +public class MamResultFilter extends FlexibleStanzaTypeFilter { + + private String queryId; + + public MamResultFilter(MamQueryIQ mamQueryIQ) { + super(Message.class); + this.queryId = mamQueryIQ.getQueryId(); + } + + @Override + protected boolean acceptSpecific(Message message) { + MamResultExtension mamResultExtension = MamResultExtension.from(message); + + if (mamResultExtension == null) { + return false; + } + + String resultQueryId = mamResultExtension.getQueryId(); + return ((queryId == null && resultQueryId == null) || (queryId != null && queryId.equals(resultQueryId))); + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/filter/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/filter/package-info.java new file mode 100644 index 000000000..d568f7d04 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/filter/package-info.java @@ -0,0 +1,25 @@ +/** + * + * 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. + */ + +/** + * Filters of Message Archive Management (MAM) XEP-0313. + * + * @see XEP-0313: Message + * Archive Management + * + */ +package org.jivesoftware.smackx.mam.filter; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/package-info.java new file mode 100644 index 000000000..16b8b2b7b --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/package-info.java @@ -0,0 +1,25 @@ +/** + * + * 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. + */ + +/** + * XEP-0313: Message Archive Management. + * + * @see XEP-0313: Message + * Archive Management + * + */ +package org.jivesoftware.smackx.mam; diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/MamFinIQProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/MamFinIQProvider.java new file mode 100644 index 000000000..aa1f12904 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/MamFinIQProvider.java @@ -0,0 +1,58 @@ +/** + * + * 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.mam.provider; + +import org.jivesoftware.smack.provider.IQProvider; +import org.jivesoftware.smackx.mam.element.MamFinIQ; +import org.jivesoftware.smackx.rsm.packet.RSMSet; +import org.jivesoftware.smackx.rsm.provider.RSMSetProvider; +import org.xmlpull.v1.XmlPullParser; + +/** + * MAM Fin IQ Provider class. + * + * @see XEP-0313: Message + * Archive Management + * @author Fernando Ramirez + * + */ +public class MamFinIQProvider extends IQProvider { + + @Override + public MamFinIQ parse(XmlPullParser parser, int initialDepth) throws Exception { + String queryId = parser.getAttributeValue("", "queryid"); + boolean complete = Boolean.parseBoolean(parser.getAttributeValue("", "complete")); + boolean stable = Boolean.parseBoolean(parser.getAttributeValue("", "stable")); + RSMSet rsmSet = null; + + outerloop: while (true) { + int eventType = parser.next(); + if (eventType == XmlPullParser.START_TAG) { + if (parser.getName().equals(RSMSet.ELEMENT)) { + rsmSet = new RSMSetProvider().parse(parser); + } + } else if (eventType == XmlPullParser.END_TAG) { + if (parser.getDepth() == initialDepth) { + break outerloop; + } + } + } + + return new MamFinIQ(queryId, rsmSet, complete, stable); + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/MamPrefsIQProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/MamPrefsIQProvider.java new file mode 100644 index 000000000..5d2e7586a --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/MamPrefsIQProvider.java @@ -0,0 +1,92 @@ +/** + * + * 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.mam.provider; + +import java.util.ArrayList; +import java.util.List; + +import org.jivesoftware.smack.packet.IQ.Type; +import org.jivesoftware.smack.provider.IQProvider; +import org.jivesoftware.smackx.mam.element.MamPrefsIQ; +import org.jxmpp.jid.Jid; +import org.jxmpp.jid.impl.JidCreate; +import org.xmlpull.v1.XmlPullParser; + +/** + * MAM Preferences IQ Provider class. + * + * @see XEP-0313: Message + * Archive Management + * @author Fernando Ramirez + * + */ +public class MamPrefsIQProvider extends IQProvider { + + @Override + public MamPrefsIQ parse(XmlPullParser parser, int initialDepth) throws Exception { + String iqType = parser.getAttributeValue("", "type"); + String defaultField = parser.getAttributeValue("", "default"); + + if (iqType == null) { + iqType = "result"; + } + + List alwaysJids = null; + List neverJids = null; + + outerloop: while (true) { + int eventType = parser.next(); + if (eventType == XmlPullParser.START_TAG) { + if (parser.getName().equals("always")) { + alwaysJids = iterateJids(parser); + } + if (parser.getName().equals("never")) { + neverJids = iterateJids(parser); + } + } else if (eventType == XmlPullParser.END_TAG) { + if (parser.getDepth() == initialDepth) { + break outerloop; + } + } + } + + return new MamPrefsIQ(Type.fromString(iqType), alwaysJids, neverJids, defaultField); + } + + private List iterateJids(XmlPullParser parser) throws Exception { + List jids = new ArrayList<>(); + + int initialDepth = parser.getDepth(); + + outerloop: while (true) { + int eventType = parser.next(); + if (eventType == XmlPullParser.START_TAG) { + if (parser.getName().equals("jid")) { + parser.next(); + jids.add(JidCreate.from(parser.getText())); + } + } else if (eventType == XmlPullParser.END_TAG) { + if (parser.getDepth() == initialDepth) { + break outerloop; + } + } + } + + return jids; + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/MamQueryIQProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/MamQueryIQProvider.java new file mode 100644 index 000000000..2d763073e --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/MamQueryIQProvider.java @@ -0,0 +1,58 @@ +/** + * + * 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.mam.provider; + +import org.jivesoftware.smack.provider.IQProvider; +import org.jivesoftware.smackx.mam.element.MamQueryIQ; +import org.jivesoftware.smackx.xdata.packet.DataForm; +import org.jivesoftware.smackx.xdata.provider.DataFormProvider; +import org.xmlpull.v1.XmlPullParser; + +/** + * MAM Query IQ Provider class. + * + * @see XEP-0313: Message + * Archive Management + * @author Fernando Ramirez + * + */ +public class MamQueryIQProvider extends IQProvider { + + @Override + public MamQueryIQ parse(XmlPullParser parser, int initialDepth) throws Exception { + DataForm dataForm = null; + String queryId = parser.getAttributeValue("", "queryid"); + String node = parser.getAttributeValue("", "node"); + + outerloop: while (true) { + int eventType = parser.next(); + + if (eventType == XmlPullParser.START_TAG) { + if (parser.getName().equals(DataForm.ELEMENT)) { + dataForm = new DataFormProvider().parse(parser); + } + } else if (eventType == XmlPullParser.END_TAG) { + if (parser.getDepth() == initialDepth) { + break outerloop; + } + } + } + + return new MamQueryIQ(queryId, node, dataForm); + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/MamResultProvider.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/MamResultProvider.java new file mode 100644 index 000000000..5ecc10f5a --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/MamResultProvider.java @@ -0,0 +1,57 @@ +/** + * + * 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.mam.provider; + +import org.jivesoftware.smack.provider.ExtensionElementProvider; +import org.jivesoftware.smackx.forward.packet.Forwarded; +import org.jivesoftware.smackx.forward.provider.ForwardedProvider; +import org.jivesoftware.smackx.mam.element.MamElements.MamResultExtension; +import org.xmlpull.v1.XmlPullParser; + +/** + * MAM Result Provider class. + * + * @see XEP-0313: Message + * Archive Management + * @author Fernando Ramirez + * + */ +public class MamResultProvider extends ExtensionElementProvider { + + @Override + public MamResultExtension parse(XmlPullParser parser, int initialDepth) throws Exception { + Forwarded forwarded = null; + String queryId = parser.getAttributeValue("", "queryid"); + String id = parser.getAttributeValue("", "id"); + + outerloop: while (true) { + int eventType = parser.next(); + if (eventType == XmlPullParser.START_TAG) { + if (parser.getName().equals(Forwarded.ELEMENT)) { + forwarded = new ForwardedProvider().parse(parser); + } + } else if (eventType == XmlPullParser.END_TAG) { + if (parser.getDepth() == initialDepth) { + break outerloop; + } + } + } + + return new MamResultExtension(queryId, id, forwarded); + } + +} diff --git a/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/package-info.java b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/package-info.java new file mode 100644 index 000000000..a6c1a20b4 --- /dev/null +++ b/smack-experimental/src/main/java/org/jivesoftware/smackx/mam/provider/package-info.java @@ -0,0 +1,25 @@ +/** + * + * 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. + */ + +/** + * Provider classes of Message Archive Management (MAM) XEP-0313. + * + * @see XEP-0313: Message + * Archive Management + * + */ +package org.jivesoftware.smackx.mam.provider; diff --git a/smack-experimental/src/main/resources/org.jivesoftware.smack.experimental/experimental.providers b/smack-experimental/src/main/resources/org.jivesoftware.smack.experimental/experimental.providers index e4906726e..145309c84 100644 --- a/smack-experimental/src/main/resources/org.jivesoftware.smack.experimental/experimental.providers +++ b/smack-experimental/src/main/resources/org.jivesoftware.smack.experimental/experimental.providers @@ -52,6 +52,28 @@ org.jivesoftware.smackx.gcm.provider.GcmExtensionProvider + + + prefs + urn:xmpp:mam:1 + org.jivesoftware.smackx.mam.provider.MamPrefsIQProvider + + + query + urn:xmpp:mam:1 + org.jivesoftware.smackx.mam.provider.MamQueryIQProvider + + + fin + urn:xmpp:mam:1 + org.jivesoftware.smackx.mam.provider.MamFinIQProvider + + + result + urn:xmpp:mam:1 + org.jivesoftware.smackx.mam.provider.MamResultProvider + + register diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/FiltersTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/FiltersTest.java new file mode 100644 index 000000000..820ab1989 --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/FiltersTest.java @@ -0,0 +1,160 @@ +/** + * + * 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.mam; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Date; +import java.util.List; + +import org.jivesoftware.smackx.mam.element.MamElements; +import org.jivesoftware.smackx.xdata.packet.DataForm; +import org.junit.Assert; +import org.junit.Test; +import org.jxmpp.jid.Jid; +import org.jxmpp.jid.impl.JidCreate; +import org.jxmpp.util.XmppDateTime; + +public class FiltersTest extends MamTest { + + private String getMamXMemberWith(List fieldsNames, List fieldsValues) { + String xml = "" + "" + "" + + MamElements.NAMESPACE + "" + ""; + + for (int i = 0; i < fieldsNames.size() && i < fieldsValues.size(); i++) { + xml += "" + "" + fieldsValues.get(i) + "" + + ""; + } + + xml += ""; + return xml; + } + + @Test + public void checkStartDateFilter() throws Exception { + Method methodAddStartDateFilter = MamManager.class.getDeclaredMethod("addStart", Date.class, DataForm.class); + methodAddStartDateFilter.setAccessible(true); + + Date date = new Date(); + DataForm dataForm = getNewMamForm(); + methodAddStartDateFilter.invoke(mamManager, date, dataForm); + + List fields = new ArrayList<>(); + fields.add("start"); + List values = new ArrayList<>(); + values.add(XmppDateTime.formatXEP0082Date(date)); + + Assert.assertEquals(dataForm.toXML().toString(), getMamXMemberWith(fields, values)); + } + + @Test + public void checkEndDateFilter() throws Exception { + Method methodAddEndDateFilter = MamManager.class.getDeclaredMethod("addEnd", Date.class, DataForm.class); + methodAddEndDateFilter.setAccessible(true); + + Date date = new Date(); + DataForm dataForm = getNewMamForm(); + methodAddEndDateFilter.invoke(mamManager, date, dataForm); + + List fields = new ArrayList<>(); + fields.add("end"); + List values = new ArrayList<>(); + values.add(XmppDateTime.formatXEP0082Date(date)); + + Assert.assertEquals(dataForm.toXML().toString(), getMamXMemberWith(fields, values)); + } + + @Test + public void checkWithJidFilter() throws Exception { + Method methodAddJidFilter = MamManager.class.getDeclaredMethod("addWithJid", Jid.class, DataForm.class); + methodAddJidFilter.setAccessible(true); + + String jid = "test@jid.com"; + DataForm dataForm = getNewMamForm(); + methodAddJidFilter.invoke(mamManager, JidCreate.from(jid), dataForm); + + List fields = new ArrayList<>(); + fields.add("with"); + List values = new ArrayList<>(); + values.add(jid); + + Assert.assertEquals(dataForm.toXML().toString(), getMamXMemberWith(fields, values)); + } + + @Test + public void checkMultipleFilters() throws Exception { + Method methodAddStartDateFilter = MamManager.class.getDeclaredMethod("addStart", Date.class, DataForm.class); + methodAddStartDateFilter.setAccessible(true); + Method methodAddEndDateFilter = MamManager.class.getDeclaredMethod("addEnd", Date.class, DataForm.class); + methodAddEndDateFilter.setAccessible(true); + Method methodAddJidFilter = MamManager.class.getDeclaredMethod("addWithJid", Jid.class, DataForm.class); + methodAddJidFilter.setAccessible(true); + + DataForm dataForm = getNewMamForm(); + Date date = new Date(); + String dateString = XmppDateTime.formatXEP0082Date(date); + String jid = "test@jid.com"; + + methodAddStartDateFilter.invoke(mamManager, date, dataForm); + methodAddEndDateFilter.invoke(mamManager, date, dataForm); + methodAddJidFilter.invoke(mamManager, JidCreate.from(jid), dataForm); + String dataFormResult = dataForm.toXML().toString(); + + List fields = new ArrayList<>(); + List values = new ArrayList<>(); + + fields.add("start"); + values.add(dateString); + Assert.assertNotEquals(dataFormResult, getMamXMemberWith(fields, values)); + + fields.add("end"); + values.add(dateString); + Assert.assertNotEquals(dataFormResult, getMamXMemberWith(fields, values)); + + fields.clear(); + values.clear(); + + fields.add("start"); + values.add(dateString); + fields.add("with"); + values.add(jid); + Assert.assertNotEquals(dataFormResult, getMamXMemberWith(fields, values)); + + fields.clear(); + values.clear(); + + fields.add("end"); + values.add(dateString); + fields.add("with"); + values.add(jid); + fields.add("start"); + values.add(dateString); + Assert.assertNotEquals(dataFormResult, getMamXMemberWith(fields, values)); + + fields.clear(); + values.clear(); + + fields.add("start"); + values.add(dateString); + fields.add("end"); + values.add(dateString); + fields.add("with"); + values.add(jid); + Assert.assertEquals(dataFormResult, getMamXMemberWith(fields, values)); + } + +} diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamFinProviderTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamFinProviderTest.java new file mode 100644 index 000000000..67654991e --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamFinProviderTest.java @@ -0,0 +1,69 @@ +/** + * + * 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.mam; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.packet.IQ.Type; +import org.jivesoftware.smack.util.PacketParserUtils; +import org.jivesoftware.smackx.mam.element.MamFinIQ; +import org.jivesoftware.smackx.mam.provider.MamFinIQProvider; +import org.jivesoftware.smackx.rsm.packet.RSMSet; +import org.junit.Assert; +import org.junit.Test; +import org.xmlpull.v1.XmlPullParser; + +public class MamFinProviderTest extends MamTest { + + String exmapleMamFinXml = "" + + "" + "10" + "09af3-cc343-b409f" + + "" + ""; + + private String getIQLimitedResultsExample() { + return "" + "" + + "" + "23452-4534-1" + + "390-2342-22" + "16" + "" + "" + ""; + } + + @Test + public void checkMamFinProvider() throws Exception { + XmlPullParser parser = PacketParserUtils.getParserFor(exmapleMamFinXml); + MamFinIQ mamFinIQ = new MamFinIQProvider().parse(parser); + + Assert.assertFalse(mamFinIQ.isComplete()); + Assert.assertTrue(mamFinIQ.isStable()); + Assert.assertNull(mamFinIQ.getQueryId()); + + RSMSet rsmSet = mamFinIQ.getRSMSet(); + Assert.assertEquals(rsmSet.getAfter(), "09af3-cc343-b409f"); + Assert.assertEquals(rsmSet.getMax(), 10); + } + + @Test + public void checkQueryLimitedResults() throws Exception { + IQ iq = (IQ) PacketParserUtils.parseStanza(getIQLimitedResultsExample()); + + MamFinIQ mamFinIQ = (MamFinIQ) iq; + Assert.assertEquals(mamFinIQ.getType(), Type.result); + + Assert.assertTrue(mamFinIQ.isComplete()); + Assert.assertEquals(mamFinIQ.getRSMSet().getCount(), 16); + Assert.assertEquals(mamFinIQ.getRSMSet().getFirst(), "23452-4534-1"); + Assert.assertEquals(mamFinIQ.getRSMSet().getFirstIndex(), 0); + Assert.assertEquals(mamFinIQ.getRSMSet().getLast(), "390-2342-22"); + } + +} diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamPrefIQProviderTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamPrefIQProviderTest.java new file mode 100644 index 000000000..6fb6ac212 --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamPrefIQProviderTest.java @@ -0,0 +1,84 @@ +/** + * + * 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.mam; + +import java.util.List; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.util.PacketParserUtils; +import org.jivesoftware.smackx.mam.element.MamPrefsIQ; +import org.jivesoftware.smackx.mam.provider.MamPrefsIQProvider; +import org.junit.Assert; +import org.junit.Test; +import org.jxmpp.jid.Jid; +import org.xmlpull.v1.XmlPullParser; + +public class MamPrefIQProviderTest extends MamTest { + + String exampleMamPrefsIQ1 = "" + "" + + "" + "romeo@montague.lit" + "" + "" + + "montague@montague.lit" + "" + "" + ""; + + String exampleMamPrefsIQ2 = "" + "" + + "" + "romeo@montague.lit" + "montague@montague.lit" + "" + + "" + "" + "" + ""; + + String exampleMamPrefsIQ3 = "" + "" + "" + + ""; + + String exampleMamPrefsResultIQ = "" + + "" + "" + "romeo@montague.lit" + + "" + "" + "sarasa@montague.lit" + "montague@montague.lit" + + "" + "" + ""; + + @Test + public void checkMamPrefsIQProvider() throws Exception { + XmlPullParser parser1 = PacketParserUtils.getParserFor(exampleMamPrefsIQ1); + MamPrefsIQ mamPrefIQ1 = new MamPrefsIQProvider().parse(parser1); + + Assert.assertTrue(mamPrefIQ1.isUpdate()); + Assert.assertEquals(mamPrefIQ1.getAlwaysJids().get(0), "romeo@montague.lit"); + Assert.assertEquals(mamPrefIQ1.getNeverJids().get(0), "montague@montague.lit"); + + XmlPullParser parser2 = PacketParserUtils.getParserFor(exampleMamPrefsIQ2); + MamPrefsIQ mamPrefIQ2 = new MamPrefsIQProvider().parse(parser2); + Assert.assertTrue(mamPrefIQ2.isUpdate()); + Assert.assertEquals(mamPrefIQ2.getAlwaysJids().get(0), "romeo@montague.lit"); + Assert.assertEquals(mamPrefIQ2.getAlwaysJids().get(1), "montague@montague.lit"); + Assert.assertTrue(mamPrefIQ2.getNeverJids().isEmpty()); + + XmlPullParser parser3 = PacketParserUtils.getParserFor(exampleMamPrefsIQ3); + MamPrefsIQ mamPrefIQ3 = new MamPrefsIQProvider().parse(parser3); + Assert.assertFalse(mamPrefIQ3.isUpdate()); + } + + @Test + public void checkMamPrefResult() throws Exception { + IQ iq = (IQ) PacketParserUtils.parseStanza(exampleMamPrefsResultIQ); + + MamPrefsIQ mamPrefsIQ = (MamPrefsIQ) iq; + + List alwaysJids = mamPrefsIQ.getAlwaysJids(); + List neverJids = mamPrefsIQ.getNeverJids(); + + Assert.assertEquals(alwaysJids.size(), 1); + Assert.assertEquals(neverJids.size(), 2); + Assert.assertEquals(alwaysJids.get(0).toString(), "romeo@montague.lit"); + Assert.assertEquals(neverJids.get(1).toString(), "montague@montague.lit"); + } + +} diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamQueryIQProviderTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamQueryIQProviderTest.java new file mode 100644 index 000000000..9141137c3 --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamQueryIQProviderTest.java @@ -0,0 +1,86 @@ +/** + * + * 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.mam; + +import java.util.ArrayList; +import java.util.List; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.packet.IQ.Type; +import org.jivesoftware.smack.util.PacketParserUtils; +import org.jivesoftware.smackx.mam.element.MamQueryIQ; +import org.jivesoftware.smackx.xdata.FormField; +import org.jivesoftware.smackx.xdata.packet.DataForm; +import org.junit.Assert; +import org.junit.Test; + +public class MamQueryIQProviderTest { + + String exampleMamQueryIQ1 = "" + "" + + "" + "" + + "urn:xmpp:mam:1" + "" + + "" + + "Where arth thou, my Juliet?" + "" + + "" + + "{http://jabber.org/protocol/mood}mood/lonely" + "" + "" + "" + + ""; + + String exampleMamQueryIQ2 = "" + "" + + "" + "" + + "urn:xmpp:mam:1" + "" + "" + + "" + "" + + "" + + "" + "" + "" + ""; + + @Test + public void checkMamQueryIQProvider() throws Exception { + // example 1 + IQ iq1 = (IQ) PacketParserUtils.parseStanza(exampleMamQueryIQ1); + MamQueryIQ mamQueryIQ1 = (MamQueryIQ) iq1; + + Assert.assertEquals(mamQueryIQ1.getType(), Type.set); + Assert.assertEquals(mamQueryIQ1.getQueryId(), "test"); + + DataForm dataForm1 = (DataForm) mamQueryIQ1.getExtension(DataForm.NAMESPACE); + Assert.assertEquals(dataForm1.getType(), DataForm.Type.submit); + + List fields1 = dataForm1.getFields(); + Assert.assertEquals(fields1.get(0).getType(), FormField.Type.hidden); + Assert.assertEquals(fields1.get(1).getType(), FormField.Type.text_single); + Assert.assertEquals(fields1.get(1).getValues().get(0), "Where arth thou, my Juliet?"); + Assert.assertEquals(fields1.get(2).getValues().get(0), "{http://jabber.org/protocol/mood}mood/lonely"); + + // example2 + IQ iq2 = (IQ) PacketParserUtils.parseStanza(exampleMamQueryIQ2); + MamQueryIQ mamQueryIQ2 = (MamQueryIQ) iq2; + + Assert.assertEquals(mamQueryIQ2.getType(), Type.result); + Assert.assertNull(mamQueryIQ2.getQueryId()); + + DataForm dataForm2 = (DataForm) mamQueryIQ2.getExtension(DataForm.NAMESPACE); + Assert.assertEquals(dataForm2.getType(), DataForm.Type.form); + + List fields2 = dataForm2.getFields(); + Assert.assertEquals(fields2.get(0).getValues().get(0), "urn:xmpp:mam:1"); + Assert.assertTrue(fields2.get(0).getValues().size() == 1); + Assert.assertEquals(fields2.get(1).getType(), FormField.Type.jid_single); + Assert.assertEquals(fields2.get(2).getType(), FormField.Type.text_single); + Assert.assertEquals(fields2.get(2).getValues(), new ArrayList<>()); + Assert.assertEquals(fields2.get(4).getVariable(), "urn:example:xmpp:free-text-search"); + } + +} diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamResultProviderTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamResultProviderTest.java new file mode 100644 index 000000000..c8c43eaea --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamResultProviderTest.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.mam; + +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.util.PacketParserUtils; +import org.jivesoftware.smackx.forward.packet.Forwarded; +import org.jivesoftware.smackx.mam.element.MamElements.MamResultExtension; +import org.jivesoftware.smackx.mam.provider.MamResultProvider; +import org.junit.Assert; +import org.junit.Test; +import org.xmlpull.v1.XmlPullParser; + +public class MamResultProviderTest { + + String exampleMamResultXml = "" + + "" + "" + + "" + + "Call me but love, and I'll be new baptized; Henceforth I never will be Romeo." + + "" + "" + ""; + + String exampleResultMessage = "" + + "" + + "" + "" + + "" + + "Hail to thee" + "" + "" + "" + ""; + + @Test + public void checkMamResultProvider() throws Exception { + XmlPullParser parser = PacketParserUtils.getParserFor(exampleMamResultXml); + MamResultExtension mamResultExtension = new MamResultProvider().parse(parser); + + Assert.assertEquals(mamResultExtension.getQueryId(), "f27"); + Assert.assertEquals(mamResultExtension.getId(), "28482-98726-73623"); + + GregorianCalendar calendar = new GregorianCalendar(2010, 7 - 1, 10, 23, 8, 25); + calendar.setTimeZone(TimeZone.getTimeZone("UTC")); + Date date = calendar.getTime(); + + Forwarded forwarded = mamResultExtension.getForwarded(); + Assert.assertEquals(forwarded.getDelayInformation().getStamp(), date); + + Message message = (Message) forwarded.getForwardedStanza(); + Assert.assertEquals(message.getFrom(), "romeo@montague.lit/orchard"); + Assert.assertEquals(message.getTo(), "juliet@capulet.lit/balcony"); + Assert.assertEquals(message.getBody(), + "Call me but love, and I'll be new baptized; Henceforth I never will be Romeo."); + } + + @Test + public void checkResultsParse() throws Exception { + Message message = (Message) PacketParserUtils.parseStanza(exampleResultMessage); + MamResultExtension mamResultExtension = MamResultExtension.from(message); + + Assert.assertEquals(mamResultExtension.getQueryId(), "f27"); + Assert.assertEquals(mamResultExtension.getId(), "28482-98726-73623"); + + GregorianCalendar calendar = new GregorianCalendar(2010, 7 - 1, 10, 23, 8, 25); + calendar.setTimeZone(TimeZone.getTimeZone("UTC")); + Date date = calendar.getTime(); + + Forwarded forwarded = mamResultExtension.getForwarded(); + Assert.assertEquals(forwarded.getDelayInformation().getStamp(), date); + + Message forwardedMessage = (Message) forwarded.getForwardedStanza(); + Assert.assertEquals(forwardedMessage.getFrom(), "witch@shakespeare.lit"); + Assert.assertEquals(forwardedMessage.getTo(), "macbeth@shakespeare.lit"); + Assert.assertEquals(forwardedMessage.getBody(), "Hail to thee"); + } + +} diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamTest.java new file mode 100644 index 000000000..6d7c7c46e --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/MamTest.java @@ -0,0 +1,54 @@ +/** + * + * 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.mam; + +import static org.mockito.Mockito.mock; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; + +import org.jivesoftware.smack.XMPPConnection; +import org.jivesoftware.smackx.ExperimentalInitializerTest; +import org.jivesoftware.smackx.xdata.packet.DataForm; +import org.junit.Before; + +public class MamTest extends ExperimentalInitializerTest { + + protected XMPPConnection connection; + protected String queryId; + protected MamManager mamManager; + + @Before + public void setup() { + // mock connection + connection = mock(XMPPConnection.class); + + // test query id + queryId = "testid"; + + // MamManager instance + mamManager = MamManager.getInstanceFor(connection); + } + + protected DataForm getNewMamForm() throws NoSuchMethodException, SecurityException, IllegalAccessException, + IllegalArgumentException, InvocationTargetException { + Method methodGetNewMamForm = MamManager.class.getDeclaredMethod("getNewMamForm"); + methodGetNewMamForm.setAccessible(true); + return (DataForm) methodGetNewMamForm.invoke(mamManager); + } + +} diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/PagingTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/PagingTest.java new file mode 100644 index 000000000..58d44aa07 --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/PagingTest.java @@ -0,0 +1,55 @@ +/** + * + * 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.mam; + +import java.lang.reflect.Method; + +import org.jivesoftware.smackx.mam.element.MamQueryIQ; +import org.jivesoftware.smackx.rsm.packet.RSMSet; +import org.jivesoftware.smackx.xdata.packet.DataForm; +import org.junit.Test; + +import org.junit.Assert; + +public class PagingTest extends MamTest { + + String pagingStanza = "" + "" + + "" + "" + + "urn:xmpp:mam:1" + "" + "" + "" + + "10" + "" + "" + ""; + + @Test + public void checkPageQueryStanza() throws Exception { + Method methodPreparePageQuery = MamManager.class.getDeclaredMethod("preparePageQuery", MamQueryIQ.class, + RSMSet.class); + methodPreparePageQuery.setAccessible(true); + + DataForm dataForm = getNewMamForm(); + int max = 10; + RSMSet rsmSet = new RSMSet(max); + + MamQueryIQ mamQueryIQ = new MamQueryIQ(queryId, dataForm); + mamQueryIQ.setStanzaId("sarasa"); + + methodPreparePageQuery.invoke(mamManager, mamQueryIQ, rsmSet); + + Assert.assertEquals(mamQueryIQ.getDataForm(), dataForm); + Assert.assertEquals(mamQueryIQ.getDataForm().getFields().get(0).getValues().get(0), "urn:xmpp:mam:1"); + Assert.assertEquals(mamQueryIQ.toXML().toString(), pagingStanza); + } + +} diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/PreferencesTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/PreferencesTest.java new file mode 100644 index 000000000..1c9681263 --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/PreferencesTest.java @@ -0,0 +1,68 @@ +/** + * + * 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.mam; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.junit.Test; +import org.jxmpp.jid.Jid; +import org.jxmpp.jid.impl.JidCreate; +import org.jivesoftware.smackx.mam.element.MamElements; +import org.jivesoftware.smackx.mam.element.MamPrefsIQ; +import org.junit.Assert; + +public class PreferencesTest extends MamTest { + + String retrievePrefsStanzaExample = "" + "" + ""; + + String updatePrefsStanzaExample = "" + "" + "" + "romeo@montague.lit" + "other@montague.lit" + + "" + "" + "montague@montague.lit" + "" + "" + ""; + + @Test + public void checkRetrievePrefsStanza() throws Exception { + Method prepareRetrievePreferencesStanza = MamManager.class + .getDeclaredMethod("prepareRetrievePreferencesStanza"); + prepareRetrievePreferencesStanza.setAccessible(true); + + MamPrefsIQ mamPrefIQ = (MamPrefsIQ) prepareRetrievePreferencesStanza.invoke(mamManager); + mamPrefIQ.setStanzaId("sarasa"); + Assert.assertEquals(mamPrefIQ.toXML().toString(), retrievePrefsStanzaExample); + } + + @Test + public void checkUpdatePrefsStanza() throws Exception { + Method prepareUpdatePreferencesStanza = MamManager.class.getDeclaredMethod("prepareUpdatePreferencesStanza", + List.class, List.class, String.class); + prepareUpdatePreferencesStanza.setAccessible(true); + + List alwaysJids = new ArrayList<>(); + alwaysJids.add(JidCreate.from("romeo@montague.lit")); + alwaysJids.add(JidCreate.from("other@montague.lit")); + + List neverJids = new ArrayList<>(); + neverJids.add(JidCreate.from("montague@montague.lit")); + + MamPrefsIQ mamPrefIQ = (MamPrefsIQ) prepareUpdatePreferencesStanza.invoke(mamManager, alwaysJids, neverJids, "roster"); + mamPrefIQ.setStanzaId("sarasa"); + Assert.assertEquals(mamPrefIQ.toXML().toString(), updatePrefsStanzaExample); + } + +} diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/QueryArchiveTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/QueryArchiveTest.java new file mode 100644 index 000000000..936aa33e1 --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/QueryArchiveTest.java @@ -0,0 +1,95 @@ +/** + * + * 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.mam; + +import java.util.Date; +import java.util.GregorianCalendar; +import java.util.TimeZone; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smack.packet.Message.Type; +import org.jivesoftware.smackx.delay.packet.DelayInformation; +import org.jivesoftware.smackx.forward.packet.Forwarded; +import org.jivesoftware.smackx.mam.element.MamElements; +import org.jivesoftware.smackx.mam.element.MamElements.MamResultExtension; +import org.jivesoftware.smackx.mam.element.MamQueryIQ; +import org.jivesoftware.smackx.xdata.packet.DataForm; +import org.junit.Assert; +import org.junit.Test; +import org.jxmpp.jid.impl.JidCreate; + +public class QueryArchiveTest extends MamTest { + + String mamSimpleQueryIQ = "" + "" + + "" + "" + "" + + MamElements.NAMESPACE + "" + "" + "" + "" + ""; + + String mamQueryResultExample = "" + + "" + + "" + + "" + "" + "Thrice the brinded cat hath mew." + "" + "" + + "" + ""; + + @Test + public void checkMamQueryIQ() throws Exception { + DataForm dataForm = getNewMamForm(); + MamQueryIQ mamQueryIQ = new MamQueryIQ(queryId, dataForm); + mamQueryIQ.setType(IQ.Type.set); + mamQueryIQ.setStanzaId("sarasa"); + Assert.assertEquals(mamQueryIQ.toXML().toString(), mamSimpleQueryIQ); + } + + @Test + public void checkMamQueryResults() throws Exception { + Message message = new Message(); + message.setStanzaId("iasd207"); + message.setFrom(JidCreate.from("coven@chat.shakespeare.lit")); + message.setTo(JidCreate.from("hag66@shakespeare.lit/pda")); + + GregorianCalendar calendar = new GregorianCalendar(2002, 10 - 1, 13, 23, 58, 37); + calendar.setTimeZone(TimeZone.getTimeZone("UTC")); + Date date = calendar.getTime(); + + DelayInformation delay = new DelayInformation(date); + Message forwardedMessage = new Message(); + forwardedMessage.setFrom(JidCreate.from("coven@chat.shakespeare.lit/firstwitch")); + forwardedMessage.setStanzaId("162BEBB1-F6DB-4D9A-9BD8-CFDCC801A0B2"); + forwardedMessage.setType(Type.chat); + forwardedMessage.setBody("Thrice the brinded cat hath mew."); + + Forwarded forwarded = new Forwarded(delay, forwardedMessage); + + message.addExtension(new MamResultExtension("g27", "34482-21985-73620", forwarded)); + + Assert.assertEquals(message.toXML().toString(), mamQueryResultExample); + + MamResultExtension mamResultExtension = MamResultExtension.from(message); + + Assert.assertEquals(mamResultExtension.getId(), "34482-21985-73620"); + Assert.assertEquals(mamResultExtension.getForwarded().getDelayInformation().getStamp(), date); + + Message resultMessage = (Message) mamResultExtension.getForwarded().getForwardedStanza(); + Assert.assertEquals(resultMessage.getFrom(), JidCreate.from("coven@chat.shakespeare.lit/firstwitch")); + Assert.assertEquals(resultMessage.getStanzaId(), "162BEBB1-F6DB-4D9A-9BD8-CFDCC801A0B2"); + Assert.assertEquals(resultMessage.getType(), Type.chat); + Assert.assertEquals(resultMessage.getBody(), "Thrice the brinded cat hath mew."); + } + +} diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/ResultsLimitTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/ResultsLimitTest.java new file mode 100644 index 000000000..f932666d3 --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/ResultsLimitTest.java @@ -0,0 +1,50 @@ +/** + * + * 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.mam; + +import java.lang.reflect.Method; + +import org.jivesoftware.smack.packet.IQ; +import org.jivesoftware.smackx.mam.element.MamElements; +import org.jivesoftware.smackx.mam.element.MamQueryIQ; +import org.jivesoftware.smackx.xdata.packet.DataForm; +import org.junit.Assert; +import org.junit.Test; + +public class ResultsLimitTest extends MamTest { + + String resultsLimitStanza = "" + "" + + "" + "" + "" + + MamElements.NAMESPACE + "" + "" + "" + "" + + "10" + "" + "" + ""; + + @Test + public void checkResultsLimit() throws Exception { + Method methodAddResultsLimit = MamManager.class.getDeclaredMethod("addResultsLimit", Integer.class, + MamQueryIQ.class); + methodAddResultsLimit.setAccessible(true); + + DataForm dataForm = getNewMamForm(); + MamQueryIQ mamQueryIQ = new MamQueryIQ(queryId, dataForm); + mamQueryIQ.setType(IQ.Type.set); + mamQueryIQ.setStanzaId("sarasa"); + + methodAddResultsLimit.invoke(mamManager, 10, mamQueryIQ); + Assert.assertEquals(mamQueryIQ.toXML().toString(), resultsLimitStanza); + } + +} diff --git a/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/RetrieveFormFieldsTest.java b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/RetrieveFormFieldsTest.java new file mode 100644 index 000000000..df64ddc4a --- /dev/null +++ b/smack-experimental/src/test/java/org/jivesoftware/smackx/mam/RetrieveFormFieldsTest.java @@ -0,0 +1,81 @@ +/** + * + * 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.mam; + +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.List; + +import org.jivesoftware.smackx.mam.element.MamElements; +import org.jivesoftware.smackx.mam.element.MamQueryIQ; +import org.jivesoftware.smackx.xdata.FormField; +import org.jivesoftware.smackx.xdata.packet.DataForm; +import org.junit.Test; + +import org.junit.Assert; + +public class RetrieveFormFieldsTest extends MamTest { + + String retrieveFormFieldStanza = "" + "" + ""; + + String additionalFieldsStanza = "" + "" + + "" + MamElements.NAMESPACE + "" + "" + + "" + "Hi" + "" + + "" + "Hi2" + "" + + ""; + + @Test + public void checkRetrieveFormFieldsStanza() throws Exception { + Method methodPrepareMamQueryIQGet = MamManager.class.getDeclaredMethod("prepareMamQueryIQGet", String.class); + methodPrepareMamQueryIQGet.setAccessible(true); + + MamQueryIQ mamQueryIQ = (MamQueryIQ) methodPrepareMamQueryIQGet.invoke(mamManager, queryId); + mamQueryIQ.setStanzaId("sarasa"); + + Assert.assertEquals(mamQueryIQ.toXML().toString(), retrieveFormFieldStanza); + } + + @Test + public void checkAddAdditionalFieldsStanza() throws Exception { + Method methodAddAdditionalFields = MamManager.class.getDeclaredMethod("addAdditionalFields", List.class, + DataForm.class); + methodAddAdditionalFields.setAccessible(true); + + DataForm dataForm = getNewMamForm(); + + List additionalFields = new ArrayList<>(); + + FormField field1 = new FormField("urn:example:xmpp:free-text-search"); + field1.setType(FormField.Type.text_single); + field1.addValue("Hi"); + + FormField field2 = new FormField("urn:example:xmpp:stanza-content"); + field2.setType(FormField.Type.jid_single); + field2.addValue("Hi2"); + + additionalFields.add(field1); + additionalFields.add(field2); + + methodAddAdditionalFields.invoke(mamManager, additionalFields, dataForm); + + String dataFormResult = dataForm.toXML().toString(); + + Assert.assertEquals(dataFormResult, additionalFieldsStanza); + } + +} diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/mam/MamIntegrationTest.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/mam/MamIntegrationTest.java new file mode 100644 index 000000000..d61fa3ac7 --- /dev/null +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/mam/MamIntegrationTest.java @@ -0,0 +1,93 @@ +/** + * + * 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.mam; + +import java.util.List; +import java.util.UUID; + +import org.igniterealtime.smack.inttest.AbstractSmackIntegrationTest; +import org.igniterealtime.smack.inttest.SmackIntegrationTest; +import org.igniterealtime.smack.inttest.SmackIntegrationTestEnvironment; +import org.igniterealtime.smack.inttest.TestNotPossibleException; +import org.jivesoftware.smack.SmackException.NoResponseException; +import org.jivesoftware.smack.SmackException.NotConnectedException; +import org.jivesoftware.smack.SmackException.NotLoggedInException; +import org.jivesoftware.smack.XMPPException.XMPPErrorException; +import org.jivesoftware.smack.packet.Message; +import org.jivesoftware.smackx.forward.packet.Forwarded; +import org.jivesoftware.smackx.mam.MamManager.MamQueryResult; +import org.junit.Assert; +import org.jxmpp.jid.Jid; + +public class MamIntegrationTest extends AbstractSmackIntegrationTest { + + private final MamManager mamManagerConTwo; + + public MamIntegrationTest(SmackIntegrationTestEnvironment environment) throws NoResponseException, + XMPPErrorException, NotConnectedException, InterruptedException, TestNotPossibleException { + super(environment); + + mamManagerConTwo = MamManager.getInstanceFor(conTwo); + + if (!mamManagerConTwo.isSupportedByServer()) { + throw new TestNotPossibleException("Message Archive Management (XEP-0313) is not supported by the server."); + } + + } + + private Message getConTwoLastMessageSentFrom(Jid userOne) throws NoResponseException, XMPPErrorException, + NotConnectedException, InterruptedException, NotLoggedInException { + int pageSize = 20; + MamQueryResult mamQueryResult = mamManagerConTwo.queryArchive(pageSize, null, null, userOne, null); + + while (!mamQueryResult.mamFin.isComplete()) { + mamQueryResult = mamManagerConTwo.pageNext(mamQueryResult, pageSize); + } + + List forwardedMessages = mamQueryResult.forwardedMessages; + Message messageFromMAM = (Message) forwardedMessages.get(forwardedMessages.size() - 1).getForwardedStanza(); + return messageFromMAM; + } + + private Message prepareMessage(Jid to, String messageId, String body) { + Message message = new Message(); + message.setTo(to); + message.setStanzaId(messageId); + message.setBody(body); + return message; + } + + @SmackIntegrationTest + public void mamTest() throws Exception { + Jid userOne = conOne.getUser().asEntityBareJid(); + Jid userTwo = conTwo.getUser().asEntityBareJid(); + + String messageId = UUID.randomUUID().toString(); + String messageBody = "test message"; + + Message message = prepareMessage(userTwo, messageId, messageBody); + conOne.sendStanza(message); + + Message mamMessage = getConTwoLastMessageSentFrom(userOne); + + Assert.assertEquals(messageId, mamMessage.getStanzaId()); + Assert.assertEquals(messageBody, mamMessage.getBody()); + Assert.assertEquals(conOne.getUser(), mamMessage.getFrom()); + Assert.assertEquals(userTwo, mamMessage.getTo()); + } + +} diff --git a/smack-integration-test/src/main/java/org/jivesoftware/smackx/mam/package-info.java b/smack-integration-test/src/main/java/org/jivesoftware/smackx/mam/package-info.java new file mode 100644 index 000000000..09b4b4074 --- /dev/null +++ b/smack-integration-test/src/main/java/org/jivesoftware/smackx/mam/package-info.java @@ -0,0 +1,21 @@ +/** + * + * 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. + */ + +/** + * Message Archive Management (XEP-0313) integration tests. + */ +package org.jivesoftware.smackx.mam;