create new models for IQ, Message & Presence

This commit is contained in:
Daniel Gultsch 2023-01-22 20:25:47 +01:00
parent f16603742f
commit d2794ccf32
No known key found for this signature in database
GPG key ID: F43D18AD2A0982C2
27 changed files with 621 additions and 393 deletions

View file

@ -78,4 +78,5 @@ public final class Namespace {
public static final String OMEMO_DTLS_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 JABBER_CLIENT = "jabber:client";
}

View file

@ -30,126 +30,128 @@
package eu.siacs.conversations.xmpp;
import androidx.annotation.NonNull;
import eu.siacs.conversations.xmpp.stanzas.AbstractStanza;
public class InvalidJid implements Jid {
private final String value;
private final String value;
private InvalidJid(String jid) {
this.value = jid;
}
private InvalidJid(String jid) {
this.value = jid;
}
public static Jid of(String jid, boolean fallback) {
final int pos = jid.indexOf('/');
if (fallback && pos >= 0 && jid.length() >= pos + 1) {
if (jid.substring(pos+1).trim().isEmpty()) {
return Jid.ofEscaped(jid.substring(0,pos));
}
}
return new InvalidJid(jid);
}
public static Jid of(String jid, boolean fallback) {
final int pos = jid.indexOf('/');
if (fallback && pos >= 0 && jid.length() >= pos + 1) {
if (jid.substring(pos + 1).trim().isEmpty()) {
return Jid.ofEscaped(jid.substring(0, pos));
}
}
return new InvalidJid(jid);
}
@Override
@NonNull
public String toString() {
return value;
}
@Override
@NonNull
public String toString() {
return value;
}
@Override
public boolean isFullJid() {
throw new AssertionError("Not implemented");
}
@Override
public boolean isFullJid() {
throw new AssertionError("Not implemented");
}
@Override
public boolean isBareJid() {
throw new AssertionError("Not implemented");
}
@Override
public boolean isBareJid() {
throw new AssertionError("Not implemented");
}
@Override
public boolean isDomainJid() {
throw new AssertionError("Not implemented");
}
@Override
public boolean isDomainJid() {
throw new AssertionError("Not implemented");
}
@Override
public Jid asBareJid() {
throw new AssertionError("Not implemented");
}
@Override
public Jid asBareJid() {
throw new AssertionError("Not implemented");
}
@Override
public Jid withResource(CharSequence charSequence) {
throw new AssertionError("Not implemented");
}
@Override
public Jid withResource(CharSequence charSequence) {
throw new AssertionError("Not implemented");
}
@Override
public String getLocal() {
throw new AssertionError("Not implemented");
}
@Override
public String getLocal() {
throw new AssertionError("Not implemented");
}
@Override
public String getEscapedLocal() {
throw new AssertionError("Not implemented");
}
@Override
public String getEscapedLocal() {
throw new AssertionError("Not implemented");
}
@Override
public Jid getDomain() {
throw new AssertionError("Not implemented");
}
@Override
public Jid getDomain() {
throw new AssertionError("Not implemented");
}
@Override
public String getResource() {
throw new AssertionError("Not implemented");
}
@Override
public String getResource() {
throw new AssertionError("Not implemented");
}
@Override
public String toEscapedString() {
throw new AssertionError("Not implemented");
}
@Override
public String toEscapedString() {
throw new AssertionError("Not implemented");
}
@Override
public int length() {
return value.length();
}
@Override
public int length() {
return value.length();
}
@Override
public char charAt(int index) {
return value.charAt(index);
}
@Override
public char charAt(int index) {
return value.charAt(index);
}
@Override
public CharSequence subSequence(int start, int end) {
return value.subSequence(start, end);
}
@Override
public CharSequence subSequence(int start, int end) {
return value.subSequence(start, end);
}
@Override
public int compareTo(@NonNull Jid o) {
throw new AssertionError("Not implemented");
}
@Override
public int compareTo(@NonNull Jid o) {
throw new AssertionError("Not implemented");
}
public static Jid getNullForInvalid(Jid jid) {
if (jid instanceof InvalidJid) {
return null;
} else {
return jid;
}
}
public static Jid getNullForInvalid(Jid jid) {
if (jid instanceof InvalidJid) {
return null;
} else {
return jid;
}
}
public static boolean isValid(Jid jid) {
return !(jid != null && jid instanceof InvalidJid);
}
public static boolean isValid(Jid jid) {
return !(jid != null && jid instanceof InvalidJid);
}
public static boolean invalid(final Jid jid) {
return jid instanceof InvalidJid;
}
public static boolean hasValidFrom(AbstractStanza stanza) {
final String from = stanza.getAttribute("from");
if (from == null) {
return false;
}
try {
Jid.ofEscaped(from);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
public static boolean hasValidFrom(AbstractStanza stanza) {
final String from = stanza.getAttribute("from");
if (from == null) {
return false;
}
try {
Jid.ofEscaped(from);
return true;
} catch (IllegalArgumentException e) {
return false;
}
}
}

View 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;
}
}

View file

@ -28,7 +28,6 @@ import eu.siacs.conversations.crypto.XmppDomainVerifier;
import eu.siacs.conversations.http.HttpConnectionManager;
import eu.siacs.conversations.persistance.FileBackend;
import eu.siacs.conversations.services.MemorizingTrustManager;
import eu.siacs.conversations.services.MessageArchiveService;
import eu.siacs.conversations.services.NotificationService;
import eu.siacs.conversations.ui.util.PendingItem;
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.Namespace;
import eu.siacs.conversations.xml.Tag;
import eu.siacs.conversations.xml.TagWriter;
import eu.siacs.conversations.xml.XmlReader;
import eu.siacs.conversations.xmpp.InvalidJid;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.bind.Bind2;
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.RequestPacket;
import eu.siacs.conversations.xmpp.stanzas.streammgmt.ResumePacket;
import im.conversations.android.IDs;
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.Connection;
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.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.processor.BindProcessor;
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.MessageProcessor;
import im.conversations.android.xmpp.processor.PresenceProcessor;
@ -93,7 +94,6 @@ import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
@ -117,14 +117,9 @@ import org.xmlpull.v1.XmlPullParserException;
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;
private final HashMap<String, Jid> commands = new HashMap<>();
private final SparseArray<AbstractAcknowledgeableStanza> mStanzaQueue = new SparseArray<>();
private final Hashtable<String, Pair<IqPacket, Consumer<IqPacket>>> packetCallbacks =
new Hashtable<>();
private final SparseArray<Stanza> mStanzaQueue = new SparseArray<>();
private final Hashtable<String, Pair<IQ, Consumer<IQ>>> packetCallbacks = new Hashtable<>();
private final Context context;
private Socket socket;
private XmlReader tagReader;
@ -149,19 +144,17 @@ public class XmppConnection implements Runnable {
private long lastPingSent = 0;
private long lastConnect = 0;
private long lastSessionStarted = 0;
private boolean isMamPreferenceAlways = false;
private final AtomicBoolean mWaitingForSmCatchup = new AtomicBoolean(false);
private final AtomicInteger mSmCatchupMessageCounter = new AtomicInteger(0);
private int attempt = 0;
private final Consumer<PresencePacket> presencePacketConsumer;
private final Consumer<JinglePacket> jinglePacketConsumer;
private final Consumer<IqPacket> iqPacketConsumer;
private final Consumer<MessagePacket> messagePacketConsumer;
private final Consumer<Presence> presencePacketConsumer;
private final Consumer<IQ> iqPacketConsumer;
private final Consumer<Message> messagePacketConsumer;
private final BiFunction<Jid, String, Boolean> messageAcknowledgeProcessor;
private final Consumer<Jid> bindConsumer;
private final ClassToInstanceMap<AbstractManager> managers;
private Consumer<XmppConnection> statusListener = null;
private PendingItem<SettableFuture<XmppConnection>> connectedFuture = new PendingItem<>();
private final PendingItem<SettableFuture<XmppConnection>> connectedFuture = new PendingItem<>();
private SaslMechanism saslMechanism;
private HashedToken.Mechanism hashTokenRequest;
private HttpUrl redirectionUrl = null;
@ -181,7 +174,6 @@ public class XmppConnection implements Runnable {
this.messagePacketConsumer = new MessageProcessor(context, this);
this.presencePacketConsumer = new PresenceProcessor(context, this);
this.iqPacketConsumer = new IqProcessor(context, this);
this.jinglePacketConsumer = new JingleProcessor(context, this);
this.messageAcknowledgeProcessor = new MessageAcknowledgeProcessor(context, this);
this.bindConsumer = new BindProcessor(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() {
this.lastConnect = SystemClock.elapsedRealtime();
this.lastPingSent = SystemClock.elapsedRealtime();
@ -616,7 +602,7 @@ public class XmppConnection implements Runnable {
Config.LOGTAG,
account.address + ": acknowledging stanza #" + this.stanzasReceived);
}
final AckPacket ack = new AckPacket(this.stanzasReceived);
final Ack ack = new Ack(this.stanzasReceived);
tagWriter.writeStanzaAsync(ack);
} else if (nextTag.isStart("a")) {
synchronized (NotificationService.CATCHUP_LOCK) {
@ -849,7 +835,7 @@ public class XmppConnection implements Runnable {
private void resetOutboundStanzaQueue() {
synchronized (this.mStanzaQueue) {
final List<AbstractAcknowledgeableStanza> intermediateStanzas = new ArrayList<>();
final List<Stanza> intermediateStanzas = new ArrayList<>();
if (Config.EXTENDED_SM_LOGGING) {
Log.d(
Config.LOGTAG,
@ -858,7 +844,7 @@ public class XmppConnection implements Runnable {
+ this.stanzasSentBeforeAuthentication);
}
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) {
intermediateStanzas.add(stanza);
}
@ -966,14 +952,14 @@ public class XmppConnection implements Runnable {
this.streamId = streamId;
this.stanzasReceived = 0;
this.inSmacksSession = true;
final RequestPacket r = new RequestPacket();
final Request r = new Request();
tagWriter.writeStanzaAsync(r);
}
private void processResumed(final Element resumed) throws StateChangingException {
this.inSmacksSession = true;
this.isBound = true;
this.tagWriter.writeStanzaAsync(new RequestPacket());
this.tagWriter.writeStanzaAsync(new Request());
lastPacketReceived = SystemClock.elapsedRealtime();
final Optional<Integer> h = resumed.getOptionalIntAttribute("h");
final int serverCount;
@ -983,7 +969,7 @@ public class XmppConnection implements Runnable {
resetStreamId();
throw new StateChangingException(ConnectionState.INCOMPATIBLE_SERVER);
}
final ArrayList<AbstractAcknowledgeableStanza> failedStanzas = new ArrayList<>();
final ArrayList<Stanza> failedStanzas = new ArrayList<>();
final boolean acknowledgedMessages;
synchronized (this.mStanzaQueue) {
if (serverCount < stanzasSent) {
@ -999,9 +985,9 @@ public class XmppConnection implements Runnable {
mStanzaQueue.clear();
}
Log.d(Config.LOGTAG, account.address + ": resending " + failedStanzas.size() + " stanzas");
for (final AbstractAcknowledgeableStanza packet : failedStanzas) {
if (packet instanceof MessagePacket) {
MessagePacket message = (MessagePacket) packet;
for (final Stanza packet : failedStanzas) {
if (packet instanceof Message) {
Message message = (Message) packet;
// TODO set ack = false in message table
// context.markMessage(account, message.getTo().asBareJid(), message.getId(),
// Message.STATUS_UNSEND);
@ -1058,9 +1044,9 @@ public class XmppConnection implements Runnable {
+ ": server acknowledged stanza #"
+ mStanzaQueue.keyAt(i));
}
final AbstractAcknowledgeableStanza stanza = mStanzaQueue.valueAt(i);
if (stanza instanceof MessagePacket && messageAcknowledgeProcessor != null) {
final MessagePacket packet = (MessagePacket) stanza;
final Stanza stanza = mStanzaQueue.valueAt(i);
if (stanza instanceof Message) {
final Message packet = (Message) stanza;
final String id = packet.getId();
final Jid to = packet.getTo();
if (id != null && to != null) {
@ -1074,36 +1060,9 @@ public class XmppConnection implements Runnable {
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 {
final Element element;
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");
}
}
final S stanza = tagReader.readElement(currentTag, clazz);
if (stanzasReceived == Integer.MAX_VALUE) {
resetStreamId();
throw new IOException("time to restart the session. cant handle >2 billion pcks");
@ -1115,103 +1074,93 @@ public class XmppConnection implements Runnable {
Config.LOGTAG,
account.address
+ ": not counting stanza("
+ element.getClass().getSimpleName()
+ stanza.getClass().getSimpleName()
+ "). Not in smacks session.");
}
lastPacketReceived = SystemClock.elapsedRealtime();
if (element instanceof IqPacket
&& (((IqPacket) element).getType() == IqPacket.TYPE.SET)
&& element.hasChild("jingle", Namespace.JINGLE)) {
return JinglePacket.upgrade((IqPacket) element);
} else {
return element;
if (InvalidJid.invalid(stanza.getTo()) || InvalidJid.invalid(stanza.getFrom())) {
Log.e(
Config.LOGTAG,
"encountered invalid stanza from "
+ stanza.getFrom()
+ " to "
+ stanza.getTo());
}
return stanza;
}
private void processIq(final Tag currentTag) throws IOException {
final IqPacket packet = (IqPacket) processPacket(currentTag, PACKET_IQ);
if (!packet.valid()) {
final IQ packet = processStanza(currentTag, IQ.class);
if (InvalidJid.invalid(packet.getTo()) || InvalidJid.invalid(packet.getFrom())) {
Log.e(
Config.LOGTAG,
"encountered invalid iq from='"
+ packet.getFrom()
+ "' to='"
+ packet.getTo()
+ "'");
"encountered invalid IQ from " + packet.getFrom() + " to " + packet.getTo());
return;
}
if (packet instanceof JinglePacket) {
this.jinglePacketConsumer.accept((JinglePacket) packet);
} else {
final Consumer<IqPacket> callback;
synchronized (this.packetCallbacks) {
final Pair<IqPacket, Consumer<IqPacket>> packetCallbackDuple =
packetCallbacks.get(packet.getId());
if (packetCallbackDuple != null) {
// Packets to the server should have responses from the server
if (toServer(packetCallbackDuple.first)) {
if (fromServer(packet)) {
callback = packetCallbackDuple.second;
packetCallbacks.remove(packet.getId());
} else {
callback = null;
Log.e(Config.LOGTAG, account.address + ": ignoring spoofed iq packet");
}
final Consumer<IQ> callback;
synchronized (this.packetCallbacks) {
final Pair<IQ, Consumer<IQ>> packetCallbackDuple = packetCallbacks.get(packet.getId());
if (packetCallbackDuple != null) {
// Packets to the server should have responses from the server
if (toServer(packetCallbackDuple.first)) {
if (fromServer(packet)) {
callback = packetCallbackDuple.second;
packetCallbacks.remove(packet.getId());
} else {
if (packet.getFrom() != null
&& packet.getFrom().equals(packetCallbackDuple.first.getTo())) {
callback = packetCallbackDuple.second;
packetCallbacks.remove(packet.getId());
} else {
callback = null;
Log.e(Config.LOGTAG, account.address + ": ignoring spoofed iq packet");
}
callback = null;
Log.e(Config.LOGTAG, account.address + ": ignoring spoofed iq packet");
}
} else if (packet.getType() == IqPacket.TYPE.GET
|| packet.getType() == IqPacket.TYPE.SET) {
callback = this.iqPacketConsumer;
} else {
callback = null;
if (packet.getFrom() != null
&& packet.getFrom().equals(packetCallbackDuple.first.getTo())) {
callback = packetCallbackDuple.second;
packetCallbacks.remove(packet.getId());
} else {
callback = null;
Log.e(Config.LOGTAG, account.address + ": ignoring spoofed iq packet");
}
}
} else if (packet.getType() == IQ.Type.GET || packet.getType() == IQ.Type.SET) {
callback = this.iqPacketConsumer;
} else {
callback = null;
}
if (callback != null) {
try {
callback.accept(packet);
} catch (StateChangingError error) {
throw new StateChangingException(error.state);
}
}
if (callback != null) {
try {
callback.accept(packet);
} catch (StateChangingError error) {
throw new StateChangingException(error.state);
}
}
}
private void processMessage(final Tag currentTag) throws IOException {
final MessagePacket packet = (MessagePacket) processPacket(currentTag, PACKET_MESSAGE);
if (!packet.valid()) {
final var message = processStanza(currentTag, Message.class);
if (InvalidJid.invalid(message.getTo()) || InvalidJid.invalid(message.getFrom())) {
Log.e(
Config.LOGTAG,
"encountered invalid message from='"
+ packet.getFrom()
+ "' to='"
+ packet.getTo()
+ "'");
"encountered invalid Message from "
+ message.getFrom()
+ " to "
+ message.getTo());
return;
}
this.messagePacketConsumer.accept(packet);
this.messagePacketConsumer.accept(message);
}
private void processPresence(final Tag currentTag) throws IOException {
PresencePacket packet = (PresencePacket) processPacket(currentTag, PACKET_PRESENCE);
if (!packet.valid()) {
final var presence = processStanza(currentTag, Presence.class);
if (InvalidJid.invalid(presence.getTo()) || InvalidJid.invalid(presence.getFrom())) {
Log.e(
Config.LOGTAG,
"encountered invalid presence from='"
+ packet.getFrom()
+ "' to='"
+ packet.getTo()
+ "'");
"encountered invalid Presence from "
+ presence.getFrom()
+ " to "
+ presence.getTo());
return;
}
this.presencePacketConsumer.accept(packet);
this.presencePacketConsumer.accept(presence);
}
private void sendStartTLS() throws IOException {
@ -1350,7 +1299,7 @@ public class XmppConnection implements Runnable {
Config.LOGTAG,
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.mWaitingForSmCatchup.set(true);
this.tagWriter.writeStanzaAsync(resume);
@ -1563,15 +1512,15 @@ public class XmppConnection implements Runnable {
sendRegistryRequest();
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);
sendUnmodifiedIqPacket(
preAuthRequest,
(response) -> {
if (response.getType() == IqPacket.TYPE.RESULT) {
if (response.getType() == IQ.Type.RESULT) {
sendRegistryRequest();
} else {
final String error = response.getErrorCondition();
final String error = ""; // response.getErrorCondition();
Log.d(Config.LOGTAG, account.address + ": failed to pre auth. " + error);
throw new StateChangingError(ConnectionState.REGISTRATION_INVALID_TOKEN);
}
@ -1580,32 +1529,39 @@ public class XmppConnection implements Runnable {
}
private void sendRegistryRequest() {
final IqPacket register = new IqPacket(IqPacket.TYPE.GET);
register.query(Namespace.REGISTER);
register.setTo(account.address.getDomain());
final IQ retrieveRegistration = new IQ(IQ.Type.GET);
retrieveRegistration.addExtension(new Register());
retrieveRegistration.setTo(account.address.getDomain());
sendUnmodifiedIqPacket(
register,
retrieveRegistration,
(packet) -> {
if (packet.getType() == IqPacket.TYPE.TIMEOUT) {
if (packet.getType() == IQ.Type.TIMEOUT) {
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);
}
final Element query = packet.query(Namespace.REGISTER);
if (query.hasChild("username") && (query.hasChild("password"))) {
final Credential credential =
CredentialStore.getInstance(context).get(account);
final IqPacket register1 = new IqPacket(IqPacket.TYPE.SET);
final IQ registrationRequest = new IQ(IQ.Type.SET);
final Element username =
new Element("username")
.setContent(account.address.getEscapedLocal());
final Element password =
new Element("password").setContent(credential.password);
register1.query(Namespace.REGISTER).addChild(username);
register1.query().addChild(password);
register1.setFrom(account.address);
sendUnmodifiedIqPacket(register1, this::handleRegistrationResponse, true);
final var register = registrationRequest.addExtension(new Register());
register.addChild(username);
register.addChild(password);
registrationRequest.setFrom(account.address);
sendUnmodifiedIqPacket(
registrationRequest, this::handleRegistrationResponse, true);
} else if (query.hasChild("x", Namespace.DATA)) {
final Data data = Data.parse(query.findChild("x", Namespace.DATA));
final Element blob = query.findChild("data", "urn:xmpp:bob");
@ -1667,8 +1623,8 @@ public class XmppConnection implements Runnable {
true);
}
private void handleRegistrationResponse(final IqPacket packet) {
if (packet.getType() == IqPacket.TYPE.RESULT) {
private void handleRegistrationResponse(final IQ packet) {
if (packet.getType() == IQ.Type.RESULT) {
ConversationsDatabase.getInstance(context)
.accountDao()
.setPendingRegistration(account.id, false);
@ -1716,9 +1672,6 @@ public class XmppConnection implements Runnable {
this.stanzasSent = 0;
mStanzaQueue.clear();
this.redirectionUrl = null;
synchronized (this.commands) {
this.commands.clear();
}
this.saslMechanism = null;
}
@ -1736,16 +1689,16 @@ public class XmppConnection implements Runnable {
} else {
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);
this.sendUnmodifiedIqPacket(
iq,
(packet) -> {
if (packet.getType() == IqPacket.TYPE.TIMEOUT) {
if (packet.getType() == IQ.Type.TIMEOUT) {
return;
}
final Element bind = packet.findChild("bind");
if (bind != null && packet.getType() == IqPacket.TYPE.RESULT) {
if (bind != null && packet.getType() == IQ.Type.RESULT) {
isBound = true;
final String jid = bind.findChildContent("jid");
if (Strings.isNullOrEmpty(jid)) {
@ -1789,7 +1742,7 @@ public class XmppConnection implements Runnable {
+ packet);
}
final Element error = packet.findChild("error");
if (packet.getType() == IqPacket.TYPE.ERROR
if (packet.getType() == IQ.Type.ERROR
&& error != null
&& error.hasChild("conflict")) {
final String alternativeResource = createNewResource(IDs.tiny());
@ -1813,8 +1766,8 @@ public class XmppConnection implements Runnable {
}
private void clearIqCallbacks() {
final IqPacket failurePacket = new IqPacket(IqPacket.TYPE.TIMEOUT);
final ArrayList<Consumer<IqPacket>> callbacks = new ArrayList<>();
final IQ failurePacket = new IQ(IQ.Type.TIMEOUT);
final ArrayList<Consumer<IQ>> callbacks = new ArrayList<>();
synchronized (this.packetCallbacks) {
if (this.packetCallbacks.size() == 0) {
return;
@ -1825,15 +1778,15 @@ public class XmppConnection implements Runnable {
+ ": clearing "
+ this.packetCallbacks.size()
+ " iq callbacks");
final Iterator<Pair<IqPacket, Consumer<IqPacket>>> iterator =
final Iterator<Pair<IQ, Consumer<IQ>>> iterator =
this.packetCallbacks.values().iterator();
while (iterator.hasNext()) {
Pair<IqPacket, Consumer<IqPacket>> entry = iterator.next();
Pair<IQ, Consumer<IQ>> entry = iterator.next();
callbacks.add(entry.second);
iterator.remove();
}
}
for (final Consumer<IqPacket> callback : callbacks) {
for (final Consumer<IQ> callback : callbacks) {
try {
callback.accept(failurePacket);
} catch (StateChangingError error) {
@ -1856,15 +1809,15 @@ public class XmppConnection implements Runnable {
private void sendStartSession() {
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");
this.sendUnmodifiedIqPacket(
startSession,
(packet) -> {
if (packet.getType() == IqPacket.TYPE.RESULT) {
if (packet.getType() == IQ.Type.RESULT) {
enableStreamManagement();
sendPostBindInitialization(false);
} else if (packet.getType() != IqPacket.TYPE.TIMEOUT) {
} else if (packet.getType() != IQ.Type.TIMEOUT) {
throw new StateChangingError(ConnectionState.SESSION_FAILURE);
}
},
@ -1876,7 +1829,7 @@ public class XmppConnection implements Runnable {
final boolean streamManagement = this.streamFeatures.streamManagement();
if (streamManagement) {
synchronized (this.mStanzaQueue) {
final EnablePacket enable = new EnablePacket();
final Enable enable = new Enable();
tagWriter.writeStanzaAsync(enable);
stanzasSent = 0;
mStanzaQueue.clear();
@ -1936,60 +1889,6 @@ public class XmppConnection implements Runnable {
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() {
this.enableAdvancedStreamFeatures();
this.bindConsumer.accept(this.connectionAddress);
@ -2005,12 +1904,12 @@ public class XmppConnection implements Runnable {
}
private void sendEnableCarbons() {
final IqPacket iq = new IqPacket(IqPacket.TYPE.SET);
final IQ iq = new IQ(IQ.Type.SET);
iq.addChild("enable", Namespace.CARBONS);
this.sendIqPacket(
iq,
(packet) -> {
if (packet.getType() == IqPacket.TYPE.RESULT) {
if (packet.getType() == IQ.Type.RESULT) {
Log.d(Config.LOGTAG, account.address + ": successfully enabled carbons");
this.carbonsEnabled = true;
} else {
@ -2055,9 +1954,9 @@ public class XmppConnection implements Runnable {
private void failPendingMessages(final String error) {
synchronized (this.mStanzaQueue) {
for (int i = 0; i < mStanzaQueue.size(); ++i) {
final AbstractAcknowledgeableStanza stanza = mStanzaQueue.valueAt(i);
if (stanza instanceof MessagePacket) {
final MessagePacket packet = (MessagePacket) stanza;
final Stanza stanza = mStanzaQueue.valueAt(i);
if (stanza instanceof Message) {
final Message packet = (Message) stanza;
final String id = packet.getId();
final Jid to = packet.getTo();
// 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);
}
public ListenableFuture<IqPacket> sendIqPacket(final IqPacket packet) {
final SettableFuture<IqPacket> future = SettableFuture.create();
public ListenableFuture<IQ> sendIqPacket(final IQ packet) {
final SettableFuture<IQ> future = SettableFuture.create();
sendIqPacket(
packet,
result -> {
final var type = result.getType();
if (type == IqPacket.TYPE.RESULT) {
if (type == IQ.Type.RESULT) {
future.set(result);
} else if (type == IqPacket.TYPE.TIMEOUT) {
} else if (type == IQ.Type.TIMEOUT) {
future.setException(new TimeoutException());
} else {
// TODO some sort of IqErrorException
@ -2141,15 +2040,15 @@ public class XmppConnection implements Runnable {
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);
return this.sendUnmodifiedIqPacket(packet, callback, false);
}
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())) {
packet.setAttribute("id", IDs.medium());
packet.setId(IDs.medium());
}
if (callback != null) {
synchronized (this.packetCallbacks) {
@ -2160,19 +2059,19 @@ public class XmppConnection implements Runnable {
return packet.getId();
}
public void sendMessagePacket(final MessagePacket packet) {
public void sendMessagePacket(final Message packet) {
this.sendPacket(packet);
}
public void sendPresencePacket(final PresencePacket packet) {
public void sendPresencePacket(final Presence packet) {
this.sendPacket(packet);
}
private synchronized void sendPacket(final AbstractStanza packet) {
private synchronized void sendPacket(final StreamElement packet) {
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) {
resetStreamId();
disconnect(true);
@ -2188,8 +2087,8 @@ public class XmppConnection implements Runnable {
+ " do not write stanza to unbound stream "
+ packet.toString());
}
if (packet instanceof AbstractAcknowledgeableStanza) {
AbstractAcknowledgeableStanza stanza = (AbstractAcknowledgeableStanza) packet;
if (packet instanceof Stanza) {
final Stanza stanza = (Stanza) packet;
if (this.mStanzaQueue.size() != 0) {
int currentHighestKey = this.mStanzaQueue.keyAt(this.mStanzaQueue.size() - 1);
@ -2209,7 +2108,7 @@ public class XmppConnection implements Runnable {
+ stanzasSent);
}
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) {
Log.d(
Config.LOGTAG,
@ -2217,7 +2116,7 @@ public class XmppConnection implements Runnable {
+ ": requesting ack for message stanza #"
+ stanzasSent);
}
tagWriter.writeStanzaAsync(new RequestPacket());
tagWriter.writeStanzaAsync(new Request());
}
}
}
@ -2225,7 +2124,7 @@ public class XmppConnection implements Runnable {
public void sendPing() {
if (!r()) {
final IqPacket iq = new IqPacket(IqPacket.TYPE.GET);
final IQ iq = new IQ(IQ.Type.GET);
iq.setFrom(account.address);
iq.addChild("ping", Namespace.PING);
this.sendIqPacket(iq, null);
@ -2308,7 +2207,7 @@ public class XmppConnection implements Runnable {
public boolean r() {
if (this.inSmacksSession) {
this.tagWriter.writeStanzaAsync(new RequestPacket());
this.tagWriter.writeStanzaAsync(new Request());
return true;
} else {
return false;
@ -2346,11 +2245,11 @@ public class XmppConnection implements Runnable {
}
public void sendActive() {
this.sendPacket(new ActivePacket());
this.sendPacket(new Active());
}
public void sendInactive() {
this.sendPacket(new InactivePacket());
this.sendPacket(new Inactive());
}
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();
return from == null
|| from.equals(connectionAddress.getDomain())
@ -2368,7 +2267,7 @@ public class XmppConnection implements Runnable {
|| from.equals(connectionAddress);
}
public boolean toServer(final AbstractStanza stanza) {
public boolean toServer(final Stanza stanza) {
final Jid to = stanza.getTo();
return to == null
|| to.equals(connectionAddress.getDomain())
@ -2376,7 +2275,7 @@ public class XmppConnection implements Runnable {
|| to.equals(connectionAddress);
}
public boolean fromAccount(final AbstractStanza stanza) {
public boolean fromAccount(final Stanza stanza) {
final Jid from = stanza.getFrom();
return from != null && from.asBareJid().equals(connectionAddress.asBareJid());
}

View file

@ -2,11 +2,11 @@ package im.conversations.android.xmpp.manager;
import android.content.Context;
import com.google.common.collect.Collections2;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.model.blocking.Block;
import im.conversations.android.xmpp.model.blocking.Blocklist;
import im.conversations.android.xmpp.model.blocking.Unblock;
import im.conversations.android.xmpp.model.stanza.IQ;
import java.util.Objects;
public class BlockingManager extends AbstractManager {
@ -20,13 +20,13 @@ public class BlockingManager extends AbstractManager {
public void handlePush(final Unblock unblock) {}
public void fetch() {
final IqPacket iqPacket = new IqPacket(IqPacket.TYPE.GET);
final IQ iqPacket = new IQ(IQ.Type.GET);
iqPacket.addChild(new Blocklist());
connection.sendIqPacket(iqPacket, this::handleFetchResult);
}
private void handleFetchResult(final IqPacket result) {
if (result.getType() != IqPacket.TYPE.RESULT) {
private void handleFetchResult(final IQ result) {
if (result.getType() != IQ.Type.RESULT) {
return;
}
final var blocklist = result.getExtension(Blocklist.class);

View file

@ -10,7 +10,6 @@ import com.google.common.util.concurrent.Futures;
import com.google.common.util.concurrent.ListenableFuture;
import com.google.common.util.concurrent.MoreExecutors;
import eu.siacs.conversations.xmpp.Jid;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import im.conversations.android.xmpp.Entity;
import im.conversations.android.xmpp.EntityCapabilities;
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.items.Item;
import im.conversations.android.xmpp.model.disco.items.ItemsQuery;
import im.conversations.android.xmpp.model.stanza.IQ;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
@ -52,7 +52,7 @@ public class DiscoManager extends AbstractManager {
@Nullable final String node,
@Nullable final EntityCapabilities.Hash hash) {
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);
final InfoQuery infoQueryRequest = iqRequest.addExtension(new InfoQuery());
if (requestNode != null) {
@ -114,7 +114,7 @@ public class DiscoManager extends AbstractManager {
public ListenableFuture<Collection<Item>> items(
@NonNull final Entity.DiscoItem entity, @Nullable final String 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);
final ItemsQuery itemsQueryRequest = iqPacket.addExtension(new ItemsQuery());
if (requestNode != null) {

View file

@ -5,10 +5,10 @@ import android.util.Log;
import com.google.common.base.Strings;
import com.google.common.collect.Collections2;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.model.roster.Item;
import im.conversations.android.xmpp.model.roster.Query;
import im.conversations.android.xmpp.model.stanza.IQ;
import java.util.Objects;
public class RosterManager extends AbstractManager {
@ -27,7 +27,7 @@ public class RosterManager extends AbstractManager {
final var account = getAccount();
final var database = getDatabase();
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();
iqPacket.addChild(rosterQuery);
if (Strings.isNullOrEmpty(rosterVersion)) {
@ -39,8 +39,8 @@ public class RosterManager extends AbstractManager {
connection.sendIqPacket(iqPacket, this::handleFetchResult);
}
private void handleFetchResult(final IqPacket result) {
if (result.getType() != IqPacket.TYPE.RESULT) {
private void handleFetchResult(final IQ result) {
if (result.getType() != IQ.Type.RESULT) {
return;
}
final var query = result.getExtension(Query.class);

View file

@ -0,0 +1,8 @@
package im.conversations.android.xmpp.model;
public abstract class StreamElement extends Extension {
protected StreamElement(Class<? extends Extension> clazz) {
super(clazz);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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);
}
}

View file

@ -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");
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;

View file

@ -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));
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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);
}
}

View file

@ -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;

View file

@ -2,40 +2,39 @@ package im.conversations.android.xmpp.processor;
import android.content.Context;
import com.google.common.base.Preconditions;
import eu.siacs.conversations.xmpp.stanzas.IqPacket;
import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.manager.BlockingManager;
import im.conversations.android.xmpp.manager.RosterManager;
import im.conversations.android.xmpp.model.blocking.Block;
import im.conversations.android.xmpp.model.blocking.Unblock;
import im.conversations.android.xmpp.model.roster.Query;
import im.conversations.android.xmpp.model.stanza.IQ;
import java.util.Arrays;
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) {
super(context, connection);
}
@Override
public void accept(final IqPacket packet) {
final IqPacket.TYPE type = packet.getType();
Preconditions.checkArgument(
Arrays.asList(IqPacket.TYPE.GET, IqPacket.TYPE.SET).contains(type));
if (type == IqPacket.TYPE.SET
public void accept(final IQ packet) {
final IQ.Type type = packet.getType();
Preconditions.checkArgument(Arrays.asList(IQ.Type.GET, IQ.Type.SET).contains(type));
if (type == IQ.Type.SET
&& connection.fromAccount(packet)
&& packet.hasExtension(Query.class)) {
getManager(RosterManager.class).handlePush(packet.getExtension(Query.class));
return;
}
if (type == IqPacket.TYPE.SET
if (type == IQ.Type.SET
&& connection.fromAccount(packet)
&& packet.hasExtension(Block.class)) {
getManager(BlockingManager.class).handlePush(packet.getExtension(Block.class));
return;
}
if (type == IqPacket.TYPE.SET
if (type == IQ.Type.SET
&& connection.fromAccount(packet)
&& packet.hasExtension(Unblock.class)) {
getManager(BlockingManager.class).handlePush(packet.getExtension(Unblock.class));

View file

@ -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) {}
}

View file

@ -1,14 +1,14 @@
package im.conversations.android.xmpp.processor;
import android.content.Context;
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.model.stanza.Message;
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) {}
@Override
public void accept(final MessagePacket messagePacket) {}
public void accept(final Message messagePacket) {}
}

View file

@ -1,22 +1,22 @@
package im.conversations.android.xmpp.processor;
import android.content.Context;
import eu.siacs.conversations.xmpp.stanzas.PresencePacket;
import im.conversations.android.database.model.PresenceShow;
import im.conversations.android.database.model.PresenceType;
import im.conversations.android.xmpp.Entity;
import im.conversations.android.xmpp.XmppConnection;
import im.conversations.android.xmpp.manager.DiscoManager;
import im.conversations.android.xmpp.model.stanza.Presence;
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) {
super(context, connection);
}
@Override
public void accept(final PresencePacket presencePacket) {
public void accept(final Presence presencePacket) {
final var from = presencePacket.getFrom();
final var address = from == null ? null : from.asBareJid();
final var resource = from == null ? null : from.getResource();
@ -38,7 +38,7 @@ public class PresenceProcessor extends XmppConnection.Delegate implements Consum
fetchCapabilities(presencePacket);
}
private void fetchCapabilities(final PresencePacket presencePacket) {
private void fetchCapabilities(final Presence presencePacket) {
final var entity = presencePacket.getFrom();
final var nodeHash = presencePacket.getCapabilities();
if (nodeHash != null) {