Purpose

IM API is an interface for sending and receiving instant messages. IM API is intended for those user applications, which need this kind of functionality, e.g. games. From a functionality point of view IM API can be divided as follows:

  • Connection management – connecting to the protocol stack and receiving connection change notifications.

  • IM handling – sending and receiving instant messages and related sending errors, e.g. invalid user IDs, etc.

Constraints

This API is valid for all platforms running on Symbian OS v8.0 or later versions.

API description

The logical type of IM API is Library API. IM API provides standalone implementation classes that are used by the client. The interface provides methods that do not block, but return immediately, so that the API operation happens simultaneously while the client application continues to run. The implementation is used in the context of the client’s thread and the operations can be used independently of each other. Notification events are used to indicate the client of changes in the connection state and on arrival of a new instant message. Moreover, when some operation is complete, the client also gets a notification of this. The API implementation uses active objects so the client application is required to install and run an active scheduler.

Use cases

The main use cases are described in Figure 1.

Main use cases


Main use cases

API class structure

IM API is divided into two logical parts: connection handling and IM handling. Each part has its observer interface, which needs to be implemented by the client. The user application first has to create an object of CImConnection with help of the ECom framework. After creating that object the connection handler part of IM API is ready for use. The user application has to implement the MImConnectionObserver interface for notifications and register that to IM API. Using the CImConnection class the user application is able to create objects of MImClient for IM handling. The interface class structure is shown in Figure 2.

Interface class structure


Interface class structure

Related APIs
  • CImConnection
  • MImClient
  • MImConnectionObserver

Using IM API

In order to use IM API, the client has to create a connection using an own unique application ID and log in to the remote IM server. After creating the interface objects, the user application has to register its observers using the corresponding method from each interface class. This is necessary because the methods of this API are non-blocking and the notification when the operation is complete is delivered through the observer methods. Each asynchronous operation returns an operation ID when the request is issued. When the operation ends, the observer method is called with the operation ID to map it back to the corresponding request.

Creating the connection and registering the observer

Creating CImConnection involves the ECom framework. ECom loads imclient.dll , which contains the API implementation. If the implementation is not found the NewL() method leaves with KErrNotFound . After the object is created, the user has to register its implementation of the MImConnectionObserver interface.

The client application has to have an application ID, which is supposed to be unique in the domain of the application using the instant messaging services. The application ID is given in the NewL() method. That ID is used in routing the instant messages to the correct application in case the session to the IM server is shared between two or more applications. Registering can be done only once, a subsequent registration without unregistration leads to an error.

An application ID can be defined as a literal, e.g.:

             
              _LIT(KMyApplicationId, “MyIMApplication”);
             
            

Creating the connection and registering...


Creating the connection and registering the observer

Example code:

             
              void CSDKExample1AppUi::ConstructL()
              
    {
    BaseConstructL( );
    iAppContainer = new (ELeave) CSDKExample1Container;
    iAppContainer->SetMopParent( this );
    iAppContainer->ConstructL( ClientRect( ) );
    AddToStackL( iAppContainer );
    // Create an instance of the connection.
    // If the plugin is not found the eCom will leave with KErrNotFound
    iMyImConnection = CImConnection::NewL( KMyApplicationId );
    }
Related APIs
  • CImConnection
  • KErrNotFound
  • MImConnectionObserver
  • NewL()

Logging in

After the CImConnection object is created the client application has to log in. Logging in is done using the IM server URL, user ID, password and the access point ID that is intended to be used. In case there already is an existing session with the same user parameters that session is shared.

Logging in


Logging in

Example code:

             
              void CSDKExample1AppUi::TestConnectL ( )
              
    {
    _LIT(KServer, “http://impsdomain.com:8080/wv”);
    _LIT(KUserId, “wv:[email protected]”);
    _LIT(KPassword, ”secret”);

    TRAPD(err,iMyImConnection->LoginL(
        KServer,
        KUserId,
        KPassowrd,
        0)); // use existing AP!!!

    if ( err != KErrNone )
        {
        // Failed to start the registration
        CAknErrorNote* note = new(ELeave) CAknErrorNote();
        TBuf<0x100> buf;
        buf.Format( _L("Login failed:( %i )"), err );
        note->ExecuteLD( buf );
        }
    }

The HandleLoginL method is implemented by the client. It is called when LoginL() is completed.

             
              void CSDKExample1AppUi::HandleLoginL( const TInt aErrorCode )
              
    {
    CAknInformationNote* note = new (ELeave) CAknInformationNote( EFalse );
    note->SetTimeout( CAknNoteDialog::ELongTimeout  );
    TBuf<0x100> buf;
    buf.Format( _L("HandleLoginL( %i )"), aErrorCode );
    note->ExecuteLD( buf );
    }
Related APIs
  • CImConnection
  • HandleLoginL
  • LoginL()

Canceling the ongoing login

If the login operation is not yet finished, there is a possibility to cancel it. If the login was not yet started or it is finished already the method will leave with an appropriate error code. The method is asynchronous and will complete by calling the corresponding observer method.

Canceling the ongoing login


Canceling the ongoing login

The HandleCancelLoginL method is implemented by the client. It is called when CancelLoginL is completed.

Example code:

             
              void CSDKExample1AppUi::HandleCancelLoginL( const TInt aErrorCode )
              
    {
    CAknInformationNote* note = new (ELeave) CAknInformationNote( EFalse );
    note->SetTimeout( CAknNoteDialog::ELongTimeout  );
    TBuf<0x100> buf;
    buf.Format( _L("HandleCancelLoginL( %i )"), aErrorCode );
    note->ExecuteLD( buf );
    }
Related APIs
  • CancelLoginL
  • HandleCancelLoginL

Logging out

After a successful login the connection can be closed by starting a logout procedure. If calling the method when not logged in it will leave with an appropriate error code. The method is asynchronous and will complete by calling the corresponding observer method.

Logging out


Logging out

HandleLogoutL method is implemented by the client. It is called when LogoutL is completed.

Example code:

             
              void CSDKExample1AppUi::HandleLogoutL( const TInt aErrorCode )
              
    {
    CAknInformationNote* note = new (ELeave) CAknInformationNote( EFalse );
    note->SetTimeout( CAknNoteDialog::EShortTimeout  );
    TBuf<0x100> buf;
    buf.Format( _L("HandleLogoutL( %i )"), aErrorCode);
    note->ExecuteLD( buf );
    }
Related APIs
  • HandleLogoutL
  • LogoutL

Unregistering the connection observer

By unregistering the connection observer all the connection related ongoing tasks are cancelled. It is advised that when login is ongoing or already logged in, first cancel the login, or logout before unregistering the connection observer.

Unregistering the connection observer


Unregistering the connection observer

Creating IM client and registering the observer

Creating the MImClient interface is needed when the user wants to send and receive instant messages. After the creation is successful the user has to register its IM observer. Without registering that observer it is not even possible to send a point-to-point message because the notification about the sending is delivered through the HandleMessageSentL() observer method.

Creating IM client and registering the o...


Creating IM client and registering the observer

The CreateImClientL method creates the IM Client interface. A pointer is returned to the object. It is the client’s responsibility to destroy the object.

Example code:

             
              void CSDKExample1AppUi::TestCreacteImClientL()
              
    {
    TRAPD(err,iMyImClient = iMyImConnection->CreateImClientL());

    // Failed to create IM Interface
    if ( err != KErrNone )
        {
        CAknErrorNote* note = new(ELeave) CAknErrorNote();
        note->ExecuteLD(_L("No IM Interface!"));
        }
    }

Before using the methods in the MImClient interface, the observer must be registered successfully to IM API using the RegisterObserverL method.

Example code:

             
              void CSDKExample1AppUi::TestRegisterImObserverL()
              
    {
    TRAPD(err, iMyImClient->RegisterObserverL( this ) );
    if( err != KErrNone )
        {
        CAknInformationNote* note = new (ELeave) CAknInformationNote( EFalse );
        note->SetTimeout( CAknNoteDialog::ELongTimeout  );
        TBuf<0x100> buf;
        buf.Format( _L("Registering failed with %d"),ret );
        note->ExecuteLD( buf );
        }
    }
Related APIs
  • CreateImClientL
  • HandleMessageSentL()
  • MImClient
  • RegisterObserverL

Sending a point-to-point message

Sending a point-to-point message is possible by using a user ID (e.g. WV user ID) or contact model ID from the contacts DB. In the latter case the IM API translates the recipient’s address to the corresponding protocol user ID. In case the contact ID given in the method does not have a user ID in its fields, the error code KImApiErrInvalidContactId is returned by a leave mechanism.

In case there are more contact IDs in the recipient list and for example one does not have a user ID, this one is silently removed from the list and a message sending is attempted to the other recipients. In case the recipient was addressed directly with a user ID the validity of the ID is checked only in the remote IMPS server. Therefore the error code can be delivered only to the observer object by the HandleSendErrorL() method. For more information on error handling, see Section Error handling

It is not possible to send several point-to-point messages in the same active object scheduling round, e.g. calling SendPToPMessageL() several times one after another in the same function, due to some limitations in the protocol stack. That kind of usage leads to the error KErrServerBusy .

Sending a point-to-point message


Sending a point-to-point message

The SendPToPMessageL method has two prototypes. Textual instant messages can be sent using contact model IDs or directly a user ID. This method is asynchronous and HandleMessageSentL() or HandleSendErrorL() is called when completed.

This method returns an operation ID. Please note that only one message can be sent during an active object scheduling round, which means for example that the SendPToPMessageL method cannot be called subsequently in one function.

Example code:

Example code of sending with contact IDs
             
              void CSDKExample1AppUi::TestSendPToPMessageContactL()
              
    {
    // Select contact from the Contacts Model
    _LIT(KWVStart, "");
    // Specify in which fields search should be performed
    CContactItemFieldDef* fieldToSearchIn = new (ELeave) CContactItemFieldDef();
    CleanupStack::PushL( fieldToSearchIn );
    fieldToSearchIn->AppendL( KUidContactFieldVCardMapWV );

    // search in contact database
    CContactIdArray *myContactArray = iMyContacts->FindLC(KWVStart, fieldToSearchIn );
    // Call the method
    TRAPD(err, iMyImClient->SendPToPMessageL(*myContactArray, _L("Hi there!"));
    if ( err != KErrNone )
        {
        CAknErrorNote* note = new(ELeave) CAknErrorNote();
        note->ExecuteLD(_L("Sending failed"));
        }
    CleanupStack::PopAndDestroy( 2 ); // fieldToSearchn, myContactArray
    }
Example code of sending with user IDs:
             
              void CSDKExample1AppUi::TestSendPToPMessageContactL()
              
    {
    CDesCArray* userIds = new(ELeave) CDesCArrayFlat(4);
    CleanupStack::PushL(userIds);
    userIds->AppendL(_L("wv:[email protected]"));
    userIds->AppendL(_L("wv:[email protected]"));
    userIds->AppendL(_L("wv:[email protected]"));
    userIds->AppendL(_L("wv:[email protected]"));
            
    // Call the method
    TRAPD(err, iMyImClient->SendPToPMessageL(*userIds, _L("Hi there!"));
    if ( err != KErrNone )
        {
        CAknErrorNote* note = new(ELeave) CAknErrorNote();
        note->ExecuteLD(_L("Sending failed"));
        }
    CleanupStack::PopAndDestroy( ); // userIds
    }

HandleMessageSentL() is implemented by client and it is called when SendPToPMessageL is completed.

Example code:

             
              void CSDKExample1AppUi:: HandleMessageSentL(const TInt aOpCode, 
              
                                            const TInt aErrorCode)
    {
    CAknInformationNote* note = new (ELeave) CAknInformationNote( EFalse );
    note->SetTimeout( CAknNoteDialog::EShortTimeout  );
    TBuf<0x100> buf;
    buf.Format( _L("HandleMessageSentL( %i )"), aErrorCode );
    note->ExecuteLD( buf );
    }

HandleSendErrorL method is implemented by the client. It is called when SendPToPMessageL is completed with an error. If the error is KImApiErrPartialSuccess the detailed list of failed user IDs can be fetched using the MImClientDetailedError interface .

Example code:

             
              void CSDKExample1AppUi:: HandleSendErrorL(const TInt aOpCode, 
              
                                         const TInt aErrorCode,
                                         MImClientDetailedError* aDetailedError);

    {
    CAknInformationNote* note = new (ELeave) CAknInformationNote( EFalse );
    note->SetTimeout( CAknNoteDialog::EShortTimeout  );
    TBuf<0x100> buf;
    buf.Format( _L("HandleSendErrorL( %i )"), aErrorCode );
    note->ExecuteLD( buf );

    if ( aDetailedError ) 
        {
        _LIT(KMessage, "Failed contacts:");
        TPtrC ptr(KMessage);
        CAknMessageQueryDialog* dlg = CAknMessageQueryDialog::NewL(ptr);
        CleanupStack::PushL(dlg); // << dlg
        dlg->PrepareLC(R_MESSAGE_QUERY);
        dlg->QueryHeading()->SetTextL(_L("Failed contacts"));
        
        buf.FillZ();
        // iterate through the failed users list
        for(TInt i(0); i < aDetailedError->Count(); ++i)
            {
            // read the ith user
            buf.AppendFormat(_L("%S %d:\n"),
                             & aDetailedError>UserId(i), 
                             aDetailedError->ErrorCode(i));
            }
        
        dlg->SetMessageTextL(buf);
        dlg->RunLD();
        CleanupStack::Pop(); // >> dlg
        }
Related APIs
  • HandleMessageSentL()
  • HandleSendErrorL
  • HandleSendErrorL()
  • KErrServerBusy
  • KImApiErrInvalidContactId
  • KImApiErrPartialSuccess
  • SendPToPMessageL
  • SendPToPMessageL()

Receiving a point-to-point message

New point-to-point messages are delivered to the IM observer method HandleNewPToPMessage() .

Receiving a point-to-point message


Receiving a point-to-point message

Example code:

Example code for textual messages
             
              void CSDKExample1AppUi::HandleNewPToPMessageL(
              
            const TInt aErrorCode, 
            const TContactItemId  aContactId,
            const TDesC& aUserId,
            const TDesC& aMessageType,
            const TDesC16& aContent )
    {
    TBuf<0x100> buf;
    _LIT(KMessage, "New Message");
    TPtrC ptr(KMessage);
    CAknMessageQueryDialog* dlg = CAknMessageQueryDialog::NewL(ptr);
    dlg->PrepareLC(R_MESSAGE_QUERY);
    // Show the sender user
    buf.AppendFormat(_L("from %S"), & aUserId);
    dlg->QueryHeading()->SetTextL(buf);

    buf.FillZ();
    // show the message itself
    if( aMessageType.Compare(_L("text/plain")) == 0 )
        dlg->SetMessageTextL(aContent);
    else
        {
        buf.Append(_L("Message content cannot be showed!"));
        dlg->SetMessageTextL(buf);
        }
    dlg->RunLD();
}
Related APIs
  • HandleNewPToPMessage()

Receiving partial success

In case that one or more user IDs were incorrect for some reason KImApiErrPartialSuccess is returned in the HandleSendErrorL() observer method. In that case the user is able to fetch the failure reasons for each failed user ID. The user IDs are not converted back to contact IDs if the contact IDs were used in sending the instant message.

Receiving partial success


Receiving partial success

Related APIs
  • HandleSendErrorL()
  • KImApiErrPartialSuccess

Unregistering the IM observer

By unregistering the observer all the pending requests are cancelled.

Unregistering the IM observer


Unregistering the IM observer

Memory and error handling

Error handling

All the basic Symbian plafform errors and also API related errors cause a leave in the interface code. For example, an out of memory situation causes a leave but also an invalid contact ID. The imerror.h lists all the errors.

Memory overhead

IM API does not consume memory significantly after creating the object. However the memory used is dependent on the size of the instant messages sent and received.

Extensions to the API

There are no possible extensions to this API.

Glossary

Abbreviations

API Application Programming Interface

DB

Data Base

DLL

Dynamic Link Library

ID

Identifier

IM

Instant Message

IMPS

Instant Messaging and Presence Services

GPRS

General Packet Radio Service

MIME

Multipurpose Internet Mail Extension

PToP

Point-To-Point

WV

Wireless Village

CSP

Client Server Protocol

Definitions

Client application An application, which uses the IM SDK API library, shortly client.

Contact

Contact item from the Contacts Model.

ECom

A generic framework for specifying plug-in interfaces, and for calling and writing plug-ins.

Point-To-Point Message

Instant message sent between two users.

User ID

Identifier of the user defined in the used protocol, e.g. WV user ID – wv: [email protected]

Application ID

Unique identification of the application. e.g. MyMessagingApplicationv2.0

References

ECom Plug-in Architecture