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;