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 832dff0ae..37b1abd56 100644
--- a/src/net/java/sip/communicator/impl/protocol/irc/IrcStack.java
+++ b/src/net/java/sip/communicator/impl/protocol/irc/IrcStack.java
@@ -147,9 +147,9 @@ public class IrcStack
private IIRCState connectionState;
/**
- * Atomic boolean containing away status.
+ * Manager component that manages current IRC presence.
*/
- private final AtomicBoolean away = new AtomicBoolean();
+ private PresenceManager presence = null;
/**
* The cached channel list.
@@ -321,6 +321,11 @@ public void onFailure(final Exception e)
if (this.connectionState != null
&& this.connectionState.isConnected())
{
+ // instantiate presence manager for the connection
+ this.presence =
+ new PresenceManager(irc, this.connectionState,
+ this.provider.getPersistentPresence());
+
// if connecting succeeded, set state to registered
this.provider.setCurrentRegistrationState(
RegistrationState.REGISTERED);
@@ -1037,7 +1042,7 @@ public void message(final Contact contact, final Message message)
*/
public boolean isAway()
{
- return isConnected() && this.away.get();
+ return isConnected() && this.presence.isAway();
}
/**
@@ -1052,15 +1057,7 @@ public void away(final String awayMessage)
{
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);
- }
+ this.presence.setAway(awayMessage);
}
/**
@@ -1170,17 +1167,6 @@ 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.
*/
@@ -1339,24 +1325,6 @@ 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 5c0a4ab74..637ed9db7 100644
--- a/src/net/java/sip/communicator/impl/protocol/irc/IrcStatusEnum.java
+++ b/src/net/java/sip/communicator/impl/protocol/irc/IrcStatusEnum.java
@@ -8,6 +8,7 @@
import java.util.*;
+import net.java.sip.communicator.impl.protocol.irc.*;
import net.java.sip.communicator.service.protocol.*;
/**
diff --git a/src/net/java/sip/communicator/impl/protocol/irc/PresenceManager.java b/src/net/java/sip/communicator/impl/protocol/irc/PresenceManager.java
new file mode 100644
index 000000000..8de649d2d
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/irc/PresenceManager.java
@@ -0,0 +1,201 @@
+/*
+ * 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 net.java.sip.communicator.util.*;
+
+import com.ircclouds.irc.api.*;
+import com.ircclouds.irc.api.domain.messages.*;
+import com.ircclouds.irc.api.listeners.*;
+import com.ircclouds.irc.api.state.*;
+
+/**
+ * Manager for presence status of IRC connection.
+ *
+ * @author Danny van Heumen
+ */
+public class PresenceManager
+{
+ /**
+ * Logger.
+ */
+ private static final Logger LOGGER = Logger
+ .getLogger(PresenceManager.class);
+
+ /**
+ * IRC client library instance.
+ */
+ private final IRCApi irc;
+
+ /**
+ * IRC client connection state.
+ */
+ private final IIRCState state;
+
+ /**
+ * Instance of OperationSetPersistentPresence for updates.
+ */
+ private final OperationSetPersistentPresenceIrcImpl operationSet;
+
+ /**
+ * Current presence status.
+ */
+ private volatile boolean away = false;
+
+ /**
+ * Active away message.
+ */
+ private String currentMessage;
+
+ /**
+ * Proposed away message.
+ */
+ private String submittedMessage;
+
+ /**
+ * Constructor.
+ *
+ * @param irc irc client library instance
+ * @param state irc client connection state instance
+ * @param operationSet OperationSetPersistentPresence irc implementation for
+ * handling presence changes.
+ */
+ public PresenceManager(final IRCApi irc, final IIRCState state,
+ final OperationSetPersistentPresenceIrcImpl operationSet)
+ {
+ if (state == null)
+ {
+ throw new IllegalArgumentException("state cannot be null");
+ }
+ this.state = state;
+ if (operationSet == null)
+ {
+ throw new IllegalArgumentException("operationSet cannot be null");
+ }
+ this.operationSet = operationSet;
+ if (irc == null)
+ {
+ throw new IllegalArgumentException("irc cannot be null");
+ }
+ irc.addListener(new PresenceListener());
+ this.irc = irc;
+ }
+
+ /**
+ * Check current Away state.
+ *
+ * @return returns true if away or false if not away
+ */
+ public boolean isAway()
+ {
+ return this.away;
+ }
+
+ /**
+ * Get away message.
+ *
+ * @return returns currently active away message or "" if currently not
+ * away.
+ */
+ public String getMessage()
+ {
+ return this.away ? this.currentMessage : "";
+ }
+
+ /**
+ * Set away status and message. Disable away status by providing
+ * null message.
+ *
+ * @param awayMessage away message to set. If away message is null
+ * or empty away status will be cancelled.
+ */
+ public void setAway(final String awayMessage)
+ {
+ if (awayMessage == null || awayMessage.isEmpty())
+ {
+ this.irc.rawMessage("AWAY");
+ }
+ else
+ {
+ this.submittedMessage = awayMessage;
+ this.irc.rawMessage("AWAY :" + awayMessage);
+ }
+ }
+
+ /**
+ * Presence listener implementation for keeping track of presence changes in
+ * the IRC connection.
+ *
+ * @author Danny van Heumen
+ */
+ private final class PresenceListener
+ 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;
+
+ /**
+ * Presence listener constructor.
+ */
+ private PresenceListener()
+ {
+ }
+
+ @Override
+ public void onServerNumericMessage(final ServerNumericMessage msg)
+ {
+ Integer msgCode = msg.getNumericCode();
+ if (msgCode == null)
+ {
+ return;
+ }
+ int code = msgCode.intValue();
+ switch (code)
+ {
+ case IRC_RPL_UNAWAY:
+ PresenceManager.this.currentMessage = "";
+ PresenceManager.this.away = false;
+ operationSet.updatePresenceStatus(IrcStatusEnum.AWAY,
+ IrcStatusEnum.ONLINE);
+ LOGGER.debug("Away status disabled.");
+ break;
+ case IRC_RPL_NOWAWAY:
+ PresenceManager.this.currentMessage =
+ PresenceManager.this.submittedMessage;
+ PresenceManager.this.away = true;
+ operationSet.updatePresenceStatus(IrcStatusEnum.ONLINE,
+ IrcStatusEnum.AWAY);
+ LOGGER.debug("Away status enabled.");
+ break;
+ default:
+ break;
+ }
+ }
+
+ @Override
+ public void onUserQuit(final QuitMessage msg)
+ {
+ final String user = msg.getSource().getNick();
+ if (user == null
+ || !user.equals(PresenceManager.this.state.getNickname()))
+ {
+ return;
+ }
+ LOGGER.debug("Local user's QUIT message received: removing "
+ + "presence listener.");
+ PresenceManager.this.irc.deleteListener(this);
+ }
+ }
+}
diff --git a/test/net/java/sip/communicator/impl/protocol/irc/ChatRoomMemberIrcImplTest.java b/test/net/java/sip/communicator/impl/protocol/irc/ChatRoomMemberIrcImplTest.java
index e1f22cee7..43da6d179 100644
--- a/test/net/java/sip/communicator/impl/protocol/irc/ChatRoomMemberIrcImplTest.java
+++ b/test/net/java/sip/communicator/impl/protocol/irc/ChatRoomMemberIrcImplTest.java
@@ -212,17 +212,19 @@ public void testRemoveInsignificantRole()
member.removeRole(ChatRoomMemberRole.MEMBER);
Assert.assertSame(ChatRoomMemberRole.ADMINISTRATOR, member.getRole());
}
-
+
public void testGetContact()
{
ChatRoom chatroom = EasyMock.createMock(ChatRoom.class);
ProtocolProviderServiceIrcImpl provider =
EasyMock.createMock(ProtocolProviderServiceIrcImpl.class);
- OperationSetPersistentPresenceIrcImpl pp = EasyMock.createMock(OperationSetPersistentPresenceIrcImpl.class);
+ OperationSetPersistentPresenceIrcImpl pp =
+ EasyMock.createMock(OperationSetPersistentPresenceIrcImpl.class);
EasyMock.expect(provider.getPersistentPresence()).andReturn(pp);
EasyMock.replay(provider);
- ChatRoomMemberIrcImpl member = new ChatRoomMemberIrcImpl(provider, chatroom,
- "user", ChatRoomMemberRole.SILENT_MEMBER);
+ ChatRoomMemberIrcImpl member =
+ new ChatRoomMemberIrcImpl(provider, chatroom, "user",
+ ChatRoomMemberRole.SILENT_MEMBER);
Assert.assertNull(member.getContact());
}
@@ -231,8 +233,9 @@ public void testGetAvatar()
ChatRoom chatroom = EasyMock.createMock(ChatRoom.class);
ProtocolProviderServiceIrcImpl provider =
EasyMock.createMock(ProtocolProviderServiceIrcImpl.class);
- ChatRoomMemberIrcImpl member = new ChatRoomMemberIrcImpl(provider, chatroom,
- "user", ChatRoomMemberRole.SILENT_MEMBER);
+ ChatRoomMemberIrcImpl member =
+ new ChatRoomMemberIrcImpl(provider, chatroom, "user",
+ ChatRoomMemberRole.SILENT_MEMBER);
Assert.assertNull(member.getAvatar());
}