From 48362732b92bff7b0e389b0238a4a2bef7614070 Mon Sep 17 00:00:00 2001 From: Yana Stamcheva Date: Mon, 3 Nov 2008 15:17:54 +0000 Subject: [PATCH] MSN implementation of group chat provided by Rupert Burchardi. --- .../msn/ChatRoomInvitationMsnImpl.java | 89 ++ .../protocol/msn/ChatRoomMemberMsnImpl.java | 186 ++++ .../impl/protocol/msn/ChatRoomMsnImpl.java | 952 ++++++++++++++++++ ...rationSetBasicInstantMessagingMsnImpl.java | 9 +- .../msn/OperationSetMultiUserChatMsnImpl.java | 903 +++++++++++++++++ .../msn/ProtocolProviderServiceMsnImpl.java | 37 +- 6 files changed, 2161 insertions(+), 15 deletions(-) create mode 100644 src/net/java/sip/communicator/impl/protocol/msn/ChatRoomInvitationMsnImpl.java create mode 100644 src/net/java/sip/communicator/impl/protocol/msn/ChatRoomMemberMsnImpl.java create mode 100644 src/net/java/sip/communicator/impl/protocol/msn/ChatRoomMsnImpl.java create mode 100644 src/net/java/sip/communicator/impl/protocol/msn/OperationSetMultiUserChatMsnImpl.java diff --git a/src/net/java/sip/communicator/impl/protocol/msn/ChatRoomInvitationMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/ChatRoomInvitationMsnImpl.java new file mode 100644 index 000000000..5952cf01f --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/msn/ChatRoomInvitationMsnImpl.java @@ -0,0 +1,89 @@ +/* + * SIP Communicator, 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.msn; + +import net.java.sip.communicator.service.protocol.*; + +/** + * The MSN implementation of the ChatRoomInvitation interface. + * @author Rupert Burchardi + */ +public class ChatRoomInvitationMsnImpl implements ChatRoomInvitation +{ + /** + * Corresponding chat room instance. + */ + private ChatRoom chatRoom; + /** + * The name of the inviter + */ + private String inviter; + /** + * The invitation reason. Note: Not supported in the msn protocol. + */ + private String reason; + + /** + * The password. Note: Not supported in the msn protocol. + */ + private byte[] password; + + /** + * Creates an instance of the ChatRoomInvitationMsnImpl by + * specifying the targetChatRoom, the inviter, the reason and the password. + * + * @param targetChatRoom The ChatRoom for which the invitation is + * @param inviter The ChatRoomMember, which sent the invitation + * @param reason The Reason for the invitation + * @param password The password + */ + public ChatRoomInvitationMsnImpl(ChatRoom targetChatRoom, + String inviter, + String reason, + byte[] password) + { + this.chatRoom = targetChatRoom; + this.inviter = inviter; + this.reason = reason; + this.password = password; + } + + /** + * Returns the corresponding chat room. + * @return The chat room + */ + public ChatRoom getTargetChatRoom() + { + return chatRoom; + } + + /** + * Returns the corresponding inviter. + * @return The name of the inviter + */ + public String getInviter() + { + return inviter; + } + + /** + * Returns the invitation reason. + * @return the invitation reason + */ + public String getReason() + { + return reason; + } + /** + * Returns the password of the chat room. + * @return The password + */ + public byte[] getChatRoomPassword() + { + return password; + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/msn/ChatRoomMemberMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/ChatRoomMemberMsnImpl.java new file mode 100644 index 000000000..77859666f --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/msn/ChatRoomMemberMsnImpl.java @@ -0,0 +1,186 @@ +/* + * SIP Communicator, 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.msn; + +import net.java.sip.communicator.service.protocol.*; + +/** + * Represents a chat room member. + * + * @author Rupert Burchardi + */ + +public class ChatRoomMemberMsnImpl implements ChatRoomMember +{ + /** + * The ChatRoom, where the member is joined. + */ + private ChatRoomMsnImpl containingRoom = null; + + /** + * The email address of the user. + */ + private String userAddress = null; + + /** + * The role of this member. + */ + private ChatRoomMemberRole memberRole = null; + + /** + * The nickname of the user. + */ + private String nickName = null; + + /** + * The contact from our server stored contact list corresponding to this + * member. + */ + private Contact contact; + + /** + * The avatar of this chat room member. + */ + private byte[] avatar; + + /** + * Creates an instance of ChatRoomMemberMsnImpl, by specifying + * the corresponding chat room, where this member is joined, the nickname + * (display name) and the user address (email address) and finally the role + * that this contact has in the chat room. + * + * @param chatRoom + * The chat room, where this member is joined + * @param nickName + * The nick of the member (display name) + * @param userAddress + * The identifier of the member (email address) + * @param role + * The role of the member inside the chat room + */ + + public ChatRoomMemberMsnImpl(ChatRoomMsnImpl chatRoom, String nickName, + String userAddress, ChatRoomMemberRole role) + { + this.containingRoom = chatRoom; + this.nickName = nickName; + this.userAddress = userAddress; + this.memberRole = role; + + OperationSetPersistentPresenceMsnImpl presenceOpSet + = (OperationSetPersistentPresenceMsnImpl) chatRoom.getParentProvider() + .getOperationSet(OperationSetPersistentPresence.class); + + this.contact = presenceOpSet.findContactByID(userAddress); + + // If we have found a contact we set also its avatar. + if (contact != null) + this.avatar = contact.getImage(); + } + + /** + * Returns the chat room that this member is participating in. + * + * @return the ChatRoom instance that this member belongs to. + */ + public ChatRoom getChatRoom() + { + return containingRoom; + } + + /** + * Returns the contact identifier representing this contact. For MSN this + * method returns the email address of the user. + * + * @return a String (contact address), uniquely representing the contact + * over the service being used by the associated protocol provider + * instance + */ + public String getContactAddress() + { + return userAddress; + } + + /** + * Returns the name of the member as he/she is known in its containing chat + * room (display name). + * + * @return The users display name. + */ + public String getName() + { + return nickName; + } + + /** + * Returns the protocol provider instance that this member has originated + * in. + * + * @return the ProtocolProviderService instance that created this + * member and its containing chat room + */ + public ProtocolProviderService getProtocolProvider() + { + return containingRoom.getParentProvider(); + } + + /** + * Returns the role of this chat room member in its containing room. + * + * @return a ChatRoomMemberRole instance indicating the role the + * this member in its containing chat room. + */ + public ChatRoomMemberRole getRole() + { + return memberRole; + } + + /** + * Returns the avatar of this member, that can be used when including it in + * user interface. + * + * @return an avatar (e.g. user photo) of this member. + */ + public byte[] getAvatar() + { + return avatar; + } + + /** + * Sets the avatar for this member. + * + * @param avatar the avatar to set. + */ + public void setAvatar(byte[] avatar) + { + this.avatar = avatar; + } + + /** + * Returns the protocol contact corresponding to this member in our contact + * list. The contact returned here could be used by the user interface to + * check if this member is contained in our contact list and in function of + * this to show additional information add additional functionality. + * + * @return the protocol contact corresponding to this member in our contact + * list. + */ + public Contact getContact() + { + return contact; + } + + /** + * Sets the given contact to this member. + * + * @param contact the contact to set. + */ + public void setContact(Contact contact) + { + this.contact = contact; + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/msn/ChatRoomMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/ChatRoomMsnImpl.java new file mode 100644 index 000000000..41be4ba4d --- /dev/null +++ b/src/net/java/sip/communicator/impl/protocol/msn/ChatRoomMsnImpl.java @@ -0,0 +1,952 @@ +/* + * SIP Communicator, 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.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.*; +import net.sf.jml.*; + +/** + * Represents a chat room, where multiple chat users could communicate in a + * many-to-many fashion. + * + * @author Rupert Burchardi + */ + +public class ChatRoomMsnImpl + implements ChatRoom +{ + private static final Logger logger = + Logger.getLogger(ChatRoomMsnImpl.class); + + /** + * The parent protocol service provider. + */ + private ProtocolProviderServiceMsnImpl parentProvider = null; + + /** + * List of the members of the chat room. + */ + private Hashtable members = new Hashtable(); + + /** + * List of unresolved member names. + */ + private ArrayList pendingInvitations = new ArrayList(); + + /** + * List of the users that are banned. Note: Not possible inside the MSN + * protocol, the list is always empty. + */ + private Hashtable banList = new Hashtable(); + + /** + * The chat rooms name. + */ + private String chatRoomName = null; + + /** + * The nick name of the user inside this chat room. Note: display name of + * the user. + */ + private String nickname; + + /** + * The subject of the chat room. Note: Not possible inside the MSN protocol. + */ + private String chatSubject = null; + + /** + * The old chat room subject. + * + * @see chatSubject. + */ + private String oldSubject; + + /** + * The corresponding switchboard for the chat room. Each chat room has its + * own switchboard and if it is closed the user cannot reconnect to it, see + * MSN documentation for further infos. + */ + private MsnSwitchboard switchboard = null; + + /** + * The OperationSet for MSN multi user chats. + */ + private OperationSetMultiUserChatMsnImpl opSetMuc = null; + + /** + * Listeners that will be notified of changes in member status in the room + * such as member joined, left or being kicked or dropped. + */ + private Vector memberListeners = new Vector(); + + /** + * Listeners that will be notified of changes in member role in the room + * such as member being granted admin permissions, or revoked admin + * permissions. + */ + private Vector memberRoleListeners = new Vector(); + + /** + * Listeners that will be notified of changes in local user role in the room + * such as member being granted administrator permissions, or revoked + * administrator permissions. + */ + private Vector localUserRoleListeners = new Vector(); + + /** + * Listeners that will be notified every time a new message is received on + * this chat room. + */ + private Vector messageListeners = new Vector(); + + /** + * Listeners that will be notified every time a chat room property has been + * changed. + */ + private Vector propertyChangeListeners = new Vector(); + + /** + * Listeners that will be notified every time a chat room member property + * has been changed. + */ + private Vector memberPropChangeListeners = new Vector(); + + /** + * A Message buffer, will keep all messages until the msn chatroom is ready. + */ + public Vector messageBuffer = new Vector(); + + private String invitationMessage = ""; + + /** + * Default Invitation message. + */ + private final String DEFAULT_INVITATION = "Please join my chat room!"; + + /** + * Creates an instance of ChatRoomMsnImpl, by specifying the name + * of the chat room and the protocol provider. + * + * @param chatRoomName Name of the chat room. + * @param provider Protocol provider. + */ + public ChatRoomMsnImpl( String chatRoomName, + ProtocolProviderServiceMsnImpl provider) + { + this.chatRoomName = chatRoomName; + this.parentProvider = provider; + this.opSetMuc = + (OperationSetMultiUserChatMsnImpl) this.parentProvider + .getOperationSet(OperationSetMultiUserChat.class); + } + + /** + * Creates an instance of ChatRoomMsnImpl, by specifying the name + * of the chat room, the protocol provider and the corresponding + * switchboard. + * + * @param chatRoomName Name of the chat room. + * @param provider Protocol provider. + * @param switchboard The corresponding switchboard. + */ + public ChatRoomMsnImpl( String chatRoomName, + ProtocolProviderServiceMsnImpl provider, + MsnSwitchboard switchboard) + { + this.chatRoomName = chatRoomName; + this.parentProvider = provider; + this.opSetMuc = + (OperationSetMultiUserChatMsnImpl) this.parentProvider + .getOperationSet(OperationSetMultiUserChat.class); + this.switchboard = switchboard; + } + + /** + * Adds a listener that will be notified of changes in our role in the room + * such as us being granded operator. + * + * @param listener a local user role listener. + */ + public void addLocalUserRoleListener(ChatRoomLocalUserRoleListener listener) + { + synchronized (localUserRoleListeners) + { + if (!localUserRoleListeners.contains(listener)) + localUserRoleListeners.add(listener); + } + } + + /** + * Removes a listener that was being notified of changes in our role in this + * chat room such as us being granded operator. + * + * @param listener a local user role listener. + */ + public void removelocalUserRoleListener( + ChatRoomLocalUserRoleListener listener) + { + synchronized (localUserRoleListeners) + { + if (localUserRoleListeners.contains(listener)) + localUserRoleListeners.remove(listener); + } + } + + /** + * Adds a listener that will be notified of changes in our status in the + * room such as us being kicked, banned, or granted admin permissions. + * + * @param listener a participant status listener. + */ + public void addMemberPresenceListener( + ChatRoomMemberPresenceListener listener) + { + synchronized (memberListeners) + { + if (!memberListeners.contains(listener)) + memberListeners.add(listener); + } + } + + /** + * Removes a listener that was being notified of changes in the status of + * other chat room participants such as users being kicked, banned, or + * granted admin permissions. + * + * @param listener a participant status listener. + */ + public void removeMemberPresenceListener( + ChatRoomMemberPresenceListener listener) + { + synchronized (memberListeners) + { + memberListeners.remove(listener); + } + } + + /** + * Registers listener so that it would receive events every time a + * new message is received on this chat room. + * + * @param listener a MessageListener that would be notified every + * time a new message is received on this chat room. + */ + public void addMessageListener(ChatRoomMessageListener listener) + { + synchronized (messageListeners) + { + if (!messageListeners.contains(listener)) + messageListeners.add(listener); + } + } + + /** + * Removes listener so that it won't receive any further message + * events from this room. + * + * @param listener the MessageListener to remove from this room + */ + public void removeMessageListener(ChatRoomMessageListener listener) + { + synchronized (messageListeners) + { + if (messageListeners.contains(listener)) + messageListeners.remove(messageListeners.indexOf(listener)); + } + } + + /** + * Adds listener to the list of listeners registered to receive + * events upon modification of chat room properties such as its subject for + * example. + * + * @param listener the ChatRoomChangeListener that is to be + * registered for ChatRoomChangeEvent-s. + */ + public void addMemberPropertyChangeListener( + ChatRoomMemberPropertyChangeListener listener) + { + synchronized (memberPropChangeListeners) + { + if (!memberPropChangeListeners.contains(listener)) + memberPropChangeListeners.add(listener); + } + + } + + /** + * Removes listener from the list of listeneres current registered + * for chat room modification events. + * + * @param listener the ChatRoomChangeListener to remove. + */ + public void removeMemberPropertyChangeListener( + ChatRoomMemberPropertyChangeListener listener) + { + synchronized (memberPropChangeListeners) + { + memberPropChangeListeners.remove(listener); + } + } + + /** + * Adds a listener that will be notified of changes of a member role in the + * room such as being granded operator. + * + * @param listener a member role listener. + */ + public void addMemberRoleListener(ChatRoomMemberRoleListener listener) + { + synchronized (memberRoleListeners) + { + if (!memberRoleListeners.contains(listener)) + memberRoleListeners.add(listener); + } + } + + /** + * Removes a listener that was being notified of changes of a member role in + * this chat room such as us being granded operator. + * + * @param listener a member role listener. + */ + public void removeMemberRoleListener(ChatRoomMemberRoleListener listener) + { + synchronized (memberRoleListeners) + { + if (memberRoleListeners.contains(listener)) + memberRoleListeners.remove(listener); + } + } + + /** + * Adds the given listener to the list of listeners registered to + * receive events upon modification of chat room member properties such as + * its nickname being changed for example. + * + * @param listener the ChatRoomMemberPropertyChangeListener that is + * to be registered for + * ChatRoomMemberPropertyChangeEvents. + */ + public void addPropertyChangeListener( + ChatRoomPropertyChangeListener listener) + { + synchronized (propertyChangeListeners) + { + if (!propertyChangeListeners.contains(listener)) + propertyChangeListeners.add(listener); + } + } + + /** + * Removes the given listener from the list of listeners currently + * registered for chat room member property change events. + * + * @param listener the ChatRoomMemberPropertyChangeListener to + * remove. + */ + public void removePropertyChangeListener( + ChatRoomPropertyChangeListener listener) + { + synchronized (propertyChangeListeners) + { + propertyChangeListeners.remove(listener); + } + } + + /** + * Bans a user from the room. The MSN protocol does not support blocking a + * chat room for a specific user, so this method will always throw an + * OperationFailedException. + * + * @param chatRoomMember the ChatRoomMember to be banned. + * @param reason the reason why the user was banned. + * @throws OperationFailedException Always throws such an Exception, because + * user banning based on chatrooms is not possible. + */ + public void banParticipant(ChatRoomMember chatRoomMember, String reason) + throws OperationFailedException + { + throw new OperationFailedException( + "This operation is not possible to perform inside the msn protocol.", + OperationFailedException.GENERAL_ERROR); + } + + /** + * Kicks a participant from the room. The MSN protocol does not support + * this. + * + * @param member the ChatRoomMember to kick from the room + * @param reason the reason why the participant is being kicked from the + * room + * @throws OperationFailedException Always throws an + * OperationFailedException, because you cannot kick users from + * a switchboard in the msn protocol. + */ + + public void kickParticipant(ChatRoomMember chatRoomMember, String reason) + throws OperationFailedException + { + throw new OperationFailedException( + "This operation is not possible to perform inside the msn protocol.", + OperationFailedException.GENERAL_ERROR); + } + + /** + * Create a Message instance for sending arbitrary MIME-encoding content. + * + * @param content content value + * @param contentType the MIME-type for content + * @param contentEncoding encoding used for content + * @param subject a String subject or null for now + * subject. + * @return the newly created message. + */ + public Message createMessage(byte[] content, String contentType, + String contentEncoding, String subject) + { + return new MessageMsnImpl(new String(content), contentType, + contentEncoding, subject); + } + + /** + * Create a Message instance for sending a simple text messages with default + * (text/plain) content type and encoding. + * + * @param messageText the string content of the message. + * @return Message the newly created message + */ + public Message createMessage(String messageText) + { + Message msg = + new MessageMsnImpl(messageText, + OperationSetBasicInstantMessaging.DEFAULT_MIME_TYPE, + OperationSetBasicInstantMessaging.DEFAULT_MIME_ENCODING, null); + + return msg; + } + + /** + * Returns the list of banned users. + */ + public Iterator getBanList() throws OperationFailedException + { + return banList.values().iterator(); + } + + /** + * Returns the ChatRoomConfigurationForm containing all + * configuration properties for this chat room. MSN does not support any + * chat room configuration, so an OperationFailedException is always thrown. + * + * @return the ChatRoomConfigurationForm containing all + * configuration properties for this chat room + * @throws OperationFailedException Always thrown if called, because the MSN + * protocol does not support any chat room configuration + */ + public ChatRoomConfigurationForm getConfigurationForm() + throws OperationFailedException + { + throw new OperationFailedException( + "The configuration form is not yet implemented for msn.", + OperationFailedException.GENERAL_ERROR); + } + + /** + * Returns the identifier of this ChatRoom. + * + * @return a String containing the identifier of this + * ChatRoom. + */ + public String getIdentifier() + { + return chatRoomName; + } + + /** + * Returns a List of ChatRoomMemberss corresponding to all + * members currently participating in this room. + * + * @return a List of Contact corresponding to all room + * members. + */ + public List getMembers() + { + return new LinkedList(members.values()); + } + + /** + * Returns the number of participants that are currently in this chat room. + * + * @return the number of Contacts, currently participating in this + * room. + */ + public int getMembersCount() + { + return members.size(); + } + + /** + * Returns the name of this ChatRoom. + * + * @return a String containing the name of this ChatRoom. + */ + public String getName() + { + return chatRoomName; + } + + /** + * Returns the protocol provider service that created us. + * + * @return the protocol provider service that created us. + */ + public ProtocolProviderService getParentProvider() + { + return parentProvider; + } + + /** + * Returns the last known room subject/theme or null if the user + * hasn't joined the room or the room does not have a subject yet. + *

+ * 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 chatRooms = chatRoomCache.elements(); + + while (chatRooms.hasMoreElements()) + { + ChatRoomMsnImpl chatRoom = chatRooms.nextElement(); + + ChatRoomMemberMsnImpl member + = chatRoom.findMemberForNickName(contact.getAddress()); + + if (member != null) + { + member.setContact(contact); + + if (contact != null) + member.setAvatar(contact.getImage()); + } + } + } +} diff --git a/src/net/java/sip/communicator/impl/protocol/msn/ProtocolProviderServiceMsnImpl.java b/src/net/java/sip/communicator/impl/protocol/msn/ProtocolProviderServiceMsnImpl.java index 3da777964..56e93fc60 100644 --- a/src/net/java/sip/communicator/impl/protocol/msn/ProtocolProviderServiceMsnImpl.java +++ b/src/net/java/sip/communicator/impl/protocol/msn/ProtocolProviderServiceMsnImpl.java @@ -305,13 +305,19 @@ protected void initialize(String screenname, supportedOperationSets.put( OperationSetPresence.class.getName(), persistentPresence); - //initialize the IM operation set - OperationSetBasicInstantMessagingMsnImpl basicInstantMessaging = - new OperationSetBasicInstantMessagingMsnImpl(this); + // initialize the multi user chat operation set + OperationSetMultiUserChat multiUserChat = new OperationSetMultiUserChatMsnImpl( + this); - supportedOperationSets.put( - OperationSetBasicInstantMessaging.class.getName(), - basicInstantMessaging); + supportedOperationSets.put(OperationSetMultiUserChat.class + .getName(), multiUserChat); + + // initialize the IM operation set + OperationSetBasicInstantMessagingMsnImpl basicInstantMessaging = new OperationSetBasicInstantMessagingMsnImpl( + this); + + supportedOperationSets.put(OperationSetBasicInstantMessaging.class + .getName(), basicInstantMessaging); //initialize the typing notifications operation set typingNotifications = @@ -512,14 +518,17 @@ else if(throwable instanceof UnknownHostException) logger.error("Error in Msn lib ", throwable); - if(isRegistered()) - { - unregister(false); - fireRegistrationStateChanged( - getRegistrationState(), - RegistrationState.UNREGISTERED, - RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null); - } +// We don't want to disconnect on any error, that's why we're +// commenting the following lines for now. +// +// if(isRegistered()) +// { +// unregister(false); +// fireRegistrationStateChanged( +// getRegistrationState(), +// RegistrationState.UNREGISTERED, +// RegistrationStateChangeEvent.REASON_NOT_SPECIFIED, null); +// } } } }