diff options
Diffstat (limited to 'icqj_s7_sss_mod/fam_01service.c')
-rw-r--r-- | icqj_s7_sss_mod/fam_01service.c | 1352 |
1 files changed, 1352 insertions, 0 deletions
diff --git a/icqj_s7_sss_mod/fam_01service.c b/icqj_s7_sss_mod/fam_01service.c new file mode 100644 index 0000000..1cf22c6 --- /dev/null +++ b/icqj_s7_sss_mod/fam_01service.c @@ -0,0 +1,1352 @@ +// ---------------------------------------------------------------------------80
+// ICQ plugin for Miranda Instant Messenger
+// ________________________________________
+//
+// Copyright 2000,2001 Richard Hughes, Roland Rabien, Tristan Van de Vreede
+// Copyright 2001,2002 Jon Keating, Richard Hughes
+// Copyright 2002,2003,2004 Martin berg, Sam Kothari, Robert Rainwater
+// Copyright 2004,2005,2006,2007 Joe Kucera
+// Copyright 2006,2007,2008 [sss], chaos.persei, [sin], Faith Healer, Theif, nullbie
+// Copyright 2008 [sss], chaos.persei, nullbie, baloo, jarvis
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License
+// as published by the Free Software Foundation; either version 2
+// of the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+//
+// -----------------------------------------------------------------------------
+//
+// File name : $Source$
+// Revision : $Revision: 36 $
+// Last change on : $Date: 2007-08-05 03:45:10 +0300 (Вс, 05 авг 2007) $
+// Last change by : $Author: sss123next $
+//
+// DESCRIPTION:
+//
+// Describe me here please...
+//
+// -----------------------------------------------------------------------------
+
+#include "icqoscar.h"
+
+#define MD5_BLOCK_SIZE 1024*1024 // use 1MB blocks
+extern int gbIdleAllow;
+extern int icqGoingOnlineStatus;
+extern int pendingAvatarsStart;
+extern WORD wListenPort;
+extern CRITICAL_SECTION modeMsgsMutex;
+extern const capstr capXStatus[];
+extern const int moodXStatus[];
+
+extern char* detectUserClient(HANDLE hContact, DWORD dwUin, WORD wVersion, DWORD dwFT1, DWORD dwFT2, DWORD dwFT3, DWORD dwOnlineSince, BYTE bDirectFlag, DWORD dwDirectCookie, DWORD dwWebPort, BYTE* caps, WORD wLen, BYTE* bClientId, char* szClientBuf);
+
+void setUserInfo();
+
+char* calcMD5Hash(char* szFile);
+
+
+void handleServiceFam(unsigned char* pBuffer, WORD wBufferLength, snac_header* pSnacHeader, serverthread_info *info)
+{
+ icq_packet packet;
+
+ switch (pSnacHeader->wSubtype)
+ {
+
+ case ICQ_SERVER_READY:
+#ifdef _DEBUG
+ NetLog_Server("Server is ready and is requesting my Family versions");
+ NetLog_Server("Sending my Families");
+#endif
+
+ // This packet is a response to SRV_FAMILIES SNAC(1,3).
+ // This tells the server which SNAC families and their corresponding
+ // versions which the client understands. This also seems to identify
+ // the client as an ICQ vice AIM client to the server.
+ // Miranda mimics the behaviour of ICQ 6
+ serverPacketInit(&packet, 54);
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_FAMILIES);
+ packDWord(&packet, 0x00220001);
+ packDWord(&packet, 0x00010004);
+ packDWord(&packet, 0x00130004);
+ packDWord(&packet, 0x00020001);
+ packDWord(&packet, 0x00030001);
+ packDWord(&packet, 0x00150001);
+ packDWord(&packet, 0x00040001);
+ packDWord(&packet, 0x00060001);
+ packDWord(&packet, 0x00090001);
+ packDWord(&packet, 0x000a0001);
+ packDWord(&packet, 0x000b0001);
+ sendServPacket(&packet);
+ break;
+
+ case ICQ_SERVER_FAMILIES2:
+ /* This is a reply to CLI_FAMILIES and it tells the client which families and their versions that this server understands.
+ * We send a rate request packet */
+#ifdef _DEBUG
+ NetLog_Server("Server told me his Family versions");
+ NetLog_Server("Requesting Rate Information");
+#endif
+ serverPacketInit(&packet, 10);
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_REQ_RATE_INFO);
+ sendServPacket(&packet);
+ break;
+
+ case ICQ_SERVER_RATE_INFO:
+#ifdef _DEBUG
+ NetLog_Server("Server sent Rate Info");
+ NetLog_Server("Sending Rate Info Ack");
+#endif
+ /* init rates management */
+ gRates = ratesCreate(pBuffer, wBufferLength);
+ /* ack rate levels */
+ serverPacketInit(&packet, 20);
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_RATE_ACK);
+ packDWord(&packet, 0x00010002);
+ packDWord(&packet, 0x00030004);
+ packWord(&packet, 0x0005);
+ sendServPacket(&packet);
+
+ /* CLI_REQINFO - This command requests from the server certain information about the client that is stored on the server. */
+#ifdef _DEBUG
+ NetLog_Server("Sending CLI_REQINFO");
+#endif
+ serverPacketInit(&packet, 10);
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_REQINFO);
+ sendServPacket(&packet);
+
+ if (gbSsiEnabled)
+ {
+ DWORD dwLastUpdate;
+ WORD wRecordCount;
+ servlistcookie* ack;
+ DWORD dwCookie;
+
+ dwLastUpdate = ICQGetContactSettingDword(NULL, "SrvLastUpdate", 0);
+ wRecordCount = ICQGetContactSettingWord(NULL, "SrvRecordCount", 0);
+
+ // CLI_REQLISTS - we want to use SSI
+#ifdef _DEBUG
+ NetLog_Server("Requesting roster rights");
+#endif
+ serverPacketInit(&packet, 16);
+ packFNACHeader(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_REQLISTS);
+ packTLVWord(&packet, 0x0B, 0x000F); // mimic ICQ 6
+ sendServPacket(&packet);
+
+ if (!wRecordCount) // CLI_REQROSTER
+ { // we do not have any data - request full list
+#ifdef _DEBUG
+ NetLog_Server("Requesting full roster");
+#endif
+ serverPacketInit(&packet, 10);
+ ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+ if (ack)
+ { // we try to use standalone cookie if available
+ ack->dwAction = SSA_CHECK_ROSTER; // loading list
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_CLI_REQUEST, 0, ack);
+ }
+ else // if not use that old fake
+ dwCookie = ICQ_LISTS_CLI_REQUEST<<0x10;
+
+ packFNACHeaderFull(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_REQUEST, 0, dwCookie);
+ sendServPacket(&packet);
+ }
+ else // CLI_CHECKROSTER
+ {
+#ifdef _DEBUG
+ NetLog_Server("Requesting roster check");
+#endif
+ serverPacketInit(&packet, 16);
+ ack = (servlistcookie*)SAFE_MALLOC(sizeof(servlistcookie));
+ if (ack) // TODO: rewrite - use get list service for empty list
+ { // we try to use standalone cookie if available
+ ack->dwAction = SSA_CHECK_ROSTER; // loading list
+ dwCookie = AllocateCookie(CKT_SERVERLIST, ICQ_LISTS_CLI_CHECK, 0, ack);
+ }
+ else // if not use that old fake
+ dwCookie = ICQ_LISTS_CLI_CHECK<<0x10;
+
+ packFNACHeaderFull(&packet, ICQ_LISTS_FAMILY, ICQ_LISTS_CLI_CHECK, 0, dwCookie);
+ // check if it was not changed elsewhere (force reload, set that setting to zero)
+ if (IsServerGroupsDefined())
+ {
+ packDWord(&packet, dwLastUpdate); // last saved time
+ packWord(&packet, wRecordCount); // number of records saved
+ }
+ else
+ { // we need to get groups info into DB, force receive list
+ packDWord(&packet, 0); // last saved time
+ packWord(&packet, 0); // number of records saved
+ }
+ sendServPacket(&packet);
+ }
+ }
+
+ // CLI_REQLOCATION
+#ifdef _DEBUG
+ NetLog_Server("Requesting Location rights");
+#endif
+ serverPacketInit(&packet, 10);
+ packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_CLI_REQ_RIGHTS);
+ sendServPacket(&packet);
+
+ // CLI_REQBUDDY
+#ifdef _DEBUG
+ NetLog_Server("Requesting Client-side contactlist rights");
+#endif
+ serverPacketInit(&packet, 16);
+ packFNACHeader(&packet, ICQ_BUDDY_FAMILY, ICQ_USER_CLI_REQBUDDY);
+ packTLVWord(&packet, 0x05, 0x0003); // mimic ICQ 6
+ sendServPacket(&packet);
+
+ // CLI_REQICBM
+#ifdef _DEBUG
+ NetLog_Server("Sending CLI_REQICBM");
+#endif
+ serverPacketInit(&packet, 10);
+ packFNACHeader(&packet, ICQ_MSG_FAMILY, ICQ_MSG_CLI_REQICBM);
+ sendServPacket(&packet);
+
+ // CLI_REQBOS
+#ifdef _DEBUG
+ NetLog_Server("Sending CLI_REQBOS");
+#endif
+ serverPacketInit(&packet, 10);
+ packFNACHeader(&packet, ICQ_BOS_FAMILY, ICQ_PRIVACY_REQ_RIGHTS);
+ sendServPacket(&packet);
+ break;
+
+ case ICQ_SERVER_PAUSE:
+ NetLog_Server("Server is going down in a few seconds... (Flags: %u)", pSnacHeader->wFlags);
+ // This is the list of groups that we want to have on the next server
+ serverPacketInit(&packet, 30);
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_PAUSE_ACK);
+ packWord(&packet,ICQ_SERVICE_FAMILY);
+ packWord(&packet,ICQ_LISTS_FAMILY);
+ packWord(&packet,ICQ_LOCATION_FAMILY);
+ packWord(&packet,ICQ_BUDDY_FAMILY);
+ packWord(&packet,ICQ_EXTENSIONS_FAMILY);
+ packWord(&packet,ICQ_MSG_FAMILY);
+ packWord(&packet,0x06);
+ packWord(&packet,ICQ_BOS_FAMILY);
+ packWord(&packet,ICQ_LOOKUP_FAMILY);
+ packWord(&packet,ICQ_STATS_FAMILY);
+ sendServPacket(&packet);
+#ifdef _DEBUG
+ NetLog_Server("Sent server pause ack");
+#endif
+ break;
+
+ case ICQ_SERVER_MIGRATIONREQ:
+ {
+ oscar_tlv_chain *chain = NULL;
+
+#ifdef _DEBUG
+ NetLog_Server("Server migration requested (Flags: %u)", pSnacHeader->wFlags);
+#endif
+ pBuffer += 2; // Unknown, seen: 0
+ wBufferLength -= 2;
+ chain = readIntoTLVChain(&pBuffer, wBufferLength, 0);
+
+ if (info->cookieDataLen > 0)
+ SAFE_FREE(&info->cookieData);
+
+ info->newServer = getStrFromChain(chain, 0x05, 1);
+ info->cookieData = getStrFromChain(chain, 0x06, 1);
+ info->cookieDataLen = getLenFromChain(chain, 0x06, 1);
+
+ if (!info->newServer || !info->cookieData)
+ {
+ icq_LogMessage(LOG_FATAL, "A server migration has failed because the server returned invalid data. You must reconnect manually.");
+ SAFE_FREE(&info->newServer);
+ SAFE_FREE(&info->cookieData);
+ info->cookieDataLen = 0;
+ info->newServerReady = 0;
+ return;
+ }
+
+ disposeChain(&chain);
+ NetLog_Server("Migration has started. New server will be %s", info->newServer);
+
+ icqGoingOnlineStatus = gnCurrentStatus;
+ SetCurrentStatus(ID_STATUS_CONNECTING); // revert to connecting state
+
+ info->newServerReady = 1;
+ info->isMigrating = 1;
+ }
+ break;
+
+ case ICQ_SERVER_NAME_INFO: // This is the reply to CLI_REQINFO
+ {
+ BYTE bUinLen;
+ oscar_tlv_chain *chain;
+
+#ifdef _DEBUG
+ NetLog_Server("Received self info");
+#endif
+ unpackByte(&pBuffer, &bUinLen);
+ pBuffer += bUinLen;
+ pBuffer += 4; /* warning level & user class */
+ wBufferLength -= 5 + bUinLen;
+
+ if (pSnacHeader->dwRef == ICQ_CLIENT_REQINFO<<0x10)
+ { // This is during the login sequence
+ DWORD dwValue;
+
+ // TLV(x01) User type?
+ // TLV(x0C) Empty CLI2CLI Direct connection info
+ // TLV(x0A) External IP
+ // TLV(x0F) Number of seconds that user has been online
+ // TLV(x03) The online since time.
+ // TLV(x0A) External IP again
+ // TLV(x22) Unknown
+ // TLV(x1E) Unknown: empty.
+ // TLV(x05) Member of ICQ since.
+ // TLV(x14) Unknown
+ chain = readIntoTLVChain(&pBuffer, wBufferLength, 0);
+
+ // Save external IP
+ dwValue = getDWordFromChain(chain, 10, 1);
+ ICQWriteContactSettingDword(NULL, "IP", dwValue);
+ ICQWriteContactSettingDword(NULL, "OldIP", dwValue);
+
+ // Save member since timestamp
+ dwValue = getDWordFromChain(chain, 5, 1);
+ if (dwValue) ICQWriteContactSettingDword(NULL, "MemberTS", dwValue);
+
+ dwValue = getDWordFromChain(chain, 3, 1);
+ ICQWriteContactSettingDword(NULL, "LogonTS", dwValue ? dwValue : time(NULL));
+
+ disposeChain(&chain);
+
+ // If we are in SSI mode, this is sent after the list is acked instead
+ // to make sure that we don't set status before seing the visibility code
+ if (!gbSsiEnabled || info->isMigrating)
+ handleServUINSettings(wListenPort, info);
+ }
+ }
+ break;
+
+ case ICQ_SERVER_RATE_CHANGE:
+
+ if (wBufferLength >= 2)
+ {
+ WORD wStatus;
+ WORD wClass;
+ DWORD dwLevel;
+ // We now have global rate management, although controlled are only some
+ // areas. This should not arrive in most cases. If it does, update our
+ // local rate levels & issue broadcast.
+ unpackWord(&pBuffer, &wStatus);
+ unpackWord(&pBuffer, &wClass);
+ pBuffer += 20;
+ unpackDWord(&pBuffer, &dwLevel);
+ EnterCriticalSection(&ratesMutex);
+ ratesUpdateLevel(gRates, wClass, dwLevel);
+ LeaveCriticalSection(&ratesMutex);
+
+ if (wStatus == 2 || wStatus == 3)
+ { // this is only the simplest solution, needs rate management to every section
+ ICQBroadcastAck(NULL, ICQACKTYPE_RATEWARNING, ACKRESULT_STATUS, (HANDLE)wClass, wStatus);
+ if (wStatus == 2)
+ NetLog_Server("Rates #%u: Alert", wClass);
+ else
+ NetLog_Server("Rates #%u: Limit", wClass);
+ }
+ else if (wStatus == 4)
+ {
+ ICQBroadcastAck(NULL, ICQACKTYPE_RATEWARNING, ACKRESULT_STATUS, (HANDLE)wClass, wStatus);
+ NetLog_Server("Rates #%u: Clear", wClass);
+ }
+ icq_CheckSpeed(wStatus);
+ }
+
+ break;
+
+ case ICQ_SERVER_REDIRECT_SERVICE: // reply to family request, got new connection point
+ {
+ oscar_tlv_chain* pChain = NULL;
+ WORD wFamily;
+ familyrequest_rec* reqdata;
+
+ if (!(pChain = readIntoTLVChain(&pBuffer, wBufferLength, 0)))
+ {
+ NetLog_Server("Received Broken Redirect Service SNAC(1,5).");
+ break;
+ }
+ wFamily = getWordFromChain(pChain, 0x0D, 1);
+
+ // pick request data
+ if ((!FindCookie(pSnacHeader->dwRef, NULL, &reqdata)) || (reqdata->wFamily != wFamily))
+ {
+ disposeChain(&pChain);
+ NetLog_Server("Received unexpected SNAC(1,5), skipping.");
+ break;
+ }
+
+ FreeCookie(pSnacHeader->dwRef);
+
+ { // new family entry point received
+ char* pServer;
+ WORD wPort;
+ char* pCookie;
+ WORD wCookieLen;
+ NETLIBOPENCONNECTION nloc = {0};
+ HANDLE hConnection;
+
+ pServer = getStrFromChain(pChain, 0x05, 1);
+ pCookie = getStrFromChain(pChain, 0x06, 1);
+ wCookieLen = getLenFromChain(pChain, 0x06, 1);
+
+ if (!pServer || !pCookie)
+ {
+ NetLog_Server("Server returned invalid data, family unavailable.");
+
+ SAFE_FREE(&pServer);
+ SAFE_FREE(&pCookie);
+ SAFE_FREE(&reqdata);
+ break;
+ }
+
+ // Get new family server ip and port
+ wPort = info->wServerPort; // get default port
+ parseServerAddress(pServer, &wPort);
+
+ // establish connection
+ nloc.flags = 0;
+ nloc.szHost = pServer;
+ nloc.wPort = wPort;
+
+ hConnection = NetLib_OpenConnection(ghServerNetlibUser, wFamily == ICQ_AVATAR_FAMILY ? "Avatar " : NULL, &nloc);
+
+ if (hConnection == NULL)
+ {
+ NetLog_Server("Unable to connect to ICQ new family server.");
+ } // we want the handler to be called even if the connecting failed
+ reqdata->familyhandler(hConnection, pCookie, wCookieLen);
+
+ // Free allocated memory
+ // NOTE: "cookie" will get freed when we have connected to the avatar server.
+ disposeChain(&pChain);
+ SAFE_FREE(&pServer);
+ SAFE_FREE(&reqdata);
+ }
+
+ break;
+ }
+
+ case ICQ_SERVER_EXTSTATUS: // our avatar
+ {
+ NetLog_Server("Received our avatar hash & status.");
+
+ if (wBufferLength > 4 && pBuffer[1] == AVATAR_HASH_PHOTO)
+ { // skip photo item
+ if (wBufferLength >= pBuffer[3] + 4)
+ {
+ wBufferLength -= pBuffer[3] + 4;
+ pBuffer += pBuffer[3] + 4;
+ }
+ else
+ {
+ pBuffer += wBufferLength;
+ wBufferLength = 0;
+ }
+ }
+
+ if ((wBufferLength >= 0x14) && gbAvatarsEnabled)
+ {
+ if (!info->bMyAvatarInited) // signal the server after login
+ { // this refreshes avatar state - it used to work automatically, but now it does not
+ if (ICQGetContactSettingByte(NULL, "ForceOurAvatar", 0))
+ { // keep our avatar
+ char* file = loadMyAvatarFileName();
+
+ IcqSetMyAvatar(0, (LPARAM)file);
+ SAFE_FREE(&file);
+ }
+ else // only change avatar hash to the same one
+ {
+ char hash[0x14];
+
+ memcpy(hash, pBuffer, 0x14);
+ hash[2] = 1; // update image status
+ updateServAvatarHash(hash, 0x14);
+ }
+ info->bMyAvatarInited = TRUE;
+ break;
+ }
+
+ switch (pBuffer[2])
+ {
+ case 1: // our avatar is on the server
+ {
+ char* file;
+ char* hash;
+
+ ICQWriteContactSettingBlob(NULL, "AvatarHash", pBuffer, 0x14);
+
+ setUserInfo();
+ // here we need to find a file, check its hash, if invalid get avatar from server
+ file = loadMyAvatarFileName();
+ if (!file)
+ { // we have no avatar file, download from server
+ char szFile[MAX_PATH + 4];
+#ifdef _DEBUG
+ NetLog_Server("We have no avatar, requesting from server.");
+#endif
+ GetAvatarFileName(0, NULL, szFile, MAX_PATH);
+ GetAvatarData(NULL, dwLocalUIN, NULL, pBuffer, 0x14, szFile);
+ }
+ else
+ { // we know avatar filename
+ hash = calcMD5Hash(file);
+ if (!hash)
+ { // hash could not be calculated - probably missing file, get avatar from server
+ char szFile[MAX_PATH + 4];
+#ifdef _DEBUG
+ NetLog_Server("We have no avatar, requesting from server.");
+#endif
+ GetAvatarFileName(0, NULL, szFile, MAX_PATH);
+ GetAvatarData(NULL, dwLocalUIN, NULL, pBuffer, 0x14, szFile);
+ } // check if we had set any avatar if yes set our, if not download from server
+ else if (memcmp(hash, pBuffer+4, 0x10))
+ { // we have different avatar, sync that
+ if (ICQGetContactSettingByte(NULL, "ForceOurAvatar", 1))
+ { // we want our avatar, update hash
+ DWORD dwPaFormat = DetectAvatarFormat(file);
+ char* pHash = _alloca(0x14);
+
+ NetLog_Server("Our avatar is different, set our new hash.");
+
+ pHash[0] = 0;
+ pHash[1] = dwPaFormat == PA_FORMAT_XML ? AVATAR_HASH_FLASH : AVATAR_HASH_STATIC;
+ pHash[2] = 1; // state of the hash
+ pHash[3] = 0x10; // len of the hash
+ memcpy(pHash + 4, hash, 0x10);
+ updateServAvatarHash(pHash, 0x14);
+ }
+ else
+ { // get avatar from server
+ char szFile[MAX_PATH + 4];
+#ifdef _DEBUG
+ NetLog_Server("We have different avatar, requesting new from server.");
+#endif
+ GetAvatarFileName(0, NULL, szFile, MAX_PATH);
+ GetAvatarData(NULL, dwLocalUIN, NULL, pBuffer, 0x14, szFile);
+ }
+ }
+ SAFE_FREE(&hash);
+ SAFE_FREE(&file);
+ }
+ break;
+ }
+ case 0x41: // request to upload avatar data
+ case 0x81:
+ { // request to re-upload avatar data
+ char* file;
+ char* hash;
+ DWORD dwPaFormat;
+
+ if (!gbSsiEnabled) break; // we could not change serv-list if it is disabled...
+
+ file = loadMyAvatarFileName();
+ if (!file)
+ { // we have no file to upload, remove hash from server
+ NetLog_Server("We do not have avatar, removing hash.");
+ IcqSetMyAvatar(0, 0);
+ break;
+ }
+ dwPaFormat = DetectAvatarFormat(file);
+ hash = calcMD5Hash(file);
+ if (!hash)
+ { // the hash could not be calculated, remove from server
+ NetLog_Server("We could not obtain hash, removing hash.");
+ IcqSetMyAvatar(0, 0);
+ }
+ else if (!memcmp(hash, pBuffer+4, 0x10))
+ { // we have the right file
+ HANDLE hFile = NULL, hMap = NULL;
+ BYTE* ppMap = NULL;
+ long cbFileSize = 0;
+
+ NetLog_Server("Uploading our avatar data.");
+
+ if ((hFile = CreateFile(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL )) != INVALID_HANDLE_VALUE)
+ if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
+ if ((ppMap = (BYTE*)MapViewOfFile(hMap, FILE_MAP_READ, 0, 0, 0)) != NULL)
+ cbFileSize = GetFileSize( hFile, NULL );
+
+ if (cbFileSize != 0)
+ {
+ SetAvatarData(NULL, (WORD)(dwPaFormat == PA_FORMAT_XML ? AVATAR_HASH_FLASH : AVATAR_HASH_STATIC), ppMap, cbFileSize);
+ }
+
+ if (ppMap != NULL) UnmapViewOfFile(ppMap);
+ if (hMap != NULL) CloseHandle(hMap);
+ if (hFile != NULL) CloseHandle(hFile);
+ SAFE_FREE(&hash);
+ }
+ else
+ {
+ char* pHash = _alloca(0x14);
+
+ NetLog_Server("Our file is different, set our new hash.");
+
+ pHash[0] = 0;
+ pHash[1] = dwPaFormat == PA_FORMAT_XML ? AVATAR_HASH_FLASH : AVATAR_HASH_STATIC;
+ pHash[2] = 1; // state of the hash
+ pHash[3] = 0x10; // len of the hash
+ memcpy(pHash + 4, hash, 0x10);
+ updateServAvatarHash(pHash, 0x14);
+
+ SAFE_FREE(&hash);
+ }
+
+ SAFE_FREE(&file);
+ break;
+ default:
+ NetLog_Server("Received UNKNOWN Avatar Status.");
+ }
+ }
+ }
+ break;
+ }
+
+ case ICQ_ERROR:
+ { // Something went wrong, probably the request for avatar family failed
+ WORD wError;
+
+ if (wBufferLength >= 2)
+ unpackWord(&pBuffer, &wError);
+ else
+ wError = 0;
+
+ LogFamilyError(ICQ_SERVICE_FAMILY, wError);
+ break;
+ }
+
+ // Stuff we don't care about
+ case ICQ_SERVER_MOTD:
+#ifdef _DEBUG
+ NetLog_Server("Server message of the day");
+#endif
+ break;
+
+ default:
+ NetLog_Server("Warning: Ignoring SNAC(x%02x,x%02x) - Unknown SNAC (Flags: %u, Ref: %u)", ICQ_SERVICE_FAMILY, pSnacHeader->wSubtype, pSnacHeader->wFlags, pSnacHeader->dwRef);
+ break;
+
+ }
+}
+
+
+
+
+char* calcMD5Hash(char* szFile)
+{
+ char* res = NULL;
+
+ if (szFile)
+ {
+ HANDLE hFile = NULL, hMap = NULL;
+ BYTE* ppMap = NULL;
+
+ if ((hFile = CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL )) != INVALID_HANDLE_VALUE)
+ {
+ if ((hMap = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL)) != NULL)
+ {
+ long cbFileSize = GetFileSize( hFile, NULL );
+ res = (char*)SAFE_MALLOC(16*sizeof(char));
+ if (cbFileSize != 0 && res)
+ {
+ mir_md5_state_t state;
+ mir_md5_byte_t digest[16];
+ int dwOffset = 0;
+ mir_md5_init(&state);
+ while (dwOffset < cbFileSize)
+ {
+ int dwBlockSize = min(MD5_BLOCK_SIZE, cbFileSize-dwOffset);
+ if (!(ppMap = (BYTE*)MapViewOfFile(hMap, FILE_MAP_READ, 0, dwOffset, dwBlockSize)))
+ break;
+ mir_md5_append(&state, (const mir_md5_byte_t *)ppMap, dwBlockSize);
+ UnmapViewOfFile(ppMap);
+ dwOffset += dwBlockSize;
+ }
+ mir_md5_finish(&state, digest);
+ memcpy(res, digest, 16);
+ }
+ }
+ }
+
+
+ if (hMap != NULL) CloseHandle(hMap);
+ if (hFile != NULL) CloseHandle(hFile);
+ }
+
+ return res;
+}
+
+
+static char* buildUinList(int subtype, WORD wMaxLen, HANDLE* hContactResume)
+{
+ char* szList;
+ HANDLE hContact;
+ WORD wCurrentLen = 0;
+ DWORD dwUIN;
+ uid_str szUID;
+ char szLen[2];
+ int add;
+
+
+ szList = (char*)SAFE_MALLOC(CallService(MS_DB_CONTACT_GETCOUNT, 0, 0) * UINMAXLEN);
+ szLen[1] = '\0';
+
+ if (*hContactResume)
+ hContact = *hContactResume;
+ else
+ hContact = ICQFindFirstContact();
+
+ while (hContact != NULL)
+ {
+ if (!ICQGetContactSettingUID(hContact, &dwUIN, &szUID))
+ {
+ szLen[0] = strlennull(strUID(dwUIN, szUID));
+
+ switch (subtype)
+ {
+
+ case BUL_VISIBLE:
+ add = ID_STATUS_ONLINE == ICQGetContactSettingWord(hContact, "ApparentMode", 0);
+ break;
+
+ case BUL_INVISIBLE:
+ add = ID_STATUS_OFFLINE == ICQGetContactSettingWord(hContact, "ApparentMode", 0);
+ break;
+
+ case BUL_TEMPVISIBLE:
+ add = ICQGetContactSettingByte(hContact, "TemporaryVisible", 0);
+ // clear temporary flag
+ // Here we assume that all temporary contacts will be in one packet
+ ICQWriteContactSettingByte(hContact, "TemporaryVisible", 0);
+ break;
+
+ default:
+ add = 1;
+
+ // If we are in SS mode, we only add those contacts that are
+ // not in our SS list, or are awaiting authorization, to our
+ // client side list
+ if (gbSsiEnabled && ICQGetContactSettingWord(hContact, "ServerId", 0) &&
+ !ICQGetContactSettingByte(hContact, "Auth", 0))
+ add = 0;
+
+ // Never add hidden contacts to CS list
+ if (DBGetContactSettingByte(hContact, "CList", "Hidden", 0))
+ add = 0;
+
+ break;
+ }
+
+ if (add)
+ {
+ wCurrentLen += szLen[0] + 1;
+ if (wCurrentLen > wMaxLen)
+ {
+ *hContactResume = hContact;
+ return szList;
+ }
+
+ strcat(szList, szLen);
+ strcat(szList, szUID);
+ }
+ }
+
+ hContact = ICQFindNextContact(hContact);
+ }
+ *hContactResume = NULL;
+
+
+ return szList;
+}
+
+
+
+void sendEntireListServ(WORD wFamily, WORD wSubtype, int listType)
+{
+ HANDLE hResumeContact;
+ char* szList;
+ int nListLen;
+ icq_packet packet;
+
+
+ hResumeContact = NULL;
+
+ do
+ { // server doesn't seem to be able to cope with packets larger than 8k
+ // send only about 100contacts per packet
+ szList = buildUinList(listType, 0x3E8, &hResumeContact);
+ nListLen = strlennull(szList);
+
+ if (nListLen)
+ {
+ serverPacketInit(&packet, (WORD)(nListLen + 10));
+ packFNACHeader(&packet, wFamily, wSubtype);
+ packBuffer(&packet, szList, (WORD)nListLen);
+ sendServPacket(&packet);
+ }
+
+ SAFE_FREE(&szList);
+ }
+ while (hResumeContact);
+}
+
+
+
+
+void setUserInfo()
+{ // CLI_SETUSERINFO
+ icq_packet packet;
+ WORD wAdditionalData = 0;
+ BYTE bXStatus = ICQGetContactXStatus(NULL);
+ BYTE cID = DBGetContactSettingWord(NULL, gpszICQProtoName, "CurrentID", 0);
+ BYTE cICQModID = DBGetContactSettingWord(NULL, gpszICQProtoName, "CurrentICQModID", 0); // eternity BYTE
+
+ static char wID[] ={ 4, 1, 8, 0, 4, 1, 1, 1, 1, 1, 1, 4,//12
+ 10, 10, 10, 10, 1, 1, 2, 0, 1, 0, 0, 6,//24
+ 6, 1, 12, 2, 1, 0, 0, 0, 0, 0, 1, 4,//36
+ 0, 0, 0, 0, 1, 3, 2, 2, 1, 1, 8, 0,//48
+ 0, 1, 3, 0, 0, 0,//54
+ 4}; // 55 xo) last is MirandaMobile
+
+/* commented out, possibly fixed already
+ { // fix for setting alpha build flag, dunno why it's not retaken from init.c
+ char szVer[MAX_PATH];
+ CallService(MS_SYSTEM_GETVERSIONTEXT, MAX_PATH, (LPARAM)szVer);
+ _strlwr(szVer); // make sure it is lowercase
+ if (strstr(szVer, "alpha") != NULL) // Are we running under Alpha Core
+ MIRANDA_VERSION |= 0x80000000;
+ }
+*/
+
+ if(!cID||cID==11||cID==54)
+ { // if miranda, as 'miranda' or as 'mirandamobile'
+#ifdef DBG_XTRAZ_MUC
+ wAdditionalData += 16;
+#endif
+ if(gbAimEnabled)
+ wAdditionalData += 16;
+ if(gbAvatarsEnabled)
+ wAdditionalData += 16;
+ if(gbUtfEnabled)
+ wAdditionalData += 16;
+ if(gbRTFEnabled)
+ wAdditionalData += 16;
+ if(gbXStatusEnabled)
+ wAdditionalData += 16;
+ if(gbTzerEnabled)
+ wAdditionalData += 16;
+ if(bXStatus)
+ wAdditionalData += 16;
+#ifdef DBG_AIMCONTACTSEND
+ wAdditionalData += 16;
+#endif
+ }
+ else if(gbHideIdEnabled)
+ wAdditionalData += 16;
+ wAdditionalData += wID[cID]*16;
+ if(gbCustomCapEnabled)
+ {
+ wAdditionalData += 16 * lstCustomCaps->realCount;
+ }
+ if(cID==2||cID==23||cID==24||cID==46) //qip caps
+ {
+ if(gbXStatusEnabled)
+ wAdditionalData += 16;
+ if(bXStatus)
+ wAdditionalData += 16;
+ }
+ if(cID>=12&&cID<=15||cID==26) //icq lite group caps
+ {
+ if(gbXStatusEnabled)
+ wAdditionalData += 16;
+ if(bXStatus)
+ wAdditionalData += 16;
+ }
+ serverPacketInit(&packet, (WORD)(62+wAdditionalData));
+ packFNACHeader(&packet, ICQ_LOCATION_FAMILY, ICQ_LOCATION_SET_USER_INFO);
+
+ /* TLV(5): capability data */
+ packWord(&packet, 0x0005);
+ packWord(&packet, (WORD)(32 + wAdditionalData));
+ packBuffer(&packet, capNewCap, 0x10);
+#ifdef DBG_CAPHTML
+ packBuffer(&packet, capHtmlMsgs, 0x10);
+#endif
+ if(gbHideIdEnabled&&cID!=11)
+ {
+ packBuffer(&packet, capIcqJp, 4);
+ packDWord(&packet, MIRANDA_VERSION);
+ packDWord(&packet, ICQ_PLUG_VERSION);
+ packDWord(&packet, gbSecureIM?0x5AFEC0DE:0x00000000);
+ }
+ switch (cID) //client change caps
+ {
+ case 11:
+ packBuffer(&packet, gbHideIdEnabled?capIcqJp:capMirandaIm, gbHideIdEnabled?4:8);
+ packBuffer(&packet, "\x06\x06\x06\x00\x06\x06\x06\x00",8);
+ gbHideIdEnabled?packDWord(&packet, gbSecureIM?0x5AFEC0DE:0x00000000):0;
+ case 0: //miranda
+ {
+ if(!cID && !gbHideIdEnabled)
+ { // Miranda Signature - added customization of various ICQ Mods
+ switch (cICQModID) {
+ case 0:
+ packBuffer(&packet, capMirandaIm, 8);
+ packDWord(&packet, MIRANDA_VERSION);
+ packDWord(&packet, ICQ_JOEWHALE_VERSION);
+ break;
+ case 1:
+ packBuffer(&packet, capMirandaIm, 8);
+ packDWord(&packet, MIRANDA_VERSION);
+ packDWord(&packet, ICQ_BM_VERSION);
+ break;
+ case 2:
+ packBuffer(&packet, capIcqJs7, 4);
+ packDWord(&packet, MIRANDA_VERSION);
+ packDWord(&packet, ICQ_S7SSS_VERSION);
+ break;
+ case 3:
+ packBuffer(&packet, capIcqJSin, 4);
+ packDWord(&packet, MIRANDA_VERSION);
+ packDWord(&packet, ICQ_SIN_VERSION);
+ break;
+ default:
+ case 4:
+ packBuffer(&packet, capIcqJp, 4);
+ packDWord(&packet, MIRANDA_VERSION);
+ packDWord(&packet, ICQ_PLUG_VERSION);
+ break;
+ case 5:
+ packBuffer(&packet, capIcqJen, 4);
+ packDWord(&packet, MIRANDA_VERSION);
+ packDWord(&packet, ICQ_ETERN_VERSION);
+ break;
+ }
+ switch (cICQModID) { // send SecureIM or not for Mods
+ case 2: // s7sss,
+ case 3: // sin,
+ case 4: // plus and
+ case 5: // eternity mods may decode SecureIM flag
+ packDWord( &packet, gbSecureIM ? 0x5AFEC0DE : 0x00000000 );
+ case 0: // icqj and bm mod
+ case 1: // packets are already full
+ default : break;
+ }
+ }
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_TYPING|CAPF_SRV_RELAY|(gbRTFEnabled?CAPF_RTF:0)|(gbXStatusEnabled?CAPF_XTRAZ:0)
+ |(gbUtfEnabled?CAPF_UTF:0)|(gbAvatarsEnabled?CAPF_ICQ_DEVIL:0)|CAPF_AIM_FILE|CAPF_DIRECT);
+ if (bXStatus)
+ packBuffer(&packet, capXStatus[bXStatus-1], 0x10);
+ if (gbAimEnabled)
+ packBuffer(&packet, capAimIcq, 0x10);
+#ifdef DBG_AIMCONTACTSEND
+ {
+ packBuffer(&packet, capAimSendbuddylist, 0x10);
+ }
+#endif
+ if (gbTzerEnabled)
+ packBuffer(&packet, captZers, 16);
+#ifdef DBG_CAPXTRAZ_MUC
+ packNewCap(&packet, 0x134C); // CAP_XTRAZ_MUC
+#endif
+ }
+ break;
+ case 2: //QIP
+ packBuffer(&packet, capQip, 0x10);
+ packBuffer(&packet, capQip_1, 0x10);
+ break;
+ case 23:
+ packBuffer(&packet, capQipPDA, 0x10);
+ break;
+ case 24:
+ packBuffer(&packet, capQipMobile, 0x10);
+ break;
+ case 46: //QIP Infium
+ packBuffer(&packet, capQipInfium, 0x10);
+ packBuffer(&packet, capQipPlugins, 0x10);
+ break;
+ case 4: //icq
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_AIM_FILE|CAPF_XTRAZ_CHAT|CAPF_PUSH2TALK|CAPF_VOICE_CHAT|CAPF_UTF);
+ break;
+ case 9:
+ packBuffer(&packet, capKopete, 0xC);
+ packDWord(&packet, 0x000C0001);
+ break;
+ case 10:
+ packBuffer(&packet, capMacIcq, 0x10);
+ break;
+ case 5:
+ packBuffer(&packet, capAndRQ, 9);
+ packBuffer(&packet, "\x04\x07\x09\x00\x00\x00\x00",7);
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_SRV_RELAY);
+ break;
+ case 6:
+ packBuffer(&packet, capJimm, 5);
+ packBuffer(&packet, "\x30\x2E\x35\x2E\x32\x62\x00\x00\x00\x00\x00",11);
+ break;
+ case 7:
+ packBuffer(&packet, capTrillian, 0x10);
+ break;
+ case 8:
+ packBuffer(&packet, capLicq, 0xC);
+ packDWord(&packet, 0x01030200);
+ break;
+ case 12:
+ packBuffer(&packet, capRambler, 0x10);
+ break;
+ case 13:
+ packBuffer(&packet, captZers, 0x10);
+ break;
+ case 14:
+ packBuffer(&packet, capAbv, 0x10);
+ break;
+ case 15:
+ packBuffer(&packet, capNetvigator, 0x10);
+ break;
+ case 20:
+ packBuffer(&packet, capmChat, 0x10);
+ break;
+ case 25:
+ packBuffer(&packet, capIs2002, 0x10);
+ break;
+ case 26:
+ packBuffer(&packet, captZers, 0x10);
+ packBuffer(&packet, capHtmlMsgs, 0x10);
+ packBuffer(&packet, capLiveVideo, 0x10);
+ break;
+ case 27:
+ packBuffer(&packet, capComm20012, 0x10);
+ packBuffer(&packet, capIs2001, 0x10);
+ break;
+ case 28:
+ packBuffer(&packet, capAnastasia, 0x10);
+ break;
+ case 16:
+ packBuffer(&packet, capSim, 0xC);
+ packDWord(&packet, 0x00090540);
+ break;
+ case 17:
+ packBuffer(&packet, capSim, 0xC);
+ packDWord(&packet, 0x00090580);
+ break;
+ case 18:
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_SRV_RELAY|CAPF_DIRECT|CAPF_RTF);
+ break;
+ case 31:
+ packBuffer(&packet, capmIcq, 0xC); //mIcq
+ packBuffer(&packet, "\x08\x02\x00\x00",4);
+ break;
+ case 34: //IM2
+ packBuffer(&packet, capIm2, 0x10);
+ break;
+ case 35: //GAIM
+ packBuffer(&packet, capAimIcon, 0x10);
+ packBuffer(&packet, capAimDirect, 0x10);
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_AIM_FILE|CAPF_UTF);
+ break;
+ case 40: //uIM
+ packBuffer(&packet, capUim, 0x10);
+ break;
+ case 41: //TICQClient
+ packBuffer(&packet, capComm20012, 0x10);
+ packBuffer(&packet, capIs2001, 0x10);
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_SRV_RELAY|CAPF_RTF);
+ break;
+ case 42: //IC@
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_SRV_RELAY|CAPF_RTF|CAPF_UTF);
+ break;
+ case 43: //PreludeICQ
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_SRV_RELAY|CAPF_UTF|CAPF_TYPING);
+ break;
+ case 44: //QNEXT
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_RTF);
+ break;
+ case 47: //JICQ
+ packBuffer(&packet, capPalmJicq, 0xC);
+ packBuffer(&packet, "\x00\x01\x00\x05",4);
+ break;
+ case 49: //MIP
+ packBuffer(&packet, capMipClient, 0xC);
+ packBuffer(&packet, "\x00\x06\x00\x00",4);
+ break;
+ case 50: //Trillian Astra
+ packBuffer(&packet, capTrillian, 0x10);
+ packBuffer(&packet, capTrilCrypt, 0x10);
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_RTF|CAPF_AIM_FILE);
+ break;
+ case 51: //R&Q
+ packBuffer(&packet, capRAndQ, 9);
+ packBuffer(&packet, "\x01\x00\x06\x01",4);
+ break;
+ case 52: //NanoICQ
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_UTF);
+ break;
+ case 53: //IMadering
+ packBuffer(&packet, capIMadering, 0x10);
+ break;
+ case 54: // eternity : MirandaMobile
+ packBuffer(&packet, capMirandaMobile, 16);
+ break;
+ default:
+ {
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_SRV_RELAY);
+ }
+ break;
+ }
+ if(cID==2||cID==23||cID==24||cID==46) //qip caps
+ {
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_TYPING|CAPF_SRV_RELAY|CAPF_DIRECT|CAPF_ICQ_DEVIL|CAPF_UTF|CAPF_RTF|(gbXStatusEnabled?CAPF_XTRAZ:0)|CAPF_AIM_FILE);
+ if (bXStatus)
+ {
+ packBuffer(&packet, capXStatus[bXStatus-1], 0x10);
+ }
+ }
+ if(cID==10||cID>=6&&cID<=10||cID==16||cID==17||cID==20||cID==25||cID>=27&&cID<=40||cID==44||cID==45||cID==47||cID>=49&&cID<=52) //default caps
+ {
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_SRV_RELAY);
+ }
+ if(cID>=12&&cID<=15||cID==26) //icq lite group caps
+ {
+ AddCapabilitiesToBuffer((BYTE*)&packet, CAPF_TYPING|CAPF_SRV_RELAY|CAPF_DIRECT|CAPF_PUSH2TALK|CAPF_ICQ_DEVIL|CAPF_UTF|CAPF_RTF|(gbXStatusEnabled?CAPF_XTRAZ:0)|CAPF_XTRAZ_CHAT|CAPF_AIM_FILE|CAPF_VOICE_CHAT);
+ if (bXStatus)
+ {
+ packBuffer(&packet, capXStatus[bXStatus-1], 0x10);
+ }
+ }
+
+ { // store own client capabilities, and detect own client
+ DBCONTACTWRITESETTING dbcws;
+ dbcws.value.type = DBVT_BLOB;
+ dbcws.value.cpbVal = wAdditionalData+46;
+ dbcws.value.pbVal = packet.pData+20;
+ dbcws.szModule = gpszICQProtoName;
+ dbcws.szSetting = "CapBuf";
+ CallService(MS_DB_CONTACT_WRITESETTING, (WPARAM)NULL, (LPARAM)&dbcws);
+ }
+ if(gbCustomCapEnabled)
+ {
+ int i;
+ for (i = 0; i < lstCustomCaps->realCount; ++i)
+ packBuffer(&packet, ((ICQ_CUSTOMCAP *)lstCustomCaps->items[i])->caps, 0x10);
+ }
+ sendServPacket(&packet);
+}
+
+
+void handleServUINSettings(int nPort, serverthread_info *info)
+{
+ icq_packet packet;
+
+ setUserInfo();
+
+
+ /* SNAC 3,4: Tell server who's on our list */
+ sendEntireListServ(ICQ_BUDDY_FAMILY, ICQ_USER_ADDTOLIST, BUL_ALLCONTACTS);
+
+ if (icqGoingOnlineStatus == ID_STATUS_INVISIBLE)
+ {
+ /* Tell server who's on our visible list */
+ if (!gbSsiEnabled)
+ sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDVISIBLE, BUL_VISIBLE);
+ else
+ updateServVisibilityCode(3);
+ }
+
+ if (icqGoingOnlineStatus != ID_STATUS_INVISIBLE)
+ {
+ /* Tell server who's on our invisible list */
+ if (!gbSsiEnabled)
+ sendEntireListServ(ICQ_BOS_FAMILY, ICQ_CLI_ADDINVISIBLE, BUL_INVISIBLE);
+ else
+ updateServVisibilityCode(4);
+ }
+
+ // SNAC 1,1E: Set status
+ {
+ WORD wStatus;
+ DWORD dwDirectCookie = rand() ^ (rand() << 16);
+ BYTE bXStatus = ICQGetContactXStatus(NULL);
+ char szMoodId[32];
+ WORD cbMoodId = 0;
+ WORD cbMoodData = 0;
+ DWORD dwFT1, dwFT2, dwFT3;
+
+ // Get status
+ wStatus = MirandaStatusToIcq(icqGoingOnlineStatus);
+
+ if (bXStatus && moodXStatus[bXStatus-1] != -1)
+ { // prepare mood id
+ null_snprintf(szMoodId, SIZEOF(szMoodId), "icqmood%d", moodXStatus[bXStatus-1]);
+ cbMoodId = strlennull(szMoodId);
+ cbMoodData = 8;
+ }
+
+ serverPacketInit(&packet, (WORD)(71 + cbMoodId + cbMoodData));
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_STATUS);
+ packDWord(&packet, 0x00060004); // TLV 6: Status mode and security flags
+ packWord(&packet, GetMyStatusFlags()); // Status flags
+ packWord(&packet, wStatus); // Status
+ packTLVWord(&packet, 0x0008, 0x0000); // TLV 8: Error code
+ packDWord(&packet, 0x000c0025); // TLV C: Direct connection info
+ packDWord(&packet, ICQGetContactSettingDword(NULL, "RealIP", 0));
+ packDWord(&packet, nPort);
+ packByte(&packet, DC_TYPE); // TCP/FLAG firewall settings
+ packWord(&packet, (WORD)GetProtoVersion());
+ packDWord(&packet, dwDirectCookie); // DC Cookie
+ packDWord(&packet, WEBFRONTPORT); // Web front port
+ packDWord(&packet, CLIENTFEATURES); // Client features
+ SetTimeStamps(&dwFT1, &dwFT2, &dwFT3);
+ packDWord(&packet, dwFT1);
+ packDWord(&packet, dwFT2);
+ packDWord(&packet, dwFT3);
+ packWord(&packet, 0x0000); // Unknown
+ packTLVWord(&packet, 0x001F, 0x0000);
+
+ if (cbMoodId)
+ { // Pack mood data
+ packWord(&packet, 0x1D); // TLV 1D
+ packWord(&packet, (WORD)(cbMoodId + 4)); // TLV length
+ packWord(&packet, 0x0E); // Item Type
+ packWord(&packet, cbMoodId); // Flags + Item Length
+ packBuffer(&packet, szMoodId, cbMoodId); // Mood
+ }
+
+ sendServPacket(&packet);
+ }
+ {
+ LPSTR szClient = {0};
+ static DWORD dwFT1, dwFT2, dwFT3;
+ char szStrBuf[MAX_PATH];
+ DBVARIANT dbv;
+ DBCONTACTGETSETTING dbcgs;
+ dbcgs.szModule = gpszICQProtoName;
+ dbcgs.szSetting = "CapBuf";
+ dbcgs.pValue = &dbv;
+ CallService(MS_DB_CONTACT_GETSETTING, 0, (LPARAM)&dbcgs);
+ if (dbv.type == DBVT_BLOB)
+ {
+ char bClient=0;
+ WORD bufsize = dbv.cpbVal;
+ BYTE *buf = dbv.pbVal;
+ SetTimeStamps(&dwFT1, &dwFT2, &dwFT3);
+ szClient = detectUserClient(NULL, 0, GetProtoVersion(), dwFT1, dwFT2, dwFT3, 0, 0, 0, 0, buf, bufsize, &bClient, szStrBuf);
+ if (!szClient||szClient<0)
+ szClient = "Unknown";
+ ICQWriteContactSettingUtf(NULL, "MirVer", szClient);
+ }
+ }
+
+
+ /* SNAC 1,11 */
+ serverPacketInit(&packet, 14);
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_SET_IDLE);
+ packDWord(&packet, 0x00000000);
+
+ sendServPacket(&packet);
+ gbIdleAllow = 0;
+
+ // Change status
+ SetCurrentStatus(icqGoingOnlineStatus);
+
+ // Finish Login sequence
+ serverPacketInit(&packet, 98);
+ packFNACHeader(&packet, ICQ_SERVICE_FAMILY, ICQ_CLIENT_READY);
+ packDWord(&packet, 0x00220001); // imitate ICQ 6 behaviour
+ packDWord(&packet, 0x0110161b);
+ packDWord(&packet, 0x00010004);
+ packDWord(&packet, 0x0110161b);
+ packDWord(&packet, 0x00130004);
+ packDWord(&packet, 0x0110161b);
+ packDWord(&packet, 0x00020001);
+ packDWord(&packet, 0x0110161b);
+ packDWord(&packet, 0x00030001);
+ packDWord(&packet, 0x0110161b);
+ packDWord(&packet, 0x00150001);
+ packDWord(&packet, 0x0110161b);
+ packDWord(&packet, 0x00040001);
+ packDWord(&packet, 0x0110161b);
+ packDWord(&packet, 0x00060001);
+ packDWord(&packet, 0x0110161b);
+ packDWord(&packet, 0x00090001);
+ packDWord(&packet, 0x0110161b);
+ packDWord(&packet, 0x000A0001);
+ packDWord(&packet, 0x0110161b);
+ packDWord(&packet, 0x000B0001);
+ packDWord(&packet, 0x0110161b);
+
+ sendServPacket(&packet);
+
+ NetLog_Server(" *** Yeehah, login sequence complete");
+
+ // login sequence is complete enter logged-in mode
+ info->bLoggedIn = 1;
+
+ // enable auto info-update routine
+ icq_EnableUserLookup(TRUE);
+
+ if (!info->isMigrating)
+ { /* Get Offline Messages Reqeust */
+ offline_message_cookie *ack;
+
+ ack = (offline_message_cookie*)SAFE_MALLOC(sizeof(offline_message_cookie));
+ if (ack)
+ {
+ DWORD dwCookie = AllocateCookie(CKT_OFFLINEMESSAGE, ICQ_MSG_CLI_REQ_OFFLINE, 0, ack);
+
+ serverPacketInit(&packet, 10);
+ packFNACHeaderFull(&packet, ICQ_MSG_FAMILY, ICQ_MSG_CLI_REQ_OFFLINE, 0, dwCookie);
+
+ sendServPacket(&packet);
+ }
+ else
+ icq_LogMessage(LOG_WARNING, "Failed to request offline messages. They may be received next time you log in.");
+
+ // Update our information from the server
+ sendOwnerInfoRequest();
+
+ // Request info updates on all contacts
+ icq_RescanInfoUpdate();
+
+ // Start sending Keep-Alive packets
+ StartKeepAlive(info);
+
+ if (gbAvatarsEnabled)
+ { // Send SNAC 1,4 - request avatar family 0x10 connection
+ icq_requestnewfamily(ICQ_AVATAR_FAMILY, StartAvatarThread);
+
+ pendingAvatarsStart = 1;
+ NetLog_Server("Requesting Avatar family entry point.");
+ }
+ }
+ info->isMigrating = 0;
+
+ if (gbAimEnabled)
+ {
+ char** szMsg = MirandaStatusToAwayMsg(gnCurrentStatus);
+
+ EnterCriticalSection(&modeMsgsMutex);
+ if (szMsg && !bNoStatusReply)
+ icq_sendSetAimAwayMsgServ(*szMsg);
+ LeaveCriticalSection(&modeMsgsMutex);
+ }
+ CheckSelfRemove();
+}
|