create new models for IQ, Message & Presence
This commit is contained in:
parent
f16603742f
commit
d2794ccf32
|
@ -78,4 +78,5 @@ public final class Namespace {
|
||||||
public static final String OMEMO_DTLS_SRTP_VERIFICATION =
|
public static final String OMEMO_DTLS_SRTP_VERIFICATION =
|
||||||
"http://gultsch.de/xmpp/drafts/omemo/dlts-srtp-verification";
|
"http://gultsch.de/xmpp/drafts/omemo/dlts-srtp-verification";
|
||||||
public static final String UNIFIED_PUSH = "http://gultsch.de/xmpp/drafts/unified-push";
|
public static final String UNIFIED_PUSH = "http://gultsch.de/xmpp/drafts/unified-push";
|
||||||
|
public static final String JABBER_CLIENT = "jabber:client";
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,7 +30,6 @@
|
||||||
package eu.siacs.conversations.xmpp;
|
package eu.siacs.conversations.xmpp;
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
|
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
|
||||||
|
|
||||||
public class InvalidJid implements Jid {
|
public class InvalidJid implements Jid {
|
||||||
|
@ -77,7 +76,6 @@ public class InvalidJid implements Jid {
|
||||||
throw new AssertionError("Not implemented");
|
throw new AssertionError("Not implemented");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Jid withResource(CharSequence charSequence) {
|
public Jid withResource(CharSequence charSequence) {
|
||||||
throw new AssertionError("Not implemented");
|
throw new AssertionError("Not implemented");
|
||||||
|
@ -140,6 +138,10 @@ public class InvalidJid implements Jid {
|
||||||
return !(jid != null && jid instanceof InvalidJid);
|
return !(jid != null && jid instanceof InvalidJid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static boolean invalid(final Jid jid) {
|
||||||
|
return jid instanceof InvalidJid;
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean hasValidFrom(AbstractStanza stanza) {
|
public static boolean hasValidFrom(AbstractStanza stanza) {
|
||||||
final String from = stanza.getAttribute("from");
|
final String from = stanza.getAttribute("from");
|
||||||
if (from == null) {
|
if (from == null) {
|
||||||
|
|
126
src/main/java/im/conversations/android/xml/TagWriter.java
Normal file
126
src/main/java/im/conversations/android/xml/TagWriter.java
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
package im.conversations.android.xml;
|
||||||
|
|
||||||
|
import android.util.Log;
|
||||||
|
import eu.siacs.conversations.Config;
|
||||||
|
import eu.siacs.conversations.xml.Element;
|
||||||
|
import eu.siacs.conversations.xml.Tag;
|
||||||
|
import im.conversations.android.xmpp.model.StreamElement;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.LinkedBlockingQueue;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
public class TagWriter {
|
||||||
|
|
||||||
|
private OutputStreamWriter outputStream;
|
||||||
|
private boolean finished = false;
|
||||||
|
private final LinkedBlockingQueue<StreamElement> writeQueue = new LinkedBlockingQueue<>();
|
||||||
|
private CountDownLatch stanzaWriterCountDownLatch = null;
|
||||||
|
|
||||||
|
private final Thread asyncStanzaWriter =
|
||||||
|
new Thread() {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
stanzaWriterCountDownLatch = new CountDownLatch(1);
|
||||||
|
while (!isInterrupted()) {
|
||||||
|
if (finished && writeQueue.size() == 0) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final StreamElement output = writeQueue.take();
|
||||||
|
outputStream.write(output.toString());
|
||||||
|
if (writeQueue.size() == 0) {
|
||||||
|
outputStream.flush();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
stanzaWriterCountDownLatch.countDown();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
public TagWriter() {}
|
||||||
|
|
||||||
|
public synchronized void setOutputStream(OutputStream out) throws IOException {
|
||||||
|
if (out == null) {
|
||||||
|
throw new IOException();
|
||||||
|
}
|
||||||
|
this.outputStream = new OutputStreamWriter(out);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void beginDocument() throws IOException {
|
||||||
|
if (outputStream == null) {
|
||||||
|
throw new IOException("output stream was null");
|
||||||
|
}
|
||||||
|
outputStream.write("<?xml version='1.0'?>");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeTag(final Tag tag) throws IOException {
|
||||||
|
writeTag(tag, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void writeTag(final Tag tag, final boolean flush) throws IOException {
|
||||||
|
if (outputStream == null) {
|
||||||
|
throw new IOException("output stream was null");
|
||||||
|
}
|
||||||
|
outputStream.write(tag.toString());
|
||||||
|
if (flush) {
|
||||||
|
outputStream.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void writeElement(Element element) throws IOException {
|
||||||
|
if (outputStream == null) {
|
||||||
|
throw new IOException("output stream was null");
|
||||||
|
}
|
||||||
|
outputStream.write(element.toString());
|
||||||
|
outputStream.flush();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void writeStanzaAsync(StreamElement stanza) {
|
||||||
|
if (finished) {
|
||||||
|
Log.d(Config.LOGTAG, "attempting to write stanza to finished TagWriter");
|
||||||
|
} else {
|
||||||
|
if (!asyncStanzaWriter.isAlive()) {
|
||||||
|
try {
|
||||||
|
asyncStanzaWriter.start();
|
||||||
|
} catch (IllegalThreadStateException e) {
|
||||||
|
// already started
|
||||||
|
}
|
||||||
|
}
|
||||||
|
writeQueue.add(stanza);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void finish() {
|
||||||
|
this.finished = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean await(long timeout, TimeUnit timeunit) throws InterruptedException {
|
||||||
|
if (stanzaWriterCountDownLatch == null) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return stanzaWriterCountDownLatch.await(timeout, timeunit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isActive() {
|
||||||
|
return outputStream != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public synchronized void forceClose() {
|
||||||
|
asyncStanzaWriter.interrupt();
|
||||||
|
if (outputStream != null) {
|
||||||
|
try {
|
||||||
|
outputStream.close();
|
||||||
|
} catch (IOException e) {
|
||||||
|
// ignoring
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outputStream = null;
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,7 +28,6 @@ import eu.siacs.conversations.crypto.XmppDomainVerifier;
|
||||||
import eu.siacs.conversations.http.HttpConnectionManager;
|
import eu.siacs.conversations.http.HttpConnectionManager;
|
||||||
import eu.siacs.conversations.persistance.FileBackend;
|
import eu.siacs.conversations.persistance.FileBackend;
|
||||||
import eu.siacs.conversations.services.MemorizingTrustManager;
|
import eu.siacs.conversations.services.MemorizingTrustManager;
|
||||||
import eu.siacs.conversations.services.MessageArchiveService;
|
|
||||||
import eu.siacs.conversations.services.NotificationService;
|
import eu.siacs.conversations.services.NotificationService;
|
||||||
import eu.siacs.conversations.ui.util.PendingItem;
|
import eu.siacs.conversations.ui.util.PendingItem;
|
||||||
import eu.siacs.conversations.utils.Patterns;
|
import eu.siacs.conversations.utils.Patterns;
|
||||||
|
@ -41,22 +40,12 @@ import eu.siacs.conversations.xml.Element;
|
||||||
import eu.siacs.conversations.xml.LocalizedContent;
|
import eu.siacs.conversations.xml.LocalizedContent;
|
||||||
import eu.siacs.conversations.xml.Namespace;
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
import eu.siacs.conversations.xml.Tag;
|
import eu.siacs.conversations.xml.Tag;
|
||||||
import eu.siacs.conversations.xml.TagWriter;
|
|
||||||
import eu.siacs.conversations.xml.XmlReader;
|
import eu.siacs.conversations.xml.XmlReader;
|
||||||
|
import eu.siacs.conversations.xmpp.InvalidJid;
|
||||||
import eu.siacs.conversations.xmpp.Jid;
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
import eu.siacs.conversations.xmpp.bind.Bind2;
|
import eu.siacs.conversations.xmpp.bind.Bind2;
|
||||||
import eu.siacs.conversations.xmpp.forms.Data;
|
import eu.siacs.conversations.xmpp.forms.Data;
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
|
|
||||||
import eu.siacs.conversations.xmpp.stanzas.AbstractAcknowledgeableStanza;
|
|
||||||
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
|
|
||||||
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
|
||||||
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
|
||||||
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
|
|
||||||
import eu.siacs.conversations.xmpp.stanzas.csi.ActivePacket;
|
|
||||||
import eu.siacs.conversations.xmpp.stanzas.csi.InactivePacket;
|
|
||||||
import eu.siacs.conversations.xmpp.stanzas.streammgmt.AckPacket;
|
|
||||||
import eu.siacs.conversations.xmpp.stanzas.streammgmt.EnablePacket;
|
import eu.siacs.conversations.xmpp.stanzas.streammgmt.EnablePacket;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.streammgmt.RequestPacket;
|
|
||||||
import eu.siacs.conversations.xmpp.stanzas.streammgmt.ResumePacket;
|
import eu.siacs.conversations.xmpp.stanzas.streammgmt.ResumePacket;
|
||||||
import im.conversations.android.IDs;
|
import im.conversations.android.IDs;
|
||||||
import im.conversations.android.database.ConversationsDatabase;
|
import im.conversations.android.database.ConversationsDatabase;
|
||||||
|
@ -64,12 +53,24 @@ import im.conversations.android.database.CredentialStore;
|
||||||
import im.conversations.android.database.model.Account;
|
import im.conversations.android.database.model.Account;
|
||||||
import im.conversations.android.database.model.Connection;
|
import im.conversations.android.database.model.Connection;
|
||||||
import im.conversations.android.database.model.Credential;
|
import im.conversations.android.database.model.Credential;
|
||||||
|
import im.conversations.android.xml.TagWriter;
|
||||||
import im.conversations.android.xmpp.manager.AbstractManager;
|
import im.conversations.android.xmpp.manager.AbstractManager;
|
||||||
import im.conversations.android.xmpp.manager.DiscoManager;
|
import im.conversations.android.xmpp.manager.DiscoManager;
|
||||||
|
import im.conversations.android.xmpp.model.StreamElement;
|
||||||
|
import im.conversations.android.xmpp.model.csi.Active;
|
||||||
|
import im.conversations.android.xmpp.model.csi.Inactive;
|
||||||
|
import im.conversations.android.xmpp.model.register.Register;
|
||||||
|
import im.conversations.android.xmpp.model.sm.Ack;
|
||||||
|
import im.conversations.android.xmpp.model.sm.Enable;
|
||||||
|
import im.conversations.android.xmpp.model.sm.Request;
|
||||||
|
import im.conversations.android.xmpp.model.sm.Resume;
|
||||||
|
import im.conversations.android.xmpp.model.stanza.IQ;
|
||||||
|
import im.conversations.android.xmpp.model.stanza.Message;
|
||||||
|
import im.conversations.android.xmpp.model.stanza.Presence;
|
||||||
|
import im.conversations.android.xmpp.model.stanza.Stanza;
|
||||||
import im.conversations.android.xmpp.model.streams.Features;
|
import im.conversations.android.xmpp.model.streams.Features;
|
||||||
import im.conversations.android.xmpp.processor.BindProcessor;
|
import im.conversations.android.xmpp.processor.BindProcessor;
|
||||||
import im.conversations.android.xmpp.processor.IqProcessor;
|
import im.conversations.android.xmpp.processor.IqProcessor;
|
||||||
import im.conversations.android.xmpp.processor.JingleProcessor;
|
|
||||||
import im.conversations.android.xmpp.processor.MessageAcknowledgeProcessor;
|
import im.conversations.android.xmpp.processor.MessageAcknowledgeProcessor;
|
||||||
import im.conversations.android.xmpp.processor.MessageProcessor;
|
import im.conversations.android.xmpp.processor.MessageProcessor;
|
||||||
import im.conversations.android.xmpp.processor.PresenceProcessor;
|
import im.conversations.android.xmpp.processor.PresenceProcessor;
|
||||||
|
@ -93,7 +94,6 @@ import java.security.cert.X509Certificate;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Hashtable;
|
import java.util.Hashtable;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -117,14 +117,9 @@ import org.xmlpull.v1.XmlPullParserException;
|
||||||
|
|
||||||
public class XmppConnection implements Runnable {
|
public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
private static final int PACKET_IQ = 0;
|
|
||||||
private static final int PACKET_MESSAGE = 1;
|
|
||||||
private static final int PACKET_PRESENCE = 2;
|
|
||||||
protected final Account account;
|
protected final Account account;
|
||||||
private final HashMap<String, Jid> commands = new HashMap<>();
|
private final SparseArray<Stanza> mStanzaQueue = new SparseArray<>();
|
||||||
private final SparseArray<AbstractAcknowledgeableStanza> mStanzaQueue = new SparseArray<>();
|
private final Hashtable<String, Pair<IQ, Consumer<IQ>>> packetCallbacks = new Hashtable<>();
|
||||||
private final Hashtable<String, Pair<IqPacket, Consumer<IqPacket>>> packetCallbacks =
|
|
||||||
new Hashtable<>();
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private Socket socket;
|
private Socket socket;
|
||||||
private XmlReader tagReader;
|
private XmlReader tagReader;
|
||||||
|
@ -149,19 +144,17 @@ public class XmppConnection implements Runnable {
|
||||||
private long lastPingSent = 0;
|
private long lastPingSent = 0;
|
||||||
private long lastConnect = 0;
|
private long lastConnect = 0;
|
||||||
private long lastSessionStarted = 0;
|
private long lastSessionStarted = 0;
|
||||||
private boolean isMamPreferenceAlways = false;
|
|
||||||
private final AtomicBoolean mWaitingForSmCatchup = new AtomicBoolean(false);
|
private final AtomicBoolean mWaitingForSmCatchup = new AtomicBoolean(false);
|
||||||
private final AtomicInteger mSmCatchupMessageCounter = new AtomicInteger(0);
|
private final AtomicInteger mSmCatchupMessageCounter = new AtomicInteger(0);
|
||||||
private int attempt = 0;
|
private int attempt = 0;
|
||||||
private final Consumer<PresencePacket> presencePacketConsumer;
|
private final Consumer<Presence> presencePacketConsumer;
|
||||||
private final Consumer<JinglePacket> jinglePacketConsumer;
|
private final Consumer<IQ> iqPacketConsumer;
|
||||||
private final Consumer<IqPacket> iqPacketConsumer;
|
private final Consumer<Message> messagePacketConsumer;
|
||||||
private final Consumer<MessagePacket> messagePacketConsumer;
|
|
||||||
private final BiFunction<Jid, String, Boolean> messageAcknowledgeProcessor;
|
private final BiFunction<Jid, String, Boolean> messageAcknowledgeProcessor;
|
||||||
private final Consumer<Jid> bindConsumer;
|
private final Consumer<Jid> bindConsumer;
|
||||||
private final ClassToInstanceMap<AbstractManager> managers;
|
private final ClassToInstanceMap<AbstractManager> managers;
|
||||||
private Consumer<XmppConnection> statusListener = null;
|
private Consumer<XmppConnection> statusListener = null;
|
||||||
private PendingItem<SettableFuture<XmppConnection>> connectedFuture = new PendingItem<>();
|
private final PendingItem<SettableFuture<XmppConnection>> connectedFuture = new PendingItem<>();
|
||||||
private SaslMechanism saslMechanism;
|
private SaslMechanism saslMechanism;
|
||||||
private HashedToken.Mechanism hashTokenRequest;
|
private HashedToken.Mechanism hashTokenRequest;
|
||||||
private HttpUrl redirectionUrl = null;
|
private HttpUrl redirectionUrl = null;
|
||||||
|
@ -181,7 +174,6 @@ public class XmppConnection implements Runnable {
|
||||||
this.messagePacketConsumer = new MessageProcessor(context, this);
|
this.messagePacketConsumer = new MessageProcessor(context, this);
|
||||||
this.presencePacketConsumer = new PresenceProcessor(context, this);
|
this.presencePacketConsumer = new PresenceProcessor(context, this);
|
||||||
this.iqPacketConsumer = new IqProcessor(context, this);
|
this.iqPacketConsumer = new IqProcessor(context, this);
|
||||||
this.jinglePacketConsumer = new JingleProcessor(context, this);
|
|
||||||
this.messageAcknowledgeProcessor = new MessageAcknowledgeProcessor(context, this);
|
this.messageAcknowledgeProcessor = new MessageAcknowledgeProcessor(context, this);
|
||||||
this.bindConsumer = new BindProcessor(context, this);
|
this.bindConsumer = new BindProcessor(context, this);
|
||||||
this.managers = Managers.initialize(context, this);
|
this.managers = Managers.initialize(context, this);
|
||||||
|
@ -262,12 +254,6 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Jid getJidForCommand(final String node) {
|
|
||||||
synchronized (this.commands) {
|
|
||||||
return this.commands.get(node);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void prepareNewConnection() {
|
public void prepareNewConnection() {
|
||||||
this.lastConnect = SystemClock.elapsedRealtime();
|
this.lastConnect = SystemClock.elapsedRealtime();
|
||||||
this.lastPingSent = SystemClock.elapsedRealtime();
|
this.lastPingSent = SystemClock.elapsedRealtime();
|
||||||
|
@ -616,7 +602,7 @@ public class XmppConnection implements Runnable {
|
||||||
Config.LOGTAG,
|
Config.LOGTAG,
|
||||||
account.address + ": acknowledging stanza #" + this.stanzasReceived);
|
account.address + ": acknowledging stanza #" + this.stanzasReceived);
|
||||||
}
|
}
|
||||||
final AckPacket ack = new AckPacket(this.stanzasReceived);
|
final Ack ack = new Ack(this.stanzasReceived);
|
||||||
tagWriter.writeStanzaAsync(ack);
|
tagWriter.writeStanzaAsync(ack);
|
||||||
} else if (nextTag.isStart("a")) {
|
} else if (nextTag.isStart("a")) {
|
||||||
synchronized (NotificationService.CATCHUP_LOCK) {
|
synchronized (NotificationService.CATCHUP_LOCK) {
|
||||||
|
@ -849,7 +835,7 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
private void resetOutboundStanzaQueue() {
|
private void resetOutboundStanzaQueue() {
|
||||||
synchronized (this.mStanzaQueue) {
|
synchronized (this.mStanzaQueue) {
|
||||||
final List<AbstractAcknowledgeableStanza> intermediateStanzas = new ArrayList<>();
|
final List<Stanza> intermediateStanzas = new ArrayList<>();
|
||||||
if (Config.EXTENDED_SM_LOGGING) {
|
if (Config.EXTENDED_SM_LOGGING) {
|
||||||
Log.d(
|
Log.d(
|
||||||
Config.LOGTAG,
|
Config.LOGTAG,
|
||||||
|
@ -858,7 +844,7 @@ public class XmppConnection implements Runnable {
|
||||||
+ this.stanzasSentBeforeAuthentication);
|
+ this.stanzasSentBeforeAuthentication);
|
||||||
}
|
}
|
||||||
for (int i = this.stanzasSentBeforeAuthentication + 1; i <= this.stanzasSent; ++i) {
|
for (int i = this.stanzasSentBeforeAuthentication + 1; i <= this.stanzasSent; ++i) {
|
||||||
final AbstractAcknowledgeableStanza stanza = this.mStanzaQueue.get(i);
|
final Stanza stanza = this.mStanzaQueue.get(i);
|
||||||
if (stanza != null) {
|
if (stanza != null) {
|
||||||
intermediateStanzas.add(stanza);
|
intermediateStanzas.add(stanza);
|
||||||
}
|
}
|
||||||
|
@ -966,14 +952,14 @@ public class XmppConnection implements Runnable {
|
||||||
this.streamId = streamId;
|
this.streamId = streamId;
|
||||||
this.stanzasReceived = 0;
|
this.stanzasReceived = 0;
|
||||||
this.inSmacksSession = true;
|
this.inSmacksSession = true;
|
||||||
final RequestPacket r = new RequestPacket();
|
final Request r = new Request();
|
||||||
tagWriter.writeStanzaAsync(r);
|
tagWriter.writeStanzaAsync(r);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processResumed(final Element resumed) throws StateChangingException {
|
private void processResumed(final Element resumed) throws StateChangingException {
|
||||||
this.inSmacksSession = true;
|
this.inSmacksSession = true;
|
||||||
this.isBound = true;
|
this.isBound = true;
|
||||||
this.tagWriter.writeStanzaAsync(new RequestPacket());
|
this.tagWriter.writeStanzaAsync(new Request());
|
||||||
lastPacketReceived = SystemClock.elapsedRealtime();
|
lastPacketReceived = SystemClock.elapsedRealtime();
|
||||||
final Optional<Integer> h = resumed.getOptionalIntAttribute("h");
|
final Optional<Integer> h = resumed.getOptionalIntAttribute("h");
|
||||||
final int serverCount;
|
final int serverCount;
|
||||||
|
@ -983,7 +969,7 @@ public class XmppConnection implements Runnable {
|
||||||
resetStreamId();
|
resetStreamId();
|
||||||
throw new StateChangingException(ConnectionState.INCOMPATIBLE_SERVER);
|
throw new StateChangingException(ConnectionState.INCOMPATIBLE_SERVER);
|
||||||
}
|
}
|
||||||
final ArrayList<AbstractAcknowledgeableStanza> failedStanzas = new ArrayList<>();
|
final ArrayList<Stanza> failedStanzas = new ArrayList<>();
|
||||||
final boolean acknowledgedMessages;
|
final boolean acknowledgedMessages;
|
||||||
synchronized (this.mStanzaQueue) {
|
synchronized (this.mStanzaQueue) {
|
||||||
if (serverCount < stanzasSent) {
|
if (serverCount < stanzasSent) {
|
||||||
|
@ -999,9 +985,9 @@ public class XmppConnection implements Runnable {
|
||||||
mStanzaQueue.clear();
|
mStanzaQueue.clear();
|
||||||
}
|
}
|
||||||
Log.d(Config.LOGTAG, account.address + ": resending " + failedStanzas.size() + " stanzas");
|
Log.d(Config.LOGTAG, account.address + ": resending " + failedStanzas.size() + " stanzas");
|
||||||
for (final AbstractAcknowledgeableStanza packet : failedStanzas) {
|
for (final Stanza packet : failedStanzas) {
|
||||||
if (packet instanceof MessagePacket) {
|
if (packet instanceof Message) {
|
||||||
MessagePacket message = (MessagePacket) packet;
|
Message message = (Message) packet;
|
||||||
// TODO set ack = false in message table
|
// TODO set ack = false in message table
|
||||||
// context.markMessage(account, message.getTo().asBareJid(), message.getId(),
|
// context.markMessage(account, message.getTo().asBareJid(), message.getId(),
|
||||||
// Message.STATUS_UNSEND);
|
// Message.STATUS_UNSEND);
|
||||||
|
@ -1058,9 +1044,9 @@ public class XmppConnection implements Runnable {
|
||||||
+ ": server acknowledged stanza #"
|
+ ": server acknowledged stanza #"
|
||||||
+ mStanzaQueue.keyAt(i));
|
+ mStanzaQueue.keyAt(i));
|
||||||
}
|
}
|
||||||
final AbstractAcknowledgeableStanza stanza = mStanzaQueue.valueAt(i);
|
final Stanza stanza = mStanzaQueue.valueAt(i);
|
||||||
if (stanza instanceof MessagePacket && messageAcknowledgeProcessor != null) {
|
if (stanza instanceof Message) {
|
||||||
final MessagePacket packet = (MessagePacket) stanza;
|
final Message packet = (Message) stanza;
|
||||||
final String id = packet.getId();
|
final String id = packet.getId();
|
||||||
final Jid to = packet.getTo();
|
final Jid to = packet.getTo();
|
||||||
if (id != null && to != null) {
|
if (id != null && to != null) {
|
||||||
|
@ -1074,36 +1060,9 @@ public class XmppConnection implements Runnable {
|
||||||
return acknowledgedMessages;
|
return acknowledgedMessages;
|
||||||
}
|
}
|
||||||
|
|
||||||
private @NonNull Element processPacket(final Tag currentTag, final int packetType)
|
private <S extends Stanza> S processStanza(final Tag currentTag, final Class<S> clazz)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final Element element;
|
final S stanza = tagReader.readElement(currentTag, clazz);
|
||||||
switch (packetType) {
|
|
||||||
case PACKET_IQ:
|
|
||||||
element = new IqPacket();
|
|
||||||
break;
|
|
||||||
case PACKET_MESSAGE:
|
|
||||||
element = new MessagePacket();
|
|
||||||
break;
|
|
||||||
case PACKET_PRESENCE:
|
|
||||||
element = new PresencePacket();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new AssertionError("Should never encounter invalid type");
|
|
||||||
}
|
|
||||||
element.setAttributes(currentTag.getAttributes());
|
|
||||||
Tag nextTag = tagReader.readTag();
|
|
||||||
if (nextTag == null) {
|
|
||||||
throw new IOException("interrupted mid tag");
|
|
||||||
}
|
|
||||||
while (!nextTag.isEnd(element.getName())) {
|
|
||||||
if (!nextTag.isNo()) {
|
|
||||||
element.addChild(tagReader.readElement(nextTag));
|
|
||||||
}
|
|
||||||
nextTag = tagReader.readTag();
|
|
||||||
if (nextTag == null) {
|
|
||||||
throw new IOException("interrupted mid tag");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (stanzasReceived == Integer.MAX_VALUE) {
|
if (stanzasReceived == Integer.MAX_VALUE) {
|
||||||
resetStreamId();
|
resetStreamId();
|
||||||
throw new IOException("time to restart the session. cant handle >2 billion pcks");
|
throw new IOException("time to restart the session. cant handle >2 billion pcks");
|
||||||
|
@ -1115,38 +1074,32 @@ public class XmppConnection implements Runnable {
|
||||||
Config.LOGTAG,
|
Config.LOGTAG,
|
||||||
account.address
|
account.address
|
||||||
+ ": not counting stanza("
|
+ ": not counting stanza("
|
||||||
+ element.getClass().getSimpleName()
|
+ stanza.getClass().getSimpleName()
|
||||||
+ "). Not in smacks session.");
|
+ "). Not in smacks session.");
|
||||||
}
|
}
|
||||||
lastPacketReceived = SystemClock.elapsedRealtime();
|
lastPacketReceived = SystemClock.elapsedRealtime();
|
||||||
if (element instanceof IqPacket
|
if (InvalidJid.invalid(stanza.getTo()) || InvalidJid.invalid(stanza.getFrom())) {
|
||||||
&& (((IqPacket) element).getType() == IqPacket.TYPE.SET)
|
Log.e(
|
||||||
&& element.hasChild("jingle", Namespace.JINGLE)) {
|
Config.LOGTAG,
|
||||||
return JinglePacket.upgrade((IqPacket) element);
|
"encountered invalid stanza from "
|
||||||
} else {
|
+ stanza.getFrom()
|
||||||
return element;
|
+ " to "
|
||||||
|
+ stanza.getTo());
|
||||||
}
|
}
|
||||||
|
return stanza;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processIq(final Tag currentTag) throws IOException {
|
private void processIq(final Tag currentTag) throws IOException {
|
||||||
final IqPacket packet = (IqPacket) processPacket(currentTag, PACKET_IQ);
|
final IQ packet = processStanza(currentTag, IQ.class);
|
||||||
if (!packet.valid()) {
|
if (InvalidJid.invalid(packet.getTo()) || InvalidJid.invalid(packet.getFrom())) {
|
||||||
Log.e(
|
Log.e(
|
||||||
Config.LOGTAG,
|
Config.LOGTAG,
|
||||||
"encountered invalid iq from='"
|
"encountered invalid IQ from " + packet.getFrom() + " to " + packet.getTo());
|
||||||
+ packet.getFrom()
|
|
||||||
+ "' to='"
|
|
||||||
+ packet.getTo()
|
|
||||||
+ "'");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (packet instanceof JinglePacket) {
|
final Consumer<IQ> callback;
|
||||||
this.jinglePacketConsumer.accept((JinglePacket) packet);
|
|
||||||
} else {
|
|
||||||
final Consumer<IqPacket> callback;
|
|
||||||
synchronized (this.packetCallbacks) {
|
synchronized (this.packetCallbacks) {
|
||||||
final Pair<IqPacket, Consumer<IqPacket>> packetCallbackDuple =
|
final Pair<IQ, Consumer<IQ>> packetCallbackDuple = packetCallbacks.get(packet.getId());
|
||||||
packetCallbacks.get(packet.getId());
|
|
||||||
if (packetCallbackDuple != null) {
|
if (packetCallbackDuple != null) {
|
||||||
// Packets to the server should have responses from the server
|
// Packets to the server should have responses from the server
|
||||||
if (toServer(packetCallbackDuple.first)) {
|
if (toServer(packetCallbackDuple.first)) {
|
||||||
|
@ -1167,8 +1120,7 @@ public class XmppConnection implements Runnable {
|
||||||
Log.e(Config.LOGTAG, account.address + ": ignoring spoofed iq packet");
|
Log.e(Config.LOGTAG, account.address + ": ignoring spoofed iq packet");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (packet.getType() == IqPacket.TYPE.GET
|
} else if (packet.getType() == IQ.Type.GET || packet.getType() == IQ.Type.SET) {
|
||||||
|| packet.getType() == IqPacket.TYPE.SET) {
|
|
||||||
callback = this.iqPacketConsumer;
|
callback = this.iqPacketConsumer;
|
||||||
} else {
|
} else {
|
||||||
callback = null;
|
callback = null;
|
||||||
|
@ -1182,36 +1134,33 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private void processMessage(final Tag currentTag) throws IOException {
|
private void processMessage(final Tag currentTag) throws IOException {
|
||||||
final MessagePacket packet = (MessagePacket) processPacket(currentTag, PACKET_MESSAGE);
|
final var message = processStanza(currentTag, Message.class);
|
||||||
if (!packet.valid()) {
|
if (InvalidJid.invalid(message.getTo()) || InvalidJid.invalid(message.getFrom())) {
|
||||||
Log.e(
|
Log.e(
|
||||||
Config.LOGTAG,
|
Config.LOGTAG,
|
||||||
"encountered invalid message from='"
|
"encountered invalid Message from "
|
||||||
+ packet.getFrom()
|
+ message.getFrom()
|
||||||
+ "' to='"
|
+ " to "
|
||||||
+ packet.getTo()
|
+ message.getTo());
|
||||||
+ "'");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.messagePacketConsumer.accept(packet);
|
this.messagePacketConsumer.accept(message);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processPresence(final Tag currentTag) throws IOException {
|
private void processPresence(final Tag currentTag) throws IOException {
|
||||||
PresencePacket packet = (PresencePacket) processPacket(currentTag, PACKET_PRESENCE);
|
final var presence = processStanza(currentTag, Presence.class);
|
||||||
if (!packet.valid()) {
|
if (InvalidJid.invalid(presence.getTo()) || InvalidJid.invalid(presence.getFrom())) {
|
||||||
Log.e(
|
Log.e(
|
||||||
Config.LOGTAG,
|
Config.LOGTAG,
|
||||||
"encountered invalid presence from='"
|
"encountered invalid Presence from "
|
||||||
+ packet.getFrom()
|
+ presence.getFrom()
|
||||||
+ "' to='"
|
+ " to "
|
||||||
+ packet.getTo()
|
+ presence.getTo());
|
||||||
+ "'");
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.presencePacketConsumer.accept(packet);
|
this.presencePacketConsumer.accept(presence);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendStartTLS() throws IOException {
|
private void sendStartTLS() throws IOException {
|
||||||
|
@ -1350,7 +1299,7 @@ public class XmppConnection implements Runnable {
|
||||||
Config.LOGTAG,
|
Config.LOGTAG,
|
||||||
account.address + ": resuming after stanza #" + stanzasReceived);
|
account.address + ": resuming after stanza #" + stanzasReceived);
|
||||||
}
|
}
|
||||||
final ResumePacket resume = new ResumePacket(this.streamId, stanzasReceived);
|
final Resume resume = new Resume(this.streamId, stanzasReceived);
|
||||||
this.mSmCatchupMessageCounter.set(0);
|
this.mSmCatchupMessageCounter.set(0);
|
||||||
this.mWaitingForSmCatchup.set(true);
|
this.mWaitingForSmCatchup.set(true);
|
||||||
this.tagWriter.writeStanzaAsync(resume);
|
this.tagWriter.writeStanzaAsync(resume);
|
||||||
|
@ -1563,15 +1512,15 @@ public class XmppConnection implements Runnable {
|
||||||
sendRegistryRequest();
|
sendRegistryRequest();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final IqPacket preAuthRequest = new IqPacket(IqPacket.TYPE.SET);
|
final IQ preAuthRequest = new IQ(IQ.Type.SET);
|
||||||
preAuthRequest.addChild("preauth", Namespace.PARS).setAttribute("token", preAuth);
|
preAuthRequest.addChild("preauth", Namespace.PARS).setAttribute("token", preAuth);
|
||||||
sendUnmodifiedIqPacket(
|
sendUnmodifiedIqPacket(
|
||||||
preAuthRequest,
|
preAuthRequest,
|
||||||
(response) -> {
|
(response) -> {
|
||||||
if (response.getType() == IqPacket.TYPE.RESULT) {
|
if (response.getType() == IQ.Type.RESULT) {
|
||||||
sendRegistryRequest();
|
sendRegistryRequest();
|
||||||
} else {
|
} else {
|
||||||
final String error = response.getErrorCondition();
|
final String error = ""; // response.getErrorCondition();
|
||||||
Log.d(Config.LOGTAG, account.address + ": failed to pre auth. " + error);
|
Log.d(Config.LOGTAG, account.address + ": failed to pre auth. " + error);
|
||||||
throw new StateChangingError(ConnectionState.REGISTRATION_INVALID_TOKEN);
|
throw new StateChangingError(ConnectionState.REGISTRATION_INVALID_TOKEN);
|
||||||
}
|
}
|
||||||
|
@ -1580,32 +1529,39 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendRegistryRequest() {
|
private void sendRegistryRequest() {
|
||||||
final IqPacket register = new IqPacket(IqPacket.TYPE.GET);
|
final IQ retrieveRegistration = new IQ(IQ.Type.GET);
|
||||||
register.query(Namespace.REGISTER);
|
retrieveRegistration.addExtension(new Register());
|
||||||
register.setTo(account.address.getDomain());
|
retrieveRegistration.setTo(account.address.getDomain());
|
||||||
sendUnmodifiedIqPacket(
|
sendUnmodifiedIqPacket(
|
||||||
register,
|
retrieveRegistration,
|
||||||
(packet) -> {
|
(packet) -> {
|
||||||
if (packet.getType() == IqPacket.TYPE.TIMEOUT) {
|
if (packet.getType() == IQ.Type.TIMEOUT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (packet.getType() == IqPacket.TYPE.ERROR) {
|
if (packet.getType() == IQ.Type.ERROR) {
|
||||||
|
throw new StateChangingError(ConnectionState.REGISTRATION_FAILED);
|
||||||
|
}
|
||||||
|
final Register query = packet.getExtension(Register.class);
|
||||||
|
if (query == null) {
|
||||||
throw new StateChangingError(ConnectionState.REGISTRATION_FAILED);
|
throw new StateChangingError(ConnectionState.REGISTRATION_FAILED);
|
||||||
}
|
}
|
||||||
final Element query = packet.query(Namespace.REGISTER);
|
|
||||||
if (query.hasChild("username") && (query.hasChild("password"))) {
|
if (query.hasChild("username") && (query.hasChild("password"))) {
|
||||||
final Credential credential =
|
final Credential credential =
|
||||||
CredentialStore.getInstance(context).get(account);
|
CredentialStore.getInstance(context).get(account);
|
||||||
final IqPacket register1 = new IqPacket(IqPacket.TYPE.SET);
|
final IQ registrationRequest = new IQ(IQ.Type.SET);
|
||||||
final Element username =
|
final Element username =
|
||||||
new Element("username")
|
new Element("username")
|
||||||
.setContent(account.address.getEscapedLocal());
|
.setContent(account.address.getEscapedLocal());
|
||||||
final Element password =
|
final Element password =
|
||||||
new Element("password").setContent(credential.password);
|
new Element("password").setContent(credential.password);
|
||||||
register1.query(Namespace.REGISTER).addChild(username);
|
|
||||||
register1.query().addChild(password);
|
final var register = registrationRequest.addExtension(new Register());
|
||||||
register1.setFrom(account.address);
|
|
||||||
sendUnmodifiedIqPacket(register1, this::handleRegistrationResponse, true);
|
register.addChild(username);
|
||||||
|
register.addChild(password);
|
||||||
|
registrationRequest.setFrom(account.address);
|
||||||
|
sendUnmodifiedIqPacket(
|
||||||
|
registrationRequest, this::handleRegistrationResponse, true);
|
||||||
} else if (query.hasChild("x", Namespace.DATA)) {
|
} else if (query.hasChild("x", Namespace.DATA)) {
|
||||||
final Data data = Data.parse(query.findChild("x", Namespace.DATA));
|
final Data data = Data.parse(query.findChild("x", Namespace.DATA));
|
||||||
final Element blob = query.findChild("data", "urn:xmpp:bob");
|
final Element blob = query.findChild("data", "urn:xmpp:bob");
|
||||||
|
@ -1667,8 +1623,8 @@ public class XmppConnection implements Runnable {
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleRegistrationResponse(final IqPacket packet) {
|
private void handleRegistrationResponse(final IQ packet) {
|
||||||
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
if (packet.getType() == IQ.Type.RESULT) {
|
||||||
ConversationsDatabase.getInstance(context)
|
ConversationsDatabase.getInstance(context)
|
||||||
.accountDao()
|
.accountDao()
|
||||||
.setPendingRegistration(account.id, false);
|
.setPendingRegistration(account.id, false);
|
||||||
|
@ -1716,9 +1672,6 @@ public class XmppConnection implements Runnable {
|
||||||
this.stanzasSent = 0;
|
this.stanzasSent = 0;
|
||||||
mStanzaQueue.clear();
|
mStanzaQueue.clear();
|
||||||
this.redirectionUrl = null;
|
this.redirectionUrl = null;
|
||||||
synchronized (this.commands) {
|
|
||||||
this.commands.clear();
|
|
||||||
}
|
|
||||||
this.saslMechanism = null;
|
this.saslMechanism = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1736,16 +1689,16 @@ public class XmppConnection implements Runnable {
|
||||||
} else {
|
} else {
|
||||||
resource = this.createNewResource(IDs.tiny(account.randomSeed));
|
resource = this.createNewResource(IDs.tiny(account.randomSeed));
|
||||||
}
|
}
|
||||||
final IqPacket iq = new IqPacket(IqPacket.TYPE.SET);
|
final IQ iq = new IQ(IQ.Type.SET);
|
||||||
iq.addChild("bind", Namespace.BIND).addChild("resource").setContent(resource);
|
iq.addChild("bind", Namespace.BIND).addChild("resource").setContent(resource);
|
||||||
this.sendUnmodifiedIqPacket(
|
this.sendUnmodifiedIqPacket(
|
||||||
iq,
|
iq,
|
||||||
(packet) -> {
|
(packet) -> {
|
||||||
if (packet.getType() == IqPacket.TYPE.TIMEOUT) {
|
if (packet.getType() == IQ.Type.TIMEOUT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Element bind = packet.findChild("bind");
|
final Element bind = packet.findChild("bind");
|
||||||
if (bind != null && packet.getType() == IqPacket.TYPE.RESULT) {
|
if (bind != null && packet.getType() == IQ.Type.RESULT) {
|
||||||
isBound = true;
|
isBound = true;
|
||||||
final String jid = bind.findChildContent("jid");
|
final String jid = bind.findChildContent("jid");
|
||||||
if (Strings.isNullOrEmpty(jid)) {
|
if (Strings.isNullOrEmpty(jid)) {
|
||||||
|
@ -1789,7 +1742,7 @@ public class XmppConnection implements Runnable {
|
||||||
+ packet);
|
+ packet);
|
||||||
}
|
}
|
||||||
final Element error = packet.findChild("error");
|
final Element error = packet.findChild("error");
|
||||||
if (packet.getType() == IqPacket.TYPE.ERROR
|
if (packet.getType() == IQ.Type.ERROR
|
||||||
&& error != null
|
&& error != null
|
||||||
&& error.hasChild("conflict")) {
|
&& error.hasChild("conflict")) {
|
||||||
final String alternativeResource = createNewResource(IDs.tiny());
|
final String alternativeResource = createNewResource(IDs.tiny());
|
||||||
|
@ -1813,8 +1766,8 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearIqCallbacks() {
|
private void clearIqCallbacks() {
|
||||||
final IqPacket failurePacket = new IqPacket(IqPacket.TYPE.TIMEOUT);
|
final IQ failurePacket = new IQ(IQ.Type.TIMEOUT);
|
||||||
final ArrayList<Consumer<IqPacket>> callbacks = new ArrayList<>();
|
final ArrayList<Consumer<IQ>> callbacks = new ArrayList<>();
|
||||||
synchronized (this.packetCallbacks) {
|
synchronized (this.packetCallbacks) {
|
||||||
if (this.packetCallbacks.size() == 0) {
|
if (this.packetCallbacks.size() == 0) {
|
||||||
return;
|
return;
|
||||||
|
@ -1825,15 +1778,15 @@ public class XmppConnection implements Runnable {
|
||||||
+ ": clearing "
|
+ ": clearing "
|
||||||
+ this.packetCallbacks.size()
|
+ this.packetCallbacks.size()
|
||||||
+ " iq callbacks");
|
+ " iq callbacks");
|
||||||
final Iterator<Pair<IqPacket, Consumer<IqPacket>>> iterator =
|
final Iterator<Pair<IQ, Consumer<IQ>>> iterator =
|
||||||
this.packetCallbacks.values().iterator();
|
this.packetCallbacks.values().iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
Pair<IqPacket, Consumer<IqPacket>> entry = iterator.next();
|
Pair<IQ, Consumer<IQ>> entry = iterator.next();
|
||||||
callbacks.add(entry.second);
|
callbacks.add(entry.second);
|
||||||
iterator.remove();
|
iterator.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (final Consumer<IqPacket> callback : callbacks) {
|
for (final Consumer<IQ> callback : callbacks) {
|
||||||
try {
|
try {
|
||||||
callback.accept(failurePacket);
|
callback.accept(failurePacket);
|
||||||
} catch (StateChangingError error) {
|
} catch (StateChangingError error) {
|
||||||
|
@ -1856,15 +1809,15 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
private void sendStartSession() {
|
private void sendStartSession() {
|
||||||
Log.d(Config.LOGTAG, account.address + ": sending legacy session to outdated server");
|
Log.d(Config.LOGTAG, account.address + ": sending legacy session to outdated server");
|
||||||
final IqPacket startSession = new IqPacket(IqPacket.TYPE.SET);
|
final IQ startSession = new IQ(IQ.Type.SET);
|
||||||
startSession.addChild("session", "urn:ietf:params:xml:ns:xmpp-session");
|
startSession.addChild("session", "urn:ietf:params:xml:ns:xmpp-session");
|
||||||
this.sendUnmodifiedIqPacket(
|
this.sendUnmodifiedIqPacket(
|
||||||
startSession,
|
startSession,
|
||||||
(packet) -> {
|
(packet) -> {
|
||||||
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
if (packet.getType() == IQ.Type.RESULT) {
|
||||||
enableStreamManagement();
|
enableStreamManagement();
|
||||||
sendPostBindInitialization(false);
|
sendPostBindInitialization(false);
|
||||||
} else if (packet.getType() != IqPacket.TYPE.TIMEOUT) {
|
} else if (packet.getType() != IQ.Type.TIMEOUT) {
|
||||||
throw new StateChangingError(ConnectionState.SESSION_FAILURE);
|
throw new StateChangingError(ConnectionState.SESSION_FAILURE);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -1876,7 +1829,7 @@ public class XmppConnection implements Runnable {
|
||||||
final boolean streamManagement = this.streamFeatures.streamManagement();
|
final boolean streamManagement = this.streamFeatures.streamManagement();
|
||||||
if (streamManagement) {
|
if (streamManagement) {
|
||||||
synchronized (this.mStanzaQueue) {
|
synchronized (this.mStanzaQueue) {
|
||||||
final EnablePacket enable = new EnablePacket();
|
final Enable enable = new Enable();
|
||||||
tagWriter.writeStanzaAsync(enable);
|
tagWriter.writeStanzaAsync(enable);
|
||||||
stanzasSent = 0;
|
stanzasSent = 0;
|
||||||
mStanzaQueue.clear();
|
mStanzaQueue.clear();
|
||||||
|
@ -1936,60 +1889,6 @@ public class XmppConnection implements Runnable {
|
||||||
return this.connectionState;
|
return this.connectionState;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void discoverMamPreferences() {
|
|
||||||
IqPacket request = new IqPacket(IqPacket.TYPE.GET);
|
|
||||||
request.addChild("prefs", MessageArchiveService.Version.MAM_2.namespace);
|
|
||||||
sendIqPacket(
|
|
||||||
request,
|
|
||||||
(response) -> {
|
|
||||||
if (response.getType() == IqPacket.TYPE.RESULT) {
|
|
||||||
Element prefs =
|
|
||||||
response.findChild(
|
|
||||||
"prefs", MessageArchiveService.Version.MAM_2.namespace);
|
|
||||||
isMamPreferenceAlways =
|
|
||||||
"always"
|
|
||||||
.equals(
|
|
||||||
prefs == null
|
|
||||||
? null
|
|
||||||
: prefs.getAttribute("default"));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void discoverCommands() {
|
|
||||||
final IqPacket request = new IqPacket(IqPacket.TYPE.GET);
|
|
||||||
request.setTo(account.address.getDomain());
|
|
||||||
request.addChild("query", Namespace.DISCO_ITEMS).setAttribute("node", Namespace.COMMANDS);
|
|
||||||
sendIqPacket(
|
|
||||||
request,
|
|
||||||
(response) -> {
|
|
||||||
if (response.getType() == IqPacket.TYPE.RESULT) {
|
|
||||||
final Element query = response.findChild("query", Namespace.DISCO_ITEMS);
|
|
||||||
if (query == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final HashMap<String, Jid> commands = new HashMap<>();
|
|
||||||
for (final Element child : query.getChildren()) {
|
|
||||||
if ("item".equals(child.getName())) {
|
|
||||||
final String node = child.getAttribute("node");
|
|
||||||
final Jid jid = child.getAttributeAsJid("jid");
|
|
||||||
if (node != null && jid != null) {
|
|
||||||
commands.put(node, jid);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
synchronized (this.commands) {
|
|
||||||
this.commands.clear();
|
|
||||||
this.commands.putAll(commands);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isMamPreferenceAlways() {
|
|
||||||
return isMamPreferenceAlways;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void finalizeBind() {
|
private void finalizeBind() {
|
||||||
this.enableAdvancedStreamFeatures();
|
this.enableAdvancedStreamFeatures();
|
||||||
this.bindConsumer.accept(this.connectionAddress);
|
this.bindConsumer.accept(this.connectionAddress);
|
||||||
|
@ -2005,12 +1904,12 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendEnableCarbons() {
|
private void sendEnableCarbons() {
|
||||||
final IqPacket iq = new IqPacket(IqPacket.TYPE.SET);
|
final IQ iq = new IQ(IQ.Type.SET);
|
||||||
iq.addChild("enable", Namespace.CARBONS);
|
iq.addChild("enable", Namespace.CARBONS);
|
||||||
this.sendIqPacket(
|
this.sendIqPacket(
|
||||||
iq,
|
iq,
|
||||||
(packet) -> {
|
(packet) -> {
|
||||||
if (packet.getType() == IqPacket.TYPE.RESULT) {
|
if (packet.getType() == IQ.Type.RESULT) {
|
||||||
Log.d(Config.LOGTAG, account.address + ": successfully enabled carbons");
|
Log.d(Config.LOGTAG, account.address + ": successfully enabled carbons");
|
||||||
this.carbonsEnabled = true;
|
this.carbonsEnabled = true;
|
||||||
} else {
|
} else {
|
||||||
|
@ -2055,9 +1954,9 @@ public class XmppConnection implements Runnable {
|
||||||
private void failPendingMessages(final String error) {
|
private void failPendingMessages(final String error) {
|
||||||
synchronized (this.mStanzaQueue) {
|
synchronized (this.mStanzaQueue) {
|
||||||
for (int i = 0; i < mStanzaQueue.size(); ++i) {
|
for (int i = 0; i < mStanzaQueue.size(); ++i) {
|
||||||
final AbstractAcknowledgeableStanza stanza = mStanzaQueue.valueAt(i);
|
final Stanza stanza = mStanzaQueue.valueAt(i);
|
||||||
if (stanza instanceof MessagePacket) {
|
if (stanza instanceof Message) {
|
||||||
final MessagePacket packet = (MessagePacket) stanza;
|
final Message packet = (Message) stanza;
|
||||||
final String id = packet.getId();
|
final String id = packet.getId();
|
||||||
final Jid to = packet.getTo();
|
final Jid to = packet.getTo();
|
||||||
// TODO set ack=true but add error?
|
// TODO set ack=true but add error?
|
||||||
|
@ -2123,15 +2022,15 @@ public class XmppConnection implements Runnable {
|
||||||
return String.format("%s.%s", context.getString(R.string.app_name), postfixId);
|
return String.format("%s.%s", context.getString(R.string.app_name), postfixId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListenableFuture<IqPacket> sendIqPacket(final IqPacket packet) {
|
public ListenableFuture<IQ> sendIqPacket(final IQ packet) {
|
||||||
final SettableFuture<IqPacket> future = SettableFuture.create();
|
final SettableFuture<IQ> future = SettableFuture.create();
|
||||||
sendIqPacket(
|
sendIqPacket(
|
||||||
packet,
|
packet,
|
||||||
result -> {
|
result -> {
|
||||||
final var type = result.getType();
|
final var type = result.getType();
|
||||||
if (type == IqPacket.TYPE.RESULT) {
|
if (type == IQ.Type.RESULT) {
|
||||||
future.set(result);
|
future.set(result);
|
||||||
} else if (type == IqPacket.TYPE.TIMEOUT) {
|
} else if (type == IQ.Type.TIMEOUT) {
|
||||||
future.setException(new TimeoutException());
|
future.setException(new TimeoutException());
|
||||||
} else {
|
} else {
|
||||||
// TODO some sort of IqErrorException
|
// TODO some sort of IqErrorException
|
||||||
|
@ -2141,15 +2040,15 @@ public class XmppConnection implements Runnable {
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String sendIqPacket(final IqPacket packet, final Consumer<IqPacket> callback) {
|
public String sendIqPacket(final IQ packet, final Consumer<IQ> callback) {
|
||||||
packet.setFrom(account.address);
|
packet.setFrom(account.address);
|
||||||
return this.sendUnmodifiedIqPacket(packet, callback, false);
|
return this.sendUnmodifiedIqPacket(packet, callback, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
public synchronized String sendUnmodifiedIqPacket(
|
public synchronized String sendUnmodifiedIqPacket(
|
||||||
final IqPacket packet, final Consumer<IqPacket> callback, boolean force) {
|
final IQ packet, final Consumer<IQ> callback, boolean force) {
|
||||||
if (Strings.isNullOrEmpty(packet.getId())) {
|
if (Strings.isNullOrEmpty(packet.getId())) {
|
||||||
packet.setAttribute("id", IDs.medium());
|
packet.setId(IDs.medium());
|
||||||
}
|
}
|
||||||
if (callback != null) {
|
if (callback != null) {
|
||||||
synchronized (this.packetCallbacks) {
|
synchronized (this.packetCallbacks) {
|
||||||
|
@ -2160,19 +2059,19 @@ public class XmppConnection implements Runnable {
|
||||||
return packet.getId();
|
return packet.getId();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendMessagePacket(final MessagePacket packet) {
|
public void sendMessagePacket(final Message packet) {
|
||||||
this.sendPacket(packet);
|
this.sendPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendPresencePacket(final PresencePacket packet) {
|
public void sendPresencePacket(final Presence packet) {
|
||||||
this.sendPacket(packet);
|
this.sendPacket(packet);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void sendPacket(final AbstractStanza packet) {
|
private synchronized void sendPacket(final StreamElement packet) {
|
||||||
sendPacket(packet, false);
|
sendPacket(packet, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private synchronized void sendPacket(final AbstractStanza packet, final boolean force) {
|
private synchronized void sendPacket(final StreamElement packet, final boolean force) {
|
||||||
if (stanzasSent == Integer.MAX_VALUE) {
|
if (stanzasSent == Integer.MAX_VALUE) {
|
||||||
resetStreamId();
|
resetStreamId();
|
||||||
disconnect(true);
|
disconnect(true);
|
||||||
|
@ -2188,8 +2087,8 @@ public class XmppConnection implements Runnable {
|
||||||
+ " do not write stanza to unbound stream "
|
+ " do not write stanza to unbound stream "
|
||||||
+ packet.toString());
|
+ packet.toString());
|
||||||
}
|
}
|
||||||
if (packet instanceof AbstractAcknowledgeableStanza) {
|
if (packet instanceof Stanza) {
|
||||||
AbstractAcknowledgeableStanza stanza = (AbstractAcknowledgeableStanza) packet;
|
final Stanza stanza = (Stanza) packet;
|
||||||
|
|
||||||
if (this.mStanzaQueue.size() != 0) {
|
if (this.mStanzaQueue.size() != 0) {
|
||||||
int currentHighestKey = this.mStanzaQueue.keyAt(this.mStanzaQueue.size() - 1);
|
int currentHighestKey = this.mStanzaQueue.keyAt(this.mStanzaQueue.size() - 1);
|
||||||
|
@ -2209,7 +2108,7 @@ public class XmppConnection implements Runnable {
|
||||||
+ stanzasSent);
|
+ stanzasSent);
|
||||||
}
|
}
|
||||||
this.mStanzaQueue.append(stanzasSent, stanza);
|
this.mStanzaQueue.append(stanzasSent, stanza);
|
||||||
if (stanza instanceof MessagePacket && stanza.getId() != null && inSmacksSession) {
|
if (stanza instanceof Message && stanza.getId() != null && inSmacksSession) {
|
||||||
if (Config.EXTENDED_SM_LOGGING) {
|
if (Config.EXTENDED_SM_LOGGING) {
|
||||||
Log.d(
|
Log.d(
|
||||||
Config.LOGTAG,
|
Config.LOGTAG,
|
||||||
|
@ -2217,7 +2116,7 @@ public class XmppConnection implements Runnable {
|
||||||
+ ": requesting ack for message stanza #"
|
+ ": requesting ack for message stanza #"
|
||||||
+ stanzasSent);
|
+ stanzasSent);
|
||||||
}
|
}
|
||||||
tagWriter.writeStanzaAsync(new RequestPacket());
|
tagWriter.writeStanzaAsync(new Request());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2225,7 +2124,7 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
public void sendPing() {
|
public void sendPing() {
|
||||||
if (!r()) {
|
if (!r()) {
|
||||||
final IqPacket iq = new IqPacket(IqPacket.TYPE.GET);
|
final IQ iq = new IQ(IQ.Type.GET);
|
||||||
iq.setFrom(account.address);
|
iq.setFrom(account.address);
|
||||||
iq.addChild("ping", Namespace.PING);
|
iq.addChild("ping", Namespace.PING);
|
||||||
this.sendIqPacket(iq, null);
|
this.sendIqPacket(iq, null);
|
||||||
|
@ -2308,7 +2207,7 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
public boolean r() {
|
public boolean r() {
|
||||||
if (this.inSmacksSession) {
|
if (this.inSmacksSession) {
|
||||||
this.tagWriter.writeStanzaAsync(new RequestPacket());
|
this.tagWriter.writeStanzaAsync(new Request());
|
||||||
return true;
|
return true;
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
|
@ -2346,11 +2245,11 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendActive() {
|
public void sendActive() {
|
||||||
this.sendPacket(new ActivePacket());
|
this.sendPacket(new Active());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void sendInactive() {
|
public void sendInactive() {
|
||||||
this.sendPacket(new InactivePacket());
|
this.sendPacket(new Inactive());
|
||||||
}
|
}
|
||||||
|
|
||||||
public void resetAttemptCount(boolean resetConnectTime) {
|
public void resetAttemptCount(boolean resetConnectTime) {
|
||||||
|
@ -2360,7 +2259,7 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean fromServer(final AbstractStanza stanza) {
|
public boolean fromServer(final Stanza stanza) {
|
||||||
final Jid from = stanza.getFrom();
|
final Jid from = stanza.getFrom();
|
||||||
return from == null
|
return from == null
|
||||||
|| from.equals(connectionAddress.getDomain())
|
|| from.equals(connectionAddress.getDomain())
|
||||||
|
@ -2368,7 +2267,7 @@ public class XmppConnection implements Runnable {
|
||||||
|| from.equals(connectionAddress);
|
|| from.equals(connectionAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean toServer(final AbstractStanza stanza) {
|
public boolean toServer(final Stanza stanza) {
|
||||||
final Jid to = stanza.getTo();
|
final Jid to = stanza.getTo();
|
||||||
return to == null
|
return to == null
|
||||||
|| to.equals(connectionAddress.getDomain())
|
|| to.equals(connectionAddress.getDomain())
|
||||||
|
@ -2376,7 +2275,7 @@ public class XmppConnection implements Runnable {
|
||||||
|| to.equals(connectionAddress);
|
|| to.equals(connectionAddress);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean fromAccount(final AbstractStanza stanza) {
|
public boolean fromAccount(final Stanza stanza) {
|
||||||
final Jid from = stanza.getFrom();
|
final Jid from = stanza.getFrom();
|
||||||
return from != null && from.asBareJid().equals(connectionAddress.asBareJid());
|
return from != null && from.asBareJid().equals(connectionAddress.asBareJid());
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,11 +2,11 @@ package im.conversations.android.xmpp.manager;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Collections2;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
|
||||||
import im.conversations.android.xmpp.XmppConnection;
|
import im.conversations.android.xmpp.XmppConnection;
|
||||||
import im.conversations.android.xmpp.model.blocking.Block;
|
import im.conversations.android.xmpp.model.blocking.Block;
|
||||||
import im.conversations.android.xmpp.model.blocking.Blocklist;
|
import im.conversations.android.xmpp.model.blocking.Blocklist;
|
||||||
import im.conversations.android.xmpp.model.blocking.Unblock;
|
import im.conversations.android.xmpp.model.blocking.Unblock;
|
||||||
|
import im.conversations.android.xmpp.model.stanza.IQ;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class BlockingManager extends AbstractManager {
|
public class BlockingManager extends AbstractManager {
|
||||||
|
@ -20,13 +20,13 @@ public class BlockingManager extends AbstractManager {
|
||||||
public void handlePush(final Unblock unblock) {}
|
public void handlePush(final Unblock unblock) {}
|
||||||
|
|
||||||
public void fetch() {
|
public void fetch() {
|
||||||
final IqPacket iqPacket = new IqPacket(IqPacket.TYPE.GET);
|
final IQ iqPacket = new IQ(IQ.Type.GET);
|
||||||
iqPacket.addChild(new Blocklist());
|
iqPacket.addChild(new Blocklist());
|
||||||
connection.sendIqPacket(iqPacket, this::handleFetchResult);
|
connection.sendIqPacket(iqPacket, this::handleFetchResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleFetchResult(final IqPacket result) {
|
private void handleFetchResult(final IQ result) {
|
||||||
if (result.getType() != IqPacket.TYPE.RESULT) {
|
if (result.getType() != IQ.Type.RESULT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final var blocklist = result.getExtension(Blocklist.class);
|
final var blocklist = result.getExtension(Blocklist.class);
|
||||||
|
|
|
@ -10,7 +10,6 @@ import com.google.common.util.concurrent.Futures;
|
||||||
import com.google.common.util.concurrent.ListenableFuture;
|
import com.google.common.util.concurrent.ListenableFuture;
|
||||||
import com.google.common.util.concurrent.MoreExecutors;
|
import com.google.common.util.concurrent.MoreExecutors;
|
||||||
import eu.siacs.conversations.xmpp.Jid;
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
|
||||||
import im.conversations.android.xmpp.Entity;
|
import im.conversations.android.xmpp.Entity;
|
||||||
import im.conversations.android.xmpp.EntityCapabilities;
|
import im.conversations.android.xmpp.EntityCapabilities;
|
||||||
import im.conversations.android.xmpp.EntityCapabilities2;
|
import im.conversations.android.xmpp.EntityCapabilities2;
|
||||||
|
@ -18,6 +17,7 @@ import im.conversations.android.xmpp.XmppConnection;
|
||||||
import im.conversations.android.xmpp.model.disco.info.InfoQuery;
|
import im.conversations.android.xmpp.model.disco.info.InfoQuery;
|
||||||
import im.conversations.android.xmpp.model.disco.items.Item;
|
import im.conversations.android.xmpp.model.disco.items.Item;
|
||||||
import im.conversations.android.xmpp.model.disco.items.ItemsQuery;
|
import im.conversations.android.xmpp.model.disco.items.ItemsQuery;
|
||||||
|
import im.conversations.android.xmpp.model.stanza.IQ;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -52,7 +52,7 @@ public class DiscoManager extends AbstractManager {
|
||||||
@Nullable final String node,
|
@Nullable final String node,
|
||||||
@Nullable final EntityCapabilities.Hash hash) {
|
@Nullable final EntityCapabilities.Hash hash) {
|
||||||
final var requestNode = hash != null && node != null ? hash.capabilityNode(node) : node;
|
final var requestNode = hash != null && node != null ? hash.capabilityNode(node) : node;
|
||||||
final var iqRequest = new IqPacket(IqPacket.TYPE.GET);
|
final var iqRequest = new IQ(IQ.Type.GET);
|
||||||
iqRequest.setTo(entity.address);
|
iqRequest.setTo(entity.address);
|
||||||
final InfoQuery infoQueryRequest = iqRequest.addExtension(new InfoQuery());
|
final InfoQuery infoQueryRequest = iqRequest.addExtension(new InfoQuery());
|
||||||
if (requestNode != null) {
|
if (requestNode != null) {
|
||||||
|
@ -114,7 +114,7 @@ public class DiscoManager extends AbstractManager {
|
||||||
public ListenableFuture<Collection<Item>> items(
|
public ListenableFuture<Collection<Item>> items(
|
||||||
@NonNull final Entity.DiscoItem entity, @Nullable final String node) {
|
@NonNull final Entity.DiscoItem entity, @Nullable final String node) {
|
||||||
final var requestNode = Strings.emptyToNull(node);
|
final var requestNode = Strings.emptyToNull(node);
|
||||||
final var iqPacket = new IqPacket(IqPacket.TYPE.GET);
|
final var iqPacket = new IQ(IQ.Type.GET);
|
||||||
iqPacket.setTo(entity.address);
|
iqPacket.setTo(entity.address);
|
||||||
final ItemsQuery itemsQueryRequest = iqPacket.addExtension(new ItemsQuery());
|
final ItemsQuery itemsQueryRequest = iqPacket.addExtension(new ItemsQuery());
|
||||||
if (requestNode != null) {
|
if (requestNode != null) {
|
||||||
|
|
|
@ -5,10 +5,10 @@ import android.util.Log;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.Collections2;
|
import com.google.common.collect.Collections2;
|
||||||
import eu.siacs.conversations.Config;
|
import eu.siacs.conversations.Config;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
|
||||||
import im.conversations.android.xmpp.XmppConnection;
|
import im.conversations.android.xmpp.XmppConnection;
|
||||||
import im.conversations.android.xmpp.model.roster.Item;
|
import im.conversations.android.xmpp.model.roster.Item;
|
||||||
import im.conversations.android.xmpp.model.roster.Query;
|
import im.conversations.android.xmpp.model.roster.Query;
|
||||||
|
import im.conversations.android.xmpp.model.stanza.IQ;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
public class RosterManager extends AbstractManager {
|
public class RosterManager extends AbstractManager {
|
||||||
|
@ -27,7 +27,7 @@ public class RosterManager extends AbstractManager {
|
||||||
final var account = getAccount();
|
final var account = getAccount();
|
||||||
final var database = getDatabase();
|
final var database = getDatabase();
|
||||||
final String rosterVersion = database.accountDao().getRosterVersion(account.id);
|
final String rosterVersion = database.accountDao().getRosterVersion(account.id);
|
||||||
final IqPacket iqPacket = new IqPacket(IqPacket.TYPE.GET);
|
final IQ iqPacket = new IQ(IQ.Type.GET);
|
||||||
final Query rosterQuery = new Query();
|
final Query rosterQuery = new Query();
|
||||||
iqPacket.addChild(rosterQuery);
|
iqPacket.addChild(rosterQuery);
|
||||||
if (Strings.isNullOrEmpty(rosterVersion)) {
|
if (Strings.isNullOrEmpty(rosterVersion)) {
|
||||||
|
@ -39,8 +39,8 @@ public class RosterManager extends AbstractManager {
|
||||||
connection.sendIqPacket(iqPacket, this::handleFetchResult);
|
connection.sendIqPacket(iqPacket, this::handleFetchResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleFetchResult(final IqPacket result) {
|
private void handleFetchResult(final IQ result) {
|
||||||
if (result.getType() != IqPacket.TYPE.RESULT) {
|
if (result.getType() != IQ.Type.RESULT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final var query = result.getExtension(Query.class);
|
final var query = result.getExtension(Query.class);
|
||||||
|
|
|
@ -0,0 +1,8 @@
|
||||||
|
package im.conversations.android.xmpp.model;
|
||||||
|
|
||||||
|
public abstract class StreamElement extends Extension {
|
||||||
|
|
||||||
|
protected StreamElement(Class<? extends Extension> clazz) {
|
||||||
|
super(clazz);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package im.conversations.android.xmpp.model.csi;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.StreamElement;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class Active extends StreamElement {
|
||||||
|
|
||||||
|
public Active() {
|
||||||
|
super(Active.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package im.conversations.android.xmpp.model.csi;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.StreamElement;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class Inactive extends StreamElement {
|
||||||
|
|
||||||
|
public Inactive() {
|
||||||
|
super(Inactive.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@XmlPackage(namespace = Namespace.CSI)
|
||||||
|
package im.conversations.android.xmpp.model.csi;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
import im.conversations.android.annotation.XmlPackage;
|
|
@ -0,0 +1,12 @@
|
||||||
|
package im.conversations.android.xmpp.model.register;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
|
||||||
|
@XmlElement(name = "query")
|
||||||
|
public class Register extends Extension {
|
||||||
|
|
||||||
|
public Register() {
|
||||||
|
super(Register.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@XmlPackage(namespace = Namespace.REGISTER)
|
||||||
|
package im.conversations.android.xmpp.model.register;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
import im.conversations.android.annotation.XmlPackage;
|
|
@ -0,0 +1,17 @@
|
||||||
|
package im.conversations.android.xmpp.model.sm;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.StreamElement;
|
||||||
|
|
||||||
|
@XmlElement(name = "a")
|
||||||
|
public class Ack extends StreamElement {
|
||||||
|
|
||||||
|
public Ack() {
|
||||||
|
super(Ack.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Ack(final int sequence) {
|
||||||
|
super(Ack.class);
|
||||||
|
this.setAttribute("h", sequence);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package im.conversations.android.xmpp.model.sm;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.StreamElement;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class Enable extends StreamElement {
|
||||||
|
|
||||||
|
public Enable() {
|
||||||
|
super(Enable.class);
|
||||||
|
this.setAttribute("resume", "true");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package im.conversations.android.xmpp.model.sm;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.StreamElement;
|
||||||
|
|
||||||
|
@XmlElement(name = "r")
|
||||||
|
public class Request extends StreamElement {
|
||||||
|
|
||||||
|
public Request() {
|
||||||
|
super(Request.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
package im.conversations.android.xmpp.model.sm;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.StreamElement;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class Resume extends StreamElement {
|
||||||
|
|
||||||
|
public Resume() {
|
||||||
|
super(Resume.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Resume(final String id, final int sequence) {
|
||||||
|
super(Resume.class);
|
||||||
|
this.setAttribute("previd", id);
|
||||||
|
this.setAttribute("h", sequence);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@XmlPackage(namespace = Namespace.STREAM_MANAGEMENT)
|
||||||
|
package im.conversations.android.xmpp.model.sm;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
import im.conversations.android.annotation.XmlPackage;
|
|
@ -0,0 +1,32 @@
|
||||||
|
package im.conversations.android.xmpp.model.stanza;
|
||||||
|
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class IQ extends Stanza {
|
||||||
|
|
||||||
|
public IQ() {
|
||||||
|
super(IQ.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public IQ(final Type type) {
|
||||||
|
super(IQ.class);
|
||||||
|
this.setAttribute("type", type.toString().toLowerCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO get rid of timeout
|
||||||
|
public enum Type {
|
||||||
|
SET,
|
||||||
|
GET,
|
||||||
|
ERROR,
|
||||||
|
RESULT,
|
||||||
|
TIMEOUT
|
||||||
|
}
|
||||||
|
|
||||||
|
public Type getType() {
|
||||||
|
return Type.valueOf(
|
||||||
|
Strings.nullToEmpty(this.getAttribute("type")).toUpperCase(Locale.ROOT));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,11 @@
|
||||||
|
package im.conversations.android.xmpp.model.stanza;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class Message extends Stanza {
|
||||||
|
|
||||||
|
public Message() {
|
||||||
|
super(Message.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
package im.conversations.android.xmpp.model.stanza;
|
||||||
|
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.capabilties.EntityCapabilities;
|
||||||
|
|
||||||
|
@XmlElement
|
||||||
|
public class Presence extends Stanza implements EntityCapabilities {
|
||||||
|
|
||||||
|
public Presence() {
|
||||||
|
super(Presence.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
package im.conversations.android.xmpp.model.stanza;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
import im.conversations.android.xmpp.model.StreamElement;
|
||||||
|
|
||||||
|
public abstract class Stanza extends StreamElement {
|
||||||
|
|
||||||
|
protected Stanza(Class<? extends Extension> clazz) {
|
||||||
|
super(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Jid getTo() {
|
||||||
|
return this.getAttributeAsJid("to");
|
||||||
|
}
|
||||||
|
|
||||||
|
public Jid getFrom() {
|
||||||
|
return this.getAttributeAsJid("from");
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return this.getAttribute("id");
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setId(final String id) {
|
||||||
|
this.setAttribute("id", id);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setFrom(final Jid from) {
|
||||||
|
this.setAttribute("from", from);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setTo(final Jid to) {
|
||||||
|
this.setAttribute("to", to);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,5 @@
|
||||||
|
@XmlPackage(namespace = Namespace.JABBER_CLIENT)
|
||||||
|
package im.conversations.android.xmpp.model.stanza;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
import im.conversations.android.annotation.XmlPackage;
|
|
@ -2,40 +2,39 @@ package im.conversations.android.xmpp.processor;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import com.google.common.base.Preconditions;
|
import com.google.common.base.Preconditions;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
|
|
||||||
import im.conversations.android.xmpp.XmppConnection;
|
import im.conversations.android.xmpp.XmppConnection;
|
||||||
import im.conversations.android.xmpp.manager.BlockingManager;
|
import im.conversations.android.xmpp.manager.BlockingManager;
|
||||||
import im.conversations.android.xmpp.manager.RosterManager;
|
import im.conversations.android.xmpp.manager.RosterManager;
|
||||||
import im.conversations.android.xmpp.model.blocking.Block;
|
import im.conversations.android.xmpp.model.blocking.Block;
|
||||||
import im.conversations.android.xmpp.model.blocking.Unblock;
|
import im.conversations.android.xmpp.model.blocking.Unblock;
|
||||||
import im.conversations.android.xmpp.model.roster.Query;
|
import im.conversations.android.xmpp.model.roster.Query;
|
||||||
|
import im.conversations.android.xmpp.model.stanza.IQ;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class IqProcessor extends XmppConnection.Delegate implements Consumer<IqPacket> {
|
public class IqProcessor extends XmppConnection.Delegate implements Consumer<IQ> {
|
||||||
|
|
||||||
public IqProcessor(final Context context, final XmppConnection connection) {
|
public IqProcessor(final Context context, final XmppConnection connection) {
|
||||||
super(context, connection);
|
super(context, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(final IqPacket packet) {
|
public void accept(final IQ packet) {
|
||||||
final IqPacket.TYPE type = packet.getType();
|
final IQ.Type type = packet.getType();
|
||||||
Preconditions.checkArgument(
|
Preconditions.checkArgument(Arrays.asList(IQ.Type.GET, IQ.Type.SET).contains(type));
|
||||||
Arrays.asList(IqPacket.TYPE.GET, IqPacket.TYPE.SET).contains(type));
|
if (type == IQ.Type.SET
|
||||||
if (type == IqPacket.TYPE.SET
|
|
||||||
&& connection.fromAccount(packet)
|
&& connection.fromAccount(packet)
|
||||||
&& packet.hasExtension(Query.class)) {
|
&& packet.hasExtension(Query.class)) {
|
||||||
getManager(RosterManager.class).handlePush(packet.getExtension(Query.class));
|
getManager(RosterManager.class).handlePush(packet.getExtension(Query.class));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == IqPacket.TYPE.SET
|
if (type == IQ.Type.SET
|
||||||
&& connection.fromAccount(packet)
|
&& connection.fromAccount(packet)
|
||||||
&& packet.hasExtension(Block.class)) {
|
&& packet.hasExtension(Block.class)) {
|
||||||
getManager(BlockingManager.class).handlePush(packet.getExtension(Block.class));
|
getManager(BlockingManager.class).handlePush(packet.getExtension(Block.class));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == IqPacket.TYPE.SET
|
if (type == IQ.Type.SET
|
||||||
&& connection.fromAccount(packet)
|
&& connection.fromAccount(packet)
|
||||||
&& packet.hasExtension(Unblock.class)) {
|
&& packet.hasExtension(Unblock.class)) {
|
||||||
getManager(BlockingManager.class).handlePush(packet.getExtension(Unblock.class));
|
getManager(BlockingManager.class).handlePush(packet.getExtension(Unblock.class));
|
||||||
|
|
|
@ -1,14 +0,0 @@
|
||||||
package im.conversations.android.xmpp.processor;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import eu.siacs.conversations.xmpp.jingle.stanzas.JinglePacket;
|
|
||||||
import im.conversations.android.xmpp.XmppConnection;
|
|
||||||
import java.util.function.Consumer;
|
|
||||||
|
|
||||||
public class JingleProcessor implements Consumer<JinglePacket> {
|
|
||||||
|
|
||||||
public JingleProcessor(final Context context, final XmppConnection connection) {}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void accept(JinglePacket jinglePacket) {}
|
|
||||||
}
|
|
|
@ -1,14 +1,14 @@
|
||||||
package im.conversations.android.xmpp.processor;
|
package im.conversations.android.xmpp.processor;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
|
||||||
import im.conversations.android.xmpp.XmppConnection;
|
import im.conversations.android.xmpp.XmppConnection;
|
||||||
|
import im.conversations.android.xmpp.model.stanza.Message;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class MessageProcessor implements Consumer<MessagePacket> {
|
public class MessageProcessor implements Consumer<Message> {
|
||||||
|
|
||||||
public MessageProcessor(final Context context, final XmppConnection connection) {}
|
public MessageProcessor(final Context context, final XmppConnection connection) {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(final MessagePacket messagePacket) {}
|
public void accept(final Message messagePacket) {}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,22 +1,22 @@
|
||||||
package im.conversations.android.xmpp.processor;
|
package im.conversations.android.xmpp.processor;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
|
|
||||||
import im.conversations.android.database.model.PresenceShow;
|
import im.conversations.android.database.model.PresenceShow;
|
||||||
import im.conversations.android.database.model.PresenceType;
|
import im.conversations.android.database.model.PresenceType;
|
||||||
import im.conversations.android.xmpp.Entity;
|
import im.conversations.android.xmpp.Entity;
|
||||||
import im.conversations.android.xmpp.XmppConnection;
|
import im.conversations.android.xmpp.XmppConnection;
|
||||||
import im.conversations.android.xmpp.manager.DiscoManager;
|
import im.conversations.android.xmpp.manager.DiscoManager;
|
||||||
|
import im.conversations.android.xmpp.model.stanza.Presence;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class PresenceProcessor extends XmppConnection.Delegate implements Consumer<PresencePacket> {
|
public class PresenceProcessor extends XmppConnection.Delegate implements Consumer<Presence> {
|
||||||
|
|
||||||
public PresenceProcessor(final Context context, final XmppConnection connection) {
|
public PresenceProcessor(final Context context, final XmppConnection connection) {
|
||||||
super(context, connection);
|
super(context, connection);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void accept(final PresencePacket presencePacket) {
|
public void accept(final Presence presencePacket) {
|
||||||
final var from = presencePacket.getFrom();
|
final var from = presencePacket.getFrom();
|
||||||
final var address = from == null ? null : from.asBareJid();
|
final var address = from == null ? null : from.asBareJid();
|
||||||
final var resource = from == null ? null : from.getResource();
|
final var resource = from == null ? null : from.getResource();
|
||||||
|
@ -38,7 +38,7 @@ public class PresenceProcessor extends XmppConnection.Delegate implements Consum
|
||||||
fetchCapabilities(presencePacket);
|
fetchCapabilities(presencePacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fetchCapabilities(final PresencePacket presencePacket) {
|
private void fetchCapabilities(final Presence presencePacket) {
|
||||||
final var entity = presencePacket.getFrom();
|
final var entity = presencePacket.getFrom();
|
||||||
final var nodeHash = presencePacket.getCapabilities();
|
final var nodeHash = presencePacket.getCapabilities();
|
||||||
if (nodeHash != null) {
|
if (nodeHash != null) {
|
||||||
|
|
Loading…
Reference in a new issue