add models for Error conditions
This commit is contained in:
parent
ddcab5fb58
commit
9a855a57ac
|
@ -1,6 +1,7 @@
|
||||||
package im.conversations.android.annotation.processor;
|
package im.conversations.android.annotation.processor;
|
||||||
|
|
||||||
import com.google.auto.service.AutoService;
|
import com.google.auto.service.AutoService;
|
||||||
|
import com.google.common.base.CaseFormat;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
@ -8,7 +9,6 @@ import im.conversations.android.annotation.XmlElement;
|
||||||
import im.conversations.android.annotation.XmlPackage;
|
import im.conversations.android.annotation.XmlPackage;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.PrintWriter;
|
import java.io.PrintWriter;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import javax.annotation.processing.AbstractProcessor;
|
import javax.annotation.processing.AbstractProcessor;
|
||||||
|
@ -88,8 +88,9 @@ public class XmlElementProcessor extends AbstractProcessor {
|
||||||
|
|
||||||
private static Id of(final TypeElement typeElement) {
|
private static Id of(final TypeElement typeElement) {
|
||||||
final XmlElement xmlElement = typeElement.getAnnotation(XmlElement.class);
|
final XmlElement xmlElement = typeElement.getAnnotation(XmlElement.class);
|
||||||
PackageElement packageElement = (PackageElement) typeElement.getEnclosingElement();
|
PackageElement packageElement = getPackageElement(typeElement);
|
||||||
XmlPackage xmlPackage = packageElement.getAnnotation(XmlPackage.class);
|
XmlPackage xmlPackage =
|
||||||
|
packageElement == null ? null : packageElement.getAnnotation(XmlPackage.class);
|
||||||
if (xmlElement == null) {
|
if (xmlElement == null) {
|
||||||
throw new IllegalStateException(
|
throw new IllegalStateException(
|
||||||
String.format(
|
String.format(
|
||||||
|
@ -112,13 +113,29 @@ public class XmlElementProcessor extends AbstractProcessor {
|
||||||
}
|
}
|
||||||
final String name;
|
final String name;
|
||||||
if (Strings.isNullOrEmpty(elementName)) {
|
if (Strings.isNullOrEmpty(elementName)) {
|
||||||
name = typeElement.getSimpleName().toString().toLowerCase(Locale.ROOT);
|
name =
|
||||||
|
CaseFormat.UPPER_CAMEL.to(
|
||||||
|
CaseFormat.LOWER_HYPHEN, typeElement.getSimpleName().toString());
|
||||||
} else {
|
} else {
|
||||||
name = elementName;
|
name = elementName;
|
||||||
}
|
}
|
||||||
return new Id(name, namespace);
|
return new Id(name, namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static PackageElement getPackageElement(final TypeElement typeElement) {
|
||||||
|
final Element parent = typeElement.getEnclosingElement();
|
||||||
|
if (parent instanceof PackageElement) {
|
||||||
|
return (PackageElement) parent;
|
||||||
|
} else {
|
||||||
|
final Element nextParent = parent.getEnclosingElement();
|
||||||
|
if (nextParent instanceof PackageElement) {
|
||||||
|
return (PackageElement) nextParent;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static class Id {
|
public static class Id {
|
||||||
public final String name;
|
public final String name;
|
||||||
public final String namespace;
|
public final String namespace;
|
||||||
|
|
|
@ -9,6 +9,7 @@ import eu.siacs.conversations.utils.XmlHelper;
|
||||||
import eu.siacs.conversations.xmpp.InvalidJid;
|
import eu.siacs.conversations.xmpp.InvalidJid;
|
||||||
import eu.siacs.conversations.xmpp.Jid;
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
import eu.siacs.conversations.xmpp.stanzas.MessagePacket;
|
||||||
|
import im.conversations.android.xmpp.ExtensionFactory;
|
||||||
import im.conversations.android.xmpp.model.Extension;
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -89,6 +90,11 @@ public class Element {
|
||||||
Collections2.filter(this.children, clazz::isInstance), clazz::cast);
|
Collections2.filter(this.children, clazz::isInstance), clazz::cast);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Collection<ExtensionFactory.Id> getExtensionIds() {
|
||||||
|
return Collections2.transform(
|
||||||
|
this.children, c -> new ExtensionFactory.Id(c.getName(), c.getNamespace()));
|
||||||
|
}
|
||||||
|
|
||||||
public String findChildContent(String name) {
|
public String findChildContent(String name) {
|
||||||
Element element = findChild(name);
|
Element element = findChild(name);
|
||||||
return element == null ? null : element.getContent();
|
return element == null ? null : element.getContent();
|
||||||
|
|
|
@ -80,4 +80,6 @@ public final class Namespace {
|
||||||
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";
|
public static final String JABBER_CLIENT = "jabber:client";
|
||||||
public static final String FORWARD = "urn:xmpp:forward:0";
|
public static final String FORWARD = "urn:xmpp:forward:0";
|
||||||
|
|
||||||
|
public static final String STANZAS = "urn:ietf:params:xml:ns:xmpp-stanzas";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
package eu.siacs.conversations.xml;
|
package eu.siacs.conversations.xml;
|
||||||
|
|
||||||
import com.google.common.io.ByteSource;
|
import com.google.common.io.ByteSource;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
|
||||||
|
@ -11,10 +10,10 @@ public class XmlElementReader {
|
||||||
return read(ByteSource.wrap(bytes).openStream());
|
return read(ByteSource.wrap(bytes).openStream());
|
||||||
}
|
}
|
||||||
|
|
||||||
public static Element read(InputStream inputStream) throws IOException {
|
public static Element read(final InputStream inputStream) throws IOException {
|
||||||
final XmlReader xmlReader = new XmlReader();
|
try (final XmlReader xmlReader = new XmlReader()) {
|
||||||
xmlReader.setInputStream(inputStream);
|
xmlReader.setInputStream(inputStream);
|
||||||
return xmlReader.readElement(xmlReader.readTag());
|
return xmlReader.readElement(xmlReader.readTag());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package im.conversations.android.xmpp;
|
package im.conversations.android.xmpp;
|
||||||
|
|
||||||
|
import com.google.common.base.MoreObjects;
|
||||||
import com.google.common.base.Objects;
|
import com.google.common.base.Objects;
|
||||||
import eu.siacs.conversations.xml.Element;
|
import eu.siacs.conversations.xml.Element;
|
||||||
import im.conversations.android.xmpp.model.Extension;
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
@ -61,5 +62,13 @@ public final class ExtensionFactory {
|
||||||
public int hashCode() {
|
public int hashCode() {
|
||||||
return Objects.hashCode(name, namespace);
|
return Objects.hashCode(name, namespace);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return MoreObjects.toStringHelper(this)
|
||||||
|
.add("name", name)
|
||||||
|
.add("namespace", namespace)
|
||||||
|
.toString();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -60,12 +60,13 @@ import im.conversations.android.xmpp.manager.DiscoManager;
|
||||||
import im.conversations.android.xmpp.model.StreamElement;
|
import im.conversations.android.xmpp.model.StreamElement;
|
||||||
import im.conversations.android.xmpp.model.csi.Active;
|
import im.conversations.android.xmpp.model.csi.Active;
|
||||||
import im.conversations.android.xmpp.model.csi.Inactive;
|
import im.conversations.android.xmpp.model.csi.Inactive;
|
||||||
|
import im.conversations.android.xmpp.model.ping.Ping;
|
||||||
import im.conversations.android.xmpp.model.register.Register;
|
import im.conversations.android.xmpp.model.register.Register;
|
||||||
import im.conversations.android.xmpp.model.sm.Ack;
|
import im.conversations.android.xmpp.model.sm.Ack;
|
||||||
import im.conversations.android.xmpp.model.sm.Enable;
|
import im.conversations.android.xmpp.model.sm.Enable;
|
||||||
import im.conversations.android.xmpp.model.sm.Request;
|
import im.conversations.android.xmpp.model.sm.Request;
|
||||||
import im.conversations.android.xmpp.model.sm.Resume;
|
import im.conversations.android.xmpp.model.sm.Resume;
|
||||||
import im.conversations.android.xmpp.model.stanza.IQ;
|
import im.conversations.android.xmpp.model.stanza.Iq;
|
||||||
import im.conversations.android.xmpp.model.stanza.Message;
|
import im.conversations.android.xmpp.model.stanza.Message;
|
||||||
import im.conversations.android.xmpp.model.stanza.Presence;
|
import im.conversations.android.xmpp.model.stanza.Presence;
|
||||||
import im.conversations.android.xmpp.model.stanza.Stanza;
|
import im.conversations.android.xmpp.model.stanza.Stanza;
|
||||||
|
@ -120,7 +121,7 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
protected final Account account;
|
protected final Account account;
|
||||||
private final SparseArray<Stanza> mStanzaQueue = new SparseArray<>();
|
private final SparseArray<Stanza> mStanzaQueue = new SparseArray<>();
|
||||||
private final Hashtable<String, Pair<IQ, Consumer<IQ>>> packetCallbacks = new Hashtable<>();
|
private final Hashtable<String, Pair<Iq, Consumer<Iq>>> packetCallbacks = new Hashtable<>();
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private Socket socket;
|
private Socket socket;
|
||||||
private XmlReader tagReader;
|
private XmlReader tagReader;
|
||||||
|
@ -147,7 +148,7 @@ public class XmppConnection implements Runnable {
|
||||||
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<Presence> presencePacketConsumer;
|
private final Consumer<Presence> presencePacketConsumer;
|
||||||
private final Consumer<IQ> iqPacketConsumer;
|
private final Consumer<Iq> iqPacketConsumer;
|
||||||
private final Consumer<Message> messagePacketConsumer;
|
private final Consumer<Message> 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;
|
||||||
|
@ -1088,16 +1089,16 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processIq(final Tag currentTag) throws IOException {
|
private void processIq(final Tag currentTag) throws IOException {
|
||||||
final IQ packet = processStanza(currentTag, IQ.class);
|
final Iq packet = processStanza(currentTag, Iq.class);
|
||||||
if (InvalidJid.invalid(packet.getTo()) || InvalidJid.invalid(packet.getFrom())) {
|
if (InvalidJid.invalid(packet.getTo()) || InvalidJid.invalid(packet.getFrom())) {
|
||||||
Log.e(
|
Log.e(
|
||||||
Config.LOGTAG,
|
Config.LOGTAG,
|
||||||
"encountered invalid IQ from " + packet.getFrom() + " to " + packet.getTo());
|
"encountered invalid IQ from " + packet.getFrom() + " to " + packet.getTo());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final Consumer<IQ> callback;
|
final Consumer<Iq> callback;
|
||||||
synchronized (this.packetCallbacks) {
|
synchronized (this.packetCallbacks) {
|
||||||
final Pair<IQ, Consumer<IQ>> packetCallbackDuple = packetCallbacks.get(packet.getId());
|
final Pair<Iq, Consumer<Iq>> packetCallbackDuple = 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)) {
|
||||||
|
@ -1118,7 +1119,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() == IQ.Type.GET || packet.getType() == IQ.Type.SET) {
|
} else if (packet.getType() == Iq.Type.GET || packet.getType() == Iq.Type.SET) {
|
||||||
callback = this.iqPacketConsumer;
|
callback = this.iqPacketConsumer;
|
||||||
} else {
|
} else {
|
||||||
callback = null;
|
callback = null;
|
||||||
|
@ -1510,12 +1511,12 @@ public class XmppConnection implements Runnable {
|
||||||
sendRegistryRequest();
|
sendRegistryRequest();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final IQ preAuthRequest = new IQ(IQ.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() == IQ.Type.RESULT) {
|
if (response.getType() == Iq.Type.RESULT) {
|
||||||
sendRegistryRequest();
|
sendRegistryRequest();
|
||||||
} else {
|
} else {
|
||||||
final String error = ""; // response.getErrorCondition();
|
final String error = ""; // response.getErrorCondition();
|
||||||
|
@ -1527,16 +1528,16 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void sendRegistryRequest() {
|
private void sendRegistryRequest() {
|
||||||
final IQ retrieveRegistration = new IQ(IQ.Type.GET);
|
final Iq retrieveRegistration = new Iq(Iq.Type.GET);
|
||||||
retrieveRegistration.addExtension(new Register());
|
retrieveRegistration.addExtension(new Register());
|
||||||
retrieveRegistration.setTo(account.address.getDomain());
|
retrieveRegistration.setTo(account.address.getDomain());
|
||||||
sendUnmodifiedIqPacket(
|
sendUnmodifiedIqPacket(
|
||||||
retrieveRegistration,
|
retrieveRegistration,
|
||||||
(packet) -> {
|
(packet) -> {
|
||||||
if (packet.getType() == IQ.Type.TIMEOUT) {
|
if (packet.getType() == Iq.Type.TIMEOUT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (packet.getType() == IQ.Type.ERROR) {
|
if (packet.getType() == Iq.Type.ERROR) {
|
||||||
throw new StateChangingError(ConnectionState.REGISTRATION_FAILED);
|
throw new StateChangingError(ConnectionState.REGISTRATION_FAILED);
|
||||||
}
|
}
|
||||||
final Register query = packet.getExtension(Register.class);
|
final Register query = packet.getExtension(Register.class);
|
||||||
|
@ -1546,7 +1547,7 @@ public class XmppConnection implements Runnable {
|
||||||
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 IQ registrationRequest = new IQ(IQ.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());
|
||||||
|
@ -1621,8 +1622,8 @@ public class XmppConnection implements Runnable {
|
||||||
true);
|
true);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleRegistrationResponse(final IQ packet) {
|
private void handleRegistrationResponse(final Iq packet) {
|
||||||
if (packet.getType() == IQ.Type.RESULT) {
|
if (packet.getType() == Iq.Type.RESULT) {
|
||||||
ConversationsDatabase.getInstance(context)
|
ConversationsDatabase.getInstance(context)
|
||||||
.accountDao()
|
.accountDao()
|
||||||
.setPendingRegistration(account.id, false);
|
.setPendingRegistration(account.id, false);
|
||||||
|
@ -1687,16 +1688,16 @@ public class XmppConnection implements Runnable {
|
||||||
} else {
|
} else {
|
||||||
resource = this.createNewResource(IDs.tiny(account.randomSeed));
|
resource = this.createNewResource(IDs.tiny(account.randomSeed));
|
||||||
}
|
}
|
||||||
final IQ iq = new IQ(IQ.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() == IQ.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() == IQ.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)) {
|
||||||
|
@ -1740,7 +1741,7 @@ public class XmppConnection implements Runnable {
|
||||||
+ packet);
|
+ packet);
|
||||||
}
|
}
|
||||||
final Element error = packet.findChild("error");
|
final Element error = packet.findChild("error");
|
||||||
if (packet.getType() == IQ.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());
|
||||||
|
@ -1764,8 +1765,8 @@ public class XmppConnection implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void clearIqCallbacks() {
|
private void clearIqCallbacks() {
|
||||||
final IQ failurePacket = new IQ(IQ.Type.TIMEOUT);
|
final Iq failurePacket = new Iq(Iq.Type.TIMEOUT);
|
||||||
final ArrayList<Consumer<IQ>> 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;
|
||||||
|
@ -1776,15 +1777,15 @@ public class XmppConnection implements Runnable {
|
||||||
+ ": clearing "
|
+ ": clearing "
|
||||||
+ this.packetCallbacks.size()
|
+ this.packetCallbacks.size()
|
||||||
+ " iq callbacks");
|
+ " iq callbacks");
|
||||||
final Iterator<Pair<IQ, Consumer<IQ>>> iterator =
|
final Iterator<Pair<Iq, Consumer<Iq>>> iterator =
|
||||||
this.packetCallbacks.values().iterator();
|
this.packetCallbacks.values().iterator();
|
||||||
while (iterator.hasNext()) {
|
while (iterator.hasNext()) {
|
||||||
Pair<IQ, Consumer<IQ>> 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<IQ> callback : callbacks) {
|
for (final Consumer<Iq> callback : callbacks) {
|
||||||
try {
|
try {
|
||||||
callback.accept(failurePacket);
|
callback.accept(failurePacket);
|
||||||
} catch (StateChangingError error) {
|
} catch (StateChangingError error) {
|
||||||
|
@ -1807,15 +1808,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 IQ startSession = new IQ(IQ.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() == IQ.Type.RESULT) {
|
if (packet.getType() == Iq.Type.RESULT) {
|
||||||
enableStreamManagement();
|
enableStreamManagement();
|
||||||
sendPostBindInitialization(false);
|
sendPostBindInitialization(false);
|
||||||
} else if (packet.getType() != IQ.Type.TIMEOUT) {
|
} else if (packet.getType() != Iq.Type.TIMEOUT) {
|
||||||
throw new StateChangingError(ConnectionState.SESSION_FAILURE);
|
throw new StateChangingError(ConnectionState.SESSION_FAILURE);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -2004,15 +2005,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<IQ> sendIqPacket(final IQ packet) {
|
public ListenableFuture<Iq> sendIqPacket(final Iq packet) {
|
||||||
final SettableFuture<IQ> 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 == IQ.Type.RESULT) {
|
if (type == Iq.Type.RESULT) {
|
||||||
future.set(result);
|
future.set(result);
|
||||||
} else if (type == IQ.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
|
||||||
|
@ -2022,13 +2023,13 @@ public class XmppConnection implements Runnable {
|
||||||
return future;
|
return future;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String sendIqPacket(final IQ packet, final Consumer<IQ> 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 IQ packet, final Consumer<IQ> callback, boolean force) {
|
final Iq packet, final Consumer<Iq> callback, boolean force) {
|
||||||
if (Strings.isNullOrEmpty(packet.getId())) {
|
if (Strings.isNullOrEmpty(packet.getId())) {
|
||||||
packet.setId(IDs.medium());
|
packet.setId(IDs.medium());
|
||||||
}
|
}
|
||||||
|
@ -2106,9 +2107,9 @@ public class XmppConnection implements Runnable {
|
||||||
|
|
||||||
public void sendPing() {
|
public void sendPing() {
|
||||||
if (!r()) {
|
if (!r()) {
|
||||||
final IQ iq = new IQ(IQ.Type.GET);
|
final Iq iq = new Iq(Iq.Type.GET);
|
||||||
iq.setFrom(account.address);
|
iq.setFrom(account.address);
|
||||||
iq.addChild("ping", Namespace.PING);
|
iq.addExtension(new Ping());
|
||||||
this.sendIqPacket(iq, null);
|
this.sendIqPacket(iq, null);
|
||||||
}
|
}
|
||||||
this.lastPingSent = SystemClock.elapsedRealtime();
|
this.lastPingSent = SystemClock.elapsedRealtime();
|
||||||
|
|
|
@ -7,7 +7,7 @@ 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.Item;
|
import im.conversations.android.xmpp.model.blocking.Item;
|
||||||
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 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 {
|
||||||
|
@ -38,13 +38,13 @@ public class BlockingManager extends AbstractManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void fetch() {
|
public void fetch() {
|
||||||
final IQ iqPacket = new IQ(IQ.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 IQ result) {
|
private void handleFetchResult(final Iq result) {
|
||||||
if (result.getType() != IQ.Type.RESULT) {
|
if (result.getType() != Iq.Type.RESULT) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final var blocklist = result.getExtension(Blocklist.class);
|
final var blocklist = result.getExtension(Blocklist.class);
|
||||||
|
|
|
@ -5,7 +5,7 @@ import im.conversations.android.xmpp.XmppConnection;
|
||||||
import im.conversations.android.xmpp.model.carbons.Enable;
|
import im.conversations.android.xmpp.model.carbons.Enable;
|
||||||
import im.conversations.android.xmpp.model.carbons.Received;
|
import im.conversations.android.xmpp.model.carbons.Received;
|
||||||
import im.conversations.android.xmpp.model.carbons.Sent;
|
import im.conversations.android.xmpp.model.carbons.Sent;
|
||||||
import im.conversations.android.xmpp.model.stanza.IQ;
|
import im.conversations.android.xmpp.model.stanza.Iq;
|
||||||
import im.conversations.android.xmpp.processor.MessageProcessor;
|
import im.conversations.android.xmpp.processor.MessageProcessor;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -24,12 +24,12 @@ public class CarbonsManager extends AbstractManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void enable() {
|
public void enable() {
|
||||||
final var iq = new IQ(IQ.Type.SET);
|
final var iq = new Iq(Iq.Type.SET);
|
||||||
iq.addExtension(new Enable());
|
iq.addExtension(new Enable());
|
||||||
connection.sendIqPacket(
|
connection.sendIqPacket(
|
||||||
iq,
|
iq,
|
||||||
result -> {
|
result -> {
|
||||||
if (result.getType() == IQ.Type.RESULT) {
|
if (result.getType() == Iq.Type.RESULT) {
|
||||||
LOGGER.info("{}: successfully enabled carbons", getAccount().address);
|
LOGGER.info("{}: successfully enabled carbons", getAccount().address);
|
||||||
this.enabled = true;
|
this.enabled = true;
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -17,7 +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 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 IQ(IQ.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 IQ(IQ.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) {
|
||||||
|
|
|
@ -6,7 +6,7 @@ import com.google.common.collect.Collections2;
|
||||||
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 im.conversations.android.xmpp.model.stanza.Iq;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
@ -29,7 +29,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 IQ iqPacket = new IQ(IQ.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)) {
|
||||||
|
@ -41,8 +41,8 @@ public class RosterManager extends AbstractManager {
|
||||||
connection.sendIqPacket(iqPacket, this::handleFetchResult);
|
connection.sendIqPacket(iqPacket, this::handleFetchResult);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleFetchResult(final IQ result) {
|
private void handleFetchResult(final Iq result) {
|
||||||
if (result.getType() != IQ.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,188 @@
|
||||||
|
package im.conversations.android.xmpp.model.error;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
|
||||||
|
public abstract class Condition extends Extension {
|
||||||
|
|
||||||
|
public Condition(Class<? extends Extension> clazz) {
|
||||||
|
super(clazz);
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class BadRequest extends Condition {
|
||||||
|
|
||||||
|
public BadRequest() {
|
||||||
|
super(BadRequest.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class Conflict extends Condition {
|
||||||
|
|
||||||
|
public Conflict() {
|
||||||
|
super(Conflict.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class FeatureNotImplemented extends Condition {
|
||||||
|
|
||||||
|
public FeatureNotImplemented() {
|
||||||
|
super(FeatureNotImplemented.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class Forbidden extends Condition {
|
||||||
|
|
||||||
|
public Forbidden() {
|
||||||
|
super(Forbidden.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class Gone extends Condition {
|
||||||
|
|
||||||
|
public Gone() {
|
||||||
|
super(Gone.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class InternalServerError extends Condition {
|
||||||
|
|
||||||
|
public InternalServerError() {
|
||||||
|
super(InternalServerError.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class ItemNotFound extends Condition {
|
||||||
|
|
||||||
|
public ItemNotFound() {
|
||||||
|
super(ItemNotFound.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class JidMalformed extends Condition {
|
||||||
|
|
||||||
|
public JidMalformed() {
|
||||||
|
super(JidMalformed.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class NotAcceptable extends Condition {
|
||||||
|
|
||||||
|
public NotAcceptable() {
|
||||||
|
super(NotAcceptable.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class NotAllowed extends Condition {
|
||||||
|
|
||||||
|
public NotAllowed() {
|
||||||
|
super(NotAllowed.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class NotAuthorized extends Condition {
|
||||||
|
|
||||||
|
public NotAuthorized() {
|
||||||
|
super(NotAuthorized.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class PaymentRequired extends Condition {
|
||||||
|
|
||||||
|
public PaymentRequired() {
|
||||||
|
super(PaymentRequired.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class RecipientUnavailable extends Condition {
|
||||||
|
|
||||||
|
public RecipientUnavailable() {
|
||||||
|
super(RecipientUnavailable.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class Redirect extends Condition {
|
||||||
|
|
||||||
|
public Redirect() {
|
||||||
|
super(Redirect.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class RegistrationRequired extends Condition {
|
||||||
|
|
||||||
|
public RegistrationRequired() {
|
||||||
|
super(RegistrationRequired.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class RemoteServerNotFound extends Condition {
|
||||||
|
|
||||||
|
public RemoteServerNotFound() {
|
||||||
|
super(RemoteServerNotFound.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class RemoteServerTimeout extends Condition {
|
||||||
|
|
||||||
|
public RemoteServerTimeout() {
|
||||||
|
super(RemoteServerTimeout.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class ResourceConstraint extends Condition {
|
||||||
|
|
||||||
|
public ResourceConstraint() {
|
||||||
|
super(ResourceConstraint.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class ServiceUnavailable extends Condition {
|
||||||
|
|
||||||
|
public ServiceUnavailable() {
|
||||||
|
super(ServiceUnavailable.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class SubscriptionRequired extends Condition {
|
||||||
|
|
||||||
|
public SubscriptionRequired() {
|
||||||
|
super(SubscriptionRequired.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class UndefinedCondition extends Condition {
|
||||||
|
|
||||||
|
public UndefinedCondition() {
|
||||||
|
super(UndefinedCondition.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.STANZAS)
|
||||||
|
public static class UnexpectedRequest extends Condition {
|
||||||
|
|
||||||
|
public UnexpectedRequest() {
|
||||||
|
super(UnexpectedRequest.class);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,21 @@
|
||||||
|
package im.conversations.android.xmpp.model.error;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.JABBER_CLIENT)
|
||||||
|
public class Error extends Extension {
|
||||||
|
|
||||||
|
public Error() {
|
||||||
|
super(Error.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Condition getCondition() {
|
||||||
|
return this.getExtension(Condition.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setCondition(final Condition condition) {
|
||||||
|
this.addExtension(condition);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
package im.conversations.android.xmpp.model.ping;
|
||||||
|
|
||||||
|
import eu.siacs.conversations.xml.Namespace;
|
||||||
|
import im.conversations.android.annotation.XmlElement;
|
||||||
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
|
|
||||||
|
@XmlElement(namespace = Namespace.PING)
|
||||||
|
public class Ping extends Extension {
|
||||||
|
|
||||||
|
public Ping() {
|
||||||
|
super(Ping.class);
|
||||||
|
}
|
||||||
|
}
|
|
@ -5,14 +5,14 @@ import im.conversations.android.annotation.XmlElement;
|
||||||
import java.util.Locale;
|
import java.util.Locale;
|
||||||
|
|
||||||
@XmlElement
|
@XmlElement
|
||||||
public class IQ extends Stanza {
|
public class Iq extends Stanza {
|
||||||
|
|
||||||
public IQ() {
|
public Iq() {
|
||||||
super(IQ.class);
|
super(Iq.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
public IQ(final Type type) {
|
public Iq(final Type type) {
|
||||||
super(IQ.class);
|
super(Iq.class);
|
||||||
this.setAttribute("type", type.toString().toLowerCase(Locale.ROOT));
|
this.setAttribute("type", type.toString().toLowerCase(Locale.ROOT));
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package im.conversations.android.xmpp.model.stanza;
|
||||||
import eu.siacs.conversations.xmpp.Jid;
|
import eu.siacs.conversations.xmpp.Jid;
|
||||||
import im.conversations.android.xmpp.model.Extension;
|
import im.conversations.android.xmpp.model.Extension;
|
||||||
import im.conversations.android.xmpp.model.StreamElement;
|
import im.conversations.android.xmpp.model.StreamElement;
|
||||||
|
import im.conversations.android.xmpp.model.error.Error;
|
||||||
|
|
||||||
public abstract class Stanza extends StreamElement {
|
public abstract class Stanza extends StreamElement {
|
||||||
|
|
||||||
|
@ -33,4 +34,8 @@ public abstract class Stanza extends StreamElement {
|
||||||
public void setTo(final Jid to) {
|
public void setTo(final Jid to) {
|
||||||
this.setAttribute("to", to);
|
this.setAttribute("to", to);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public Error getError() {
|
||||||
|
return this.getExtension(Error.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,7 +9,6 @@ import im.conversations.android.xmpp.manager.BlockingManager;
|
||||||
import im.conversations.android.xmpp.manager.BookmarkManager;
|
import im.conversations.android.xmpp.manager.BookmarkManager;
|
||||||
import im.conversations.android.xmpp.manager.DiscoManager;
|
import im.conversations.android.xmpp.manager.DiscoManager;
|
||||||
import im.conversations.android.xmpp.manager.RosterManager;
|
import im.conversations.android.xmpp.manager.RosterManager;
|
||||||
import im.conversations.android.xmpp.model.stanza.Presence;
|
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
public class BindProcessor extends XmppConnection.Delegate implements Consumer<Jid> {
|
public class BindProcessor extends XmppConnection.Delegate implements Consumer<Jid> {
|
||||||
|
@ -47,7 +46,7 @@ public class BindProcessor extends XmppConnection.Delegate implements Consumer<J
|
||||||
|
|
||||||
getManager(BookmarkManager.class).fetch();
|
getManager(BookmarkManager.class).fetch();
|
||||||
|
|
||||||
connection.sendPresencePacket(new Presence());
|
// connection.sendPresencePacket(new Presence());
|
||||||
|
|
||||||
// TODO send initial presence
|
// TODO send initial presence
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,41 +5,83 @@ import com.google.common.base.Preconditions;
|
||||||
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.Extension;
|
||||||
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.error.Condition;
|
||||||
|
import im.conversations.android.xmpp.model.error.Error;
|
||||||
|
import im.conversations.android.xmpp.model.ping.Ping;
|
||||||
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 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;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
|
||||||
public class IqProcessor extends XmppConnection.Delegate implements Consumer<IQ> {
|
public class IqProcessor extends XmppConnection.Delegate implements Consumer<Iq> {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = LoggerFactory.getLogger(IqProcessor.class);
|
||||||
|
|
||||||
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 IQ packet) {
|
public void accept(final Iq packet) {
|
||||||
final IQ.Type type = packet.getType();
|
final Iq.Type type = packet.getType();
|
||||||
Preconditions.checkArgument(Arrays.asList(IQ.Type.GET, IQ.Type.SET).contains(type));
|
Preconditions.checkArgument(Arrays.asList(Iq.Type.GET, Iq.Type.SET).contains(type));
|
||||||
if (type == IQ.Type.SET
|
if (type == Iq.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));
|
||||||
|
sendResultFor(packet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == IQ.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));
|
||||||
|
sendResultFor(packet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (type == IQ.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));
|
||||||
|
sendResultFor(packet);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// TODO return feature not implemented
|
if (type == Iq.Type.GET && packet.hasExtension(Ping.class)) {
|
||||||
|
LOGGER.debug("Responding to ping from {}", packet.getFrom());
|
||||||
|
sendResultFor(packet);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
final var extensionIds = packet.getExtensionIds();
|
||||||
|
LOGGER.info("Could not handle {}. Sending feature-not-implemented", extensionIds);
|
||||||
|
sendErrorFor(packet, new Condition.FeatureNotImplemented());
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendResultFor(final Iq request, final Extension... extensions) {
|
||||||
|
final var from = request.getFrom();
|
||||||
|
final var id = request.getId();
|
||||||
|
final var response = new Iq(Iq.Type.RESULT);
|
||||||
|
response.setTo(from);
|
||||||
|
response.setId(id);
|
||||||
|
for (final Extension extension : extensions) {
|
||||||
|
response.addExtension(extension);
|
||||||
|
}
|
||||||
|
connection.sendIqPacket(response);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void sendErrorFor(final Iq request, final Condition condition) {
|
||||||
|
final var from = request.getFrom();
|
||||||
|
final var id = request.getId();
|
||||||
|
final var response = new Iq(Iq.Type.ERROR);
|
||||||
|
response.setTo(from);
|
||||||
|
response.setId(id);
|
||||||
|
final Error error = response.addExtension(new Error());
|
||||||
|
error.setCondition(condition);
|
||||||
|
connection.sendIqPacket(response);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,5 +42,14 @@ public class MessageProcessor extends XmppConnection.Delegate implements Consume
|
||||||
if (!Strings.isNullOrEmpty(body)) {
|
if (!Strings.isNullOrEmpty(body)) {
|
||||||
LOGGER.info("'{}' from {}", body, message.getFrom());
|
LOGGER.info("'{}' from {}", body, message.getFrom());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO process receipt requests (184 + 333)
|
||||||
|
|
||||||
|
// TODO collect Extensions that require transformation (everything that will end up in the
|
||||||
|
// message tables)
|
||||||
|
|
||||||
|
// TODO pass pubsub events to pubsub manager
|
||||||
|
|
||||||
|
// TODO pass JMI to JingleManager
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,8 +6,11 @@ import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import eu.siacs.conversations.xml.Element;
|
import eu.siacs.conversations.xml.Element;
|
||||||
import eu.siacs.conversations.xml.XmlElementReader;
|
import eu.siacs.conversations.xml.XmlElementReader;
|
||||||
|
import im.conversations.android.xmpp.model.error.Condition;
|
||||||
|
import im.conversations.android.xmpp.model.error.Error;
|
||||||
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.Message;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
@ -31,4 +34,23 @@ public class XmlElementReaderTest {
|
||||||
final Collection<Item> items = query.getExtensions(Item.class);
|
final Collection<Item> items = query.getExtensions(Item.class);
|
||||||
assertEquals(2, items.size());
|
assertEquals(2, items.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void readMessageError() throws IOException {
|
||||||
|
final String xml =
|
||||||
|
"<message\n"
|
||||||
|
+ " to='juliet@capulet.com/balcony'\n"
|
||||||
|
+ " from='romeo@montague.net/garden'\n"
|
||||||
|
+ " xmlns='jabber:client'\n"
|
||||||
|
+ " type='error'>\n"
|
||||||
|
+ " <body>Wherefore art thou, Romeo?</body>\n"
|
||||||
|
+ " <error code='404' type='cancel'>\n"
|
||||||
|
+ " <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>\n"
|
||||||
|
+ " </error>\n"
|
||||||
|
+ "</message>";
|
||||||
|
final Element element = XmlElementReader.read(xml.getBytes(StandardCharsets.UTF_8));
|
||||||
|
assertThat(element, instanceOf(Message.class));
|
||||||
|
final Message message = (Message) element;
|
||||||
|
final Error error = message.getError();
|
||||||
|
assertThat(error.getCondition(), instanceOf(Condition.ItemNotFound.class));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue