[Licq-devel] Re: clients detection stuff

Jon Keating <[email protected]> Sun, 18 May 2008 10:14:47 +0900
Newsgroups gmane.network.licq.devel
Message-ID <[email protected]>
On Wednesday 14 May 2008, 2sev wrote:
> I have already posted this in the licq IRC channel yesterday.
> And now I just made a little fix. It was not a bug but certain
> inaccuracy when detecting some Miranda IM variants.

Thanks for your patch, I took a look at it and fixed some issues: 

* A call to delete[] was changed to delete. This is very bad. I changed it to 
use boost::scoped_array.
* A call to memcmp on an array uses the address of the array (pointer to a 
pointer) instead of the array.
* shortcaps was being handled improperly. They were being set by:
shortcaps |= 1 << CAP_NAME;
And then detected by
bool hasThisCap = shortcaps >> CAP_NAME;
The correct way is:
bool hasThisCap = (shortcaps >> CAP_NAME) & 0x01;

I also removed saving the client info to the user file, as it really isn't 
important if the user is offline.

Also, upon testing of the patch, it doesn't seem very accurate. libgaim 
(pidgin?) and meebo detection and wrong. Most of the other clients are very 
rare. And not quite sure how well it detects the official clients, I didn't 
spend much time on that. I'm attaching my changes to the patch in case more 
people want to test it out.

I will add the ShortCaps stuff to SVN since that seems necessary now that most 
clients are not sending the longer caps. For example, pidgin and meebo only 
send one normal sized cap, but more short caps.

> Patches:
> http://www.mediafire.com/?yzgwdyuywbm
> http://www.mediafire.com/?n9oiwiwoznw
>
> (I'm sorry for distributing the patches such a way but I just don't
> know how to attach the files right here :). )

If you can't attach them to e-mail, you can create a ticket on the website and 
upload them to the ticket.

Jon

-- 
________________________________________________________
Jon Keating                ICQ: 16325723
[email protected]               MSN: [email protected]
http://www.licq.org        GPG: 2290A71F
http://www.thejon.org      HOME: Tokyo, Japan
licq-revised_useragent.patch (text/x-diff, 63.4 KB)
diff --git a/licq/include/licq_icq.h b/licq/include/licq_icq.h
index aee2175..351ec28 100644
--- a/licq/include/licq_icq.h
+++ b/licq/include/licq_icq.h
@@ -529,10 +529,54 @@ const char ICQ_CAPABILITY_SRVxRELAY[] = { 0x09, 0x46, 0x13, 0x49, 0x4C, 0x7F,
                                           0x11, 0xD1, 0x82, 0x22, 0x44, 0x45,
                                           0x53, 0x54, 0x00, 0x00 };
 
+const char ICQ_CAPABILITY_SHORTCAPS[]   = { 0x09, 0x46, 0x00, 0x00, 0x4C, 0x7F,
+                                            0x11, 0xD1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_AIMVOICE[]    = { 0x09, 0x46, 0x13, 0x41, 0x4C, 0x7F,
+                                            0x11, 0xD1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_AIMSENDFILE[] = { 0x09, 0x46, 0x13, 0x43, 0x4c, 0x7f,
+                                            0x11, 0xd1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
 const char ICQ_CAPABILITY_DIRECT[]    = { 0x09, 0x46, 0x13, 0x44, 0x4C, 0x7F,
                                           0x11, 0xD1, 0x82, 0x22, 0x44, 0x45,
                                           0x53, 0x54, 0x00, 0x00 };
 
+const char ICQ_CAPABILITY_AIMIMAGE[]    = { 0x09, 0x46, 0x13, 0x45, 0x4c, 0x7f,
+                                            0x11, 0xd1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_AIMICON[]     = { 0x09, 0x46, 0x13, 0x46, 0x4c, 0x7f,
+                                            0x11, 0xd1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_AIM_STOCKS[]  = { 0x09, 0x46, 0x13, 0x47, 0x4C, 0x7F,
+                                            0x11, 0xD1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_AIMGETFILE[]  = { 0x09, 0x46, 0x13, 0x48, 0x4c, 0x7f,
+                                            0x11, 0xd1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_AIM_GAMES[]   = { 0x09, 0x46, 0x13, 0x4A, 0x4C, 0x7F,
+                                            0x11, 0xD1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_BUDDY_LIST[]  = { 0x09, 0x46, 0x13, 0x4B, 0x4C, 0x7F,
+                                            0x11, 0xD1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_AVATAR[]      = { 0x09, 0x46, 0x13, 0x4C, 0x4C, 0x7F,
+                                            0x11, 0xD1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_AIM_SUPPORT[] = { 0x09, 0x46, 0x13, 0x4D, 0x4C, 0x7F,
+                                            0x11, 0xD1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
 const char ICQ_CAPABILITY_UTF8[]      = { 0x09, 0x46, 0x13, 0x4E, 0x4C, 0x7F,
                                           0x11, 0xD1, 0x82, 0x22, 0x44, 0x45,
                                           0x53, 0x54, 0x00, 0x00 };
@@ -568,14 +612,305 @@ const char ICQ_CAPABILITY_LICQxVER[]  = { 'L',  'i',  'c',  'q',  ' ',  'c',
 const char ICQ_CAPABILITY_SIMxVER[]   = { 'S',  'I',  'M',  ' ',  'c',  'l', 
                                           'i',  'e',  'n',  't',  ' ',  ' ',
                                           0x00, 0x00, 0x00, 0x00 };
+                                            
+const char ICQ_CAPABILITY_SIMOLDxVER[]  = { 0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c,
+                                            0x43, 0x34, 0xad, 0x22, 0xd6, 0xab,
+                                            0xf7, 0x3f, 0x14, 0x00 };
+
+const char ICQ_CAPABILITY_KOPETExVER[]  = { 'K',  'o',  'p',  'e',  't',  'e',
+                                            ' ',  'I',  'C',  'Q',  ' ',  ' ',
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_MICQxVER[]    = { 'm',  'I',  'C',  'Q',  ' ', 0xA9,
+                                            ' ',  'R',  '.',  'K',  '.',  ' ', 
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_MIRANDAxVER[] = { 'M', 'i', 'r', 'a', 'n', 'd', 'a',
+                                            'M', 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_MIRMOBxVER[]  = { 'M', 'i', 'r', 'a', 'n', 'd', 'a',
+                                            'M', 'o', 'b', 'i', 'l', 'e', 0x00,
+                                            0x00, 0x00 };
+                                              
+const char ICQ_CAPABILITY_MIMPACKxVER[] = { 'M', 'I', 'M', '/', 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_ICQJS7xVER[]  = { 'i', 'c', 'q', 'j', 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_ICQJPxVER[]   = { 'i', 'c', 'q', 'p', 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_ICQJS7SxVER[] = { 'i', 'c', 'q', 'j', 0x00, 'S', 'e',
+                                            'c', 'u', 'r', 'e', 0x00, 'I', 'M',
+                                            0x00, 0x00 };
+
+const char ICQ_CAPABILITY_ICQJS7OxVER[] = { 0x69, 0x63, 0x71, 0x6a, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_ICQJSINxVER[] = { 's', 'i', 'n', 'j',  0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_ICQJENxVER[]  = { 'e', 'n', 'q', 'j', 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_AIMOSCARxVER[]= { 'M', 'i', 'r', 'a', 'n', 'd', 'a',
+                                            'A', 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_TRILLIANxVER[]= { 0x97, 0xb1, 0x27, 0x51, 0x24, 0x3c,
+                                            0x43, 0x34, 0xad, 0x22, 0xd6, 0xab,
+                                            0xf7, 0x3f, 0x14, 0x09 };
+
+const char ICQ_CAPABILITY_TRILCRPTxVER[]= { 0xf2, 0xe7, 0xc7, 0xf4, 0xfe, 0xad,
+                                            0x4d, 0xfb, 0xb2, 0x35, 0x36, 0x79,
+                                            0x8b, 0xdf, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_CLIMMxVER[]   = { 'c', 'l', 'i', 'm', 'm', 0xA9, ' ',
+                                            'R', '.', 'K', '.', ' ', 0x00,
+                                            0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_ANDRQxVER[]   = { '&', 'R', 'Q', 'i', 'n', 's', 'i',
+                                            'd', 'e', 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_RANDQxVER[]   = { 'R', '&', 'Q', 'i', 'n', 's', 'i',
+                                            'd', 'e', 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_MCHATxVER[]   = { 'm', 'C', 'h', 'a', 't', ' ', 'i',
+                                            'c', 'q', ' ', 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_JIMMxVER[]    = { 'J', 'i', 'm', 'm', ' ', 0x00,
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_COREPGRxVER[] = { 'C', 'O', 'R', 'E', ' ', 'P', 'a',
+                                            'g', 'e', 'r', 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_DICHATxVER[]  = { 'D', '[', 'i', ']', 'C', 'h', 'a',
+                                            't', ' ', 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_NAIMxVER[]    = { 0xFF, 0xFF, 0xFF, 0xFF, 'n', 'a',
+                                            'i', 'm', 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_ANSTxVER[]    = { 0x44, 0xE5, 0xBF, 0xCE, 0xB0, 0x96,
+                                            0xE5, 0x47, 0xBD, 0x65, 0xEF, 0xD6,
+                                            0xA3, 0x7E, 0x36, 0x02 };
+
+const char ICQ_CAPABILITY_QIPxVER[]     = { 0x56, 0x3F, 0xC8, 0x09, 0x0B, 0x6F,
+                                            0x41, 'Q', 'I', 'P', ' ', '2', '0',
+                                            '0', '5', 'a' };
+
+const char ICQ_CAPABILITY_QIPPDAxVER[]  = { 0x56, 0x3F, 0xC8, 0x09, 0x0B, 0x6F,
+                                            0x41, 'Q', 'I', 'P', ' ', ' ', ' ',
+                                            ' ', ' ', '!' };
+
+const char ICQ_CAPABILITY_QIPMOBxVER[]  = { 0x56, 0x3F, 0xC8, 0x09, 0x0B, 0x6F,
+                                            0x41, 'Q', 'I', 'P', ' ', ' ', ' ',
+                                            ' ', ' ', '"' };
+
+const char ICQ_CAPABILITY_QIPINFxVER[]  = { 0x7C, 0x73, 0x75, 0x02, 0xC3, 0xBE,
+                                            0x4F, 0x3E, 0xA6, 0x9F, 0x01, 0x53,
+                                            0x13, 0x43, 0x1E, 0x1A };
+
+const char ICQ_CAPABILITY_QIPPLUGINS[]  = { 0x7c, 0x53, 0x3f, 0xfa, 0x68, 0x00,
+                                            0x4f, 0x21, 0xbc, 0xfb, 0xc7, 0xd2,
+                                            0x43, 0x9a, 0xad, 0x31 };
+
+const char ICQ_CAPABILITY_QIP1[]        = { 0xd3, 0xd4, 0x53, 0x19, 0x8b, 0x32,
+                                            0x40, 0x3b, 0xac, 0xc7, 0xd1, 0xa9,
+                                            0xe2, 0xb5, 0x81, 0x3e };
+
+const char ICQ_CAPABILITY_QIPSYMBxVER[] = { 0x51, 0xad, 0xd1, 0x90, 0x72, 0x04,
+                                            0x47, 0x3d, 0xa1, 0xa1, 0x49, 0xf4,
+                                            0xa3, 0x97, 0xa4, 0x1f };
+
+const char ICQ_CAPABILITY_VMICQxVER[]   = { 0x56, 0x6d, 0x49, 0x43, 0x51, 0x20,
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_SMAPERxVER[]  = { 'S', 'm', 'a', 'p', 'e', 'r', ' ',
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_IMPLUXxVER[]  = { 0x8e, 0xcd, 0x90, 0xe7, 0x4f, 0x18,
+                                            0x28, 0xf8, 0x02, 0xec, 0xd6, 0x18,
+                                            0xa4, 0xe9, 0xde, 0x68 };
+
+const char ICQ_CAPABILITY_YAPPxVER[]    = { 0x59, 0x61, 0x70, 0x70, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_IM2xVER[]     = { 0x74, 0xED, 0xC3, 0x36, 0x44, 0xDF,
+                                            0x48, 0x5B, 0x8B, 0x1C, 0x67, 0x1A,
+                                            0x1F, 0x86, 0x09, 0x9F };
+
+const char ICQ_CAPABILITY_MACICQxVER[]  = { 0xdd, 0x16, 0xf2, 0x02, 0x84, 0xe6,
+                                            0x11, 0xd4, 0x90, 0xdb, 0x00, 0x10,
+                                            0x4b, 0x9b, 0x4b, 0x7d };
+
+const char ICQ_CAPABILITY_IS2001[]      = { 0x2e, 0x7a, 0x64, 0x75, 0xfa, 0xdf,
+                                            0x4d, 0xc8, 0x88, 0x6f, 0xea, 0x35,
+                                            0x95, 0xfd, 0xb6, 0xdf };
+const char ICQ_CAPABILITY_IS2002[]      = { 0x10, 0xcf, 0x40, 0xd1, 0x4c, 0x7f,
+                                            0x11, 0xd1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+const char ICQ_CAPABILITY_COMM20012[]   = { 0xa0, 0xe9, 0x3f, 0x37, 0x4c, 0x7f,
+                                            0x11, 0xd1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_STRICQxVER[]  = { 0xa0, 0xe9, 0x3f, 0x37, 0x4f, 0xe9,
+                                            0xd3, 0x11, 0xbc, 0xd2, 0x00, 0x04,
+                                            0xac, 0x96, 0xdd, 0x96 };
+
+const char ICQ_CAPABILITY_ICQLITExVER[] = { 0x17, 0x8C, 0x2D, 0x9B, 0xDA, 0xA5,
+                                            0x45, 0xBB, 0x8D, 0xDB, 0xF3, 0xBD,
+                                            0xBD, 0x53, 0xA1, 0x0A };
+
+const char ICQ_CAPABILITY_AIMCHAT[]     = { 0x74, 0x8F, 0x24, 0x20, 0x62, 0x87,
+                                            0x11, 0xD1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_UIM[]         = { 0xA7, 0xE4, 0x0A, 0x96, 0xB3, 0xA0,
+                                            0x47, 0x9A, 0xB8, 0x45, 0xC9, 0xE4,
+                                            0x67, 0xC5, 0x6B, 0x1F };
+const char ICQ_CAPABILITY_RAMBLER[]     = { 0x7E, 0x11, 0xB7, 0x78, 0xA3, 0x53,
+                                            0x49, 0x26, 0xA8, 0x02, 0x44, 0x73,
+                                            0x52, 0x08, 0xC4, 0x2A };
+
+const char ICQ_CAPABILITY_ABV[]         = { 0x00, 0xE7, 0xE0, 0xDF, 0xA9, 0xD0,
+                                            0x4F, 0xe1, 0x91, 0x62, 0xC8, 0x90,
+                                            0x9A, 0x13, 0x2A, 0x1B };
+
+const char ICQ_CAPABILITY_NETVIGATOR[]  = { 0x4C, 0x6B, 0x90, 0xA3, 0x3D, 0x2D,
+                                            0x48, 0x0E, 0x89, 0xD6, 0x2E, 0x4B,
+                                            0x2C, 0x10, 0xD9, 0x9F };
+
+const char ICQ_CAPABILITY_TZERS[]       = { 0xb2, 0xec, 0x8f, 0x16, 0x7c, 0x6f,
+                                            0x45, 0x1b, 0xbd, 0x79, 0xdc, 0x58,
+                                            0x49, 0x78, 0x88, 0xb9 };
+
+const char ICQ_CAPABILITY_HTMLMSGS[]    = { 0x01, 0x38, 0xca, 0x7b, 0x76, 0x9a,
+                                            0x49, 0x15, 0x88, 0xf2, 0x13, 0xfc,
+                                            0x00, 0x97, 0x9e, 0xa8 };
+
+const char ICQ_CAPABILITY_LIVEVIDEO[]   = { 0x09, 0x46, 0x01, 0x01, 0x4c, 0x7f,
+                                            0x11, 0xd1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_SIMPLITE[]    = { 0x53, 0x49, 0x4D, 0x50, 0x53, 0x49,
+                                            0x4D, 0x50, 0x53, 0x49, 0x4D, 0x50,
+                                            0x53, 0x49, 0x4D, 0x50 };
+
+const char ICQ_CAPABILITY_SIMPPRO[]     = { 0x53, 0x49, 0x4D, 0x50, 0x5F, 0x50,
+                                            0x52, 0x4F, 0x53, 0x49, 0x4D, 0x50,
+                                            0x5F, 0x50, 0x52, 0x4F };
+
+const char ICQ_CAPABILITY_IMSECURE[]    = { 'I', 'M', 's', 'e', 'c', 'u', 'r',
+                                            'e', 'C', 'p', 'h', 'r', 0x00,
+                                            0x00, 0x06, 0x01 };
+
+const char ICQ_CAPABILITY_MSGTYPE2[]    = { 0x09, 0x49, 0x13, 0x49, 0x4c, 0x7f,
+                                            0x11, 0xd1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_AIMICQ[]      = { 0x09, 0x46, 0x13, 0x4D, 0x4C, 0x7F,
+                                            0x11, 0xD1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_AIMAUDIO[]    = { 0x09, 0x46, 0x01, 0x04, 0x4c, 0x7f,
+                                            0x11, 0xd1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_PALMJICQ[]    = { 'J', 'I', 'C', 'Q', 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_INLUXMSGR[]   = { 0xA7, 0xE4, 0x0A, 0x96, 0xB3, 0xA0,
+                                            0x47, 0x9A, 0xB8, 0x45, 0xC9, 0xE4,
+                                            0x67, 0xC5, 0x6B, 0x1F };
+
+const char ICQ_CAPABILITY_MIPCLIENT[]   = { 0x4D, 0x49, 0x50, 0x20, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_IMADERING[]   = { 'I', 'M', 'a', 'd', 'e', 'r', 'i',
+                                            'n', 'g', ' ', 'C', 'l', 'i', 'e',
+                                            'n', 't' };
+//AIM Client version 5.9 capabilities
+const char ICQ_CAPABILITY_AIMADDINGS[]  = { 0x09, 0x46, 0x13, 0x47, 0x4c, 0x7f,
+                                            0x11, 0xd1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_AIMCONTSEND[] = { 0x09, 0x46, 0x13, 0x4b, 0x4c, 0x7f,
+                                            0x11, 0xd1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_AIMUNK2[]     = { 0x09, 0x46, 0x01, 0x02, 0x4c, 0x7f,
+                                            0x11, 0xd1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_AIMSNDBDDLST[]= { 0x09, 0x46, 0x00, 0x00, 0x4c, 0x7f,
+                                            0x11, 0xd1, 0x82, 0x22, 0x44, 0x45,
+                                            0x53, 0x54, 0x13, 0x4B };
+
+const char ICQ_CAPABILITY_IMSECKEY1[]   = { 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00 };
+
+const char ICQ_CAPABILITY_IMSECKEY2[]   = { 0x02, 0x02, 0x02, 0x02, 0x02, 0x02,
+                                            0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                            0x00, 0x00, 0x00, 0x00 };
+
+
+// Short capabilities
+#define SHORT_CAPS_COUNT 14
+const char ShortCaps[2 * SHORT_CAPS_COUNT + 1] = {
+  0x00, 0x00, // CAP_SHORTCAPS
+  0x13, 0x41, // CAP_AIM_VOICE
+  0x13, 0x43, // CAP_AIM_SENDFILE
+  0x13, 0x44, // CAP_DIRECT
+  0x13, 0x45, // CAP_AIM_IMIMAGE
+  0x13, 0x46, // CAP_AIM_BUDDYCON
+  0x13, 0x47, // CAP_AIM_STOCKS
+  0x13, 0x48, // CAP_AIM_GETFILE
+  0x13, 0x49, // CAP_SRV_RELAY
+  0x13, 0x4a, // CAP_AIM_GAMES
+  0x13, 0x4b, // CAP_AIM_BUDDYLIST
+  0x13, 0x4c, // CAP_AVATAR
+  0x13, 0x4d, // CAP_AIM_SUPPORT
+  0x13, 0x4e  // CAP_UTF
+};
 
-const char ICQ_CAPABILITY_KOPETExVER[] ={ 'K',  'o',  'p',  'e',  't',  'e',
-                                          ' ',  'I',  'C',  'Q',  ' ',  ' ',
-                                          0x00, 0x00, 0x00, 0x00 };
+typedef enum {
+  SHORTCAP_SHORTCAPS = 0,
+  SHORTCAP_AIM_VOICE,
+  SHORTCAP_AIM_SENDFILE,
+  SHORTCAP_DIRECT,
+  SHORTCAP_AIM_IMIMAGE,
+  SHORTCAP_AIM_BUDDYCON,
+  SHORTCAP_AIM_STOCKS,
+  SHORTCAP_AIM_GETFILE,
+  SHORTCAP_SRV_RELAY,
+  SHORTCAP_AIM_GAMES,
+  SHORTCAP_AIM_BUDDYLIST,
+  SHORTCAP_AVATAR,
+  SHORTCAP_AIM_SUPPORT,
+  SHORTCAP_UTF
+} shortCapID;
 
-const char ICQ_CAPABILITY_MICQxVER[]  = { 'm',  'I',  'C',  'Q',  ' ', 0xA9,
-                                          ' ',  'R',  '.',  'K',  '.',  ' ', 
-                                          0x00, 0x00, 0x00, 0x00 };
 
 // XtraAway
 const int XTRA_AWAY_COUNT             = 32;
diff --git a/licq/include/licq_icqd.h b/licq/include/licq_icqd.h
index aa8589b..bdb1e80 100644
--- a/licq/include/licq_icqd.h
+++ b/licq/include/licq_icqd.h
@@ -809,6 +809,10 @@ protected:
   void ProcessBOSFam(CBuffer&, unsigned short);
   void ProcessListFam(CBuffer &, unsigned short);
   void ProcessNewUINFam(CBuffer &, unsigned short);
+  
+  //--- Capabilities -----
+  void ProcessBuddyCaps(ICQUser *, char *, unsigned short);
+  char *MatchBuddyCaps(char *, unsigned, const char *, unsigned short);
 
   void ProcessSystemMessage(CBuffer &packet, unsigned long checkUin, unsigned short newCommand, time_t timeSent);
   void ProcessMetaCommand(CBuffer &packet, unsigned short nMetaCommand, ICQEvent *e);
diff --git a/licq/include/licq_user.h b/licq/include/licq_user.h
index 5f5c703..7b2723b 100644
--- a/licq/include/licq_user.h
+++ b/licq/include/licq_user.h
@@ -552,6 +552,7 @@ public:
   unsigned long OurClientInfoTimestamp() { return m_nOurClientInfoTimestamp; }
   unsigned long ClientStatusTimestamp() { return m_nClientStatusTimestamp; }
   unsigned long OurClientStatusTimestamp() { return m_nOurClientStatusTimestamp; }
+  unsigned short ShortCaps() { return m_nClientShortCaps; }
   bool UserUpdated()                    { return m_bUserUpdated; }
   SecureChannelSupport_et SecureChannelSupport();
   unsigned short LicqVersion();
@@ -666,6 +667,7 @@ public:
   void SetOurClientInfoTimestamp(unsigned long s) { m_nOurClientInfoTimestamp = s; }
   void SetClientStatusTimestamp(unsigned long s) { m_nClientStatusTimestamp = s; }
   void SetOurClientStatusTimestamp(unsigned long s) { m_nOurClientStatusTimestamp = s; }
+  void SetShortCaps(unsigned short s) { m_nClientShortCaps = s; }
   void SetUserUpdated(bool s)         { m_bUserUpdated = s; }
   void SetConnectionVersion(unsigned short s)    { m_nConnectionVersion = s; }
   void SetAutoChatAccept(bool s)      { s ? m_nAutoAccept |= AUTO_ACCEPT_CHAT : m_nAutoAccept &= ~AUTO_ACCEPT_CHAT; SaveLicqInfo(); }
@@ -860,6 +862,7 @@ protected:
   unsigned long m_nClientInfoTimestamp, m_nClientStatusTimestamp;
   unsigned long m_nOurClientTimestamp, m_nOurClientInfoTimestamp;
   unsigned long m_nOurClientStatusTimestamp;
+  unsigned short m_nClientShortCaps;
   bool m_bUserUpdated;
   unsigned short m_nPort, m_nLocalPort, m_nConnectionVersion;
   unsigned short m_nTyping;
diff --git a/licq/src/icqd-srv.cpp b/licq/src/icqd-srv.cpp
index 202fb5f..4089d35 100644
--- a/licq/src/icqd-srv.cpp
+++ b/licq/src/icqd-srv.cpp
@@ -2565,6 +2565,1122 @@ void CICQDaemon::ProcessLocationFam(CBuffer &packet, unsigned short nSubtype)
   }
 }
 
+//--------ProcessBuddyCaps-------------------------------------------------
+void CICQDaemon::ProcessBuddyCaps(ICQUser *user, char *caps, unsigned short capsize)
+{
+  unsigned long nTimestamp = user->ClientTimestamp();
+  unsigned long nStatusTimestamp = user->ClientStatusTimestamp();
+  unsigned long nInfoTimestamp = user->ClientInfoTimestamp();
+  unsigned short tcpVersion = user->Version();
+  unsigned short shortcaps = user->ShortCaps();
+  char *capID;
+  char szExtraInfo[64] = { 0 };
+  string version = "";
+  char tmpVer[64];
+  unsigned int ver1, ver2, ver3, ver4;
+  
+  // Trying to determine a client version using direct connection info.
+  if ((nTimestamp & 0xffff0000) == LICQ_WITHSSL)
+  {
+    snprintf(szExtraInfo,
+             sizeof(szExtraInfo) - 1,
+             "Licq %s/SSL",
+             CUserEvent::LicqVersionToString(nTimestamp & 0xffff));
+  }
+  else if ((nTimestamp & 0xffff0000) == LICQ_WITHOUTSSL)
+  {
+    snprintf(szExtraInfo,
+             sizeof(szExtraInfo) - 1,
+             "Licq %s",
+             CUserEvent::LicqVersionToString(nTimestamp & 0xffff));
+  }
+  else if (nTimestamp == 0xffffffff)
+  {
+    if (nStatusTimestamp == 0xffffffff)
+      strcpy(szExtraInfo, "Gaim");
+    else if ((!nStatusTimestamp) && (tcpVersion == 7))
+      strcpy(szExtraInfo, "WebICQ");
+    else if ((!nStatusTimestamp) && (nInfoTimestamp == 0x3b7248ed))
+      strcpy(szExtraInfo, "Spam Bot");
+    else
+    {
+      unsigned ver1 = (nStatusTimestamp >> 0x18) & 0xFF;
+      unsigned ver2 = (nStatusTimestamp >> 0x10) & 0xFF;
+      unsigned ver3 = (nStatusTimestamp >> 0x08) & 0xFF;
+      unsigned ver4 = nStatusTimestamp & 0xFF;
+      if(ver1 & 0x80)
+      {
+        snprintf(szExtraInfo,
+                 sizeof(szExtraInfo) - 1,
+                 "Miranda IM (ICQ 0.%hu.%hu.%hu alpha)",
+                 ver2,
+                 ver3,
+                 ver4);
+      }
+      else
+      {
+        snprintf(szExtraInfo,
+                 sizeof(szExtraInfo) - 1,
+                 "Miranda IM (ICQ %hu.%hu.%hu.%hu)",
+                 ver1,
+                 ver2,
+                 ver3,
+                 ver4);
+      }
+
+      if (nInfoTimestamp == 0x5AFEC0DE)
+        strcat(szExtraInfo, " (SecureIM)");
+      else if ((nInfoTimestamp >> 0x18) == 0x80)
+        strcat(szExtraInfo, " (Unicode)");
+    }
+  }
+  else if (nTimestamp == 0x7fffffff)
+  {
+    unsigned ver1 = (nStatusTimestamp >> 0x18) & 0xFF;
+    unsigned ver2 = (nStatusTimestamp >> 0x10) & 0xFF;
+    unsigned ver3 = (nStatusTimestamp >> 0x08) & 0xFF;
+    unsigned ver4 = nStatusTimestamp & 0xFF;
+    if(ver1 & 0x80)
+    {
+      snprintf(szExtraInfo,
+               sizeof(szExtraInfo) - 1,
+               "Miranda IM (ICQ 0.%hu.%hu.%hu alpha)",
+               ver2,
+               ver3,
+               ver4);
+    }
+    else
+    {
+      snprintf(szExtraInfo,
+               sizeof(szExtraInfo) - 1,
+               "Miranda IM (ICQ %hu.%hu.%hu.%hu)",
+               ver1,
+               ver2,
+               ver3,
+               ver4);
+    }
+
+    if (nInfoTimestamp == 0x5AFEC0DE)
+      strcat(szExtraInfo, " (SecureIM)");
+    else if ((nInfoTimestamp >> 0x18) == 0x80)
+      strcat(szExtraInfo, " (Unicode)");
+  }
+  else if (nTimestamp == 0x3b75ac09)
+    strcpy(szExtraInfo, "Trillian");
+  else if (nTimestamp == 0xffffff42)
+    strcpy(szExtraInfo, "mICQ");
+  else if (nTimestamp == 0xffffff8f)
+    strcpy(szExtraInfo, "StrICQ");
+  else if (nTimestamp == 0xffffff7f)
+    strcpy(szExtraInfo, "&RQ");
+  else if (nTimestamp == 0xffffffab)
+    strcpy(szExtraInfo, "YSM");
+  else if (nTimestamp == 0xffffffbe)
+  {
+    ver1 = (nStatusTimestamp >> 0x18) & 0xff;
+    ver2 = (nStatusTimestamp >> 0x10) & 0xff;
+    ver3 = (nStatusTimestamp >> 0x08) & 0xff;
+  
+    snprintf(szExtraInfo, sizeof(szExtraInfo) - 1, "Alicq %d.%d.%d", ver1, ver2, ver3);
+  }
+  else if (nTimestamp == 0x04031980)
+    strcpy(szExtraInfo, "vICQ");
+  else if ((nTimestamp == 0x3aa773ee) && (nStatusTimestamp == 0x3aa66380))
+    strcpy(szExtraInfo, "libicq2000");
+  else if ((nTimestamp == 0x3ba8dbaf) && (tcpVersion == 2))
+    strcpy(szExtraInfo, "stICQ");
+  else if ((nTimestamp == 0xfffffffe) && (nInfoTimestamp == 0xfffffffe))
+    strcpy(szExtraInfo, "Jimm");
+  else if ((nTimestamp == 0x3ff19beb) && (nInfoTimestamp == 0x3ff19beb))
+    strcpy(szExtraInfo, "IM2");
+  else if ((nTimestamp == 0xddddeeff) &&
+           (!nStatusTimestamp) &&
+           (!nInfoTimestamp))
+    strcpy(szExtraInfo, "SmartICQ");
+  else if (((nTimestamp & 0xfffffff0) == 0x494d2b00) &&
+           (!nStatusTimestamp) &&
+           (!nInfoTimestamp))
+    strcpy(szExtraInfo, "IM+");
+  else if ((nTimestamp == 0x3b4c4c0c) &&
+           (!nStatusTimestamp) &&
+           (nInfoTimestamp == 0x3b7248ed))
+    strcpy(szExtraInfo, "KXicq2");
+  else if ((nTimestamp == 0xfffff666) && (!nInfoTimestamp))
+    snprintf(szExtraInfo, 63, "R&Q %ud", (unsigned)nStatusTimestamp);
+  else if ((nTimestamp == 0x66666666) && (nInfoTimestamp == 0x66666666))
+  {
+    strcpy(szExtraInfo, "D[i]Chat");
+    if (nStatusTimestamp == 0x10000)
+      strcat(szExtraInfo, " v.0.1a");
+    else if (nStatusTimestamp == 0x22)
+      strcat(szExtraInfo, " v.0.2b");
+  }
+  else if ((nTimestamp == 0x44F523B0) &&
+           (nStatusTimestamp == 0x44F523A6) &&
+           (nInfoTimestamp == 0x44F523A6) &&
+           (tcpVersion == 8))
+    strcpy(szExtraInfo, "Virus");
+  else
+    szExtraInfo[0] = 0;
+  szExtraInfo[63] = '\0';
+
+  if (szExtraInfo[0] != 0)
+    version = string(szExtraInfo);
+
+  // Trying to determine a client version using capabilities.
+  bool bUTF8     = (shortcaps >> SHORTCAP_UTF) & 0x01; // Check if they support UTF8
+  bool bRTF      = false;
+  bool bTYPING   = false;
+  bool bAIMCHAT  = false;
+  bool bSENDFILE = (shortcaps >> SHORTCAP_AIM_SENDFILE) & 0x01;
+  bool bDIRECT   = (shortcaps >> SHORTCAP_DIRECT) & 0x01;
+  bool bAIMICON  = (shortcaps >> SHORTCAP_AIM_BUDDYCON) & 0x01;
+  bool bGETFILE  = (shortcaps >> SHORTCAP_AIM_GETFILE) & 0x01;
+  bool bSRVRELAY = (shortcaps >> SHORTCAP_SRV_RELAY) & 0x01;
+  
+  if ((bUTF8 == false) &&
+      (MatchBuddyCaps(caps, capsize, ICQ_CAPABILITY_UTF8, CAP_LENGTH)))
+  {
+    bUTF8 = true;
+  }
+  if (MatchBuddyCaps(caps, capsize, ICQ_CAPABILITY_RTFxMSGS, CAP_LENGTH))
+  {
+    bRTF = true;
+  }
+  if ((MatchBuddyCaps(caps, capsize, ICQ_CAPABILITY_AIMCHAT, CAP_LENGTH)))
+  {
+    bAIMCHAT = true;
+  }
+  if ((bSENDFILE == false) &&
+      (MatchBuddyCaps(caps, capsize, ICQ_CAPABILITY_AIMSENDFILE, CAP_LENGTH)))
+  {
+    bSENDFILE = true;
+  }
+  if ((bDIRECT == false) &&
+      (MatchBuddyCaps(caps, capsize, ICQ_CAPABILITY_DIRECT, CAP_LENGTH)))
+  {
+    bDIRECT = true;
+  }
+  if ((bAIMICON == false) &&
+      (MatchBuddyCaps(caps, capsize, ICQ_CAPABILITY_AIMICON, CAP_LENGTH)))
+  {
+    bAIMICON = true;
+  }
+  if ((bGETFILE == false) &&
+      (MatchBuddyCaps(caps, capsize, ICQ_CAPABILITY_AIMGETFILE, CAP_LENGTH)))
+  {
+    bGETFILE = true;
+  }
+  if ((bSRVRELAY == false) &&
+      (MatchBuddyCaps(caps, capsize, ICQ_CAPABILITY_SRVxRELAY, CAP_LENGTH)))
+  {
+    bSRVRELAY = true;
+  }
+
+  // Check capability flags for their client version.
+  // LICQ
+  if ((capID = MatchBuddyCaps(caps,
+                              capsize,
+                              ICQ_CAPABILITY_LICQxVER,
+                              strlen(ICQ_CAPABILITY_LICQxVER))))
+  {
+    char *verStr = capID + CAP_LENGTH - 4;
+    ver1 = verStr[0];
+    ver2 = verStr[1]%100;
+    ver3 = verStr[2];
+    snprintf(tmpVer, sizeof(tmpVer) - 1, "%u.%u.%u", ver1, ver2, ver3);
+    version = "Licq v" + string(tmpVer);
+    if (verStr[3] == 1) version += "/SSL";
+  }
+  // KOPETE
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_KOPETExVER,
+                                   strlen(ICQ_CAPABILITY_KOPETExVER))))
+  {
+    char *verStr = capID + CAP_LENGTH - 4;
+    ver1 = verStr[0];
+    ver2 = verStr[1];
+    ver3 = verStr[2]*100;
+    ver3 += verStr[3];
+    snprintf(tmpVer, sizeof(tmpVer) - 1, "%u.%u.%u", ver1, ver2, ver3);
+    version = "Kopete v" + string(tmpVer);
+  }
+  // SIM
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_SIMxVER,
+                                   strlen(ICQ_CAPABILITY_SIMxVER))))
+  {
+    char *verStr = capID + CAP_LENGTH - 4;
+    ver1 = verStr[0];
+    ver2 = verStr[1];
+    ver3 = verStr[2];
+    ver4 = verStr[3] & 0x0f;
+    if (ver4)
+    {
+      snprintf(tmpVer,
+               sizeof(tmpVer) - 1,
+               "%u.%u.%u.%u",
+               ver1,
+               ver2,
+               ver3,
+               ver4);
+    }
+    else if (ver3)
+    {
+      snprintf(tmpVer,
+               sizeof(tmpVer) - 1,
+               "%u.%u.%u",
+               ver1,
+               ver2,
+               ver3);
+    }
+    else
+    {
+      snprintf(tmpVer,
+               sizeof(tmpVer) - 1,
+               "%u.%u",
+               ver1,
+               ver2);
+    }
+    if (ver4 & 0x80)
+      strcat(tmpVer,"/Win32");
+    else if (ver4 & 0x40)
+      strcat(tmpVer,"/MacOS X");
+    version = "SIM v" + string(tmpVer);
+  }
+  // MICQ
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_MICQxVER,
+                                   0x0c)))
+  {
+    char *verStr = capID + CAP_LENGTH - 4;
+    ver1 = verStr[0];
+    ver2 = verStr[1];
+    ver3 = verStr[2];
+    ver4 = verStr[3];
+    snprintf(tmpVer,
+             sizeof(tmpVer) - 1,
+             "%u.%u.%u.%u",
+             ver1,
+             ver2,
+             ver3,
+             ver4);
+    if ((ver1 & 0x80) == 0x80) strcat(tmpVer, " alpha");
+    version = "mICQ" + string(tmpVer);
+  }
+  // MIRANDA
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_ICQJSINxVER,
+                                   0x04)) ||
+           (capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_ICQJS7xVER,
+                                   0x04)) ||
+           (capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_ICQJPxVER,
+                                   0x04)) ||
+           (capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_ICQJENxVER,
+                                   0x04)))
+  {  
+    unsigned mver0   = capID[0x4] & 0xff;
+    unsigned mver1   = capID[0x5] & 0xff;
+    unsigned mver2   = capID[0x6] & 0xff;
+    unsigned mver3   = capID[0x7] & 0xff;
+    unsigned iver0   = capID[0x8] & 0xff;
+    unsigned iver1   = capID[0x9] & 0xff;
+    unsigned iver2   = capID[0xa] & 0xff;
+    unsigned iver3   = capID[0xb] & 0xff;
+    unsigned secure  = capID[0xc] & 0xff;
+    unsigned ModVer  = capID[0x3] & 0xff;
+    unsigned Unicode = (nInfoTimestamp >> 24) & 0xff;
+    if ((mver1 < 20) && (iver1 < 20))
+    {
+      version = "Miranda IM ";
+      if (mver0 == 0x80)
+      {
+        if (mver2 == 0x00)
+        {
+          snprintf(tmpVer,
+                   sizeof(tmpVer) - 1,
+                   "0.%u alpha build #%u",
+                   mver1,
+                   mver3);
+        }
+        else
+        {
+          snprintf(tmpVer,
+                   sizeof(tmpVer) - 1,
+                   "0.%u.%u alpha build #%u",
+                   mver1,
+                   mver2,
+                   mver3);
+        }
+        version += string(tmpVer);
+      }
+      else
+      {
+        if (mver2 == 0x00)
+        {
+          snprintf(tmpVer,
+                   sizeof(tmpVer) - 1,
+                   "%u.%u",
+                   mver0,
+                   mver1);
+        }
+        else
+        {
+          snprintf(tmpVer,
+                   sizeof(tmpVer) - 1,
+                   "%u.%u.%u",
+                   mver0,
+                   mver1,
+                   mver2);
+        }
+        version += string(tmpVer);
+        if ((mver3 != 0x00) && (mver3 != 0x64))
+        {
+          snprintf(tmpVer,
+                   sizeof(tmpVer) - 1,
+                   " alpha build #%u",
+                   mver3);
+          version += string(tmpVer);
+        }
+      }
+      if ((Unicode == 0x80) || (nTimestamp == 0x7fffffff))
+        version += " Unicode";
+      if (ModVer == 'p')
+        version += " (ICQ Plus";
+      else if (capID[0x0] == 's')
+        version += " (ICQ S!N";
+      else if (capID[0x0] == 'e')
+        version += " (ICQ eternity/PlusPlus++";
+      else if (ModVer == 'j')
+        version += " (ICQ S7 & SSS";
+      if (iver0 == 0x80)
+      {
+        snprintf(tmpVer,
+                 sizeof(tmpVer) - 1,
+                 " 0.%u.%u.%u alpha)",
+                 iver1,
+                 iver2,
+                 iver3);
+        version += string(tmpVer);
+      }
+      else
+      {
+        snprintf(tmpVer,
+                 sizeof(tmpVer) - 1,
+                 " %u.%u.%u.%u)",
+                 iver0,
+                 iver1,
+                 iver2,
+                 iver3);
+        version += string(tmpVer);
+      }
+      if ((secure != 0) && (secure != 20) || (nInfoTimestamp == 0x5AFEC0DE))
+        version += " (SecureIM)";
+		  else if (MatchBuddyCaps(caps,
+                              capsize,
+                              ICQ_CAPABILITY_ICQJS7SxVER,
+                              0x10))
+		    version = "Miranda IM (ICQ SSS & S7)(SecureIM)";
+      else if (MatchBuddyCaps(caps,
+                              capsize,
+                              ICQ_CAPABILITY_ICQJS7OxVER,
+                              0x10))
+        version = "Miranda IM (ICQ SSS & S7)";
+	  }
+  }
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_MIRANDAxVER,
+                                   0x08)))
+  {
+    unsigned mver0 = capID[0x8] & 0xff;
+    unsigned mver1 = capID[0x9] & 0xff;
+    unsigned mver2 = capID[0xA] & 0xff;
+    unsigned mver3 = capID[0xB] & 0xff;
+    unsigned iver0 = capID[0xC] & 0xff;
+    unsigned iver1 = capID[0xD] & 0xff;
+    unsigned iver2 = capID[0xE] & 0xff;
+    unsigned iver3 = capID[0xF] & 0xff;
+    version = "Miranda IM ";
+    if (MatchBuddyCaps(caps,
+                       capsize,
+                       ICQ_CAPABILITY_MIRMOBxVER,
+                       0x0d))
+      version += "Mobile ";
+    if (mver0 == 0x80)
+    {
+      if (mver2 == 0x00)
+      {
+        snprintf(tmpVer,
+                 sizeof(tmpVer) - 1,
+                 "0.%u alpha build #%u",
+                 mver1,
+                 mver3);
+      }
+      else
+      {
+        snprintf(tmpVer,
+                 sizeof(tmpVer),
+                 "0.%u.%u preview #%u",
+                 mver1,
+                 mver2,
+                 mver3);
+      }
+      version += string(tmpVer);
+    }
+    else
+    {
+      if (mver2 == 0x00)
+      {
+        snprintf(tmpVer,
+                 sizeof(tmpVer) - 1,
+                 "%u.%u",
+                 mver0,
+                 mver1);
+      }
+      else
+      {
+        snprintf(tmpVer,
+                 sizeof(tmpVer) - 1,
+                 "%u.%u.%u",
+                 mver0,
+                 mver1,
+                 mver2);
+      }
+      version += string(tmpVer);
+      if ((mver3 != 0x00) && (mver3 != 0x64))
+      {
+        snprintf(tmpVer,
+                 sizeof(tmpVer) - 1,
+                 " alpha build #%u",
+                 mver3);
+        version += string(tmpVer);
+      }
+    }
+    if ((nTimestamp == 0x7fffffff) ||
+        ((unsigned)((nInfoTimestamp >> 24) & 0xFF) == 0x80))
+      version == " Unicode";
+    version += " (ICQ ";
+    if (MatchBuddyCaps(caps,
+                       capsize,
+                       ICQ_CAPABILITY_ICQJS7OxVER,
+                       0x10) ||
+        MatchBuddyCaps(caps,
+                       capsize,
+                       ICQ_CAPABILITY_ICQJS7SxVER,
+                       0x10))
+      version += " S7 & SSS (old)";
+    else
+    {
+      switch (iver0)
+      {
+        case 0x81:
+          version += " BM";
+          break;
+        case 0x88:
+          version += " eternity (old)";
+        default:
+          break;
+      }
+    }
+    switch (iver2)
+    {
+      case 0x58:
+        version += " eternity/PlusPlus++ Mod";
+        break;
+      default:
+        break;
+    }
+    version += " ";
+    switch (iver0)
+    {
+      case 0x88:
+      case 0x81:
+      case 0x80:
+        snprintf(tmpVer,
+                 sizeof(tmpVer) - 1,
+                 "0.%u.%u.%u alpha)",
+                 iver1,
+                 iver2,
+                 iver3);
+        break;
+      default:
+        snprintf(tmpVer,
+                 sizeof(tmpVer) - 1,
+                 "%u.%u.%u.%u)",
+                 iver0,
+                 iver1,
+                 iver2,
+                 iver3);
+        break;
+    }
+    version += string(tmpVer);
+    if ((nInfoTimestamp == 0x5AFEC0DE) ||
+        MatchBuddyCaps(caps,
+                       capsize,
+                       ICQ_CAPABILITY_ICQJS7SxVER,
+                       0x10))
+      version += " (SecureIM)";
+  }
+  // TRILLIAN
+  else if ((MatchBuddyCaps(caps,
+                           capsize,
+                           ICQ_CAPABILITY_TRILLIANxVER,
+                           0x10)) ||
+           (MatchBuddyCaps(caps,
+                           capsize,
+                           ICQ_CAPABILITY_TRILCRPTxVER,
+                           0x10)))
+  {  
+    if (bRTF)
+    {
+      if (bSENDFILE)
+        version = "Trillian Astra";
+      else
+        version = "Trillian v3";
+    }
+    else
+      version = "Trillian";
+  }
+  // CLIMM
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_CLIMMxVER,
+                                   0x0C)))
+  {  
+    ver1 = capID[0xC];
+    ver2 = capID[0xD];
+    ver3 = capID[0xE];
+    ver4 = capID[0xF];
+
+    snprintf(tmpVer,
+             sizeof(tmpVer) - 1,
+             "%u.%u.%u.%u",
+             ver1,
+             ver2,
+             ver3,
+             ver4);
+    version = "climm " + string(tmpVer);
+		if ((ver1 & 0x80) == 0x80)
+		  version += " alpha";
+    if (nInfoTimestamp == 0x02000020)
+      version += "/Win32";
+    else if (nInfoTimestamp == 0x03000800)
+      version += "/MacOS X";
+  }		
+  // IM2
+  else if (MatchBuddyCaps(caps,
+                          capsize,
+                          ICQ_CAPABILITY_IM2xVER,
+                          0x10))
+  {  
+    version = "IM2";
+  }
+  // ANDRQ
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_ANDRQxVER,
+                                   0x09)))
+  {
+    ver1 = capID[0xC];
+    ver2 = capID[0xB];
+    ver3 = capID[0xA];
+    ver4 = capID[9];
+    snprintf(tmpVer,
+             sizeof(tmpVer) - 1,
+             "%u.%u.%u.%u",
+             ver1,
+             ver2,
+             ver3,
+             ver4);
+    version += "&RQ " + string(tmpVer);
+  }
+  // RANDQ
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_RANDQxVER,
+                                   0x09)))
+  {
+    ver1 = capID[0xC];
+    ver2 = capID[0xB];
+    ver3 = capID[0xA];
+    ver4 = capID[9];
+    snprintf(tmpVer,
+             sizeof(tmpVer) - 1,
+             "%u.%u.%u.%u",
+             ver1,
+             ver2,
+             ver3,
+             ver4);
+    version += "R&Q " + string(tmpVer);
+  }
+  // IMADERING
+  else if (MatchBuddyCaps(caps,
+                          capsize,
+                          ICQ_CAPABILITY_IMADERING,
+                          0x10))
+  {
+    version = "IMadering";
+  }
+  // QIPPDA
+  else if (MatchBuddyCaps(caps,
+                          capsize,
+                          ICQ_CAPABILITY_QIPPDAxVER,
+                          0x10))
+  {
+    version = "QIP PDA (Windows)";
+  }
+  // QIP MOBILE
+  else if (MatchBuddyCaps(caps,
+                          capsize,
+                          ICQ_CAPABILITY_QIPMOBxVER,
+                          0x10))
+  {
+    version = "QIP Mobile (Java)";
+  }
+  else if (MatchBuddyCaps(caps,
+                          capsize,
+                          ICQ_CAPABILITY_QIPSYMBxVER,
+                          0x10))
+  {
+    version = "QIP Mobile (Symbian)";
+  }
+  // QIP INFIUM
+  else if (MatchBuddyCaps(caps,
+                          capsize,
+                          ICQ_CAPABILITY_QIPINFxVER,
+                          0x10))
+  {
+    version = "QIP Infium";
+    if (nTimestamp)
+    {
+      snprintf(tmpVer, sizeof(tmpVer) - 1, " (Build %lu)", nTimestamp);
+      version += string(tmpVer);
+    }
+    if (nStatusTimestamp == 0x0000000B)
+      version += " Beta";
+  }
+  // QIP
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_QIPxVER,
+                                   0x0e)))
+  {
+    if (nInfoTimestamp == 0x0F)
+      strcpy(tmpVer, "2005");
+    else
+    {
+      strncpy(tmpVer, capID + 11, 5);
+      tmpVer[5] = '\0';
+    }
+    version = "QIP " + string(tmpVer);
+    if ((nStatusTimestamp == 0x0000000e) && (nInfoTimestamp == 0x0000000f))
+    {
+      snprintf(tmpVer,
+               sizeof(tmpVer) - 1,
+               " (Build %lu%lu%lu%lu)",
+               nTimestamp >> 0x18,
+               (nTimestamp >> 0x10) & 0xFF,
+               (nTimestamp >> 0x08) & 0xFF,
+               nTimestamp & 0xFF);
+      version += string(tmpVer);
+    }
+  }
+  // MCHAT
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_MCHATxVER,
+                                   0xA)))
+  {
+    strncpy(tmpVer, capID + 0xA, 6);
+    version = "mChat " + string(tmpVer);
+  }
+  // JIMM
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_JIMMxVER,
+                                   0x5)))
+  {
+    strncpy(tmpVer, capID + 0x5, 11);
+    version = "Jimm " + string(tmpVer);
+  }
+  // COREPAGER
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_COREPGRxVER,
+                                   0xA)))
+  {
+    version = "CORE Pager";
+    if ((nStatusTimestamp == 0x0FFFF0011) &&
+        (nInfoTimestamp == 0x1100FFFF) &&
+        (nTimestamp >> 0x18))
+    {
+      snprintf(tmpVer,
+               sizeof(tmpVer) - 1,
+               " %lu.%lu",
+               nTimestamp >> 0x18,
+               (nTimestamp >> 0x10) & 0xFF);
+      if ((nTimestamp & 0xFF) == 0x0B)
+        strcat(tmpVer, " Beta");
+      version += string(tmpVer);;
+    }
+  }
+  // DICHAT
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_DICHATxVER,
+                                   0x9)))
+  {
+    strncpy(tmpVer, capID + 8, 8);
+    version = "D[i]Chat" + string(tmpVer);
+  }
+  // MACICQ
+  else if (MatchBuddyCaps(caps,
+                          capsize,
+                          ICQ_CAPABILITY_MACICQxVER,
+                          0x10))
+  {
+    version = "ICQ for Mac";
+  }
+  // UIM
+  else if (MatchBuddyCaps(caps,
+                          capsize,
+                          ICQ_CAPABILITY_UIM,
+                          0x10))
+  {
+    version = "uIM";
+  }
+  // ANASTASIA
+  else if (MatchBuddyCaps(caps,
+                          capsize,
+                          ICQ_CAPABILITY_ANSTxVER,
+                          0x10))
+  {
+    version = "Anastasia";
+  }
+  // JICQ
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_PALMJICQ,
+                                   0xc)))
+  {
+    ver1 = capID[0xC];
+    ver2 = capID[0xD];
+    ver3 = capID[0xE];
+    ver4 = capID[0xF];
+    snprintf(tmpVer,
+             sizeof(tmpVer) - 1,
+             "%u.%u.%u.%u",
+             ver1,
+             ver2,
+             ver3,
+             ver4);
+    version = "JICQ " + string(tmpVer);
+  }
+  // INLUX MESSENGER
+  else if (MatchBuddyCaps(caps,
+                          capsize,
+                          ICQ_CAPABILITY_INLUXMSGR,
+                          0x10))
+  {
+    version = "Inlux Messenger";
+  }
+  // VMICQ
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_VMICQxVER,
+                                   0x5)))
+  {
+    strncpy(tmpVer, capID + 5, 11);                              
+    version = "VmICQ " + string(tmpVer);
+  }
+  // SMAPER
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_SMAPERxVER,
+                                   0x7)))
+  {
+    strncpy(tmpVer, capID + 6, 10);
+    version = "SmapeR " + string(tmpVer);
+  }
+  // MIP
+  else if ((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_MIPCLIENT,
+                                   0x4)))
+  {
+    strncpy(tmpVer, capID + 4, 12);
+    version = "MIP " + string(tmpVer);
+  }
+  // YAPP!
+  else if((capID = MatchBuddyCaps(caps,
+                                   capsize,
+                                   ICQ_CAPABILITY_YAPPxVER,
+                                   0x4)))
+  {
+    strncpy(tmpVer, capID + 8, 5);
+    version = "Yapp! v" + string(tmpVer);
+  }
+  // LIBICQ2000 VARIANTS
+  else if (version == "libicq2000")
+  {
+    if (bRTF)
+      version = "Centericq";
+    else if (bUTF8)
+      version += " (Unicode)";
+  }
+  // Trying to detect a client version using the protocol version.
+  // VERSION = 0
+  else if (tcpVersion == 0)
+  {
+    if (!nTimestamp &&
+        !nStatusTimestamp &&
+        !nInfoTimestamp &&
+        !(user->Port()) &&
+        !(user->Cookie()))
+    {
+      if ((MatchBuddyCaps(caps,
+                          capsize,
+                          ICQ_CAPABILITY_TYPING,
+                          0x10)) &&
+          (MatchBuddyCaps(caps,
+                          capsize,
+                          ICQ_CAPABILITY_IS2001,
+                          0x10)) &&
+          (MatchBuddyCaps(caps,
+                          capsize,
+                          ICQ_CAPABILITY_IS2002,
+                          0x10)) &&
+          (MatchBuddyCaps(caps,
+                          capsize,
+                          ICQ_CAPABILITY_COMM20012,
+                          0x10)))
+      {
+        version = "Spam Bot";
+      }
+      else if (bAIMICON)
+      {
+        if ((bDIRECT && bSENDFILE && bUTF8) ||
+            (bDIRECT && bAIMCHAT && bSENDFILE && (capsize == 0x40)))
+          version = "libgaim";
+        else if (bAIMCHAT && bUTF8 && (capsize == 0x30))
+          version = "Meebo";
+        if ((bUTF8 && (capsize == 0x20)) ||
+                 (MatchBuddyCaps(caps,
+                                 capsize,
+                                 ICQ_CAPABILITY_ICQLITExVER,
+                                 0x10)) &&
+                 (MatchBuddyCaps(caps,
+                                 capsize,
+                                 ICQ_CAPABILITY_XTRAZ,
+                                 0x10)))
+          version = "PyICQ-t Jabber Transport";
+      }
+      else if (bAIMCHAT && bSENDFILE && (capsize == 0x20))
+        version = "Easy Message";
+      else if (bUTF8 && bSRVRELAY && bDIRECT)
+      {
+        if (bTYPING && (capsize == 0x40))
+          version = "Agile Messenger";
+        else if (bSENDFILE && bGETFILE)
+          version = "Slick";
+      }
+      else if(bDIRECT && bRTF && bTYPING && bUTF8)
+        version = "GlICQ";
+    }
+  }
+  // VERSION = 7
+  else if (tcpVersion == 7)
+  {
+    if (bRTF)
+      version = "GnomeICU";
+    else if (bSRVRELAY)
+    {
+      if (!nTimestamp && !nStatusTimestamp && !nInfoTimestamp)
+        version = "&RQ";
+      else
+      {
+        version = "ICQ 2000";
+      }
+    }
+    else if (bUTF8)
+    {
+      if (bTYPING)
+        version = "Icq2Go! (Java)";
+      else
+        version = "Icq2Go! (Flash)";
+    }
+  }
+  // VERSION = 8
+  else if (tcpVersion == 8)
+  {
+    if ((MatchBuddyCaps(caps,
+                        capsize,
+                        ICQ_CAPABILITY_XTRAZ,
+                        0x10)) &&
+        (MatchBuddyCaps(caps,
+                        capsize,
+                        ICQ_CAPABILITY_IMSECKEY1,
+                        0x06)) &&
+        (MatchBuddyCaps(caps,
+                        capsize,
+                        ICQ_CAPABILITY_IMSECKEY2,
+                        0x06)))
+      tcpVersion = 9;
+    else if ((MatchBuddyCaps(caps,
+                             capsize,
+                             ICQ_CAPABILITY_COMM20012,
+                             0x10)) || (bSRVRELAY))
+    {
+      if (MatchBuddyCaps(caps,
+                         capsize,
+                         ICQ_CAPABILITY_IS2001,
+                         0x10))
+      {
+        if (!nTimestamp && !nStatusTimestamp && !nInfoTimestamp)
+			  {
+          if (bRTF)
+            version = "TICQClient"; // possibly also older GnomeICU
+          else
+            version = "ICQ for Pocket PC";
+			  }
+        else
+          version = "ICQ 2001";
+      }
+      else if (MatchBuddyCaps(caps,
+                         capsize,
+                         ICQ_CAPABILITY_IS2002,
+                         0x10))
+        version = "ICQ 2002";
+		  else if (bSRVRELAY && bUTF8 && bRTF &&
+		           (!MatchBuddyCaps(caps,
+                                capsize,
+                                ICQ_CAPABILITY_ICQJS7xVER,
+                                0x04)) &&
+               (!MatchBuddyCaps(caps,
+                                capsize,
+                                ICQ_CAPABILITY_ICQJSINxVER,
+                                0x04)))
+		           
+      {
+        if (!nTimestamp && !nStatusTimestamp && !nInfoTimestamp)
+        {
+          if (!user->Port())
+            version = "GnomeICU 0.99.5+";
+          else
+            version = "IC@";
+        }
+        else
+          version = "ICQ 2002/2003a";
+      }
+      else if (bSRVRELAY && bUTF8 && bTYPING)
+      {
+        if (!nTimestamp && !nStatusTimestamp && !nInfoTimestamp)
+          version = "PreludeICQ";
+      }
+    }
+  }
+  // VERSION = 9
+  else if (tcpVersion == 9)
+  {
+    if (MatchBuddyCaps(caps,
+                       capsize,
+                       ICQ_CAPABILITY_XTRAZ,
+                       0x10))
+    {
+      if (bSENDFILE)
+      {
+        if (MatchBuddyCaps(caps,
+                           capsize,
+                           ICQ_CAPABILITY_TZERS,
+                           0x10))
+        {
+          if (MatchBuddyCaps(caps,
+                             capsize,
+                             ICQ_CAPABILITY_HTMLMSGS,
+                             0x10))
+            version = "ICQ 6";
+          else
+            version = "ICQ 5.1";
+        }
+        else
+          version = "ICQ 5";
+        if (MatchBuddyCaps(caps,
+                           capsize,
+                           ICQ_CAPABILITY_RAMBLER,
+                           0x10))
+          version += " (Rambler)";
+        else if (MatchBuddyCaps(caps,
+                                capsize,
+                                ICQ_CAPABILITY_ABV,
+                                0x10))
+          version += " (Abv)";
+        else if (MatchBuddyCaps(caps,
+                                capsize,
+                                ICQ_CAPABILITY_NETVIGATOR,
+                                0x10))
+          version += " (Netvigator)";
+      }
+      else if (!bDIRECT)
+        if (bRTF)
+          version = "QNext";
+        else
+          version = "pyICQ";
+      else
+        version = "ICQ Lite v4";
+    }
+    else if (!bDIRECT && bUTF8 && !bRTF)
+      version = "pyICQ";
+  }
+  // VERSION = 10
+  else if (tcpVersion == 0xA)
+  {
+    if (!bRTF && !bUTF8)
+      version = "QNext";
+    else if (!bRTF &&
+             bUTF8 &&
+             !nTimestamp &&
+             !nStatusTimestamp &&
+             !nInfoTimestamp)
+      version = "NanoICQ";
+  }
+  
+  user->SetSupportsUTF8(bUTF8);
+  user->SetClientInfo(version.c_str());
+
+  return;
+}
+
+//--------MatchBuddyCaps---------------------------------------------------
+char *CICQDaemon::MatchBuddyCaps(char *buf, unsigned bufsize, const char *cap, unsigned short capsize)
+{
+  while (bufsize > 0)
+  {
+    if (!memcmp(buf, cap, capsize))
+    {
+      // the capability is found
+      return (char *)buf;
+    }
+    else
+    {
+      buf += 0x10;
+      bufsize -= 0x10;
+    }
+  }
+  // there is not such a capability.
+  return 0;
+}
+
 //--------ProcessBuddyFam--------------------------------------------------
 void CICQDaemon::ProcessBuddyFam(CBuffer &packet, unsigned short nSubtype)
 {
@@ -2618,20 +3734,6 @@ void CICQDaemon::ProcessBuddyFam(CBuffer &packet, unsigned short nSubtype)
         nNewStatus = ICQ_STATUS_ONLINE;
     }
 
-    // ICQ status
-    if (packet.getTLVLen(0x0006))
-      nNewStatus = packet.UnpackUnsignedLongTLV(0x0006);
-
-    if (packet.getTLVLen(0x000a) == 4) {
-      nUserIP = packet.UnpackUnsignedLongTLV(0x000a);
-      if (nUserIP) {
-        rev_e_long(nUserIP);
-        nUserIP = PacketIpToNetworkIp(nUserIP);
-      }
-    }
-    if( u->StatusOffline() || nUserIP )
-      u->SetIp(nUserIP);
-
     if (packet.getTLVLen(0x0002) == 4)
     {
       registeredTimestamp = packet.UnpackUnsignedLongTLV(0x0002);
@@ -2659,6 +3761,23 @@ void CICQDaemon::ProcessBuddyFam(CBuffer &packet, unsigned short nSubtype)
       u->SetRegisteredTime(registeredTimestamp);
     }
 
+    // ICQ status
+    if (packet.getTLVLen(0x0006))
+      nNewStatus = packet.UnpackUnsignedLongTLV(0x0006);
+
+    if (packet.getTLVLen(0x000a) == 4)
+    {
+      nUserIP = packet.UnpackUnsignedLongTLV(0x000a);
+      if (nUserIP)
+      {
+        rev_e_long(nUserIP);
+        nUserIP = PacketIpToNetworkIp(nUserIP);
+      }
+    }
+    if (u->StatusOffline() || nUserIP)
+      u->SetIp(nUserIP);
+
+    // Direct connection info
     if (packet.getTLVLen(0x000c) == 0x25)
     {
       CBuffer msg = packet.UnpackTLV(0x000c);
@@ -2682,52 +3801,10 @@ void CICQDaemon::ProcessBuddyFam(CBuffer &packet, unsigned short nSubtype)
         
       junk2 = msg.UnpackUnsignedShortBE();
 
-      char szExtraInfo[28] = { 0 };
-      if ((nInfoTimestamp & 0xFFFF0000) == LICQ_WITHSSL)
-        snprintf(szExtraInfo, 27, "Licq %s/SSL",
-                 CUserEvent::LicqVersionToString(nInfoTimestamp & 0xFFFF));
-      else if ((nInfoTimestamp & 0xFFFF0000) == LICQ_WITHOUTSSL)
-        snprintf(szExtraInfo, 27, "Licq %s",
-                 CUserEvent::LicqVersionToString(nInfoTimestamp & 0xFFFF));
-      else if (nInfoTimestamp == 0xffffffff)
-        strcpy(szExtraInfo, "MIRANDA");
-      else if (nInfoTimestamp == 0xFFFFFF8F)
-        strcpy(szExtraInfo, "StrICQ");
-      else if (nInfoTimestamp == 0xFFFFFF42)
-        strcpy(szExtraInfo, "mICQ");
-      else if (nInfoTimestamp == 0xFFFFFF7F)
-        strcpy(szExtraInfo, "&RQ");
-      else if (nInfoTimestamp == 0xFFFFFFAB)
-        strcpy(szExtraInfo, "YSM");
-      else
-        szExtraInfo[0]=0;
-      szExtraInfo[27] = '\0';
-
-      u->SetClientInfo(szExtraInfo[0] ? szExtraInfo : NULL);
+      u->SetClientTimestamp(nInfoTimestamp);
+      u->SetClientStatusTimestamp(nStatusPluginTimestamp);
+      u->SetClientInfoTimestamp(nInfoPluginTimestamp);
       u->SetVersion(tcpVersion);
-      
-      if (nOldStatus != nNewStatus)
-      {
-        char *szClient = new char[strlen(szExtraInfo)+6];
-        if (szExtraInfo[0])
-          sprintf(szClient, " [%s].\n", szExtraInfo);
-        else
-          sprintf(szClient, ".\n");
-
-        ChangeUserStatus(u, nNewStatus);
-        gLog.Info(tr("%s%s (%s) changed status: %s (v%d)%s"),
-                   L_SRVxSTR, u->GetAlias(), u->IdString(), u->StatusStr(),
-                   tcpVersion & 0x0F, szClient);
-        if ( (nNewStatus & ICQ_STATUS_FxUNKNOWNxFLAGS) )
-          gLog.Unknown("%sUnknown status flag for %s (%s): 0x%08lX\n",
-                       L_UNKNOWNxSTR, u->GetAlias(), u->IdString(),
-                       (nNewStatus & ICQ_STATUS_FxUNKNOWNxFLAGS));
-        nNewStatus &= ICQ_STATUS_FxUNKNOWNxFLAGS;
-        u->SetAutoResponse(NULL);
-        u->SetShowAwayMsg(false);
-
-        delete [] szClient;
-      }
 
       if (intIP)
       {
@@ -2783,70 +3860,39 @@ void CICQDaemon::ProcessBuddyFam(CBuffer &packet, unsigned short nSubtype)
       u->SetICQphoneStatus(ICQ_PLUGIN_STATUSxINACTIVE);
       u->SetSharedFilesStatus(ICQ_PLUGIN_STATUSxINACTIVE);
     }
-    
+
+    // Capabilities
     if (packet.hasTLV(0x000D))
     {
       CBuffer capBuf = packet.UnpackTLV(0x000D);
-      int nCapSize = packet.getTLVLen(0x000D);
-      char *caps = new char[nCapSize];    
+      unsigned short nCapSize = packet.getTLVLen(0x000D);
+      boost::scoped_array<char> caps(new char[nCapSize]);
       for (unsigned short i = 0; i < nCapSize; i++)
         capBuf >> caps[i];
-
-      // Check if they support UTF8
-      bool bUTF8 = false;
-
-      // Check capability flags for their client version
-      string version = "";
-      char tmpVer[24];
-      unsigned int ver1, ver2, ver3;
-
-      for (int i = 0; i < (nCapSize / CAP_LENGTH); i++)
-      {
-        if (memcmp(caps+(i * CAP_LENGTH), ICQ_CAPABILITY_UTF8, CAP_LENGTH) == 0)
-        {
-          bUTF8 = true;
-        }
-        else if (memcmp(caps+(i * CAP_LENGTH), ICQ_CAPABILITY_LICQxVER,
-                 strlen(ICQ_CAPABILITY_LICQxVER)) == 0)
-        {
-          char *verStr = caps+((i+1)*CAP_LENGTH-4);
-          ver1 = verStr[0];
-          ver2 = verStr[1]%100;
-          ver3 = verStr[2];
-          snprintf(tmpVer, sizeof(tmpVer)-1, "%u.%u.%u", ver1, ver2, ver3);
-          version = "Licq v" + string(tmpVer);
-          if (verStr[3] == 1)
-            version += "/SSL";
-        }
-        else if (memcmp(caps+(i * CAP_LENGTH), ICQ_CAPABILITY_KOPETExVER,
-                 strlen(ICQ_CAPABILITY_KOPETExVER)) == 0)
-        {
-          char *verStr = caps+((i+1)*CAP_LENGTH-4);
-          ver1 = verStr[0];
-          ver2 = verStr[1];
-          ver3 = verStr[2]*100;
-          ver3 += verStr[3];
-          snprintf(tmpVer, sizeof(tmpVer)-1, "%u.%u.%u", ver1, ver2, ver3);
-          version = "Kopete v" + string(tmpVer);
-        }
-        else if (memcmp(caps+(i * CAP_LENGTH), ICQ_CAPABILITY_SIMxVER,
-                 strlen(ICQ_CAPABILITY_SIMxVER)) == 0)
-        {
-          version = "SIM";
-        }
-        else if (memcmp(caps+(i * CAP_LENGTH), ICQ_CAPABILITY_MICQxVER,
-                 strlen(ICQ_CAPABILITY_MICQxVER)) == 0)
-        {
-          version = "mICQ";
-        }
-      }  
-      delete [] caps;
-
-      if (u)
+        
+      ProcessBuddyCaps(u, caps.get(), nCapSize);
+ 
+      if (nOldStatus != nNewStatus)
       {
-        u->SetSupportsUTF8(bUTF8);
-        if (version != "")
-          u->SetClientInfo(version.c_str());
+        string version = (!strcmp(u->ClientInfo(), "")) ?
+                         "Unknown" : u->ClientInfo();
+        ChangeUserStatus(u, nNewStatus);
+        gLog.Info(tr("%s%s (%s) changed status: %s (v%d) [%s].\n"),
+                  L_SRVxSTR,
+                  u->GetAlias(),
+                  u->IdString(),
+                  u->StatusStr(),
+                  (int)(u->Version() & 0x0F),
+                  version.c_str());
+        if ( (nNewStatus & ICQ_STATUS_FxUNKNOWNxFLAGS) )
+          gLog.Unknown("%sUnknown status flag for %s (%s): 0x%08lX\n",
+                       L_UNKNOWNxSTR,
+                       u->GetAlias(),
+                       u->IdString(),
+                       (nNewStatus & ICQ_STATUS_FxUNKNOWNxFLAGS));
+        nNewStatus &= ICQ_STATUS_FxUNKNOWNxFLAGS;
+        u->SetAutoResponse(NULL);
+        u->SetShowAwayMsg(false);
       }
     }
     
@@ -2941,6 +3987,30 @@ void CICQDaemon::ProcessBuddyFam(CBuffer &packet, unsigned short nSubtype)
       }
     }
 
+    // Short capabilities
+    if (packet.hasTLV(0x0019))
+    {
+      CBuffer capBuf = packet.UnpackTLV(0x0019);
+      unsigned short nCapSize = packet.getTLVLen(0x0019);
+      char cap[2];
+      unsigned short shortCaps = 0;
+
+      for (unsigned short i = 0; i < nCapSize; i += 2)
+      {
+        capBuf >> cap[0];
+        capBuf >> cap[1];
+        for (unsigned short j = 0; j < SHORT_CAPS_COUNT; ++j)
+        {
+          if(!memcmp(&ShortCaps[2 * j], cap, 2))
+          {
+            shortCaps |= 1 << j;
+            break;
+          }
+        }
+      }
+      u->SetShortCaps(shortCaps);
+    }
+
     if (packet.hasTLV(0x001d))	// Server-stored buddy icon information
     {
       CBuffer BART_info = packet.UnpackTLV(0x001d);
signature.asc (application/pgp-signature, 197 B)
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2.0.9 (GNU/Linux)

iEYEABECAAYFAkgvgw4ACgkQld1KayKQpx9z2gCfVOeZbx4L/UMyPiRYZE9r74eN
d3sAoJ4gCsfKIv1/GVM9oBAJxiJdAEsO
=z7pQ
-----END PGP SIGNATURE-----