/* * Jitsi, the OpenSource Java VoIP and Instant Messaging client. * * Copyright @ 2015 Atlassian Pty Ltd * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.java.sip.communicator.impl.protocol.irc; import java.util.*; import net.java.sip.communicator.service.gui.*; import net.java.sip.communicator.service.muc.*; import net.java.sip.communicator.service.protocol.*; import net.java.sip.communicator.service.protocol.event.*; /** * Allows creating, configuring, joining and administering of individual * text-based conference rooms. * * @author Stephane Remy * @author Loic Kempf * @author Yana Stamcheva * @author Lubomir Marinov * @author Danny van Heumen */ public class OperationSetMultiUserChatIrcImpl extends AbstractOperationSetMultiUserChat { /** * A call back to the IRC provider that created us. */ private ProtocolProviderServiceIrcImpl ircProvider = null; /** * A list of the rooms that are currently open by this account. Note that * we have not necessarily joined these rooms, we might have simply been * searching through them. */ private final Map chatRoomCache = new Hashtable(); /** * The ChatRoom corresponding to the IRC server channel. This chat * room is not returned by any of methods getExistingChatRooms(), * getCurrentlyJoinedChatRooms, etc. */ private ChatRoomIrcImpl serverChatRoom; /** * Instantiates the user operation set with a currently valid instance of * the irc protocol provider. * @param provider a currently valid instance of * ProtocolProviderServiceIrcImpl. */ public OperationSetMultiUserChatIrcImpl( final ProtocolProviderServiceIrcImpl provider) { this.ircProvider = provider; } /** * Returns the List of ChatRooms currently available on * the server that this protocol provider is connected to. * * @return a java.util.List of ChatRooms that are * currently available on the server that this protocol provider is * connected to. * * @throws OperationFailedException if we failed retrieving this list from * the server. */ public List getExistingChatRooms() throws OperationFailedException { final IrcConnection connection = this.ircProvider.getIrcStack().getConnection(); if (connection == null) { throw new IllegalStateException("Connection is not available."); } return connection.getServerChannelLister().getList(); } /** * 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 (!joinedRoomsIter.next().isJoined()) { joinedRoomsIter.remove(); } } return joinedRooms; } } /** * Returns a list of the chat rooms that chatRoomMember has joined * and is currently active in. * * @param chatRoomMember the chat room member whose current ChatRooms we * will be querying. * @return a list of the chat rooms that chatRoomMember has joined * and is currently active in. */ public List getCurrentlyJoinedChatRooms( final ChatRoomMember chatRoomMember) { // Implement "who is" for the IRC stack. // (currently not in use) /* * According to the RFC: * * 311 RPL_WHOISUSER " * :" * * 312 RPL_WHOISSERVER " :" * * 313 RPL_WHOISOPERATOR " :is an IRC operator" * * 317 RPL_WHOISIDLE " :seconds idle" * * 318 RPL_ENDOFWHOIS " :End of /WHOIS list" * * 319 RPL_WHOISCHANNELS " :{[@|+]}" * * - Replies 311 - 313, 317 - 319 are all replies generated in response * to a WHOIS message. Given that there are enough parameters present, * the answering server must either formulate a reply out of the above * numerics (if the query nick is found) or return an error reply. The * '*' in RPL_WHOISUSER is there as the literal character and not as a * wild card. For each reply set, only RPL_WHOISCHANNELS may appear more * than once (for long lists of channel names). The '@' and '+' * characters next to the channel name indicate whether a client is a * channel operator or has been granted permission to speak on a * moderated channel. The RPL_ENDOFWHOIS reply is used to mark the end * of processing a WHOIS message. */ return Collections.emptyList(); } /** * Creates a room with the named roomName and according to the * specified roomProperties on the server that this protocol * provider is currently connected to. When the method returns the room the * local user will not have joined it and thus will not receive messages on * it until the ChatRoom.join() method is called. *

* @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 the newly created ChatRoom named roomName. */ public ChatRoom createChatRoom( final String roomName, final Map roomProperties) throws OperationFailedException, OperationNotSupportedException { try { return findOrCreateRoom(roomName); } catch (IllegalArgumentException e) { String message = IrcActivator.getResources().getI18NString( "service.gui.CREATE_CHAT_ROOM_ERROR", new String[] {roomName}); throw new OperationFailedException(message, OperationFailedException.ILLEGAL_ARGUMENT, e); } } /** * Returns a reference to a chatRoom named roomName. * * Originally, this method would create the room if it doesn't exist. This * is not acceptable anymore, since rebuilding the chat room list would * create new instances without the IRC stack being prepared for this or * having corresponding instances. * * @param roomName the name of the ChatRoom that we're looking for. * @return the ChatRoom named roomName. */ public ChatRoomIrcImpl findRoom(final String roomName) { return chatRoomCache.get(roomName); } /** * Find an existing room with the provided name, or create a new room with * this name. * * @param roomName name of the chat room * @return returns a chat room */ public ChatRoomIrcImpl findOrCreateRoom(final String roomName) { synchronized (this.chatRoomCache) { ChatRoomIrcImpl room = chatRoomCache.get(roomName); if (room == null) { room = createLocalChatRoomInstance(roomName); } return room; } } /** * There is no such thing as a rejection to an invitatation. The notion of * an invite in IRC is just an addition to a white list. There is nothing to * reject. * * @param invitation the invitation we are rejecting. * @param reason the reason of rejecting */ public void rejectInvitation(final ChatRoomInvitation invitation, final String reason) { } /** * 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 chat * rooms. */ public boolean isMultiChatSupportedByContact(final Contact contact) { return true; } /** * Returns a reference to the chat room named chatRoomName or * null if the room hasn't been cached yet. * * @param chatRoomName the name of the room we're looking for. * * @return the ChatRoomJabberImpl instance that has been cached * for chatRoomName or null if no such room has been cached so far. */ protected ChatRoomIrcImpl getChatRoom(final String chatRoomName) { return this.chatRoomCache.get(chatRoomName); } /** * Creates a ChatRoom from the specified chat room name. * * Must be used in SYNCHRONIZED context. * * @param chatRoomName the name of the chat room to add * * @return ChatRoom the chat room that we've just created. */ private ChatRoomIrcImpl createLocalChatRoomInstance( final String chatRoomName) { ChatRoomIrcImpl chatRoom = new ChatRoomIrcImpl(chatRoomName, ircProvider); this.chatRoomCache.put(chatRoom.getName(), chatRoom); return chatRoom; } /** * Register chat room instance in case it is not yet registered. * * @param chatroom the chatroom */ public void registerChatRoomInstance(final ChatRoomIrcImpl chatroom) { synchronized (this.chatRoomCache) { this.chatRoomCache.put(chatroom.getIdentifier(), chatroom); } } /** * Delivers a ChatRoomInvitationReceivedEvent to all * registered ChatRoomInvitationListeners. * * @param targetChatRoom the room that invitation refers to * @param inviter the inviter that sent the invitation * @param reason the reason why the inviter sent the invitation * @param password the password to use when joining the room */ protected void fireInvitationEvent(final ChatRoom targetChatRoom, final String inviter, final String reason, final byte[] password) { ChatRoomInvitationIrcImpl invitation = new ChatRoomInvitationIrcImpl(targetChatRoom, inviter, reason, password); fireInvitationReceived(invitation); } /** * Returns the room corresponding to the server channel. * * @return the room corresponding to the server channel */ protected ChatRoomIrcImpl findSystemRoom() { if (serverChatRoom == null) { serverChatRoom = new ChatRoomIrcImpl( ircProvider.getAccountID().getService(), ircProvider, true); // is system room this.fireLocalUserPresenceEvent( serverChatRoom, LocalUserChatRoomPresenceChangeEvent.LOCAL_USER_JOINED, "Connected to the server."); } return serverChatRoom; } /** * Returns the system room member. * * @return the system room member. */ protected ChatRoomMemberIrcImpl findSystemMember() { if (serverChatRoom.getMembers().size() > 0) { return (ChatRoomMemberIrcImpl) serverChatRoom.getMembers().get(0); } else { return new ChatRoomMemberIrcImpl(ircProvider, serverChatRoom, ircProvider.getAccountID().getService(), "", ircProvider .getAccountID().getServerAddress(), ChatRoomMemberRole.GUEST, IrcStatusEnum.ONLINE); } } /** * {@inheritDoc} * * Always returns true. */ @Override public boolean isPrivateMessagingContact(final String contactAddress) { return true; } /** * Open a chat room window. * * In IRC a situation may occur where the user gets joined to a channel * without Jitsi initiating the joining activity. This "unannounced" join * event, must also be handled and we should display the chat room window in * that case, to alert the user that this happened. * * @param chatRoom the chat room */ void openChatRoomWindow(final ChatRoomIrcImpl chatRoom) { MUCService mucService = IrcActivator.getMUCService(); UIService uiService = IrcActivator.getUIService(); ChatRoomWrapper wrapper = mucService.getChatRoomWrapperByChatRoom(chatRoom, true); uiService.openChatRoomWindow(wrapper); } }