mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-22 06:12:05 +01:00
Merge branch '4.3'
This commit is contained in:
commit
f290197f6a
20 changed files with 1149 additions and 424 deletions
|
@ -3,192 +3,4 @@ Message Archive Management
|
|||
|
||||
[Back](index.md)
|
||||
|
||||
Query and control an archive of messages stored on a server.
|
||||
|
||||
* Check MAM support
|
||||
* Query archive
|
||||
* Paging
|
||||
* Get form fields
|
||||
* Get preferences
|
||||
* Update preferences
|
||||
|
||||
|
||||
**XEP related:** [XEP-0313](http://xmpp.org/extensions/xep-0313.html)
|
||||
|
||||
|
||||
Get an instance of Message Archive Management Manager
|
||||
-----------------------------------------------------
|
||||
|
||||
```
|
||||
MamManager mamManager = MamManager.getInstanceFor(connection);
|
||||
```
|
||||
|
||||
|
||||
Check MAM support
|
||||
-----------------
|
||||
|
||||
```
|
||||
boolean isSupported = mamManager.isSupported();
|
||||
```
|
||||
|
||||
|
||||
Query archive
|
||||
-------------
|
||||
|
||||
```
|
||||
MamQueryResult mamQueryResult = mamManager.queryArchive(max);
|
||||
```
|
||||
*max* is an `Integer`
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
MamQueryResult mamQueryResult = mamManager.queryArchive(withJid);
|
||||
```
|
||||
*withJid* is a `Jid`
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
MamQueryResult mamQueryResult = mamManager.queryArchive(start, end);
|
||||
```
|
||||
*start* is a `Date`
|
||||
|
||||
*end* is a `Date`
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
MamQueryResult mamQueryResult = mamManager.queryArchive(additionalFields);
|
||||
```
|
||||
*additionalFields* is a `List<FormField>`
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
MamQueryResult mamQueryResult = mamManager.queryArchiveWithStartDate(start);
|
||||
```
|
||||
*start* is a `Date`
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
MamQueryResult mamQueryResult = mamManager.queryArchiveWithEndDate(end);
|
||||
```
|
||||
*end* is a `Date`
|
||||
|
||||
or
|
||||
|
||||
```
|
||||
MamQueryResult mamQueryResult = mamManager.queryArchive(max, start, end, withJid, additionalFields);
|
||||
```
|
||||
*max* is an `Integer`
|
||||
|
||||
*start* is a `Date`
|
||||
|
||||
*end* is a `Date`
|
||||
|
||||
*withJid* is a `Jid`
|
||||
|
||||
*additionalFields* is a `List<FormField>`
|
||||
|
||||
|
||||
**Get data from mamQueryResult object**
|
||||
|
||||
```
|
||||
// Get forwarded messages
|
||||
List<Forwarded> forwardedMessages = mamQueryResult.forwardedMessages;
|
||||
|
||||
// Get fin IQ
|
||||
MamFinIQ mamFinIQ = mamQueryResult.mamFin;
|
||||
```
|
||||
|
||||
|
||||
Paging
|
||||
------
|
||||
|
||||
**Get a page**
|
||||
|
||||
```
|
||||
MamQueryResult mamQueryResult = mamManager.page(dataForm, rsmSet);
|
||||
```
|
||||
*dataForm* is a `DataForm`
|
||||
|
||||
*rsmSet* is a `RSMSet`
|
||||
|
||||
|
||||
**Get the next page**
|
||||
|
||||
```
|
||||
MamQueryResult mamQueryResult = mamManager.pageNext(previousMamQueryResult, count);
|
||||
```
|
||||
*previousMamQueryResult* is a `MamQueryResult`
|
||||
|
||||
*count* is an `int`
|
||||
|
||||
|
||||
**Get page before the first message saved (specific chat)**
|
||||
|
||||
```
|
||||
MamQueryResult mamQueryResult = mamManager.pageBefore(chatJid, firstMessageId, max);
|
||||
```
|
||||
*chatJid* is a `Jid`
|
||||
|
||||
*firstMessageId* is a `String`
|
||||
|
||||
*max* is an `int`
|
||||
|
||||
|
||||
**Get page after the last message saved (specific chat)**
|
||||
|
||||
```
|
||||
MamQueryResult mamQueryResult = mamManager.pageAfter(chatJid, lastMessageId, max);
|
||||
```
|
||||
*chatJid* is a `Jid`
|
||||
|
||||
*lastMessageId* is a `String`
|
||||
|
||||
*max* is an `int`
|
||||
|
||||
|
||||
Get form fields
|
||||
---------------
|
||||
|
||||
```
|
||||
List<FormField> formFields = mamManager.retrieveFormFields();
|
||||
```
|
||||
|
||||
|
||||
Get preferences
|
||||
---------------
|
||||
|
||||
```
|
||||
MamPrefsResult mamPrefsResult = mamManager.retrieveArchivingPreferences();
|
||||
|
||||
// Get preferences IQ
|
||||
MamPrefsIQ mamPrefs = mamPrefsResult.mamPrefs;
|
||||
|
||||
// Obtain always and never list
|
||||
List<Jid> alwaysJids = mamPrefs.getAlwaysJids();
|
||||
List<Jid> neverJids = mamPrefs.getNeverJids();
|
||||
|
||||
// Obtain default behaviour (can be 'always', 'never' or 'roster')
|
||||
DefaultBehavior defaultBehavior = mamPrefs.getDefault();
|
||||
|
||||
// Get the data form
|
||||
DataForm dataForm = mamPrefsResult.form;
|
||||
```
|
||||
|
||||
|
||||
Update preferences
|
||||
------------------
|
||||
|
||||
```
|
||||
MamPrefsResult mamPrefsResult = mamManager.updateArchivingPreferences(alwaysJids, neverJids, defaultBehavior);
|
||||
```
|
||||
*alwaysJids* is a `List<Jid>`
|
||||
|
||||
*neverJids* is a `List<Jid>`
|
||||
|
||||
*defaultBehavior* is a `DefaultBehavior`
|
||||
|
||||
See the javadoc of `MamManager` for details.
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2003-2007 Jive Software, 2016-2017 Florian Schmaus.
|
||||
* Copyright 2003-2007 Jive Software, 2016-2018 Florian Schmaus.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -17,6 +17,8 @@
|
|||
|
||||
package org.jivesoftware.smack;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
|
@ -55,7 +57,7 @@ public class StanzaCollector {
|
|||
|
||||
private final Stanza request;
|
||||
|
||||
private boolean cancelled = false;
|
||||
private volatile boolean cancelled = false;
|
||||
|
||||
/**
|
||||
* Creates a new stanza collector. If the stanza filter is <tt>null</tt>, then
|
||||
|
@ -268,6 +270,27 @@ public class StanzaCollector {
|
|||
return result;
|
||||
}
|
||||
|
||||
private List<Stanza> collectedCache;
|
||||
|
||||
/**
|
||||
* Return a list of all collected stanzas. This method must be invoked after the collector has been cancelled.
|
||||
*
|
||||
* @return a list of collected stanzas.
|
||||
* @since 4.3.0
|
||||
*/
|
||||
public List<Stanza> getCollectedStanzasAfterCancelled() {
|
||||
if (!cancelled) {
|
||||
throw new IllegalStateException("Stanza collector was not yet cancelled");
|
||||
}
|
||||
|
||||
if (collectedCache == null) {
|
||||
collectedCache = new ArrayList<>(getCollectedCount());
|
||||
resultQueue.drainTo(collectedCache);
|
||||
}
|
||||
|
||||
return collectedCache;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the number of collected stanzas this stanza collector has collected so far.
|
||||
*
|
||||
|
@ -300,7 +323,7 @@ public class StanzaCollector {
|
|||
|
||||
private void throwIfCancelled() {
|
||||
if (cancelled) {
|
||||
throw new IllegalStateException("Packet collector already cancelled");
|
||||
throw new IllegalStateException("Stanza collector already cancelled");
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,94 @@
|
|||
/**
|
||||
*
|
||||
* Copyright the original author or authors
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smack.util;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* Extends a {@link HashMap} with {@link WeakReference} values, so that
|
||||
* weak references which have been cleared are periodically removed from
|
||||
* the map. The cleaning occurs as part of {@link #put}, after a specific
|
||||
* number ({@link #cleanInterval}) of calls to {@link #put}.
|
||||
*
|
||||
* @param <K> The key type.
|
||||
* @param <V> The value type.
|
||||
*
|
||||
* @author Boris Grozev
|
||||
*/
|
||||
public class CleaningWeakReferenceMap<K, V>
|
||||
extends HashMap<K, WeakReference<V>> {
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
/**
|
||||
* The number of calls to {@link #put} after which to clean this map
|
||||
* (i.e. remove cleared {@link WeakReference}s from it).
|
||||
*/
|
||||
private final int cleanInterval;
|
||||
|
||||
/**
|
||||
* The number of times {@link #put} has been called on this instance
|
||||
* since the last time it was {@link #clean}ed.
|
||||
*/
|
||||
private int numberOfInsertsSinceLastClean = 0;
|
||||
|
||||
/**
|
||||
* Initializes a new {@link CleaningWeakReferenceMap} instance with the
|
||||
* default clean interval.
|
||||
*/
|
||||
public CleaningWeakReferenceMap() {
|
||||
this(50);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes a new {@link CleaningWeakReferenceMap} instance with a given
|
||||
* clean interval.
|
||||
* @param cleanInterval the number of calls to {@link #put} after which the
|
||||
* map will clean itself.
|
||||
*/
|
||||
public CleaningWeakReferenceMap(int cleanInterval) {
|
||||
this.cleanInterval = cleanInterval;
|
||||
}
|
||||
|
||||
@Override
|
||||
public WeakReference<V> put(K key, WeakReference<V> value) {
|
||||
WeakReference<V> ret = super.put(key, value);
|
||||
|
||||
if (numberOfInsertsSinceLastClean++ > cleanInterval) {
|
||||
numberOfInsertsSinceLastClean = 0;
|
||||
clean();
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all cleared entries from this map (i.e. entries whose value
|
||||
* is a cleared {@link WeakReference}).
|
||||
*/
|
||||
private void clean() {
|
||||
Iterator<Entry<K, WeakReference<V>>> iter = entrySet().iterator();
|
||||
while (iter.hasNext()) {
|
||||
Entry<K, WeakReference<V>> e = iter.next();
|
||||
if (e != null && e.getValue() != null
|
||||
&& e.getValue().get() == null) {
|
||||
iter.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -451,6 +451,16 @@ public class StringUtils {
|
|||
return cs;
|
||||
}
|
||||
|
||||
public static <CS extends CharSequence> CS requireNullOrNotEmpty(CS cs, String message) {
|
||||
if (cs == null) {
|
||||
return null;
|
||||
}
|
||||
if (cs.toString().isEmpty()) {
|
||||
throw new IllegalArgumentException(message);
|
||||
}
|
||||
return cs;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the String representation of the given char sequence if it is not null.
|
||||
*
|
||||
|
|
|
@ -75,7 +75,9 @@ public class XmlStringBuilder implements Appendable, CharSequence, Element {
|
|||
* @return the XmlStringBuilder
|
||||
*/
|
||||
public XmlStringBuilder element(String name, String content) {
|
||||
assert content != null;
|
||||
if (content.isEmpty()) {
|
||||
return emptyElement(name);
|
||||
}
|
||||
openElement(name);
|
||||
escape(content);
|
||||
closeElement(name);
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2014 Florian Schmaus
|
||||
* Copyright 2014-2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -26,10 +26,14 @@ import org.xml.sax.SAXException;
|
|||
|
||||
public class XmlUnitUtils {
|
||||
|
||||
// TOOD: Remove this method.
|
||||
public static void assertSimilar(CharSequence expected, CharSequence actual) throws SAXException, IOException {
|
||||
assertXmlSimilar(expected, actual);
|
||||
}
|
||||
|
||||
public static void assertXmlSimilar(CharSequence expected, CharSequence actual) throws SAXException, IOException {
|
||||
Diff diff = new Diff(expected.toString(), actual.toString());
|
||||
diff.overrideElementQualifier(new RecursiveElementNameAndTextQualifier());
|
||||
assertXMLEqual(diff, true);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016 Fernando Ramirez
|
||||
* Copyright 2016 Fernando Ramirez, 2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,23 +16,24 @@
|
|||
*/
|
||||
package org.jivesoftware.smackx.mam;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.jivesoftware.smackx.mam.MamManager.MamQueryArgs;
|
||||
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.jid.JidTestUtil;
|
||||
import org.jxmpp.util.XmppDateTime;
|
||||
|
||||
public class FiltersTest extends MamTest {
|
||||
|
||||
private static String getMamXMemberWith(List<String> fieldsNames, List<String> fieldsValues) {
|
||||
private static String getMamXMemberWith(List<String> fieldsNames, List<? extends CharSequence> fieldsValues) {
|
||||
String xml = "<x xmlns='jabber:x:data' type='submit'>" + "<field var='FORM_TYPE' type='hidden'>" + "<value>"
|
||||
+ MamElements.NAMESPACE + "</value>" + "</field>";
|
||||
|
||||
|
@ -47,115 +48,47 @@ public class FiltersTest extends MamTest {
|
|||
|
||||
@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);
|
||||
|
||||
MamQueryArgs mamQueryArgs = MamQueryArgs.builder().limitResultsSince(date).build();
|
||||
DataForm dataForm = mamQueryArgs.getDataForm();
|
||||
|
||||
List<String> fields = new ArrayList<>();
|
||||
fields.add("start");
|
||||
List<String> values = new ArrayList<>();
|
||||
values.add(XmppDateTime.formatXEP0082Date(date));
|
||||
|
||||
Assert.assertEquals(dataForm.toXML(null).toString(), getMamXMemberWith(fields, values));
|
||||
assertEquals(getMamXMemberWith(fields, values), dataForm.toXML(null).toString());
|
||||
}
|
||||
|
||||
@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);
|
||||
|
||||
MamQueryArgs mamQueryArgs = MamQueryArgs.builder().limitResultsBefore(date).build();
|
||||
DataForm dataForm = mamQueryArgs.getDataForm();
|
||||
|
||||
List<String> fields = new ArrayList<>();
|
||||
fields.add("end");
|
||||
List<String> values = new ArrayList<>();
|
||||
values.add(XmppDateTime.formatXEP0082Date(date));
|
||||
|
||||
Assert.assertEquals(dataForm.toXML(null).toString(), getMamXMemberWith(fields, values));
|
||||
assertEquals(getMamXMemberWith(fields, values), dataForm.toXML(null).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkWithJidFilter() throws Exception {
|
||||
Method methodAddJidFilter = MamManager.class.getDeclaredMethod("addWithJid", Jid.class, DataForm.class);
|
||||
methodAddJidFilter.setAccessible(true);
|
||||
Jid jid = JidTestUtil.BARE_JID_1;
|
||||
|
||||
String jid = "test@jid.com";
|
||||
DataForm dataForm = getNewMamForm();
|
||||
methodAddJidFilter.invoke(mamManager, JidCreate.from(jid), dataForm);
|
||||
MamQueryArgs mamQueryArgs = MamQueryArgs.builder().limitResultsToJid(jid).build();
|
||||
DataForm dataForm = mamQueryArgs.getDataForm();
|
||||
|
||||
List<String> fields = new ArrayList<>();
|
||||
fields.add("with");
|
||||
List<String> values = new ArrayList<>();
|
||||
List<CharSequence> values = new ArrayList<>();
|
||||
values.add(jid);
|
||||
|
||||
Assert.assertEquals(dataForm.toXML(null).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(null).toString();
|
||||
|
||||
List<String> fields = new ArrayList<>();
|
||||
List<String> 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));
|
||||
assertEquals(getMamXMemberWith(fields, values), dataForm.toXML(null).toString());
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016 Fernando Ramirez
|
||||
* Copyright 2016 Fernando Ramirez, 2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,11 +16,10 @@
|
|||
*/
|
||||
package org.jivesoftware.smackx.mam;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.StreamOpen;
|
||||
|
||||
import org.jivesoftware.smackx.mam.MamManager.MamQueryArgs;
|
||||
import org.jivesoftware.smackx.mam.element.MamElements;
|
||||
import org.jivesoftware.smackx.mam.element.MamQueryIQ;
|
||||
import org.jivesoftware.smackx.xdata.packet.DataForm;
|
||||
|
@ -37,16 +36,14 @@ public class ResultsLimitTest extends MamTest {
|
|||
|
||||
@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);
|
||||
MamQueryArgs mamQueryArgs = MamQueryArgs.builder().setResultPageSize(10).build();
|
||||
mamQueryArgs.maybeAddRsmSet(mamQueryIQ);
|
||||
Assert.assertEquals(mamQueryIQ.toXML(StreamOpen.CLIENT_NAMESPACE).toString(), resultsLimitStanza);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016 Fernando Ramirez
|
||||
* Copyright 2016 Fernando Ramirez, 2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -16,18 +16,17 @@
|
|||
*/
|
||||
package org.jivesoftware.smackx.mam;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import static org.jivesoftware.smack.test.util.XmlUnitUtils.assertXmlSimilar;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.jivesoftware.smack.packet.StreamOpen;
|
||||
|
||||
import org.jivesoftware.smackx.mam.MamManager.MamQueryArgs;
|
||||
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.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class RetrieveFormFieldsTest extends MamTest {
|
||||
|
@ -46,19 +45,11 @@ public class RetrieveFormFieldsTest extends MamTest {
|
|||
MamQueryIQ mamQueryIQ = new MamQueryIQ(queryId);
|
||||
mamQueryIQ.setStanzaId("sarasa");
|
||||
|
||||
Assert.assertEquals(mamQueryIQ.toXML(StreamOpen.CLIENT_NAMESPACE).toString(), retrieveFormFieldStanza);
|
||||
assertEquals(retrieveFormFieldStanza, mamQueryIQ.toXML(StreamOpen.CLIENT_NAMESPACE).toString());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void checkAddAdditionalFieldsStanza() throws Exception {
|
||||
Method methodAddAdditionalFields = MamManager.class.getDeclaredMethod("addAdditionalFields", List.class,
|
||||
DataForm.class);
|
||||
methodAddAdditionalFields.setAccessible(true);
|
||||
|
||||
DataForm dataForm = getNewMamForm();
|
||||
|
||||
List<FormField> additionalFields = new ArrayList<>();
|
||||
|
||||
FormField field1 = new FormField("urn:example:xmpp:free-text-search");
|
||||
field1.setType(FormField.Type.text_single);
|
||||
field1.addValue("Hi");
|
||||
|
@ -67,14 +58,15 @@ public class RetrieveFormFieldsTest extends MamTest {
|
|||
field2.setType(FormField.Type.jid_single);
|
||||
field2.addValue("Hi2");
|
||||
|
||||
additionalFields.add(field1);
|
||||
additionalFields.add(field2);
|
||||
|
||||
methodAddAdditionalFields.invoke(mamManager, additionalFields, dataForm);
|
||||
MamQueryArgs mamQueryArgs = MamQueryArgs.builder()
|
||||
.withAdditionalFormField(field1)
|
||||
.withAdditionalFormField(field2)
|
||||
.build();
|
||||
DataForm dataForm = mamQueryArgs.getDataForm();
|
||||
|
||||
String dataFormResult = dataForm.toXML(null).toString();
|
||||
|
||||
Assert.assertEquals(dataFormResult, additionalFieldsStanza);
|
||||
assertXmlSimilar(additionalFieldsStanza, dataFormResult);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -210,6 +210,7 @@ public final class Socks5Proxy {
|
|||
|
||||
if (this.serverSocket != null) {
|
||||
this.serverThread = new Thread(this.serverProcess);
|
||||
this.serverThread.setName("Smack Local SOCKS5 Proxy");
|
||||
this.serverThread.start();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,12 @@
|
|||
*/
|
||||
package org.jivesoftware.smackx.forward.packet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import org.jivesoftware.smack.packet.ExtensionElement;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smack.util.XmlStringBuilder;
|
||||
|
||||
|
@ -112,4 +117,21 @@ public class Forwarded implements ExtensionElement {
|
|||
public static Forwarded from(Stanza packet) {
|
||||
return packet.getExtension(ELEMENT, NAMESPACE);
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract messages in a collection of forwarded elements. Note that it is required that the {@link Forwarded} in
|
||||
* the given collection only contain {@link Message} stanzas.
|
||||
*
|
||||
* @param forwardedCollection the collection to extract from.
|
||||
* @return a list a the extracted messages.
|
||||
* @since 4.3.0
|
||||
*/
|
||||
public static List<Message> extractMessagesFrom(Collection<Forwarded> forwardedCollection) {
|
||||
List<Message> res = new ArrayList<>(forwardedCollection.size());
|
||||
for (Forwarded forwarded : forwardedCollection) {
|
||||
Message message = (Message) forwarded.forwardedPacket;
|
||||
res.add(message);
|
||||
}
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,7 @@ import org.jivesoftware.smack.packet.IQ;
|
|||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.packet.Presence;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smack.util.StringUtils;
|
||||
import org.jivesoftware.smack.util.Objects;
|
||||
|
||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||
import org.jivesoftware.smackx.disco.packet.DiscoverInfo;
|
||||
|
@ -149,7 +149,7 @@ public class MultiUserChat {
|
|||
private final StanzaListener declinesListener;
|
||||
|
||||
private String subject;
|
||||
private Resourcepart nickname;
|
||||
private EntityFullJid myRoomJid;
|
||||
private boolean joined = false;
|
||||
private StanzaCollector messageCollector;
|
||||
|
||||
|
@ -208,7 +208,7 @@ public class MultiUserChat {
|
|||
LOGGER.warning("Presence not from a full JID: " + presence.getFrom());
|
||||
return;
|
||||
}
|
||||
final String myRoomJID = MultiUserChat.this.room + "/" + nickname;
|
||||
final EntityFullJid myRoomJID = myRoomJid;
|
||||
final boolean isUserStatusModification = presence.getFrom().equals(myRoomJID);
|
||||
|
||||
asyncButOrdered.performAsyncButOrdered(MultiUserChat.this, new Runnable() {
|
||||
|
@ -383,7 +383,9 @@ public class MultiUserChat {
|
|||
|
||||
// This presence must be send from a full JID. We use the resourcepart of this JID as nick, since the room may
|
||||
// performed roomnick rewriting
|
||||
this.nickname = presence.getFrom().asEntityFullJidIfPossible().getResourcepart();
|
||||
Resourcepart receivedNickname = presence.getFrom().getResourceOrThrow();
|
||||
setNickname(receivedNickname);
|
||||
|
||||
joined = true;
|
||||
|
||||
// Update the list of joined rooms
|
||||
|
@ -391,6 +393,10 @@ public class MultiUserChat {
|
|||
return presence;
|
||||
}
|
||||
|
||||
private void setNickname(Resourcepart nickname) {
|
||||
this.myRoomJid = JidCreate.entityFullFrom(room, nickname);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a new MUC enter configuration builder.
|
||||
*
|
||||
|
@ -486,6 +492,7 @@ public class MultiUserChat {
|
|||
* @deprecated use {@link #createOrJoin(MucEnterConfiguration)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
// TODO Remove in Smack 4.4
|
||||
public MucCreateConfigFormHandle createOrJoin(Resourcepart nickname, String password, @SuppressWarnings("deprecation") DiscussionHistory history, long timeout)
|
||||
throws NoResponseException, XMPPErrorException, InterruptedException, MucAlreadyJoinedException, NotConnectedException, NotAMucServiceException {
|
||||
MucEnterConfiguration.Builder builder = getEnterConfigurationBuilder(nickname).withPassword(
|
||||
|
@ -684,6 +691,7 @@ public class MultiUserChat {
|
|||
* @deprecated use {@link #join(MucEnterConfiguration)} instead.
|
||||
*/
|
||||
@Deprecated
|
||||
// TODO Remove in Smack 4.4
|
||||
public void join(
|
||||
Resourcepart nickname,
|
||||
String password,
|
||||
|
@ -756,10 +764,15 @@ public class MultiUserChat {
|
|||
// throw.
|
||||
userHasLeft();
|
||||
|
||||
final EntityFullJid myRoomJid = this.myRoomJid;
|
||||
if (myRoomJid == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// We leave a room by sending a presence packet where the "to"
|
||||
// field is in the form "roomName@service/nickname"
|
||||
Presence leavePresence = new Presence(Presence.Type.unavailable);
|
||||
leavePresence.setTo(JidCreate.fullFrom(room, nickname));
|
||||
leavePresence.setTo(myRoomJid);
|
||||
connection.sendStanza(leavePresence);
|
||||
}
|
||||
|
||||
|
@ -1096,7 +1109,11 @@ public class MultiUserChat {
|
|||
* @return the nickname currently being used.
|
||||
*/
|
||||
public Resourcepart getNickname() {
|
||||
return nickname;
|
||||
final EntityFullJid myRoomJid = this.myRoomJid;
|
||||
if (myRoomJid == null) {
|
||||
return null;
|
||||
}
|
||||
return myRoomJid.getResourcepart();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1114,7 +1131,7 @@ public class MultiUserChat {
|
|||
* @throws MucNotJoinedException
|
||||
*/
|
||||
public synchronized void changeNickname(Resourcepart nickname) throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException, MucNotJoinedException {
|
||||
StringUtils.requireNotNullOrEmpty(nickname, "Nickname must not be null or blank.");
|
||||
Objects.requireNonNull(nickname, "Nickname must not be null or blank.");
|
||||
// Check that we already have joined the room before attempting to change the
|
||||
// nickname.
|
||||
if (!joined) {
|
||||
|
@ -1137,7 +1154,8 @@ public class MultiUserChat {
|
|||
// exception will be thrown
|
||||
response.nextResultOrThrow();
|
||||
|
||||
this.nickname = nickname;
|
||||
// TODO: Shouldn't this handle nickname rewriting by the MUC service?
|
||||
setNickname(nickname);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1152,7 +1170,11 @@ public class MultiUserChat {
|
|||
* @throws MucNotJoinedException
|
||||
*/
|
||||
public void changeAvailabilityStatus(String status, Presence.Mode mode) throws NotConnectedException, InterruptedException, MucNotJoinedException {
|
||||
StringUtils.requireNotNullOrEmpty(nickname, "Nickname must not be null or blank.");
|
||||
final EntityFullJid myRoomJid = this.myRoomJid;
|
||||
if (myRoomJid == null) {
|
||||
throw new MucNotJoinedException(this);
|
||||
}
|
||||
|
||||
// Check that we already have joined the room before attempting to change the
|
||||
// availability status.
|
||||
if (!joined) {
|
||||
|
@ -1163,7 +1185,7 @@ public class MultiUserChat {
|
|||
Presence joinPresence = new Presence(Presence.Type.available);
|
||||
joinPresence.setStatus(status);
|
||||
joinPresence.setMode(mode);
|
||||
joinPresence.setTo(JidCreate.fullFrom(room, nickname));
|
||||
joinPresence.setTo(myRoomJid);
|
||||
|
||||
// Send join packet.
|
||||
connection.sendStanza(joinPresence);
|
||||
|
@ -2398,7 +2420,7 @@ public class MultiUserChat {
|
|||
|
||||
// Reset occupant information.
|
||||
occupantsMap.clear();
|
||||
nickname = null;
|
||||
myRoomJid = null;
|
||||
userHasLeft();
|
||||
}
|
||||
else {
|
||||
|
@ -2418,7 +2440,7 @@ public class MultiUserChat {
|
|||
|
||||
// Reset occupant information.
|
||||
occupantsMap.clear();
|
||||
nickname = null;
|
||||
myRoomJid = null;
|
||||
userHasLeft();
|
||||
}
|
||||
}
|
||||
|
@ -2437,11 +2459,21 @@ public class MultiUserChat {
|
|||
|
||||
// Reset occupant information.
|
||||
occupantsMap.clear();
|
||||
nickname = null;
|
||||
myRoomJid = null;
|
||||
userHasLeft();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the XMPP connection associated with this chat instance.
|
||||
*
|
||||
* @return the associated XMPP connection.
|
||||
* @since 4.3.0
|
||||
*/
|
||||
public XMPPConnection getXmppConnection() {
|
||||
return connection;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "MUC: " + room + "(" + connection.getUser() + ")";
|
||||
|
|
|
@ -19,7 +19,6 @@ package org.jivesoftware.smackx.muc;
|
|||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
@ -46,6 +45,7 @@ import org.jivesoftware.smack.filter.StanzaTypeFilter;
|
|||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smack.util.Async;
|
||||
import org.jivesoftware.smack.util.CleaningWeakReferenceMap;
|
||||
|
||||
import org.jivesoftware.smackx.disco.AbstractNodeInformationProvider;
|
||||
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
|
||||
|
@ -144,7 +144,7 @@ public final class MultiUserChatManager extends Manager {
|
|||
* those instances to get garbage collected. Note that MultiUserChat instances can not get garbage collected while
|
||||
* the user is joined, because then the MUC will have PacketListeners added to the XMPPConnection.
|
||||
*/
|
||||
private final Map<EntityBareJid, WeakReference<MultiUserChat>> multiUserChats = new HashMap<>();
|
||||
private final Map<EntityBareJid, WeakReference<MultiUserChat>> multiUserChats = new CleaningWeakReferenceMap<>();
|
||||
|
||||
private boolean autoJoinOnReconnect;
|
||||
|
||||
|
|
|
@ -17,8 +17,10 @@
|
|||
|
||||
package org.jivesoftware.smackx.xdata;
|
||||
|
||||
import java.text.ParseException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.jivesoftware.smack.packet.NamedElement;
|
||||
|
@ -27,6 +29,8 @@ import org.jivesoftware.smack.util.XmlStringBuilder;
|
|||
|
||||
import org.jivesoftware.smackx.xdatavalidation.packet.ValidateElement;
|
||||
|
||||
import org.jxmpp.util.XmppDateTime;
|
||||
|
||||
/**
|
||||
* Represents a field of a form. The field could be used to represent a question to complete,
|
||||
* a completed question or a data returned from a search. The exact interpretation of the field
|
||||
|
@ -266,6 +270,21 @@ public class FormField implements NamedElement {
|
|||
return firstValue.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the first value of this form field as XEP-0082 date/time format and returns a date instance or {@code null}.
|
||||
*
|
||||
* @return a Date instance representing the date/time information of the first value of this field.
|
||||
* @throws ParseException if parsing fails.
|
||||
* @since 4.3.0
|
||||
*/
|
||||
public Date getFirstValueAsDate() throws ParseException {
|
||||
String valueString = getFirstValue();
|
||||
if (valueString == null) {
|
||||
return null;
|
||||
}
|
||||
return XmppDateTime.parseXEP0082Date(valueString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the variable name that the question is filling out.
|
||||
* <p>
|
||||
|
@ -361,6 +380,18 @@ public class FormField implements NamedElement {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the given Date as XEP-0082 formated string by invoking {@link #addValue(CharSequence)} after the date
|
||||
* instance was formated.
|
||||
*
|
||||
* @param date the date instance to add as XEP-0082 formated string.
|
||||
* @since 4.3.0
|
||||
*/
|
||||
public void addValue(Date date) {
|
||||
String dateString = XmppDateTime.formatXEP0082Date(date);
|
||||
addValue(dateString);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a default values to the question if the question is part of a form to fill out.
|
||||
* Otherwise, adds an answered values to the question.
|
||||
|
@ -378,7 +409,7 @@ public class FormField implements NamedElement {
|
|||
*/
|
||||
protected void resetValues() {
|
||||
synchronized (values) {
|
||||
values.removeAll(new ArrayList<>(values));
|
||||
values.clear();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
package org.jivesoftware.smackx.xdata.packet;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
|
@ -234,6 +235,26 @@ public class DataForm implements ExtensionElement {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the given fields to this form.
|
||||
*
|
||||
* @param fieldsToAdd
|
||||
* @return true if a field was overridden.
|
||||
* @since 4.3.0
|
||||
*/
|
||||
public boolean addFields(Collection<FormField> fieldsToAdd) {
|
||||
boolean fieldOverridden = false;
|
||||
synchronized (fields) {
|
||||
for (FormField field : fieldsToAdd) {
|
||||
FormField previousField = fields.put(field.getVariable(), field);
|
||||
if (previousField != null) {
|
||||
fieldOverridden = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return fieldOverridden;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new instruction to the list of instructions that explain how to fill out the form
|
||||
* and what the form is about. The dataform could include multiple instructions since each
|
||||
|
|
|
@ -0,0 +1,50 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.jivesoftware.smackx.commands.provider;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import org.jivesoftware.smack.packet.IQ;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
import org.jivesoftware.smack.packet.StanzaError;
|
||||
import org.jivesoftware.smack.util.PacketParserUtils;
|
||||
|
||||
import org.jivesoftware.smackx.commands.AdHocCommand;
|
||||
import org.jivesoftware.smackx.commands.packet.AdHocCommandData;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class CommandsProviderTest {
|
||||
|
||||
@Test
|
||||
public void parseErrorWithRequest() throws Exception {
|
||||
final String errorWithRequest = "<iq id='sid' type='error' from='from@example.com' to='to@example.com'>"
|
||||
+ "<command xmlns='http://jabber.org/protocol/commands' node='http://example.com' action='execute'>"
|
||||
+ "</command>" + "<error type='cancel'>"
|
||||
+ "<bad-request xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>" + "</error>" + "</iq>";
|
||||
|
||||
final Stanza requestStanza = PacketParserUtils.parseStanza(errorWithRequest);
|
||||
final AdHocCommandData adHocIq = (AdHocCommandData) requestStanza;
|
||||
|
||||
assertEquals(IQ.Type.error, adHocIq.getType());
|
||||
assertEquals(AdHocCommand.Action.execute, adHocIq.getAction());
|
||||
|
||||
StanzaError error = adHocIq.getError();
|
||||
assertEquals(StanzaError.Type.CANCEL, error.getType());
|
||||
assertEquals(StanzaError.Condition.bad_request, error.getCondition());
|
||||
}
|
||||
}
|
|
@ -1,6 +1,6 @@
|
|||
/**
|
||||
*
|
||||
* Copyright 2016 Fernando Ramirez
|
||||
* Copyright 2016 Fernando Ramirez, 2018 Florian Schmaus
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
@ -17,23 +17,30 @@
|
|||
package org.jivesoftware.smackx.mam;
|
||||
|
||||
import static org.junit.Assert.assertEquals;
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
|
||||
import org.jivesoftware.smack.SmackException.NoResponseException;
|
||||
import org.jivesoftware.smack.SmackException.NotConnectedException;
|
||||
import org.jivesoftware.smack.SmackException.NotLoggedInException;
|
||||
import org.jivesoftware.smack.StanzaListener;
|
||||
import org.jivesoftware.smack.XMPPException.XMPPErrorException;
|
||||
import org.jivesoftware.smack.filter.MessageWithBodiesFilter;
|
||||
import org.jivesoftware.smack.packet.Message;
|
||||
import org.jivesoftware.smack.packet.Stanza;
|
||||
|
||||
import org.jivesoftware.smackx.forward.packet.Forwarded;
|
||||
import org.jivesoftware.smackx.mam.MamManager.MamQueryResult;
|
||||
import org.jivesoftware.smackx.mam.element.MamPrefsIQ;
|
||||
import org.jivesoftware.smackx.mam.MamManager.MamQuery;
|
||||
import org.jivesoftware.smackx.mam.MamManager.MamQueryArgs;
|
||||
|
||||
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.igniterealtime.smack.inttest.util.SimpleResultSyncPoint;
|
||||
import org.jxmpp.jid.EntityBareJid;
|
||||
|
||||
public class MamIntegrationTest extends AbstractSmackIntegrationTest {
|
||||
|
@ -41,7 +48,7 @@ public class MamIntegrationTest extends AbstractSmackIntegrationTest {
|
|||
private final MamManager mamManagerConTwo;
|
||||
|
||||
public MamIntegrationTest(SmackIntegrationTestEnvironment environment) throws NoResponseException,
|
||||
XMPPErrorException, NotConnectedException, InterruptedException, TestNotPossibleException {
|
||||
XMPPErrorException, NotConnectedException, InterruptedException, TestNotPossibleException, NotLoggedInException {
|
||||
super(environment);
|
||||
|
||||
mamManagerConTwo = MamManager.getInstanceFor(conTwo);
|
||||
|
@ -50,33 +57,51 @@ public class MamIntegrationTest extends AbstractSmackIntegrationTest {
|
|||
throw new TestNotPossibleException("Message Archive Management (XEP-0313) is not supported by the server.");
|
||||
}
|
||||
|
||||
// Make sure MAM is archiving messages.
|
||||
mamManagerConTwo.enableMamForAllMessages();
|
||||
}
|
||||
|
||||
@SmackIntegrationTest
|
||||
public void mamTest() throws NotConnectedException, InterruptedException, NoResponseException, XMPPErrorException,
|
||||
NotLoggedInException {
|
||||
public void mamTest() throws TimeoutException, Exception {
|
||||
EntityBareJid userOne = conOne.getUser().asEntityBareJid();
|
||||
EntityBareJid userTwo = conTwo.getUser().asEntityBareJid();
|
||||
|
||||
// Make sure MAM is archiving messages.
|
||||
mamManagerConTwo.updateArchivingPreferences(null, null, MamPrefsIQ.DefaultBehavior.always);
|
||||
|
||||
Message message = new Message(userTwo);
|
||||
String messageId = message.setStanzaId();
|
||||
String messageBody = "test message";
|
||||
final String messageBody = "Test MAM message (" + testRunId + ')';
|
||||
message.setBody(messageBody);
|
||||
|
||||
conOne.sendStanza(message);
|
||||
final SimpleResultSyncPoint messageReceived = new SimpleResultSyncPoint();
|
||||
|
||||
int pageSize = 20;
|
||||
MamQueryResult mamQueryResult = mamManagerConTwo.queryArchive(pageSize, null, null, userOne, null);
|
||||
final StanzaListener stanzaListener = new StanzaListener() {
|
||||
@Override
|
||||
public void processStanza(Stanza stanza) {
|
||||
Message message = (Message) stanza;
|
||||
if (message.getBody().equals(messageBody)) {
|
||||
messageReceived.signal();
|
||||
}
|
||||
}
|
||||
};
|
||||
conTwo.addAsyncStanzaListener(stanzaListener, MessageWithBodiesFilter.INSTANCE);
|
||||
|
||||
while (!mamQueryResult.mamFin.isComplete()) {
|
||||
mamQueryResult = mamManagerConTwo.pageNext(mamQueryResult, pageSize);
|
||||
try {
|
||||
conOne.sendStanza(message);
|
||||
|
||||
messageReceived.waitForResult(timeout);
|
||||
} finally {
|
||||
conTwo.removeAsyncStanzaListener(stanzaListener);
|
||||
}
|
||||
|
||||
List<Forwarded> forwardedMessages = mamQueryResult.forwardedMessages;
|
||||
Message mamMessage = (Message) forwardedMessages.get(forwardedMessages.size() - 1).getForwardedStanza();
|
||||
MamQueryArgs mamQueryArgs = MamQueryArgs.builder()
|
||||
.setResultPageSizeTo(1)
|
||||
.limitResultsToJid(userOne)
|
||||
.queryLastPage()
|
||||
.build();
|
||||
MamQuery mamQuery = mamManagerConTwo.queryArchive(mamQueryArgs);
|
||||
|
||||
assertEquals(1, mamQuery.getMessages().size());
|
||||
|
||||
Message mamMessage = mamQuery.getMessages().get(0);
|
||||
|
||||
assertEquals(messageId, mamMessage.getStanzaId());
|
||||
assertEquals(messageBody, mamMessage.getBody());
|
||||
|
@ -84,4 +109,87 @@ public class MamIntegrationTest extends AbstractSmackIntegrationTest {
|
|||
assertEquals(userTwo, mamMessage.getTo());
|
||||
}
|
||||
|
||||
@SmackIntegrationTest
|
||||
public void mamPageTest() throws TimeoutException, Exception {
|
||||
final int messagesPerPage = 10;
|
||||
final int numPages = 3;
|
||||
final int totalMessages = messagesPerPage * numPages;
|
||||
final List<Message> outgoingMessages = new ArrayList<>(totalMessages);
|
||||
final EntityBareJid userOne = conOne.getUser().asEntityBareJid();
|
||||
final EntityBareJid userTwo = conTwo.getUser().asEntityBareJid();
|
||||
final SimpleResultSyncPoint allMessagesReceived = new SimpleResultSyncPoint();
|
||||
final String lastMessageArchiveUid = mamManagerConTwo.getMessageUidOfLatestMessage();
|
||||
|
||||
for (int i = 0; i < totalMessages; i++) {
|
||||
String messageBody = "MAM Page Test " + testRunId + ' ' + (i + 1);
|
||||
Message message = new Message(userTwo, messageBody);
|
||||
outgoingMessages.add(message);
|
||||
}
|
||||
|
||||
final String lastBody = outgoingMessages.get(outgoingMessages.size() - 1).getBody();
|
||||
|
||||
final StanzaListener stanzaListener = new StanzaListener() {
|
||||
@Override
|
||||
public void processStanza(Stanza stanza) {
|
||||
Message message = (Message) stanza;
|
||||
if (message.getBody().equals(lastBody)) {
|
||||
allMessagesReceived.signal();
|
||||
}
|
||||
}
|
||||
};
|
||||
conTwo.addAsyncStanzaListener(stanzaListener, MessageWithBodiesFilter.INSTANCE);
|
||||
|
||||
try {
|
||||
for (Message message : outgoingMessages) {
|
||||
conOne.sendStanza(message);
|
||||
}
|
||||
|
||||
allMessagesReceived.waitForResult(timeout);
|
||||
} finally {
|
||||
conTwo.removeAsyncStanzaListener(stanzaListener);
|
||||
}
|
||||
|
||||
MamQueryArgs mamQueryArgs = MamQueryArgs.builder()
|
||||
.setResultPageSize(messagesPerPage)
|
||||
.limitResultsToJid(userOne)
|
||||
.afterUid(lastMessageArchiveUid)
|
||||
.build();
|
||||
|
||||
MamQuery mamQuery = mamManagerConTwo.queryArchive(mamQueryArgs);
|
||||
|
||||
assertFalse(mamQuery.isComplete());
|
||||
assertEquals(messagesPerPage, mamQuery.getMessageCount());
|
||||
|
||||
List<List<Message>> pages = new ArrayList<>(numPages);
|
||||
pages.add(mamQuery.getMessages());
|
||||
|
||||
for (int additionalPageRequestNum = 0; additionalPageRequestNum < numPages - 1; additionalPageRequestNum++) {
|
||||
List<Message> page = mamQuery.pageNext(messagesPerPage);
|
||||
|
||||
boolean isLastQuery = additionalPageRequestNum == numPages - 2;
|
||||
if (isLastQuery) {
|
||||
assertTrue(mamQuery.isComplete());
|
||||
} else {
|
||||
assertFalse(mamQuery.isComplete());
|
||||
}
|
||||
|
||||
assertEquals(messagesPerPage, page.size());
|
||||
|
||||
pages.add(page);
|
||||
}
|
||||
|
||||
List<Message> queriedMessages = new ArrayList<>(totalMessages);
|
||||
for (List<Message> messages : pages) {
|
||||
queriedMessages.addAll(messages);
|
||||
}
|
||||
|
||||
assertEquals(outgoingMessages.size(), queriedMessages.size());
|
||||
|
||||
for (int i = 0; i < outgoingMessages.size(); i++) {
|
||||
Message outgoingMessage = outgoingMessages.get(i);
|
||||
Message queriedMessage = queriedMessages.get(i);
|
||||
|
||||
assertEquals(outgoingMessage.getBody(), queriedMessage.getBody());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -325,16 +325,16 @@ public final class OmemoManager extends Manager {
|
|||
* Return a list of all OMEMO messages that were found in the MAM query result, that could be successfully decrypted.
|
||||
* Normal cleartext messages are also added to this list.
|
||||
*
|
||||
* @param mamQueryResult mamQueryResult
|
||||
* @param mamQuery The MAM query
|
||||
* @return list of decrypted OmemoMessages
|
||||
* @throws InterruptedException Exception
|
||||
* @throws XMPPException.XMPPErrorException Exception
|
||||
* @throws SmackException.NotConnectedException Exception
|
||||
* @throws SmackException.NoResponseException Exception
|
||||
*/
|
||||
public List<ClearTextMessage> decryptMamQueryResult(MamManager.MamQueryResult mamQueryResult) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException {
|
||||
public List<ClearTextMessage> decryptMamQueryResult(MamManager.MamQuery mamQuery) throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException {
|
||||
List<ClearTextMessage> l = new ArrayList<>();
|
||||
l.addAll(getOmemoService().decryptMamQueryResult(this, mamQueryResult));
|
||||
l.addAll(getOmemoService().decryptMamQueryResult(this, mamQuery));
|
||||
return l;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,6 @@ import org.jivesoftware.smack.util.Async;
|
|||
import org.jivesoftware.smackx.carbons.CarbonCopyReceivedListener;
|
||||
import org.jivesoftware.smackx.carbons.CarbonManager;
|
||||
import org.jivesoftware.smackx.carbons.packet.CarbonExtension;
|
||||
import org.jivesoftware.smackx.forward.packet.Forwarded;
|
||||
import org.jivesoftware.smackx.mam.MamManager;
|
||||
import org.jivesoftware.smackx.muc.MultiUserChat;
|
||||
import org.jivesoftware.smackx.muc.MultiUserChatManager;
|
||||
|
@ -1127,21 +1126,21 @@ public abstract class OmemoService<T_IdKeyPair, T_IdKey, T_PreKey, T_SigPreKey,
|
|||
* @throws SmackException.NotConnectedException
|
||||
* @throws SmackException.NoResponseException
|
||||
*/
|
||||
List<ClearTextMessage> decryptMamQueryResult(OmemoManager omemoManager, MamManager.MamQueryResult mamQueryResult)
|
||||
List<ClearTextMessage> decryptMamQueryResult(OmemoManager omemoManager, MamManager.MamQuery mamQuery)
|
||||
throws InterruptedException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, SmackException.NoResponseException {
|
||||
List<ClearTextMessage> result = new ArrayList<>();
|
||||
for (Forwarded f : mamQueryResult.forwardedMessages) {
|
||||
if (OmemoManager.stanzaContainsOmemoElement(f.getForwardedStanza())) {
|
||||
for (Message message : mamQuery.getMessages()) {
|
||||
if (OmemoManager.stanzaContainsOmemoElement(message)) {
|
||||
// Decrypt OMEMO messages
|
||||
try {
|
||||
result.add(processLocalMessage(omemoManager, f.getForwardedStanza().getFrom().asBareJid(), (Message) f.getForwardedStanza()));
|
||||
result.add(processLocalMessage(omemoManager, message.getFrom().asBareJid(), message));
|
||||
} catch (NoRawSessionException | CorruptedOmemoKeyException | CryptoFailedException e) {
|
||||
LOGGER.log(Level.WARNING, "decryptMamQueryResult failed to decrypt message from "
|
||||
+ f.getForwardedStanza().getFrom() + " due to corrupted session/key: " + e.getMessage());
|
||||
+ message.getFrom() + " due to corrupted session/key: " + e.getMessage());
|
||||
}
|
||||
} else {
|
||||
// Wrap cleartext messages
|
||||
Message m = (Message) f.getForwardedStanza();
|
||||
Message m = message;
|
||||
result.add(new ClearTextMessage(m.getBody(), m,
|
||||
new OmemoMessageInformation(null, null, OmemoMessageInformation.CARBON.NONE, false)));
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue