aboutsummaryrefslogtreecommitdiffstats
path: root/src/main/java/de/thedevstack/conversationsplus/xmpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/de/thedevstack/conversationsplus/xmpp')
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/AbstractXep.java30
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/IqPacketHandler.java12
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/Xep.java16
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/XepRegistry.java51
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java6
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/disco/FeatureRegistry.java90
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscovery.java8
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryIqPacketGenerator.java38
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryIqPacketHandler.java21
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryIqPacketParser.java15
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryXep.java51
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/NotAllowedIqException.java11
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersion.java9
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersionPacket.java23
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersionPacketGenerator.java21
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersionPacketHandler.java21
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/SoftwareVersionXep.java51
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/openpgp/OpenPgpXep.java48
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/ping/Ping.java8
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/ping/PingPacketHandler.java22
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/ping/PingXep.java51
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/ErrorIqPacket.java16
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqErrorCondition.java48
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqErrorType.java12
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacket.java4
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacketGenerator.java17
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacketReceiver.java96
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/csi/ActivePacket.java2
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/csi/Csi.java7
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/csi/InactivePacket.java2
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/time/EntityTime.java8
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/time/EntityTimeXep.java51
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/time/TimeIqPacketHandler.java21
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/time/TimePacket.java35
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/time/TimePacketGenerator.java31
-rw-r--r--src/main/java/de/thedevstack/conversationsplus/xmpp/utils/ErrorIqPacketExceptionHelper.java16
36 files changed, 886 insertions, 83 deletions
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/AbstractXep.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/AbstractXep.java
new file mode 100644
index 00000000..96cbeb3e
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/AbstractXep.java
@@ -0,0 +1,30 @@
+package de.thedevstack.conversationsplus.xmpp;
+
+/**
+ */
+public abstract class AbstractXep implements Xep {
+ protected boolean enabled = true;
+
+ public AbstractXep() {
+ this(true);
+ }
+
+ public AbstractXep(boolean enabled) {
+ this.enabled = enabled;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ return enabled;
+ }
+
+ @Override
+ public final void enable() {
+ this.enabled = true;
+ }
+
+ @Override
+ public final void disable() {
+ this.enabled = false;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/IqPacketHandler.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/IqPacketHandler.java
new file mode 100644
index 00000000..cfd5172e
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/IqPacketHandler.java
@@ -0,0 +1,12 @@
+package de.thedevstack.conversationsplus.xmpp;
+
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.xmpp.exceptions.IqPacketErrorException;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ *
+ */
+public interface IqPacketHandler {
+ void handleIqPacket(Account account, IqPacket packet) throws IqPacketErrorException;
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/Xep.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/Xep.java
new file mode 100644
index 00000000..058f345e
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/Xep.java
@@ -0,0 +1,16 @@
+package de.thedevstack.conversationsplus.xmpp;
+
+/**
+ */
+public interface Xep {
+ boolean isEnabled();
+ void enable();
+ void disable();
+ String xepNumber();
+ String shortName();
+ String name();
+ String namespace();
+ String featureNamespace();
+ String elementName();
+ IqPacketHandler handler();
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/XepRegistry.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/XepRegistry.java
new file mode 100644
index 00000000..89174c70
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/XepRegistry.java
@@ -0,0 +1,51 @@
+package de.thedevstack.conversationsplus.xmpp;
+
+import java.util.Hashtable;
+
+import de.thedevstack.conversationsplus.xmpp.disco.FeatureRegistry;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacketReceiver;
+
+/**
+ */
+public class XepRegistry {
+ private final Hashtable<String, Xep> xeps = new Hashtable<>();
+ private static final XepRegistry INSTANCE = new XepRegistry();
+
+ public static void enable(String shortName) {
+ if (INSTANCE.xeps.containsKey(shortName)) {
+ Xep xep = INSTANCE.xeps.get(shortName);
+ xep.enable();
+ FeatureRegistry.remove(xep);
+ IqPacketReceiver.getInstance().registerIqPacketHandler(xep);
+ }
+ }
+
+ public static void disable(String shortName) {
+ if (INSTANCE.xeps.containsKey(shortName)) {
+ Xep xep = INSTANCE.xeps.get(shortName);
+ xep.disable();
+ FeatureRegistry.remove(xep);
+ IqPacketReceiver.getInstance().unregisterIqPacketHandler(xep);
+ }
+ }
+
+ public static void add(Xep xep) {
+ INSTANCE.xeps.put(xep.shortName(), xep);
+ if (xep.isEnabled()) {
+ FeatureRegistry.add(xep);
+ IqPacketReceiver.getInstance().registerIqPacketHandler(xep);
+ }
+ }
+
+ public static void remove(Xep xep) {
+ INSTANCE.xeps.remove(xep.shortName());
+ FeatureRegistry.remove(xep);
+ IqPacketReceiver.getInstance().unregisterIqPacketHandler(xep);
+ }
+
+ public static XepRegistry getInstance() {
+ return INSTANCE;
+ }
+
+ private XepRegistry() {}
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java
index 54db5346..2b366dbb 100644
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/XmppConnection.java
@@ -84,9 +84,11 @@ import de.thedevstack.conversationsplus.xmpp.mam.Mam;
import de.thedevstack.conversationsplus.xmpp.stanzas.AbstractAcknowledgeableStanza;
import de.thedevstack.conversationsplus.xmpp.stanzas.AbstractStanza;
import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacketReceiver;
import de.thedevstack.conversationsplus.xmpp.stanzas.MessagePacket;
import de.thedevstack.conversationsplus.xmpp.stanzas.PresencePacket;
import de.thedevstack.conversationsplus.xmpp.stanzas.csi.ActivePacket;
+import de.thedevstack.conversationsplus.xmpp.stanzas.csi.Csi;
import de.thedevstack.conversationsplus.xmpp.stanzas.csi.InactivePacket;
import de.thedevstack.conversationsplus.xmpp.stanzas.streammgmt.AckPacket;
import de.thedevstack.conversationsplus.xmpp.stanzas.streammgmt.EnablePacket;
@@ -1092,7 +1094,7 @@ public class XmppConnection implements Runnable {
}
if (getFeatures().blocking() && !features.blockListRequested) {
Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": Requesting block list");
- this.sendIqPacket(getIqGenerator().generateGetBlockList(), mXmppConnectionService.getIqParser());
+ this.sendIqPacket(getIqGenerator().generateGetBlockList(), IqPacketReceiver.getInstance().getLegacyIqParser());
}
for (final OnAdvancedStreamFeaturesLoaded listener : advancedStreamFeaturesLoadedListeners) {
listener.onAdvancedStreamFeaturesAvailable(account);
@@ -1509,7 +1511,7 @@ public class XmppConnection implements Runnable {
}
public boolean csi() {
- return connection.streamFeatures != null && connection.streamFeatures.hasChild("csi", "urn:xmpp:csi:0");
+ return connection.streamFeatures != null && connection.streamFeatures.hasChild("csi", Csi.NAMESPACE);
}
public boolean pep() {
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/FeatureRegistry.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/FeatureRegistry.java
new file mode 100644
index 00000000..1c266545
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/FeatureRegistry.java
@@ -0,0 +1,90 @@
+package de.thedevstack.conversationsplus.xmpp.disco;
+
+import android.util.Base64;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+import de.thedevstack.conversationsplus.crypto.axolotl.AxolotlService;
+import de.thedevstack.conversationsplus.xmpp.Xep;
+import de.thedevstack.conversationsplus.xmpp.chatstate.ChatState;
+import de.tzur.conversations.Settings;
+
+/**
+ */
+public final class FeatureRegistry {
+ public static final String IDENTITY_TYPE = "phone";
+
+ private static final String[] LEGACY_FEATURES = {
+ "urn:xmpp:jingle:1",
+ "urn:xmpp:jingle:apps:file-transfer:3",
+ "urn:xmpp:jingle:transports:s5b:1",
+ "urn:xmpp:jingle:transports:ibb:1",
+ "http://jabber.org/protocol/muc",
+ "jabber:x:conference",
+ "http://jabber.org/protocol/caps",
+ "http://jabber.org/protocol/disco#info",
+ "urn:xmpp:avatar:metadata+notify",
+ "http://jabber.org/protocol/nick+notify",
+ ChatState.NAMESPACE,
+ AxolotlService.PEP_DEVICE_LIST+"+notify"};
+ private static final String[] LEGACY_MESSAGE_CONFIRMATION_FEATURES = {
+ "urn:xmpp:chat-markers:0",
+ "urn:xmpp:receipts"
+ };
+ private final List<String> features = new ArrayList<>();
+ private static final FeatureRegistry INSTANCE = new FeatureRegistry();
+
+ public static void add(String featureNamespace) {
+ if (null != featureNamespace) {
+ INSTANCE.features.add(featureNamespace);
+ }
+ }
+
+ public static void remove(String featureNamespace) {
+ if (null != featureNamespace && INSTANCE.features.contains(featureNamespace)) {
+ INSTANCE.features.remove(featureNamespace);
+ }
+ }
+ public static void add(Xep xep) {
+ add(xep.featureNamespace());
+ }
+
+ public static void remove(Xep xep) {
+ remove(xep.featureNamespace());
+ }
+
+ public static List<String> getFeatures() {
+ Collections.sort(INSTANCE.features);
+ return INSTANCE.features;
+ }
+
+ public static String getCapHash() {
+ StringBuilder s = new StringBuilder();
+ s.append("client/" + IDENTITY_TYPE + "//" + ConversationsPlusApplication.getNameAndVersion() + "<");
+ MessageDigest md;
+ try {
+ md = MessageDigest.getInstance("SHA-1");
+ } catch (NoSuchAlgorithmException e) {
+ return null;
+ }
+
+ for (String feature : getFeatures()) {
+ s.append(feature + "<");
+ }
+ byte[] sha1 = md.digest(s.toString().getBytes());
+ return new String(Base64.encode(sha1, Base64.DEFAULT));
+ }
+
+ private FeatureRegistry() {
+ this.features.addAll(Arrays.asList(LEGACY_FEATURES));
+ if (Settings.CONFIRM_MESSAGE_RECEIVED) {
+ this.features.addAll(Arrays.asList(LEGACY_MESSAGE_CONFIRMATION_FEATURES));
+ }
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscovery.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscovery.java
new file mode 100644
index 00000000..59a4212b
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscovery.java
@@ -0,0 +1,8 @@
+package de.thedevstack.conversationsplus.xmpp.disco;
+
+/**
+ */
+public interface ServiceDiscovery {
+ String NAMESPACE = "http://jabber.org/protocol/disco#info";
+ String ELEMENT = "query";
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryIqPacketGenerator.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryIqPacketGenerator.java
new file mode 100644
index 00000000..8e1fc075
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryIqPacketGenerator.java
@@ -0,0 +1,38 @@
+package de.thedevstack.conversationsplus.xmpp.disco;
+
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.jid.Jid;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacketGenerator;
+
+/**
+ */
+public class ServiceDiscoveryIqPacketGenerator {
+
+ public static IqPacket generateRequest(Jid jid) {
+ IqPacket request = IqPacketGenerator.generateIqGetPacket();
+ request.setTo(jid);
+ request.query(ServiceDiscovery.NAMESPACE);
+
+ return request;
+ }
+
+ public static IqPacket generateResponse(IqPacket packet) {
+ IqPacket responsePacket = IqPacketGenerator.generateIqResultPacket();
+ responsePacket.setTo(packet.getFrom());
+ responsePacket.setId(packet.getId());
+
+ Element query = responsePacket.addChild(ServiceDiscovery.ELEMENT, ServiceDiscovery.NAMESPACE);
+ query.setAttribute("node", packet.query().getAttribute("node"));
+ final Element identity = query.addChild("identity");
+ identity.setAttribute("category", "client");
+ identity.setAttribute("type", FeatureRegistry.IDENTITY_TYPE);
+ identity.setAttribute("name", ConversationsPlusApplication.getNameAndVersion());
+ for (final String feature : FeatureRegistry.getFeatures()) {
+ query.addChild("feature").setAttribute("var", feature);
+ }
+
+ return responsePacket;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryIqPacketHandler.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryIqPacketHandler.java
new file mode 100644
index 00000000..6f1b0676
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryIqPacketHandler.java
@@ -0,0 +1,21 @@
+package de.thedevstack.conversationsplus.xmpp.disco;
+
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.utils.XmppSendUtil;
+import de.thedevstack.conversationsplus.xmpp.IqPacketHandler;
+import de.thedevstack.conversationsplus.xmpp.exceptions.IqPacketErrorException;
+import de.thedevstack.conversationsplus.xmpp.exceptions.NotAllowedIqException;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ */
+public class ServiceDiscoveryIqPacketHandler implements IqPacketHandler {
+ @Override
+ public void handleIqPacket(Account account, IqPacket packet) throws IqPacketErrorException {
+ if (packet.getType() == IqPacket.TYPE.GET) {
+ XmppSendUtil.sendIqPacket(account, ServiceDiscoveryIqPacketGenerator.generateResponse(packet));
+ } else {
+ throw new NotAllowedIqException(packet, "only type=get allowed for processing an service discovery (XEP-0030)");
+ }
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryIqPacketParser.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryIqPacketParser.java
new file mode 100644
index 00000000..0ea0d752
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryIqPacketParser.java
@@ -0,0 +1,15 @@
+package de.thedevstack.conversationsplus.xmpp.disco;
+
+import de.thedevstack.conversationsplus.entities.ServiceDiscoveryResult;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ */
+public class ServiceDiscoveryIqPacketParser {
+ public static ServiceDiscoveryResult parse(IqPacket packet) {
+ if (packet.getType() == IqPacket.TYPE.RESULT) {
+ return new ServiceDiscoveryResult(packet);
+ }
+ return null;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryXep.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryXep.java
new file mode 100644
index 00000000..6a21c71b
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/disco/ServiceDiscoveryXep.java
@@ -0,0 +1,51 @@
+package de.thedevstack.conversationsplus.xmpp.disco;
+
+import de.thedevstack.conversationsplus.xmpp.AbstractXep;
+import de.thedevstack.conversationsplus.xmpp.IqPacketHandler;
+
+/**
+ */
+public class ServiceDiscoveryXep extends AbstractXep {
+ public ServiceDiscoveryXep() {
+ super();
+ }
+
+ public ServiceDiscoveryXep(boolean enabled) {
+ super(enabled);
+ }
+
+ @Override
+ public String xepNumber() {
+ return "0030";
+ }
+
+ @Override
+ public String shortName() {
+ return "disco";
+ }
+
+ @Override
+ public String name() {
+ return "Service Discovery";
+ }
+
+ @Override
+ public String namespace() {
+ return ServiceDiscovery.NAMESPACE;
+ }
+
+ @Override
+ public String featureNamespace() {
+ return ServiceDiscovery.NAMESPACE;
+ }
+
+ @Override
+ public String elementName() {
+ return ServiceDiscovery.ELEMENT;
+ }
+
+ @Override
+ public IqPacketHandler handler() {
+ return new ServiceDiscoveryIqPacketHandler();
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/NotAllowedIqException.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/NotAllowedIqException.java
new file mode 100644
index 00000000..45bf231a
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/exceptions/NotAllowedIqException.java
@@ -0,0 +1,11 @@
+package de.thedevstack.conversationsplus.xmpp.exceptions;
+
+import de.thedevstack.conversationsplus.xml.Element;
+
+/**
+ */
+public class NotAllowedIqException extends IqPacketErrorException {
+ public NotAllowedIqException(Element context, String errorMessage) {
+ super(context, errorMessage);
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersion.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersion.java
new file mode 100644
index 00000000..e90ccb5a
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersion.java
@@ -0,0 +1,9 @@
+package de.thedevstack.conversationsplus.xmpp.iqversion;
+
+/**
+ *
+ */
+public interface IqVersion {
+ String NAMESPACE = "jabber:iq:version";
+ String ELEMENT = "query";
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersionPacket.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersionPacket.java
deleted file mode 100644
index a3cecdac..00000000
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersionPacket.java
+++ /dev/null
@@ -1,23 +0,0 @@
-package de.thedevstack.conversationsplus.xmpp.iqversion;
-
-import android.os.Build;
-
-import de.thedevstack.conversationsplus.ConversationsPlusApplication;
-import de.thedevstack.conversationsplus.xml.Element;
-import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
-
-/**
- * Representation of an software version packet as defined in XEP-0092.
- * @see <a href="http://xmpp.org/extensions/xep-0092.html">http://xmpp.org/extensions/xep-0092.html</a>
- */
-public class IqVersionPacket extends IqPacket {
- public static final String NAMESPACE = "jabber:iq:version";
-
- IqVersionPacket() {
- super(IqPacket.TYPE.RESULT);
- Element query = this.addChild("query", NAMESPACE);
- query.addChild("name").setContent(ConversationsPlusApplication.getName());
- query.addChild("version").setContent(ConversationsPlusApplication.getVersion());
- query.addChild("os").setContent("Android " + Build.VERSION.RELEASE);
- }
-}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersionPacketGenerator.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersionPacketGenerator.java
index 97a7e90d..c4961c1d 100644
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersionPacketGenerator.java
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersionPacketGenerator.java
@@ -1,6 +1,12 @@
package de.thedevstack.conversationsplus.xmpp.iqversion;
+import android.os.Build;
+
+import de.thedevstack.conversationsplus.ConversationsPlusApplication;
+import de.thedevstack.conversationsplus.ConversationsPlusPreferences;
+import de.thedevstack.conversationsplus.xml.Element;
import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacketGenerator;
/**
* Generates the IQ Packets for Software Version
@@ -26,12 +32,17 @@ public final class IqVersionPacketGenerator {
* @param packet the packet to respond to
* @return
*/
- public static IqVersionPacket generateResponse(IqPacket packet) {
- IqVersionPacket iqVersionPacket = new IqVersionPacket();
- iqVersionPacket.setTo(packet.getFrom());
- iqVersionPacket.setId(packet.getId());
+ public static IqPacket generateResponse(IqPacket packet) {
+ IqPacket responsePacket = IqPacketGenerator.generateIqResultResponse(packet);
+
+ Element query = responsePacket.addChild(IqVersion.ELEMENT, IqVersion.NAMESPACE);
+ query.addChild("name").setContent(ConversationsPlusApplication.getName());
+ query.addChild("version").setContent(ConversationsPlusApplication.getVersion());
+ if (ConversationsPlusPreferences.sendOsInformation()) {
+ query.addChild("os").setContent("Android " + Build.VERSION.RELEASE);
+ }
- return iqVersionPacket;
+ return responsePacket;
}
private IqVersionPacketGenerator() {}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersionPacketHandler.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersionPacketHandler.java
new file mode 100644
index 00000000..7462d0cb
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/IqVersionPacketHandler.java
@@ -0,0 +1,21 @@
+package de.thedevstack.conversationsplus.xmpp.iqversion;
+
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.utils.XmppSendUtil;
+import de.thedevstack.conversationsplus.xmpp.IqPacketHandler;
+import de.thedevstack.conversationsplus.xmpp.exceptions.IqPacketErrorException;
+import de.thedevstack.conversationsplus.xmpp.exceptions.NotAllowedIqException;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ */
+public class IqVersionPacketHandler implements IqPacketHandler {
+ @Override
+ public void handleIqPacket(Account account, IqPacket packet) throws IqPacketErrorException {
+ if (packet.getType() == IqPacket.TYPE.GET) {
+ XmppSendUtil.sendIqPacket(account, IqVersionPacketGenerator.generateResponse(packet));
+ } else {
+ throw new NotAllowedIqException(packet, "only type=get allowed for processing an Software Version (XEP-0092)");
+ }
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/SoftwareVersionXep.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/SoftwareVersionXep.java
new file mode 100644
index 00000000..9cd69bb2
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/iqversion/SoftwareVersionXep.java
@@ -0,0 +1,51 @@
+package de.thedevstack.conversationsplus.xmpp.iqversion;
+
+import de.thedevstack.conversationsplus.xmpp.AbstractXep;
+import de.thedevstack.conversationsplus.xmpp.IqPacketHandler;
+
+/**
+ */
+public class SoftwareVersionXep extends AbstractXep {
+ public SoftwareVersionXep() {
+ super();
+ }
+
+ public SoftwareVersionXep(boolean enabled) {
+ super(enabled);
+ }
+
+ @Override
+ public String xepNumber() {
+ return "0092";
+ }
+
+ @Override
+ public String shortName() {
+ return "iq-version";
+ }
+
+ @Override
+ public String name() {
+ return "Software Version";
+ }
+
+ @Override
+ public String namespace() {
+ return IqVersion.NAMESPACE;
+ }
+
+ @Override
+ public String featureNamespace() {
+ return IqVersion.NAMESPACE;
+ }
+
+ @Override
+ public String elementName() {
+ return IqVersion.ELEMENT;
+ }
+
+ @Override
+ public IqPacketHandler handler() {
+ return new IqVersionPacketHandler();
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/openpgp/OpenPgpXep.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/openpgp/OpenPgpXep.java
new file mode 100644
index 00000000..15229bf9
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/openpgp/OpenPgpXep.java
@@ -0,0 +1,48 @@
+package de.thedevstack.conversationsplus.xmpp.openpgp;
+
+import de.thedevstack.conversationsplus.xmpp.AbstractXep;
+import de.thedevstack.conversationsplus.xmpp.IqPacketHandler;
+
+/**
+ */
+public class OpenPgpXep extends AbstractXep {
+ public static final String ENCRYPTED_NAMESPACE = "jabber:x:encrypted";
+ public static final String ENCRYPTED_ELEMENT = "x";
+ public static final String SIGNED_NAMESPACE = "jabber:x:signed";
+ public static final String SIGNED_ELEMENT = "x";
+
+ @Override
+ public String xepNumber() {
+ return "0027";
+ }
+
+ @Override
+ public String shortName() {
+ return "openpgp";
+ }
+
+ @Override
+ public String name() {
+ return "Current Jabber OpenPGP Usage";
+ }
+
+ @Override
+ public String namespace() {
+ return null;
+ }
+
+ @Override
+ public String featureNamespace() {
+ return null;
+ }
+
+ @Override
+ public String elementName() {
+ return null;
+ }
+
+ @Override
+ public IqPacketHandler handler() {
+ return null;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/ping/Ping.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/ping/Ping.java
new file mode 100644
index 00000000..ac201c01
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/ping/Ping.java
@@ -0,0 +1,8 @@
+package de.thedevstack.conversationsplus.xmpp.ping;
+
+/**
+ */
+public interface Ping {
+ String NAMESPACE = "urn:xmpp:ping";
+ String ELEMENT = "ping";
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/ping/PingPacketHandler.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/ping/PingPacketHandler.java
new file mode 100644
index 00000000..14e8f57c
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/ping/PingPacketHandler.java
@@ -0,0 +1,22 @@
+package de.thedevstack.conversationsplus.xmpp.ping;
+
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.utils.XmppSendUtil;
+import de.thedevstack.conversationsplus.xmpp.IqPacketHandler;
+import de.thedevstack.conversationsplus.xmpp.exceptions.IqPacketErrorException;
+import de.thedevstack.conversationsplus.xmpp.exceptions.NotAllowedIqException;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacketGenerator;
+
+/**
+ */
+public class PingPacketHandler implements IqPacketHandler {
+ @Override
+ public void handleIqPacket(Account account, IqPacket packet) throws IqPacketErrorException {
+ if (packet.getType() == IqPacket.TYPE.GET) {
+ XmppSendUtil.sendIqPacket(account, IqPacketGenerator.generateIqResultResponse(packet));
+ } else {
+ throw new NotAllowedIqException(packet, "only type=get allowed for processing an XMPP Ping (XEP-0199)");
+ }
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/ping/PingXep.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/ping/PingXep.java
new file mode 100644
index 00000000..6036a64f
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/ping/PingXep.java
@@ -0,0 +1,51 @@
+package de.thedevstack.conversationsplus.xmpp.ping;
+
+import de.thedevstack.conversationsplus.xmpp.AbstractXep;
+import de.thedevstack.conversationsplus.xmpp.IqPacketHandler;
+
+/**
+ */
+public class PingXep extends AbstractXep {
+ public PingXep() {
+ super();
+ }
+
+ public PingXep(boolean enabled) {
+ super(enabled);
+ }
+
+ @Override
+ public String xepNumber() {
+ return "0199";
+ }
+
+ @Override
+ public String shortName() {
+ return "ping";
+ }
+
+ @Override
+ public String name() {
+ return "XMPP Ping";
+ }
+
+ @Override
+ public String namespace() {
+ return Ping.NAMESPACE;
+ }
+
+ @Override
+ public String featureNamespace() {
+ return Ping.NAMESPACE;
+ }
+
+ @Override
+ public String elementName() {
+ return Ping.ELEMENT;
+ }
+
+ @Override
+ public IqPacketHandler handler() {
+ return new PingPacketHandler();
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/ErrorIqPacket.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/ErrorIqPacket.java
new file mode 100644
index 00000000..3f87202e
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/ErrorIqPacket.java
@@ -0,0 +1,16 @@
+package de.thedevstack.conversationsplus.xmpp.stanzas;
+
+import de.thedevstack.conversationsplus.xml.Element;
+
+/**
+ */
+public class ErrorIqPacket extends IqPacket {
+ public final static String NAMESPACE = "urn:ietf:params:xml:ns:xmpp-stanzas";
+
+ public ErrorIqPacket(IqErrorCondition condition) {
+ super(IqPacket.TYPE.ERROR);
+ final Element error = this.addChild("error");
+ error.setAttribute("type", condition.getType().toString());
+ error.addChild(condition.toString(), NAMESPACE);
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqErrorCondition.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqErrorCondition.java
new file mode 100644
index 00000000..688ea007
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqErrorCondition.java
@@ -0,0 +1,48 @@
+package de.thedevstack.conversationsplus.xmpp.stanzas;
+
+/**
+ */
+public enum IqErrorCondition {
+ BAD_REQUEST(IqErrorType.MODIFY),
+ CONFLICT(IqErrorType.CANCEL),
+ FEATURE_NOT_IMPLEMENTED(IqErrorType.CANCEL),
+ FORBIDDEN(IqErrorType.AUTH),
+ GONE(IqErrorType.MODIFY),
+ INTERNAL_SERVER_ERROR(IqErrorType.WAIT),
+ ITEM_NOT_FOUND(IqErrorType.CANCEL),
+ JID_MALFORMED(IqErrorType.MODIFY),
+ NOT_ACCEPTABLE(IqErrorType.MODIFY),
+ NOT_ALLOWED(IqErrorType.CANCEL),
+ NOT_AUTHORIZED(IqErrorType.AUTH),
+ PAYMENT_REQUIRED(IqErrorType.AUTH),
+ RECIPIENT_UNAVAILABLE(IqErrorType.WAIT),
+ REDIRECT(IqErrorType.MODIFY),
+ REGISTRATION_REQUIRED(IqErrorType.AUTH),
+ REMOTE_SERVER_NOT_FOUND(IqErrorType.CANCEL),
+ REMOTE_SERVER_TIMEOUT(IqErrorType.WAIT),
+ RESOURCE_CONSTRAINT(IqErrorType.WAIT),
+ SERVICE_UNAVAILABLE(IqErrorType.CANCEL),
+ SUBSCRIPTION_REQUIRED(IqErrorType.AUTH),
+ UNDEFINED_CONDITION(IqErrorType.CANCEL),
+ UNEXPECTED_REQUEST(IqErrorType.WAIT)
+ ;
+
+ private IqErrorType type;
+
+ IqErrorCondition(IqErrorType type) {
+ this.type = type;
+ }
+
+ public IqErrorType getType() {
+ return type;
+ }
+
+ public static IqErrorCondition fromString(String condition) {
+ return (null != condition) ? Enum.valueOf(IqErrorCondition.class, condition.toUpperCase().replaceAll("-", "_")) : null;
+ }
+
+ @Override
+ public String toString() {
+ return super.toString().toLowerCase().replaceAll("_", "-");
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqErrorType.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqErrorType.java
new file mode 100644
index 00000000..4ebe0f41
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqErrorType.java
@@ -0,0 +1,12 @@
+package de.thedevstack.conversationsplus.xmpp.stanzas;
+
+/**
+ */
+public enum IqErrorType {
+ CANCEL, MODIFY, AUTH, WAIT;
+
+ @Override
+ public String toString() {
+ return super.toString().toLowerCase();
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacket.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacket.java
index d86831e0..415d5de3 100644
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacket.java
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacket.java
@@ -59,6 +59,10 @@ public class IqPacket extends AbstractAcknowledgeableStanza {
}
}
+ public Element getChildElement() {
+ return this.children.get(0);
+ }
+
public IqPacket generateResponse(final TYPE type) {
final IqPacket packet = new IqPacket(type);
packet.setTo(this.getFrom());
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacketGenerator.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacketGenerator.java
index 27e6607f..01204a96 100644
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacketGenerator.java
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacketGenerator.java
@@ -1,5 +1,7 @@
package de.thedevstack.conversationsplus.xmpp.stanzas;
+import de.thedevstack.conversationsplus.xml.Element;
+
/**
* Created by tzur on 15.01.2016.
*/
@@ -21,8 +23,19 @@ public final class IqPacketGenerator {
return generateIqPacket(IqPacket.TYPE.RESULT);
}
- public static IqPacket generateIqErrorPacket() {
- return generateIqPacket(IqPacket.TYPE.ERROR);
+ public static IqPacket generateIqResultResponse(IqPacket packet) {
+ IqPacket responsePacket = generateIqResultPacket();
+ responsePacket.setTo(packet.getFrom());
+ responsePacket.setId(packet.getId());
+
+ return responsePacket;
+ }
+
+ public static ErrorIqPacket generateIqErrorPacketResponse(IqErrorCondition condition, IqPacket packet) {
+ ErrorIqPacket errorPacket = new ErrorIqPacket(condition);
+ errorPacket.setTo(packet.getFrom());
+ errorPacket.setId(packet.getId());
+ return errorPacket;
}
private IqPacketGenerator() {
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacketReceiver.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacketReceiver.java
new file mode 100644
index 00000000..bfae0355
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/IqPacketReceiver.java
@@ -0,0 +1,96 @@
+package de.thedevstack.conversationsplus.xmpp.stanzas;
+
+import java.util.Hashtable;
+
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.parser.IqParser;
+import de.thedevstack.conversationsplus.utils.XmppConnectionServiceAccessor;
+import de.thedevstack.conversationsplus.utils.XmppSendUtil;
+import de.thedevstack.conversationsplus.xml.Element;
+import de.thedevstack.conversationsplus.xmpp.IqPacketHandler;
+import de.thedevstack.conversationsplus.xmpp.OnIqPacketReceived;
+import de.thedevstack.conversationsplus.xmpp.Xep;
+import de.thedevstack.conversationsplus.xmpp.exceptions.IqPacketErrorException;
+import de.thedevstack.conversationsplus.xmpp.exceptions.NotAllowedIqException;
+
+/**
+ */
+public final class IqPacketReceiver implements OnIqPacketReceived {
+ private final Hashtable<String, IqPacketHandler> iqPacketHandlers = new Hashtable<>();
+ private final IqParser legacyIqParser;
+ private static IqPacketReceiver INSTANCE;
+
+ public synchronized static IqPacketReceiver getInstance() {
+ if (null == INSTANCE) {
+ IqPacketReceiver.INSTANCE = new IqPacketReceiver();
+ }
+ return INSTANCE;
+ }
+
+ private IqPacketReceiver() {
+ this.legacyIqParser = new IqParser(XmppConnectionServiceAccessor.xmppConnectionService);
+ }
+
+ @Override
+ public void onIqPacketReceived(Account account, IqPacket packet) {
+ String key = generateKey(packet);
+ if (null != key && this.iqPacketHandlers.containsKey(key)) {
+ try {
+ IqPacketHandler iqPacketHandler = this.iqPacketHandlers.get(key);
+ iqPacketHandler.handleIqPacket(account, packet);
+ } catch (NotAllowedIqException e) {
+ ErrorIqPacket errorIqPacket = IqPacketGenerator.generateIqErrorPacketResponse(IqErrorCondition.NOT_ALLOWED, packet);
+ XmppSendUtil.sendIqPacket(account, errorIqPacket);
+ } catch (IqPacketErrorException e) {
+
+ }
+ } else {
+ this.legacyIqParser.onIqPacketReceived(account, packet);
+ }
+ }
+
+ public static String generateKey(IqPacket packet) {
+ Element childElement = packet.getChildElement();
+ return generateKey(childElement.getName(), childElement.getNamespace());
+ }
+
+ public static String generateKey(String elementName, String xmlns) {
+ if (null == elementName && null == xmlns) {
+ return null;
+ }
+ return ((null != elementName) ? elementName : "") + ((null != xmlns) ? ("-" + xmlns) : "");
+ }
+
+ public void registerIqPacketHandler(String elementName, String xmlns, IqPacketHandler iqPacketHandler) {
+ String key = generateKey(elementName, xmlns);
+ if (null != key) {
+ this.iqPacketHandlers.put(key, iqPacketHandler);
+ }
+ }
+
+ public void unregisterIqPacketHandler(String elementName, String xmlns) {
+ String key = generateKey(elementName, xmlns);
+ if (null != key && this.iqPacketHandlers.containsKey(key)) {
+ this.iqPacketHandlers.remove(key);
+ }
+ }
+
+ public void registerIqPacketHandler(Xep xep) {
+ String key = generateKey(xep.elementName(), xep.namespace());
+ if (null != key && null != xep.handler()) {
+ this.iqPacketHandlers.put(key, xep.handler());
+ }
+ }
+
+ public void unregisterIqPacketHandler(Xep xep) {
+ String key = generateKey(xep.elementName(), xep.namespace());
+ if (null != key && this.iqPacketHandlers.containsKey(key)) {
+ this.iqPacketHandlers.remove(key);
+ }
+ }
+
+ @Deprecated
+ public IqParser getLegacyIqParser() {
+ return this.legacyIqParser;
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/csi/ActivePacket.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/csi/ActivePacket.java
index 47538a64..52b2e04d 100644
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/csi/ActivePacket.java
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/csi/ActivePacket.java
@@ -5,6 +5,6 @@ import de.thedevstack.conversationsplus.xmpp.stanzas.AbstractStanza;
public class ActivePacket extends AbstractStanza {
public ActivePacket() {
super("active");
- setAttribute("xmlns", "urn:xmpp:csi:0");
+ setAttribute("xmlns", Csi.NAMESPACE);
}
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/csi/Csi.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/csi/Csi.java
new file mode 100644
index 00000000..e002b093
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/csi/Csi.java
@@ -0,0 +1,7 @@
+package de.thedevstack.conversationsplus.xmpp.stanzas.csi;
+
+/**
+ */
+public interface Csi {
+ String NAMESPACE = "urn:xmpp:csi:0";
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/csi/InactivePacket.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/csi/InactivePacket.java
index ca5904a5..35486858 100644
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/csi/InactivePacket.java
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/stanzas/csi/InactivePacket.java
@@ -5,6 +5,6 @@ import de.thedevstack.conversationsplus.xmpp.stanzas.AbstractStanza;
public class InactivePacket extends AbstractStanza {
public InactivePacket() {
super("inactive");
- setAttribute("xmlns", "urn:xmpp:csi:0");
+ setAttribute("xmlns", Csi.NAMESPACE);
}
}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/time/EntityTime.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/time/EntityTime.java
new file mode 100644
index 00000000..7382f37a
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/time/EntityTime.java
@@ -0,0 +1,8 @@
+package de.thedevstack.conversationsplus.xmpp.time;
+
+/**
+ */
+public interface EntityTime {
+ String NAMESPACE = "urn:xmpp:time";
+ String ELEMENT = "time";
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/time/EntityTimeXep.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/time/EntityTimeXep.java
new file mode 100644
index 00000000..fb721bce
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/time/EntityTimeXep.java
@@ -0,0 +1,51 @@
+package de.thedevstack.conversationsplus.xmpp.time;
+
+import de.thedevstack.conversationsplus.xmpp.AbstractXep;
+import de.thedevstack.conversationsplus.xmpp.IqPacketHandler;
+
+/**
+ */
+public class EntityTimeXep extends AbstractXep {
+ public EntityTimeXep() {
+ super();
+ }
+
+ public EntityTimeXep(boolean enabled) {
+ super(enabled);
+ }
+
+ @Override
+ public String xepNumber() {
+ return "0202";
+ }
+
+ @Override
+ public String shortName() {
+ return "time";
+ }
+
+ @Override
+ public String name() {
+ return "Entity Time";
+ }
+
+ @Override
+ public String namespace() {
+ return EntityTime.NAMESPACE;
+ }
+
+ @Override
+ public String featureNamespace() {
+ return EntityTime.NAMESPACE;
+ }
+
+ @Override
+ public String elementName() {
+ return EntityTime.ELEMENT;
+ }
+
+ @Override
+ public IqPacketHandler handler() {
+ return new TimeIqPacketHandler();
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/time/TimeIqPacketHandler.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/time/TimeIqPacketHandler.java
new file mode 100644
index 00000000..961c649b
--- /dev/null
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/time/TimeIqPacketHandler.java
@@ -0,0 +1,21 @@
+package de.thedevstack.conversationsplus.xmpp.time;
+
+import de.thedevstack.conversationsplus.entities.Account;
+import de.thedevstack.conversationsplus.utils.XmppSendUtil;
+import de.thedevstack.conversationsplus.xmpp.IqPacketHandler;
+import de.thedevstack.conversationsplus.xmpp.exceptions.IqPacketErrorException;
+import de.thedevstack.conversationsplus.xmpp.exceptions.NotAllowedIqException;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+
+/**
+ */
+public class TimeIqPacketHandler implements IqPacketHandler {
+ @Override
+ public void handleIqPacket(Account account, IqPacket packet) throws IqPacketErrorException {
+ if (packet.getType() == IqPacket.TYPE.GET) {
+ XmppSendUtil.sendIqPacket(account, TimePacketGenerator.generateResponse(packet));
+ } else {
+ throw new NotAllowedIqException(packet, "only type=get allowed for processing an Entity Time (XEP-0202)");
+ }
+ }
+}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/time/TimePacket.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/time/TimePacket.java
deleted file mode 100644
index d8756d41..00000000
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/time/TimePacket.java
+++ /dev/null
@@ -1,35 +0,0 @@
-package de.thedevstack.conversationsplus.xmpp.time;
-
-import java.util.Locale;
-import java.util.TimeZone;
-
-import de.thedevstack.conversationsplus.generator.AbstractGenerator;
-import de.thedevstack.conversationsplus.xml.Element;
-import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
-
-/**
- * Representation of an software version packet as defined in XEP-0202.
- * @see <a href="http://xmpp.org/extensions/xep-0202.html">http://xmpp.org/extensions/xep-0202.html</a>
- */
-public class TimePacket extends IqPacket {
- public static final String NAMESPACE = "urn:xmpp:time";
-
- TimePacket() {
- super(IqPacket.TYPE.RESULT);
- Element time = this.addChild("time", NAMESPACE);
- final long now = System.currentTimeMillis();
- time.addChild("utc").setContent(AbstractGenerator.getTimestamp(now));
- TimeZone ourTimezone = TimeZone.getDefault();
- long offsetSeconds = ourTimezone.getOffset(now) / 1000;
- long offsetMinutes = Math.abs((offsetSeconds % 3600) / 60);
- long offsetHours = offsetSeconds / 3600;
- String hours;
- if (offsetHours < 0) {
- hours = String.format(Locale.US, "%03d", offsetHours);
- } else {
- hours = String.format(Locale.US, "%02d", offsetHours);
- }
- String minutes = String.format(Locale.US, "%02d", offsetMinutes);
- time.addChild("tzo").setContent(hours + ":" + minutes);
- }
-}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/time/TimePacketGenerator.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/time/TimePacketGenerator.java
index 344beb9e..ef381d4d 100644
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/time/TimePacketGenerator.java
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/time/TimePacketGenerator.java
@@ -1,7 +1,12 @@
package de.thedevstack.conversationsplus.xmpp.time;
-import de.thedevstack.conversationsplus.xmpp.iqversion.IqVersionPacket;
+import java.util.Locale;
+import java.util.TimeZone;
+
+import de.thedevstack.conversationsplus.generator.AbstractGenerator;
+import de.thedevstack.conversationsplus.xml.Element;
import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacket;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqPacketGenerator;
/**
* Generates the IQ Packets for Entity Time
@@ -26,12 +31,26 @@ public final class TimePacketGenerator {
* @param packet
* @return
*/
- public static TimePacket generateResponse(IqPacket packet) {
- TimePacket timePacket = new TimePacket();
- timePacket.setTo(packet.getFrom());
- timePacket.setId(packet.getId());
+ public static IqPacket generateResponse(IqPacket packet) {
+ IqPacket responsePacket = IqPacketGenerator.generateIqResultResponse(packet);
+
+ Element time = responsePacket.addChild(EntityTime.ELEMENT, EntityTime.NAMESPACE);
+ final long now = System.currentTimeMillis();
+ time.addChild("utc").setContent(AbstractGenerator.getTimestamp(now));
+ TimeZone ourTimezone = TimeZone.getDefault();
+ long offsetSeconds = ourTimezone.getOffset(now) / 1000;
+ long offsetMinutes = Math.abs((offsetSeconds % 3600) / 60);
+ long offsetHours = offsetSeconds / 3600;
+ String hours;
+ if (offsetHours < 0) {
+ hours = String.format(Locale.US, "%03d", offsetHours);
+ } else {
+ hours = String.format(Locale.US, "%02d", offsetHours);
+ }
+ String minutes = String.format(Locale.US, "%02d", offsetMinutes);
+ time.addChild("tzo").setContent(hours + ":" + minutes);
- return timePacket;
+ return responsePacket;
}
private TimePacketGenerator() {}
diff --git a/src/main/java/de/thedevstack/conversationsplus/xmpp/utils/ErrorIqPacketExceptionHelper.java b/src/main/java/de/thedevstack/conversationsplus/xmpp/utils/ErrorIqPacketExceptionHelper.java
index bcc5e9dd..f3ac92dc 100644
--- a/src/main/java/de/thedevstack/conversationsplus/xmpp/utils/ErrorIqPacketExceptionHelper.java
+++ b/src/main/java/de/thedevstack/conversationsplus/xmpp/utils/ErrorIqPacketExceptionHelper.java
@@ -7,26 +7,26 @@ import de.thedevstack.conversationsplus.xmpp.exceptions.InternalServerErrorExcep
import de.thedevstack.conversationsplus.xmpp.exceptions.IqPacketErrorException;
import de.thedevstack.conversationsplus.xmpp.exceptions.ServiceUnavailableException;
import de.thedevstack.conversationsplus.xmpp.exceptions.UndefinedConditionException;
+import de.thedevstack.conversationsplus.xmpp.stanzas.ErrorIqPacket;
+import de.thedevstack.conversationsplus.xmpp.stanzas.IqErrorCondition;
/**
- * Created by steckbrief on 22.08.2016.
*/
public final class ErrorIqPacketExceptionHelper {
- private final static String ERROR_NAMESPACE = "urn:ietf:params:xml:ns:xmpp-stanzas";
public static void throwIqErrorException(Element errorIqPacket) throws IqPacketErrorException {
Element packet = IqPacketParser.findChild(errorIqPacket, "error", "jabber:client");
if (null != packet) {
- if (hasErrorElement(packet, "bad-request")) {
+ if (hasErrorElement(packet, IqErrorCondition.BAD_REQUEST.toString())) {
throw new BadRequestIqErrorException(errorIqPacket, getErrorText(packet));
}
- if (hasErrorElement(packet, "service-unavailable")) {
+ if (hasErrorElement(packet, IqErrorCondition.SERVICE_UNAVAILABLE.toString())) {
throw new ServiceUnavailableException(errorIqPacket, getErrorText(packet));
}
- if (hasErrorElement(packet, "internal-server-error")) {
+ if (hasErrorElement(packet, IqErrorCondition.INTERNAL_SERVER_ERROR.toString())) {
throw new InternalServerErrorException(errorIqPacket, getErrorText(packet));
}
- if (hasErrorElement(packet, "undefined-condition")) {
+ if (hasErrorElement(packet, IqErrorCondition.UNDEFINED_CONDITION.toString())) {
throw new UndefinedConditionException(errorIqPacket, getErrorText(packet));
}
}
@@ -34,11 +34,11 @@ public final class ErrorIqPacketExceptionHelper {
}
private static boolean hasErrorElement(Element packet, String elementName) {
- return null != IqPacketParser.findChild(packet, elementName, ERROR_NAMESPACE);
+ return null != IqPacketParser.findChild(packet, elementName, ErrorIqPacket.NAMESPACE);
}
private static String getErrorText(Element packet) {
- return IqPacketParser.findChildContent(packet, "text", ERROR_NAMESPACE);
+ return IqPacketParser.findChildContent(packet, "text", ErrorIqPacket.NAMESPACE);
}
private ErrorIqPacketExceptionHelper() {