IMUnified - protocol
Written on
In 2000, IM Unified announced to create a protocol that enables an instant messaging client to join different IM services. Founding members were MSN, Odigo, Yahoo! and others.
Since then I have not heard much of IMU. I don't even think that their IMIP protocol will ever be used really. But it does exist and e.g. the Yahoo! messenger client supports it. You only have to change some values in the Windows registry. Afterwards, you're client is able to join other IM services like Odigo with the Y! messenger.
For no other reason than to see how IMIP works I've dumped some IMIP sessions with a network sniffer. The IMIP protocol is very simple structured and looks a bit like SMTP or http.
All data is exchanged over a TCP/IP connection. The clients connects to port 11319 at the server. Firstly, it performs the login handshake and afterswards, it is exchanging messages, presences and other data. All data is exchanged in blocks.
All blocks have a structure of lines. Every line is finished by \r\n (carriage return, line feed). The first line contains the type of a block, the second line contains the size of the block (first two lines not counted). It is a decimal ASCII number containing the size in bytes. Starting at the third line, there are head lines, optionally followed by an empty line, optionally followed by a block body. If the body is empty, the empty line can be absent. (The Y! messenger is allways sending the empty line, the Odigo server isn't.)
As block types (content of the first line) I have noticed the following so far: "HELO" (before login, version check, negotiation of auth type), "LOGN odigo-number" (exchange of login data), "STAT presence" (exchange of presence information, presence is one of ONLINE, AWAY, BUSY, OFFLINE (other side going offline or this side going invisible), "ACK status" acknowledge (status 600 is OK, I got 811 after sending wrong login data), "LIST ADD odigo-number" (adding user to list), "PING" (keep-alive packet, interval set by server in HELO block), "MESG" (message), "LIST ACCEPT odigo-number" (accept being added by other side), "DISC" (logout).
The header lines always have the form "identifier: content\r\n". Every block has an ID line ("ID: idvalue"). This ID is mirrored in a reply by the "Reference: idvalue" header line, sent by the server. The Y! messenger starts to generate the IDs at "1001" and increments this value for every block. The Y! messenger is always sending the ID lines as the first header line. I don't think this is neccessary because the Odigo server is not always sending this line as first header line.
The first block that is transmitted from the client to the server is a "HELO" block. Besides the ID line it contains a "Protocol: IMIP/1.0" line. The Odigo server replies with another "HELO" block containing the following lines: "Auth-Type: imip-md5", "Capabilities: server-lists", the ID line, "Keep-Alive: 60", "Protocol: IMIP/1.0", "Registration http://www.odigo.com/user", "Service: odigo.com", "ServiceDisplayName: Odigo", an empty line and an ASCII string (Odigo uses the decimal ASCII representation of a 32 bit value), that is used as salt for the MD5 password exchange. The Keep-Alive line seems to control the interval of the client sending "PING" blocks. The HELO block does not contain a Reference line.
Afterwards, the client sends a "LOGIN odigo-number" block containing the following header lines: ID line, "Client: Yahoo! IMIP Client", "Auth-Type: imip-md5", an empty line and the MD5 hash of a string containing the salt concatenated with the user's password. The hash is represented as a hexadecimal ASCII value with small letters. At the UNIX command line you can reproduce the hash value with md5sum. e.g. if the salt in the HELO block was "1919833824" and your password is "password" you get the hash with: printf "1919833824password" | md5sum (the result should be c35900c24a82592dd2d0db27c647ff17). The server replies with a "LOGN odigo-number" block containing only ID and Reference header lines.
After login, the client sets its presence with a "STAT status" block (status being ONLINE, BUSY, AWAY or OFFLINE). This block only contains an ID header line. The server replies with an "ACK 600" block containing ID and reference header lines. The presence can be explained additionally by a message in the body of the block.
The server informs the client about the presence of the user's contacts with "STAT status" blocks as well. These blocks contain an ID header line and a "From: odigo-number" header line. The client doesn't reply these blocks.
Every time the interval set by the HELO block expires the client sends a "PING" block to the server. This block only contains the ID header line. The server replies with "ACK 600".
A message is sent by a "MESG" block that contains the following header lines: ID, "To: odigo-number", "ACK-Type: errors-only", "From: own-odigo-number". After an empty line, there is the body of the message. The server doesn't react on this, probably controlled by the ACK-Type line.
A message is also received by a "MESG" block. The server sends some more header lines: "Content-Type: text/plain;charset=utf-8", "From: odigo-number \"nickname\"", ID line, "Timo: yyyy-mm-ddThh:mm:ssZ" (time in UTC), "To: own-odigo-number", an empty line and afterwards the body with the message in it. The client doesn't react on this block.
The clients starts a disconnect with a "DISC" block containing only an ID header line. The server replies with an "ACK 600" block. Afterwards the connection is closed.
To add a contact to the list, the client sends a "LIST ADD odigo-number" block. The contained header lines are: ID, "List: Buddy", "From: odigo-number". The body can contain a message. The server replies immediately with an "ACK 600" block containing ID and Reference header lines. After the contact has accepted the subscription, the server sends a "STAT status" block.
If somebody else wants to add you to his list, the server sends a "LIST ADD" block without an Odigo number in the first line. This block contains the following header lines: "From: odigo-number \"nick\"", ID, "List: Buddy" (I had this user in the Buddy group). This block can contain a message in the body. The subscription is accepted by a "LIST ACCEPT odigo-number \"nick\"" block, that contains an ID and a From header line. It does not contain a Reference header line. The server replies with an "ACK 600" block.
Update: In the meantime I beleave that "List: Buddy" is no contact list group but just the contact list and that there could be other lists like a invisible list. I havn't done more research on this topic yet. New is what I found out how a contact is removed (block of type "LIST REMOVE odigo-number" with the headers ID, "List: Buddy" and "From: odigo-number"; acknowledged with A "ACK 600" block by the server) and how to reject a subscription (block of type "LIST REJECT odigo-number" with the headers ID and "From: odigo-number").
In the LOGN block of the server there is also the list of buddies on the contact-list. This in the Buddy header. The content of this header is a list of comma separated contacts (with their nick names appended in quotes).
I got the following ACK status numbers besides "ACK 600": 800 after I sent a STAT block without a status, 801 after I sent a STAT block with a non existant status, 810 if I try to log in with a wrong password, 811 if I try to log in with an illegal user id or send a message to an illegal user id (the id was non-numerical, Odigo uses numerical IDs).
Simple IMIP session as an example, IMIP session with message exchange and subscription, simple Java-Odigo-Client implementing the IMIP protocol.