+ * To be notified every time the room's subject change you should add a + * ChatRoomPropertyChangelistener to this room. + *
+ *
+ *
+ * To change the room's subject use {@link #setSubject(String)}. Note: Not
+ * possible inside the msn protocol!
+ *
+ * @return the room subject or null if the user hasn't joined the
+ * room or the room does not have a subject yet.
+ */
+ public String getSubject()
+ {
+ return chatSubject;
+ }
+
+ /**
+ * Returns the local user's nickname in the context of this chat room or
+ * null if not currently joined.
+ *
+ * @return the nickname currently being used by the local user in the
+ * context of the local chat room.
+ */
+ public String getUserNickname()
+ {
+ if (nickname == null && isJoined())
+ nickname =
+ parentProvider.getMessenger().getOwner().getDisplayName();
+
+ return nickname;
+ }
+
+ /**
+ * Invites another user to this room. If we're not joined nothing will
+ * happen.
+ *
+ * @param userAddress the address of the user (email address) to invite to
+ * the room.(one may also invite users not on their contact
+ * list).
+ * @param reason You cannot specify a Reason inside the msn protocol
+ */
+ public void invite(String userAddress, String reason)
+ {
+ // msn requires lower case email addresses
+ userAddress = userAddress.toLowerCase();
+
+ if (switchboard == null)
+ {
+ pendingInvitations.add(userAddress);
+ }
+ else
+ {
+ switchboard.inviteContact(Email.parseStr(userAddress));
+ }
+ }
+
+ public boolean isJoined()
+ {
+ if (this.switchboard == null)
+ return false;
+
+ // unfortunately we can't check if the switchboard session is still
+ // active
+ // so we have to compare it to the active switchboards from the provider
+ for (MsnSwitchboard board : parentProvider.getMessenger()
+ .getActiveSwitchboards())
+ {
+ if (switchboard.equals(board))
+ return true;
+ }
+
+ return false;
+ }
+
+ public boolean isSystem()
+ {
+ return false;
+ }
+
+ /**
+ * Sends the message to the destination indicated by the
+ * to contact.
+ *
+ * @param message The Message to send.
+ * @throws OperationFailedException if the underlying stack is not
+ * registered or initialized or if the chat room is not joined.
+ */
+
+ public void sendMessage(Message message) throws OperationFailedException
+ {
+ if (!isJoined())
+ {
+ throw new OperationFailedException("This chat room is not active.",
+ OperationFailedException.CHAT_ROOM_NOT_JOINED);
+ }
+
+ switchboard.sendText(message.getContent());
+
+ ChatRoomMessageDeliveredEvent msgDeliveredEvt =
+ new ChatRoomMessageDeliveredEvent(this, new Date(), message,
+ ChatRoomMessageDeliveredEvent.CONVERSATION_MESSAGE_DELIVERED);
+
+ fireMessageEvent(msgDeliveredEvt);
+ }
+
+ /**
+ * Sets the subject of this chat room. If the user does not have the right
+ * to change the room subject, or the protocol does not support this, or the
+ * operation fails for some other reason, the method throws an
+ * OperationFailedException with the corresponding code. Note: Not
+ * supported inside the MSN protocol.
+ *
+ * @param subject the new subject that we'd like this room to have
+ * @throws OperationFailedException thrown if the user is not joined to the
+ * channel or if he/she doesn't have enough privileges to change
+ * the topic or if the topic is null.
+ */
+ public void setSubject(String subject) throws OperationFailedException
+ {
+ throw new OperationFailedException("You cannot change the subject!",
+ OperationFailedException.GENERAL_ERROR);
+ }
+
+ /**
+ * Joins this chat room with the nickname of the local user so that the user
+ * would start receiving events and messages for it.
+ *
+ * @throws OperationFailedException with the corresponding code if an error
+ * occurs while joining the room.
+ */
+ public void join() throws OperationFailedException
+ {
+ joinAs(parentProvider.getMessenger().getOwner().getDisplayName());
+ }
+
+ /**
+ * Joins this chat room so that the user would start receiving events and
+ * messages for it. Note: Secured chat rooms are not supported inside the
+ * msn protocol,
+ *
+ * @see join()
+ *
+ * @param password the password to use when authenticating on the chat room.
+ * @throws OperationFailedException with the corresponding code if an error
+ * occurs while joining the room.
+ */
+ public void join(byte[] password) throws OperationFailedException
+ {
+ joinAs(parentProvider.getMessenger().getOwner().getDisplayName());
+ }
+
+ /**
+ * Joins this chat room with the specified nickname so that the user would
+ * start receiving events and messages for it.
+ *
+ * @param nickname the nickname to use.
+ * @param password Not support inside the msn protocol
+ * @throws OperationFailedException with the corresponding code if an error
+ * occurs while joining the room.
+ */
+ public void joinAs(String nickName, byte[] password)
+ throws OperationFailedException
+ {
+ joinAs(parentProvider.getMessenger().getOwner().getDisplayName());
+ }
+
+ /**
+ * Joins this chat room with the specified nickname so that the user would
+ * start receiving events and messages for it.
+ *
+ * @param nickname the nickname to use.
+ * @throws OperationFailedException with the corresponding code if an error
+ * occurs while joining the room.
+ */
+ public void joinAs(String nickName) throws OperationFailedException
+ {
+ ChatRoomMemberMsnImpl member =
+ new ChatRoomMemberMsnImpl(this, nickName, parentProvider
+ .getAccountID().getAccountAddress(), ChatRoomMemberRole.MEMBER);
+
+ members.put(nickName, member);
+
+ // We don't specify a reason.
+ opSetMuc.fireLocalUserPresenceEvent(this,
+ LocalUserChatRoomPresenceChangeEvent.LOCAL_USER_JOINED, null);
+
+ // We buffered the messages before the user has joined the chat, now the
+ // user has joined so we fire them again
+ for (EventObject evt : messageBuffer)
+ {
+ fireMessageEvent(evt);
+ }
+ }
+
+ /**
+ * Leave this chat room. Once this method is called, the user won't be
+ * listed as a member of the chat room any more and no further chat events
+ * will be delivered. Depending on the underlying protocol and
+ * implementation leave() might cause the room to be destroyed if it has
+ * been created by the local user.
+ */
+ public void leave()
+ {
+ if (switchboard != null)
+ {
+ switchboard.close();
+ switchboard = null;
+ }
+ Iterator membersSet = members.entrySet().iterator();
+
+ while (membersSet.hasNext())
+ {
+ Map.Entry memberEntry = (Map.Entry) membersSet.next();
+
+ ChatRoomMember member = (ChatRoomMember) memberEntry.getValue();
+
+ fireMemberPresenceEvent(member,
+ ChatRoomMemberPresenceChangeEvent.MEMBER_LEFT,
+ "Local user has left the chat room.");
+ }
+
+ // Delete the list of members
+ members.clear();
+ }
+
+ /**
+ * Sets the nickName for this chat room.
+ *
+ * @param nickName the nick name to set
+ * @throws OperationFailedException If called, an OpFailedException is
+ * called, because MSN does not support nickname inside chat
+ * rooms.
+ *
+ */
+ public void setUserNickname(String nickname)
+ throws OperationFailedException
+ {
+ throw new OperationFailedException("You cannot set the user nickname!",
+ OperationFailedException.GENERAL_ERROR);
+ }
+
+ /**
+ * Fills the member list with all members inside the switchboard (chat
+ * room).
+ *
+ * @param switchboard The corresponding switchboard
+ */
+ public void updateMemberList(MsnSwitchboard switchboard)
+ {
+ MsnContact[] contacts = switchboard.getAllContacts();
+
+ for (MsnContact msnContact : contacts)
+ {
+ if (!members.containsKey(msnContact.getDisplayName()))
+ { // if the member is not inside the members list, create a member
+ // instance,
+ // add it to the list and fire a member presence event
+ ChatRoomMemberMsnImpl member =
+ new ChatRoomMemberMsnImpl(this,
+ msnContact.getDisplayName(), msnContact.getEmail()
+ .toString(), ChatRoomMemberRole.MEMBER);
+
+ members.put(member.getName(), member);
+
+ fireMemberPresenceEvent(member,
+ ChatRoomMemberPresenceChangeEvent.MEMBER_JOINED, null);
+ }
+ }
+
+ for (String contactAddress: pendingInvitations)
+ {
+ this.invite(contactAddress, "");
+ }
+ }
+
+ public ChatRoomMemberMsnImpl getChatRoomMember(String nickName,
+ String userAdress)
+ {
+ Iterator chatRoomMembers = this.members.values().iterator();
+
+ while (chatRoomMembers.hasNext())
+ {
+ ChatRoomMemberMsnImpl member =
+ (ChatRoomMemberMsnImpl) chatRoomMembers.next();
+
+ if (nickName.equals(member.getName()))
+ return member;
+ }
+ return null;
+ }
+
+ /**
+ * Notifies all interested listeners that a
+ * ChatRoomMessageDeliveredEvent,
+ * ChatRoomMessageReceivedEvent or a
+ * ChatRoomMessageDeliveryFailedEvent has been fired.
+ *
+ * @param evt The specific event
+ */
+ public void fireMessageEvent(EventObject evt)
+ {
+ Iterator listeners = null;
+ synchronized (messageListeners)
+ {
+ listeners = new ArrayList(messageListeners).iterator();
+ }
+
+ if (!listeners.hasNext())
+ {
+ messageBuffer.add(evt);
+ }
+
+ while (listeners.hasNext())
+ {
+ ChatRoomMessageListener listener =
+ (ChatRoomMessageListener) listeners.next();
+
+ if (evt instanceof ChatRoomMessageDeliveredEvent)
+ {
+ listener.messageDelivered((ChatRoomMessageDeliveredEvent) evt);
+ }
+ else if (evt instanceof ChatRoomMessageReceivedEvent)
+ {
+ listener.messageReceived((ChatRoomMessageReceivedEvent) evt);
+ }
+ else if (evt instanceof ChatRoomMessageDeliveryFailedEvent)
+ {
+ listener
+ .messageDeliveryFailed((ChatRoomMessageDeliveryFailedEvent) evt);
+ }
+ }
+ }
+
+ /**
+ * Sets the corresponding switchboard.
+ *
+ * @param switchboard Corresponding switchboard.
+ */
+ public void setSwitchboard(MsnSwitchboard switchboard)
+ {
+ this.switchboard = switchboard;
+ }
+
+ /**
+ * Adds a chat room member to the members list.
+ *
+ * @param member The member to add.
+ */
+ public void addChatRoomMember(ChatRoomMemberMsnImpl member)
+ {
+ members.put(member.getName(), member);
+
+ fireMemberPresenceEvent(member,
+ ChatRoomMemberPresenceChangeEvent.MEMBER_JOINED, null);
+ }
+
+ /**
+ * Removes a chat room member from the and fires a member presence change
+ * event, so that the user gets the leaving information.
+ *
+ * @param member The member to remove.
+ */
+ public void removeChatRoomMember(ChatRoomMemberMsnImpl member)
+ {
+ members.remove(member.getName());
+
+ fireMemberPresenceEvent(member,
+ ChatRoomMemberPresenceChangeEvent.MEMBER_LEFT, null);
+ }
+
+ /**
+ * Creates the corresponding ChatRoomMemberPresenceChangeEvent and notifies
+ * all ChatRoomMemberPresenceListeners that a ChatRoomMember has
+ * joined or left this ChatRoom.
+ *
+ * @param member the ChatRoomMember that this
+ * @param eventID the identifier of the event
+ * @param eventReason the reason of the event
+ */
+ private void fireMemberPresenceEvent(ChatRoomMember member, String eventID,
+ String eventReason)
+ {
+ ChatRoomMemberPresenceChangeEvent evt =
+ new ChatRoomMemberPresenceChangeEvent(this, member, eventID,
+ eventReason);
+
+ logger.trace("Will dispatch the following ChatRoom event: " + evt);
+
+ Iterator listeners = null;
+ synchronized (memberListeners)
+ {
+ listeners = new ArrayList(memberListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ ChatRoomMemberPresenceListener listener =
+ (ChatRoomMemberPresenceListener) listeners.next();
+
+ listener.memberPresenceChanged(evt);
+ }
+ }
+
+ public void setChatRoomName(String name)
+ {
+ this.chatRoomName = name;
+ }
+
+ /**
+ * Determines whether this chat room should be stored in the configuration
+ * file or not. If the chat room is persistent it still will be shown after
+ * a restart in the chat room list. A non-persistent chat room will be only
+ * in the chat room list until the the program is running.
+ *
+ * @return true if this chat room is persistent, false otherwise
+ */
+ public boolean isPersistent()
+ {
+ return false;
+ }
+
+ /**
+ * Finds the member of this chat room corresponding to the given nick name.
+ *
+ * @param nickName the nick name to search for.
+ * @return the member of this chat room corresponding to the given nick name.
+ */
+ public ChatRoomMemberMsnImpl findMemberForNickName(String nickName)
+ {
+ return (ChatRoomMemberMsnImpl) members.get(nickName);
+ }
+}
diff --git a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java
index 262d1a375..f27f94720 100644
--- a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java
+++ b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetBasicInstantMessagingMsnImpl.java
@@ -40,6 +40,7 @@ public class OperationSetBasicInstantMessagingMsnImpl
*/
private OperationSetPersistentPresenceMsnImpl opSetPersPresence = null;
+ private OperationSetMultiUserChatMsnImpl opSetMuc = null;
/**
* Creates an instance of this operation set.
* @param provider a ref to the ProtocolProviderServiceImpl
@@ -50,6 +51,8 @@ public class OperationSetBasicInstantMessagingMsnImpl
ProtocolProviderServiceMsnImpl provider)
{
this.msnProvider = provider;
+ opSetMuc = (OperationSetMultiUserChatMsnImpl) msnProvider
+ .getOperationSet(OperationSetMultiUserChat.class);
provider.addRegistrationStateChangeListener(new RegistrationStateListener());
}
@@ -185,7 +188,11 @@ public void instantMessageReceived(MsnSwitchboard switchboard,
MsnInstantMessage message,
MsnContact contact)
{
- Message newMessage = createMessage(message.getContent());
+ // FILTER OUT THE GROUP MESSAGES
+ if (opSetMuc.isGroupChatMessage(switchboard))
+ return;
+
+ Message newMessage = createMessage(message.getContent());
Contact sourceContact = opSetPersPresence.
findContactByID(contact.getEmail().getEmailAddress());
diff --git a/src/net/java/sip/communicator/impl/protocol/msn/OperationSetMultiUserChatMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetMultiUserChatMsnImpl.java
new file mode 100644
index 000000000..0e6bfc597
--- /dev/null
+++ b/src/net/java/sip/communicator/impl/protocol/msn/OperationSetMultiUserChatMsnImpl.java
@@ -0,0 +1,903 @@
+package net.java.sip.communicator.impl.protocol.msn;
+
+import java.util.*;
+
+import net.java.sip.communicator.service.protocol.*;
+import net.java.sip.communicator.service.protocol.event.*;
+import net.java.sip.communicator.util.Logger;
+import net.sf.jml.*;
+import net.sf.jml.event.*;
+import net.sf.jml.message.*;
+
+/**
+ * A MSN implementation of the multi user chat operation set.
+ *
+ * @author Rupert Burchardi
+ */
+
+public class OperationSetMultiUserChatMsnImpl
+ implements OperationSetMultiUserChat,
+ SubscriptionListener
+{
+ private static final Logger logger =
+ Logger.getLogger(OperationSetMultiUserChatMsnImpl.class);
+
+ /**
+ * A list of listeners subscribed for invitations multi user chat events.
+ */
+ private Vector invitationListeners = new Vector();
+
+ /**
+ * A list of listeners subscribed for events indicating rejection of a multi
+ * user chat invitation sent by us.
+ */
+ private Vector invitationRejectionListeners = new Vector();
+
+ /**
+ * Listeners that will be notified of changes in our status in the room such
+ * as us being kicked, banned, or granted admin permissions.
+ */
+ private Vector presenceListeners = new Vector();
+
+ private OperationSetPersistentPresenceMsnImpl opSetPersPresence = null;
+
+ /**
+ * A list of the rooms that are currently open by this account. Note that
+ * this list only contains chat rooms where the user is not the initiator.
+ */
+ private Hashtable chatRoomCache = new Hashtable();
+
+ /**
+ * A list of the rooms that are currently open and created by this account.
+ */
+ private Hashtable userCreatedChatRoomList = new Hashtable();
+
+ /**
+ * The currently valid MSN protocol provider service implementation.
+ */
+ private ProtocolProviderServiceMsnImpl msnProvider = null;
+
+ /**
+ * Instantiates the user operation set with a currently valid instance of
+ * the MSN protocol provider.
+ *
+ * @param msnProvider a currently valid instance of
+ * ProtocolProviderServiceMsnImpl.
+ */
+ OperationSetMultiUserChatMsnImpl(ProtocolProviderServiceMsnImpl msnProvider)
+ {
+ this.msnProvider = msnProvider;
+
+ msnProvider
+ .addRegistrationStateChangeListener(new RegistrationStateListener());
+
+ OperationSetPersistentPresence presenceOpSet
+ = (OperationSetPersistentPresence) msnProvider
+ .getOperationSet(OperationSetPersistentPresence.class);
+
+ presenceOpSet.addSubscriptionListener(this);
+ }
+
+ /**
+ * Adds a listener to invitation notifications.
+ *
+ * @param listener an invitation listener.
+ */
+ public void addInvitationListener(ChatRoomInvitationListener listener)
+ {
+ synchronized (invitationListeners)
+ {
+ if (!invitationListeners.contains(listener))
+ invitationListeners.add(listener);
+ }
+
+ }
+
+ /**
+ * Removes listener from the list of invitation listeners
+ * registered to receive invitation events.
+ *
+ * @param listener the invitation listener to remove.
+ */
+ public void removeInvitationListener(ChatRoomInvitationListener listener)
+ {
+ synchronized (invitationListeners)
+ {
+ invitationListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Adds a listener to invitation notifications.
+ *
+ * @param listener an invitation listener.
+ */
+ public void addInvitationRejectionListener(
+ ChatRoomInvitationRejectionListener listener)
+ {
+ synchronized (invitationRejectionListeners)
+ {
+ if (!invitationRejectionListeners.contains(listener))
+ invitationRejectionListeners.add(listener);
+ }
+ }
+
+ /**
+ * Removes listener from the list of invitation listeners
+ * registered to receive invitation events.
+ *
+ * @param listener the invitation listener to remove.
+ */
+ public void removeInvitationRejectionListener(
+ ChatRoomInvitationRejectionListener listener)
+ {
+ synchronized (invitationRejectionListeners)
+ {
+ invitationRejectionListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Adds a listener that will be notified of changes in our status in a chat
+ * room such as us being kicked, banned or dropped.
+ *
+ * @param listener the LocalUserChatRoomPresenceListener.
+ */
+ public void addPresenceListener(LocalUserChatRoomPresenceListener listener)
+ {
+ synchronized (presenceListeners)
+ {
+ if (!presenceListeners.contains(listener))
+ presenceListeners.add(listener);
+ }
+ }
+
+ /**
+ * Removes a listener that was being notified of changes in our status in a
+ * room such as us being kicked, banned or dropped.
+ *
+ * @param listener the LocalUserChatRoomPresenceListener.
+ */
+ public void removePresenceListener(
+ LocalUserChatRoomPresenceListener listener)
+ {
+ synchronized (presenceListeners)
+ {
+ presenceListeners.remove(listener);
+ }
+ }
+
+ /**
+ * Returns true if contact supports multi user chat sessions.
+ *
+ * @param contact reference to the contact whose support for chat rooms we
+ * are currently querying.
+ * @return a boolean indicating whether contact supports chatrooms.
+ */
+ public boolean isMultiChatSupportedByContact(Contact contact)
+ {
+ // if (contact.getProtocolProvider().getOperationSet(
+ // OperationSetMultiUserChat.class) != null)
+ // return true;
+ //
+ // return false;
+
+ return true;
+ }
+
+ /**
+ * Creates a room with the named roomName and according to the
+ * specified roomProperties on the server that this protocol
+ * provider is currently connected to.
+ *
+ * @param roomName the name of the ChatRoom to create.
+ * @param roomProperties properties specifying how the room should be
+ * created.
+ *
+ * @throws OperationFailedException if the room couldn't be created for some
+ * reason (e.g. room already exists; user already joined to an
+ * existent room or user has no permissions to create a chat
+ * room).
+ * @throws OperationNotSupportedException if chat room creation is not
+ * supported by this server
+ *
+ * @return ChatRoom the chat room that we've just created.
+ */
+ public ChatRoom createChatRoom( String roomName,
+ Hashtable roomProperties)
+ throws OperationFailedException,
+ OperationNotSupportedException
+ {
+ return findRoom(roomName);
+ }
+
+ /**
+ * Returns a reference to a chatRoom named roomName or creates a
+ * new chat room and puts it into the userCreatedChatRoomList. Note: Only
+ * called by user.
+ *
+ * @param roomName the name of the ChatRoom that we're looking for.
+ * @return the ChatRoom named roomName or null if no such
+ * room exists on the server that this provider is currently
+ * connected to.
+ * @throws OperationFailedException if an error occurs while trying to
+ * discover the room on the server.
+ * @throws OperationNotSupportedException if the server does not support
+ * multi user chat
+ */
+
+ public ChatRoom findRoom(String roomName)
+ throws OperationFailedException,
+ OperationNotSupportedException
+ {
+ assertConnected();
+
+ ChatRoom room = (ChatRoom) chatRoomCache.get(roomName);
+
+ if (room == null)
+ { // when the room hasn't been created, we create it.
+ room = createLocalChatRoomInstance(roomName);
+
+ // we create an identifier object and create a new switchboard
+ // we need to track this object to identify this chatRoom
+ Object id = new Object();
+ msnProvider.getMessenger().newSwitchboard(id);
+ // we put it into a hash table
+ userCreatedChatRoomList.put(id, room);
+ }
+
+ return room;
+ }
+
+ /**
+ * Returns a reference to a chatRoom named roomName. If the chat
+ * room doesn't exist, a new chat room is created for the given
+ * MsnSwitchboard.
+ *
+ * @param switchboard The specific switchboard for the chat room.
+ *
+ * @return the corresponding chat room
+ *
+ * @throws OperationFailedException if an error occurs while trying to
+ * discover the room on the server.
+ * @throws OperationNotSupportedException if the server does not support
+ * multi user chat
+ */
+
+ public ChatRoom findRoom(MsnSwitchboard switchboard)
+ throws OperationFailedException,
+ OperationNotSupportedException
+ {
+ assertConnected();
+
+ ChatRoomMsnImpl room =
+ (ChatRoomMsnImpl) chatRoomCache.get(String.valueOf(switchboard
+ .hashCode()));
+
+ if (room == null)
+ {
+ String name = String.valueOf(switchboard.hashCode());
+ room = createChatRoom(name, switchboard);
+ room.setSwitchboard(switchboard);
+ room.updateMemberList(switchboard);
+
+ chatRoomCache.put(name, room);
+
+ // fireInvitationEvent(room,
+ // switchboard.getMessenger().getOwner().getDisplayName(),
+ // "You have been invited to a group chat", null);
+ room.join();
+ }
+
+ return room;
+ }
+
+ /**
+ * Creates a ChatRoom from the specified chatRoomName.
+ *
+ * @param chatRoomName the specific chat room name.
+ *
+ * @return ChatRoom the chat room that we've just created.
+ */
+ private ChatRoom createLocalChatRoomInstance(String chatRoomName)
+ {
+ synchronized (chatRoomCache)
+ {
+ ChatRoomMsnImpl chatRoom =
+ new ChatRoomMsnImpl(chatRoomName, msnProvider);
+
+ this.chatRoomCache.put(chatRoom.getName(), chatRoom);
+ return chatRoom;
+ }
+ }
+
+ /**
+ * Creates a ChatRoom from the specified chatRoomName and the
+ * corresponding switchboard.
+ *
+ * @param chatRoomName the specific chat room name.
+ * @param switchboard The corresponding switchboard.
+ *
+ * @return ChatRoom the chat room that we've just created.
+ */
+ private ChatRoomMsnImpl createChatRoom(String chatRoomName,
+ MsnSwitchboard switchboard)
+ {
+ synchronized (chatRoomCache)
+ {
+ ChatRoomMsnImpl chatRoom =
+ new ChatRoomMsnImpl(chatRoomName, msnProvider, switchboard);
+
+ this.chatRoomCache.put(chatRoom.getName(), chatRoom);
+ return chatRoom;
+ }
+
+ }
+
+ /**
+ * Makes sure that we are properly connected.
+ *
+ * @throws OperationFailedException if the provider is not connected.
+ * @throws OperationNotSupportedException if the service is not supported by
+ * the server.
+ */
+ private void assertConnected()
+ throws OperationFailedException,
+ OperationNotSupportedException
+ {
+ if (msnProvider == null)
+ throw new IllegalStateException(
+ "The provider must be non-null and signed on the "
+ + "service before being able to communicate.");
+ if (!msnProvider.isRegistered())
+ throw new IllegalStateException(
+ "The provider must be signed on the service before "
+ + "being able to communicate.");
+ }
+
+ /**
+ * Returns a list of the chat rooms that we have joined and are currently
+ * active in.
+ *
+ * @return a List of the rooms where the user has joined using a
+ * given connection.
+ */
+ public List getCurrentlyJoinedChatRooms()
+ {
+ synchronized (chatRoomCache)
+ {
+ List joinedRooms = new LinkedList(this.chatRoomCache.values());
+
+ Iterator joinedRoomsIter = joinedRooms.iterator();
+
+ while (joinedRoomsIter.hasNext())
+ {
+ if (!((ChatRoom) joinedRoomsIter.next()).isJoined())
+ joinedRoomsIter.remove();
+ }
+
+ return joinedRooms;
+ }
+ }
+
+ /**
+ * Returns a list of the names of all chat rooms that contact is
+ * currently a member of.
+ *
+ * @param contact the contact whose current ChatRooms we will be querying.
+ * @return a list of String indicating the names of the chat rooms
+ * that contact has joined and is currently active in.
+ *
+ * @throws OperationFailedException if an error occurs while trying to
+ * discover the room on the server.
+ * @throws OperationNotSupportedException if the server does not support
+ * multi user chat
+ */
+ public List getCurrentlyJoinedChatRooms(ChatRoomMember chatRoomMember)
+ throws OperationFailedException,
+ OperationNotSupportedException
+ {
+ synchronized (chatRoomCache)
+ {
+ List joinedRooms = new LinkedList(this.chatRoomCache.values());
+
+ Iterator joinedRoomsIter = joinedRooms.iterator();
+
+ while (joinedRoomsIter.hasNext())
+ {
+ if (!((ChatRoom) joinedRoomsIter.next()).isJoined())
+ joinedRoomsIter.remove();
+ }
+
+ return joinedRooms;
+ }
+ }
+
+ /**
+ * Note: This is not supported inside the MSN, so we just return an empty
+ * list.
+ */
+ public List getExistingChatRooms()
+ throws OperationFailedException,
+ OperationNotSupportedException
+ {
+ // we dont have any available chat rooms on the server.
+
+ return new LinkedList();
+ }
+
+ /**
+ * Note: Not supported inside the MSN.
+ */
+
+ public void rejectInvitation(ChatRoomInvitation invitation,
+ String rejectReason)
+ {
+ // there is no way to block invitations, because there arn't any
+ // invitations.
+ // the only way would be to block the Friend and that shouldn't be done
+ // here.
+ return;
+ }
+
+ /**
+ * Creates a message by a given message text.
+ *
+ * @param messageText The message text.
+ * @return the newly created message.
+ */
+
+ public Message createMessage(String messageText)
+ {
+ return new MessageMsnImpl(messageText,
+ OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE,
+ OperationSetBasicInstantMessaging.DEFAULT_MIME_ENCODING, null);
+ }
+
+ /**
+ * Checks if an incoming message is a multi user chat message. This is done
+ * by the switchboard, if it is not created by the user, its an active file
+ * transfer switchboard or the user count is too low then this method return
+ * false.
+ *
+ * @param switchboard The corresponding MSNswitchboard.
+ * @return True if it is a group chat message or false in the other case.
+ */
+
+ public boolean isGroupChatMessage(MsnSwitchboard switchboard)
+ {
+ // //fileTransfer??
+ // if (switchboard.getActiveFileTransfers() != null)
+ // return false;
+
+ Object attachment = switchboard.getAttachment();
+ if (attachment == null)
+ { // the user did not created the chat room by him/her self,
+ // the only way to figure out if this is a group chat message
+ // is to check the user count
+ return (switchboard.getAllContacts().length > 1);
+
+ }
+
+ return userCreatedChatRoomList.containsKey(attachment);
+ }
+
+ protected void fireInvitationEvent(ChatRoom targetChatRoom, String inviter,
+ String reason, byte[] password)
+ {
+ ChatRoomInvitationMsnImpl invitation =
+ new ChatRoomInvitationMsnImpl(targetChatRoom, inviter, reason,
+ password);
+
+ ChatRoomInvitationReceivedEvent evt =
+ new ChatRoomInvitationReceivedEvent(this, invitation, new Date(
+ System.currentTimeMillis()));
+
+ Iterator listeners = null;
+ synchronized (invitationListeners)
+ {
+ listeners = new ArrayList(invitationListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ ChatRoomInvitationListener listener =
+ (ChatRoomInvitationListener) listeners.next();
+
+ listener.invitationReceived(evt);
+ }
+ }
+
+ /**
+ * Delivers a LocalUserChatRoomPresenceChangeEvent to all
+ * registered LocalUserChatRoomPresenceListeners.
+ *
+ * @param chatRoom the ChatRoom which has been joined, left, etc.
+ * @param eventType the type of this event; one of LOCAL_USER_JOINED,
+ * LOCAL_USER_LEFT, etc.
+ * @param reason the reason
+ */
+ public void fireLocalUserPresenceEvent(ChatRoom chatRoom, String eventType,
+ String reason)
+ {
+ LocalUserChatRoomPresenceChangeEvent evt =
+ new LocalUserChatRoomPresenceChangeEvent(this, chatRoom, eventType,
+ reason);
+
+ Iterator listeners = null;
+ synchronized (presenceListeners)
+ {
+ listeners = new ArrayList(presenceListeners).iterator();
+ }
+
+ while (listeners.hasNext())
+ {
+ LocalUserChatRoomPresenceListener listener =
+ (LocalUserChatRoomPresenceListener) listeners.next();
+
+ listener.localUserPresenceChanged(evt);
+ }
+ }
+
+ /**
+ * Our listener that will tell us when we're registered to msn.
+ *
+ */
+ private class RegistrationStateListener
+ implements RegistrationStateChangeListener
+ {
+ /**
+ * The method is called by a ProtocolProvider implementation whenever a
+ * change in the registration state of the corresponding provider had
+ * occurred.
+ *
+ * @param evt ProviderStatusChangeEvent the event describing the status
+ * change.
+ */
+ public void registrationStateChanged(RegistrationStateChangeEvent evt)
+ {
+ if (evt.getNewState() == RegistrationState.REGISTERED)
+ {
+
+ opSetPersPresence =
+ (OperationSetPersistentPresenceMsnImpl) msnProvider
+ .getSupportedOperationSets().get(
+ OperationSetPersistentPresence.class.getName());
+
+ msnProvider.getMessenger().addSwitchboardListener(
+ new MsnSwitchboardListener());
+ msnProvider.getMessenger().addMessageListener(
+ new MsnMessageListener());
+ }
+ }
+
+ }
+
+ /**
+ * Our group chat message listener, it extends the MsnMessageAdapter from
+ * the the jml library.
+ *
+ */
+ private class MsnMessageListener
+ extends MsnMessageAdapter
+ implements MsnEmailListener
+ {
+ public void instantMessageReceived(MsnSwitchboard switchboard,
+ MsnInstantMessage message, MsnContact contact)
+ {
+ if (!isGroupChatMessage(switchboard))
+ return;
+
+ Message newMessage = createMessage(message.getContent());
+
+ Contact sourceContact =
+ opSetPersPresence.findContactByID(contact.getEmail()
+ .getEmailAddress());
+
+ logger.debug("Group chat message received.");
+ Object attachment = switchboard.getAttachment();
+ try
+ {
+ ChatRoomMsnImpl chatRoom = null;
+
+ if (attachment == null) // chat room session NOT created by
+ // yourself
+ chatRoom = (ChatRoomMsnImpl) findRoom(switchboard);
+
+ // user created chat room session?
+ if (attachment != null
+ && userCreatedChatRoomList.containsKey(attachment))
+ chatRoom =
+ (ChatRoomMsnImpl) userCreatedChatRoomList
+ .get(attachment);
+
+ if (chatRoom == null)
+ return;
+
+ ChatRoomMemberMsnImpl member =
+ chatRoom.getChatRoomMember(contact.getDisplayName(),
+ contact.getEmail().getEmailAddress());
+
+ ChatRoomMessageReceivedEvent msgReceivedEvent =
+ new ChatRoomMessageReceivedEvent(
+ chatRoom,
+ member,
+ new Date(),
+ newMessage,
+ ChatRoomMessageReceivedEvent.CONVERSATION_MESSAGE_RECEIVED);
+
+ chatRoom.fireMessageEvent(msgReceivedEvent);
+
+ }
+ catch (OperationFailedException e)
+ {
+ logger.error("Failed to find room with name: ", e);
+ }
+ catch (OperationNotSupportedException e)
+ {
+ logger.error("Failed to find room with name: ", e);
+ }
+
+ }
+
+ public void initialEmailNotificationReceived(
+ MsnSwitchboard switchboard, MsnEmailInitMessage message,
+ MsnContact contact)
+ {
+ }
+
+ public void initialEmailDataReceived(MsnSwitchboard switchboard,
+ MsnEmailInitEmailData message, MsnContact contact)
+ {
+ }
+
+ public void newEmailNotificationReceived(MsnSwitchboard switchboard,
+ MsnEmailNotifyMessage message, MsnContact contact)
+ {
+
+ }
+
+ public void activityEmailNotificationReceived(
+ MsnSwitchboard switchboard, MsnEmailActivityMessage message,
+ MsnContact contact)
+ {
+ }
+ }
+
+ /**
+ * The Switchboard Listener, listens to all four switchboard events:
+ * Switchboard started/closed and User joins/left.
+ *
+ */
+ private class MsnSwitchboardListener
+ extends MsnSwitchboardAdapter
+ {
+ public void contactJoinSwitchboard(MsnSwitchboard switchboard,
+ MsnContact contact)
+ {
+ logger.debug(contact.getDisplayName()
+ + " has joined the Switchboard");
+ if (!isGroupChatMessage(switchboard))
+ return;
+
+ Object attachment = switchboard.getAttachment();
+ try
+ {
+ ChatRoomMsnImpl chatRoom = null;
+ if (attachment == null) // chat room session NOT created by
+ // yourself
+ chatRoom = (ChatRoomMsnImpl) findRoom(switchboard);
+
+ // user created chat room session?
+ if (attachment != null
+ && userCreatedChatRoomList.containsKey(attachment))
+ chatRoom =
+ (ChatRoomMsnImpl) userCreatedChatRoomList
+ .get(attachment);
+
+ if (chatRoom == null)
+ return;
+
+ ChatRoomMemberMsnImpl member =
+ chatRoom.getChatRoomMember(contact.getDisplayName(),
+ contact.getEmail().getEmailAddress());
+ if (member == null)
+ {
+ member =
+ new ChatRoomMemberMsnImpl(chatRoom, contact
+ .getDisplayName(), contact.getEmail().toString(),
+ ChatRoomMemberRole.MEMBER);
+ chatRoom.addChatRoomMember(member);
+ }
+ }
+ catch (Exception e)
+ {
+
+ }
+
+ }
+
+ public void contactLeaveSwitchboard(MsnSwitchboard switchboard,
+ MsnContact contact)
+ {
+ logger
+ .debug(contact.getDisplayName() + " has left the Switchboard");
+
+ Object attachment = switchboard.getAttachment();
+
+ try
+ {
+ ChatRoomMsnImpl chatRoom = null;
+ if (attachment == null)// chat room session NOT created by
+ // yourself
+ chatRoom = (ChatRoomMsnImpl) findRoom(switchboard);
+
+ // user created chat room session?
+ if (attachment != null
+ && userCreatedChatRoomList.containsKey(attachment))
+ chatRoom =
+ (ChatRoomMsnImpl) userCreatedChatRoomList
+ .get(attachment);
+
+ if (chatRoom == null)
+ return;
+
+ ChatRoomMemberMsnImpl member =
+ chatRoom.getChatRoomMember(contact.getDisplayName(),
+ contact.getEmail().getEmailAddress());
+
+ if (member != null)
+ {
+ chatRoom.removeChatRoomMember(member);
+ }
+ }
+ catch (OperationFailedException e)
+ {
+ logger.debug( "Could not find a chat room corresponding" +
+ "to the given switchboard.", e);
+ }
+ catch (OperationNotSupportedException e)
+ {
+ logger.debug( "Could not find a chat room corresponding" +
+ "to the given switchboard.", e);
+ }
+ }
+
+ public void switchboardClosed(MsnSwitchboard switchboard)
+ {
+ logger.debug("Switchboard closed.");
+
+ Object attachment = switchboard.getAttachment();
+ try
+ {
+ ChatRoomMsnImpl chatRoom = null;
+ if (attachment == null)// chat room session NOT created by
+ // yourself
+ chatRoom = (ChatRoomMsnImpl) findRoom(switchboard);
+ // user created chat room session?
+ if (attachment != null
+ && userCreatedChatRoomList.containsKey(attachment))
+ chatRoom =
+ (ChatRoomMsnImpl) userCreatedChatRoomList
+ .get(attachment);
+
+ if (chatRoom == null)
+ return;
+
+ chatRoom.setSwitchboard(null);
+
+ // chatRoom.leave();
+ // fireLocalUserPresenceEvent(chatRoom,
+ // LocalUserChatRoomPresenceChangeEvent.LOCAL_USER_DROPPED ,
+ // "Switchboard closed.");
+ }
+ catch (Exception e)
+ {
+ }
+ }
+
+ public void switchboardStarted(MsnSwitchboard switchboard)
+ {
+ logger.debug("Switchboard started.");
+ Object switchboardID = switchboard.getAttachment();
+ try
+ {
+ ChatRoomMsnImpl chatRoom = null;
+ if (switchboardID != null
+ && userCreatedChatRoomList.containsKey(switchboardID))
+ {
+ chatRoom =
+ (ChatRoomMsnImpl) userCreatedChatRoomList
+ .get(switchboardID);
+
+ chatRoom.setSwitchboard(switchboard);
+ chatRoom.updateMemberList(switchboard);
+ chatRoom.join();
+ }
+
+ }
+ catch (OperationFailedException ofe)
+ {
+ logger.debug("Could not join the ChatRoom: " + ofe);
+ }
+ }
+ }
+
+ /**
+ * Updates corresponding chat room members when a contact has been modified
+ * in our contact list.
+ */
+ public void contactModified(ContactPropertyChangeEvent evt)
+ {
+ Contact modifiedContact = evt.getSourceContact();
+
+ this.updateChatRoomMembers(modifiedContact);
+ }
+
+ /**
+ * Updates corresponding chat room members when a contact has been created
+ * in our contact list.
+ */
+ public void subscriptionCreated(SubscriptionEvent evt)
+ {
+ Contact createdContact = evt.getSourceContact();
+
+ this.updateChatRoomMembers(createdContact);
+ }
+
+ /**
+ * Not interested in this event for our member update purposes.
+ */
+ public void subscriptionFailed(SubscriptionEvent evt)
+ {}
+
+ /**
+ * Not interested in this event for our member update purposes.
+ */
+ public void subscriptionMoved(SubscriptionMovedEvent evt)
+ {}
+
+ /**
+ * Updates corresponding chat room members when a contact has been removed
+ * from our contact list.
+ */
+ public void subscriptionRemoved(SubscriptionEvent evt)
+ {
+ // Set to null the contact reference in all corresponding chat room
+ // members.
+ this.updateChatRoomMembers(null);
+ }
+
+ /**
+ * Not interested in this event for our member update purposes.
+ */
+ public void subscriptionResolved(SubscriptionEvent evt)
+ {}
+
+ /**
+ * Finds all chat room members, which name corresponds to the name of the
+ * given contact and updates their contact references.
+ *
+ * @param contact the contact we're looking correspondences for.
+ */
+ private void updateChatRoomMembers(Contact contact)
+ {
+ Enumeration