diff --git a/src/net/java/sip/communicator/impl/protocol/irc/ChannelManager.java b/src/net/java/sip/communicator/impl/protocol/irc/ChannelManager.java
new file mode 100644
index 000000000..3e99a5742
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/irc/ChannelManager.java
@@ -0,0 +1,1331 @@
+/*
+ * 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.impl.protocol.irc.ModeParser.ModeEntry;
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.util.*;
+
+import com.ircclouds.irc.api.*;
+import com.ircclouds.irc.api.domain.*;
+import com.ircclouds.irc.api.domain.messages.*;
+import com.ircclouds.irc.api.domain.messages.interfaces.*;
+import com.ircclouds.irc.api.listeners.*;
+import com.ircclouds.irc.api.state.*;
+
+/**
+ * Channel manager.
+ *
+ * @author Danny van Heumen
+ */
+public class ChannelManager
+{
+ /**
+ * Logger.
+ */
+ private static final Logger LOGGER = Logger.getLogger(ChannelManager.class);
+
+ /**
+ * IRCApi instance.
+ */
+ private final IRCApi irc;
+
+ /**
+ * Connection state.
+ */
+ private final IIRCState connectionState;
+
+ /**
+ * Provider.
+ */
+ private final ProtocolProviderServiceIrcImpl provider;
+
+ /**
+ * Identity manager instance.
+ */
+ private final IdentityManager identity;
+
+ /**
+ * Container for joined channels.
+ *
+ * There are two different cases:
+ *
+ *
+ * - null value: joining is initiated but still in progress.
+ * - non-null value: joining is finished, chat room instance is available.
+ *
+ */
+ private final Map joined = Collections
+ .synchronizedMap(new HashMap());
+
+ /**
+ * Constructor.
+ * @param irc the IRCApi instance
+ * @param connectionState the connection state
+ * @param provider the provider instance
+ * @param identity the identity manager instance
+ */
+ public ChannelManager(final IRCApi irc, final IIRCState connectionState,
+ final ProtocolProviderServiceIrcImpl provider,
+ final IdentityManager identity)
+ {
+ if (irc == null)
+ {
+ throw new IllegalArgumentException("irc instance cannot be null");
+ }
+ irc.addListener(new ManagerListener(irc));
+ this.irc = irc;
+ if (connectionState == null)
+ {
+ throw new IllegalArgumentException(
+ "connectionState cannot be null");
+ }
+ this.connectionState = connectionState;
+ if (provider == null)
+ {
+ throw new IllegalArgumentException("provider cannot be null");
+ }
+ this.provider = provider;
+ if (identity == null)
+ {
+ throw new IllegalArgumentException(
+ "IdentityManager instance cannot be null");
+ }
+ this.identity = identity;
+ }
+
+ /**
+ * Get a set of channel type indicators.
+ *
+ * @return returns set of channel type indicators.
+ */
+ public Set getChannelTypes()
+ {
+ return this.connectionState.getServerOptions().getChanTypes();
+ }
+
+ /**
+ * Check whether the user has joined a particular chat room.
+ *
+ * @param chatroom Chat room to check for.
+ * @return Returns true in case the user is already joined, or false if the
+ * user has not joined.
+ */
+ public boolean isJoined(final ChatRoomIrcImpl chatroom)
+ {
+ return this.joined.get(chatroom.getIdentifier()) != null;
+ }
+
+ /**
+ * Join a particular chat room.
+ *
+ * @param chatroom Chat room to join.
+ * @throws OperationFailedException failed to join the chat room
+ */
+ public void join(final ChatRoomIrcImpl chatroom)
+ throws OperationFailedException
+ {
+ join(chatroom, "");
+ }
+
+ /**
+ * Join a particular chat room.
+ *
+ * Issue a join channel IRC operation and wait for the join operation to
+ * complete (either successfully or failing).
+ *
+ * @param chatroom The chatroom to join.
+ * @param password Optionally, a password that may be required for some
+ * channels.
+ * @throws OperationFailedException failed to join the chat room
+ */
+ public void join(final ChatRoomIrcImpl chatroom, final String password)
+ throws OperationFailedException
+ {
+ if (!this.connectionState.isConnected())
+ {
+ throw new IllegalStateException(
+ "Please connect to an IRC server first");
+ }
+ if (chatroom == null)
+ {
+ throw new IllegalArgumentException("chatroom cannot be null");
+ }
+ if (password == null)
+ {
+ throw new IllegalArgumentException("password cannot be null");
+ }
+
+ final String chatRoomId = chatroom.getIdentifier();
+ if (this.joined.containsKey(chatRoomId))
+ {
+ // If we already joined this particular chatroom, no further action
+ // is required.
+ return;
+ }
+
+ LOGGER.trace("Start joining channel " + chatRoomId);
+ final Result