On Tuesday 23 April 2002 11:52, Pletyak Attila wrote: <snip> > As I've a quite big contact list what I do not want to add again > one-by-one (or with editing the users.conf file), I would like to ask > whether the server side list storage will be implemented in the near > future.
I am attaching an "embryonic" patch that add support to the server side list retrival. Why? because i won't have any spare time in the nexts days or week and may be someone want to play with it or import his/her list. I am planing finishing the patch and add the full support of the server side list (add,remove, store groups, ...) if nobody finish it before or if licq developers complain. if you want to add something in the meanwhile just do it :) So...This patch gets the list from server and prints it to the standar error fd. nothing else. if you want to disable it just comment line 1024 in srv/icqd-srv.cpp...and yes..that line will be moved to other place i guess. It's not a patch for dayly use.... Also, i think that is a good time to start the discussion of how the server side list storage (ssld) feature will be integrated to the rest of the licq. i added another file to the src/ directory: fam_lists.cpp that handle the packets of the lists snac family. i did this because i think that icqd-srv.cpp is too crowded. It would be nice that some one test it with a big list: i just used lite.icq.com and added only 3 contacts, and i didn't recive all the range of features of the list. How to patch? cd cvs -z3 -d:pserver:[EMAIL PROTECTED]:/cvsroot/licq co licq cd licq patch -p0 < ../slists_1.diff cp ../fam_lists.cpp src ... (remember to recomplile qt) This is an example of what i am getting. (set DEBUG level to all if you want to see the packet)(where X is a number of the uin and x is a letter of the nickname) --------0------- Group ID: 23550 Group ID: 19426 Group ID: 25661 Group ID: 27527 --------1------- Visibily setting: Block only users in the invisible list from seeing us --------2------- ICQTIC (do you know the meaning?) TAG = 0 ID = 2892 NP = 1 TLV = 3610,0,0,0 --------3------- Group: GID: 19426 G#: 512 Name: Family --------4------- UIN: XXXXXXX NAME: 'Juam' ID: 2 GROUPID 19426 (Normal) --------5------- Group: GID: 23550 G#: 20272 Name: General --------6------- UIN: XXXXXXX NAME: 'xxxx' ID: 12367 GROUPID 23550 (Normal) --------7------- Group: GID: 25661 G#: 768 Name: Friends --------8------- UIN: XXXXXXXXX NAME: 'xxxxxxxx' ID: 3 GROUPID 25661 (Normal)(Waiting auth) --------9------- Group: GID: 27527 G#: 28483 Name: Co-Workers time_t = Wed Apr 24 07:19:27 2002 Now parse this to get a new user.conf is trivial :) Hell...this email got big :) Well.- i am waiting a reply. Regards, Juan. -- Buenos Aires, Argentina
Index: include/licq_buffer.h =================================================================== RCS file: /cvsroot/licq/licq/include/licq_buffer.h,v retrieving revision 1.5 diff -u -1 -b -p -r1.5 licq_buffer.h --- include/licq_buffer.h 23 Jan 2002 07:04:11 -0000 1.5 +++ include/licq_buffer.h 25 Apr 2002 00:09:02 -0000 @@ -25,2 +25,7 @@ extern unsigned long NetworkIpToPacketIp + +/* little indian 2 big endian shorts + */ +extern unsigned short get_be_short(char *p); + extern void rev_e_short(unsigned short &); @@ -89,2 +94,3 @@ public: char *UnpackStringBE(char *); + char *UnpackStringBE(); unsigned long UnpackUnsignedLong(); Index: include/licq_icq.h =================================================================== RCS file: /cvsroot/licq/licq/include/licq_icq.h,v retrieving revision 1.21 diff -u -1 -b -p -r1.21 licq_icq.h --- include/licq_icq.h 8 Apr 2002 16:09:14 -0000 1.21 +++ include/licq_icq.h 25 Apr 2002 00:09:02 -0000 @@ -82,2 +82,18 @@ const unsigned short ICQ_SNACxBOS_REMxIN +// Subtypes for Lists family +// from Massimo Melina protocol notes (www.rejetto.com/icq) +// and stricq (www.stricq.com/icqv8/Command_view.cfm) +const unsigned short ICQ_SNACxLISTS_REQUESTxRIGHTS = 0x0002; // client +const unsigned short ICQ_SNACxLISTS_RIGHTSxGRANTED = 0x0003; // server +const unsigned short ICQ_SNACxLISTS_REQUESTxROSTER2 = 0x0004; // server +const unsigned short ICQ_SNACxLISTS_REQUESTxROSTER = 0x0005; // client +const unsigned short ICQ_SNACxLISTS_ROSTERxREPLY = 0x0006; // server +const unsigned short ICQ_SNACxLISTS_ROSTERxACK = 0x0007; // client +const unsigned short ICQ_SNACxLISTS_ADDxVISIBLExLIST= 0x0008; // client +const unsigned short ICQ_SNACxLISTS_UPDATExGROUP = 0x0009; // client +const unsigned short ICQ_SNACxLISTS_REMOVExVISIBLExLIST=0x000A; // client +const unsigned short ICQ_SNACxLISTS_REMOVEXACK = 0x000E; // server +const unsigned short ICQ_SNACxLISTS_AUTHxREQUEST2 = 0x0014; // client +const unsigned short ICQ_SNACxLISTS_AUTHxREQUEST = 0x0018; // client + // Subtypes for various family Index: include/licq_icqd.h =================================================================== RCS file: /cvsroot/licq/licq/include/licq_icqd.h,v retrieving revision 1.27 diff -u -1 -b -p -r1.27 licq_icqd.h --- include/licq_icqd.h 16 Apr 2002 13:33:01 -0000 1.27 +++ include/licq_icqd.h 25 Apr 2002 00:09:03 -0000 @@ -382,2 +382,3 @@ protected: void ProcessBOSFam(CBuffer&, unsigned short); + void ProcessListsFam( CBuffer &, unsigned short); void ProcessNewUINFam(CBuffer &, unsigned short); Index: include/licq_packets.h =================================================================== RCS file: /cvsroot/licq/licq/include/licq_packets.h,v retrieving revision 1.23 diff -u -1 -b -p -r1.23 licq_packets.h --- include/licq_packets.h 16 Apr 2002 13:34:37 -0000 1.23 +++ include/licq_packets.h 25 Apr 2002 00:09:03 -0000 @@ -263,3 +263,11 @@ public: }; - +//-----RequesterverList------------------------------------------------------ +class CPU_RequestServerList : public CPU_GenericFamily +{ + public: + CPU_RequestServerList( time_t saved_time, unsigned short nrecords); + protected: + time_t saved_time; + unsigned short nrcords; +}; //-----SetStatus---------------------------------------------------------------- @@ -714,3 +722,2 @@ protected: }; - Index: include/licq_user.h =================================================================== RCS file: /cvsroot/licq/licq/include/licq_user.h,v retrieving revision 1.23 diff -u -1 -b -p -r1.23 licq_user.h --- include/licq_user.h 20 Mar 2002 06:35:46 -0000 1.23 +++ include/licq_user.h 25 Apr 2002 00:09:03 -0000 @@ -214,2 +214,3 @@ public: // Licq Info + unsigned short GetSID() { return m_nSID; } char *AutoResponse() { return m_szAutoResponse; } @@ -248,2 +249,4 @@ public: + + // General Info @@ -296,2 +299,3 @@ public: // Licq Info + void SetSID(unsigned short id) { m_nSID = id; } void SetEnableSave(bool s) { if (m_bOnContactList) m_bEnableSave = s; } @@ -447,2 +451,3 @@ protected: m_nGroups[2]; + unsigned short sid; char m_nMode; @@ -506,2 +511,5 @@ protected: + // server side id + unsigned short m_nSID; + UserEventList m_vcMessages; @@ -541,2 +549,8 @@ public: + // Server side functions + time_t GetSSCheck() { return m_nSStime; } + void SetSSCheck( time_t t) { m_nSStime = t ;} + unsigned short GetSSCount() { return m_nSScount; } + void SetSSCount(unsigned short c) { m_nSScount = c;} + // Virtual overloaded functions @@ -552,2 +566,4 @@ protected: unsigned long m_nRandomChatGroup; + time_t m_nSStime; + unsigned short m_nSScount; }; Index: src/Makefile.am =================================================================== RCS file: /cvsroot/licq/licq/src/Makefile.am,v retrieving revision 1.15 diff -u -1 -b -p -r1.15 Makefile.am --- src/Makefile.am 17 Mar 2002 05:47:55 -0000 1.15 +++ src/Makefile.am 25 Apr 2002 00:09:04 -0000 @@ -17,3 +17,3 @@ licq_SOURCES = licq.cpp main.cpp \ icqd-chat.cpp sighandler.c icqd-filetransfer.cpp \ - hebrev.c icqcolor.cpp + hebrev.c icqcolor.cpp fam_lists.cpp Index: src/buffer.cpp =================================================================== RCS file: /cvsroot/licq/licq/src/buffer.cpp,v retrieving revision 1.11 diff -u -1 -b -p -r1.11 buffer.cpp --- src/buffer.cpp 20 Mar 2002 16:00:53 -0000 1.11 +++ src/buffer.cpp 25 Apr 2002 00:09:04 -0000 @@ -301,2 +301,15 @@ CBuffer& CBuffer::operator>>(unsigned lo +char *CBuffer::UnpackStringBE() +{ + unsigned short nLen; + *this >> nLen; + nLen = get_be_short( (char *) &nLen ); + char* sz = new char[nLen+1]; + sz[0] = '\0'; + for (unsigned short i = 0; i < nLen; i++) *this >> sz[i]; + sz[nLen] = '\0'; + + return sz; +} + char *CBuffer::UnpackStringBE(char* sz) Index: src/icqd-srv.cpp =================================================================== RCS file: /cvsroot/licq/licq/src/icqd-srv.cpp,v retrieving revision 1.30 diff -u -1 -b -p -r1.30 icqd-srv.cpp --- src/icqd-srv.cpp 16 Apr 2002 13:37:36 -0000 1.30 +++ src/icqd-srv.cpp 25 Apr 2002 00:09:05 -0000 @@ -1014,2 +1014,16 @@ void CICQDaemon::ProcessServiceFam(CBuff + // SS List. + ICQOwner *o = gUserManager.FetchOwner(LOCK_R); + gLog.Info("%sRequesting %s Server Contact List rights.\n",L_SRVxSTR, + (o->GetSSCheck() && o->GetSSCount()) ? "Partial":"Complete"); + + /* if( o->GetSSCheck() && o->GetSSCount() ) + * p = new CPU_RequestServerList( o->GetSSCheck(),o->GetSSCount()); + *else + */ + p = new CPU_GenericFamily(ICQ_SNACxFAM_LISTS, + ICQ_SNACxLISTS_REQUESTxRIGHTS); + gUserManager.DropOwner(); + SendEvent_Server(p); + gLog.Info("%sRequesting Instant Messaging rights.\n", L_SRVxSTR); @@ -1022,2 +1036,3 @@ void CICQDaemon::ProcessServiceFam(CBuff + break; @@ -2599,2 +2614,6 @@ void CICQDaemon::ProcessDataChannel(CBuf ProcessMessageFam(packet, nSubtype); + break; + + case ICQ_SNACxFAM_LISTS: + ProcessListsFam(packet, nSubtype); break; Index: src/icqpacket.cpp =================================================================== RCS file: /cvsroot/licq/licq/src/icqpacket.cpp,v retrieving revision 1.37 diff -u -1 -b -p -r1.37 icqpacket.cpp --- src/icqpacket.cpp 16 Apr 2002 13:38:33 -0000 1.37 +++ src/icqpacket.cpp 25 Apr 2002 00:09:06 -0000 @@ -900,2 +900,13 @@ CPU_GenericUinList::CPU_GenericUinList(u +//----RequestServerList------------------------------------------------------- +CPU_RequestServerList::CPU_RequestServerList( time_t saved_time, + unsigned short nrecords) + : CPU_GenericFamily(ICQ_SNACxFAM_LISTS,ICQ_SNACxLISTS_REQUESTxROSTER) +{ + printf("%x\n",nrecords); + m_nSize += 4 + 2; + buffer->PackUnsignedLongBE(saved_time); + buffer->PackUnsignedShortBE(nrecords); +} + CPU_GenericFamily::CPU_GenericFamily(unsigned short Family, unsigned short SubType) Index: src/user.cpp =================================================================== RCS file: /cvsroot/licq/licq/src/user.cpp,v retrieving revision 1.36 diff -u -1 -b -p -r1.36 user.cpp --- src/user.cpp 19 Mar 2002 06:54:24 -0000 1.36 +++ src/user.cpp 25 Apr 2002 00:09:07 -0000 @@ -906,2 +906,3 @@ void ICQUser::LoadLicqInfo() SetHistoryFile(szTemp); + m_fConf.ReadNum("SID",m_nSID,0); @@ -1112,2 +1113,3 @@ void ICQUser::Init(unsigned long _nUin) m_bConnectionInProgress = false; + m_nSID = 0; @@ -1876,2 +1878,3 @@ void ICQUser::SaveLicqInfo() m_fConf.WriteStr("UserEncoding", m_szEncoding); + m_fConf.WriteNum("SID",m_nSID); @@ -2149,2 +2152,4 @@ ICQOwner::ICQOwner() m_fConf.ReadStr("AutoResponse", szTemp, ""); + m_fConf.ReadNum("SSTime", (unsigned long)m_nSStime, 0L); + m_fConf.ReadNum("SSCount",m_nSScount, 0); SetAutoResponse(szTemp); @@ -2225,2 +2230,4 @@ void ICQOwner::SaveLicqInfo() m_fConf.WriteNum("RCG", RandomChatGroup()); + m_fConf.WriteNum("SSTime", (unsigned long)m_nSStime); + m_fConf.WriteNum("SSCount",m_nSScount);
/* * LISTS snac family chain processing. * (server side contact list managment) * * Originaly by Juan F. Codagnone <[EMAIL PROTECTED]> * * Information taken from: * o from Massimo Melina protocol notes (www.rejetto.com/icq) * o Stricq (www.stricq.com/icqv8/Command_view.cfm) */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* *#include <stdio.h> *#include <string.h> *#include <sys/types.h> *#include <unistd.h> *#include <errno.h> */ #include "time-fix.h" #include "licq_icqd.h" #include "licq_translate.h" #include "licq_packets.h" #include "licq_socket.h" #include "licq_user.h" #include "licq_events.h" #include "licq_log.h" #include "support.h" #include "licq_message.h" //--------ProcessListsFam------------------------------------------------------ enum roster_type { RRHT_CNORMA = 0x0000, // a normal contact list entry RRHT_LGROUP = 0x0001, // larger grouping header RRHT_CINVIS = 0x0003, // a contact on the Invisible List RRHT_VISIBS = 0x0004, // visibility setting. TLV(00CA) RRHT_CIGNOR = 0x000E, // a contact on the Ignore List RRHT_ICQTIC = 0x0009, // i don't know what the hell this represent RRHT_IMPORT = 0x0013, // TLV contains the time(NULL) 'Import Time' }; const unsigned short MAX_TLV = 4; struct roster { // names the group, either a contact UIN or a larger grouping title // based upon the TAG value. char *name; // tag or marker associating different groups together into a larger //group such as the Ignore List or 'General' contact list group, etc. unsigned short tag; // random number generated when the user is added to the contact list, // or when the user is ignored unsigned short id; enum roster_type type; // number of TLVs unsigned short nparam; // array of TLVs SOscarTLV param[MAX_TLV]; }; /* extract a roster struct from the `packet' */ static struct roster * roster_body_extract( CBuffer &packet, struct roster *r) { unsigned short i,j,k=0,bytelen; assert( r ); r->name = packet.UnpackStringBE(); r->tag = packet.UnpackUnsignedShortBE(); r->id = packet.UnpackUnsignedShortBE(); r->type = (enum roster_type)packet.UnpackUnsignedShortBE(); bytelen = packet.UnpackUnsignedShortBE(); if( bytelen ) { // several TLVs. usually 1 for( k=i=0 ; i<bytelen && k<MAX_TLV ; i+=4,k++ ) { r->param[k].nType = packet.UnpackUnsignedShortBE(); r->param[k].nLen = packet.UnpackUnsignedShortBE(); // nLen + 1 so in the strings we can add the NIL r->param[k].pData=new unsigned char[r->param[k].nLen+1]; for( j = 0; i<r->param[k].nLen && i<bytelen;j++,i++ ) r->param[k].pData[j] = (unsigned char)packet.UnpackChar(); r->param[k].pData[j] = '\0'; } /* opps we ran out of space. should never happend (MAX_TLV) * should be big enougth...we eat the rests of the bytes */ if( k == MAX_TLV ) { for( ;i<bytelen;i++ ) packet.UnpackChar(); cerr << "Opps. increment MAX_TLV \n"; } } r->nparam = k; return r; } /* Free's roster_body_extract() data */ static void roster_body_free( struct roster *r ) { unsigned short i; assert(r); for( i=0 ; i<r->nparam ; i++ ) delete r->param[i].pData; } static bool roster_body_contact( const struct roster *r ) { char *t; if( r->nparam == 0 || r->param[0].nType != 0x0131) { cerr << "RRHT_NORMAL invalid\n"; return false; } switch( r->type ) { case RRHT_CINVIS: t = " (Invisible)"; break; case RRHT_CIGNOR: t = " (Ignore)"; break; case RRHT_CNORMA: t = " (Normal)"; break; default: t = " (!!!!!)"; } cerr << " UIN: " << r->name << " NAME: '" << r->param[0].pData << "'" << " ID: " << r->id << " GROUPID "<< r->tag << t << ( (r->nparam>1 && r->param[1].nType==0x0066) ? "(Waiting auth)": " ") <<"\n"; return true; } static bool roster_body_lgroup( const struct roster *r ) { unsigned short *id,i,gid; const char *gname ; // if there is a TLV should be C8 if( r->nparam!= 0 && r->param[0].nType != 0x00C8 ) { cerr << " Invalid TLV in lgroup\n"; return false; } if( r->name[0] == '\0' ) { // no name means that we have a TLV(C8) with groups ids if( r->nparam != 0 ) { for( i = 0; i<r->param[0].nLen; i+=2 ) { id = (unsigned short *)(r->param[0].pData + i); cerr << "Group ID: "<< get_be_short((char *)id) <<"\n"; } } } else { // normal group: Eg: name=="Family" TLV(C8)=00 02 if( r->name[0] == '\0' ) gname = "Unamed"; else gname = r->name; gid = *( (unsigned short *)(r->param[0].pData) ); cerr << "Group:" << " GID: "<< r->tag << " G#: " << gid << " Name: " << gname << "\n"; } return true; } static bool roster_body_vsettings( const struct roster *r ) { unsigned short i; for( i = 0; i<r->param[0].nLen ; i++ ) { cerr << "Visibily setting: "; switch( r->param[0].pData[i] ) { case 0x0001: cerr <<"Allow all users to see us\n"; break; case 0x0002: cerr <<"Block all users from seeing us\n"; break; case 0x0003: cerr <<"Allow only users in the permit list" " to see us\n"; break; case 0x0004: cerr <<"Block only users in the " "invisible list from seeing us\n"; break; case 0x0005: cerr <<"Allow only users in the buddy" " list to see you\n"; break; default: cerr << "Unknow\n"; } } return true; } static bool roster_body_importtime( const struct roster *r ) { if( r->param[0].nType != 0x00d4 ) { cerr << "bad TLV (should be d4)\n"; return false; } if( r->name[0] ) cerr << r->name[0]<<" "<< *((unsigned long *)r->param[0].pData); return true; } static bool roster_body_icqtic( const struct roster *r) { cerr << "ICQTIC (do you know the meaning?)\n" << "TAG = "<< r->tag << "\n" << "ID = "<< r->id << "\n" << "NP = "<< r->nparam << "\n" << "TLV = "<< r->param[0].pData << "\n"; return true; } static bool roster_body_default( const struct roster *r ) { unsigned short i; cerr << "Unknown roster\n" << " name " << r->name << "\n" << " tag " << r->tag << "\n" << " id " << r->id << "\n" << "type " << r->type << "\n" << " len " << r->nparam << "\n"; for( i=0; i<r->nparam ; i++ ) { cerr << " TLV(" << r->param[i].nType <<") " << "Len: "<< r->param[i].nLen << "\n"; } return true; } void CICQDaemon::ProcessListsFam( CBuffer &packet, unsigned short nSubtype) { CSrvPacketTcp *p; unsigned short flags; unsigned long ref; flags = packet.UnpackUnsignedShortBE(); ref = packet.UnpackUnsignedLong(); switch( nSubtype ) { case ICQ_SNACxLISTS_RIGHTSxGRANTED: { gLog.Info("%sServer granted us the Server Contact List\n", L_SRVxSTR); gLog.Info("%sRequesting saved contact List\n",L_SRVxSTR); // TODO: save the time_t of the last saved and ask for // TODO: new contacs insted of only requesting all. CSrvPacketTcp* p = new CPU_GenericFamily(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_REQUESTxROSTER2); SendEvent_Server(p); break; } case ICQ_SNACxLISTS_ROSTERxREPLY: { struct roster r; unsigned short count,i; unsigned long stime; gLog.Info("%sServer sent us the contact list\n",L_SRVxSTR); packet.UnpackChar(); // unknow count = packet.UnpackUnsignedShortBE(); for( i=0; i<count ; i++) { cerr << "--------" << i << "-------\n"; roster_body_extract(packet,&r); // process switch (r.type) { case RRHT_CIGNOR: case RRHT_CINVIS: case RRHT_CNORMA: roster_body_contact(&r); break; case RRHT_LGROUP: roster_body_lgroup(&r); break; case RRHT_VISIBS: roster_body_vsettings(&r); break; case RRHT_IMPORT: roster_body_importtime(&r); break; case RRHT_ICQTIC: roster_body_icqtic(&r); break; default: roster_body_default(&r); break; } roster_body_free(&r); } stime = packet.UnpackUnsignedLongBE(); cerr << "time_t = " << ctime((time_t *)&stime); ICQOwner *o = gUserManager.FetchOwner(LOCK_W); o->SetSSCheck( stime ); o->SetSSCount( count ); gUserManager.DropOwner(); // Send ack p = new CPU_GenericFamily(ICQ_SNACxFAM_LISTS, ICQ_SNACxLISTS_ROSTERxACK); SendEvent_Server(p); break; } case ICQ_SNACxLISTS_REMOVEXACK: // not yet default: { char *buf; gLog.Unknown("%sUnknow List UIN Family Subtype: %04hx\n%s\n", L_UNKNOWNxSTR,nSubtype, packet.print(buf)); delete [] buf; } } return; }