[sip-comm-dev] SIP Communicator - Open Usability Season


#1

Hi Developers,

My name is Fabiana and I was the Usability Student chosen to take part of the SIP Communicator Project during the Open Usability Season (www.openusability.org). For the next three months we are going to work close to you developers to improve usability for the SIP Communicator Project! I've already had a chat with Emil, and some of the developers, but unfortunately, due to technical problems, we weren't able to communicate for a long time. That's one of the reasons I'm joining this mailing list.

Jan Muehlig- from Open Usability and I, have come up with a plan to help us go through all the necessary aspects of the current and future versions of SIP Communicator in order to analyze, suggest and promote the results you are expecting. I included the plan at the end of this email for your evaluation.

Just in case someone is interested, here is a little information about my experience:

I am a Brazilian Usability Student with a bachelor's degree in Computer Science, currently attending a Software Engeneering course focusing on usability and interface design. I will be pursuing a master degree on usability for the next two years.

I have also taken part of telecom software projects in Brazil as an Usability Analyst for the past 3 years. Usability Oriented GUI Design is my expertise and - among other expectations, I intend to improve my Usability testing skills and join the open source community. This is actually the first Open Source Project I'm participating in, so I would very much appreciate any help with that!

Thank you all for the opportunity,

Fabiana Azevedo

USABILITY PROJECT PLAN

1) Assessment
- Brainstorm with project leaders
- Actors Identification (Target Users)
. Current Users
. Expected Users
- Scenarios Identification
. Current usage scenarios
. Intented usage scenarios
- System Features Identification
. Current Features: Main and extra features. Define priorities.
. Future Features(Roadmap)
- Problem Identification
. Known Bugs

Agreement

2) Analysis
- Defining main use cases
- Cognitive Walkthrough for use cases
- Interface
. Design Standards
. Usage Ease
- System Feedback
=> Report

3) Optional: Testing
- Task based
- Thinking aloud
- 8-12 participants
=> Report

4) Optimization
- Best practices
- Smoothing of use cases
=> Report


#2

Hello Fabiana,

And welcome to the project. Up to this point we haven't had any particular usability concept on SIP Communicator. All functionality have so far been implemented the way we "felt" it would be right and this is most certainly not a strategy we can count on in order to conquer the hearts of the users :).

This is one of the reasons why we're very glad to have you work with us! Besides, your background seems to fit very nicely into the project context! In other words we are really eager to start working on usability for SC with you.

This is actually the first Open Source Project I'm participating in, so I would very much appreciate any help with that!

Well, this would be the first time we work on usability so we'd have to be helping each other.

OK, so here we go. Following are my comments on assessment points:

1) Assessment
- Brainstorm with project leaders

What would you expect from us here? Is it stuff that we'd like to improve or probably subjects that we'd like to get considered by a usability expert? Could you give us some hints?

- Actors Identification (Target Users)
. Current Users

My own impression is that most of the people currently using SIP Communicator are developers themselves. I don't think that right now we have many users that have just stumbled upon SC and are using it on a daily basis for the sheer fun of it. Given the fact that it is still unstable, using it still requires an effort and is not a completely painless experience.

. Expected Users

Is this a trick question? The entire planet of course! :slight_smile:

Seriously, we would like the SIP Communicator to be usable by all people who use a computer on a daily basis. More or less the same people who use spreadsheets and rich text processors.

- Scenarios Identification
. Current usage scenarios

What exactly would you need here? A generic enumeration like,
     making calls, sending messages, adding contacts
or something more like:
     Sending a message: select the intended addressee in the contact list, open a new chat window by click or pressing enter on it, type a message, send the message by pressing enter/alt+s/Left-click on Send
     Making a call: ....

or probably something between the two? Can you give us an example?

. Intended usage scenarios

     Same question as above.

- System Features Identification
. Current Features: Main and extra features. Define priorities.

I am not sure I know what is exactly the difference between a main and extra feature but here's a try. Let me know if this is not exactly what you need or in case you'd need more details:

     Main features:
         - Making audio/video calls.
         - Sending and receiving instant messages through Jabber, MSN, ICQ and Yahoo!
         - Retrieving server stored contact lists
         - Merging contacts locally in meta contacts
         - Sending messages to (meta) contacts
         - Receiving messages from (meta) contacts
         - Tabbed chatting.

     Extra features:
         - Selecting the "send via" protocol when sending a message to a meta contact
         - Message history
         - Call history

If anyone has anything to add or change please speak up.

. Future Features(Roadmap)

Here's a start.
https://www.sip-communicator.org/index.php/Development/Roadmap

- Problem Identification
. Known Bugs

We're trying to keep our issue tracker as up to date as possible so it would be worthy having a look at it.
https://sip-communicator.dev.java.net/issues/buglist.cgi?target_milestone=alpha2&component=sip-communicator&issue_status=UNCONFIRMED&issue_status=NEW&issue_status=STARTED&issue_status=REOPENED

I've also created a page on the wiki that we could use as an entry point to all documents related to usability.

http://sip-communicator.org/usability/

The page is currently linked to from the

. If anyone has a better suggestion - let me know.

Cheers
Emil

Fabiana Meira Pires wrote:

···

Hi Developers,
My name is Fabiana and I was the Usability Student chosen to take part of the SIP Communicator Project during the Open Usability Season (www.openusability.org <http://www.openusability.org>). For the next three months we are going to work close to you developers to improve usability for the SIP Communicator Project! I've already had a chat with Emil, and some of the developers, but unfortunately, due to technical problems, we weren't able to communicate for a long time. That's one of the reasons I'm joining this mailing list.
Jan Muehlig- from Open Usability and I, have come up with a plan to help us go through all the necessary aspects of the current and future versions of SIP Communicator in order to analyze, suggest and promote the results you are expecting. I included the plan at the end of this email for your evaluation.
Just in case someone is interested, here is a little information about my experience:
I am a Brazilian Usability Student with a bachelor's degree in Computer Science, currently attending a Software Engeneering course focusing on usability and interface design. I will be pursuing a master degree on usability for the next two years.
I have also taken part of telecom software projects in Brazil as an Usability Analyst for the past 3 years. Usability Oriented GUI Design is my expertise and - among other expectations, I intend to improve my Usability testing skills and join the open source community. This is actually the first Open Source Project I'm participating in, so I would very much appreciate any help with that!

Fabiana Azevedo

1) Assessment
- Brainstorm with project leaders
- Actors Identification (Target Users)
. Current Users
. Expected Users
- Scenarios Identification
. Current usage scenarios
. Intented usage scenarios
- System Features Identification
. Current Features: Main and extra features. Define priorities.
. Future Features(Roadmap)
- Problem Identification
. Known Bugs
>>Agreement

2) Analysis
- Defining main use cases
- Cognitive Walkthrough for use cases
- Interface
. Design Standards
. Usage Ease
- System Feedback
=> Report

3) Optional: Testing
- Task based
- Thinking aloud
- 8-12 participants
=> Report

4) Optimization
- Best practices
- Smoothing of use cases
=> Report

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net


#3

Hi all,

I currently concentrate on SIP and very interested in SIP Communicator. I intend to develop SIP Communicator, specialist SIP and VOIP on Handheld device.
Are there any one intend to develop SIP Communicator on Handheld like Linux PDA, Windows Pocket PC... or done?
I would like to port the current version of SIP Communicator to J2ME and run on Handheld device but I worried we could successful or not because of limit of handheld device like memory, library, full support of Java... I'm starting with Java and SIP on my Pocket PC XDA II Windows Mobile 5.0 but for Linux PDA also recommended. I'm the first year of Master student on Computer Networks of University of Paris 6.

I'm looking forward your idea.

Thanks in advance,
   Minh Nguyen.


#4

Hi all,

I'm currently trying to use the icq protocol to get the hang and learn with the system.

I want to make the system to be able to reply automatically (once : at the early of the conversation). I have added some lines in impl/protocol/icq/ProtocolProviderServiceIcqImpl.java (to provoke AutoResponse) and added a file impl/protocol/icq/callcenter/AutoResponse.java for that reason.

I have tried several ways to implement it.. and put it in commented lines. Thank you..

xrurouni.

ProtocolProviderServiceIcqImpl.java (36.1 KB)

AutoResponse.java (6.06 KB)

···

---------------------------------
Never miss an email again!
Yahoo! Toolbar alerts you the instant new Mail arrives. Check it out.


#5

Hello Minh,

I currently concentrate on SIP and very interested in SIP Communicator. I intend to develop SIP Communicator, specialist SIP and VOIP on Handheld device.
Are there any one intend to develop SIP Communicator on Handheld like Linux PDA, Windows Pocket PC... or done?

Not that I know of. Porting SIP Communicator to a handheld device would require rewriting at least the UI and Media services and in the case of a MobilePhone (MIDP) most of the protocol providers as well due to the differences in the socket API.

I would like to port the current version of SIP Communicator to J2ME and run on Handheld device but I worried we could successful or not because of limit of handheld device like memory, library, full support of Java... I'm starting with Java and SIP on my Pocket PC XDA II Windows Mobile 5.0 but for Linux PDA also recommended. I'm the first year of Master student on Computer Networks of University of Paris 6.

Yes, in order to make it work on MIDP, you'd need to find phones that support at least JSRs 135 (MMAPI) and 180 (SIP API for J2ME).

Good luck
Emil

···

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net


#6

Hello Xrurouni,

In the case of ICQ, you don't need to add anything in the icq package. Have a look at the growl notifier in sip-communicator/src/net/java/sip/communicator/impl/growlnotification and the way it registers for incoming messages. You could do the same and use OperationSetBasicInstantMessaging to send you response.

Emil

xrurouni des wrote:

···

Hi all,

I'm currently trying to use the icq protocol to get the hang and learn with the system.

I want to make the system to be able to reply automatically (once : at the early of the conversation). I have added some lines in impl/protocol/icq/ProtocolProviderServiceIcqImpl.java (to provoke AutoResponse) and added a file impl/protocol/icq/callcenter/AutoResponse.java for that reason.

I have tried several ways to implement it.. and put it in commented lines. Thank you..

xrurouni.

------------------------------------------------------------------------
Never miss an email again!
Yahoo! Toolbar <http://us.rd.yahoo.com/evt=49938/*http://tools.search.yahoo.com/toolbar/features/mail/> alerts you the instant new Mail arrives. Check it out. < http://us.rd.yahoo.com/evt=49937/*http://tools.search.yahoo.com/toolbar/features/mail/>

------------------------------------------------------------------------

/*
* 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.icq;

import java.util.*;

import net.java.sip.communicator.impl.protocol.icq.message.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.impl.protocol.icq.callcenter.AutoResponse;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
import net.kano.joscar.flap.*;
import net.kano.joscar.flapcmd.*;
import net.kano.joscar.snaccmd.auth.*;
import net.kano.joustsim.*;
import net.kano.joustsim.oscar.*;
import net.kano.joustsim.oscar.State;
import net.kano.joustsim.oscar.oscar.loginstatus.*;
import net.kano.joustsim.oscar.oscar.service.*;
import net.kano.joustsim.oscar.oscar.service.icbm.*;

//until here

/**
* An implementation of the protocol provider service over the AIM/ICQ protocol
*
* @author Emil Ivov
* @author Damian Minkov
*
* @SPC3 author azrul
*/
public class ProtocolProviderServiceIcqImpl
    implements ProtocolProviderService
{
    private static final Logger logger =
        Logger.getLogger(ProtocolProviderServiceIcqImpl.class);
        /**
     * The hashtable with the operation sets that we support locally.
     */
    private Hashtable supportedOperationSets = new Hashtable();

    private DefaultAppSession session = null;

    private AimSession aimSession = null;

    private AimConnection aimConnection = null;

    private IcbmService icbmService = null;

    /**
     * Listener that catches all connection events originating from joscar
     * during connection to icq.
     */
    private AimConnStateListener aimConnStateListener = null;

    /**
     * Listener that catches all incoming and outgoing chat events generated
     * by joscar.
     */
    private AimIcbmListener aimIcbmListener = new AimIcbmListener();

    /**
     * indicates whether or not the provider is initialized and ready for use.
     */
    private boolean isInitialized = false;

    /**
     * We use this to lock access to initialization.
     */
    private Object initializationLock = new Object();

    /**
     * A list of all listeners registered for
     * <tt>RegistrationStateChangeEvent</tt>s.
     */
    private List registrationListeners = new ArrayList();

    /**
     * The identifier of the account that this provider represents.
     */
    private AccountID accountID = null;

    /**
     * Retrieves short or full user info, such as Name, Address, Nickname etc.
     */
    private InfoRetreiver infoRetreiver = null;
        /*
     * callcenter's AutoResponse class to be support locally
     *
     * added by azrul
     */
    private AutoResponse autoResponse = new AutoResponse();
    //private MessageIcqImpl messageIcqImpl = new MessageIcqImpl();
    //private MessageIcqImpl messageIcqImpl = null;
    //until here
       /**
     * Returns the state of the registration of this protocol provider
     * @return the <tt>RegistrationState</tt> that this provider is
     * currently in or null in case it is in a unknown state.
     */
    public RegistrationState getRegistrationState()
    {
        if(getAimConnection() == null)
            return RegistrationState.UNREGISTERED;

        State connState = getAimConnection().getState();

        return joustSimStateToRegistrationState(connState);
    }

    /**
     * Converts the specified joust sim connection state to a corresponding
     * RegistrationState.
     * @param jsState the joust sim connection state.
     * @return a RegistrationState corresponding best to the specified
     * joustSimState.
     */
    private RegistrationState joustSimStateToRegistrationState(State jsState)
    {
        return joustSimStateToRegistrationState(jsState, null);
    }

    /**
     * Converts the specified joust sim connection state to a corresponding
     * RegistrationState.
     * @param joustSimConnState the joust sim connection state.
     * @param joustSimConnStateInfo additional stateinfo if available (may be
     * null)
     * @return a RegistrationState corresponding best to the specified
     * joustSimState.
     */
    private RegistrationState joustSimStateToRegistrationState(
        State joustSimConnState,
        StateInfo joustSimConnStateInfo)
    {
        if(joustSimConnState == State.ONLINE)
            return RegistrationState.REGISTERED;
        else if (joustSimConnState == State.CONNECTING)
            return RegistrationState.REGISTERING;
        else if( joustSimConnState == State.AUTHORIZING)
            return RegistrationState.AUTHENTICATING;
        else if (joustSimConnState == State.CONNECTINGAUTH)
            return RegistrationState.AUTHENTICATING;
        else if (joustSimConnState == State.SIGNINGON)
            return RegistrationState.REGISTERING;
        else if (joustSimConnState == State.DISCONNECTED
                 >> joustSimConnState == State.NOTCONNECTED)
        {
            if(joustSimConnStateInfo != null
                && joustSimConnStateInfo instanceof DisconnectedStateInfo
                && !((DisconnectedStateInfo)joustSimConnStateInfo).isOnPurpose())
            {
                return RegistrationState.CONNECTION_FAILED;
            }

            return RegistrationState.UNREGISTERED;
        }
        else if (joustSimConnState == State.FAILED)
        {
            if(joustSimConnStateInfo != null
                && joustSimConnStateInfo instanceof LoginFailureStateInfo)
            {
                LoginFailureInfo lfInfo = ((LoginFailureStateInfo)
                                joustSimConnStateInfo).getLoginFailureInfo();

                if (lfInfo instanceof AuthFailureInfo)
                    return RegistrationState.AUTHENTICATION_FAILED;
            }
            return RegistrationState.CONNECTION_FAILED;
        }
        else{
            logger.warn("Unknown state " + joustSimConnState
                        + ". Defaulting to " + RegistrationState.UNREGISTERED);
            return RegistrationState.UNREGISTERED;
        }
    }

    /**
     * Starts the registration process. Connection details such as
     * registration server, user name/number are provided through the
     * configuration service through implementation specific properties.
     *
     * @param authority the security authority that will be used for resolving
     * any security challenges that may be returned during the
     * registration or at any moment while wer're registered.
     */
    public void register(SecurityAuthority authority)
    {
        if(authority == null)
            throw new IllegalArgumentException(
                "The register method needs a valid non-null authority impl "
                + " in order to be able and retrieve passwords.");

        synchronized(initializationLock)
        {
            //verify whether a password has already been stored for this account
            String password = IcqActivator.getProtocolProviderFactory()
                .loadPassword(getAccountID());

            //decode
            if( password == null )
            {
                //create a default credentials object
                UserCredentials credentials = new UserCredentials();
                credentials.setUserName(this.getAccountID().getUserID());

                //request a password from the user
                credentials = authority.obtainCredentials(ProtocolNames.ICQ
                                                          , credentials);
                //extract the password the user passed us.
                char[] pass = credentials.getPassword();

                // the user didn't provide us a password (canceled the operation)
                if(pass == null)
                {
                    fireRegistrationStateChanged(
                        RegistrationState.UNREGISTERED,
                        RegistrationStateChangeEvent.REASON_USER_REQUEST, "");
                    return;
                }

                password = new String(pass);

                if (credentials.isPasswordPersistent())
                {
                    IcqActivator.getProtocolProviderFactory()
                        .storePassword(getAccountID(), password);
                }
            }

            // it seems icq servers doesn't accept password with
            // length more then 8. But allow such registrations
            // we must trim such passwords to 8 characters
            if(password.length() > 8)
                password = password.substring(0, 8);

            //init the necessary objects
            session = new DefaultAppSession();
            aimSession = session.openAimSession(
                new Screenname(getAccountID().getUserID()));
            aimConnection = aimSession.openConnection(
                new AimConnectionProperties(
                    new Screenname(getAccountID().getUserID())
                    , password));

            aimConnStateListener = new AimConnStateListener();
            aimConnection.addStateListener(aimConnStateListener);

            aimConnection.connect();
        }
    }

    /**
     * Ends the registration of this protocol provider with the service.
     */
    public void unregister()
    {
        if(aimConnection != null)
            aimConnection.disconnect(true);
    }

    /**
     * Indicates whether or not this provider is signed on the icq service
     * @return true if the provider is currently signed on (and hence online)
     * and false otherwise.
     */
    public boolean isRegistered()
    {
        return getRegistrationState().equals(RegistrationState.REGISTERED);
    }

    /**
     * Returns the short name of the protocol that the implementation of this
     * provider is based upon (like SIP, Jabber, ICQ/AIM, or others for
     * example).
     *
     * @return a String containing the short name of the protocol this
     * service is taking care of.
     */
    public String getProtocolName()
    {
        return ProtocolNames.ICQ;
    }

    /**
     * Returns an array containing all operation sets supported by the
     * current implementation.
     *
     * @return an array of OperationSet-s supported by this protocol
     * provider implementation.
     */
    public Map getSupportedOperationSets()
    {
        return supportedOperationSets;
    }

    /**
     * Returns the operation set corresponding to the specified class or null
     * if this operation set is not supported by the provider implementation.
     *
     * @param opsetClass the <tt>Class</tt> of the operation set that we're
     * looking for.
     * @return returns an OperationSet of the specified <tt>Class</tt> if the
     * undelying implementation supports it or null otherwise.
     */
    public OperationSet getOperationSet(Class opsetClass)
    {
        return (OperationSet)getSupportedOperationSets()
            .get(opsetClass.getName());
    }

    /**
     * Initialized the service implementation, and puts it in a sate where it
     * could interoperate with other services. It is strongly recomended that
     * properties in this Map be mapped to property names as specified by
     * <tt>AccountProperties</tt>.
     *
     * @param screenname the account id/uin/screenname of the account that
     * we're about to create
     * @param accountID the identifier of the account that this protocol
     * provider represents.
     *
     * @see net.java.sip.communicator.service.protocol.AccountID
     */
    protected void initialize(String screenname,
                              AccountID accountID)
    {
        synchronized(initializationLock)
        {
            this.accountID = accountID;

            //initialize the presence operationset
            OperationSetPersistentPresence persistentPresence =
                new OperationSetPersistentPresenceIcqImpl(this, screenname);

            supportedOperationSets.put(
                OperationSetPersistentPresence.class.getName(),
                persistentPresence);

            //register it once again for those that simply need presence
            supportedOperationSets.put( OperationSetPresence.class.getName(),
                                        persistentPresence);

            //initialize the IM operation set
            OperationSetBasicInstantMessaging basicInstantMessaging =
                new OperationSetBasicInstantMessagingIcqImpl(this);

            supportedOperationSets.put(
                OperationSetBasicInstantMessaging.class.getName(),
                basicInstantMessaging);

            //initialize the typing notifications operation set
            OperationSetTypingNotifications typingNotifications =
                new OperationSetTypingNotificationsIcqImpl(this);

            supportedOperationSets.put(
                OperationSetTypingNotifications.class.getName(),
                typingNotifications);

            this.infoRetreiver = new InfoRetreiver(this, screenname);

            OperationSetServerStoredContactInfo serverStoredContactInfo =
                new OperationSetServerStoredContactInfoIcqImpl(infoRetreiver);

            supportedOperationSets.put(
                OperationSetServerStoredContactInfo.class.getName(),
                serverStoredContactInfo);

            OperationSetServerStoredAccountInfo serverStoredAccountInfo =
                new OperationSetServerStoredAccountInfoIcqImpl
                    (infoRetreiver, screenname, this);

            supportedOperationSets.put(
                OperationSetServerStoredAccountInfo.class.getName(),
                serverStoredAccountInfo);

            OperationSetWebAccountRegistration webAccountRegistration =
                new OperationSetWebAccountRegistrationIcqImpl();
            supportedOperationSets.put(
                OperationSetWebAccountRegistration.class.getName(),
                webAccountRegistration);

            OperationSetWebContactInfo webContactInfo =
                new OperationSetWebContactInfoIcqImpl();
            supportedOperationSets.put(
                OperationSetWebContactInfo.class.getName(),
                webContactInfo);

            isInitialized = true;
        }
    }

    /**
     * Makes the service implementation close all open sockets and release
     * any resources that it might have taken and prepare for
     * shutdown/garbage collection.
     */
    public void shutdown()
    {
        /** @todo is there anything else to add here? */
        synchronized(initializationLock){
            icbmService = null;
            session = null;
            aimSession = null;
            aimConnection = null;
            aimConnStateListener = null;
            aimIcbmListener = null;
            isInitialized = false;
        }
    }

    /**
     * Returns true if the provider service implementation is initialized and
     * ready for use by other services, and false otherwise.
     *
     * @return true if the provider is initialized and ready for use and false
     * otherwise
     */
    public boolean isInitialized()
    {
        return isInitialized;
    }

    /**
     * Removes the specified registration state change listener so that it does
     * not receive any further notifications upon changes of the
     * RegistrationState of this provider.
     *
     * @param listener the listener to register for
     * <tt>RegistrationStateChangeEvent</tt>s.
     */
    public void removeRegistrationStateChangeListener(
        RegistrationStateChangeListener listener)
    {
        synchronized(registrationListeners)
        {
            registrationListeners.remove(listener);
        }
    }

    /**
     * Registers the specified listener with this provider so that it would
     * receive notifications on changes of its state or other properties such
     * as its local address and display name.
     *
     * @param listener the listener to register.
     */
    public void addRegistrationStateChangeListener(
        RegistrationStateChangeListener listener)
    {
        synchronized(registrationListeners)
        {
            if (!registrationListeners.contains(listener))
                registrationListeners.add(listener);
        }
    }

    /**
     * Returns the AccountID that uniquely identifies the account represented
     * by this instance of the ProtocolProviderService.
     * @return the id of the account represented by this provider.
     */
    public AccountID getAccountID()
    {
        return accountID;
    }

    /**
     * Creates a RegistrationStateChange event corresponding to the specified
     * old and new joust sim states and notifies all currently registered
     * listeners.
     *
     * @param oldJoustSimState the state that the joust sim connection had
     * before the change occurred
     * @param oldJoustSimStateInfo the state info associated with the state of
     * the underlying connection state as it is after the change.
     * @param newJoustSimState the state that the underlying joust sim
     * connection is currently in.
     * @param newJoustSimStateInfo the state info associated with the state of
     * the underlying connection state as it was before the change.
     * @param reasonCode a value corresponding to one of the REASON_XXX fields
     * of the RegistrationStateChangeEvent class, indicating the reason for this
     * state transition.
     * @param reason a String further explaining the reason code or null if
     * no such explanation is necessary.
     */
    private void fireRegistrationStateChanged( State oldJoustSimState,
                                                StateInfo oldJoustSimStateInfo,
                                                State newJoustSimState,
                                                StateInfo newJoustSimStateInfo,
                                                int reasonCode,
                                                String reason)
    {
        RegistrationState oldRegistrationState
            = joustSimStateToRegistrationState(oldJoustSimState
                                               , oldJoustSimStateInfo);
        RegistrationState newRegistrationState
            = joustSimStateToRegistrationState(newJoustSimState
                                               , newJoustSimStateInfo);

        if(newJoustSimStateInfo instanceof LoginFailureStateInfo)
        {
            LoginFailureInfo loginFailure =
                ((LoginFailureStateInfo)newJoustSimStateInfo)
                    .getLoginFailureInfo();

            if(loginFailure instanceof AuthFailureInfo)
            {
                AuthFailureInfo afi = (AuthFailureInfo)loginFailure;
                logger.debug("AuthFailureInfo code : " +
                             afi.getErrorCode());
                int code = ConnectionClosedListener
                    .convertAuthCodeToReasonCode(afi);
                reasonCode = ConnectionClosedListener
                    .convertCodeToRegistrationStateChangeEvent(code);
                reason = ConnectionClosedListener
                    .convertCodeToStringReason(code);
            }
        }

        fireRegistrationStateChanged(oldRegistrationState, newRegistrationState
                                     , reasonCode, reason);

    }

    /**
     * Creates a RegistrationStateChange event corresponding to the specified
     * old and new states and notifies all currently registered listeners.
     *
     * @param oldState the state that the provider had before the change
     * occurred
     * @param newState the state that the provider is currently in.
     * @param reasonCode a value corresponding to one of the REASON_XXX fields
     * of the RegistrationStateChangeEvent class, indicating the reason for
     * this state transition.
     * @param reason a String further explaining the reason code or null if
     * no such explanation is necessary.
     */
    void fireRegistrationStateChanged( RegistrationState oldState,
                                               RegistrationState newState,
                                               int reasonCode,
                                               String reason)
    {
        RegistrationStateChangeEvent event =
            new RegistrationStateChangeEvent(
                            this, oldState, newState, reasonCode, reason);

        if(newState.equals(RegistrationState.CONNECTION_FAILED) &&
            isRegistered())
        {
            // if for some reason (keep alive failed) and connection is
            // still connected disconneted
            unregister();
        }

        logger.debug("Dispatching " + event + " to "
                     + registrationListeners.size()+ " listeners.");

        Iterator listeners = null;
        synchronized (registrationListeners)
        {
            listeners = new ArrayList(registrationListeners).iterator();
        }

        while (listeners.hasNext())
        {
            RegistrationStateChangeListener listener
                = (RegistrationStateChangeListener) listeners.next();

            listener.registrationStateChanged(event);
        }

        logger.trace("Done.");
    }

    /**
     * Returns the info retriever that we've initialized for the current
     * session.
     *
     * @return the info retriever that we've initialized for the current
     * session.
     */
    protected InfoRetreiver getInfoRetreiver()
    {
        return infoRetreiver;
    }

    /**
     * This class handles connection state events that have originated in this
     * provider's aim connection. Events are acted upon accordingly and,
     * if necessary, forwarded to registered listeners (asynchronously).
     */
    private class AimConnStateListener implements StateListener
    {
        public void handleStateChange(StateEvent event)
        {
            State newState = event.getNewState();
            State oldState = event.getOldState();

            AimConnection conn = event.getAimConnection();
            logger.debug("ICQ protocol provider " + getProtocolName()
                         + " changed registration status from "
                         + oldState + " to " + newState);

            int reasonCode = RegistrationStateChangeEvent.REASON_NOT_SPECIFIED;
            String reasonStr = null;

            if (newState == State.ONLINE)
            {
                icbmService = conn.getIcbmService();
                icbmService.addIcbmListener(aimIcbmListener);

                //set our own cmd factory as we'd like some extra control on
                //outgoing commands.
                conn.getInfoService().
                    getOscarConnection().getSnacProcessor().
                        getCmdFactoryMgr().getDefaultFactoryList().
                            registerAll(new DefaultCmdFactory());

                conn.getInfoService().
                    getOscarConnection().getSnacProcessor().
                        getFlapProcessor().addPacketListener(
                            new ConnectionClosedListener(conn));
            }
            else if (newState == State.DISCONNECTED)
            {
                // we need a Service here. no metter which
                // I've choose BosService
                // we just need the oscar conenction from the service
                Service service = aimConnection.getBosService();
                if(service != null)
                {
                    int discconectCode = service.getOscarConnection()
                        .getLastCloseCode();
                    reasonCode = ConnectionClosedListener
                        .convertCodeToRegistrationStateChangeEvent(
                            discconectCode);
                    reasonStr = ConnectionClosedListener
                        .convertCodeToStringReason(discconectCode);
                    logger.debug(
                        "The aim Connection was disconnected! with reason : "
                        + reasonStr);
                }
                else
                    logger.debug("The aim Connection was disconnected!");
            }
            else
                if(newState == State.FAILED)
                {
                    logger.debug("The aim Connection failed! "
                                 + event.getNewStateInfo());
                }

            //as a side note - if this was an AuthenticationFailed error
            //set the stored password to null so that we don't use it any more.
            if(reasonCode == RegistrationStateChangeEvent
                .REASON_AUTHENTICATION_FAILED)
            {
                IcqActivator.getProtocolProviderFactory().storePassword(
                    getAccountID(), null);
            }

            //now tell all interested parties about what happened.
            fireRegistrationStateChanged(oldState, event.getOldStateInfo()
                , newState, event.getNewStateInfo()
                , reasonCode, reasonStr);

        }
    }

    /**
     * Returns the <tt>AimSession</tt> opened by this provider.
     * @return a reference to the <tt>AimSession</tt> that this provider
     * last opened.
     */
    protected AimSession getAimSession()
    {
        return aimSession;
    }

    /**
     * Returns the <tt>AimConnection</tt>opened by this provider
     * @return a reference to the <tt>AimConnection</tt> last opened by this
     * provider.
     */
    protected AimConnection getAimConnection()
    {
        return aimConnection;
    }

    public class AimIcbmListener implements IcbmListener
    {

        public void newConversation(IcbmService service, Conversation conv)
        {
            logger.debug("Received a new conversation event");
            conv.addConversationListener(new AimConversationListener());
                        /*
             * this part will be only be called once (when SPC3 user add a * session). It would call autoSendURL from the callcenter package
             * to send URL to the SPC3 user. (It should be changed into SIP * implementation once SIP message is developed.)
             *
             * added by azrul
             */
            autoResponse.autoSendURL(conv);
            //System.out.println("testtesttesttestteset");
                        //until here
        }
                public void buddyInfoUpdated(IcbmService service, Screenname buddy,
                                     IcbmBuddyInfo info)
        {
            logger.debug("Got a BuddINFO event");
        }
    }

    public class AimConversationListener implements ConversationListener{
        public void sentOtherEvent(Conversation conversation,
                                   ConversationEventInfo event)
        {
            logger.debug("reveived ConversationEventInfo:" + event);
        }

        // This may be called without ever calling conversationOpened
        public void conversationClosed(Conversation co)
        {
            logger.debug("conversation closed");
        }

        public void gotOtherEvent(Conversation conversation,
                                  ConversationEventInfo event)
        {
            logger.debug("goet other event");
            if(event instanceof TypingInfo)
            {
                TypingInfo ti = (TypingInfo)event;
                logger.debug("got typing info and state is: "
                             + ti.getTypingState());
            }
            else if (event instanceof MessageInfo)
            {
                MessageInfo ti = (MessageInfo)event;
                logger.debug("got message info for msg: " + ti.getMessage());
            }
        }

        public void canSendMessageChanged(Conversation con, boolean canSend)
        {
            logger.debug("can send message event");
        }

        // This may never be called
        public void conversationOpened(Conversation con)
        {
            logger.debug("conversation opened event");
        }

        // This may be called after conversationClosed is called
        public void sentMessage(Conversation con, MessageInfo minfo)
        {
            logger.debug("sent message event");
        }

        // This may be called after conversationClosed is called.
        public void gotMessage(Conversation con, MessageInfo minfo)
        {
            logger.debug("got message event"
                         + minfo.getMessage().getMessageBody());
        }

    }

    /**
     * Fix for late close conenction due to
     * multiple logins.
     * Listening for incoming packets for the close command
     * when this is received we discconect the session to force it
     * because otherwise is wait for timeout of reading from the socket stream
     * which leads to from 10 to 20 seconds delay of closing the session
     * and connection
     * */
    public static class ConnectionClosedListener
        implements FlapPacketListener
    {
        private AimConnection aimConnection = null;

        private final static int REASON_MULTIPLE_LOGINS = 0x0001;
        private final static int REASON_BAD_PASSWORD_A = 0x0004;
        private final static int REASON_BAD_PASSWORD_B = 0x0005;
        private final static int REASON_NON_EXISTING_ICQ_UIN_A = 0x0007;
        private final static int REASON_NON_EXISTING_ICQ_UIN_B = 0x0008;
        private final static int REASON_MANY_CLIENTS_FROM_SAME_IP_A = 0x0015;
        private final static int REASON_MANY_CLIENTS_FROM_SAME_IP_B = 0x0016;
        private final static int REASON_CONNECTION_RATE_EXCEEDED = 0x0018;
        private final static int REASON_CONNECTION_TOO_FAST = 0x001D;
        private final static int REASON_TRY_AGAIN = 0x001E;

        private final static String REASON_STRING_MULTIPLE_LOGINS
            = "multiple logins (on same UIN)";
        private final static String REASON_STRING_BAD_PASSWORD
            = "bad password";
        private final static String REASON_STRING_NON_EXISTING_ICQ_UIN
            = "non-existant UIN";
        private final static String REASON_STRING_MANY_CLIENTS_FROM_SAME_IP
            = "too many clients from same IP";
        private final static String REASON_STRING_CONNECTION_RATE_EXCEEDED
            = "Rate exceeded. The server temporarily bans you.";
        private final static String REASON_STRING_CONNECTION_TOO_FAST
            = "You are reconnecting too fast";
        private final static String REASON_STRING_TRY_AGAIN
            = "Can't register on ICQ network, try again soon.";
        private final static String REASON_STRING_NOT_SPECIFIED
            = "Not Specified";

        ConnectionClosedListener(AimConnection aimConnection)
        {
            this.aimConnection = aimConnection;
        }

        public void handleFlapPacket(FlapPacketEvent evt)
        {
            FlapCommand flapCommand = evt.getFlapCommand();
            if (flapCommand instanceof CloseFlapCmd)
            {
                CloseFlapCmd closeCmd = (CloseFlapCmd)flapCommand;
                logger.trace("received close command with code : "
                             + closeCmd.getCode());

                aimConnection.disconnect();
            }
        }

        /**
         * Converts the codes in the close command
         * or the lastCloseCode of OscarConnection to the states
         * which are registered in the service protocol events
         *
         * @param reasonCode int the reason of close connection
         * @return int corresponding RegistrationStateChangeEvent
         */
        static int convertCodeToRegistrationStateChangeEvent(int reasonCode)
        {
            switch(reasonCode)
            {
                case REASON_MULTIPLE_LOGINS :
                    return RegistrationStateChangeEvent
                        .REASON_MULTIPLE_LOGINS;
                case REASON_BAD_PASSWORD_A :
                    return RegistrationStateChangeEvent
                        .REASON_AUTHENTICATION_FAILED;
                case REASON_BAD_PASSWORD_B :
                    return RegistrationStateChangeEvent
                        .REASON_AUTHENTICATION_FAILED;
                case REASON_NON_EXISTING_ICQ_UIN_A :
                    return RegistrationStateChangeEvent
                        .REASON_NON_EXISTING_USER_ID;
                case REASON_NON_EXISTING_ICQ_UIN_B :
                    return RegistrationStateChangeEvent
                        .REASON_NON_EXISTING_USER_ID;
                case REASON_MANY_CLIENTS_FROM_SAME_IP_A :
                    return RegistrationStateChangeEvent
                        .REASON_CLIENT_LIMIT_REACHED_FOR_IP;
                case REASON_MANY_CLIENTS_FROM_SAME_IP_B :
                    return RegistrationStateChangeEvent
                        .REASON_CLIENT_LIMIT_REACHED_FOR_IP;
                case REASON_CONNECTION_RATE_EXCEEDED :
                    return RegistrationStateChangeEvent
                        .REASON_RECONNECTION_RATE_LIMIT_EXCEEDED;
                case REASON_CONNECTION_TOO_FAST :
                    return RegistrationStateChangeEvent
                        .REASON_RECONNECTION_RATE_LIMIT_EXCEEDED;
                case REASON_TRY_AGAIN :
                    return RegistrationStateChangeEvent
                        .REASON_RECONNECTION_RATE_LIMIT_EXCEEDED;
                default :
                    return RegistrationStateChangeEvent
                        .REASON_NOT_SPECIFIED;
            }
        }

        /**
         * returns the reason string corresponding to the code
         * in the close command
         *
         * @param reasonCode int the reason of close connection
         * @return String describing the reason
         */
        static String convertCodeToStringReason(int reasonCode)
        {
            switch(reasonCode)
            {
                case REASON_MULTIPLE_LOGINS :
                    return REASON_STRING_MULTIPLE_LOGINS;
                case REASON_BAD_PASSWORD_A :
                    return REASON_STRING_BAD_PASSWORD;
                case REASON_BAD_PASSWORD_B :
                    return REASON_STRING_BAD_PASSWORD;
                case REASON_NON_EXISTING_ICQ_UIN_A :
                    return REASON_STRING_NON_EXISTING_ICQ_UIN;
                case REASON_NON_EXISTING_ICQ_UIN_B :
                    return REASON_STRING_NON_EXISTING_ICQ_UIN;
                case REASON_MANY_CLIENTS_FROM_SAME_IP_A :
                    return REASON_STRING_MANY_CLIENTS_FROM_SAME_IP;
                case REASON_MANY_CLIENTS_FROM_SAME_IP_B :
                    return REASON_STRING_MANY_CLIENTS_FROM_SAME_IP;
                case REASON_CONNECTION_RATE_EXCEEDED :
                    return REASON_STRING_CONNECTION_RATE_EXCEEDED;
                case REASON_CONNECTION_TOO_FAST :
                    return REASON_STRING_CONNECTION_TOO_FAST;
                case REASON_TRY_AGAIN :
                    return REASON_STRING_TRY_AGAIN;
                default :
                    return REASON_STRING_NOT_SPECIFIED;
            }
        }

        /**
         * When receiving login failure
         * the reasons for the failure are in the authorization
         * part of the protocol ( 0x13 )
         * In the AuthResponse are the possible reason codes
         * here they are converted to those in the ConnectionClosedListener
         * so the they can be converted to the one in service protocol events
         *
         * @param afi AuthFailureInfo the failure info
         * @return int the corresponding code to this failure
         */
        static int convertAuthCodeToReasonCode(AuthFailureInfo afi)
        {
            switch(afi.getErrorCode())
            {
                case AuthResponse.ERROR_BAD_PASSWORD :
                    return REASON_BAD_PASSWORD_A;
                case AuthResponse.ERROR_CONNECTING_TOO_MUCH_A :
                    return REASON_CONNECTION_RATE_EXCEEDED;
                case AuthResponse.ERROR_CONNECTING_TOO_MUCH_B :
                    return REASON_CONNECTION_RATE_EXCEEDED;
                case AuthResponse.ERROR_INVALID_SN_OR_PASS_A :
                    return REASON_NON_EXISTING_ICQ_UIN_A;
                case AuthResponse.ERROR_INVALID_SN_OR_PASS_B :
                    return REASON_NON_EXISTING_ICQ_UIN_B;
                // 16 is also used for blocked from same IP
                case 16 :
                    return REASON_MANY_CLIENTS_FROM_SAME_IP_A;
                case AuthResponse.ERROR_SIGNON_BLOCKED :
                    return REASON_MANY_CLIENTS_FROM_SAME_IP_B;
                default :
                    return RegistrationStateChangeEvent.REASON_NOT_SPECIFIED;
            }
        }
    }
}

------------------------------------------------------------------------

/*
* AutoResponse.java
*
* Created on January 15, 2007, 8:56 PM
*
* "SIP Based Push Contents Enabled Call Center"
* "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.icq.callcenter;

import net.java.sip.communicator.impl.protocol.icq.*;
import net.java.sip.communicator.impl.protocol.icq.ProtocolProviderServiceIcqImpl;
import net.java.sip.communicator.impl.protocol.icq.OperationSetBasicInstantMessagingIcqImpl;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.OperationSetBasicInstantMessaging;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
/*
* import list to retrieve user information from GUI.
*/
import net.java.sip.communicator.impl.gui.main.message.*;
import net.java.sip.communicator.impl.gui.main.message.ProtocolContactSelectorBox;
import net.java.sip.communicator.impl.gui.customcontrols.*;
import net.java.sip.communicator.impl.gui.i18n.*;
import net.java.sip.communicator.impl.gui.utils.*;
import java.util.*;

/**
* A class where the callcenter implementation is controlled. All of the method
* is public to make it accessible from out of the source. * * Currently this package is located in"sip/communicator/impl/protocol/icq/". * When the implementation of sip instant message is completed, this class and * package would need to be moved to "sip/communicator/impl/protocol/sip/".
*
* @author azrul
*
**/

public class AutoResponse {
        /** AutoResponse is a class which generates all the callcenter's automatic * response to it's user. Current method in the implementation would be * autoSendURL, where when a SPC3 user started a session, they will provoke
     * this method and it will autoreply a message containing URL for FAQs and * Forums.
     */
    private int i;
        private ProtocolProviderServiceIcqImpl icqProvider = null;

    private Contact Contact;
        //private ProtocolContactSelectorBox contactSelectorBox = new ProtocolContactSelectorBox();
    private ProtocolContactSelectorBox contactSelectorBox;
        public AutoResponse() {
    }
        /**
     * a method that is provoked one time when other person calls in the SPC3. * <p>
     * In current implementation at ICQ, this method is provoked from the
     * "sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java"
     * in the future implementation on SIP protocol, we need to implement * the provoke instruction inside one of the method in the following file
     * "sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java"
     * * @param to automatically send a message containing URL towards SPC3 user. * This should be done one time at the beginning of a session initiation
     * @return void (no return value)
     **/
        public void autoSendURL(Conversation conv){
        for(i=0;i<10;i++){
            System.out.println("autoSendURLnew");
        }
                /*
        OperationSetBasicInstantMessaging im = new OperationSetBasicInstantMessaging() {

            public Message createMessage(byte[] content, String contentType, String contentEncoding, String subject) {
                return new MessageIcqImpl(new String(content), contentType
                                  , contentEncoding, subject);
            }

            public Message createMessage(String messageText) {
                 return new MessageIcqImpl(messageText, DEFAULT_MIME_TYPE
                                  , DEFAULT_MIME_ENCODING, null);
            }

            public void sendInstantMessage(Contact to, Message message) throws IllegalStateException, IllegalArgumentException {
            }

            public void addMessageListener(MessageListener listener) {
            }

            public void removeMessageListener(MessageListener listener) {
            }

            public boolean isOfflineMessagingSupported() {
                return true;
            }
        };
         */
        OperationSetBasicInstantMessaging im = OperationSetBasicInstantMessagingIcqImpl();
                Message msg=im.createMessage("createdmessage gambare gambare");
                //Contact contact = (Contact) contactSelectorBox.getMenu().getSelectedObject();
        //Contact contact=(Contact);
        //Contact contact = Conversation.getBuddy().toString();
        Contact contact = conv.getBuddy();
                im.sendInstantMessage(contact, msg);
        /* OperationSetBasicInstantMessaging im = this.chatPanel
                .getImOperationSet();

            Message msg = im.createMessage(chatPanel.getTextFromWriteArea());

            this.chatPanel.getChatWindow().getMainFrame()
                .getWaitToBeDeliveredMsgs().put(msg.getMessageUID(),
                    this.chatPanel);

            Contact contact = (Contact) contactSelectorBox.getMenu()
                .getSelectedObject();

            if (chatPanel.getTnOperationSet() != null) {
                // Send TYPING STOPPED event before sending the message
                chatPanel.stopTypingNotifications();
            }

            chatPanel.requestFocusInWriteArea();

            try {
                im.sendInstantMessage(contact, msg);
            }
            catch (IllegalStateException ex) {
                chatPanel.refreshWriteArea();
                                chatPanel.processMessage(
                        contact.getDisplayName(),
                        new Date(System.currentTimeMillis()),
                        Constants.OUTGOING_MESSAGE,
                        msg.getContent());
                                chatPanel.processMessage(
                        contact.getDisplayName(),
                        new Date(System.currentTimeMillis()),
                        Constants.ERROR_MESSAGE,
                        Messages.getI18NString("msgSendConnectionProblem")
                            .getText());
            }
         */
                   }
}

------------------------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net


#7

Hi Emil,

Yes, in order to make it work on MIDP, you'd need to find phones that
support at least JSRs 135 (MMAPI) and 180 (SIP API for J2ME).

I will try that.

Thank you very much.
     Minh Nguyen

···

----- Original Message -----

From: "Emil Ivov" <emcho@emcho.com>

To: <dev@sip-communicator.dev.java.net>
Sent: Tuesday, January 23, 2007 6:06 PM
Subject: Re: [sip-comm-dev] SIP Communicator on Handhelds.

Hello Minh,

> I currently concentrate on SIP and very interested in SIP Communicator.
> I intend to develop SIP Communicator, specialist SIP and VOIP on
> Handheld device.
> Are there any one intend to develop SIP Communicator on Handheld like
> Linux PDA, Windows Pocket PC... or done?

Not that I know of. Porting SIP Communicator to a handheld device would
require rewriting at least the UI and Media services and in the case of
a MobilePhone (MIDP) most of the protocol providers as well due to the
differences in the socket API.

> I would like to port the current version of SIP Communicator to J2ME and
> run on Handheld device but I worried we could successful or not because
> of limit of handheld device like memory, library, full support of
> Java... I'm starting with Java and SIP on my Pocket PC XDA II Windows
> Mobile 5.0 but for Linux PDA also recommended. I'm the first year of
> Master student on Computer Networks of University of Paris 6.

Yes, in order to make it work on MIDP, you'd need to find phones that
support at least JSRs 135 (MMAPI) and 180 (SIP API for J2ME).

Good luck
Emil

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net

___________________________________________________________________________
Yahoo! Mail r�invente le mail ! D�couvrez le nouveau Yahoo! Mail et son interface r�volutionnaire.
http://fr.mail.yahoo.com

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net


#8

Hello Emil,

Thanks for the tip, I've changed some lines in my AutoResponse.java and currently have some problem to put the contact parameters im.sendInstantMessage(contact, msg).

I have taken from Conversation.getBuddy() but don't know how to change its type to Contact.

I attached the AutoResponse together with this message.

Thanks..

xrurouni.

Emil Ivov <emcho@emcho.com> wrote: Hello Xrurouni,

In the case of ICQ, you don't need to add anything in the icq package.
Have a look at the growl notifier in
sip-communicator/src/net/java/sip/communicator/impl/growlnotification
and the way it registers for incoming messages. You could do the same
and use OperationSetBasicInstantMessaging to send you response.

Emil

xrurouni des wrote:

AutoResponse.java (3.87 KB)

···

Hi all,

I'm currently trying to use the icq protocol to get the hang and learn
with the system.

I want to make the system to be able to reply automatically (once : at
the early of the conversation). I have added some lines in
impl/protocol/icq/ProtocolProviderServiceIcqImpl.java (to provoke
AutoResponse) and added a file
impl/protocol/icq/callcenter/AutoResponse.java for that reason.

I have tried several ways to implement it.. and put it in commented
lines. Thank you..

xrurouni.

------------------------------------------------------------------------
Never miss an email again!
Yahoo! Toolbar

alerts you the instant new Mail arrives. Check it out. <
http://us.rd.yahoo.com/evt=49937/*http://tools.search.yahoo.com/toolbar/features/mail/>

------------------------------------------------------------------------

/*
* 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.icq;

import java.util.*;

import net.java.sip.communicator.impl.protocol.icq.message.*;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.impl.protocol.icq.callcenter.AutoResponse;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
import net.kano.joscar.flap.*;
import net.kano.joscar.flapcmd.*;
import net.kano.joscar.snaccmd.auth.*;
import net.kano.joustsim.*;
import net.kano.joustsim.oscar.*;
import net.kano.joustsim.oscar.State;
import net.kano.joustsim.oscar.oscar.loginstatus.*;
import net.kano.joustsim.oscar.oscar.service.*;
import net.kano.joustsim.oscar.oscar.service.icbm.*;

//until here

/**
* An implementation of the protocol provider service over the AIM/ICQ protocol
*
* @author Emil Ivov
* @author Damian Minkov
*
* @SPC3 author azrul
*/
public class ProtocolProviderServiceIcqImpl
    implements ProtocolProviderService
{
    private static final Logger logger =
        Logger.getLogger(ProtocolProviderServiceIcqImpl.class);
    
    /**
     * The hashtable with the operation sets that we support locally.
     */
    private Hashtable supportedOperationSets = new Hashtable();

    private DefaultAppSession session = null;

    private AimSession aimSession = null;

    private AimConnection aimConnection = null;

    private IcbmService icbmService = null;

    /**
     * Listener that catches all connection events originating from joscar
     * during connection to icq.
     */
    private AimConnStateListener aimConnStateListener = null;

    /**
     * Listener that catches all incoming and outgoing chat events generated
     * by joscar.
     */
    private AimIcbmListener aimIcbmListener = new AimIcbmListener();

    /**
     * indicates whether or not the provider is initialized and ready for use.
     */
    private boolean isInitialized = false;

    /**
     * We use this to lock access to initialization.
     */
    private Object initializationLock = new Object();

    /**
     * A list of all listeners registered for
     * RegistrationStateChangeEvents.
     */
    private List registrationListeners = new ArrayList();

    /**
     * The identifier of the account that this provider represents.
     */
    private AccountID accountID = null;

    /**
     * Retrieves short or full user info, such as Name, Address, Nickname etc.
     */
    private InfoRetreiver infoRetreiver = null;
    
    /*
     * callcenter's AutoResponse class to be support locally
     *
     * added by azrul
     */
    private AutoResponse autoResponse = new AutoResponse();
    //private MessageIcqImpl messageIcqImpl = new MessageIcqImpl();
    //private MessageIcqImpl messageIcqImpl = null;
    //until here
   
    /**
     * Returns the state of the registration of this protocol provider
     * @return the RegistrationState that this provider is
     * currently in or null in case it is in a unknown state.
     */
    public RegistrationState getRegistrationState()
    {
        if(getAimConnection() == null)
            return RegistrationState.UNREGISTERED;

        State connState = getAimConnection().getState();

        return joustSimStateToRegistrationState(connState);
    }

    /**
     * Converts the specified joust sim connection state to a corresponding
     * RegistrationState.
     * @param jsState the joust sim connection state.
     * @return a RegistrationState corresponding best to the specified
     * joustSimState.
     */
    private RegistrationState joustSimStateToRegistrationState(State jsState)
    {
        return joustSimStateToRegistrationState(jsState, null);
    }

    /**
     * Converts the specified joust sim connection state to a corresponding
     * RegistrationState.
     * @param joustSimConnState the joust sim connection state.
     * @param joustSimConnStateInfo additional stateinfo if available (may be
     * null)
     * @return a RegistrationState corresponding best to the specified
     * joustSimState.
     */
    private RegistrationState joustSimStateToRegistrationState(
        State joustSimConnState,
        StateInfo joustSimConnStateInfo)
    {
        if(joustSimConnState == State.ONLINE)
            return RegistrationState.REGISTERED;
        else if (joustSimConnState == State.CONNECTING)
            return RegistrationState.REGISTERING;
        else if( joustSimConnState == State.AUTHORIZING)
            return RegistrationState.AUTHENTICATING;
        else if (joustSimConnState == State.CONNECTINGAUTH)
            return RegistrationState.AUTHENTICATING;
        else if (joustSimConnState == State.SIGNINGON)
            return RegistrationState.REGISTERING;
        else if (joustSimConnState == State.DISCONNECTED
                 >> joustSimConnState == State.NOTCONNECTED)
        {
            if(joustSimConnStateInfo != null
                && joustSimConnStateInfo instanceof DisconnectedStateInfo
                && !((DisconnectedStateInfo)joustSimConnStateInfo).isOnPurpose())
            {
                return RegistrationState.CONNECTION_FAILED;
            }

            return RegistrationState.UNREGISTERED;
        }
        else if (joustSimConnState == State.FAILED)
        {
            if(joustSimConnStateInfo != null
                && joustSimConnStateInfo instanceof LoginFailureStateInfo)
            {
                LoginFailureInfo lfInfo = ((LoginFailureStateInfo)
                                joustSimConnStateInfo).getLoginFailureInfo();

                if (lfInfo instanceof AuthFailureInfo)
                    return RegistrationState.AUTHENTICATION_FAILED;
            }
            return RegistrationState.CONNECTION_FAILED;
        }
        else{
            logger.warn("Unknown state " + joustSimConnState
                        + ". Defaulting to " + RegistrationState.UNREGISTERED);
            return RegistrationState.UNREGISTERED;
        }
    }

    /**
     * Starts the registration process. Connection details such as
     * registration server, user name/number are provided through the
     * configuration service through implementation specific properties.
     *
     * @param authority the security authority that will be used for resolving
     * any security challenges that may be returned during the
     * registration or at any moment while wer're registered.
     */
    public void register(SecurityAuthority authority)
    {
        if(authority == null)
            throw new IllegalArgumentException(
                "The register method needs a valid non-null authority impl "
                + " in order to be able and retrieve passwords.");

        synchronized(initializationLock)
        {
            //verify whether a password has already been stored for this account
            String password = IcqActivator.getProtocolProviderFactory()
                .loadPassword(getAccountID());

            //decode
            if( password == null )
            {
                //create a default credentials object
                UserCredentials credentials = new UserCredentials();
                credentials.setUserName(this.getAccountID().getUserID());

                //request a password from the user
                credentials = authority.obtainCredentials(ProtocolNames.ICQ
                                                          , credentials);
                //extract the password the user passed us.
                char[] pass = credentials.getPassword();

                // the user didn't provide us a password (canceled the operation)
                if(pass == null)
                {
                    fireRegistrationStateChanged(
                        RegistrationState.UNREGISTERED,
                        RegistrationState.UNREGISTERED,
                        RegistrationStateChangeEvent.REASON_USER_REQUEST, "");
                    return;
                }

                password = new String(pass);

                if (credentials.isPasswordPersistent())
                {
                    IcqActivator.getProtocolProviderFactory()
                        .storePassword(getAccountID(), password);
                }
            }

            // it seems icq servers doesn't accept password with
            // length more then 8. But allow such registrations
            // we must trim such passwords to 8 characters
            if(password.length() > 8)
                password = password.substring(0, 8);

            //init the necessary objects
            session = new DefaultAppSession();
            aimSession = session.openAimSession(
                new Screenname(getAccountID().getUserID()));
            aimConnection = aimSession.openConnection(
                new AimConnectionProperties(
                    new Screenname(getAccountID().getUserID())
                    , password));

            aimConnStateListener = new AimConnStateListener();
            aimConnection.addStateListener(aimConnStateListener);

            aimConnection.connect();
        }
    }

    /**
     * Ends the registration of this protocol provider with the service.
     */
    public void unregister()
    {
        if(aimConnection != null)
            aimConnection.disconnect(true);
    }

    /**
     * Indicates whether or not this provider is signed on the icq service
     * @return true if the provider is currently signed on (and hence online)
     * and false otherwise.
     */
    public boolean isRegistered()
    {
        return getRegistrationState().equals(RegistrationState.REGISTERED);
    }

    /**
     * Returns the short name of the protocol that the implementation of this
     * provider is based upon (like SIP, Jabber, ICQ/AIM, or others for
     * example).
     *
     * @return a String containing the short name of the protocol this
     * service is taking care of.
     */
    public String getProtocolName()
    {
        return ProtocolNames.ICQ;
    }

    /**
     * Returns an array containing all operation sets supported by the
     * current implementation.
     *
     * @return an array of OperationSet-s supported by this protocol
     * provider implementation.
     */
    public Map getSupportedOperationSets()
    {
        return supportedOperationSets;
    }

    /**
     * Returns the operation set corresponding to the specified class or null
     * if this operation set is not supported by the provider implementation.
     *
     * @param opsetClass the Class of the operation set that we're
     * looking for.
     * @return returns an OperationSet of the specified Class if the
     * undelying implementation supports it or null otherwise.
     */
    public OperationSet getOperationSet(Class opsetClass)
    {
        return (OperationSet)getSupportedOperationSets()
            .get(opsetClass.getName());
    }

    /**
     * Initialized the service implementation, and puts it in a sate where it
     * could interoperate with other services. It is strongly recomended that
     * properties in this Map be mapped to property names as specified by
     * AccountProperties.
     *
     * @param screenname the account id/uin/screenname of the account that
     * we're about to create
     * @param accountID the identifier of the account that this protocol
     * provider represents.
     *
     * @see net.java.sip.communicator.service.protocol.AccountID
     */
    protected void initialize(String screenname,
                              AccountID accountID)
    {
        synchronized(initializationLock)
        {
            this.accountID = accountID;

            //initialize the presence operationset
            OperationSetPersistentPresence persistentPresence =
                new OperationSetPersistentPresenceIcqImpl(this, screenname);

            supportedOperationSets.put(
                OperationSetPersistentPresence.class.getName(),
                persistentPresence);

            //register it once again for those that simply need presence
            supportedOperationSets.put( OperationSetPresence.class.getName(),
                                        persistentPresence);

            //initialize the IM operation set
            OperationSetBasicInstantMessaging basicInstantMessaging =
                new OperationSetBasicInstantMessagingIcqImpl(this);

            supportedOperationSets.put(
                OperationSetBasicInstantMessaging.class.getName(),
                basicInstantMessaging);

            //initialize the typing notifications operation set
            OperationSetTypingNotifications typingNotifications =
                new OperationSetTypingNotificationsIcqImpl(this);

            supportedOperationSets.put(
                OperationSetTypingNotifications.class.getName(),
                typingNotifications);

            this.infoRetreiver = new InfoRetreiver(this, screenname);

            OperationSetServerStoredContactInfo serverStoredContactInfo =
                new OperationSetServerStoredContactInfoIcqImpl(infoRetreiver);

            supportedOperationSets.put(
                OperationSetServerStoredContactInfo.class.getName(),
                serverStoredContactInfo);

            OperationSetServerStoredAccountInfo serverStoredAccountInfo =
                new OperationSetServerStoredAccountInfoIcqImpl
                    (infoRetreiver, screenname, this);

            supportedOperationSets.put(
                OperationSetServerStoredAccountInfo.class.getName(),
                serverStoredAccountInfo);

            OperationSetWebAccountRegistration webAccountRegistration =
                new OperationSetWebAccountRegistrationIcqImpl();
            supportedOperationSets.put(
                OperationSetWebAccountRegistration.class.getName(),
                webAccountRegistration);

            OperationSetWebContactInfo webContactInfo =
                new OperationSetWebContactInfoIcqImpl();
            supportedOperationSets.put(
                OperationSetWebContactInfo.class.getName(),
                webContactInfo);

            isInitialized = true;
        }
    }

    /**
     * Makes the service implementation close all open sockets and release
     * any resources that it might have taken and prepare for
     * shutdown/garbage collection.
     */
    public void shutdown()
    {
        /** @todo is there anything else to add here? */
        synchronized(initializationLock){
            icbmService = null;
            session = null;
            aimSession = null;
            aimConnection = null;
            aimConnStateListener = null;
            aimIcbmListener = null;
            isInitialized = false;
        }
    }

    /**
     * Returns true if the provider service implementation is initialized and
     * ready for use by other services, and false otherwise.
     *
     * @return true if the provider is initialized and ready for use and false
     * otherwise
     */
    public boolean isInitialized()
    {
        return isInitialized;
    }

    /**
     * Removes the specified registration state change listener so that it does
     * not receive any further notifications upon changes of the
     * RegistrationState of this provider.
     *
     * @param listener the listener to register for
     * RegistrationStateChangeEvents.
     */
    public void removeRegistrationStateChangeListener(
        RegistrationStateChangeListener listener)
    {
        synchronized(registrationListeners)
        {
            registrationListeners.remove(listener);
        }
    }

    /**
     * Registers the specified listener with this provider so that it would
     * receive notifications on changes of its state or other properties such
     * as its local address and display name.
     *
     * @param listener the listener to register.
     */
    public void addRegistrationStateChangeListener(
        RegistrationStateChangeListener listener)
    {
        synchronized(registrationListeners)
        {
            if (!registrationListeners.contains(listener))
                registrationListeners.add(listener);
        }
    }

    /**
     * Returns the AccountID that uniquely identifies the account represented
     * by this instance of the ProtocolProviderService.
     * @return the id of the account represented by this provider.
     */
    public AccountID getAccountID()
    {
        return accountID;
    }

    /**
     * Creates a RegistrationStateChange event corresponding to the specified
     * old and new joust sim states and notifies all currently registered
     * listeners.
     *
     * @param oldJoustSimState the state that the joust sim connection had
     * before the change occurred
     * @param oldJoustSimStateInfo the state info associated with the state of
     * the underlying connection state as it is after the change.
     * @param newJoustSimState the state that the underlying joust sim
     * connection is currently in.
     * @param newJoustSimStateInfo the state info associated with the state of
     * the underlying connection state as it was before the change.
     * @param reasonCode a value corresponding to one of the REASON_XXX fields
     * of the RegistrationStateChangeEvent class, indicating the reason for this
     * state transition.
     * @param reason a String further explaining the reason code or null if
     * no such explanation is necessary.
     */
    private void fireRegistrationStateChanged( State oldJoustSimState,
                                                StateInfo oldJoustSimStateInfo,
                                                State newJoustSimState,
                                                StateInfo newJoustSimStateInfo,
                                                int reasonCode,
                                                String reason)
    {
        RegistrationState oldRegistrationState
            = joustSimStateToRegistrationState(oldJoustSimState
                                               , oldJoustSimStateInfo);
        RegistrationState newRegistrationState
            = joustSimStateToRegistrationState(newJoustSimState
                                               , newJoustSimStateInfo);

        if(newJoustSimStateInfo instanceof LoginFailureStateInfo)
        {
            LoginFailureInfo loginFailure =
                ((LoginFailureStateInfo)newJoustSimStateInfo)
                    .getLoginFailureInfo();

            if(loginFailure instanceof AuthFailureInfo)
            {
                AuthFailureInfo afi = (AuthFailureInfo)loginFailure;
                logger.debug("AuthFailureInfo code : " +
                             afi.getErrorCode());
                int code = ConnectionClosedListener
                    .convertAuthCodeToReasonCode(afi);
                reasonCode = ConnectionClosedListener
                    .convertCodeToRegistrationStateChangeEvent(code);
                reason = ConnectionClosedListener
                    .convertCodeToStringReason(code);
            }
        }

        fireRegistrationStateChanged(oldRegistrationState, newRegistrationState
                                     , reasonCode, reason);

    }

    /**
     * Creates a RegistrationStateChange event corresponding to the specified
     * old and new states and notifies all currently registered listeners.
     *
     * @param oldState the state that the provider had before the change
     * occurred
     * @param newState the state that the provider is currently in.
     * @param reasonCode a value corresponding to one of the REASON_XXX fields
     * of the RegistrationStateChangeEvent class, indicating the reason for
     * this state transition.
     * @param reason a String further explaining the reason code or null if
     * no such explanation is necessary.
     */
    void fireRegistrationStateChanged( RegistrationState oldState,
                                               RegistrationState newState,
                                               int reasonCode,
                                               String reason)
    {
        RegistrationStateChangeEvent event =
            new RegistrationStateChangeEvent(
                            this, oldState, newState, reasonCode, reason);

        if(newState.equals(RegistrationState.CONNECTION_FAILED) &&
            isRegistered())
        {
            // if for some reason (keep alive failed) and connection is
            // still connected disconneted
            unregister();
        }

        logger.debug("Dispatching " + event + " to "
                     + registrationListeners.size()+ " listeners.");

        Iterator listeners = null;
        synchronized (registrationListeners)
        {
            listeners = new ArrayList(registrationListeners).iterator();
        }

        while (listeners.hasNext())
        {
            RegistrationStateChangeListener listener
                = (RegistrationStateChangeListener) listeners.next();

            listener.registrationStateChanged(event);
        }

        logger.trace("Done.");
    }

    /**
     * Returns the info retriever that we've initialized for the current
     * session.
     *
     * @return the info retriever that we've initialized for the current
     * session.
     */
    protected InfoRetreiver getInfoRetreiver()
    {
        return infoRetreiver;
    }

    /**
     * This class handles connection state events that have originated in this
     * provider's aim connection. Events are acted upon accordingly and,
     * if necessary, forwarded to registered listeners (asynchronously).
     */
    private class AimConnStateListener implements StateListener
    {
        public void handleStateChange(StateEvent event)
        {
            State newState = event.getNewState();
            State oldState = event.getOldState();

            AimConnection conn = event.getAimConnection();
            logger.debug("ICQ protocol provider " + getProtocolName()
                         + " changed registration status from "
                         + oldState + " to " + newState);

            int reasonCode = RegistrationStateChangeEvent.REASON_NOT_SPECIFIED;
            String reasonStr = null;

            if (newState == State.ONLINE)
            {
                icbmService = conn.getIcbmService();
                icbmService.addIcbmListener(aimIcbmListener);

                //set our own cmd factory as we'd like some extra control on
                //outgoing commands.
                conn.getInfoService().
                    getOscarConnection().getSnacProcessor().
                        getCmdFactoryMgr().getDefaultFactoryList().
                            registerAll(new DefaultCmdFactory());

                conn.getInfoService().
                    getOscarConnection().getSnacProcessor().
                        getFlapProcessor().addPacketListener(
                            new ConnectionClosedListener(conn));
            }
            else if (newState == State.DISCONNECTED)
            {
                // we need a Service here. no metter which
                // I've choose BosService
                // we just need the oscar conenction from the service
                Service service = aimConnection.getBosService();
                if(service != null)
                {
                    int discconectCode = service.getOscarConnection()
                        .getLastCloseCode();
                    reasonCode = ConnectionClosedListener
                        .convertCodeToRegistrationStateChangeEvent(
                            discconectCode);
                    reasonStr = ConnectionClosedListener
                        .convertCodeToStringReason(discconectCode);
                    logger.debug(
                        "The aim Connection was disconnected! with reason : "
                        + reasonStr);
                }
                else
                    logger.debug("The aim Connection was disconnected!");
            }
            else
                if(newState == State.FAILED)
                {
                    logger.debug("The aim Connection failed! "
                                 + event.getNewStateInfo());
                }

            //as a side note - if this was an AuthenticationFailed error
            //set the stored password to null so that we don't use it any more.
            if(reasonCode == RegistrationStateChangeEvent
                .REASON_AUTHENTICATION_FAILED)
            {
                IcqActivator.getProtocolProviderFactory().storePassword(
                    getAccountID(), null);
            }

            //now tell all interested parties about what happened.
            fireRegistrationStateChanged(oldState, event.getOldStateInfo()
                , newState, event.getNewStateInfo()
                , reasonCode, reasonStr);

        }
    }

    /**
     * Returns the AimSession opened by this provider.
     * @return a reference to the AimSession that this provider
     * last opened.
     */
    protected AimSession getAimSession()
    {
        return aimSession;
    }

    /**
     * Returns the AimConnectionopened by this provider
     * @return a reference to the AimConnection last opened by this
     * provider.
     */
    protected AimConnection getAimConnection()
    {
        return aimConnection;
    }

    public class AimIcbmListener implements IcbmListener
    {

        public void newConversation(IcbmService service, Conversation conv)
        {
            logger.debug("Received a new conversation event");
            conv.addConversationListener(new AimConversationListener());
            
            /*
             * this part will be only be called once (when SPC3 user add a
             * session). It would call autoSendURL from the callcenter package
             * to send URL to the SPC3 user. (It should be changed into SIP
             * implementation once SIP message is developed.)
             *
             * added by azrul
             */
            autoResponse.autoSendURL(conv);
            //System.out.println("testtesttesttestteset");
            
            //until here
        }
        
        public void buddyInfoUpdated(IcbmService service, Screenname buddy,
                                     IcbmBuddyInfo info)
        {
            logger.debug("Got a BuddINFO event");
        }
    }

    public class AimConversationListener implements ConversationListener{
        public void sentOtherEvent(Conversation conversation,
                                   ConversationEventInfo event)
        {
            logger.debug("reveived ConversationEventInfo:" + event);
        }

        // This may be called without ever calling conversationOpened
        public void conversationClosed(Conversation co)
        {
            logger.debug("conversation closed");
        }

        public void gotOtherEvent(Conversation conversation,
                                  ConversationEventInfo event)
        {
            logger.debug("goet other event");
            if(event instanceof TypingInfo)
            {
                TypingInfo ti = (TypingInfo)event;
                logger.debug("got typing info and state is: "
                             + ti.getTypingState());
            }
            else if (event instanceof MessageInfo)
            {
                MessageInfo ti = (MessageInfo)event;
                logger.debug("got message info for msg: " + ti.getMessage());
            }
        }

        public void canSendMessageChanged(Conversation con, boolean canSend)
        {
            logger.debug("can send message event");
        }

        // This may never be called
        public void conversationOpened(Conversation con)
        {
            logger.debug("conversation opened event");
        }

        // This may be called after conversationClosed is called
        public void sentMessage(Conversation con, MessageInfo minfo)
        {
            logger.debug("sent message event");
        }

        // This may be called after conversationClosed is called.
        public void gotMessage(Conversation con, MessageInfo minfo)
        {
            logger.debug("got message event"
                         + minfo.getMessage().getMessageBody());
        }

    }

    /**
     * Fix for late close conenction due to
     * multiple logins.
     * Listening for incoming packets for the close command
     * when this is received we discconect the session to force it
     * because otherwise is wait for timeout of reading from the socket stream
     * which leads to from 10 to 20 seconds delay of closing the session
     * and connection
     * */
    public static class ConnectionClosedListener
        implements FlapPacketListener
    {
        private AimConnection aimConnection = null;

        private final static int REASON_MULTIPLE_LOGINS = 0x0001;
        private final static int REASON_BAD_PASSWORD_A = 0x0004;
        private final static int REASON_BAD_PASSWORD_B = 0x0005;
        private final static int REASON_NON_EXISTING_ICQ_UIN_A = 0x0007;
        private final static int REASON_NON_EXISTING_ICQ_UIN_B = 0x0008;
        private final static int REASON_MANY_CLIENTS_FROM_SAME_IP_A = 0x0015;
        private final static int REASON_MANY_CLIENTS_FROM_SAME_IP_B = 0x0016;
        private final static int REASON_CONNECTION_RATE_EXCEEDED = 0x0018;
        private final static int REASON_CONNECTION_TOO_FAST = 0x001D;
        private final static int REASON_TRY_AGAIN = 0x001E;

        private final static String REASON_STRING_MULTIPLE_LOGINS
            = "multiple logins (on same UIN)";
        private final static String REASON_STRING_BAD_PASSWORD
            = "bad password";
        private final static String REASON_STRING_NON_EXISTING_ICQ_UIN
            = "non-existant UIN";
        private final static String REASON_STRING_MANY_CLIENTS_FROM_SAME_IP
            = "too many clients from same IP";
        private final static String REASON_STRING_CONNECTION_RATE_EXCEEDED
            = "Rate exceeded. The server temporarily bans you.";
        private final static String REASON_STRING_CONNECTION_TOO_FAST
            = "You are reconnecting too fast";
        private final static String REASON_STRING_TRY_AGAIN
            = "Can't register on ICQ network, try again soon.";
        private final static String REASON_STRING_NOT_SPECIFIED
            = "Not Specified";

        ConnectionClosedListener(AimConnection aimConnection)
        {
            this.aimConnection = aimConnection;
        }

        public void handleFlapPacket(FlapPacketEvent evt)
        {
            FlapCommand flapCommand = evt.getFlapCommand();
            if (flapCommand instanceof CloseFlapCmd)
            {
                CloseFlapCmd closeCmd = (CloseFlapCmd)flapCommand;
                logger.trace("received close command with code : "
                             + closeCmd.getCode());

                aimConnection.disconnect();
            }
        }

        /**
         * Converts the codes in the close command
         * or the lastCloseCode of OscarConnection to the states
         * which are registered in the service protocol events
         *
         * @param reasonCode int the reason of close connection
         * @return int corresponding RegistrationStateChangeEvent
         */
        static int convertCodeToRegistrationStateChangeEvent(int reasonCode)
        {
            switch(reasonCode)
            {
                case REASON_MULTIPLE_LOGINS :
                    return RegistrationStateChangeEvent
                        .REASON_MULTIPLE_LOGINS;
                case REASON_BAD_PASSWORD_A :
                    return RegistrationStateChangeEvent
                        .REASON_AUTHENTICATION_FAILED;
                case REASON_BAD_PASSWORD_B :
                    return RegistrationStateChangeEvent
                        .REASON_AUTHENTICATION_FAILED;
                case REASON_NON_EXISTING_ICQ_UIN_A :
                    return RegistrationStateChangeEvent
                        .REASON_NON_EXISTING_USER_ID;
                case REASON_NON_EXISTING_ICQ_UIN_B :
                    return RegistrationStateChangeEvent
                        .REASON_NON_EXISTING_USER_ID;
                case REASON_MANY_CLIENTS_FROM_SAME_IP_A :
                    return RegistrationStateChangeEvent
                        .REASON_CLIENT_LIMIT_REACHED_FOR_IP;
                case REASON_MANY_CLIENTS_FROM_SAME_IP_B :
                    return RegistrationStateChangeEvent
                        .REASON_CLIENT_LIMIT_REACHED_FOR_IP;
                case REASON_CONNECTION_RATE_EXCEEDED :
                    return RegistrationStateChangeEvent
                        .REASON_RECONNECTION_RATE_LIMIT_EXCEEDED;
                case REASON_CONNECTION_TOO_FAST :
                    return RegistrationStateChangeEvent
                        .REASON_RECONNECTION_RATE_LIMIT_EXCEEDED;
                case REASON_TRY_AGAIN :
                    return RegistrationStateChangeEvent
                        .REASON_RECONNECTION_RATE_LIMIT_EXCEEDED;
                default :
                    return RegistrationStateChangeEvent
                        .REASON_NOT_SPECIFIED;
            }
        }

        /**
         * returns the reason string corresponding to the code
         * in the close command
         *
         * @param reasonCode int the reason of close connection
         * @return String describing the reason
         */
        static String convertCodeToStringReason(int reasonCode)
        {
            switch(reasonCode)
            {
                case REASON_MULTIPLE_LOGINS :
                    return REASON_STRING_MULTIPLE_LOGINS;
                case REASON_BAD_PASSWORD_A :
                    return REASON_STRING_BAD_PASSWORD;
                case REASON_BAD_PASSWORD_B :
                    return REASON_STRING_BAD_PASSWORD;
                case REASON_NON_EXISTING_ICQ_UIN_A :
                    return REASON_STRING_NON_EXISTING_ICQ_UIN;
                case REASON_NON_EXISTING_ICQ_UIN_B :
                    return REASON_STRING_NON_EXISTING_ICQ_UIN;
                case REASON_MANY_CLIENTS_FROM_SAME_IP_A :
                    return REASON_STRING_MANY_CLIENTS_FROM_SAME_IP;
                case REASON_MANY_CLIENTS_FROM_SAME_IP_B :
                    return REASON_STRING_MANY_CLIENTS_FROM_SAME_IP;
                case REASON_CONNECTION_RATE_EXCEEDED :
                    return REASON_STRING_CONNECTION_RATE_EXCEEDED;
                case REASON_CONNECTION_TOO_FAST :
                    return REASON_STRING_CONNECTION_TOO_FAST;
                case REASON_TRY_AGAIN :
                    return REASON_STRING_TRY_AGAIN;
                default :
                    return REASON_STRING_NOT_SPECIFIED;
            }
        }

        /**
         * When receiving login failure
         * the reasons for the failure are in the authorization
         * part of the protocol ( 0x13 )
         * In the AuthResponse are the possible reason codes
         * here they are converted to those in the ConnectionClosedListener
         * so the they can be converted to the one in service protocol events
         *
         * @param afi AuthFailureInfo the failure info
         * @return int the corresponding code to this failure
         */
        static int convertAuthCodeToReasonCode(AuthFailureInfo afi)
        {
            switch(afi.getErrorCode())
            {
                case AuthResponse.ERROR_BAD_PASSWORD :
                    return REASON_BAD_PASSWORD_A;
                case AuthResponse.ERROR_CONNECTING_TOO_MUCH_A :
                    return REASON_CONNECTION_RATE_EXCEEDED;
                case AuthResponse.ERROR_CONNECTING_TOO_MUCH_B :
                    return REASON_CONNECTION_RATE_EXCEEDED;
                case AuthResponse.ERROR_INVALID_SN_OR_PASS_A :
                    return REASON_NON_EXISTING_ICQ_UIN_A;
                case AuthResponse.ERROR_INVALID_SN_OR_PASS_B :
                    return REASON_NON_EXISTING_ICQ_UIN_B;
                // 16 is also used for blocked from same IP
                case 16 :
                    return REASON_MANY_CLIENTS_FROM_SAME_IP_A;
                case AuthResponse.ERROR_SIGNON_BLOCKED :
                    return REASON_MANY_CLIENTS_FROM_SAME_IP_B;
                default :
                    return RegistrationStateChangeEvent.REASON_NOT_SPECIFIED;
            }
        }
    }
}

------------------------------------------------------------------------

/*
* AutoResponse.java
*
* Created on January 15, 2007, 8:56 PM
*
* "SIP Based Push Contents Enabled Call Center"
* "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.icq.callcenter;

import net.java.sip.communicator.impl.protocol.icq.*;
import net.java.sip.communicator.impl.protocol.icq.ProtocolProviderServiceIcqImpl;
import net.java.sip.communicator.impl.protocol.icq.OperationSetBasicInstantMessagingIcqImpl;
import net.java.sip.communicator.service.protocol.*;
import net.java.sip.communicator.service.protocol.OperationSetBasicInstantMessaging;
import net.java.sip.communicator.service.protocol.event.*;
import net.java.sip.communicator.util.*;
/*
* import list to retrieve user information from GUI.
*/
import net.java.sip.communicator.impl.gui.main.message.*;
import net.java.sip.communicator.impl.gui.main.message.ProtocolContactSelectorBox;
import net.java.sip.communicator.impl.gui.customcontrols.*;
import net.java.sip.communicator.impl.gui.i18n.*;
import net.java.sip.communicator.impl.gui.utils.*;
import java.util.*;

/**
* A class where the callcenter implementation is controlled. All of the method
* is public to make it accessible from out of the source.
*
* Currently this package is located in"sip/communicator/impl/protocol/icq/".
* When the implementation of sip instant message is completed, this class and
* package would need to be moved to "sip/communicator/impl/protocol/sip/".
*
* @author azrul
*
**/

public class AutoResponse {
    
    /** AutoResponse is a class which generates all the callcenter's automatic
     * response to it's user. Current method in the implementation would be
     * autoSendURL, where when a SPC3 user started a session, they will provoke
     * this method and it will autoreply a message containing URL for FAQs and
     * Forums.
     */
    private int i;
    
    private ProtocolProviderServiceIcqImpl icqProvider = null;

    private Contact Contact;
    
    //private ProtocolContactSelectorBox contactSelectorBox = new ProtocolContactSelectorBox();
    private ProtocolContactSelectorBox contactSelectorBox;
    
    public AutoResponse() {
    }
    
    /**
     * a method that is provoked one time when other person calls in the SPC3.
     *
     * In current implementation at ICQ, this method is provoked from the
     * "sip/communicator/impl/protocol/icq/ProtocolProviderServiceIcqImpl.java"
     * in the future implementation on SIP protocol, we need to implement
     * the provoke instruction inside one of the method in the following file
     * "sip/communicator/impl/protocol/sip/ProtocolProviderServiceSipImpl.java"
     *
     * @param to automatically send a message containing URL towards SPC3 user.
     * This should be done one time at the beginning of a session initiation
     * @return void (no return value)
     **/
    
    public void autoSendURL(Conversation conv){
        for(i=0;i<10;i++){
            System.out.println("autoSendURLnew");
        }
        
        /*
        OperationSetBasicInstantMessaging im = new OperationSetBasicInstantMessaging() {

            public Message createMessage(byte[] content, String contentType, String contentEncoding, String subject) {
                return new MessageIcqImpl(new String(content), contentType
                                  , contentEncoding, subject);
            }

            public Message createMessage(String messageText) {
                 return new MessageIcqImpl(messageText, DEFAULT_MIME_TYPE
                                  , DEFAULT_MIME_ENCODING, null);
            }

            public void sendInstantMessage(Contact to, Message message) throws IllegalStateException, IllegalArgumentException {
            }

            public void addMessageListener(MessageListener listener) {
            }

            public void removeMessageListener(MessageListener listener) {
            }

            public boolean isOfflineMessagingSupported() {
                return true;
            }
        };
         */
        OperationSetBasicInstantMessaging im = OperationSetBasicInstantMessagingIcqImpl();
        
        Message msg=im.createMessage("createdmessage gambare gambare");
        
        //Contact contact = (Contact) contactSelectorBox.getMenu().getSelectedObject();
        //Contact contact=(Contact);
        //Contact contact = Conversation.getBuddy().toString();
        Contact contact = conv.getBuddy();
        
        im.sendInstantMessage(contact, msg);
        /*
            OperationSetBasicInstantMessaging im = this.chatPanel
                .getImOperationSet();

            Message msg = im.createMessage(chatPanel.getTextFromWriteArea());

            this.chatPanel.getChatWindow().getMainFrame()
                .getWaitToBeDeliveredMsgs().put(msg.getMessageUID(),
                    this.chatPanel);

            Contact contact = (Contact) contactSelectorBox.getMenu()
                .getSelectedObject();

            if (chatPanel.getTnOperationSet() != null) {
                // Send TYPING STOPPED event before sending the message
                chatPanel.stopTypingNotifications();
            }

            chatPanel.requestFocusInWriteArea();

            try {
                im.sendInstantMessage(contact, msg);
            }
            catch (IllegalStateException ex) {
                chatPanel.refreshWriteArea();
                
                chatPanel.processMessage(
                        contact.getDisplayName(),
                        new Date(System.currentTimeMillis()),
                        Constants.OUTGOING_MESSAGE,
                        msg.getContent());
                
                chatPanel.processMessage(
                        contact.getDisplayName(),
                        new Date(System.currentTimeMillis()),
                        Constants.ERROR_MESSAGE,
                        Messages.getI18NString("msgSendConnectionProblem")
                            .getText());
            }
         */
               
    }
}

------------------------------------------------------------------------

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net

---------------------------------
Don't get soaked. Take a quick peak at the forecast
with theYahoo! Search weather shortcut.


#9

Hello,
I'm trying to build the Sip-Communicator Proyect with Eclipse. And so far it
works fine. I can run an debug it. But if I do a change to the Source Code
there are no effects on the program. In the debugger window appears the new
source code but the blue debugger bar jumps to the lines where the old
source code had been and even does the old action. I can't understand it.
The building does overwrite the old .class files. So from where does the
builder gets the old files?

Thank you for any help

Laura


#10

Hello Laura,

In addition to compiling you'd also have to build sip-communicator bundles which is where class files are actually loaded from by Felix.

You can do so by executing ant's rebuild target.

Hope this helps
Emil

wotanunddasoh wrote:

···

Hello,
I'm trying to build the Sip-Communicator Proyect with Eclipse. And so far it works fine. I can run an debug it. But if I do a change to the Source Code there are no effects on the program. In the debugger window appears the new source code but the blue debugger bar jumps to the lines where the old source code had been and even does the old action. I can't understand it. The building does overwrite the old .class files. So from where does the builder gets the old files?
Thank you for any help
Laura

---------------------------------------------------------------------
To unsubscribe, e-mail: dev-unsubscribe@sip-communicator.dev.java.net
For additional commands, e-mail: dev-help@sip-communicator.dev.java.net