From 54a9e733a84decefa34f195da0b3f2a18f989a18 Mon Sep 17 00:00:00 2001 From: Danny van Heumen Date: Sat, 16 Aug 2014 20:41:53 +0200 Subject: [PATCH] Support for away status in Jitsi presence Operation Set. --- .../impl/protocol/irc/IrcStack.java | 79 ++++++++++++++++++- .../impl/protocol/irc/IrcStatusEnum.java | 3 +- ...OperationSetPersistentPresenceIrcImpl.java | 71 ++++++++++++++--- 3 files changed, 137 insertions(+), 16 deletions(-) diff --git a/src/net/java/sip/communicator/impl/protocol/irc/IrcStack.java b/src/net/java/sip/communicator/impl/protocol/irc/IrcStack.java index 81066b7f3..832dff0ae 100644 --- a/src/net/java/sip/communicator/impl/protocol/irc/IrcStack.java +++ b/src/net/java/sip/communicator/impl/protocol/irc/IrcStack.java @@ -31,10 +31,16 @@ * * TODO Do we need to cancel any join channel operations still in progress? * + *

* Common IRC network facilities: - * 1. NickServ - nick related services - * 2. ChanServ - channel related services - * 3. MemoServ - message relaying services + *

+ * + * * * @author Danny van Heumen */ @@ -140,6 +146,11 @@ public class IrcStack */ private IIRCState connectionState; + /** + * Atomic boolean containing away status. + */ + private final AtomicBoolean away = new AtomicBoolean(); + /** * The cached channel list. * @@ -1019,6 +1030,39 @@ public void message(final Contact contact, final Message message) } } + /** + * Check whether current state is away or online. + * + * @return returns true if away, or false if online + */ + public boolean isAway() + { + return isConnected() && this.away.get(); + } + + /** + * Set or unset away message. In case the awayMessage is null the away + * message will be disabled and as a consequence the away-status is removed. + * + * @param awayMessage the away message to set, or null to remove away-status + */ + public void away(final String awayMessage) + { + if (!isConnected()) + { + throw new IllegalStateException("Not connected to an IRC server."); + } + final IRCApi irc = this.session.get(); + if (awayMessage == null || awayMessage.isEmpty()) + { + irc.rawMessage("AWAY"); + } + else + { + irc.rawMessage("AWAY :" + awayMessage); + } + } + /** * Grant user permissions to specified user. * @@ -1126,6 +1170,17 @@ private static ChatRoomMemberRole convertMemberMode(final char modeSymbol) private final class ServerListener extends VariousMessageListenerAdapter { + /** + * Reply for acknowledging transition to available (not away any + * longer). + */ + private static final int IRC_RPL_UNAWAY = 305; + + /** + * Reply for acknowledging transition to away. + */ + private static final int IRC_RPL_NOWAWAY = 306; + /** * IRCApi instance. */ @@ -1284,6 +1339,24 @@ public void onServerNumericMessage(final ServerNumericMessage msg) .OFFLINE_MESSAGES_NOT_SUPPORTED); break; + case IRC_RPL_UNAWAY: + final IrcStatusEnum previousUnAway = + IrcStack.this.away.get() ? IrcStatusEnum.AWAY + : IrcStatusEnum.ONLINE; + IrcStack.this.away.set(false); + IrcStack.this.provider.getPersistentPresence() + .updatePresenceStatus(previousUnAway, IrcStatusEnum.ONLINE); + break; + + case IRC_RPL_NOWAWAY: + final IrcStatusEnum previousNowAway = + IrcStack.this.away.get() ? IrcStatusEnum.AWAY + : IrcStatusEnum.ONLINE; + IrcStack.this.away.set(true); + IrcStack.this.provider.getPersistentPresence() + .updatePresenceStatus(previousNowAway, IrcStatusEnum.AWAY); + break; + default: if (LOGGER.isTraceEnabled()) { diff --git a/src/net/java/sip/communicator/impl/protocol/irc/IrcStatusEnum.java b/src/net/java/sip/communicator/impl/protocol/irc/IrcStatusEnum.java index 69c3fcb59..5c0a4ab74 100644 --- a/src/net/java/sip/communicator/impl/protocol/irc/IrcStatusEnum.java +++ b/src/net/java/sip/communicator/impl/protocol/irc/IrcStatusEnum.java @@ -61,8 +61,7 @@ public final class IrcStatusEnum static { SUPPORTED_STATUS_SET.add(OFFLINE); - // TODO implement support for presence status AWAY - //supportedStatusSet.add(AWAY); + SUPPORTED_STATUS_SET.add(AWAY); SUPPORTED_STATUS_SET.add(ONLINE); } diff --git a/src/net/java/sip/communicator/impl/protocol/irc/OperationSetPersistentPresenceIrcImpl.java b/src/net/java/sip/communicator/impl/protocol/irc/OperationSetPersistentPresenceIrcImpl.java index 67994c4ab..f6f9bfbb0 100644 --- a/src/net/java/sip/communicator/impl/protocol/irc/OperationSetPersistentPresenceIrcImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/irc/OperationSetPersistentPresenceIrcImpl.java @@ -300,18 +300,22 @@ public ContactGroupIrcImpl createUnresolvedContactGroup( /** * Get current IRC presence status. * - * The presence status currently is ONLINE if we are connected or OFFLINE if - * we aren't connected. + * The presence status currently is ONLINE or AWAY if we are connected or + * OFFLINE if we aren't connected. The status is set to AWAY if an away + * message is set. * - * @return returns status ONLINE if connected or OFFLINE if not connected + * @return returns status ONLINE if connected and not away, or AWAY if + * connected and an away message is set, or OFFLINE if not connected + * at all */ @Override public PresenceStatus getPresenceStatus() { - // TODO implement AWAY presence if available in irc-api if (this.parentProvider.getIrcStack().isConnected()) { - return IrcStatusEnum.ONLINE; + return this.parentProvider.getIrcStack().isAway() + ? IrcStatusEnum.AWAY + : IrcStatusEnum.ONLINE; } else { @@ -320,7 +324,10 @@ public PresenceStatus getPresenceStatus() } /** - * "Publishing" presence status in IRC is currently not implemented. + * Set a new presence status corresponding to the provided arguments. + * + * @param status presence status + * @param statusMessage message for the specified status */ @Override public void publishPresenceStatus(final PresenceStatus status, @@ -329,10 +336,48 @@ public void publishPresenceStatus(final PresenceStatus status, IllegalStateException, OperationFailedException { - // TODO implement publishPresenceStatus (we might be able to do - // something with modes invisible and away (IIRC) in IRC. - throw new OperationFailedException("Not implemented.", - OperationFailedException.NOT_SUPPORTED_OPERATION); + final IrcStack provider = this.parentProvider.getIrcStack(); + if (status.getStatus() >= IrcStatusEnum.AVAILABLE_THRESHOLD) + { + provider.away(null); + } + else if (status.getStatus() >= IrcStatusEnum.AWAY_THRESHOLD) + { + final String awayMessage; + if (statusMessage == null || statusMessage.isEmpty()) + { + awayMessage = + IrcActivator.getResources().getI18NString( + "service.gui.AWAY_STATUS"); + } + else + { + awayMessage = statusMessage; + } + provider.away(awayMessage); + } + else + { + // FIXME How to behave for status OFFLINE? + } + } + + /** + * Update (from IRC) containing the current presence status and message. + * + * @param previousStatus the previous presence status + * @param status the current presence status + */ + void updatePresenceStatus(final PresenceStatus previousStatus, + final PresenceStatus status) + { + // Note: Currently uses general PresenceStatus type parameters because + // EasyMock throws a java.lang.NoClassDefFoundError: Could not + // initialize class + // net.java.sip.communicator.impl.protocol.irc. + // OperationSetPersistentPresenceIrcImpl$$EnhancerByCGLIB$$403085ac + // if IrcStatusEnum is used. I'm not sure why, though ... + fireProviderStatusChangeEvent(previousStatus, status); } /** @@ -418,12 +463,16 @@ public void setAuthorizationHandler(final AuthorizationHandler handler) * IRC does not have a status message, so it will always return an empty * string. * + * TODO Consider using this for showing the away message if set. + * * @return returns empty string */ @Override public String getCurrentStatusMessage() { - return ""; + // FIXME look up active status message in case of away or "" in case of + // available. + return this.parentProvider.getIrcStack().isAway() ? "" : ""; } /**