Instance
Message Enabler
1. Brief introduction
This package is aimed to provide an implementation comliant to the LiPS Instance Message & Presence enabler definition. LiPS Instance Message & Presence enabler, IM enabler in short, defines a set of protocol agnostic APIs to facilitate Instance Message (IM) application development based on LiPS compliant devices. "Protocol agnostic" means that IM enabler will not target on any specific IM protocol, on the contrast, it aims at defining a common interface to abstract variant of IM protocols, especially for IETF & OMA standards, i.e. XMPP, SIP/SIMPLE and IMPS. We hope that other proprietary protocols could also be easy adapted to this IM interface. On the other hand, IM will not implement any IM protocol stack; instead, IM make use of a concrete IM protocol stack for implementation.
This document will give an introducation of the architecture & code structure of IM enabler to both IM application and the enalber developpers.
Section 2 will describe funcitonalities of IM Client, while section 3 will illustrate the package architecture and concepts. While section 4 will go deeper to detail the implementation.
2. Overview
A typical IM application provides the functionalities such like: MESSAGING, PRESENCE, BUDDY MANAGEMENT and CONTENT SHARING; whereas, considering the characteristic of embedded system, LiPS IM enabler provides a part of MESSAGING, PRESENCE and functions in current version. More advanced features will be added in future.
In generally, to use an IM service, user must register a login account in the IM server which is called as IM URI. IM URI is the unique identifier of an IM user or even a group / chatting room.
After user obtained a login account and logined into the service, user can create his / her contact list(s), and add other users as his / her buddies in the contact list.
User also can send or receive pieces of messages to other users in very real time. That message is co-called Instance Message.
Most of IM services can provide users some kind of notification about their buddies' availabilities, moods, locations, device capacities etc; or user can also choose to publish his / her own availabilities, mood, locations, device capacities etc. to buddies. This kind of state information is called presence. For privacy consideration, before receiving buddies' presence notification, user must subscribe to the buddies and obtain the authorization from the buddies.
In a summary, the basic concepts for an IM Client we talked above are:
- IM URI
- Instance Message
- Presence
And the basic functionalities are:
- Register / Unregister
- Login / Logout
- Send / Receive messages
- Subscribe / Unsubscribe
- Authorize / Un-authorize
- Notify
- Publish
Considering the user scenario in mobile, IM enabler implements all basic functionalities above except Register & Unregister.
3. design & concepts
We do believe the IM is becoming into a stand application for mobile phones, and would provide a new communication method not only for end user but also for other mobile applications. So that IM enaber is desigend in a way which enable different applications share a single IM connection (account) in the same time. This is implemented by session and event mechanism. The following diagram shows the whole picture:

As the diagram shows, there are several entities inside this architecture:
· IM Server: The server lays on the network to provide IM service.
· IM applications: such like IM App1, IM App2 & IM App3, they make use of IM enabler APIs.
· IM Enabler: It's a set of interfaces which provide IM functionalities to applications, and the code always runs in the application proccess. These interfaces just communicate with IM Proxy which will really do the jobs. One thing should be poinited out is that the interfaces are designed to keep comlient with LiPS IM specification (Since the LiPS IM specification is not released, the interface would evolve from time to time).
· IM Proxy: IM Proxy is the entity that really do the IM jobs. It runs in a separate process, collecting requests from IM Applications (through IM Enabler), transfering the requests to IM Server, and also dispatching the IM Server responses / notifications to IM Applications. Only one IM proxy should exist in the same device.
· Session: Session is the entity that keep the executing context between IM Enabler & IM proxy. As described above, IM Applications can connect to the same account in the same time. IM Proxy distinguishes the different IM Applications by their own sessions. Session always starts when IM application asks to open a session, and always ends when IM Application asks to close the opened session. All the communication between IM Enablers and IM Proxy happens inside sessions. Furthermore, sessions are only known by IM Applications and IM Proxy, while IM Server knows nothing about sessions.
· Event: Event is the way that IM Application communicate with IM Proxy. There are two kinds of events: Asynchronous event & Unsolicited event.
o Asynchronous event is caused by IM Application: IM Enabler passes asynchronous requests to IM proxy, after some processing (by IM Proxy or IM Server), responses will be returned to IM Enabler, which generats asynchronous events to tell the results to IM Applictions. For example: IM App send a message to some contact: the app should invoke send-msg interface in IM Enabler to place a send-msg request, this is passed to IM Proxy. When the messsage is sent out by proxy, an return notification will be passed to the IM Enabler, The Enabler would generate an Asynchronous event to tell the app that the message was sent out.
o Unsolicited event is caused by IM Server, network, IM Proxy or event other IM Applications. Before receive any Unsolicited event, IM Applications should register the event type they concern about. When the unsolicited event happens, Application will be informed by IM Enabler. For example: IM App registers message-receiving event. When someone send a massage to the user, IM Proxy will tell the IM Enabler, which generates an message-receiving event and throws to IM App.
IM Enaber provides a set of abstract interfaces to invoke IM functions, while IM Proxy will execute the invocations. So IM Proxy can implemented deferent protocols but the IM Proxy interfaces could keep no change. Please see the following diagram about IM Proxy architecture:

IM Proxy run as a deamon in device. In the above diagram, from left to right, the main thread –- proxy -- communicates with the IM Enablers by Dbus. It's the proxy that keeps the session information. The IM Enablers only know their own session id, and all the communication between IM Enabler and IM Proxy should indicate the session id (except IM Enabler asks to open a session). Proxy runs a loop. When Dbus tell it a request come from an IM Enabler, proxy parses the Dbus message and find the session relevant to the IM Enabler. If necessary, proxy will create a transaction and push the transaction to a queue, which will pop the transaction to connections.
Proxy also reads transactions from another queue, which connection would push the completed transactions. When there is a completed transaction to read, it means maybe an event happens. Proxy will try to find relevant session information, and dispatches the event messages to IM Enalbers by DBus.
We mentioned there are two queues in IM Proxy, one is from proxy to connection, another is from connection to proxy. Connection is the component that communicates with IM server. Different IM servers use different protocols, and have different behaviors. An abstract connection provide a framework to implement concrete connections for different protocols. In this package, we implemented XMPP connection, and SIP/SIMPLE connection is under going.
When an account is asked to login, a connection will start it execution. Connection runs in its own thread. It will login into the server, then loops to monitor the queue from proxy and network. Any transaction is popped from the queue, connection will execute it by communicate with server (write some message to socket). During execution, the transaction may need to be kept in an pandding list and waiting for response from network. If connection read some message from network, it will parse the message, finding relevant pandding transaction or create a new transaction. Then push the transaction to the queue which could be read by proxy.
If an account is going to logout, the connection will do necessary actions and stop its thread.
Now we can see, a connection thread means an login of an account. Different sessions can share the same login.
4. general structure
The previous section illustrate the basic idea of IM Enabler. This section will show how this package implements this idea.
IM URI
For the public IM protocols standardized by IETF/OMA, such as IMPS, SIP/SIMPLE or IMPS, the IM URI are defined in the similar formats:
scheme:user@domain
Unusually, XMPP, SIP/SIMPLE or IMPS address URI is composed of several parts:
· Scheme;
· User;
· Domain;
· Resource;
For example:
An Xmpp uri jabber:john.smith@jabber.org/mobile:
scheme: jabber;
user: john.smith;
domain: jabber.org;
resource: mobile;
An SIP URI sip:john.smith@somedomain.com
scheme: sip;
user: john.smith
domain: somedomain.com
An IMPS uri wv:john.smith/friends@imps.com
scheme: wv;
user: john.smith
domain: imps.com
resource: friends;
Besides these parts introduced above, protocols may also support some extension values. A good example is a SIP URI could be
sip:+86-10-87654321@somedomain.com;user=phone
Here the sip URI has an extension variable named 'user', and the value is 'phone'.
In this package, we define an im_uri_t structure to represent an IM URI, and a set of im_uri_xxx functions to manipulate im_uri_t structure.
For example:
typedef struct _im_uri_t im_uri_t;
im_err_t im_uri_new(char *uri_str, im_protocol_t prtl, im_uri_t **uri);
im_err_t im_uri_free(im_uri_t *uri);
bool im_uri_cmp(im_uri_t *first, im_uri_t *second, im_uri_part_t part);
im_err_t im_uri_get_ext(im_uri_t *uri, char *name, char **value);
im_err_t im_uri_set_ext(im_uri_t *uri, char *name, char *value);
im_err_t im_uri_get_ext_names(im_uri_t *uri, char ***names);
im_err_t im_uri_get_full_ext(im_uri_t *uri, char **str);
im_err_t im_uri_get_uri(im_uri_t *uri, char **std_str);
im_err_t im_uri_get_uri_full(im_uri_t *uri, char **full_str);
im_err_t im_uri_get_protocol(im_uri_t *uri, im_protocol_t *prtl);
im_err_t im_uri_get_user(im_uri_t *uri, char **user);
im_err_t im_uri_set_user(im_uri_t *uri, char *user);
im_err_t im_uri_get_domain(im_uri_t *uri, char **domain);
im_err_t im_uri_set_domain(im_uri_t *uri, char *domain);
im_err_t im_uri_get_res(im_uri_t *uri, char **res);
im_err_t im_uri_set_res(im_uri_t *uri, char *res);
IM Message
Normally, an instance messsage contains a piece of simple Text as it message body. However the body could also encode some binary data. So that a message should indicate the type of its body, body length, body encode etc. Besides, developer also need to get or set some properties such like recipiences or senders, status (received / sending / sent out), sent / received time etc.
In this package, we define an im_msg_t structure to represent a piece of instance message, and a set of im_msg_xxx functions to manipulate im_msg_t structure.
typedef struct _im_msg_t im_msg_t;
im_err_t im_msg_new(im_sid_t sid, im_msg_type_t type, im_msg_ctype_t ctype, im_msg_t **msg);
im_err_t im_msg_get_sid(im_msg_t *msg, im_sid_t *sid);
im_err_t im_msg_get_id(im_msg_t *msg, im_msg_id_t *msg_id);
im_err_t im_msg_get_time(im_msg_t *msg, time_t *msg_time);
im_err_t im_msg_get_ctype(im_msg_t *msg, im_msg_ctype_t *ctype);
im_err_t im_msg_get_type(im_msg_t *msg, im_msg_type_t *type);
im_err_t im_msg_get_state(im_msg_t *msg, im_msg_state_t *msg_state);
im_err_t im_msg_set_state(im_msg_t *msg, im_msg_state_t msg_state);
im_err_t im_msg_head_length(im_msg_t *msg, size_t *hsize);
im_err_t im_msg_get_recipient(im_msg_t *msg, char **recipient);
im_err_t im_msg_set_recipient(im_msg_t *msg, char *recipient);
im_err_t im_msg_get_from(im_msg_t *msg, char **from);
im_err_t im_msg_set_from(im_msg_t *msg, char *from);
im_err_t im_msg_get_body_length(im_msg_t *msg, size_t *bsize);
im_err_t im_msg_get_body(im_msg_t *msg, void **body);
im_err_t im_msg_get_encode(im_msg_t *msg, char **encode);
im_err_t im_msg_set_body(im_msg_t *msg, void *body, size_t len, char *encode);
im_err_t im_msg_free(im_msg_t *msg);
IM Presence
As we introduced previously, presence is a kind of state information about an IM user. What kind of state information could be included in presence is still an open issue, since there is no standard and each protocol or IM service has their own definitions. However, the availabilies of an IM user is the premier presence information.
In this package we use an im_presence_t structure to represent presence information im_presence_t contain the availability field and extensible field for other properties. As well, a set of im_presence_xxx functions are defined to manipulate the im_presence_t structure.
typedef struct _im_presence_t im_presence_t;
im_err_t im_presence_new(im_protocol_t prtl, char *to, im_presence_t **p);
im_err_t im_presence_free(im_presence_t *presence);
im_err_t im_presence_get_state(im_presence_t *presence,
im_presence_state_t *state);
im_err_t im_presence_set_state(im_presence_t *presence,
im_presence_state_t state);
im_err_t im_presence_get_desc(im_presence_t *presence,
char **desc);
im_err_t im_presence_set_desc(im_presence_t *presence,
char *desc);
im_err_t im_presence_get_to(im_presence_t *presence,
char **to);
im_err_t im_presence_set_to(im_presence_t *presence,
char *to);
im_err_t im_presence_get_from(im_presence_t *presence,
char **from);
im_err_t im_presence_get_protocol(im_presence_t *presence,
im_protocol_t *prtl);
im_err_t im_presence_get_ex_info(im_presence_t *presence,
char *name,
char **value);
im_err_t im_presence_set_ex_info(im_presence_t *presence,
char *name,
char *value);
im_err_t im_presence_get_ex_name_list(
im_presence_t *presence,
char ***names);
Event
IM Enabler package use the liblipsevent package to compose events.
Currently, it supports following events:
§ Asynchronous events:
§ IM_REQ_LOGIN: login
§ IM_REQ_LOGOUT: logout
§ IM_REQ_SUBSCRIBE: subscribe to others’ presence info
§ IM_REQ_ACCEPTANCE: authorize others’ subscription
§ IM_REQ_PRESENCE: change one’s own presence
§ IM_REQ_PRESENCE_PROBE: probe others’ presence
§ IM_REQ_MESSAGE: send a message
§ Unsolicited events:
§ IM_EVT_PRESENCE: others’ presence changed
§ IM_EVT_MESSAGE: new message arriving
§ IM_EVT_SUBSCRIBE: a subscription request from others arriving
§ IM_EVT_ACCEPTANCE: others’ acceptance response (to one’s subscription request) arriving
§ IM_EVT_ERROR: an error notification arriving
§ IM_EVT_LOGIN: an login happed in another session
§ IM_EVT_LOGOUT: an logout happed in another session
In order to receive the unsolicited event, application must register the event types. So that IM enabler can know which event the application cares about. Reversely, if an application won't want to receive a kind of event any more, it can un-register the event type from IM enabler. The registration / un-registration are achieved by following two functions:
im_err_t im_evt_register(sid_t sid, evt_type_t type, evt_handler_t *handler);
im_err_t im_evt_unregister(sid_t sid, evt_type_t type);
IM_EVT_PRESENCE
An IM_EVT_PRESENCE event will be emitted when user's buddy change their presence state. In some protocol, other resource of current user changing presence state will also cause an IM_EVT_PRESENCE event.
When an IM_EVT_PRESENCE event comes out, its evt_data field should be a pointer to an im_presence_t structure. Please refer to Section 4.5
IM_EVT_MESSAGE
An IM_EVT_MESSAGE event will be emitted when someone else sent a message to the current user.
When an IM_EVT_MESSAGE event comes out, its evt_data field should be a pointer to an im_msg_t structure. Please refer to Section 4.4.
An IM_EVT_SUBSCRIBE event will be emitted when someone else try to subscribe the presence notification of the current user. Normally, when this event is received, user should give an answer to tell the server or the buddy whether the subscription is accepted or refused.
When an IM_EVT_ SUBSCRIBE event comes out, its evt_data field should be a pointer to an im_subs_msg_t structure.
typedef struct {
char *contactor; ///< Contactor URI.
char *msg; ///< Attached Message.
char *group; ///< Group name.
char *nick; ///< Nick name.
bool subscribe; ///< Subscribe or Unsubscribe
} im_subs_msg_t;
The contactor is the URI who would like to subscribe current user. The msg field contains a text message for a brief salutation, but it could be NULL. The group & nick field could be used by some protocol to indicate the user's group and nickname. The subscribe field if the user would like to subscribe or un-subscribe to the current user.
If user A sent out a presence subscription to user B, and B accepted / refused the subscription, user A will receive the IM_EVT_ACCEPTANCE event (when user B refused A's subscription, whether A will received the acceptance event or not depends on the IM protocol).
When an IM_EVT_ ACCEPTANCE event comes out, its evt_data field should be a pointer to an im_accept_msg_t structure.
typedef struct {
char *contactor; ///< Contactor URI.
bool accept; ///< Accept or refuse
char *msg; ///< Attached Message.
} im_accept_msg_t;
The contactor is the URI who sent out the acceptance message. The msg field contains a text message for a brief salutation, but it could be NULL. The accept field indicates if the user accepted or refused the subscription.
IM_EVT_ERROR
During a session, user's incorrect operations can cause some error. Furthermore, server side can also cause errors. IM_EVT_ERROR event is used to tell application some error is raising.
When an IM_EVT_ ERROR event comes out, its evt_data field should be a pointer to an im_accept_msg_t structure.
typedef enum {
IM_ERR_CODE_NONE, ///< No error.
IM_ERR_CODE_NOSUPPORT, ///< Not supported.
IM_ERR_CODE_NETWORK, ///< Network error.
IM_ERR_CODE_BAD_URI, ///< Bad uri.
IM_ERR_CODE_PASSWORD, ///< Bad password.
IM_ERR_CODE_SERVER, ///< Server close connection.
IM_ERR_CODE_TRANSACTION, ///< Transaction error.
IM_ERR_CODE_MEM, ///< Not enough memory
IM_ERR_CODE_OTHER ///< Other error.
} im_err_code_t;
/**
* @brief structure definition for error message.
*/
typedef struct
{
im_err_code_t err_type; ///< Error type @see im_err_code_t
char *msg; ///< Error message.
} im_error_t;
The err_type field indicates the reason for the error, and msg field can give a description about the error.
IM_EVT_LOGIN
An IM_EVT_LOGIN event will be emitted when another session cause a login success with the same account of current session.
When an IM_EVT_LOGIN event comes out, its evt_data field must be NULL.
IM_EVT_LOGOUT
An IM_EVT_LOGOUT event will be emitted when another session cause a logout success with the same account of current session.
When an IM_EVT_LOGOUT event comes out, its evt_data field must be NULL.
IM_REQ_LOGIN
Application can send an IM_REQ_LOGIN request to ask IM enabler to login into the IM server. The login result will be returned by an IM_REQ_LOGIN event.
typedef struct {
im_uri_t *user; ///< login user
char *passwd; ///< password
} im_param_login_t;
im_err_t im_login(im_sid_t sid,
evt_handler_t *handler,
im_rid_t *pRid,
im_param_login_t *login);
The IM_REQ_LOGIN event's evt_data field must be NULL, and the err_code of async_data field can tell the login result to the application.
IM_REQ_LOGOUT
Application can send an IM_REQ_LOGOUT request to ask IM enabler to logout from the IM server. The logout result will be returned by an IM_REQ_LOGOUT event.
im_err_t im_logout(im_sid_t sid,
evt_handler_t *handler,
im_rid_t *pRid);
The IM_REQ_LOGOUT event's evt_data field must be NULL, and the err_code of async_data field can tell the logout result to the application.
IM_REQ_SUBSCRIBE
Application can send an IM_REQ_SUBSCRIBE request to ask IM enabler to subscribe / unsubscribe to someone's presence notification. An IM_REQ_SUBSCRIBE event will be returned to tell application the request is sent out or not.
evt_err_t im_subscribe(im_sid_t sid,
evt_handler_t *handler,
im_rid_t *pRid,
im_subs_msg_t *subs_msg);
Here, the contactor field of subs_msg structure is the URI string whom the application would like to subscribe to. Other fields can refer to section 4.6.2.3
The IM_REQ_SUBSCRIBE event's evt_data field must be NULL, and the err_code of async_data field can tell application if the request is sent to server correctly.
IM_REQ_ACCEPTANCE
Application can send an IM_REQ_ACCEPTANCE request to ask IM enabler to answer the presence subscription from other users. An IM_REQ_ACCEPTANCE event will be returned to tell application the request is sent out or not.
im_err_t im_acceptance(im_sid_t sid,
evt_handler_t *handler,
im_rid_t *pRid,
im_accept_msg_t *accept_msg);
Here, the contactor field of accept_msg structure is the URI string whom the application would like to answer. Other fields can refer to section 4.6.2.4
The IM_REQ_ACCEPTANCE event's evt_data field must be NULL, and the err_code of async_data field can tell application if the request is sent to server correctly.
IM_REQ_PRESENCE
Application can send an IM_REQ_PRESENCE request to ask IM enabler to publish current user's presence information. Normally, the request is sent when user changes his/her presence during the session. An IM_REQ_PRESENCE event will be returned to tell application the request is sent out or not.
im_err_t im_change_presence(im_sid_t sid,
evt_handler_t *handler,
im_rid_t *pRid,
im_presence_t *presence);
The detail about how to set the parameter of presence can refer to section 4.5
The IM_REQ_PRESENCE event's evt_data field must be NULL, and the err_code of async_data field can tell application if the request is sent to server correctly.
When application send out an IM_REQ_PRESENCE event successfully, the other sessions which use the same account should receive an IM_EVT_PRESENCE event to be notified the presence change of this account.
IM_REQ_PRESENCE_PROBE
Application can send an IM_REQ_PRESENCE_PROBE request to ask IM enabler to detect the presence state of an IM user. An IM_REQ_PRESENCE_PROBE event will be returned to tell application the request is sent out or not.
im_err_t im_presence_probe(im_sid_t sid,
evt_handler_t *handler,
im_rid_t *pRid,
char *uri);
The uri is the URI string of whose presence should be detected.
The IM_REQ_ACCEPTANCE event's evt_data field must be NULL, and the err_code of async_data field can tell application if the request is sent to server correctly.
This request should cause an IM_EVT_PRESENCE event which contains the presence information about the user specified by uri.
IM_REQ_MESSAGE
Application can send an IM_REQ_MESSAGE request to ask IM enabler to send out an message to a certain buddy. An IM_REQ_MESSAGE event will be returned to tell application the request is sent out or not.
im_err_t im_send_message(im_sid_t sid,
evt_handler_t *handler,
im_rid_t *pRid,
im_msg_t *msg);
Refer to section 4.4 to get the detail about im_msg_t. Here the msg should be specified the recipient by function of im_msg_set_recipient.
The IM_REQ_MESSAGE event's evt_data field must be NULL, and the err_code of async_data field can tell application if the request is sent to server correctly.
Request cancel
Asynchronous requests can be canceled if it hasn't been sent out by IM enabler. The cancellation can be performed by:
im_err_t im_req_cancel(im_sid_t sid,
im_rid_t rid);
If a request is cancelled, the related event will be returned in which the req_state_t of async_data is set to EVT_STATE_CANCELED.