summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/isode/stroke/presence')
-rw-r--r--src/com/isode/stroke/presence/PayloadAddingPresenceSender.java62
-rw-r--r--src/com/isode/stroke/presence/PresenceOracle.java127
-rw-r--r--src/com/isode/stroke/presence/SubscriptionManager.java68
3 files changed, 257 insertions, 0 deletions
diff --git a/src/com/isode/stroke/presence/PayloadAddingPresenceSender.java b/src/com/isode/stroke/presence/PayloadAddingPresenceSender.java
new file mode 100644
index 0000000..ed6106b
--- /dev/null
+++ b/src/com/isode/stroke/presence/PayloadAddingPresenceSender.java
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2010-2015, Isode Limited, London, England.
+ * All rights reserved.
+ */
+package com.isode.stroke.presence;
+
+import com.isode.stroke.elements.Payload;
+import com.isode.stroke.elements.Presence;
+
+public class PayloadAddingPresenceSender implements PresenceSender {
+ private Presence lastSentPresence;
+ private final PresenceSender sender;
+ private Payload payload;
+
+ public PayloadAddingPresenceSender(PresenceSender sender) {
+ this.sender = sender;
+ }
+
+ public void sendPresence(Presence presence) {
+ if (presence.isAvailable()) {
+ if (presence.getTo() != null && !presence.getTo().isValid()) {
+ lastSentPresence = presence;
+ }
+ } else {
+ lastSentPresence = null;
+ }
+ if (payload != null) {
+ Presence sentPresence = presence;
+ sentPresence.updatePayload(payload);
+ sender.sendPresence(sentPresence);
+ } else {
+ sender.sendPresence(presence);
+ }
+ }
+
+ public boolean isAvailable() {
+ return sender.isAvailable();
+ }
+
+ /**
+ * Sets the payload to be added to outgoing presences. If initial presence
+ * has been sent, this will resend the last sent presence with an updated
+ * payload. Initial presence is reset when unavailable presence is sent, or
+ * when reset() is called.
+ */
+ public void setPayload(Payload payload) {
+ this.payload = payload;
+ if (lastSentPresence != null) {
+ sendPresence(lastSentPresence);
+ }
+ }
+
+ /**
+ * Resets the presence sender. This puts the presence sender back in the
+ * initial state (before initial presence has been sent). This also resets
+ * the chained sender.
+ */
+ public void reset() {
+ lastSentPresence = null;
+ }
+
+}
diff --git a/src/com/isode/stroke/presence/PresenceOracle.java b/src/com/isode/stroke/presence/PresenceOracle.java
new file mode 100644
index 0000000..8d63f59
--- /dev/null
+++ b/src/com/isode/stroke/presence/PresenceOracle.java
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2010-2015, Isode Limited, London, England.
+ * All rights reserved.
+ */
+package com.isode.stroke.presence;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import com.isode.stroke.client.StanzaChannel;
+import com.isode.stroke.elements.Presence;
+import com.isode.stroke.elements.StatusShow;
+import com.isode.stroke.jid.JID;
+import com.isode.stroke.signals.Signal1;
+import com.isode.stroke.signals.SignalConnection;
+import com.isode.stroke.signals.Slot1;
+
+public class PresenceOracle {
+ private final Map<JID,Map<JID,Presence>> entries_ = new HashMap<JID,Map<JID,Presence>>();
+ private final StanzaChannel stanzaChannel_;
+ private final SignalConnection onPresenceReceivedSignal;
+ private final SignalConnection onAvailableChangedSignal;
+
+
+ public final Signal1<Presence> onPresenceChange = new Signal1<Presence>();
+
+ public PresenceOracle(StanzaChannel stanzaChannel) {
+ stanzaChannel_ = stanzaChannel;
+ onPresenceReceivedSignal = stanzaChannel_.onPresenceReceived.connect(new Slot1<Presence>() {
+ @Override
+ public void call(Presence p1) {
+ handleIncomingPresence(p1);
+ }
+ });
+ onAvailableChangedSignal = stanzaChannel_.onAvailableChanged.connect(new Slot1<Boolean>() {
+ @Override
+ public void call(Boolean p1) {
+ handleStanzaChannelAvailableChanged(p1);
+ }
+ });
+ }
+
+ void delete() {
+ onPresenceReceivedSignal.disconnect();
+ onAvailableChangedSignal.disconnect();
+ }
+
+ void handleStanzaChannelAvailableChanged(boolean available) {
+ if (available) {
+ entries_.clear();
+ }
+ }
+
+
+ void handleIncomingPresence(Presence presence) {
+ JID bareJID = presence.getFrom().toBare();
+ if (presence.getType() == Presence.Type.Subscribe) {
+ }
+ else {
+ Presence passedPresence = presence;
+ if (presence.getType() == Presence.Type.Unsubscribe) {
+ /* 3921bis says that we don't follow up with an unavailable, so simulate this ourselves */
+ passedPresence = new Presence();
+ passedPresence.setType(Presence.Type.Unavailable);
+ passedPresence.setFrom(bareJID);
+ passedPresence.setStatus(presence.getStatus());
+ }
+ Map<JID,Presence> jidMap = entries_.get(bareJID);
+ if (jidMap == null) jidMap = new HashMap<JID,Presence>();
+ if (passedPresence.getFrom().isBare() && presence.getType() == Presence.Type.Unavailable) {
+ /* Have a bare-JID only presence of offline */
+ jidMap.clear();
+ } else if (passedPresence.getType() == Presence.Type.Available) {
+ /* Don't have a bare-JID only offline presence once there are available presences */
+ jidMap.remove(bareJID);
+ }
+ if (passedPresence.getType() == Presence.Type.Unavailable && jidMap.size() > 1) {
+ jidMap.remove(passedPresence.getFrom());
+ } else {
+ jidMap.put(passedPresence.getFrom(), passedPresence);
+ }
+ entries_.put(bareJID, jidMap);
+ onPresenceChange.emit(passedPresence);
+ }
+ }
+
+ public Presence getLastPresence(final JID jid) {
+ Map<JID,Presence> presenceMap = entries_.get(jid.toBare());
+ if (presenceMap == null) return new Presence();
+
+ Presence i = presenceMap.get(jid);
+ if (i != null) {
+ return i;
+ } else {
+ return new Presence();
+ }
+ }
+
+ public Collection<Presence> getAllPresence(final JID bareJID) {
+ Collection<Presence> results = new ArrayList<Presence>();
+
+ Map<JID,Presence> presenceMap = entries_.get(bareJID);
+ if (presenceMap == null) return results;
+
+ results.addAll(presenceMap.values());
+ return results;
+ }
+
+ public Presence getHighestPriorityPresence(final JID bareJID) {
+ Map<JID,Presence> presenceMap = entries_.get(bareJID);
+ if (presenceMap == null) return new Presence();
+
+ Presence highest = null;
+ for (Presence current : presenceMap.values()) {
+ if (highest == null
+ || current.getPriority() > highest.getPriority()
+ || (current.getPriority() == highest.getPriority()
+ && StatusShow.typeToAvailabilityOrdering(current.getShow()) > StatusShow.typeToAvailabilityOrdering(highest.getShow()))) {
+ highest = current;
+ }
+
+ }
+ return highest;
+ }
+}
diff --git a/src/com/isode/stroke/presence/SubscriptionManager.java b/src/com/isode/stroke/presence/SubscriptionManager.java
new file mode 100644
index 0000000..91075fc
--- /dev/null
+++ b/src/com/isode/stroke/presence/SubscriptionManager.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2010-2015, Isode Limited, London, England.
+ * All rights reserved.
+ */
+package com.isode.stroke.presence;
+
+import com.isode.stroke.client.StanzaChannel;
+import com.isode.stroke.elements.Presence;
+import com.isode.stroke.jid.JID;
+import com.isode.stroke.signals.Signal2;
+import com.isode.stroke.signals.Signal3;
+import com.isode.stroke.signals.SignalConnection;
+import com.isode.stroke.signals.Slot1;
+
+public class SubscriptionManager {
+ private StanzaChannel stanzaChannel;
+ private SignalConnection onPresenceReceivedConnection;
+
+ public final Signal3<JID, String, Presence> onPresenceSubscriptionRequest = new Signal3<JID, String, Presence>();
+
+ public final Signal2<JID, String> onPresenceSubscriptionRevoked = new Signal2<JID, String>();
+
+ public SubscriptionManager(StanzaChannel channel) {
+ stanzaChannel = channel;
+ onPresenceReceivedConnection = stanzaChannel.onPresenceReceived.connect(new Slot1<Presence>() {
+ @Override
+ public void call(Presence p1) {
+ handleIncomingPresence(p1);
+ }
+ });
+ }
+
+ void delete() {
+ onPresenceReceivedConnection.disconnect();
+ }
+
+ public void cancelSubscription(final JID jid) {
+ Presence stanza = new Presence();
+ stanza.setType(Presence.Type.Unsubscribed);
+ stanza.setTo(jid);
+ stanzaChannel.sendPresence(stanza);
+ }
+
+ public void confirmSubscription(final JID jid) {
+ Presence stanza = new Presence();
+ stanza.setType(Presence.Type.Subscribed);
+ stanza.setTo(jid);
+ stanzaChannel.sendPresence(stanza);
+ }
+
+
+ public void requestSubscription(final JID jid) {
+ Presence stanza = new Presence();
+ stanza.setType(Presence.Type.Subscribe);
+ stanza.setTo(jid);
+ stanzaChannel.sendPresence(stanza);
+ }
+
+ void handleIncomingPresence(Presence presence) {
+ JID bareJID = presence.getFrom().toBare();
+ if (presence.getType() == Presence.Type.Subscribe) {
+ onPresenceSubscriptionRequest.emit(bareJID, presence.getStatus(), presence);
+ }
+ else if (presence.getType() == Presence.Type.Unsubscribe) {
+ onPresenceSubscriptionRevoked.emit(bareJID, presence.getStatus());
+ }
+ }
+}