aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanny van Heumen <danny@dannyvanheumen.nl>2015-02-08 22:58:28 +0100
committerDanny van Heumen <danny@dannyvanheumen.nl>2015-03-13 19:35:53 +0100
commitbc3b4ca5b4a46a3b740822063869a0a2ddb99e32 (patch)
tree04caa5c144900d017e0fd9a5d742d3206ad68537
parent70188d78485bfa352594d739514114851edea903 (diff)
downloadjitsi-bc3b4ca5b4a46a3b740822063869a0a2ddb99e32.zip
jitsi-bc3b4ca5b4a46a3b740822063869a0a2ddb99e32.tar.gz
jitsi-bc3b4ca5b4a46a3b740822063869a0a2ddb99e32.tar.bz2
Working on MONITOR support for online presence.
-rw-r--r--src/net/java/sip/communicator/impl/protocol/irc/BasicPollerPresenceWatcher.java2
-rw-r--r--src/net/java/sip/communicator/impl/protocol/irc/MonitorPresenceWatcher.java264
-rw-r--r--src/net/java/sip/communicator/impl/protocol/irc/PresenceManager.java9
3 files changed, 271 insertions, 4 deletions
diff --git a/src/net/java/sip/communicator/impl/protocol/irc/BasicPollerPresenceWatcher.java b/src/net/java/sip/communicator/impl/protocol/irc/BasicPollerPresenceWatcher.java
index 10f1413..c82058e 100644
--- a/src/net/java/sip/communicator/impl/protocol/irc/BasicPollerPresenceWatcher.java
+++ b/src/net/java/sip/communicator/impl/protocol/irc/BasicPollerPresenceWatcher.java
@@ -64,7 +64,7 @@ class BasicPollerPresenceWatcher
* @param nickWatchList the nick watch list
* @param serverIdentity the server identity
*/
- public BasicPollerPresenceWatcher(final IRCApi irc,
+ BasicPollerPresenceWatcher(final IRCApi irc,
final IIRCState connectionState,
final OperationSetPersistentPresenceIrcImpl operationSet,
final SortedSet<String> nickWatchList,
diff --git a/src/net/java/sip/communicator/impl/protocol/irc/MonitorPresenceWatcher.java b/src/net/java/sip/communicator/impl/protocol/irc/MonitorPresenceWatcher.java
new file mode 100644
index 0000000..4a52e9c
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/irc/MonitorPresenceWatcher.java
@@ -0,0 +1,264 @@
+/*
+ * Jitsi, the OpenSource Java VoIP and Instant Messaging client.
+ *
+ * Distributable under LGPL license.
+ * See terms of license at gnu.org.
+ */
+package net.java.sip.communicator.impl.protocol.irc;
+
+import java.util.*;
+
+import net.java.sip.communicator.util.*;
+
+import com.ircclouds.irc.api.*;
+import com.ircclouds.irc.api.domain.messages.*;
+import com.ircclouds.irc.api.state.*;
+
+/**
+ * MONITOR presence watcher.
+ *
+ * @author Danny van Heumen
+ */
+class MonitorPresenceWatcher
+ implements PresenceWatcher
+{
+ /**
+ * Logger.
+ */
+ private static final Logger LOGGER = Logger
+ .getLogger(MonitorPresenceWatcher.class);
+
+ /**
+ * IRCApi instance.
+ */
+ private final IRCApi irc;
+
+ /**
+ * IRC connection state.
+ */
+ private final IIRCState connectionState;
+
+ /**
+ * Complete nick watch list.
+ */
+ private final SortedSet<String> nickWatchList;
+
+ /**
+ * Set of nicks that are confirmed to be monitored by the server.
+ */
+ private final SortedSet<String> monitoredNickList;
+
+ /**
+ * Constructor.
+ *
+ * @param irc the IRCApi instance
+ * @param connectionState the connection state
+ * @param nickWatchList the nick watch list
+ * @param operationSet the persistent presence operation set
+ */
+ MonitorPresenceWatcher(final IRCApi irc, final IIRCState connectionState,
+ final SortedSet<String> nickWatchList, final OperationSetPersistentPresenceIrcImpl operationSet)
+ {
+ if (irc == null)
+ {
+ throw new IllegalArgumentException("irc cannot be null");
+ }
+ this.irc = irc;
+ if (connectionState == null)
+ {
+ throw new IllegalArgumentException("connectionState cannot be null");
+ }
+ this.connectionState = connectionState;
+ if (nickWatchList == null)
+ {
+ throw new IllegalArgumentException("nickWatchList cannot be null");
+ }
+ this.nickWatchList = nickWatchList;
+ this.monitoredNickList =
+ Collections.synchronizedSortedSet(new TreeSet<String>());
+ this.irc.addListener(new MonitorReplyListener(operationSet));
+ setUpMonitor(this.irc, this.nickWatchList);
+ // FIXME add basic poller watcher as a fallback method
+ // FIXME adhere to limits according to ISUPPORT MONITOR=# entry
+ }
+
+ /**
+ * Set up monitor based on the nick watch list in its current state.
+ *
+ * Created a static method as not to interfere too much with a state that is
+ * still being initialized.
+ */
+ private static void setUpMonitor(final IRCApi irc, final SortedSet<String> nickWatchList)
+ {
+ final List<String> current;
+ synchronized (nickWatchList)
+ {
+ current = new LinkedList<String>(nickWatchList);
+ }
+ // FIXME compute actual limit
+ final int maxLength = 400;
+ final StringBuilder query = new StringBuilder();
+ for (String nick : current)
+ {
+ if (nick.length() + 1 > maxLength)
+ {
+ // payload is full, send monitor query now
+ irc.rawMessage(createMonitorCmd(query));
+ query.delete(0, query.length());
+ }
+ else if (query.length() > 0)
+ {
+ query.append(",");
+ }
+ query.append(nick);
+ }
+ if (query.length() > 0)
+ {
+ // send query for remaining nicks
+ irc.rawMessage(createMonitorCmd(query));
+ }
+ }
+
+ /**
+ * Create a MONITOR add command with the provided nick list query.
+ *
+ * @param query the query
+ * @return returns the full command
+ */
+ private static String createMonitorCmd(final StringBuilder query)
+ {
+ return "MONITOR + " + query.toString();
+ }
+
+ @Override
+ public void add(final String nick)
+ {
+ LOGGER.trace("Adding nick '" + nick + "' to MONITOR watch list.");
+ this.nickWatchList.add(nick);
+ this.irc.rawMessage("MONITOR + " + nick);
+ }
+
+ @Override
+ public void remove(final String nick)
+ {
+ LOGGER.trace("Removing nick '" + nick + "' from MONITOR watch list.");
+ this.nickWatchList.remove(nick);
+ this.irc.rawMessage("MONITOR - " + nick);
+ }
+
+ /**
+ * Listener for MONITOR replies.
+ *
+ * FIXME upon QUIT/ERROR/CLIENTERROR updateAll monitored OFFLINE
+ *
+ * @author Danny van Heumen
+ */
+ private final class MonitorReplyListener
+ extends AbstractIrcMessageListener
+ {
+ /**
+ * Numeric message id for ONLINE nick response.
+ */
+ private static final int IRC_RPL_MONONLINE = 730;
+
+ /**
+ * Numeric message id for OFFLINE nick response.
+ */
+ private static final int IRC_RPL_MONOFFLINE = 731;
+
+ // Unused constants. Listed for completeness.
+ // /**
+ // * Numeric message id for MONLIST entry.
+ // */
+ // private static final int IRC_RPL_MONLIST = 732;
+ //
+ // /**
+ // * Numeric message id for ENDOFMONLIST.
+ // */
+ // private static final int IRC_RPL_ENDOFMONLIST = 733;
+
+ /**
+ * Operation set persistent presence instance.
+ */
+ private final OperationSetPersistentPresenceIrcImpl operationSet;
+
+ // TODO Update to act on ClientError once available.
+
+ /**
+ * Constructor.
+ *
+ * @param operationSet the persistent presence opset used to update nick
+ * presence statuses.
+ */
+ public MonitorReplyListener(
+ final OperationSetPersistentPresenceIrcImpl operationSet)
+ {
+ super(MonitorPresenceWatcher.this.irc,
+ MonitorPresenceWatcher.this.connectionState);
+ if (operationSet == null)
+ {
+ throw new IllegalArgumentException(
+ "operationSet cannot be null");
+ }
+ this.operationSet = operationSet;
+ }
+
+ /**
+ * Numeric messages received in response to MONITOR commands or presence
+ * updates.
+ */
+ @Override
+ public void onServerNumericMessage(final ServerNumericMessage msg)
+ {
+ final List<String> confirmed;
+ switch (msg.getNumericCode())
+ {
+ case IRC_RPL_MONONLINE:
+ confirmed = parseMonitorResponse(msg.getText());
+ for (String nick : confirmed)
+ {
+ update(nick, IrcStatusEnum.ONLINE);
+ }
+ MonitorPresenceWatcher.this.monitoredNickList.addAll(confirmed);
+ break;
+ case IRC_RPL_MONOFFLINE:
+ confirmed = parseMonitorResponse(msg.getText());
+ for (String nick : confirmed)
+ {
+ update(nick, IrcStatusEnum.OFFLINE);
+ }
+ MonitorPresenceWatcher.this.monitoredNickList.addAll(confirmed);
+ break;
+ }
+ }
+
+ /**
+ * Parse response messages.
+ *
+ * @param message the message
+ * @return Returns the list of targets extracted.
+ */
+ private List<String> parseMonitorResponse(final String message)
+ {
+ final LinkedList<String> confirmed = new LinkedList<String>();
+ final String[] targets = message.substring(1).split(",");
+ for (String target : targets)
+ {
+ String[] parts = target.split("!");
+ confirmed.add(parts[0]);
+ }
+ return confirmed;
+ }
+
+ /**
+ * Update specified nick to specified presence status.
+ *
+ * @param nick the target nick
+ * @param status the current status
+ */
+ private void update(final String nick, final IrcStatusEnum status)
+ {
+ this.operationSet.updateNickContactPresence(nick, status);
+ }
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/irc/PresenceManager.java b/src/net/java/sip/communicator/impl/protocol/irc/PresenceManager.java
index 000fa13..547653b 100644
--- a/src/net/java/sip/communicator/impl/protocol/irc/PresenceManager.java
+++ b/src/net/java/sip/communicator/impl/protocol/irc/PresenceManager.java
@@ -138,9 +138,12 @@ public class PresenceManager
this.isupportAwayLen = parseISupportAwayLen(this.connectionState);
if (config.isContactPresenceTaskEnabled())
{
- this.watcher =
- new BasicPollerPresenceWatcher(this.irc, this.connectionState,
- this.operationSet, nickWatchList, this.serverIdentity);
+ // FIXME check for availability of MONITOR by ISUPPORT param
+ // FIXME fine tune code.
+// this.watcher =
+// new BasicPollerPresenceWatcher(this.irc, this.connectionState,
+// this.operationSet, nickWatchList, this.serverIdentity);
+ this.watcher = new MonitorPresenceWatcher(this.irc, this.connectionState, nickWatchList, this.operationSet);
}
else
{