/* * 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.icq; 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.kano.joustsim.*; import net.kano.joustsim.oscar.oscar.service.icbm.*; /** * Maps SIP Communicator typing notifications to those going and coming from * joust sim. * * @author Emil Ivov */ public class OperationSetTypingNotificationsIcqImpl extends AbstractOperationSetTypingNotifications { private static final Logger logger = Logger.getLogger(OperationSetTypingNotificationsIcqImpl.class); /** * An active instance of the opSetPersPresence operation set. We're using * it to map incoming events to contacts in our contact list. */ private OperationSetPersistentPresenceIcqImpl opSetPersPresence = null; /** * The joust sim listener that we use for catching chat events. */ private JoustSimIcbmListener joustSimIcbmListener = new JoustSimIcbmListener(); /** * That's the listener that would gather the typing notifications * themselves. */ private JoustSimTypingListener joustSimTypingListener = new JoustSimTypingListener(); /** * We use this listener to ceise the moment when the protocol provider * has been successfully registered. */ private ProviderRegListener providerRegListener = new ProviderRegListener(); /** * @param icqProvider a ref to the ProtocolProviderServiceIcqImpl * that created us and that we'll use for retrieving the underlying aim * connection. */ OperationSetTypingNotificationsIcqImpl( ProtocolProviderServiceIcqImpl icqProvider) { super(icqProvider); icqProvider.addRegistrationStateChangeListener(providerRegListener); } /** * Converts the typingState variable to its corresponding joustsim * TypingState instance * @param typingState one of the STATE_XXX int fields of this * operation set. * @return the TypingState corresponding to the * typingState argument. */ private TypingState intToTypingState(int typingState) { switch (typingState) { case STATE_PAUSED: return TypingState.PAUSED; case STATE_TYPING: return TypingState.TYPING; case STATE_STOPPED: return TypingState.NO_TEXT; } //if unknown return STOPPED return TypingState.NO_TEXT; } /** * Returns the int var (one of the STATE_XXX fields in * OperationSetTypingNotifications) that best corresponds to state * @param state the TypingState that we'd like to translate. * @return one of the STATE_XXX int fields that best corresponds * to state */ private int typingStateToInt(TypingState state) { if (state == TypingState.TYPING) return STATE_TYPING; else if(state == TypingState.PAUSED) return STATE_PAUSED; else if(state == TypingState.NO_TEXT) return STATE_STOPPED; return STATE_UNKNOWN; } /** * Sends a notification to notifiedContatct that we have entered * typingState. * * @param notifiedContact the Contact to notify * @param typingState the typing state that we have entered. * * @throws java.lang.IllegalStateException if the underlying ICQ stack is * not registered and initialized. * @throws java.lang.IllegalArgumentException if notifiedContact is * not an instance belonging to the underlying implementation. */ public void sendTypingNotification(Contact notifiedContact, int typingState) throws IllegalStateException, IllegalArgumentException { assertConnected(); if( !(notifiedContact instanceof ContactIcqImpl) ) throw new IllegalArgumentException( "The specified contact is not an ICQ contact." + notifiedContact); parentProvider .getAimConnection() .getIcbmService() .getImConversation( new Screenname(notifiedContact.getAddress())) .setTypingState(intToTypingState(typingState)); } /** * Our listener that will tell us when we're registered to icq and joust * sim is ready to accept us as a listener. */ private class ProviderRegListener implements RegistrationStateChangeListener { /** * The method is called by a ProtocolProvider implementation whenver * 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 (logger.isDebugEnabled()) logger.debug("The ICQ provider changed state from: " + evt.getOldState() + " to: " + evt.getNewState()); if (evt.getNewState() == RegistrationState.FINALIZING_REGISTRATION) { parentProvider.getAimConnection().getIcbmService() .addIcbmListener(joustSimIcbmListener); opSetPersPresence = (OperationSetPersistentPresenceIcqImpl) parentProvider .getOperationSet(OperationSetPersistentPresence.class); } } } /** * We track newly created conversations and register a typing listener with * every one of them so that we could fire events for typing events. */ private class JoustSimIcbmListener implements IcbmListener { /** * All we do here is add a listener that would snoop for typing events * sent by oscar.jar * @param service the IcbmService that is sending the event * @param conv the Conversation where we're to add ourselves as a * listener. */ public void newConversation(IcbmService service, Conversation conv) { conv.addConversationListener(joustSimTypingListener); } public void buddyInfoUpdated(IcbmService service, Screenname buddy, IcbmBuddyInfo info) { if (logger.isDebugEnabled()) logger.debug("buddyInfoUpdated for:"+buddy+" info: " +info); } public void sendAutomaticallyFailed( IcbmService service, net.kano.joustsim.oscar.oscar.service.icbm.Message message, Set triedConversations) { } } /** * The oscar.jar lib sends us typing events through this listener. */ private class JoustSimTypingListener implements IcbmListener, TypingListener { public void gotTypingState(Conversation conversation, TypingInfo typingInfo) { Contact sourceContact = opSetPersPresence.findContactByID( conversation.getBuddy().getFormatted()); if(sourceContact == null) { if (logger.isDebugEnabled()) logger.debug("Received a typing notification from an unknown "+ "buddy=" + conversation.getBuddy()); //create the volatile contact sourceContact = opSetPersPresence .createVolatileContact( conversation.getBuddy().getFormatted()); } fireTypingNotificationsEvent( sourceContact, typingStateToInt(typingInfo.getTypingState())); } //the follwoing methods only have dummy implementations here as they //do not interest us. complete implementatios are provider in the //basic instant messaging operation set. public void buddyInfoUpdated(IcbmService service, Screenname buddy, IcbmBuddyInfo info){} public void conversationClosed(Conversation conv){} public void gotMessage(Conversation conv, MessageInfo minfo){} public void gotOtherEvent(Conversation conversation, ConversationEventInfo event){} public void sentOtherEvent(Conversation conversation, ConversationEventInfo event){} public void canSendMessageChanged(Conversation conv, boolean canSend){} public void conversationOpened(Conversation conv){} public void newConversation(IcbmService service, Conversation conv){} public void sentMessage(Conversation conv, MessageInfo minfo){} public void sendAutomaticallyFailed(IcbmService service, net.kano.joustsim.oscar.oscar. service.icbm.Message message, Set triedConversations) { } } }