File ssbi-licq2.patch of Package Licq
diff -urN licq/include/licq_buffer.h licq-ssbi/include/licq_buffer.h
--- licq/include/licq_buffer.h 2006-08-10 21:17:07.000000000 +0300
+++ licq-ssbi/include/licq_buffer.h 2008-01-22 01:11:26.000000000 +0200
@@ -85,6 +85,7 @@
CBuffer& operator >> (unsigned short &in);
CBuffer& operator >> (unsigned long &in);
char *UnpackRaw(char *, unsigned short);
+ char *UnpackBinBlock(char *, unsigned short);
char *UnpackString(char *, unsigned short);
char *UnpackString(); // Need to delete[] returned string
char *UnpackStringBE(char *, unsigned short);
diff -urN licq/include/licq_events.h licq-ssbi/include/licq_events.h
--- licq/include/licq_events.h 2006-11-11 21:24:51.000000000 +0200
+++ licq-ssbi/include/licq_events.h 2008-01-22 01:11:26.000000000 +0200
@@ -249,6 +249,12 @@
// Daemon only
unsigned short SubType() { return m_nSubType; }
unsigned short ExtraInfo() { return m_nExtraInfo; }
+ void SetSubType(unsigned short nSubType) { m_nSubType = nSubType; }
+ bool NoAck() { return m_NoAck; }
+ void SetNoAck(bool NoAck) { m_NoAck = NoAck; }
+ bool IsCancelled() { return m_bCancelled; }
+
+ void AttachPacket(CPacket *p);
// Compare this event to another one
bool CompareEvent(int, unsigned short) const;
@@ -290,9 +296,11 @@
static unsigned long s_nNextEventId;
friend class CICQDaemon;
+friend class COscarService;
friend class CMSN;
friend void *ProcessRunningEvent_Client_tep(void *p);
friend void *ProcessRunningEvent_Server_tep(void *p);
+friend void *OscarServiceSendQueue_tep(void *p);
friend void *MonitorSockets_tep(void *p);
};
@@ -476,6 +484,8 @@
PROTOxREQUESTxINFO,
//! The user has requested to update the owner's profile/information.
PROTOxUPDATExINFO,
+ //! The user has requested the user's picture/icon/avatar/etc..
+ PROTOxREQUESTxPICTURE,
//! The user has requested this user be added to the Invisible/Block list.
PROTOxBLOCKxUSER,
//! The user has requested this user be removed from the Invisible/Block
@@ -684,6 +694,13 @@
*m_szZipCode;
};
+class CRequestPicture : public CSignal
+{
+public:
+ CRequestPicture(const char *);
+ virtual ~CRequestPicture();
+};
+
class CBlockUserSignal : public CSignal
{
public:
diff -urN licq/include/licq_icqd.h licq-ssbi/include/licq_icqd.h
--- licq/include/licq_icqd.h 2007-08-21 14:51:52.000000000 +0300
+++ licq-ssbi/include/licq_icqd.h 2008-01-22 01:11:26.000000000 +0200
@@ -42,6 +42,7 @@
class SrvSocket;
class INetSocket;
class ProxyServer;
+class COscarService;
class CReverseConnectToUserData;
class CMSN;
@@ -300,6 +301,8 @@
const char *szFaxNumber, const char *szAddress, const char *szCellularNumber,
const char *szZipCode, unsigned short nCountryCode, bool bHideEmail);
+ unsigned long ProtoRequestPicture(const char *szId, unsigned long nPPID);
+
unsigned long ProtoOpenSecureChannel(const char *szId, unsigned long nPPID);
unsigned long ProtoCloseSecureChannel(const char *szId, unsigned long nPPID);
void ProtoOpenSecureChannelCancel(const char *szId, unsigned long nPPID,
@@ -474,6 +477,7 @@
void icqUpdateContactList();
void icqTypingNotification(const char *_szId, bool _bActive);
void icqCheckInvisible(const char *_szId);
+ void icqRequestService(unsigned short nFam);
// Visible/Invisible/Ignore list functions
void ProtoToggleInvisibleList(const char *_szId, unsigned long _nPPID);
@@ -514,6 +518,8 @@
void UnregisterProtoPlugin();
char *ProtoPluginName(unsigned long);
+ EDaemonStatus Status() { return m_eStatus; }
+
void PluginUIViewEvent(const char *szId, unsigned long nPPID ) {
PushPluginSignal(new CICQSignal(SIGNAL_UI_VIEWEVENT, 0, szId, nPPID, 0));
}
@@ -567,7 +573,9 @@
// Proxy options
void InitProxy();
+ ProxyServer *CreateProxy();
bool ProxyEnabled() { return m_bProxyEnabled; }
+ ProxyServer *GetProxy() { return m_xProxy; }
void SetProxyEnabled(bool b) { m_bProxyEnabled = b; }
unsigned short ProxyType() { return m_nProxyType; }
void SetProxyType(unsigned short t) { m_nProxyType = t; }
@@ -609,10 +617,12 @@
// ICQ options
bool UseServerContactList() { return m_bUseSS; }
+ bool UseServerSideBuddyIcons() { return m_bUseSSBI; }
bool SendTypingNotification() { return m_bSendTN; }
- void SetUseServerContactList(bool b) { m_bUseSS = b; }
- void SetSendTypingNotification(bool b) { m_bSendTN = b; }
+ void SetUseServerContactList(bool b) { m_bUseSS = b; }
+ void SetUseServerSideBuddyIcons(bool b);
+ void SetSendTypingNotification(bool b) { m_bSendTN = b; }
// Misc functions
bool ReconnectAfterUinClash() { return m_bReconnectAfterUinClash; }
@@ -700,8 +710,12 @@
char *m_szProxyPasswd;
ProxyServer *m_xProxy;
+ // Services
+ COscarService *m_xSSBIService;
+
// Misc
bool m_bUseSS; // server side list
+ bool m_bUseSSBI; // server side buddy icons
bool m_bSendTN; // Send typing notifications
bool m_bReconnectAfterUinClash; // reconnect after uin has been used from another location?
@@ -729,6 +743,7 @@
pthread_t thread_monitorsockets,
thread_ping,
thread_updateusers,
+ thread_ssbiservice,
thread_shutdown;
pthread_cond_t cond_serverack;
@@ -762,6 +777,7 @@
ICQEvent *DoneExtendedEvent(unsigned long tag, EventResult _eResult);
bool hasServerEvent(unsigned long);
void ProcessDoneEvent(ICQEvent *);
+ void PushEvent(ICQEvent *);
void PushExtendedEvent(ICQEvent *);
void PushPluginSignal(CICQSignal *);
void PushPluginEvent(ICQEvent *);
@@ -830,10 +846,12 @@
friend void *ReverseConnectToUser_tep(void *p);
friend void *ProcessRunningEvent_Client_tep(void *p);
friend void *ProcessRunningEvent_Server_tep(void *p);
+ friend void *OscarServiceSendQueue_tep(void *p);
friend void *Shutdown_tep(void *p);
friend void *ConnectToServer_tep(void *s);
friend class ICQUser;
friend class CSocketManager;
+ friend class COscarService;
friend class CChatManager;
friend class CFileTransferManager;
friend class COnEventManager;
diff -urN licq/include/licq_icq.h licq-ssbi/include/licq_icq.h
--- licq/include/licq_icq.h 2008-01-03 16:09:22.000000000 +0200
+++ licq-ssbi/include/licq_icq.h 2008-01-22 01:11:26.000000000 +0200
@@ -34,6 +34,7 @@
const unsigned short ICQ_SNACxFAM_BUDDY = 0x0003;
const unsigned short ICQ_SNACxFAM_MESSAGE = 0x0004;
const unsigned short ICQ_SNACxFAM_BOS = 0x0009;
+const unsigned short ICQ_SNACxFAM_SSBI = 0x0010;
const unsigned short ICQ_SNACxFAM_LIST = 0x0013;
const unsigned short ICQ_SNACxFAM_VARIOUS = 0x0015;
const unsigned short ICQ_SNACxFAM_NEWUIN = 0x0017;
@@ -104,6 +105,13 @@
const unsigned short ICQ_SNACxREQUEST_IMAGE = 0x000C; // client
const unsigned short ICQ_SNACxSEND_IMAGE = 0x000D; // server
+// Subtypes for SSBI family
+const unsigned short ICQ_SNACxSSBI_ERROR = 0x0001; // server
+const unsigned short ICQ_SNACxSSBI_UPLOAD = 0x0002; // client
+const unsigned short ICQ_SNACxSSBI_UPLOADxACK = 0x0003; // server
+const unsigned short ICQ_SNACxSSBI_ICONxREQUEST = 0x0006; // client
+const unsigned short ICQ_SNACxSSBI_ICONxREPLY = 0x0007; // server
+
// Subtypes for list family
const unsigned short ICQ_SNACxLIST_REQUESTxRIGHTS = 0x0002; // client
const unsigned short ICQ_SNACxLIST_RIGHTSxGRANTED = 0x0003; // server
@@ -544,6 +552,10 @@
0x4E, 0xC5, 0x9D, 0x51, 0xA6, 0x47,
0x4E, 0x34, 0xF5, 0xA0 };
+const char ICQ_CAPABILITY_SSBI[] = { 0x09, 0x46, 0x13, 0x46, 0x4C, 0x7F,
+ 0x11, 0xD1, 0x82, 0x22, 0x44, 0x45,
+ 0x53, 0x54, 0x00, 0x00 };
+
const char ICQ_CAPABILITY_LICQxVER[] = { 'L', 'i', 'c', 'q', ' ', 'c',
'l', 'i', 'e', 'n', 't', ' ',
0x00, 0x00, 0x00, 0x00 };
diff -urN licq/include/licq_oscarservice.h licq-ssbi/include/licq_oscarservice.h
--- licq/include/licq_oscarservice.h 1970-01-01 03:00:00.000000000 +0300
+++ licq-ssbi/include/licq_oscarservice.h 2008-01-22 01:11:26.000000000 +0200
@@ -0,0 +1,61 @@
+#ifndef OSCARSERVICE_H
+#define OSCARSERVICE_H
+
+#include <list>
+
+class CICQDaemon;
+class ICQEvent;
+class CBuffer;
+class CPacket;
+class ProxyServer;
+
+enum EOscarServiceStatus {STATUS_UNINITIALIZED, STATUS_SERVICE_REQ_SENT,
+ STATUS_SERVICE_REQ_ACKED, STATUS_CONNECTED,
+ STATUS_SRV_READY_RECV, STATUS_SRV_VER_RECV,
+ STATUS_SRV_RATE_RECV, STATUS_READY};
+
+void *OscarServiceSendQueue_tep(void *p);
+
+class COscarService
+{
+public:
+ COscarService(CICQDaemon *Daemon, unsigned short Fam);
+ ~COscarService();
+ bool Initialize();
+ bool ProcessPacket(CBuffer &packet);
+ unsigned long SendEvent(const char *Id, unsigned short SubType, bool Request);
+ void ClearQueue();
+
+ void SetConnectCredential(char *Server, unsigned short Port,
+ char *Cookie, unsigned short CookieLen);
+ void ChangeStatus(EOscarServiceStatus s);
+ int GetSocketDesc() { return mySocketDesc; }
+ void ResetSocket() { mySocketDesc = -1; }
+ unsigned short GetFam() { return myFam; }
+
+protected:
+ CICQDaemon *myDaemon;
+ unsigned short myFam;
+ int mySocketDesc;
+ ProxyServer *myProxy;
+ EOscarServiceStatus myStatus;
+ char *myServer, *myCookie;
+ unsigned short myPort, myCookieLen;
+ std::list <ICQEvent *> mySendQueue;
+ pthread_mutex_t mutex_sendqueue;
+ pthread_cond_t cond_sendqueue;
+ pthread_mutex_t mutex_status;
+ pthread_cond_t cond_status;
+
+ bool SendPacket(CPacket *packet);
+ bool WaitForStatus(EOscarServiceStatus s);
+ bool SendSSBIFam(ICQEvent *e);
+ void ProcessNewChannel(CBuffer &packet);
+ void ProcessDataChannel(CBuffer &packet);
+ void ProcessServiceFam(CBuffer &packet, unsigned short SubType, unsigned long RequestId);
+ void ProcessSSBIFam(CBuffer &packet, unsigned short SubType, unsigned long RequestId);
+
+ friend void *OscarServiceSendQueue_tep(void *p);
+};
+
+#endif
diff -urN licq/include/licq_packets.h licq-ssbi/include/licq_packets.h
--- licq/include/licq_packets.h 2008-01-03 16:09:22.000000000 +0200
+++ licq-ssbi/include/licq_packets.h 2008-01-22 01:11:26.000000000 +0200
@@ -134,7 +134,7 @@
void InitBuffer();
static bool s_bRegistered;
- static unsigned short s_nSequence;
+ static unsigned short s_nSequence[32];
static unsigned short s_nSubSequence;
static pthread_mutex_t s_xMutex;
@@ -145,6 +145,7 @@
unsigned short m_nSubType;
unsigned short m_nSubCommand;
unsigned short m_nExtraInfo;
+ unsigned short m_nService;
char *m_szSequenceOffset;
};
@@ -219,7 +220,7 @@
class CPU_SendCookie : public CSrvPacketTcp
{
public:
- CPU_SendCookie(const char *, int len);
+ CPU_SendCookie(const char *, int len, unsigned short nService = 0);
virtual ~CPU_SendCookie();
};
@@ -237,7 +238,8 @@
class CPU_GenericFamily : public CPU_CommonFamily
{
public:
- CPU_GenericFamily(unsigned short Family, unsigned short SubType);
+ CPU_GenericFamily(unsigned short Family, unsigned short SubType,
+ unsigned short nService = 0);
virtual ~CPU_GenericFamily();
};
@@ -312,7 +314,9 @@
class CPU_ImICQ : public CPU_CommonFamily
{
public:
- CPU_ImICQ();
+ CPU_ImICQ();
+ CPU_ImICQ(unsigned short VerArray[][2], unsigned short NumVer,
+ unsigned short nService);
};
//-----ICQMode------------------------------------------------------------------
@@ -333,7 +337,7 @@
class CPU_RateAck : public CPU_CommonFamily
{
public:
- CPU_RateAck();
+ CPU_RateAck(unsigned short nService = 0);
};
//-----GenericUinList------------------------------------------------------------
@@ -487,6 +491,8 @@
{
public:
CPU_ClientReady();
+ CPU_ClientReady(unsigned short VerArray[][4], unsigned short NumVer,
+ unsigned short nService);
};
//-----ClientAckNameInfo--------------------------------------------------------
@@ -1126,6 +1132,21 @@
CPU_RequestInfo(const char *szId);
};
+//-----RequestBuddyIcon------------------------------------------------------
+class CPU_RequestBuddyIcon : public CPU_CommonFamily
+{
+public:
+ CPU_RequestBuddyIcon(const char *szId, unsigned short _nBuddyIconType,
+ char _nBuddyIconHashType, const char *_szBuddyIconHash,
+ unsigned short nService);
+};
+
+class CPU_RequestService : public CPU_CommonFamily
+{
+public:
+ CPU_RequestService(unsigned short nFam);
+};
+
//-----AIMFetchAwayMessage--------------------------------------------------
class CPU_AIMFetchAwayMessage : public CPU_CommonFamily
{
diff -urN licq/include/licq_proxy.h licq-ssbi/include/licq_proxy.h
--- licq/include/licq_proxy.h 2006-11-11 21:24:51.000000000 +0200
+++ licq-ssbi/include/licq_proxy.h 2008-01-22 01:11:26.000000000 +0200
@@ -1,3 +1,6 @@
+#ifndef PROXY_H
+#define PROXY_H
+
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
@@ -68,3 +71,5 @@
bool HTTPInitProxy();
bool HTTPOpenProxyConnection(const char *_szRemoteName, unsigned short _nRemotePort);
};
+
+#endif
diff -urN licq/include/licq_socket.h licq-ssbi/include/licq_socket.h
--- licq/include/licq_socket.h 2006-11-11 21:24:51.000000000 +0200
+++ licq-ssbi/include/licq_socket.h 2008-01-22 01:11:26.000000000 +0200
@@ -166,6 +166,7 @@
// Functions specific to Server TCP communication
bool SendPacket(CBuffer *b);
bool RecvPacket();
+ bool ConnectTo(const char* server, unsigned short port, ProxyServer *xProxy);
};
diff -urN licq/include/licq_user.h licq-ssbi/include/licq_user.h
--- licq/include/licq_user.h 2008-01-21 22:47:35.000000000 +0200
+++ licq-ssbi/include/licq_user.h 2008-01-22 01:11:26.000000000 +0200
@@ -515,6 +515,10 @@
// Picture Info
bool GetPicturePresent() { return m_bPicturePresent; }
+ unsigned short BuddyIconType() { return m_nBuddyIconType; }
+ char BuddyIconHashType() { return m_nBuddyIconHashType; }
+ char *BuddyIconHash() { return m_szBuddyIconHash; }
+ char *OurBuddyIconHash() { return m_szOurBuddyIconHash; }
// Dynamic info fields for protocol plugins
string GetPPField(const string &);
@@ -634,6 +638,10 @@
// Picture info
void SetPicturePresent(bool b) { m_bPicturePresent = b; SavePictureInfo(); }
+ void SetBuddyIconType(unsigned short s) { m_nBuddyIconType = s; }
+ void SetBuddyIconHashType(char s) { m_nBuddyIconHashType = s; }
+ void SetBuddyIconHash(char *s) { SetString(&m_szBuddyIconHash, s); }
+ void SetOurBuddyIconHash(char *s) { SetString(&m_szOurBuddyIconHash, s); }
// Licq Info
void SetAwaitingAuth(bool b) { m_bAwaitingAuth = b; }
@@ -940,6 +948,9 @@
// Picture Info
bool m_bPicturePresent;
+ unsigned short m_nBuddyIconType;
+ char m_nBuddyIconHashType;
+ char *m_szBuddyIconHash, *m_szOurBuddyIconHash;
// Dynamic info fields for protocol plugins
map<string, string> m_mPPFields;
diff -urN licq/plugins/qt-gui/src/sigman.cpp licq-ssbi/plugins/qt-gui/src/sigman.cpp
--- licq/plugins/qt-gui/src/sigman.cpp 2007-10-22 16:21:27.000000000 +0300
+++ licq-ssbi/plugins/qt-gui/src/sigman.cpp 2008-01-22 01:11:26.000000000 +0200
@@ -175,6 +175,7 @@
case MAKESNAC(ICQ_SNACxFAM_MESSAGE, ICQ_SNACxMSG_SENDxSERVER):
case MAKESNAC(ICQ_SNACxFAM_LOCATION, ICQ_SNACxREQUESTxUSERxINFO):
case MAKESNAC(ICQ_SNACxFAM_LOCATION, ICQ_SNACxLOC_INFOxREQ):
+ case MAKESNAC(ICQ_SNACxFAM_SSBI, ICQ_SNACxSSBI_ICONxREQUEST):
emit signal_doneUserFcn(e);
break;
diff -urN licq/plugins/qt-gui/src/userinfodlg.cpp licq-ssbi/plugins/qt-gui/src/userinfodlg.cpp
--- licq/plugins/qt-gui/src/userinfodlg.cpp 2007-11-25 17:37:31.000000000 +0200
+++ licq-ssbi/plugins/qt-gui/src/userinfodlg.cpp 2008-01-22 01:11:26.000000000 +0200
@@ -2358,11 +2358,7 @@
}
case PictureInfo:
{
- ICQUser *u = gUserManager.FetchUser(m_szId, m_nPPID, LOCK_R);
- if (u == NULL) return;
- bool bSendServer = (u->SocketDesc(ICQ_CHNxINFO) < 0);
- gUserManager.DropUser(u);
- icqEventTag = server->icqRequestPicture(m_szId, bSendServer);
+ icqEventTag = server->ProtoRequestPicture(m_szId, m_nPPID);
break;
}
}
diff -urN licq/src/buffer.cpp licq-ssbi/src/buffer.cpp
--- licq/src/buffer.cpp 2007-08-21 14:51:52.000000000 +0300
+++ licq-ssbi/src/buffer.cpp 2008-01-22 01:11:26.000000000 +0200
@@ -333,6 +333,12 @@
return sz;
}
+char *CBuffer::UnpackBinBlock(char *sz, unsigned short _nSize)
+{
+ for (unsigned short i = 0; i < _nSize; i++) *this >> sz[i];
+ return sz;
+}
+
char *CBuffer::UnpackStringBE(char* sz, unsigned short _usiSize)
{
unsigned short nLen;
diff -urN licq/src/icqd.cpp licq-ssbi/src/icqd.cpp
--- licq/src/icqd.cpp 2007-11-26 13:26:35.000000000 +0200
+++ licq-ssbi/src/icqd.cpp 2008-01-22 01:11:26.000000000 +0200
@@ -32,6 +32,7 @@
#include "licq_icq.h"
#include "licq_user.h"
+#include "licq_oscarservice.h"
#include "licq_constants.h"
#include "licq_file.h"
#include "licq_log.h"
@@ -270,8 +271,12 @@
m_szProxyPasswd = (char *)malloc(strlen(t_str) + 1);
strcpy(m_szProxyPasswd, t_str);
+ // Services
+ m_xSSBIService = NULL;
+
// Misc
licqConf.ReadBool("UseSS", m_bUseSS, true); // server side list
+ licqConf.ReadBool("UseSSBI", m_bUseSSBI, true); // server side buddy icons
licqConf.ReadBool("SendTypingNotification", m_bSendTN, true);
licqConf.ReadBool("ReconnectAfterUinClash", m_bReconnectAfterUinClash, false);
@@ -447,10 +452,23 @@
nResult = pthread_create(&thread_updateusers, NULL, &UpdateUsers_tep, this);
if (nResult != 0)
{
- gLog.Error("%sUnable to start ping thread:\n%s%s.\n", L_ERRORxSTR, L_BLANKxSTR, strerror(nResult));
+ gLog.Error("%sUnable to start users update thread:\n%s%s.\n", L_ERRORxSTR, L_BLANKxSTR, strerror(nResult));
return false;
}
+ if (UseServerSideBuddyIcons())
+ {
+ m_xSSBIService = new COscarService(this, ICQ_SNACxFAM_SSBI);
+ nResult = pthread_create(&thread_ssbiservice, NULL,
+ &OscarServiceSendQueue_tep, m_xSSBIService);
+ if (nResult != 0)
+ {
+ gLog.Error(tr("%sUnable to start SSBI service thread:\n%s%s.\n"),
+ L_ERRORxSTR, L_BLANKxSTR, strerror(nResult));
+ return false;
+ }
+ }
+
return true;
}
@@ -804,6 +822,7 @@
// Misc
licqConf.WriteBool("UseSS", m_bUseSS); // server side list
+ licqConf.WriteBool("UseSSBI", m_bUseSSBI); // server side buddy icons
licqConf.WriteBool("SendTypingNotification", m_bSendTN);
licqConf.WriteBool("ReconnectAfterUinClash", m_bReconnectAfterUinClash);
@@ -975,38 +994,46 @@
delete m_xProxy;
m_xProxy = NULL;
}
+ m_xProxy = CreateProxy();
+}
+
+ProxyServer *CICQDaemon::CreateProxy()
+{
+ ProxyServer *Proxy = NULL;
switch (m_nProxyType)
{
case PROXY_TYPE_HTTP :
- m_xProxy = new HTTPProxyServer();
+ Proxy = new HTTPProxyServer();
break;
default:
break;
}
- if (m_xProxy != NULL)
+ if (Proxy != NULL)
{
gLog.Info(tr("%sResolving proxy: %s:%d...\n"), L_INITxSTR, m_szProxyHost, m_nProxyPort);
- if (!m_xProxy->SetProxyAddr(m_szProxyHost, m_nProxyPort)) {
+ if (!Proxy->SetProxyAddr(m_szProxyHost, m_nProxyPort))
+ {
char buf[128];
gLog.Warn(tr("%sUnable to resolve proxy server %s:\n%s%s.\n"), L_ERRORxSTR,
- m_szProxyHost, L_BLANKxSTR, m_xProxy->ErrorStr(buf, 128));
- delete m_xProxy;
- m_xProxy = NULL;
+ m_szProxyHost, L_BLANKxSTR, Proxy->ErrorStr(buf, 128));
+ delete Proxy;
+ Proxy = NULL;
}
- if (m_xProxy)
+ if (Proxy)
{
if (m_bProxyAuthEnabled)
- m_xProxy->SetProxyAuth(m_szProxyLogin, m_szProxyPasswd);
+ Proxy->SetProxyAuth(m_szProxyLogin, m_szProxyPasswd);
- m_xProxy->InitProxy();
+ Proxy->InitProxy();
}
}
-}
+ return Proxy;
+}
unsigned short VersionToUse(unsigned short v_in)
{
@@ -1111,6 +1138,25 @@
m_nIgnoreTypes &= ~n;
}
+void CICQDaemon::SetUseServerSideBuddyIcons(bool b)
+{
+ if (b && m_xSSBIService == NULL)
+ {
+ m_xSSBIService = new COscarService(this, ICQ_SNACxFAM_SSBI);
+ int nResult = pthread_create(&thread_ssbiservice, NULL,
+ &OscarServiceSendQueue_tep, m_xSSBIService);
+ if (nResult != 0)
+ {
+ gLog.Error(tr("%sUnable to start SSBI service thread:\n%s%s.\n"),
+ L_ERRORxSTR, L_BLANKxSTR, strerror(nResult));
+ }
+ else
+ m_bUseSSBI = true;
+ }
+ else
+ m_bUseSSBI = b;
+}
+
bool CICQDaemon::AddUserToList(const char *szId, unsigned long nPPID,
bool bNotify, bool bTempUser)
{
@@ -2029,6 +2075,13 @@
return(e);
}
+void CICQDaemon::PushEvent(ICQEvent *e)
+{
+ assert(e != NULL);
+ pthread_mutex_lock(&mutex_runningevents);
+ m_lxRunningEvents.push_back(e);
+ pthread_mutex_unlock(&mutex_runningevents);
+}
/*------------------------------------------------------------------------------
* PushExtendedEvent
diff -urN licq/src/icqd-srv.cpp licq-ssbi/src/icqd-srv.cpp
--- licq/src/icqd-srv.cpp 2008-01-03 16:09:23.000000000 +0200
+++ licq-ssbi/src/icqd-srv.cpp 2008-01-22 01:11:26.000000000 +0200
@@ -27,6 +27,7 @@
#include "licq_icqd.h"
#include "licq_translate.h"
+#include "licq_oscarservice.h"
#include "licq_packets.h"
#include "licq_socket.h"
#include "licq_user.h"
@@ -716,6 +717,43 @@
return icqRequestMetaInfo(szUin);
}
+//-----ProtoRequestPicture------------------------------------------------------
+unsigned long CICQDaemon::ProtoRequestPicture(const char *_szId, unsigned long _nPPID)
+{
+ unsigned long nRet = 0;
+
+ if (_nPPID == LICQ_PPID)
+ {
+ ICQUser *u = gUserManager.FetchUser(_szId, LICQ_PPID, LOCK_R);
+ if (u == NULL) return 0;
+
+ if (UseServerSideBuddyIcons() && strlen(u->BuddyIconHash()) > 0)
+ {
+ gUserManager.DropUser(u);
+ nRet = m_xSSBIService->SendEvent(_szId, ICQ_SNACxSSBI_ICONxREQUEST, true);
+ }
+ else
+ {
+ bool bSendServer = (u->SocketDesc(ICQ_CHNxINFO) < 0);
+ gUserManager.DropUser(u);
+ nRet = icqRequestPicture(_szId, bSendServer);
+ }
+ }
+ else
+ PushProtoSignal(new CRequestPicture(_szId), _nPPID);
+
+ return nRet;
+}
+
+//-----icqRequestService--------------------------------------------------------
+void CICQDaemon::icqRequestService(unsigned short nFam)
+{
+ CPU_CommonFamily *p = new CPU_RequestService(nFam);
+ gLog.Info(tr("%sRequesting service socket for FAM 0x%02X (#%hu/#%d)...\n"),
+ L_SRVxSTR, nFam, p->Sequence(), p->SubSequence());
+ SendEvent_Server(p);
+}
+
//-----icqSetStatus-------------------------------------------------------------
unsigned long CICQDaemon::ProtoSetStatus(unsigned long _nPPID,
unsigned short _nNewStatus)
@@ -1736,6 +1774,7 @@
case MAKESNAC(ICQ_SNACxFAM_NEWUIN, ICQ_SNACxREGISTER_USER):
case MAKESNAC(ICQ_SNACxFAM_LOCATION, ICQ_SNACxREQUESTxUSERxINFO):
case MAKESNAC(ICQ_SNACxFAM_LOCATION, ICQ_SNACxLOC_INFOxREQ):
+ case MAKESNAC(ICQ_SNACxFAM_SSBI, ICQ_SNACxSSBI_ICONxREQUEST):
PushPluginEvent(e);
break;
@@ -1876,6 +1915,16 @@
void CICQDaemon::postLogoff(int nSD, ICQEvent *cancelledEvent)
{
+ if (m_xSSBIService)
+ {
+ if (m_xSSBIService->GetSocketDesc() != -1)
+ {
+ gSocketManager.CloseSocket(m_xSSBIService->GetSocketDesc());
+ m_xSSBIService->ResetSocket();
+ m_xSSBIService->ChangeStatus(STATUS_UNINITIALIZED);
+ m_xSSBIService->ClearQueue();
+ }
+ }
pthread_mutex_lock(&mutex_runningevents);
pthread_mutex_lock(&mutex_sendqueue_server);
pthread_mutex_lock(&mutex_extendedevents);
@@ -2025,7 +2074,6 @@
delete s;
return (-1);
}
- s->SetProxy(m_xProxy);
}
else if (m_xProxy != NULL)
{
@@ -2033,37 +2081,8 @@
m_xProxy = NULL;
}
- char ipbuf[32];
-
- if (m_xProxy == NULL)
- {
- gLog.Info(tr("%sResolving %s port %d...\n"), L_SRVxSTR, server, port);
- if (!s->SetRemoteAddr(server, port)) {
- char buf[128];
- gLog.Warn(tr("%sUnable to resolve %s:\n%s%s.\n"), L_ERRORxSTR,
- server, L_BLANKxSTR, s->ErrorStr(buf, 128));
- delete s;
- return (-1); // no route to host (not connected)
- }
- gLog.Info(tr("%sICQ server found at %s:%d.\n"), L_SRVxSTR,
- s->RemoteIpStr(ipbuf), s->RemotePort());
- }
- else
- {
- // It doesn't matter if it resolves or not, the proxy should do it then
- s->SetRemoteAddr(server, port);
- }
-
- if (m_xProxy == NULL)
- gLog.Info(tr("%sOpening socket to server.\n"), L_SRVxSTR);
- else
- gLog.Info("%sOpening socket to server via proxy.\n", L_SRVxSTR);
- if (!s->OpenConnection())
+ if (!s->ConnectTo(server, port, m_xProxy))
{
- char buf[128];
- gLog.Warn(tr("%sUnable to connect to %s:%d:\n%s%s.\n"), L_ERRORxSTR,
- s->RemoteIpStr(ipbuf), s->RemotePort(), L_BLANKxSTR,
- s->ErrorStr(buf, 128));
delete s;
return -1;
}
@@ -2215,9 +2234,15 @@
void CICQDaemon::ProcessServiceFam(CBuffer &packet, unsigned short nSubtype)
{
- packet.UnpackUnsignedShortBE(); // flags
+ unsigned short flags = packet.UnpackUnsignedShortBE(); // flags
packet.UnpackUnsignedLongBE(); // sequence
+ if (flags & 0x8000) // version of the family that this SNAC, just ignore it
+ {
+ unsigned short len = packet.UnpackUnsignedShortBE();
+ packet.incDataPosRead(len);
+ }
+
switch (nSubtype)
{
case ICQ_SNACxSUB_READYxSERVER:
@@ -2241,6 +2266,67 @@
break;
}
+ case ICQ_SNACxSUB_REDIRECT:
+ {
+ unsigned short nFam = 0;
+
+ if (!packet.readTLV())
+ {
+ gLog.Warn(tr("%sError during parsing service redirect packet!\n"), L_WARNxSTR);
+ break;
+ }
+ if (packet.getTLVLen(0x000D) == 2)
+ nFam = packet.UnpackUnsignedShortTLV(0x000D);
+
+ gLog.Info(tr("%sRedirect for service 0x%02X received.\n"), L_SRVxSTR, nFam);
+
+ char *szServer = packet.UnpackStringTLV(0x0005);
+ char *szCookie = packet.UnpackStringTLV(0x0006);
+ unsigned short nCookieLen = packet.getTLVLen(0x0006);
+ if (!szServer || !szCookie)
+ {
+ gLog.Warn(tr("%sInvalid servername (%s) or cookie (%s) in service redirect packet!\n"),
+ L_WARNxSTR, szServer ? szServer : "(null)", szCookie ? szCookie : "(null)");
+ if (szServer) delete [] szServer;
+ if (szCookie) delete [] szCookie;
+ break;
+ }
+
+ char *szPort = strchr(szServer, ':');
+ unsigned short nPort;
+ if (szPort)
+ {
+ *szPort++ = '\0';
+ nPort = atoi(szPort);
+ } else
+ {
+ nPort = m_nICQServerPort;
+ }
+
+ switch (nFam)
+ {
+ case ICQ_SNACxFAM_SSBI:
+ if (m_xSSBIService)
+ {
+ m_xSSBIService->SetConnectCredential(szServer, nPort, szCookie, nCookieLen);
+ m_xSSBIService->ChangeStatus(STATUS_SERVICE_REQ_ACKED);
+ break;
+ } else
+ {
+ gLog.Warn(tr("%sService redirect packet for unallocated SSBI service.\n"),
+ L_WARNxSTR);
+ break;
+ }
+ default:
+ gLog.Warn(tr("%sService redirect packet for unhandled service 0x%02X.\n"),
+ L_WARNxSTR, nFam);
+ }
+
+ delete [] szServer;
+ delete [] szCookie;
+ break;
+ }
+
case ICQ_SNACxSRV_ACKxIMxICQ:
{
// ICQOwner *o = gUserManager.FetchOwner(LICQ_PPID, LOCK_R);
@@ -2842,6 +2928,41 @@
}
}
+ if (packet.hasTLV(0x001d)) // Server-stored buddy icon information
+ {
+ CBuffer SSBI_info = packet.UnpackTLV(0x001d);
+ unsigned short IconType = SSBI_info.UnpackUnsignedShortBE();
+ char HashType = SSBI_info.UnpackChar();
+ char HashLenght = SSBI_info.UnpackChar();
+
+ switch (IconType)
+ {
+ case 0x01: // Simple Buddy Icon
+ case 0x0C: // Photo Buddy Icon
+ {
+ if (HashType == 1 && HashLenght > 0 && HashLenght <= 16)
+ {
+ char *Hash = new char[HashLenght];
+ char *HashHex = new char[HashLenght*2 + 1];
+
+ SSBI_info.UnpackBinBlock(Hash, HashLenght);
+ u->SetBuddyIconHash(PrintHex(HashHex, Hash, HashLenght));
+ u->SetBuddyIconType(IconType);
+ u->SetBuddyIconHashType(HashType);
+ u->SavePictureInfo();
+ delete [] Hash;
+ delete [] HashHex;
+ }
+ break;
+ }
+
+ default: // Unsupported types of SSBI
+ gLog.Warn(tr("%sUnsupported type 0x%02X of buddy icon for %s.\n"),
+ L_WARNxSTR, IconType, u->GetAlias());
+ break;
+ }
+ }
+
// maybe use this for auto update info later
u->SetClientTimestamp(nInfoTimestamp);
u->SetClientInfoTimestamp(nInfoPluginTimestamp);
diff -urN licq/src/icqd-tcp.cpp licq-ssbi/src/icqd-tcp.cpp
--- licq/src/icqd-tcp.cpp 2007-10-10 13:36:54.000000000 +0300
+++ licq-ssbi/src/icqd-tcp.cpp 2008-01-22 01:11:26.000000000 +0200
@@ -3430,6 +3430,9 @@
{
gLog.Info("%sPicture reply from %s.\n", szInfo, u->GetAlias());
packet.incDataPosRead(nEntries); // filename, don't care
+ unsigned long nLen = packet.UnpackUnsignedLong();
+ if (nLen == 0) // do not create empty .pic files
+ break;
char szFilename[MAX_FILENAME_LEN];
szFilename[MAX_FILENAME_LEN - 1] = '\0';
@@ -3444,7 +3447,6 @@
break;
}
- unsigned long nLen = packet.UnpackUnsignedLong();
char data[nLen];
for (unsigned long i = 0; i < nLen; i++)
{
@@ -3452,6 +3454,7 @@
}
write(nFD, data, nLen);
+ close(nFD);
u->SetEnableSave(false);
u->SetPicturePresent(true);
diff -urN licq/src/icqd-threads.cpp licq-ssbi/src/icqd-threads.cpp
--- licq/src/icqd-threads.cpp 2007-10-10 13:36:54.000000000 +0300
+++ licq-ssbi/src/icqd-threads.cpp 2008-01-22 01:11:43.000000000 +0200
@@ -17,6 +17,7 @@
#include "licq_icqd.h"
#include "licq_log.h"
#include "licq_packets.h"
+#include "licq_oscarservice.h"
#include "licq_plugind.h"
#include "licq.h"
@@ -665,7 +666,7 @@
CICQDaemon *d = (CICQDaemon *)p;
fd_set f;
- int nSocketsAvailable, nCurrentSocket, l;
+ int nSocketsAvailable, nCurrentSocket, nServiceSocket, l;
char buf[1024];
while (true)
@@ -691,6 +692,14 @@
/*pthread_testcancel();
pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);*/
+ if (d->m_xSSBIService)
+ {
+ COscarService *svc = d->m_xSSBIService;
+ nServiceSocket = svc->GetSocketDesc();
+ }
+ else
+ nServiceSocket = -1;
+
nCurrentSocket = 0;
while (nSocketsAvailable > 0 && nCurrentSocket < l)
{
@@ -764,6 +773,37 @@
}
}
+ // Message from the service sockets -----------------------------------
+ else if (nCurrentSocket == nServiceSocket)
+ {
+ DEBUG_THREADS("[MonitorSockets_tep] Data on SSBI service socket.\n");
+ COscarService *svc = d->m_xSSBIService;
+ SrvSocket *sock_svc = static_cast<SrvSocket*>(s);
+ if (sock_svc->Recv())
+ {
+ CBuffer packet(sock_svc->RecvBuffer());
+ sock_svc->ClearRecvBuffer();
+ gSocketManager.DropSocket(sock_svc);
+ if (!svc->ProcessPacket(packet))
+ {
+ gLog.Warn(tr("%sCan't process packet for service 0x%02X.\n"),
+ L_WARNxSTR, svc->GetFam());
+ svc->ResetSocket();
+ svc->ChangeStatus(STATUS_UNINITIALIZED);
+ gSocketManager.CloseSocket(nCurrentSocket);
+ }
+ }
+ else
+ {
+ gLog.Warn(tr("%sCan't receive packet for service 0x%02X.\n"),
+ L_WARNxSTR, svc->GetFam());
+ svc->ResetSocket();
+ svc->ChangeStatus(STATUS_UNINITIALIZED);
+ gSocketManager.DropSocket(sock_svc);
+ gSocketManager.CloseSocket(nCurrentSocket);
+ }
+ }
+
// Connection on the server port -------------------------------------
else if (nCurrentSocket == d->m_nTCPSocketDesc)
{
@@ -901,7 +941,11 @@
// Cancel the update users thread
pthread_cancel(d->thread_updateusers);
-
+
+ // Cancel the SSBI service thread
+ if (d->m_xSSBIService)
+ pthread_cancel(d->thread_ssbiservice);
+
// Join our threads
pthread_join(d->thread_monitorsockets, NULL);
@@ -937,6 +981,7 @@
FOR_EACH_PROTO_USER_START(LICQ_PPID, LOCK_R)
{
bool bSent = false;
+ bool bSSBI = false;
if (d->AutoUpdateInfo() && !pUser->UserUpdated() &&
pUser->ClientTimestamp() != pUser->OurClientTimestamp()
@@ -946,6 +991,15 @@
bSent = true;
}
+ if (d->UseServerSideBuddyIcons() && d->AutoUpdateInfo() &&
+ strlen(pUser->BuddyIconHash()) > 0 &&
+ strcmp(pUser->BuddyIconHash(), pUser->OurBuddyIconHash()) != 0)
+ {
+ d->m_xSSBIService->SendEvent(pUser->IdString(), ICQ_SNACxSSBI_ICONxREQUEST, true);
+ bSent = true;
+ bSSBI = true;
+ }
+
if (!pUser->StatusOffline() && !pUser->UserUpdated() &&
//Don't bother clients that we know don't support plugins
pUser->Version() >= 7 &&
@@ -974,7 +1028,8 @@
gLog.Info("Updating %s's info plugins.\n", pUser->GetAlias());
d->icqRequestInfoPlugin(pUser, true, PLUGIN_QUERYxINFO);
d->icqRequestInfoPlugin(pUser, true, PLUGIN_PHONExBOOK);
- d->icqRequestInfoPlugin(pUser, true, PLUGIN_PICTURE);
+ if (!bSSBI) // Send only if we din't request SSBI already
+ d->icqRequestInfoPlugin(pUser, true, PLUGIN_PICTURE);
bSent = true;
}
diff -urN licq/src/icqevent.cpp licq-ssbi/src/icqevent.cpp
--- licq/src/icqevent.cpp 2006-11-11 21:24:53.000000000 +0200
+++ licq-ssbi/src/icqevent.cpp 2008-01-22 01:11:26.000000000 +0200
@@ -109,18 +109,32 @@
// : m_xBuffer(p.getBuffer())
{
// set up internal variables
- m_pPacket = p;
m_bCancelled = false;
m_Deleted = false;
m_NoAck = false;
- m_nChannel = p->Channel();
- m_nCommand = p->Command();
- m_nSNAC = p->SNAC();
- m_nSubCommand = p->SubCommand();
- m_nSequence = p->Sequence();
- m_nSubSequence = p->SubSequence();
- m_nSubType = (p->SNAC() & 0xFFFF);
- m_nExtraInfo = p->ExtraInfo();
+ if (p)
+ {
+ m_pPacket = p;
+ m_nChannel = p->Channel();
+ m_nCommand = p->Command();
+ m_nSNAC = p->SNAC();
+ m_nSubCommand = p->SubCommand();
+ m_nSequence = p->Sequence();
+ m_nSubSequence = p->SubSequence();
+ m_nSubType = (p->SNAC() & 0xFFFF);
+ m_nExtraInfo = p->ExtraInfo();
+ } else
+ {
+ m_pPacket = NULL;
+ m_nChannel = 0;
+ m_nCommand = 0;
+ m_nSNAC = 0;
+ m_nSubCommand = 0;
+ m_nSequence = 0;
+ m_nSubSequence = 0;
+ m_nSubType = 0;
+ m_nExtraInfo = 0;
+ }
m_nDestinationUin = 0;
m_szId = _szId ? strdup(_szId) : 0;
m_nPPID = _nPPID;
@@ -200,6 +214,20 @@
}
+//-----ICQEvent::AttachPacket---------------------------------------------------
+void ICQEvent::AttachPacket(CPacket *p)
+{
+ m_pPacket = p;
+ m_nChannel = p->Channel();
+ m_nCommand = p->Command();
+ m_nSNAC = p->SNAC();
+ m_nSubCommand = p->SubCommand();
+ m_nSequence = p->Sequence();
+ m_nSubSequence = p->SubSequence();
+ m_nSubType = (p->SNAC() & 0xFFFF);
+ m_nExtraInfo = p->ExtraInfo();
+}
+
//-----ICQEvent::CompareEvent---------------------------------------------------
bool ICQEvent::CompareEvent(int sockfd, unsigned short _nSequence) const
{
@@ -470,6 +498,15 @@
free(m_szZipCode);
}
+CRequestPicture::CRequestPicture(const char *szId)
+ : CSignal(PROTOxREQUESTxPICTURE, szId)
+{
+}
+
+CRequestPicture::~CRequestPicture()
+{
+}
+
CBlockUserSignal::CBlockUserSignal(const char *szId)
: CSignal(PROTOxBLOCKxUSER, szId)
{
diff -urN licq/src/icqpacket.cpp licq-ssbi/src/icqpacket.cpp
--- licq/src/icqpacket.cpp 2008-01-03 16:09:23.000000000 +0200
+++ licq-ssbi/src/icqpacket.cpp 2008-01-22 01:11:26.000000000 +0200
@@ -268,7 +268,8 @@
//======Server TCP============================================================
bool CSrvPacketTcp::s_bRegistered = false;
-unsigned short CSrvPacketTcp::s_nSequence = 0;
+unsigned short CSrvPacketTcp::s_nSequence[32] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
unsigned short CSrvPacketTcp::s_nSubSequence = 0;
pthread_mutex_t CSrvPacketTcp::s_xMutex = PTHREAD_MUTEX_INITIALIZER;
@@ -276,13 +277,14 @@
{
m_nChannel = nChannel;
pthread_mutex_lock(&s_xMutex);
- m_nSequence = s_nSequence++;
+ // will set m_nSequence later, in InitBuffer;
m_nSubSequence = s_nSubSequence++;
pthread_mutex_unlock(&s_xMutex);
m_nFamily = m_nSubType = m_nSubCommand = m_nExtraInfo = 0;
buffer = NULL;
m_nSize = 0;
+ m_nService = 0;
m_szSequenceOffset = NULL;
}
@@ -300,6 +302,13 @@
void CSrvPacketTcp::InitBuffer()
{
+ pthread_mutex_lock(&s_xMutex);
+ if (s_nSequence[m_nService] == 0xffff)
+ s_nSequence[m_nService] = rand() & 0x7fff;
+ m_nSequence = s_nSequence[m_nService]++;
+ s_nSequence[m_nService] &= 0x7fff;
+ pthread_mutex_unlock(&s_xMutex);
+
buffer = new CBuffer(m_nSize+6);
buffer->PackChar(0x2a);
buffer->PackChar(m_nChannel);
@@ -686,9 +695,8 @@
m_nSize = 4;
pthread_mutex_lock(&s_xMutex);
- s_nSequence = rand() & 0x7fff;
+ s_nSequence[m_nService] = 0xffff;
s_bRegistered = true;
- m_nSequence = s_nSequence++;
pthread_mutex_unlock(&s_xMutex);
InitBuffer();
@@ -792,9 +800,8 @@
pthread_mutex_lock(&s_xMutex);
if (!s_bRegistered) {
- s_nSequence = rand() & 0x7fff;
+ s_nSequence[m_nService] = 0xffff;
s_bRegistered = true;
- m_nSequence = s_nSequence++;
}
pthread_mutex_unlock(&s_xMutex);
@@ -847,13 +854,14 @@
}
//-----SendCookie------------------------------------------------------------
-CPU_SendCookie::CPU_SendCookie(const char *szCookie, int nLen)
+CPU_SendCookie::CPU_SendCookie(const char *szCookie, int nLen,
+ unsigned short nService)
: CSrvPacketTcp(ICQ_CHNxNEW)
{
+ m_nService = nService;
m_nSize = nLen + 8;
pthread_mutex_lock(&s_xMutex);
- s_nSequence = (rand() & 0x7fff);
- m_nSequence = s_nSequence++;
+ s_nSequence[m_nService] = 0xffff;
pthread_mutex_unlock(&s_xMutex);
InitBuffer();
@@ -887,7 +895,22 @@
buffer->PackUnsignedLongBE(0x000b0001);
}
-//-----ImICQ-----------------------------------------------------------------
+CPU_ImICQ::CPU_ImICQ(unsigned short VerArray[][2], unsigned short NumVer,
+ unsigned short nService)
+ : CPU_CommonFamily(ICQ_SNACxFAM_SERVICE, ICQ_SNACxSRV_IMxICQ)
+{
+ m_nService = nService;
+ m_nSize += NumVer * 4;
+ InitBuffer();
+
+ for (int i = 0; i < NumVer; i++)
+ {
+ buffer->PackUnsignedShortBE(VerArray[i][0]);
+ buffer->PackUnsignedShortBE(VerArray[i][1]);
+ }
+}
+
+//-----ImICQMode-------------------------------------------------------------
CPU_ICQMode::CPU_ICQMode(unsigned short channel, unsigned long flags)
: CPU_CommonFamily(ICQ_SNACxFAM_MESSAGE, ICQ_SNACxMSG_SETxICQxMODE)
{
@@ -907,9 +930,10 @@
}
//-----RateAck-----------------------------------------------------------------
-CPU_RateAck::CPU_RateAck()
+CPU_RateAck::CPU_RateAck(unsigned short nService)
: CPU_CommonFamily(ICQ_SNACxFAM_SERVICE, ICQ_SNACxSND_RATE_ACK)
{
+ m_nService = nService;
m_nSize += 10;
InitBuffer();
@@ -923,7 +947,7 @@
CPU_CapabilitySettings::CPU_CapabilitySettings()
: CPU_CommonFamily(ICQ_SNACxFAM_LOCATION, ICQ_SNACxLOC_SETxUSERxINFO)
{
- char data[7][CAP_LENGTH];
+ char data[8][CAP_LENGTH];
m_nSize += 4 + sizeof(data);
InitBuffer();
@@ -934,6 +958,7 @@
memcpy(data[4], ICQ_CAPABILITY_AIMxINTER, CAP_LENGTH);
memcpy(data[5], ICQ_CAPABILITY_RTFxMSGS, CAP_LENGTH);
memcpy(data[6], ICQ_CAPABILITY_ICHAT, CAP_LENGTH);
+ memcpy(data[7], ICQ_CAPABILITY_SSBI, CAP_LENGTH);
// Send our licq version
data[3][12] = INT_VERSION / 1000;
@@ -946,6 +971,40 @@
buffer->PackTLV(0x05, sizeof(data), (char *)data);
}
+//-----RequestBuddyIcon---------------------------------------------------------
+CPU_RequestBuddyIcon::CPU_RequestBuddyIcon(const char *_szId,
+ unsigned short _nBuddyIconType, char _nBuddyIconHashType,
+ const char *_szBuddyIconHash, unsigned short nService)
+ : CPU_CommonFamily(ICQ_SNACxFAM_SSBI, ICQ_SNACxSSBI_ICONxREQUEST)
+{
+ int nSize = strlen(_szId);
+ int nHashLenght = strlen(_szBuddyIconHash)/2;
+ char *Hash = new char[nHashLenght];
+ m_nService = nService;
+ m_nSize += 6 + nSize + nHashLenght;
+
+ InitBuffer();
+
+ buffer->PackChar(nSize);
+ buffer->Pack(_szId, nSize);
+ buffer->PackChar(0x01); // unknown, probably type of request
+ buffer->PackUnsignedShortBE(_nBuddyIconType);
+ buffer->PackChar(_nBuddyIconHashType);
+ buffer->PackChar(nHashLenght);
+ buffer->Pack(ReadHex(Hash, _szBuddyIconHash, nHashLenght), nHashLenght);
+}
+
+//-----RequestService-----------------------------------------------------------
+CPU_RequestService::CPU_RequestService(unsigned short nFam)
+ : CPU_CommonFamily(ICQ_SNACxFAM_SERVICE, ICQ_SNACxSUB_NEW_SERVICE)
+{
+ m_nSize += 2;
+
+ InitBuffer();
+
+ buffer->PackUnsignedShortBE(nFam);
+}
+
//-----SetPrivacy---------------------------------------------------------------
CPU_SetPrivacy::CPU_SetPrivacy(unsigned char _cPrivacy)
: CPU_CommonFamily(ICQ_SNACxFAM_LIST, ICQ_SNACxLIST_ROSTxUPD_GROUP)
@@ -1190,9 +1249,11 @@
buffer->Pack(uin, n);
}
-CPU_GenericFamily::CPU_GenericFamily(unsigned short Family, unsigned short SubType)
+CPU_GenericFamily::CPU_GenericFamily(unsigned short Family, unsigned short SubType,
+ unsigned short nService)
: CPU_CommonFamily(Family, SubType)
{
+ m_nService = nService;
m_nSize += 0;
InitBuffer();
}
@@ -1284,6 +1345,23 @@
#endif
}
+CPU_ClientReady::CPU_ClientReady(unsigned short VerArray[][4], unsigned short NumVer,
+ unsigned short nService)
+ : CPU_CommonFamily(ICQ_SNACxFAM_SERVICE, ICQ_SNACxSUB_READYxCLIENT)
+{
+ m_nService = nService;
+ m_nSize += NumVer * 8;
+ InitBuffer();
+
+ for (int i = 0; i < NumVer; i++)
+ {
+ buffer->PackUnsignedShortBE(VerArray[i][0]);
+ buffer->PackUnsignedShortBE(VerArray[i][1]);
+ buffer->PackUnsignedShortBE(VerArray[i][2]);
+ buffer->PackUnsignedShortBE(VerArray[i][3]);
+ }
+}
+
CPU_AckNameInfo::CPU_AckNameInfo()
: CPU_CommonFamily(ICQ_SNACxFAM_SERVICE, ICQ_SNACxSND_NAMExINFOxACK)
{
diff -urN licq/src/Makefile.am licq-ssbi/src/Makefile.am
--- licq/src/Makefile.am 2006-11-11 21:24:53.000000000 +0200
+++ licq-ssbi/src/Makefile.am 2008-01-22 01:11:26.000000000 +0200
@@ -11,7 +11,7 @@
bin_PROGRAMS = licq
licq_SOURCES = licq.cpp main.cpp \
icqpacket.cpp proxy.cpp socket.cpp icqd.cpp \
- icqd-tcp.cpp icqd-srv.cpp icqd-threads.cpp \
+ icqd-tcp.cpp icqd-srv.cpp icqd-threads.cpp oscarservice.cpp \
icqevent.cpp buffer.cpp user.cpp history.cpp \
utility.cpp countrycodes.c log.cpp translate.cpp \
file.cpp message.cpp support.c pthread_rdwr.c \
diff -urN licq/src/oscarservice.cpp licq-ssbi/src/oscarservice.cpp
--- licq/src/oscarservice.cpp 1970-01-01 03:00:00.000000000 +0300
+++ licq-ssbi/src/oscarservice.cpp 2008-01-22 01:11:46.000000000 +0200
@@ -0,0 +1,660 @@
+// -*- c-basic-offset: 2 -*-
+/* ----------------------------------------------------------------------------
+ * Licq - A ICQ Client for Unix
+ * Copyright (C) 2007 Licq developers
+ *
+ * This program is licensed under the terms found in the LICENSE file.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <cstdlib>
+#include <cstdio>
+
+// Localization
+#include "gettext.h"
+
+#include "licq_oscarservice.h"
+#include "licq_icqd.h"
+#include "licq_events.h"
+#include "licq_socket.h"
+#include "licq_proxy.h"
+#include "licq_packets.h"
+#include "licq_buffer.h"
+#include "licq_log.h"
+#include "support.h"
+
+COscarService::COscarService(CICQDaemon *Daemon, unsigned short Fam)
+{
+ myDaemon = Daemon;
+ myFam = Fam;
+ mySocketDesc = -1;
+ myProxy = NULL;
+ myStatus = STATUS_UNINITIALIZED;
+ myServer = NULL;
+ myCookie = NULL;
+ pthread_mutex_init(&mutex_sendqueue, NULL);
+ pthread_cond_init(&cond_sendqueue, NULL);
+ pthread_mutex_init(&mutex_status, NULL);
+ pthread_cond_init(&cond_status, NULL);
+}
+
+COscarService::~COscarService()
+{
+ if (myProxy) delete myProxy;
+ if (myServer) free(myServer);
+ if (myCookie) delete [] myCookie;
+}
+
+void COscarService::ChangeStatus(EOscarServiceStatus s)
+{
+ pthread_mutex_lock(&mutex_status);
+ myStatus = s;
+ pthread_cond_signal(&cond_status);
+ pthread_mutex_unlock(&mutex_status);
+}
+
+bool COscarService::WaitForStatus(EOscarServiceStatus s)
+{
+ pthread_mutex_lock(&mutex_status);
+
+ struct timespec ts;
+ ts.tv_nsec = 0;
+ //wait for 120 seconds
+ ts.tv_sec = time(NULL) + 120;
+
+ if (pthread_cond_timedwait(&cond_status, &mutex_status, &ts) == ETIMEDOUT)
+ {
+ pthread_mutex_unlock(&mutex_status);
+ return false;
+ }
+ if (myStatus == s)
+ {
+ pthread_mutex_unlock(&mutex_status);
+ return true;
+ }
+
+ pthread_mutex_unlock(&mutex_status);
+ return false;
+}
+
+void COscarService::SetConnectCredential(char *Server, unsigned short Port,
+ char *Cookie, unsigned short CookieLen)
+{
+ if (myServer) free(myServer);
+ myServer = strdup(Server);
+ myPort = Port;
+ if (myCookie) delete [] myCookie;
+ myCookie = new char[CookieLen];
+ memcpy(myCookie, Cookie, CookieLen);
+ myCookieLen = CookieLen;
+}
+
+bool COscarService::SendPacket(CPacket *p)
+{
+ INetSocket *s = gSocketManager.FetchSocket(mySocketDesc);
+ if (s == NULL) return false;
+ CBuffer *b = p->Finalize(s);
+ if (!s->Send(b))
+ {
+ char ErrorBuf[128];
+ s->ErrorStr(ErrorBuf, 128);
+ gLog.Warn(tr("%sError sending event (FAM #%02X, Subtype #%02X, Sequence #%hu):\n%s%s.\n"),
+ L_WARNxSTR, (unsigned short)((p->SNAC() >> 16) & 0xffff), (unsigned short)(p->SNAC() & 0xffff),
+ p->Sequence(), L_BLANKxSTR, ErrorBuf);
+ gSocketManager.DropSocket(s);
+ delete b;
+ return false;
+ }
+ gSocketManager.DropSocket(s);
+ delete b;
+ return true;
+}
+
+void COscarService::ClearQueue()
+{
+ pthread_mutex_lock(&mutex_sendqueue);
+ std::list<ICQEvent *>::iterator iter;
+ unsigned long i = mySendQueue.size();
+ for (iter = mySendQueue.begin(); i > 0; i--)
+ {
+ ICQEvent *e = *iter;
+ mySendQueue.erase(iter);
+ if (e != NULL)
+ {
+ gLog.Info("Event #%hu is still on the service 0x%02X queue!\n", e->Sequence(), myFam);
+ delete e;
+ }
+ }
+ pthread_mutex_unlock(&mutex_sendqueue);
+}
+
+unsigned long COscarService::SendEvent(const char *Id,
+ unsigned short SubType, bool Request)
+{
+ ICQEvent *e = new ICQEvent(myDaemon, mySocketDesc, NULL, CONNECT_SERVER,
+ Id, LICQ_PPID, NULL);
+ e->SetSubType(SubType);
+ if (Request)
+ myDaemon->PushEvent(e);
+ else
+ e->SetNoAck(true);
+ pthread_mutex_lock(&mutex_sendqueue);
+ mySendQueue.push_back(e);
+ pthread_cond_signal(&cond_sendqueue);
+ pthread_mutex_unlock(&mutex_sendqueue);
+
+ return e->EventId();
+}
+
+bool COscarService::SendSSBIFam(ICQEvent *e)
+{
+ switch (e->SubType())
+ {
+ case ICQ_SNACxSSBI_ICONxREQUEST:
+ {
+ ICQUser *u = gUserManager.FetchUser(e->Id(), LICQ_PPID, LOCK_R);
+ CPU_RequestBuddyIcon *p = new CPU_RequestBuddyIcon(e->Id(), u->BuddyIconType(),
+ u->BuddyIconHashType(), u->BuddyIconHash(), myFam);
+ gLog.Info(tr("%sRequesting buddy icon for %s (#%hu/#%d)...\n"),
+ L_SRVxSTR, u->GetAlias(), p->Sequence(), p->SubSequence());
+ gUserManager.DropUser(u);
+ e->AttachPacket(p);
+ return (SendPacket(p));
+ }
+
+ default:
+ gLog.Warn(tr("%sEvent with unsupported subtype (%02X) for FAM %02X failed.\n"),
+ L_WARNxSTR, e->SubType(), myFam);
+ return false;
+ }
+
+ return false;
+}
+
+bool COscarService::ProcessPacket(CBuffer &packet)
+{
+ unsigned short Len;
+ unsigned short Sequence;
+ char startCode, Channel;
+
+ // read in the serveice header info
+ packet >> startCode;
+
+ if (startCode != 0x2a)
+ {
+ gLog.Warn(tr("%sbad start code %d for packet in socket of service 0x%02X.\n"),
+ L_WARNxSTR, startCode, myFam);
+ return false;
+ }
+
+ packet >> Channel
+ >> Sequence
+ >> Len;
+
+ rev_e_short(Sequence);
+ rev_e_short(Len);
+
+ switch (Channel)
+ {
+ case ICQ_CHNxNEW:
+ ProcessNewChannel(packet);
+ break;
+
+ case ICQ_CHNxDATA:
+ ProcessDataChannel(packet);
+ break;
+
+ case ICQ_CHNxCLOSE:
+ gLog.Info(tr("%sServer send us request for close service 0x%02X.\n"),
+ L_SRVxSTR, myFam);
+ return false;
+ break;
+
+ default:
+ gLog.Warn(tr("%sPacket from unhandled channel %02x for service 0x%02X.\n"),
+ L_WARNxSTR, Channel, myFam);
+ break;
+ }
+
+ return true;
+}
+
+void COscarService::ProcessNewChannel(CBuffer &packet)
+{
+ unsigned long Version = packet.UnpackUnsignedLongBE();
+
+ if (Version != 0x00000001)
+ {
+ gLog.Warn(tr("%sPacket with wrong version (0x%08lx) from new channel for service 0x%02X.\n"),
+ L_WARNxSTR, Version, myFam);
+ }
+}
+
+void COscarService::ProcessDataChannel(CBuffer &packet)
+{
+ unsigned short Family, SubType, Flags;
+ unsigned long RequestId;
+
+ packet >> Family >> SubType >> Flags >> RequestId;
+ rev_e_short(Family);
+ rev_e_short(SubType);
+ rev_e_short(Flags);
+ rev_e_long(RequestId);
+
+ if (Flags & 0x8000) // version of the family that this SNAC, just ignore it
+ {
+ unsigned short len = packet.UnpackUnsignedShortBE();
+ packet.incDataPosRead(len);
+ }
+
+ switch (Family)
+ {
+ case ICQ_SNACxFAM_SERVICE:
+ ProcessServiceFam(packet, SubType, RequestId);
+ break;
+
+ case ICQ_SNACxFAM_SSBI:
+ if (myFam == ICQ_SNACxFAM_SSBI)
+ ProcessSSBIFam(packet, SubType, RequestId);
+ else
+ gLog.Warn(tr("%sUsupported family %04hx\n on data channel of service %02X.\n"),
+ L_WARNxSTR, Family, myFam);
+ break;
+
+ default:
+ gLog.Warn(tr("%sUnknown or usupported family %04hx\n on data channel of service %02X.\n"),
+ L_WARNxSTR, Family, myFam);
+ break;
+ }
+}
+
+void COscarService::ProcessServiceFam(CBuffer &packet, unsigned short SubType,
+ unsigned long RequestId)
+{
+ switch (SubType)
+ {
+ case ICQ_SNACxSUB_ERROR:
+ {
+ unsigned short err = packet.UnpackUnsignedShortBE();
+ unsigned short suberr = 0;
+
+ packet.readTLV();
+ if (packet.getTLVLen(0x0008) == 2)
+ suberr = packet.UnpackUnsignedShortTLV(0x0008);
+ gLog.Warn(tr("%sError #%02x.%02x in control FAM request (%ld) for service 0x%02X.\n"),
+ L_WARNxSTR, err, suberr, RequestId, myFam);
+ break;
+ }
+
+ case ICQ_SNACxSUB_READYxSERVER:
+ gLog.Info(tr("%sServer says he's ready for service 0x%02X.\n"),
+ L_SRVxSTR, myFam);
+ ChangeStatus(STATUS_SRV_READY_RECV);
+ break;
+
+ case ICQ_SNACxSRV_ACKxIMxICQ:
+ gLog.Info(tr("%sServer sent us channel capability list for service 0x%02X.\n"),
+ L_SRVxSTR, myFam);
+ ChangeStatus(STATUS_SRV_VER_RECV);
+ break;
+
+ case ICQ_SNACxSUB_RATE_INFO:
+ gLog.Info(tr("%sServer sent us rate-limits information for service 0x%02X.\n"),
+ L_SRVxSTR, myFam);
+ ChangeStatus(STATUS_SRV_RATE_RECV);
+ break;
+
+ default:
+ gLog.Warn(tr("%sUnknown or unsupported service FAM subtype 0x%02X for service 0x%02X.\n"),
+ L_WARNxSTR, SubType, myFam);
+ break;
+ }
+}
+
+void COscarService::ProcessSSBIFam(CBuffer &packet, unsigned short SubType,
+ unsigned long RequestId)
+{
+ switch (SubType)
+ {
+ case ICQ_SNACxSSBI_ERROR:
+ {
+ unsigned short err = packet.UnpackUnsignedShortBE();
+ unsigned short suberr = 0;
+
+ packet.readTLV();
+ if (packet.getTLVLen(0x0008) == 2)
+ suberr = packet.UnpackUnsignedShortTLV(0x0008);
+ gLog.Warn(tr("%sError #%02x.%02x in SSBI request (%ld) for service 0x%02X.\n"),
+ L_WARNxSTR, err, suberr, RequestId, myFam);
+
+ ICQEvent *e = myDaemon->DoneServerEvent(RequestId, EVENT_ERROR);
+ if (e)
+ myDaemon->ProcessDoneEvent(e);
+ break;
+ }
+
+ case ICQ_SNACxSSBI_ICONxREPLY:
+ {
+ char *Id = packet.UnpackUserString();
+ ICQUser *u = gUserManager.FetchUser(Id, LICQ_PPID, LOCK_W);
+ if (u == NULL)
+ {
+ gLog.Warn(tr("%sBuddy icon for unknown user (%s).\n"),
+ L_WARNxSTR, Id);
+ delete [] Id;
+ break;
+ }
+ delete [] Id;
+
+ unsigned short IconType = packet.UnpackUnsignedShortBE();
+ char HashType = packet.UnpackChar();
+ char HashLenght = packet.UnpackChar();
+ switch (IconType)
+ {
+ case 0x01: // Simple Buddy Icon
+ case 0x0C: // Photo Buddy Icon
+ if (HashType == 1 && HashLenght > 0 && HashLenght <= 16)
+ {
+ char *Hash = new char[HashLenght];
+ char *HashHex = new char[HashLenght*2 + 1];
+ packet.UnpackBinBlock(Hash, HashLenght);
+ packet.UnpackChar(); // unknown (command ?)
+ packet.UnpackUnsignedShortBE(); // IconType once more
+ packet.UnpackChar(); // HashType once more
+ char HashLenght2 = packet.UnpackChar(); // HashLenght once more
+ packet.incDataPosRead(HashLenght2); // Hash once more
+ u->SetOurBuddyIconHash(PrintHex(HashHex, Hash, HashLenght));
+ delete [] Hash;
+ delete [] HashHex;
+
+ gLog.Info(tr("%sBuddy icon reply for %s.\n"), L_SRVxSTR, u->GetAlias());
+ unsigned short IconLen = packet.UnpackUnsignedShortBE();
+ if (IconLen > 0) // do not create empty .pic files
+ {
+ char Filename[MAX_FILENAME_LEN];
+ Filename[MAX_FILENAME_LEN - 1] = '\0';
+ snprintf(Filename, MAX_FILENAME_LEN - 1, "%s/%s/%lu.pic",
+ BASE_DIR, USER_DIR, u->Uin());
+ int FD = open(Filename, O_WRONLY | O_CREAT | O_TRUNC, 00664);
+ if (FD == -1)
+ {
+ gLog.Error(tr("%sUnable to open picture file (%s):\n%s%s.\n"),
+ L_ERRORxSTR, Filename, L_BLANKxSTR, strerror(errno));
+ break;
+ }
+
+ char *Icon = new char[IconLen];
+ packet.UnpackBinBlock(Icon, IconLen);
+ write(FD, Icon, IconLen);
+ close(FD);
+ delete [] Icon;
+
+ u->SetEnableSave(false);
+ u->SetPicturePresent(true);
+ u->SetEnableSave(true);
+ }
+ u->SavePictureInfo();
+ myDaemon->PushPluginSignal(new CICQSignal(SIGNAL_UPDATExUSER, USER_PICTURE,
+ u->IdString(), u->PPID()));
+
+ ICQEvent *e = myDaemon->DoneServerEvent(RequestId, EVENT_SUCCESS);
+ if (e)
+ myDaemon->ProcessDoneEvent(e);
+ }
+ else
+ {
+ gLog.Warn(tr("%sBuddy icon reply for %s with wrong or unsupported hashtype (%d) or hashlenght (%d).\n"),
+ L_WARNxSTR, u->GetAlias(), HashType, HashLenght);
+ ICQEvent *e = myDaemon->DoneServerEvent(RequestId, EVENT_FAILED);
+ if (e)
+ myDaemon->ProcessDoneEvent(e);
+ }
+ break;
+
+ default:
+ gLog.Warn(tr("%sBuddy icon reply for %s with wrong or unsupported icontype (0x%02x).\n"),
+ L_WARNxSTR, u->GetAlias(), IconType);
+ ICQEvent *e = myDaemon->DoneServerEvent(RequestId, EVENT_FAILED);
+ if (e)
+ myDaemon->ProcessDoneEvent(e);
+ break;
+ }
+ gUserManager.DropUser(u);
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+bool COscarService::Initialize()
+{
+ ChangeStatus(STATUS_SERVICE_REQ_SENT);
+ myDaemon->icqRequestService(myFam);
+
+ if (!WaitForStatus(STATUS_SERVICE_REQ_ACKED))
+ {
+ gLog.Warn(tr("%sGive up waiting for redirect reply while initializing service 0x%02X.\n"),
+ L_WARNxSTR, myFam);
+ ChangeStatus(STATUS_UNINITIALIZED);
+ return false;
+ }
+
+ ChangeStatus(STATUS_CONNECTED);
+ SrvSocket *s = new SrvSocket(gUserManager.OwnerUin());
+ gLog.Info(tr("%sConnecting to separate server for service 0x%02X.\n"),
+ L_SRVxSTR, myFam);
+ if (myDaemon->GetProxy() == NULL)
+ {
+ if (myProxy != NULL)
+ {
+ delete myProxy;
+ myProxy = NULL;
+ }
+ }
+ else
+ {
+ if (myProxy == NULL)
+ myProxy = myDaemon->CreateProxy();
+ }
+ if (!s->ConnectTo(myServer, myPort, myProxy))
+ {
+ gLog.Warn(tr("%sCan't establish service 0x%02X socket.\n"),
+ L_WARNxSTR, myFam);
+ ChangeStatus(STATUS_UNINITIALIZED);
+ return false;
+ }
+ mySocketDesc = s->Descriptor();
+ gSocketManager.AddSocket(s);
+ gSocketManager.DropSocket(s);
+ // Alert the select thread that there is a new socket
+ write(myDaemon->pipe_newsocket[PIPE_WRITE], "S", 1);
+
+ CPU_SendCookie *p1 = new CPU_SendCookie(myCookie, myCookieLen, myFam);
+ gLog.Info(tr("%sSending cookie for service 0x%02X.\n"),
+ L_SRVxSTR, myFam);
+ if (!SendPacket(p1))
+ {
+ gLog.Warn(tr("%sCan't send cookie while initializing service 0x%02X.\n"),
+ L_WARNxSTR, myFam);
+ ChangeStatus(STATUS_UNINITIALIZED);
+ return false;
+ }
+
+ if (!WaitForStatus(STATUS_SRV_READY_RECV))
+ {
+ gLog.Warn(tr("%sGive up waiting for server ready packet while initializing service 0x%02X.\n"),
+ L_WARNxSTR, myFam);
+ ChangeStatus(STATUS_UNINITIALIZED);
+ return false;
+ }
+
+ unsigned short VerArray[2][2] = {{ 0x0001, 0x0004 }, // Service FAM
+ { 0x0010, 0x0001 }}; // SSBI FAM
+ CPU_ImICQ *p2 = new CPU_ImICQ(VerArray, 2, myFam);
+ gLog.Info(tr("%sSending our families versions for service 0x%02X.\n"),
+ L_SRVxSTR, myFam);
+ if (!SendPacket(p2))
+ {
+ gLog.Warn(tr("%sCan't send channel capability request while initializing service 0x%02X.\n"),
+ L_WARNxSTR, myFam);
+ ChangeStatus(STATUS_UNINITIALIZED);
+ return false;
+ }
+
+ if (!WaitForStatus(STATUS_SRV_VER_RECV))
+ {
+ gLog.Warn(tr("%sGive up waiting for channel capability list while initializing service 0x%02X.\n"),
+ L_WARNxSTR, myFam);
+ ChangeStatus(STATUS_UNINITIALIZED);
+ return false;
+ }
+
+ CPU_GenericFamily *p3 = new CPU_GenericFamily(ICQ_SNACxFAM_SERVICE,
+ ICQ_SNACxSUB_REQ_RATE_INFO, myFam);
+ gLog.Info(tr("%sSending request of rate-limits for service 0x%02X.\n"),
+ L_SRVxSTR, myFam);
+ if (!SendPacket(p3))
+ {
+ gLog.Warn(tr("%sCan't send request for rate-limits while initializing service 0x%02X.\n"),
+ L_WARNxSTR, myFam);
+ ChangeStatus(STATUS_UNINITIALIZED);
+ return false;
+ }
+
+ if (!WaitForStatus(STATUS_SRV_RATE_RECV))
+ {
+ gLog.Warn(tr("%sGive up waiting for rate-limits while initializing service 0x%02X.\n"),
+ L_WARNxSTR, myFam);
+ ChangeStatus(STATUS_UNINITIALIZED);
+ return false;
+ }
+
+ CPU_RateAck *p4 = new CPU_RateAck(myFam);
+ gLog.Info(tr("%sSending ack for rate-limits for service 0x%02X.\n"),
+ L_SRVxSTR, myFam);
+ if (!SendPacket(p4))
+ {
+ gLog.Warn(tr("%sCan't send rate-limits ack while initializing service 0x%02X.\n"),
+ L_WARNxSTR, myFam);
+ ChangeStatus(STATUS_UNINITIALIZED);
+ return false;
+ }
+ unsigned short VerArray2[2][4] = {{ 0x0001, 0x0004, 0x0110, 0x08e4 }, // Service FAM
+ { 0x0010, 0x0001, 0x0110, 0x08e4 }}; // SSBI FAM
+ CPU_ClientReady *p5 = new CPU_ClientReady(VerArray2, 2, myFam);
+ gLog.Info(tr("%sSending client ready for service 0x%02X.\n"),
+ L_SRVxSTR, myFam);
+ if (!SendPacket(p5))
+ {
+ gLog.Warn(tr("%sCan't send client ready while initializing service 0x%02X.\n"),
+ L_WARNxSTR, myFam);
+ ChangeStatus(STATUS_UNINITIALIZED);
+ return false;
+ }
+
+ ChangeStatus(STATUS_READY);
+ return true;
+}
+
+void *OscarServiceSendQueue_tep(void *p)
+{
+ pthread_detach(pthread_self());
+
+ COscarService *os = (COscarService *)p;
+ CICQDaemon *d = os->myDaemon;
+
+ while (true)
+ {
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, NULL);
+ pthread_mutex_lock(&os->mutex_sendqueue);
+ if (!os->mySendQueue.empty())
+ {
+ std::list<ICQEvent *>::iterator iter = os->mySendQueue.begin();
+ ICQEvent *e = *iter;
+ os->mySendQueue.erase(iter);
+ pthread_mutex_unlock(&os->mutex_sendqueue);
+
+ if (e->IsCancelled())
+ {
+ delete e;
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_testcancel();
+ continue;
+ }
+
+ if (d->Status() != STATUS_ONLINE)
+ {
+ gLog.Warn(tr("%sCan't send event for service 0x%02X because we are not online.\n"),
+ L_WARNxSTR, os->myFam);
+ if (d->DoneEvent(e, EVENT_ERROR) != NULL)
+ d->ProcessDoneEvent(e);
+ else
+ delete e;
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_testcancel();
+ continue;
+ }
+
+ if (os->mySocketDesc == -1)
+ {
+ gLog.Info(tr("%sInitializing socket for service 0x%02X.\n"), L_SRVxSTR, os->myFam);
+ if (!os->Initialize())
+ {
+ gLog.Warn(tr("%sInitialization of socket for service 0x%02X failed, failing event\n"),
+ L_WARNxSTR, os->myFam);
+ if (d->DoneEvent(e, EVENT_ERROR) != NULL)
+ d->ProcessDoneEvent(e);
+ else
+ delete e;
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_testcancel();
+ continue;
+ }
+ }
+
+ bool Sent;
+ switch (os->myFam)
+ {
+ case ICQ_SNACxFAM_SSBI:
+ Sent = os->SendSSBIFam(e);
+ break;
+
+ default:
+ gLog.Warn(tr("%sEvent for unknown or unsupported service 0x%02X failed.\n"),
+ L_WARNxSTR, os->myFam);
+ Sent = false;
+ break;
+ }
+
+ if (!Sent)
+ {
+ if (d->DoneEvent(e, EVENT_ERROR) != NULL)
+ d->ProcessDoneEvent(e);
+ else
+ delete e;
+ }
+
+ if (e->NoAck())
+ delete e;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_testcancel();
+ continue;
+ }
+ else
+ {
+ pthread_cond_wait(&os->cond_sendqueue, &os->mutex_sendqueue);
+ pthread_mutex_unlock(&os->mutex_sendqueue);
+ pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, NULL);
+ pthread_testcancel();
+ }
+ }
+
+ pthread_exit(NULL);
+}
diff -urN licq/src/socket.cpp licq-ssbi/src/socket.cpp
--- licq/src/socket.cpp 2007-10-22 16:20:56.000000000 +0300
+++ licq-ssbi/src/socket.cpp 2008-01-22 01:11:26.000000000 +0200
@@ -781,6 +781,50 @@
return (true);
}
+/*-----SrvSocket::ConnectTo--------------------------------------------------
+* Establish connection to server (through proxy or not)
+*---------------------------------------------------------------------------*/
+bool SrvSocket::ConnectTo(const char* server, unsigned short port,
+ ProxyServer *xProxy)
+{
+ char ipbuf[32];
+
+ if (xProxy == NULL)
+ {
+ gLog.Info(tr("%sResolving %s port %d...\n"), L_SRVxSTR, server, port);
+ if (!SetRemoteAddr(server, port)) {
+ char buf[128];
+ gLog.Warn(tr("%sUnable to resolve %s:\n%s%s.\n"), L_ERRORxSTR,
+ server, L_BLANKxSTR, ErrorStr(buf, 128));
+ return false;
+ }
+ gLog.Info(tr("%sICQ server found at %s:%d.\n"), L_SRVxSTR,
+ RemoteIpStr(ipbuf), RemotePort());
+ }
+ else
+ {
+ // It doesn't matter if it resolves or not, the proxy should do it then
+ SetProxy(xProxy);
+ SetRemoteAddr(server, port);
+ }
+
+ if (xProxy == NULL)
+ gLog.Info(tr("%sOpening socket to server.\n"), L_SRVxSTR);
+ else
+ gLog.Info(tr("%sOpening socket to server %s:%d via proxy.\n"),
+ L_SRVxSTR, server, port);
+ if (!OpenConnection())
+ {
+ char buf[128];
+ gLog.Warn(tr("%sUnable to connect to %s:%d:\n%s%s.\n"), L_ERRORxSTR,
+ RemoteIpStr(ipbuf), RemotePort(), L_BLANKxSTR,
+ ErrorStr(buf, 128));
+ return false;
+ }
+
+ return true;
+}
+
//=====TCPSocket===============================================================
TCPSocket::TCPSocket(unsigned long _nOwner) : INetSocket(_nOwner)
{
diff -urN licq/src/support.c licq-ssbi/src/support.c
--- licq/src/support.c 2006-08-10 21:17:45.000000000 +0300
+++ licq-ssbi/src/support.c 2008-01-22 01:11:26.000000000 +0200
@@ -112,6 +112,62 @@
return (nRet == -1) ? _nSize - 1 : nRet;
}
+char *PrintHex(char *szPrint, const char *szHex, size_t nSize)
+{
+ int i, j = 0;
+
+ for(i = 0; i < nSize ; i++)
+ {
+ unsigned char byte = (unsigned char)szHex[i];
+
+ unsigned char high = (byte >> 4) & 0x0f;
+ unsigned char low = byte & 0x0f;
+
+ if (high > 9)
+ szPrint[j++] = 'A' + (high - 10);
+ else
+ szPrint[j++] = '0' + high;
+
+ if (low > 9)
+ szPrint[j++] = 'A' + (low - 10);
+ else
+ szPrint[j++] = '0' + low;
+ }
+ szPrint[j] = '\0';
+
+ return szPrint;
+}
+
+char *ReadHex(char *szHex, const char *szRead, size_t nSize)
+{
+ int i, j = 0;
+ for(i = 0; i < nSize ; i++)
+ {
+ unsigned char digit, high, low;
+
+ if (szRead[j] == '\0') break;
+ digit = (unsigned char)szRead[j++];
+ high = 0;
+ if (digit >= 'A')
+ high = digit - 'A' + 10;
+ else if (digit >= '0')
+ high = digit - '0';
+ high <<= 4;
+
+ if (szRead[j] == '\0') break;
+ digit = (unsigned char)szRead[j++];
+ low = 0;
+ if (digit >= 'A')
+ low = digit - 'A' + 10;
+ else if (digit >= '0')
+ low = digit - '0';
+
+ szHex[i] = high + low;
+ }
+
+ return szHex;
+}
+
int Redirect(const char *_szFile)
{
int fd = open(_szFile, O_WRONLY | O_CREAT | O_APPEND, 00660);
diff -urN licq/src/support.h licq-ssbi/src/support.h
--- licq/src/support.h 2006-08-10 21:17:45.000000000 +0300
+++ licq-ssbi/src/support.h 2008-01-22 01:11:26.000000000 +0200
@@ -34,6 +34,9 @@
int UinString(char *_szBuf, size_t _nSize, unsigned long _nUin);
+char *PrintHex(char *szPrint, const char *szHex, size_t nSize);
+char *ReadHex(char *szHex, const char *szRead, size_t nSize);
+
int Redirect(const char *);
int strlen_safe(const char *);
diff -urN licq/src/user.cpp licq-ssbi/src/user.cpp
--- licq/src/user.cpp 2007-11-25 17:37:21.000000000 +0200
+++ licq-ssbi/src/user.cpp 2008-01-22 01:11:30.000000000 +0200
@@ -2011,8 +2011,15 @@
//-----ICQUser::LoadPictureInfo----------------------------------------------
void ICQUser::LoadPictureInfo()
{
+ char szTemp[MAX_LINE_LEN];
m_fConf.SetSection("user");
m_fConf.ReadBool("PicturePresent", m_bPicturePresent, false);
+ m_fConf.ReadNum("BuddyIconType", m_nBuddyIconType, 0);
+ m_fConf.ReadNum("BuddyIconHashType", m_nBuddyIconHashType, 0);
+ m_fConf.ReadStr("BuddyIconHash", szTemp, "");
+ SetString(&m_szBuddyIconHash, szTemp );
+ m_fConf.ReadStr("OurBuddyIconHash", szTemp, "");
+ SetString(&m_szOurBuddyIconHash, szTemp );
}
//-----ICQUser::LoadLicqInfo-------------------------------------------------
@@ -2333,6 +2340,10 @@
// Picture
m_bPicturePresent = false;
+ m_nBuddyIconType = 0;
+ m_nBuddyIconHashType = 0;
+ m_szBuddyIconHash = strdup("");
+ m_szOurBuddyIconHash = strdup("");
// GPG key
m_szGPGKey = strdup("");
@@ -3513,6 +3524,10 @@
}
m_fConf.SetSection("user");
m_fConf.WriteBool("PicturePresent", m_bPicturePresent);
+ m_fConf.WriteNum("BuddyIconType", m_nBuddyIconType);
+ m_fConf.WriteNum("BuddyIconHashType", m_nBuddyIconHashType);
+ m_fConf.WriteStr("BuddyIconHash", m_szBuddyIconHash);
+ m_fConf.WriteStr("OurBuddyIconHash", m_szOurBuddyIconHash);
if (!m_fConf.FlushFile())
{
gLog.Error("%sError opening '%s' for writing.\n%sSee log for details.\n",