From 960336573d3420785094dd46fe4a3edb4cb152a8 Mon Sep 17 00:00:00 2001 From: George Hazan Date: Sat, 10 Aug 2013 21:34:29 +0000 Subject: divide et impera git-svn-id: http://svn.miranda-ng.org/main/trunk@5639 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/AVS/src/main.cpp | 2158 +++------------------------------------------- 1 file changed, 114 insertions(+), 2044 deletions(-) (limited to 'plugins/AVS/src/main.cpp') diff --git a/plugins/AVS/src/main.cpp b/plugins/AVS/src/main.cpp index bd54f660e6..83a36ea251 100644 --- a/plugins/AVS/src/main.cpp +++ b/plugins/AVS/src/main.cpp @@ -29,1794 +29,103 @@ bool g_shutDown = false; int hLangpack; -static TCHAR g_szDataPath[MAX_PATH]; // user datae path (read at startup only) -static BOOL g_MetaAvail = FALSE; -BOOL g_AvatarHistoryAvail = FALSE; -static long hwndSetMyAvatar = 0; +TCHAR g_szDataPath[MAX_PATH]; // user datae path (read at startup only) +BOOL g_MetaAvail = FALSE; +BOOL g_AvatarHistoryAvail = FALSE; +HWND hwndSetMyAvatar = 0; -static HANDLE hMyAvatarsFolder; -static HANDLE hGlobalAvatarFolder; -static HANDLE hLoaderEvent, hShutdownEvent; -static HANDLE hEventContactAvatarChanged, hMyAvatarChanged; -HANDLE hEventChanged; +HANDLE hMyAvatarsFolder; +HANDLE hGlobalAvatarFolder; +HANDLE hLoaderEvent, hShutdownEvent; +HANDLE hEventChanged, hEventContactAvatarChanged, hMyAvatarChanged; -BOOL (WINAPI *AvsAlphaBlend)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION) = NULL; +void InitServices(); -static struct CacheNode *g_Cache = 0; -static CRITICAL_SECTION cachecs, alloccs; +BOOL (WINAPI *AvsAlphaBlend)(HDC, int, int, int, int, HDC, int, int, int, int, BLENDFUNCTION) = NULL; static int ComparePicture( const protoPicCacheEntry* p1, const protoPicCacheEntry* p2 ) { if ((lstrcmpA(p1->szProtoname, "Global avatar") == 0) || strstr(p1->szProtoname, "Global avatar")) - return -1; - if ((lstrcmpA(p2->szProtoname, "Global avatar") == 0) || strstr(p1->szProtoname, "Global avatar")) - return 1; - return lstrcmpA( p1->szProtoname, p2->szProtoname ); -} - -OBJLIST - g_ProtoPictures( 10, ComparePicture ), - g_MyAvatars( 10, ComparePicture ); - -char* g_szMetaName = NULL; - -#ifndef SHVIEW_THUMBNAIL -#define SHVIEW_THUMBNAIL 0x702D -#endif - -// Stores the id of the dialog - -int ChangeAvatar(HANDLE hContact, BOOL fLoad, BOOL fNotifyHist = FALSE, int pa_format = 0); - -int OnDetailsInit(WPARAM wParam, LPARAM lParam); -int OptInit(WPARAM wParam, LPARAM lParam); - -static int ShutdownProc(WPARAM wParam, LPARAM lParam); -static int OkToExitProc(WPARAM wParam, LPARAM lParam); -static int GetFileHash(TCHAR* filename); -static DWORD GetFileSize(TCHAR *szFilename); - -void ProcessAvatarInfo(HANDLE hContact, int type, PROTO_AVATAR_INFORMATIONT *pai, const char *szProto); -int FetchAvatarFor(HANDLE hContact, char *szProto = NULL); -static INT_PTR ReportMyAvatarChanged(WPARAM wParam, LPARAM lParam); - -BOOL Proto_IsAvatarsEnabled(const char *proto); -BOOL Proto_IsAvatarFormatSupported(const char *proto, int format); -void Proto_GetAvatarMaxSize(const char *proto, int *width, int *height); -int Proto_AvatarImageProportion(const char *proto); -BOOL Proto_NeedDelaysForAvatars(const char *proto); -int Proto_GetAvatarMaxFileSize(const char *proto); -int Proto_GetDelayAfterFail(const char *proto); - -FI_INTERFACE *fei = 0; - -PLUGININFOEX pluginInfoEx = { - sizeof(PLUGININFOEX), - __PLUGIN_NAME, - PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), - __DESCRIPTION, - __AUTHOR, - __AUTHOREMAIL, - __COPYRIGHT, - __AUTHORWEB, - UNICODE_AWARE, - // {E00F1643-263C-4599-B84B-053E5C511D29} - {0xe00f1643, 0x263c, 0x4599, {0xb8, 0x4b, 0x5, 0x3e, 0x5c, 0x51, 0x1d, 0x29}} -}; - -extern INT_PTR CALLBACK DlgProcAvatarOptions(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); - -static int SetProtoMyAvatar(char *protocol, HBITMAP hBmp, TCHAR *originalFilename, int format, BOOL square, BOOL grow); - -/* - * output a notification message. - * may accept a hContact to include the contacts nickname in the notification message... - * the actual message is using printf() rules for formatting and passing the arguments... - * - * can display the message either as systray notification (baloon popup) or using the - * popup plugin. - */ - -#ifdef _DEBUG - -int _DebugTrace(const char *fmt, ...) -{ - char debug[2048]; - int ibsize = 2047; - va_list va; - va_start(va, fmt); - - mir_snprintf(debug, SIZEOF(debug) - 10, " ***** AVS [%08d] [ID:%04x]: ", GetTickCount(), GetCurrentThreadId()); - OutputDebugStringA(debug); - mir_vsnprintf(debug, ibsize, fmt, va); - OutputDebugStringA(debug); - OutputDebugStringA(" ***** \n"); - - return 0; -} - -int _DebugTrace(HANDLE hContact, const char *fmt, ...) -{ - char text[1024]; - size_t len; - va_list va; - - char *name = NULL; - char *proto = NULL; - if (hContact != NULL) - { - name = (char*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM)hContact, 0); - proto = GetContactProto(hContact); - } - - mir_snprintf(text, SIZEOF(text) - 10, " ***** AVS [%08d] [ID:%04x]: [%08d - %s - %s] ", - GetTickCount(), GetCurrentThreadId(), hContact, proto == NULL ? "" : proto, name == NULL ? "" : name); - len = strlen(text); - - va_start(va, fmt); - mir_vsnprintf(&text[len], SIZEOF(text) - len, fmt, va); - va_end(va); - - OutputDebugStringA(text); - OutputDebugStringA(" ***** \n"); - - return 0; -} - -#endif - -void mir_sleep(int time) -{ - if (!g_shutDown) - WaitForSingleObject(hShutdownEvent, time); -} - -/* - * path utilities (make avatar paths relative to *PROFILE* directory, not miranda directory. - * taken and modified from core services - */ - -int AVS_pathIsAbsolute(const TCHAR *path) -{ - if (!path || !(lstrlen(path) > 2)) - return 0; - if ((path[1]==':'&&path[2]=='\\')||(path[0]=='\\'&&path[1]=='\\')) return 1; - return 0; -} - -size_t AVS_pathToRelative(const TCHAR *pSrc, TCHAR *pOut) -{ - if (!pSrc || !*pSrc || _tcslen(pSrc) > MAX_PATH) return 0; - if (!AVS_pathIsAbsolute( pSrc )) - lstrcpyn(pOut, pSrc, MAX_PATH); - else { - TCHAR szTmp[MAX_PATH]; - mir_sntprintf(szTmp, SIZEOF(szTmp), _T("%s"), pSrc); - _tcslwr(szTmp); - if (_tcsstr(szTmp, g_szDataPath)) - lstrcpyn(pOut, pSrc + _tcslen(g_szDataPath) + 1, MAX_PATH); - else - lstrcpyn(pOut, pSrc, MAX_PATH); - } - return _tcslen(pOut); -} - -size_t AVS_pathToAbsolute(const TCHAR *pSrc, TCHAR *pOut) -{ - if (!pSrc || !lstrlen(pSrc) || lstrlen(pSrc) > MAX_PATH) - return 0; - - if (AVS_pathIsAbsolute(pSrc) || !_istalnum(pSrc[0])) - lstrcpyn(pOut, pSrc, MAX_PATH); - else - mir_sntprintf(pOut, MAX_PATH, _T("%s\\%s"), g_szDataPath, pSrc, MAX_PATH); - return lstrlen(pOut); -} - -static void NotifyMetaAware(HANDLE hContact, struct CacheNode *node = NULL, AVATARCACHEENTRY *ace = (AVATARCACHEENTRY *)-1) -{ - if (g_shutDown) - return; - - if (ace == (AVATARCACHEENTRY *)-1) - ace = &node->ace; - - NotifyEventHooks(hEventChanged, (WPARAM)hContact, (LPARAM)ace); - - if (g_MetaAvail && (node->dwFlags & MC_ISSUBCONTACT) && db_get_b(NULL, g_szMetaName, "Enabled", 0)) { - HANDLE hMasterContact = (HANDLE)db_get_dw(hContact, g_szMetaName, "Handle", 0); - if (hMasterContact && (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hMasterContact, 0) == hContact && - !db_get_b(hMasterContact, "ContactPhoto", "Locked", 0)) - NotifyEventHooks(hEventChanged, (WPARAM)hMasterContact, (LPARAM)ace); - } - - if (node->dwFlags & AVH_MUSTNOTIFY) { - // Fire the event for avatar history - node->dwFlags &= ~AVH_MUSTNOTIFY; - if (node->ace.szFilename[0] != '\0') { - CONTACTAVATARCHANGEDNOTIFICATION cacn = {0}; - cacn.cbSize = sizeof(CONTACTAVATARCHANGEDNOTIFICATION); - cacn.hContact = hContact; - cacn.format = node->pa_format; - _tcsncpy(cacn.filename, node->ace.szFilename, MAX_PATH); - cacn.filename[MAX_PATH - 1] = 0; - - // Get hash - char *szProto = GetContactProto(hContact); - if (szProto != NULL) { - DBVARIANT dbv = {0}; - if ( !db_get_s(hContact, szProto, "AvatarHash", &dbv)) { - if (dbv.type == DBVT_TCHAR) - _tcsncpy_s(cacn.hash, SIZEOF(cacn.hash), dbv.ptszVal, _TRUNCATE); - else if (dbv.type == DBVT_BLOB) { - // Lets use base64 encode - char *tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; - int i; - for(i = 0; i < dbv.cpbVal / 3 && i*4+3 < sizeof(cacn.hash)-1; i++) { - BYTE a = dbv.pbVal[i*3]; - BYTE b = i*3 + 1 < dbv.cpbVal ? dbv.pbVal[i*3 + 1] : 0; - BYTE c = i*3 + 2 < dbv.cpbVal ? dbv.pbVal[i*3 + 2] : 0; - - cacn.hash[i*4] = tab[(a & 0xFC) >> 2]; - cacn.hash[i*4+1] = tab[((a & 0x3) << 4) + ((b & 0xF0) >> 4)]; - cacn.hash[i*4+2] = tab[((b & 0xF) << 2) + ((c & 0xC0) >> 6)]; - cacn.hash[i*4+3] = tab[c & 0x3F]; - } - if (dbv.cpbVal % 3 != 0 && i*4+3 < sizeof(cacn.hash)-1) { - BYTE a = dbv.pbVal[i*3]; - BYTE b = i*3 + 1 < dbv.cpbVal ? dbv.pbVal[i*3 + 1] : 0; - - cacn.hash[i*4] = tab[(a & 0xFC) >> 2]; - cacn.hash[i*4+1] = tab[((a & 0x3) << 4) + ((b & 0xF0) >> 4)]; - if (i + 1 < dbv.cpbVal) - cacn.hash[i*4+2] = tab[((b & 0xF) << 4)]; - else - cacn.hash[i*4+2] = '='; - cacn.hash[i*4+3] = '='; - } - } - db_free(&dbv); - } - } - - // Default value - if (cacn.hash[0] == '\0') - mir_sntprintf(cacn.hash, SIZEOF(cacn.hash), _T("AVS-HASH-%x"), GetFileHash(cacn.filename)); - - NotifyEventHooks(hEventContactAvatarChanged, (WPARAM)cacn.hContact, (LPARAM)&cacn); - } - else NotifyEventHooks(hEventContactAvatarChanged, (WPARAM)hContact, NULL); - } -} - -static int g_maxBlock = 0, g_curBlock = 0; -static struct CacheNode **g_cacheBlocks = NULL; - -/* - * allocate a cache block and add it to the list of blocks - * does not link the new block with the old block(s) - caller needs to do this - */ - -static struct CacheNode *AllocCacheBlock() -{ - struct CacheNode *allocedBlock = NULL; - - allocedBlock = (struct CacheNode *)malloc(CACHE_BLOCKSIZE * sizeof(struct CacheNode)); - ZeroMemory((void *)allocedBlock, sizeof(struct CacheNode) * CACHE_BLOCKSIZE); - - for(int i = 0; i < CACHE_BLOCKSIZE - 1; i++) - allocedBlock[i].pNextNode = &allocedBlock[i + 1]; // pre-link the alloced block - - if (g_Cache == NULL) // first time only... - g_Cache = allocedBlock; - - // add it to the list of blocks - - if (g_curBlock == g_maxBlock) { - g_maxBlock += 10; - g_cacheBlocks = (struct CacheNode **)realloc(g_cacheBlocks, g_maxBlock * sizeof(struct CacheNode *)); - } - g_cacheBlocks[g_curBlock++] = allocedBlock; - - return(allocedBlock); -} - -int SetAvatarAttribute(HANDLE hContact, DWORD attrib, int mode) -{ - struct CacheNode *ρρ = g_Cache; - - while(ρρ) { - if (ρρ->ace.hContact == hContact) { - DWORD dwFlags = ρρ->ace.dwFlags; - - ρρ->ace.dwFlags = mode ? (ρρ->ace.dwFlags | attrib) : (ρρ->ace.dwFlags & ~attrib); - if (ρρ->ace.dwFlags != dwFlags) - NotifyMetaAware(hContact, ρρ); - break; - } - ρρ = ρρ->pNextNode; - } - return 0; -} - -/* - * convert the avatar image path to a relative one... - * given: contact handle, path to image - */ -void MakePathRelative(HANDLE hContact, TCHAR *path) -{ - TCHAR szFinalPath[MAX_PATH]; - szFinalPath[0] = '\0'; - - size_t result = AVS_pathToRelative(path, szFinalPath); - if (result && lstrlen(szFinalPath) > 0) { - db_set_ts(hContact, "ContactPhoto", "RFile", szFinalPath); - if (!db_get_b(hContact, "ContactPhoto", "Locked", 0)) - db_set_ts(hContact, "ContactPhoto", "Backup", szFinalPath); - } -} - -/* - * convert the avatar image path to a relative one... - * given: contact handle - */ - -static void MakePathRelative(HANDLE hContact) -{ - DBVARIANT dbv; - if ( !db_get_ts(hContact, "ContactPhoto", "File", &dbv)) { - MakePathRelative(hContact, dbv.ptszVal); - db_free(&dbv); - } -} - -static void ResetTranspSettings(HANDLE hContact) -{ - db_unset(hContact, "ContactPhoto", "MakeTransparentBkg"); - db_unset(hContact, "ContactPhoto", "TranspBkgNumPoints"); - db_unset(hContact, "ContactPhoto", "TranspBkgColorDiff"); -} - -static TCHAR *getJGMailID(char *szProto) -{ - static TCHAR szJID[MAX_PATH+1]; szJID[0] = '\0'; - - DBVARIANT dbva, dbvb; - if ( db_get_ts(NULL, szProto, "LoginName", &dbva)) - return szJID; - - if ( db_get_ts(NULL, szProto, "LoginServer", &dbvb)) { - db_free(&dbva); - return szJID; - } - - mir_sntprintf(szJID, SIZEOF(szJID), _T("%s@%s"), dbva.ptszVal, dbvb.ptszVal); - db_free(&dbva); - db_free(&dbvb); - return szJID; -} - -// create the avatar in cache -// returns 0 if not created (no avatar), iIndex otherwise, -2 if has to request avatar, -3 if avatar too big -int CreateAvatarInCache(HANDLE hContact, avatarCacheEntry *ace, char *szProto) -{ - DBVARIANT dbv = {0}; - char *szExt = NULL; - TCHAR tszFilename[MAX_PATH]; - HANDLE hFile = INVALID_HANDLE_VALUE; - DWORD dwFileSizeHigh = 0, dwFileSize = 0, sizeLimit = 0; - - tszFilename[0] = 0; - - ace->hbmPic = 0; - ace->dwFlags = 0; - ace->bmHeight = 0; - ace->bmWidth = 0; - ace->lpDIBSection = NULL; - ace->szFilename[0] = 0; - - if (szProto == NULL) { - char *proto = GetContactProto(hContact); - if (proto == NULL || !db_get_b(NULL, AVS_MODULE, proto, 1)) - return -1; - - if (db_get_b(hContact, "ContactPhoto", "Locked", 0) - && !db_get_ts(hContact, "ContactPhoto", "Backup", &dbv)) { - AVS_pathToAbsolute(dbv.ptszVal, tszFilename); - db_free(&dbv); - } - else if ( !db_get_ts(hContact, "ContactPhoto", "RFile", &dbv)) { - AVS_pathToAbsolute(dbv.ptszVal, tszFilename); - db_free(&dbv); - } - else if ( !db_get_ts(hContact, "ContactPhoto", "File", &dbv)) { - AVS_pathToAbsolute(dbv.ptszVal, tszFilename); - db_free(&dbv); - } - else return -2; - } - else { - if (hContact == 0) { // create a protocol picture in the proto picture cache - if ( !db_get_ts(NULL, PPICT_MODULE, szProto, &dbv)) { - AVS_pathToAbsolute(dbv.ptszVal, tszFilename); - db_free(&dbv); - } - else { - if (lstrcmpA(szProto, AVS_DEFAULT)) { - if ( !db_get_ts(NULL, PPICT_MODULE, AVS_DEFAULT, &dbv)) { - AVS_pathToAbsolute(dbv.ptszVal, tszFilename); - db_free(&dbv); - } - - if (!strstr(szProto, "Global avatar for")) { - PROTOACCOUNT* pdescr = (PROTOACCOUNT*)CallService(MS_PROTO_GETACCOUNT, 0, (LPARAM)szProto); - if (pdescr == NULL) - return -1; - char key[MAX_PATH]; - mir_snprintf(key, SIZEOF(key), "Global avatar for %s accounts", pdescr->szProtoName); - if ( !db_get_ts(NULL, PPICT_MODULE, key, &dbv)) { - AVS_pathToAbsolute(dbv.ptszVal, tszFilename); - db_free(&dbv); - } - } - } - } - } - else if (hContact == (HANDLE)-1) { // create own picture - note, own avatars are not on demand, they are loaded once at - // startup and everytime they are changed. - if (szProto[0] == '\0') { - // Global avatar - if ( db_get_ts(NULL, AVS_MODULE, "GlobalUserAvatarFile", &dbv)) - return -10; - - AVS_pathToAbsolute(dbv.ptszVal, tszFilename); - db_free(&dbv); - } - else if ( ProtoServiceExists(szProto, PS_GETMYAVATART)) { - if (CallProtoService(szProto, PS_GETMYAVATART, (WPARAM)tszFilename, (LPARAM)MAX_PATH)) - tszFilename[0] = '\0'; - } - else if ( ProtoServiceExists(szProto, PS_GETMYAVATAR)) { - char szFileName[ MAX_PATH ]; - if (CallProtoService(szProto, PS_GETMYAVATAR, (WPARAM)szFileName, (LPARAM)MAX_PATH)) - tszFilename[0] = '\0'; - else - MultiByteToWideChar( CP_ACP, 0, szFileName, -1, tszFilename, SIZEOF(tszFilename)); - } - else if ( !db_get_ts(NULL, szProto, "AvatarFile", &dbv)) { - AVS_pathToAbsolute(dbv.ptszVal, tszFilename); - db_free(&dbv); - } - else return -1; - } - } - - if ( lstrlen(tszFilename) < 4) - return -1; - - _tcsncpy_s(tszFilename, SIZEOF(tszFilename), VARST(tszFilename), _TRUNCATE); - if ((hFile = CreateFile(tszFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) - return -2; - - CloseHandle(hFile); - WPARAM isTransparentImage = 0; - - ace->hbmPic = (HBITMAP) BmpFilterLoadBitmap32((WPARAM)&isTransparentImage, (LPARAM)tszFilename); - ace->dwFlags = 0; - ace->bmHeight = 0; - ace->bmWidth = 0; - ace->lpDIBSection = NULL; - _tcsncpy(ace->szFilename, tszFilename, MAX_PATH); - ace->szFilename[MAX_PATH - 1] = 0; - if (ace->hbmPic != 0) { - BITMAP bminfo; - - GetObject(ace->hbmPic, sizeof(bminfo), &bminfo); - - ace->cbSize = sizeof(avatarCacheEntry); - ace->dwFlags = AVS_BITMAP_VALID; - if (hContact != NULL && db_get_b(hContact, "ContactPhoto", "Hidden", 0)) - ace->dwFlags |= AVS_HIDEONCLIST; - ace->hContact = hContact; - ace->bmHeight = bminfo.bmHeight; - ace->bmWidth = bminfo.bmWidth; - - BOOL noTransparency = db_get_b(0, AVS_MODULE, "RemoveAllTransparency", 0); - - // Calc image hash - if (hContact != 0 && hContact != (HANDLE)-1) { - // Have to reset settings? -> do it if image changed - DWORD imgHash = GetImgHash(ace->hbmPic); - if (imgHash != db_get_dw(hContact, "ContactPhoto", "ImageHash", 0)) { - ResetTranspSettings(hContact); - db_set_dw(hContact, "ContactPhoto", "ImageHash", imgHash); - } - - // Make transparent? - if (!noTransparency && !isTransparentImage - && db_get_b(hContact, "ContactPhoto", "MakeTransparentBkg", - db_get_b(0, AVS_MODULE, "MakeTransparentBkg", 0))) - { - if (MakeTransparentBkg(hContact, &ace->hbmPic)) { - ace->dwFlags |= AVS_CUSTOMTRANSPBKG | AVS_HASTRANSPARENCY; - GetObject(ace->hbmPic, sizeof(bminfo), &bminfo); - isTransparentImage = TRUE; - } - } - } - else if (hContact == (HANDLE)-1) { // My avatars - if (!noTransparency && !isTransparentImage - && db_get_b(0, AVS_MODULE, "MakeTransparentBkg", 0) - && db_get_b(0, AVS_MODULE, "MakeMyAvatarsTransparent", 0)) - { - if (MakeTransparentBkg(0, &ace->hbmPic)) { - ace->dwFlags |= AVS_CUSTOMTRANSPBKG | AVS_HASTRANSPARENCY; - GetObject(ace->hbmPic, sizeof(bminfo), &bminfo); - isTransparentImage = TRUE; - } - } - } - - if (db_get_b(0, AVS_MODULE, "MakeGrayscale", 0)) - ace->hbmPic = MakeGrayscale(hContact, ace->hbmPic); - - if (noTransparency) { - fei->FI_CorrectBitmap32Alpha(ace->hbmPic, TRUE); - isTransparentImage = FALSE; - } - - if (bminfo.bmBitsPixel == 32 && isTransparentImage) { - if (fei->FI_Premultiply(ace->hbmPic)) - ace->dwFlags |= AVS_HASTRANSPARENCY; - - ace->dwFlags |= AVS_PREMULTIPLIED; - } - - if (szProto) { - protoPicCacheEntry *pAce = (protoPicCacheEntry *)ace; - if (hContact == 0) - pAce->dwFlags |= AVS_PROTOPIC; - else if (hContact == (HANDLE)-1) - pAce->dwFlags |= AVS_OWNAVATAR; - } - - return 1; - } - return -1; -} - -/* - * link a new cache block with the already existing chain of blocks - */ - -static struct CacheNode *AddToList(struct CacheNode *node) -{ - struct CacheNode *pCurrent = g_Cache; - - while(pCurrent->pNextNode != 0) - pCurrent = pCurrent->pNextNode; - - pCurrent->pNextNode = node; - return pCurrent; -} - -struct CacheNode *FindAvatarInCache(HANDLE hContact, BOOL add, BOOL findAny = FALSE) -{ - if (g_shutDown) - return NULL; - - char *szProto = GetContactProto(hContact); - if (szProto == NULL || !db_get_b(NULL, AVS_MODULE, szProto, 1)) - return NULL; - - mir_cslock lck(cachecs); - - struct CacheNode *ρρ = g_Cache, *foundNode = NULL; - while(ρρ) { - if (ρρ->ace.hContact == hContact) { - ρρ->ace.t_lastAccess = time(NULL); - foundNode = ρρ->loaded || findAny ? ρρ : NULL; - return foundNode; - } - - // found an empty and usable node - if (foundNode == NULL && ρρ->ace.hContact == 0) - foundNode = ρρ; - - ρρ = ρρ->pNextNode; - } - - // not found - if (!add) - return NULL; - - if (foundNode == NULL) { // no free entry found, create a new and append it to the list - mir_cslock all(alloccs); // protect memory block allocation - struct CacheNode *newNode = AllocCacheBlock(); - AddToList(newNode); - foundNode = newNode; - } - - foundNode->ace.hContact = hContact; - if (g_MetaAvail) - foundNode->dwFlags |= (db_get_b(hContact, g_szMetaName, "IsSubcontact", 0) ? MC_ISSUBCONTACT : 0); - foundNode->loaded = FALSE; - foundNode->mustLoad = 1; // pic loader will watch this and load images - SetEvent(hLoaderEvent); // wake him up - return NULL; -} - -#define POLYNOMIAL (0x488781ED) /* This is the CRC Poly */ -#define TOPBIT (1 << (WIDTH - 1)) /* MSB */ -#define WIDTH 32 - -static int GetFileHash(TCHAR* filename) -{ - HANDLE hFile = CreateFile(filename, GENERIC_READ, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, NULL); - if (hFile == INVALID_HANDLE_VALUE) - return 0; - - int remainder = 0; - char data[1024]; - DWORD dwRead; - do - { - // Read file chunk - dwRead = 0; - ReadFile(hFile, data, 1024, &dwRead, NULL); - - /* loop through each byte of data */ - for (int byte = 0; byte < (int) dwRead; ++byte) { - /* store the next byte into the remainder */ - remainder ^= (data[byte] << (WIDTH - 8)); - /* calculate for all 8 bits in the byte */ - for (int bit = 8; bit > 0; --bit) { - /* check if MSB of remainder is a one */ - if (remainder & TOPBIT) - remainder = (remainder << 1) ^ POLYNOMIAL; - else - remainder = (remainder << 1); - } - } - } - while(dwRead == 1024); - - CloseHandle(hFile); - - return remainder; -} - -static int ProtocolAck(WPARAM wParam, LPARAM lParam) -{ - ACKDATA *ack = (ACKDATA *) lParam; - - if (ack != NULL && ack->type == ACKTYPE_AVATAR && ack->hContact != 0 && (!g_MetaAvail || strcmp(ack->szModule, g_szMetaName))) { - if (ack->result == ACKRESULT_SUCCESS) { - if (ack->hProcess == NULL) - ProcessAvatarInfo(ack->hContact, GAIR_NOAVATAR, NULL, ack->szModule); - else - ProcessAvatarInfo(ack->hContact, GAIR_SUCCESS, (PROTO_AVATAR_INFORMATIONT *) ack->hProcess, ack->szModule); - } - else if (ack->result == ACKRESULT_FAILED) { - ProcessAvatarInfo(ack->hContact, GAIR_FAILED, (PROTO_AVATAR_INFORMATIONT *) ack->hProcess, ack->szModule); - } - else if (ack->result == ACKRESULT_STATUS) { - char *szProto = GetContactProto(ack->hContact); - if (szProto == NULL || Proto_NeedDelaysForAvatars(szProto)) { - // Queue - db_set_b(ack->hContact, "ContactPhoto", "NeedUpdate", 1); - QueueAdd(ack->hContact); - } - else { - // Fetch it now - FetchAvatarFor(ack->hContact, szProto); - } - } - } - return 0; -} - -INT_PTR ProtectAvatar(WPARAM wParam, LPARAM lParam) -{ - HANDLE hContact = (HANDLE)wParam; - BYTE was_locked = db_get_b(hContact, "ContactPhoto", "Locked", 0); - - if (fei == NULL || was_locked == (BYTE)lParam) // no need for redundant lockings... - return 0; - - if (hContact) { - if (!was_locked) - MakePathRelative(hContact); - db_set_b(hContact, "ContactPhoto", "Locked", lParam ? 1 : 0); - if (lParam == 0) - MakePathRelative(hContact); - ChangeAvatar(hContact, TRUE); - } - return 0; -} - -/* - * for subclassing the open file dialog... - */ -struct OpenFileSubclassData { - BYTE *locking_request; - BYTE setView; -}; - -static BOOL CALLBACK OpenFileSubclass(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - OpenFileSubclassData *data= (OpenFileSubclassData *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - - switch(msg) { - case WM_INITDIALOG: - { - OPENFILENAME *ofn = (OPENFILENAME *)lParam; - - data = (OpenFileSubclassData *) malloc(sizeof(OpenFileSubclassData)); - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)data); - data->locking_request = (BYTE *)ofn->lCustData; - data->setView = TRUE; - - TranslateDialogDefault(hwnd); - CheckDlgButton(hwnd, IDC_PROTECTAVATAR, *(data->locking_request)); - } - break; - - case WM_COMMAND: - if (LOWORD(wParam) == IDC_PROTECTAVATAR) - *(data->locking_request) = IsDlgButtonChecked(hwnd, IDC_PROTECTAVATAR) ? TRUE : FALSE; - break; - - case WM_NOTIFY: - if (data->setView) { - HWND hwndParent = GetParent(hwnd); - HWND hwndLv = FindWindowEx(hwndParent, NULL, _T("SHELLDLL_DefView"), NULL) ; - if (hwndLv != NULL) { - SendMessage(hwndLv, WM_COMMAND, SHVIEW_THUMBNAIL, 0); - data->setView = FALSE; - } - } - break; - - case WM_NCDESTROY: - free((OpenFileSubclassData *)data); - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)0); - break; - } - - return FALSE; -} - -/* - * set an avatar (service function) - * if lParam == NULL, a open file dialog will be opened, otherwise, lParam is taken as a FULL - * image filename (will be checked for existance, though) - */ - -INT_PTR avSetAvatar(HANDLE hContact, TCHAR* tszPath) -{ - BYTE is_locked = 0; - TCHAR FileName[MAX_PATH], szBackupName[MAX_PATH]; - TCHAR *szFinalName = NULL; - HANDLE hFile = 0; - BYTE locking_request; - - if (hContact == NULL || fei == NULL) - return 0; - - is_locked = db_get_b(hContact, "ContactPhoto", "Locked", 0); - - if ( tszPath == NULL ) { - OPENFILENAME ofn = {0}; - TCHAR filter[256]; - - filter[0] = '\0'; - CallService(MS_UTILS_GETBITMAPFILTERSTRINGST, SIZEOF(filter), ( LPARAM )filter); - - if (IsWinVer2000Plus()) - ofn.lStructSize = sizeof(ofn); - else - ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; - ofn.hwndOwner = 0; - ofn.lpstrFile = FileName; - ofn.lpstrFilter = filter; - ofn.nMaxFile = MAX_PATH; - ofn.nMaxFileTitle = MAX_PATH; - ofn.Flags = OFN_FILEMUSTEXIST | OFN_ENABLETEMPLATE | OFN_EXPLORER | OFN_ENABLESIZING | OFN_ENABLEHOOK; - ofn.lpstrInitialDir = _T("."); - *FileName = '\0'; - ofn.lpstrDefExt = _T(""); - ofn.hInstance = g_hInst; - ofn.lpTemplateName = MAKEINTRESOURCE(IDD_OPENSUBCLASS); - ofn.lpfnHook = (LPOFNHOOKPROC)OpenFileSubclass; - locking_request = is_locked; - ofn.lCustData = (LPARAM)&locking_request; - if (GetOpenFileName(&ofn)) { - szFinalName = FileName; - is_locked = locking_request ? 1 : is_locked; - } - else - return 0; - } - else - szFinalName = tszPath; - - /* - * filename is now set, check it and perform all needed action - */ - - if ((hFile = CreateFile(szFinalName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) - return 0; - - // file exists... - - CloseHandle(hFile); - - AVS_pathToRelative(szFinalName, szBackupName); - db_set_ts(hContact, "ContactPhoto", "Backup", szBackupName); - - db_set_b(hContact, "ContactPhoto", "Locked", is_locked); - db_set_ts(hContact, "ContactPhoto", "File", szFinalName); - MakePathRelative(hContact, szFinalName); - // Fix cache - ChangeAvatar(hContact, TRUE); - - return 0; -} - -INT_PTR SetAvatar(WPARAM wParam, LPARAM lParam) -{ - return avSetAvatar(( HANDLE )wParam, _A2T(( const char* )lParam )); -} - -INT_PTR SetAvatarW(WPARAM wParam, LPARAM lParam) -{ - return avSetAvatar(( HANDLE )wParam, ( TCHAR* )lParam ); -} - -/* - * see if is possible to set the avatar for the expecified protocol - */ -static INT_PTR CanSetMyAvatar(WPARAM wParam, LPARAM lParam) -{ - char *protocol = (char *) wParam; - if (protocol == NULL || fei == NULL) - return 0; - - return ProtoServiceExists(protocol, PS_SETMYAVATAR); -} - -struct SetMyAvatarHookData { - char *protocol; - BOOL square; - BOOL grow; - - BOOL thumbnail; -}; - -/* - * Callback to set thumbnaill view to open dialog - */ -static UINT_PTR CALLBACK SetMyAvatarHookProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch(msg) { - case WM_INITDIALOG: - { - InterlockedExchange(&hwndSetMyAvatar, (LONG) hwnd); - - SetWindowLongPtr(hwnd, GWLP_USERDATA, (LONG_PTR)lParam); - OPENFILENAME *ofn = (OPENFILENAME *)lParam; - SetMyAvatarHookData *data = (SetMyAvatarHookData *) ofn->lCustData; - data->thumbnail = TRUE; - - SetWindowText(GetDlgItem(hwnd, IDC_MAKE_SQUARE), TranslateT("Make the avatar square")); - SetWindowText(GetDlgItem(hwnd, IDC_GROW), TranslateT("Grow avatar to fit max allowed protocol size")); - - CheckDlgButton(hwnd, IDC_MAKE_SQUARE, data->square ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hwnd, IDC_GROW, data->grow ? BST_CHECKED : BST_UNCHECKED); - - if (data->protocol != NULL && (Proto_AvatarImageProportion(data->protocol) & PIP_SQUARE)) - EnableWindow(GetDlgItem(hwnd, IDC_MAKE_SQUARE), FALSE); - } - break; - - case WM_NOTIFY: - { - OPENFILENAME *ofn = (OPENFILENAME *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - SetMyAvatarHookData *data = (SetMyAvatarHookData *) ofn->lCustData; - if (data->thumbnail) - { - HWND hwndParent = GetParent(hwnd); - HWND hwndLv = FindWindowEx(hwndParent, NULL, _T("SHELLDLL_DefView"), NULL) ; - if (hwndLv != NULL) - { - SendMessage(hwndLv, WM_COMMAND, SHVIEW_THUMBNAIL, 0); - data->thumbnail = FALSE; - } - } - break; - } - case WM_DESTROY: - { - OPENFILENAME *ofn = (OPENFILENAME *)GetWindowLongPtr(hwnd, GWLP_USERDATA); - SetMyAvatarHookData *data = (SetMyAvatarHookData *) ofn->lCustData; - data->square = IsDlgButtonChecked(hwnd, IDC_MAKE_SQUARE); - data->grow = IsDlgButtonChecked(hwnd, IDC_GROW); - - InterlockedExchange(&hwndSetMyAvatar, 0); - break; - } - } - - return 0; -} - -const TCHAR *GetFormatExtension(int format) -{ - if (format == PA_FORMAT_PNG) - return _T(".png"); - if (format == PA_FORMAT_JPEG) - return _T(".jpg"); - if (format == PA_FORMAT_ICON) - return _T(".ico"); - if (format == PA_FORMAT_BMP) - return _T(".bmp"); - if (format == PA_FORMAT_GIF) - return _T(".gif"); - if (format == PA_FORMAT_SWF) - return _T(".swf"); - if (format == PA_FORMAT_XML) - return _T(".xml"); - - return NULL; -} - -int GetImageFormat(TCHAR *filename) -{ - size_t len = lstrlen(filename); - - if (len < 5) - return PA_FORMAT_UNKNOWN; - - if (_tcsicmp(_T(".png"), &filename[len-4]) == 0) - return PA_FORMAT_PNG; - - if (_tcsicmp(_T(".jpg"), &filename[len-4]) == 0 || _tcsicmp(_T(".jpeg"), &filename[len-4]) == 0) - return PA_FORMAT_JPEG; - - if (_tcsicmp(_T(".ico"), &filename[len-4]) == 0) - return PA_FORMAT_ICON; - - if (_tcsicmp(_T(".bmp"), &filename[len-4]) == 0 || _tcsicmp(_T(".rle"), &filename[len-4]) == 0) - return PA_FORMAT_BMP; - - if (_tcsicmp(_T(".gif"), &filename[len-4]) == 0) - return PA_FORMAT_GIF; - - if (_tcsicmp(_T(".swf"), &filename[len-4]) == 0) - return PA_FORMAT_SWF; - - if (_tcsicmp(_T(".xml"), &filename[len-4]) == 0) - return PA_FORMAT_XML; - - return PA_FORMAT_UNKNOWN; -} - -static void FilterGetStrings(TCHAR *filter, int bytesLeft, BOOL xml, BOOL swf) -{ - TCHAR *pfilter; - int wParam = bytesLeft; - - lstrcpyn(filter, TranslateT("All Files"), bytesLeft); bytesLeft-=lstrlen(filter); - _tcsncat(filter, _T(" (*.bmp;*.jpg;*.gif;*.png"), bytesLeft); - if (swf) _tcscat(filter, _T(";*.swf")); - if (xml) _tcscat(filter, _T(";*.xml")); - _tcscat(filter, _T(")")); - pfilter=filter+lstrlen(filter)+1; bytesLeft=wParam-(pfilter-filter); - lstrcpyn(pfilter, _T("*.BMP;*.RLE;*.JPG;*.JPEG;*.GIF;*.PNG"), bytesLeft); - if (swf) _tcscat(pfilter, _T(";*.SWF")); - if (xml) _tcscat(pfilter, _T(";*.XML")); - pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter); - - lstrcpyn(pfilter, TranslateT("Windows Bitmaps"), bytesLeft); bytesLeft-=lstrlen(pfilter); - _tcsncat(pfilter, _T(" (*.bmp;*.rle)"), bytesLeft); - pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter); - lstrcpyn(pfilter, _T("*.BMP;*.RLE"), bytesLeft); - pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter); - - lstrcpyn(pfilter,TranslateT("JPEG Bitmaps"),bytesLeft); bytesLeft-=lstrlen(pfilter); - _tcsncat(pfilter, _T(" (*.jpg;*.jpeg)"), bytesLeft); - pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter); - lstrcpyn(pfilter, _T("*.JPG;*.JPEG"), bytesLeft); - pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter); - - lstrcpyn(pfilter,TranslateT("GIF Bitmaps"),bytesLeft); bytesLeft-=lstrlen(pfilter); - _tcsncat(pfilter, _T(" (*.gif)"), bytesLeft); - pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter); - lstrcpyn(pfilter, _T("*.GIF"), bytesLeft); - pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter); - - lstrcpyn(pfilter,TranslateT("PNG Bitmaps"), bytesLeft); bytesLeft-=lstrlen(pfilter); - _tcsncat(pfilter, _T(" (*.png)"), bytesLeft); - pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter); - lstrcpyn(pfilter, _T("*.PNG"), bytesLeft); - pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter); - - if (swf) - { - lstrcpyn(pfilter,TranslateT("Flash Animations"), bytesLeft); bytesLeft-=lstrlen(pfilter); - _tcsncat(pfilter, _T(" (*.swf)"), bytesLeft); - pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter); - lstrcpyn(pfilter, _T("*.SWF"), bytesLeft); - pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter); - } - - if (xml) - { - lstrcpyn(pfilter, TranslateT("XML Files"), bytesLeft); bytesLeft-=lstrlen(pfilter); - _tcsncat(pfilter, _T(" (*.xml)"), bytesLeft); - pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter); - lstrcpyn(pfilter, _T("*.XML"), bytesLeft); - pfilter+=lstrlen(pfilter)+1; bytesLeft=wParam-(pfilter-filter); - } - - if (bytesLeft) *pfilter='\0'; -} - -static void DeleteGlobalUserAvatar() -{ - DBVARIANT dbv = {0}; - if (db_get_ts(NULL, AVS_MODULE, "GlobalUserAvatarFile", &dbv)) - return; - - TCHAR szFilename[MAX_PATH]; - AVS_pathToAbsolute(dbv.ptszVal, szFilename); - db_free(&dbv); - - DeleteFile(szFilename); - db_unset(NULL, AVS_MODULE, "GlobalUserAvatarFile"); -} - -static void SetIgnoreNotify(char *protocol, BOOL ignore) -{ - for(int i = 0; i < g_MyAvatars.getCount(); i++) { - if (protocol == NULL || !lstrcmpA(g_MyAvatars[i].szProtoname, protocol)) { - if (ignore) - g_MyAvatars[i].dwFlags |= AVS_IGNORENOTIFY; - else - g_MyAvatars[i].dwFlags &= ~AVS_IGNORENOTIFY; - } - } -} - -static int InternalRemoveMyAvatar(char *protocol) -{ - SetIgnoreNotify(protocol, TRUE); - - // Remove avatar - int ret = 0; - if (protocol != NULL) - { - if ( ProtoServiceExists(protocol, PS_SETMYAVATAR)) - ret = SaveAvatar(protocol, NULL); - else - ret = -3; - - if (ret == 0) - { - // Has global avatar? - DBVARIANT dbv = {0}; - if ( !db_get_ts(NULL, AVS_MODULE, "GlobalUserAvatarFile", &dbv)) { - db_free(&dbv); - db_set_b(NULL, AVS_MODULE, "GlobalUserAvatarNotConsistent", 1); - DeleteGlobalUserAvatar(); - } - } - } - else - { - PROTOACCOUNT **accs; - int i,count; - - ProtoEnumAccounts( &count, &accs ); - for (i = 0; i < count; i++) - { - if ( !ProtoServiceExists( accs[i]->szModuleName, PS_SETMYAVATAR)) - continue; - - if (!Proto_IsAvatarsEnabled( accs[i]->szModuleName )) - continue; - - // Found a protocol - int retTmp = SaveAvatar( accs[i]->szModuleName, NULL); - if (retTmp != 0) - ret = retTmp; - } - - DeleteGlobalUserAvatar(); - - if (ret) - db_set_b(NULL, AVS_MODULE, "GlobalUserAvatarNotConsistent", 1); - else - db_set_b(NULL, AVS_MODULE, "GlobalUserAvatarNotConsistent", 0); - } - - SetIgnoreNotify(protocol, FALSE); - - ReportMyAvatarChanged((WPARAM)(( protocol == NULL ) ? "" : protocol ), 0); - return ret; -} - -static int InternalSetMyAvatar(char *protocol, TCHAR *szFinalName, SetMyAvatarHookData &data, BOOL allAcceptXML, BOOL allAcceptSWF) -{ - HANDLE hFile = 0; - - int format = GetImageFormat(szFinalName); - if (format == PA_FORMAT_UNKNOWN || (hFile = CreateFile(szFinalName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE) - return -3; - - CloseHandle(hFile); - - // file exists... - - HBITMAP hBmp = NULL; - - if (format == PA_FORMAT_SWF) - { - if (!allAcceptSWF) - return -4; - } - else if (format == PA_FORMAT_XML) - { - if (!allAcceptXML) - return -4; - } - else - { - // Try to open if is not a flash or XML - hBmp = (HBITMAP) CallService(MS_IMG_LOAD, (WPARAM) szFinalName, IMGL_TCHAR); - if (hBmp == NULL) - return -4; - } - - SetIgnoreNotify(protocol, TRUE); - - int ret = 0; - if (protocol != NULL) - { - ret = SetProtoMyAvatar(protocol, hBmp, szFinalName, format, data.square, data.grow); - - if (ret == 0) - { - DeleteGlobalUserAvatar(); - db_set_b(NULL, AVS_MODULE, "GlobalUserAvatarNotConsistent", 1); - } - } - else - { - PROTOACCOUNT **accs; - int i,count; - - ProtoEnumAccounts( &count, &accs ); - for (i = 0; i < count; i++) - { - if ( !ProtoServiceExists( accs[i]->szModuleName, PS_SETMYAVATAR)) - continue; - - if ( !Proto_IsAvatarsEnabled( accs[i]->szModuleName )) - continue; - - int retTmp = SetProtoMyAvatar( accs[i]->szModuleName, hBmp, szFinalName, format, data.square, data.grow); - if (retTmp != 0) - ret = retTmp; - } - - DeleteGlobalUserAvatar(); - - if (ret) - { - db_set_b(NULL, AVS_MODULE, "GlobalUserAvatarNotConsistent", 1); - } - else - { - // Copy avatar file to store as global one - TCHAR globalFile[1024]; - BOOL saved = TRUE; - if (FoldersGetCustomPathT(hGlobalAvatarFolder, globalFile, SIZEOF(globalFile), _T(""))) - { - mir_sntprintf(globalFile, SIZEOF(globalFile), _T("%s\\%s"), g_szDataPath, _T("GlobalAvatar")); - CreateDirectory(globalFile, NULL); - } - - TCHAR *ext = _tcsrchr(szFinalName, _T('.')); // Can't be NULL here - if (format == PA_FORMAT_XML || format == PA_FORMAT_SWF) - { - mir_sntprintf(globalFile, SIZEOF(globalFile), _T("%s\\my_global_avatar%s"), globalFile, ext); - CopyFile(szFinalName, globalFile, FALSE); - } - else - { - // Resize (to avoid too big avatars) - ResizeBitmap rb = {0}; - rb.size = sizeof(ResizeBitmap); - rb.hBmp = hBmp; - rb.max_height = 300; - rb.max_width = 300; - rb.fit = (data.grow ? 0 : RESIZEBITMAP_FLAG_DONT_GROW) - | (data.square ? RESIZEBITMAP_MAKE_SQUARE : RESIZEBITMAP_KEEP_PROPORTIONS); - - HBITMAP hBmpTmp = (HBITMAP) BmpFilterResizeBitmap((WPARAM)&rb, 0); - - // Check if need to resize - if (hBmpTmp == hBmp || hBmpTmp == NULL) - { - // Use original image - mir_sntprintf(globalFile, SIZEOF(globalFile), _T("%s\\my_global_avatar%s"), globalFile, ext); - CopyFile(szFinalName, globalFile, FALSE); - } - else - { - // Save as PNG - mir_sntprintf(globalFile, SIZEOF(globalFile), _T("%s\\my_global_avatar.png"), globalFile); - if (BmpFilterSaveBitmap((WPARAM) hBmpTmp, (LPARAM) globalFile)) - saved = FALSE; - - DeleteObject(hBmpTmp); - } - } - - if (saved) - { - TCHAR relFile[1024]; - if (AVS_pathToRelative(globalFile, relFile)) - db_set_ts(NULL, AVS_MODULE, "GlobalUserAvatarFile", relFile); - else - db_set_ts(NULL, AVS_MODULE, "GlobalUserAvatarFile", globalFile); - - db_set_b(NULL, AVS_MODULE, "GlobalUserAvatarNotConsistent", 0); - } - else - { - db_set_b(NULL, AVS_MODULE, "GlobalUserAvatarNotConsistent", 1); - } - } - } - - DeleteObject(hBmp); - - SetIgnoreNotify(protocol, FALSE); - - ReportMyAvatarChanged((WPARAM)(( protocol == NULL ) ? "" : protocol ), 0); - return ret; -} - -/* - * set an avatar for a protocol (service function) - * if lParam == NULL, a open file dialog will be opened, otherwise, lParam is taken as a FULL - * image filename (will be checked for existance, though) - */ - -INT_PTR avSetMyAvatar( char* protocol, TCHAR* tszPath ) -{ - TCHAR FileName[MAX_PATH]; - TCHAR *szFinalName = NULL; - BOOL allAcceptXML; - BOOL allAcceptSWF; - - // Protocol allow seting of avatar? - if (protocol != NULL && !CanSetMyAvatar((WPARAM) protocol, 0)) - return -1; - - if (tszPath == NULL && hwndSetMyAvatar != 0) - { - SetForegroundWindow((HWND) hwndSetMyAvatar); - SetFocus((HWND) hwndSetMyAvatar); - ShowWindow((HWND) hwndSetMyAvatar, SW_SHOW); - return -2; - } - - SetMyAvatarHookData data = { 0 }; - - // Check for XML and SWF - if (protocol == NULL) - { - allAcceptXML = TRUE; - allAcceptSWF = TRUE; - - PROTOACCOUNT **accs; - int i,count; - - ProtoEnumAccounts( &count, &accs ); - for (i = 0; i < count; i++) - { - if ( !ProtoServiceExists( accs[i]->szModuleName, PS_SETMYAVATAR)) - continue; - - if ( !Proto_IsAvatarsEnabled( accs[i]->szModuleName )) - continue; - - allAcceptXML = allAcceptXML && Proto_IsAvatarFormatSupported( accs[i]->szModuleName, PA_FORMAT_XML); - allAcceptSWF = allAcceptSWF && Proto_IsAvatarFormatSupported( accs[i]->szModuleName, PA_FORMAT_SWF); - } - - data.square = db_get_b(0, AVS_MODULE, "SetAllwaysMakeSquare", 0); - } - else - { - allAcceptXML = Proto_IsAvatarFormatSupported(protocol, PA_FORMAT_XML); - allAcceptSWF = Proto_IsAvatarFormatSupported(protocol, PA_FORMAT_SWF); - - data.protocol = protocol; - data.square = (Proto_AvatarImageProportion(protocol) & PIP_SQUARE) - || db_get_b(0, AVS_MODULE, "SetAllwaysMakeSquare", 0); - } - - if (tszPath == NULL) { - OPENFILENAME ofn = {0}; - TCHAR filter[512]; - TCHAR inipath[1024]; - - data.protocol = protocol; - - filter[0] = '\0'; - FilterGetStrings(filter, SIZEOF(filter), allAcceptXML, allAcceptSWF); - - FoldersGetCustomPathT(hMyAvatarsFolder, inipath, SIZEOF(inipath), _T(".")); - - if (IsWinVer2000Plus()) - ofn.lStructSize = sizeof(ofn); - else - ofn.lStructSize = OPENFILENAME_SIZE_VERSION_400; - ofn.hwndOwner = 0; - ofn.lpstrFile = FileName; - ofn.lpstrFilter = filter; - ofn.nMaxFile = MAX_PATH; - ofn.nMaxFileTitle = MAX_PATH; - ofn.Flags = OFN_FILEMUSTEXIST | OFN_ENABLETEMPLATE | OFN_EXPLORER | OFN_ENABLESIZING | OFN_ENABLEHOOK; - ofn.lpstrInitialDir = inipath; - ofn.lpTemplateName = MAKEINTRESOURCE(IDD_SET_OWN_SUBCLASS); - ofn.lpfnHook = SetMyAvatarHookProc; - ofn.lCustData = (LPARAM) &data; - - *FileName = '\0'; - ofn.lpstrDefExt = _T(""); - ofn.hInstance = g_hInst; - - TCHAR title[256]; - if (protocol == NULL) - mir_sntprintf(title, SIZEOF(title), TranslateT("Set My Avatar")); - else - { - TCHAR* prototmp = mir_a2t(protocol); - mir_sntprintf(title, SIZEOF(title), TranslateT("Set My Avatar for %s"), prototmp); - mir_free(prototmp); - } - ofn.lpstrTitle = title; - - if (GetOpenFileName(&ofn)) - szFinalName = FileName; - else - return 1; - } - else - szFinalName = (TCHAR *)tszPath; - - /* - * filename is now set, check it and perform all needed action - */ - - if (szFinalName[0] == '\0') - return InternalRemoveMyAvatar(protocol); - - return InternalSetMyAvatar(protocol, szFinalName, data, allAcceptXML, allAcceptSWF); -} - -static INT_PTR SetMyAvatar( WPARAM wParam, LPARAM lParam ) -{ - return avSetMyAvatar(( char* )wParam, _A2T(( const char* )lParam )); -} - -static INT_PTR SetMyAvatarW( WPARAM wParam, LPARAM lParam ) -{ - return avSetMyAvatar(( char* )wParam, ( TCHAR* )lParam ); -} - -/////////////////////////////////////////////////////////////////////////////////////////////////////// - -static DWORD GetFileSize(TCHAR *szFilename) -{ - HANDLE hFile = CreateFile(szFilename, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); - if (hFile == INVALID_HANDLE_VALUE) - return 0; - - DWORD low = GetFileSize(hFile, NULL); - - CloseHandle(hFile); - - if (low == INVALID_FILE_SIZE) - return 0; - - return low; -} - -struct SaveProtocolData { - DWORD max_size; - TCHAR image_file_name[MAX_PATH]; - BOOL saved; - BOOL need_smaller_size; - int width; - int height; - TCHAR temp_file[MAX_PATH]; - HBITMAP hBmpProto; -}; - -static void SaveImage(SaveProtocolData &d, char *protocol, int format) -{ - if (Proto_IsAvatarFormatSupported(protocol, format)) - { - mir_sntprintf(d.image_file_name, SIZEOF(d.image_file_name), _T("%s%s"), d.temp_file, GetFormatExtension(format)); - if (!BmpFilterSaveBitmapT(d.hBmpProto, d.image_file_name, format == PA_FORMAT_JPEG ? JPEG_QUALITYSUPERB : 0)) - { - if (d.max_size != 0 && GetFileSize(d.image_file_name) > d.max_size) - { - DeleteFile(d.image_file_name); - - if (format == PA_FORMAT_JPEG) - { - // Try with lower quality - if (!BmpFilterSaveBitmapT(d.hBmpProto, d.image_file_name, JPEG_QUALITYGOOD)) - { - if (GetFileSize(d.image_file_name) > d.max_size) - { - DeleteFile(d.image_file_name); - d.need_smaller_size = TRUE; - } - else - d.saved = TRUE; - } - } - else - d.need_smaller_size = TRUE; - } - else - d.saved = TRUE; - } - } -} - -static int SetProtoMyAvatar(char *protocol, HBITMAP hBmp, TCHAR *originalFilename, int originalFormat, BOOL square, BOOL grow) -{ - if (!ProtoServiceExists(protocol, PS_SETMYAVATAR)) - return -1; - - // If is swf or xml, just set it - - if (originalFormat == PA_FORMAT_SWF) - { - if (!Proto_IsAvatarFormatSupported(protocol, PA_FORMAT_SWF)) - return -1; - - return SaveAvatar(protocol, originalFilename); - } - - if (originalFormat == PA_FORMAT_XML) - { - if (!Proto_IsAvatarFormatSupported(protocol, PA_FORMAT_XML)) - return -1; - - return SaveAvatar(protocol, originalFilename); - } - - // Get protocol info - SaveProtocolData d = {0}; - - d.max_size = (DWORD) Proto_GetAvatarMaxFileSize(protocol); - - Proto_GetAvatarMaxSize(protocol, &d.width, &d.height); - int orig_width = d.width; - int orig_height = d.height; - - if (Proto_AvatarImageProportion(protocol) & PIP_SQUARE) - square = TRUE; - - // Try to save until a valid image is found or we give up - int num_tries = 0; - do { - // Lets do it - ResizeBitmap rb; - rb.size = sizeof(ResizeBitmap); - rb.hBmp = hBmp; - rb.max_height = d.height; - rb.max_width = d.width; - rb.fit = (grow ? 0 : RESIZEBITMAP_FLAG_DONT_GROW) - | (square ? RESIZEBITMAP_MAKE_SQUARE : RESIZEBITMAP_KEEP_PROPORTIONS); - - d.hBmpProto = (HBITMAP) BmpFilterResizeBitmap((WPARAM)&rb, 0); - - if (d.hBmpProto == NULL) - { - if (d.temp_file[0] != '\0') - DeleteFile(d.temp_file); - return -1; - } - - // Check if can use original image - if (d.hBmpProto == hBmp - && Proto_IsAvatarFormatSupported(protocol, originalFormat) - && (d.max_size == 0 || GetFileSize(originalFilename) < d.max_size)) - { - if (d.temp_file[0] != '\0') - DeleteFile(d.temp_file); - - // Use original image - return SaveAvatar(protocol, originalFilename); - } - - // Create a temporary file (if was not created already) - if (d.temp_file[0] == '\0') - { - d.temp_file[0] = '\0'; - if (GetTempPath(MAX_PATH, d.temp_file) == 0 - || GetTempFileName(d.temp_file, _T("mir_av_"), 0, d.temp_file) == 0) - { - DeleteObject(d.hBmpProto); - return -1; - } - } - - // Which format? - - // First try to use original format - if (originalFormat != PA_FORMAT_BMP) - SaveImage(d, protocol, originalFormat); - - if (!d.saved && originalFormat != PA_FORMAT_PNG) - SaveImage(d, protocol, PA_FORMAT_PNG); - - if (!d.saved && originalFormat != PA_FORMAT_JPEG) - SaveImage(d, protocol, PA_FORMAT_JPEG); - - if (!d.saved && originalFormat != PA_FORMAT_GIF) - SaveImage(d, protocol, PA_FORMAT_GIF); - - if (!d.saved) - SaveImage(d, protocol, PA_FORMAT_BMP); - - num_tries++; - if (!d.saved && d.need_smaller_size && num_tries < 4) - { - // Cleanup - if (d.hBmpProto != hBmp) - DeleteObject(d.hBmpProto); - - // use a smaller size - d.width = orig_width * (4 - num_tries) / 4; - d.height = orig_height * (4 - num_tries) / 4; - } - - } while(!d.saved && d.need_smaller_size && num_tries < 4); - - int ret; - - if (d.saved) - { - // Call proto service - ret = SaveAvatar(protocol, d.image_file_name); - DeleteFile(d.image_file_name); - } - else - { - ret = -1; - } - - if (d.temp_file[0] != '\0') - DeleteFile(d.temp_file); - - if (d.hBmpProto != hBmp) - DeleteObject(d.hBmpProto); - - return ret; -} - -static INT_PTR ContactOptions(WPARAM wParam, LPARAM lParam) -{ - if (wParam) - CreateDialogParam(g_hInst, MAKEINTRESOURCE(IDD_AVATAROPTIONS), 0, DlgProcAvatarOptions, (LPARAM)wParam); - return 0; -} - -INT_PTR GetMyAvatar(WPARAM wParam, LPARAM lParam) -{ - if (wParam || g_shutDown || fei == NULL) - return 0; - - char *szProto = (char *)lParam; - if (lParam == 0 || IsBadReadPtr(szProto, 4)) - return 0; - - for(int i = 0; i < g_MyAvatars.getCount(); i++) - if (!lstrcmpA(szProto, g_MyAvatars[i].szProtoname) && g_MyAvatars[i].hbmPic != 0) - return (INT_PTR)&g_MyAvatars[i]; - - return 0; -} - -static protoPicCacheEntry *GetProtoDefaultAvatar(HANDLE hContact) -{ - char *szProto = GetContactProto(hContact); - if (szProto) { - for(int i = 0; i < g_ProtoPictures.getCount(); i++) { - protoPicCacheEntry& p = g_ProtoPictures[i]; - if ( !lstrcmpA(p.szProtoname, szProto) && p.hbmPic != NULL) - return &g_ProtoPictures[i]; - } - } - return NULL; + return -1; + if ((lstrcmpA(p2->szProtoname, "Global avatar") == 0) || strstr(p1->szProtoname, "Global avatar")) + return 1; + return lstrcmpA( p1->szProtoname, p2->szProtoname ); } -HANDLE GetContactThatHaveTheAvatar(HANDLE hContact, int locked = -1) -{ - if (g_MetaAvail && db_get_b(NULL, g_szMetaName, "Enabled", 0)) { - if (db_get_dw(hContact, g_szMetaName, "NumContacts", 0) >= 1) { - if (locked == -1) - locked = db_get_b(hContact, "ContactPhoto", "Locked", 0); +OBJLIST + g_ProtoPictures( 10, ComparePicture ), + g_MyAvatars( 10, ComparePicture ); - if (!locked) - hContact = (HANDLE)CallService(MS_MC_GETMOSTONLINECONTACT, (WPARAM)hContact, 0); - } - } - return hContact; -} +char* g_szMetaName = NULL; -INT_PTR GetAvatarBitmap(WPARAM wParam, LPARAM lParam) -{ - if (wParam == 0 || g_shutDown || fei == NULL) - return 0; +// Stores the id of the dialog - HANDLE hContact = (HANDLE) wParam; - hContact = GetContactThatHaveTheAvatar(hContact); +int OnDetailsInit(WPARAM wParam, LPARAM lParam); +int OptInit(WPARAM wParam, LPARAM lParam); - // Get the node - struct CacheNode *node = FindAvatarInCache(hContact, TRUE); - if (node == NULL || !node->loaded) - return (INT_PTR) GetProtoDefaultAvatar(hContact); - else - return (INT_PTR) &node->ace; -} +FI_INTERFACE *fei = 0; -// Just delete an avatar from cache -// An cache entry is never deleted. What is deleted is the image handle inside it -// This is done this way to keep track of which avatars avs have to keep track -void DeleteAvatarFromCache(HANDLE hContact, BOOL forever) -{ - hContact = GetContactThatHaveTheAvatar(hContact); - - struct CacheNode *node = FindAvatarInCache(hContact, FALSE); - if (node == NULL) { - struct CacheNode temp_node = {0}; - if (g_MetaAvail) - temp_node.dwFlags |= (db_get_b(hContact, g_szMetaName, "IsSubcontact", 0) ? MC_ISSUBCONTACT : 0); - NotifyMetaAware(hContact, &temp_node, (AVATARCACHEENTRY *)GetProtoDefaultAvatar(hContact)); - return; - } - node->mustLoad = -1; // mark for deletion - if (forever) - node->dwFlags |= AVS_DELETENODEFOREVER; - SetEvent(hLoaderEvent); -} +PLUGININFOEX pluginInfoEx = { + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESCRIPTION, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + // {E00F1643-263C-4599-B84B-053E5C511D29} + {0xe00f1643, 0x263c, 0x4599, {0xb8, 0x4b, 0x5, 0x3e, 0x5c, 0x51, 0x1d, 0x29}} +}; -int ChangeAvatar(HANDLE hContact, BOOL fLoad, BOOL fNotifyHist, int pa_format) +static TCHAR* getJGMailID(char *szProto) { - if (g_shutDown) - return 0; - - hContact = GetContactThatHaveTheAvatar(hContact); + static TCHAR szJID[MAX_PATH+1]; szJID[0] = '\0'; - // Get the node - struct CacheNode *node = FindAvatarInCache(hContact, g_AvatarHistoryAvail && fNotifyHist, TRUE); - if (node == NULL) - return 0; + DBVARIANT dbva, dbvb; + if ( db_get_ts(NULL, szProto, "LoginName", &dbva)) + return szJID; - if (fNotifyHist) - node->dwFlags |= AVH_MUSTNOTIFY; + if ( db_get_ts(NULL, szProto, "LoginServer", &dbvb)) { + db_free(&dbva); + return szJID; + } - node->mustLoad = fLoad ? 1 : -1; - node->pa_format = pa_format; - SetEvent(hLoaderEvent); - return 0; + mir_sntprintf(szJID, SIZEOF(szJID), _T("%s@%s"), dbva.ptszVal, dbvb.ptszVal); + db_free(&dbva); + db_free(&dbvb); + return szJID; } -/* - * this thread scans the cache and handles nodes which have mustLoad set to > 0 (must be loaded/reloaded) or - * nodes where mustLoad is < 0 (must be deleted). - * its waken up by the event and tries to lock the cache only when absolutely necessary. - */ - -static void PicLoader(LPVOID param) +static int ProtocolAck(WPARAM wParam, LPARAM lParam) { - DWORD dwDelay = db_get_dw(NULL, AVS_MODULE, "picloader_sleeptime", 80); - - if (dwDelay < 30) - dwDelay = 30; - else if (dwDelay > 100) - dwDelay = 100; - - while(!g_shutDown) { - struct CacheNode *node = g_Cache; - - while(!g_shutDown && node) { - if (node->mustLoad > 0 && node->ace.hContact) { - node->mustLoad = 0; - AVATARCACHEENTRY ace_temp; - - if (db_get_b(node->ace.hContact, "ContactPhoto", "NeedUpdate", 0)) - QueueAdd(node->ace.hContact); - - CopyMemory(&ace_temp, &node->ace, sizeof(AVATARCACHEENTRY)); - ace_temp.hbmPic = 0; - - int result = CreateAvatarInCache(node->ace.hContact, &ace_temp, NULL); - - if (result == -2) { - char *szProto = GetContactProto(node->ace.hContact); - if (szProto == NULL || Proto_NeedDelaysForAvatars(szProto)) - QueueAdd(node->ace.hContact); - else if (FetchAvatarFor(node->ace.hContact, szProto) == GAIR_SUCCESS) // Try yo create again - result = CreateAvatarInCache(node->ace.hContact, &ace_temp, NULL); - } - - if (result == 1 && ace_temp.hbmPic != 0) { // Loaded - HBITMAP oldPic = node->ace.hbmPic; - - EnterCriticalSection(&cachecs); - CopyMemory(&node->ace, &ace_temp, sizeof(AVATARCACHEENTRY)); - node->loaded = TRUE; - LeaveCriticalSection(&cachecs); - if (oldPic) - DeleteObject(oldPic); - NotifyMetaAware(node->ace.hContact, node); - } - else if (result == 0 || result == -3) { // Has no avatar - HBITMAP oldPic = node->ace.hbmPic; - - EnterCriticalSection(&cachecs); - CopyMemory(&node->ace, &ace_temp, sizeof(AVATARCACHEENTRY)); - node->loaded = FALSE; - node->mustLoad = 0; - LeaveCriticalSection(&cachecs); - if (oldPic) - DeleteObject(oldPic); - NotifyMetaAware(node->ace.hContact, node); - } - - mir_sleep(dwDelay); + ACKDATA *ack = (ACKDATA *) lParam; + + if (ack != NULL && ack->type == ACKTYPE_AVATAR && ack->hContact != 0 && (!g_MetaAvail || strcmp(ack->szModule, g_szMetaName))) { + if (ack->result == ACKRESULT_SUCCESS) { + if (ack->hProcess == NULL) + ProcessAvatarInfo(ack->hContact, GAIR_NOAVATAR, NULL, ack->szModule); + else + ProcessAvatarInfo(ack->hContact, GAIR_SUCCESS, (PROTO_AVATAR_INFORMATIONT *) ack->hProcess, ack->szModule); + } + else if (ack->result == ACKRESULT_FAILED) { + ProcessAvatarInfo(ack->hContact, GAIR_FAILED, (PROTO_AVATAR_INFORMATIONT *) ack->hProcess, ack->szModule); + } + else if (ack->result == ACKRESULT_STATUS) { + char *szProto = GetContactProto(ack->hContact); + if (szProto == NULL || Proto_NeedDelaysForAvatars(szProto)) { + // Queue + db_set_b(ack->hContact, "ContactPhoto", "NeedUpdate", 1); + QueueAdd(ack->hContact); } - else if (node->mustLoad < 0 && node->ace.hContact) { // delete this picture - HANDLE hContact = node->ace.hContact; - EnterCriticalSection(&cachecs); - node->mustLoad = 0; - node->loaded = 0; - if (node->ace.hbmPic) - DeleteObject(node->ace.hbmPic); - ZeroMemory(&node->ace, sizeof(AVATARCACHEENTRY)); - if (node->dwFlags & AVS_DELETENODEFOREVER) - node->dwFlags &= ~AVS_DELETENODEFOREVER; - else - node->ace.hContact = hContact; - - LeaveCriticalSection(&cachecs); - NotifyMetaAware(hContact, node, (AVATARCACHEENTRY *)GetProtoDefaultAvatar(hContact)); + else { + // Fetch it now + FetchAvatarFor(ack->hContact, szProto); } - // protect this by changes from the cache block allocator as it can cause inconsistencies while working - // on allocating a new block. - EnterCriticalSection(&alloccs); - node = node->pNextNode; - LeaveCriticalSection(&alloccs); } - WaitForSingleObject(hLoaderEvent, INFINITE); - //_DebugTrace(0, "pic loader awake..."); - ResetEvent(hLoaderEvent); } + return 0; } static int MetaChanged(WPARAM wParam, LPARAM lParam) @@ -1830,7 +139,7 @@ static int MetaChanged(WPARAM wParam, LPARAM lParam) HANDLE hSubContact = GetContactThatHaveTheAvatar(hContact); // Get the node - struct CacheNode *node = FindAvatarInCache(hSubContact, TRUE); + CacheNode *node = FindAvatarInCache(hSubContact, TRUE); if (node == NULL || !node->loaded) { ace = (AVATARCACHEENTRY *)GetProtoDefaultAvatar(hSubContact); QueueAdd(hSubContact); @@ -1852,7 +161,7 @@ static void LoadDefaultInfo() g_ProtoPictures.insert(pce); } -static void LoadProtoInfo(PROTOCOLDESCRIPTOR* proto) +static void LoadProtoInfo(PROTOCOLDESCRIPTOR *proto) { if (proto->type != PROTOTYPE_PROTOCOL || proto->cbSize != sizeof(*proto)) return; @@ -1871,7 +180,7 @@ static void LoadProtoInfo(PROTOCOLDESCRIPTOR* proto) g_ProtoPictures.insert(pce); } -static void LoadAccountInfo( PROTOACCOUNT* acc ) +static void LoadAccountInfo(PROTOACCOUNT *acc) { protoPicCacheEntry *pce = new protoPicCacheEntry; if ( CreateAvatarInCache(0, pce, acc->szModuleName) != 1) @@ -1913,112 +222,6 @@ static int OnAccChanged(WPARAM wParam, LPARAM lParam) return 0; } -static int ModulesLoaded(WPARAM wParam, LPARAM lParam) -{ - int i; - DBVARIANT dbv = {0}; - TCHAR szEventName[100]; - int result = 0; - - mir_sntprintf(szEventName, 100, _T("avs_loaderthread_%d"), GetCurrentThreadId()); - hLoaderEvent = CreateEvent(NULL, TRUE, FALSE, szEventName); - SetThreadPriority( mir_forkthread(PicLoader, 0), THREAD_PRIORITY_IDLE); - - // Folders plugin support - hMyAvatarsFolder = FoldersRegisterCustomPathT(LPGEN("Avatars"), LPGEN("My Avatars"), MIRANDA_USERDATAT _T("\\Avatars")); - hGlobalAvatarFolder = FoldersRegisterCustomPathT(LPGEN("Avatars"), LPGEN("My Global Avatar Cache"), MIRANDA_USERDATAT _T("\\Avatars")); - - g_AvatarHistoryAvail = ServiceExists(MS_AVATARHISTORY_ENABLED); - - g_MetaAvail = ServiceExists(MS_MC_GETPROTOCOLNAME) ? TRUE : FALSE; - if (g_MetaAvail) { - g_szMetaName = (char *)CallService(MS_MC_GETPROTOCOLNAME, 0, 0); - if (g_szMetaName == NULL) - g_MetaAvail = FALSE; - } - - PROTOACCOUNT **accs = NULL; - int accCount; - ProtoEnumAccounts(&accCount, &accs); - - if (fei != NULL) { - LoadDefaultInfo(); - PROTOCOLDESCRIPTOR** proto; - int protoCount; - CallService(MS_PROTO_ENUMPROTOS, (WPARAM)&protoCount, (LPARAM)&proto); - for (i=0; i < protoCount; i++ ) - LoadProtoInfo( proto[i] ); - for (i=0; i < accCount; i++) - LoadAccountInfo( accs[i] ); - } - - // Load global avatar - protoPicCacheEntry *pce = new protoPicCacheEntry; - CreateAvatarInCache((HANDLE)-1, pce, ""); - pce->szProtoname = mir_strdup(""); - g_MyAvatars.insert( pce ); - - HookEvent(ME_PROTO_ACCLISTCHANGED, OnAccChanged); - HookEvent(ME_SYSTEM_PRESHUTDOWN, ShutdownProc); - HookEvent(ME_USERINFO_INITIALISE, OnDetailsInit); - return 0; -} - -static void ReloadMyAvatar(LPVOID lpParam) -{ - char *szProto = (char *)lpParam; - - mir_sleep(500); - for(int i = 0; !g_shutDown && i < g_MyAvatars.getCount(); i++) { - char *myAvatarProto = g_MyAvatars[i].szProtoname; - - if (szProto[0] == 0) { - // Notify to all possibles - if (lstrcmpA(myAvatarProto, szProto)) { - if (!ProtoServiceExists( myAvatarProto, PS_SETMYAVATAR)) - continue; - if (!Proto_IsAvatarsEnabled( myAvatarProto )) - continue; - } - - } - else if (lstrcmpA(myAvatarProto, szProto)) - continue; - - if (g_MyAvatars[i].hbmPic) - DeleteObject(g_MyAvatars[i].hbmPic); - - if (CreateAvatarInCache((HANDLE)-1, &g_MyAvatars[i], myAvatarProto) != -1) - NotifyEventHooks(hMyAvatarChanged, (WPARAM)myAvatarProto, (LPARAM)&g_MyAvatars[i]); - else - NotifyEventHooks(hMyAvatarChanged, (WPARAM)myAvatarProto, 0); - } - - free(lpParam); -} - -static INT_PTR ReportMyAvatarChanged(WPARAM wParam, LPARAM lParam) -{ - if (wParam == NULL) - return -1; - - char *proto = (char *) wParam; - - for(int i = 0; i < g_MyAvatars.getCount(); i++) { - if (g_MyAvatars[i].dwFlags & AVS_IGNORENOTIFY) - continue; - - if ( !lstrcmpA(g_MyAvatars[i].szProtoname, proto)) { - LPVOID lpParam = (void *)malloc(lstrlenA(g_MyAvatars[i].szProtoname) + 2); - strcpy((char *)lpParam, g_MyAvatars[i].szProtoname); - mir_forkthread(ReloadMyAvatar, lpParam); - return 0; - } - } - - return -2; -} - static int ContactSettingChanged(WPARAM wParam, LPARAM lParam) { DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam; @@ -2158,59 +361,59 @@ void InternalDrawAvatar(AVATARDRAWREQUEST *r, HBITMAP hbm, LONG bmWidth, LONG bm } } -INT_PTR DrawAvatarPicture(WPARAM wParam, LPARAM lParam) +static int ModulesLoaded(WPARAM wParam, LPARAM lParam) { - AVATARDRAWREQUEST *r = (AVATARDRAWREQUEST *)lParam; - AVATARCACHEENTRY *ace = NULL; + int i; + DBVARIANT dbv = {0}; + TCHAR szEventName[100]; + int result = 0; - if (fei == NULL || r == NULL || IsBadReadPtr((void *)r, sizeof(AVATARDRAWREQUEST))) - return 0; + mir_sntprintf(szEventName, 100, _T("avs_loaderthread_%d"), GetCurrentThreadId()); + hLoaderEvent = CreateEvent(NULL, TRUE, FALSE, szEventName); + SetThreadPriority( mir_forkthread(PicLoader, 0), THREAD_PRIORITY_IDLE); - if (r->cbSize != sizeof(AVATARDRAWREQUEST)) - return 0; + // Folders plugin support + hMyAvatarsFolder = FoldersRegisterCustomPathT(LPGEN("Avatars"), LPGEN("My Avatars"), MIRANDA_USERDATAT _T("\\Avatars")); + hGlobalAvatarFolder = FoldersRegisterCustomPathT(LPGEN("Avatars"), LPGEN("My Global Avatar Cache"), MIRANDA_USERDATAT _T("\\Avatars")); - if (r->dwFlags & AVDRQ_PROTOPICT) { - if (r->szProto == NULL) - return 0; + g_AvatarHistoryAvail = ServiceExists(MS_AVATARHISTORY_ENABLED); - for(int i = 0; i < g_ProtoPictures.getCount(); i++) { - protoPicCacheEntry& p = g_ProtoPictures[i]; - if ( !lstrcmpA(p.szProtoname, r->szProto) && lstrlenA(r->szProto) == lstrlenA(p.szProtoname) && p.hbmPic != 0) { - ace = (AVATARCACHEENTRY *)&g_ProtoPictures[i]; - break; - } - } + g_MetaAvail = ServiceExists(MS_MC_GETPROTOCOLNAME) ? TRUE : FALSE; + if (g_MetaAvail) { + g_szMetaName = (char *)CallService(MS_MC_GETPROTOCOLNAME, 0, 0); + if (g_szMetaName == NULL) + g_MetaAvail = FALSE; } - else if (r->dwFlags & AVDRQ_OWNPIC) { - if (r->szProto == NULL) - return 0; - if (r->szProto[0] == '\0' && db_get_b(NULL, AVS_MODULE, "GlobalUserAvatarNotConsistent", 1)) - return -1; + PROTOACCOUNT **accs = NULL; + int accCount; + ProtoEnumAccounts(&accCount, &accs); - ace = (AVATARCACHEENTRY *)GetMyAvatar(0, (LPARAM)r->szProto); + if (fei != NULL) { + LoadDefaultInfo(); + PROTOCOLDESCRIPTOR** proto; + int protoCount; + CallService(MS_PROTO_ENUMPROTOS, (WPARAM)&protoCount, (LPARAM)&proto); + for (i=0; i < protoCount; i++ ) + LoadProtoInfo( proto[i] ); + for (i=0; i < accCount; i++) + LoadAccountInfo( accs[i] ); } - else - ace = (AVATARCACHEENTRY *)GetAvatarBitmap((WPARAM)r->hContact, 0); - - if (ace && (!(r->dwFlags & AVDRQ_RESPECTHIDDEN) || !(ace->dwFlags & AVS_HIDEONCLIST))) { - ace->t_lastAccess = time(NULL); - if (ace->bmHeight == 0 || ace->bmWidth == 0 || ace->hbmPic == 0) - return 0; - - InternalDrawAvatar(r, ace->hbmPic, ace->bmWidth, ace->bmHeight, ace->dwFlags); - return 1; - } + // Load global avatar + protoPicCacheEntry *pce = new protoPicCacheEntry; + CreateAvatarInCache((HANDLE)-1, pce, ""); + pce->szProtoname = mir_strdup(""); + g_MyAvatars.insert(pce); + HookEvent(ME_PROTO_ACCLISTCHANGED, OnAccChanged); + HookEvent(ME_SYSTEM_PRESHUTDOWN, ShutdownProc); + HookEvent(ME_USERINFO_INITIALISE, OnDetailsInit); return 0; } static int LoadAvatarModule() { - InitializeCriticalSection(&cachecs); - InitializeCriticalSection(&alloccs); - hShutdownEvent = CreateEvent(NULL, TRUE, FALSE, NULL); HookEvent(ME_OPT_INITIALISE, OptInit); @@ -2219,27 +422,12 @@ static int LoadAvatarModule() HookEvent(ME_DB_CONTACT_DELETED, ContactDeleted); HookEvent(ME_PROTO_ACK, ProtocolAck); - CreateServiceFunction(MS_AV_GETAVATARBITMAP, GetAvatarBitmap); - CreateServiceFunction(MS_AV_PROTECTAVATAR, ProtectAvatar); - CreateServiceFunction(MS_AV_SETAVATAR, SetAvatar); - CreateServiceFunction(MS_AV_SETMYAVATAR, SetMyAvatar); - CreateServiceFunction(MS_AV_CANSETMYAVATAR, CanSetMyAvatar); - CreateServiceFunction(MS_AV_CONTACTOPTIONS, ContactOptions); - CreateServiceFunction(MS_AV_DRAWAVATAR, DrawAvatarPicture); - CreateServiceFunction(MS_AV_GETMYAVATAR, GetMyAvatar); - CreateServiceFunction(MS_AV_REPORTMYAVATARCHANGED, ReportMyAvatarChanged); - CreateServiceFunction(MS_AV_LOADBITMAP32, BmpFilterLoadBitmap32); - CreateServiceFunction(MS_AV_SAVEBITMAP, BmpFilterSaveBitmap); - CreateServiceFunction(MS_AV_CANSAVEBITMAP, BmpFilterCanSaveBitmap); - CreateServiceFunction(MS_AV_RESIZEBITMAP, BmpFilterResizeBitmap); - CreateServiceFunction(MS_AV_SETAVATARW, SetAvatarW); - CreateServiceFunction(MS_AV_SETMYAVATARW, SetMyAvatarW); - hEventChanged = CreateHookableEvent(ME_AV_AVATARCHANGED); hEventContactAvatarChanged = CreateHookableEvent(ME_AV_CONTACTAVATARCHANGED); hMyAvatarChanged = CreateHookableEvent(ME_AV_MYAVATARCHANGED); - AllocCacheBlock(); + InitServices(); + InitCache(); InitPolls(); HMODULE hDll; @@ -2284,17 +472,7 @@ extern "C" int __declspec(dllexport) Load(void) extern "C" int __declspec(dllexport) Unload(void) { UninitPolls(); - - struct CacheNode *pNode = g_Cache; - while(pNode) { - if (pNode->ace.hbmPic != 0) - DeleteObject(pNode->ace.hbmPic); - pNode = pNode->pNextNode; - } - - for(int i = 0; i < g_curBlock; i++) - free(g_cacheBlocks[i]); - free(g_cacheBlocks); + UnloadCache(); g_ProtoPictures.destroy(); g_MyAvatars.destroy(); @@ -2304,113 +482,5 @@ extern "C" int __declspec(dllexport) Unload(void) DestroyHookableEvent(hMyAvatarChanged); CloseHandle(hLoaderEvent); - DeleteCriticalSection(&alloccs); - DeleteCriticalSection(&cachecs); - return 0; -} - -/////////////////////////////////////////////////////////////////////////////////////////////////// - -protoPicCacheEntry::~protoPicCacheEntry() -{ - if (hbmPic != 0) - DeleteObject(hbmPic); - mir_free(szProtoname); - mir_free(tszAccName); -} - -void protoPicCacheEntry::clear() -{ - if (hbmPic != 0) - DeleteObject(hbmPic); - - memset(this, 0, sizeof(avatarCacheEntry)); -} - -BOOL Proto_IsAvatarsEnabled(const char *proto) -{ - if ( ProtoServiceExists(proto, PS_GETAVATARCAPS)) - return CallProtoService(proto, PS_GETAVATARCAPS, AF_ENABLED, 0); - - return TRUE; -} - -BOOL Proto_IsAvatarFormatSupported(const char *proto, int format) -{ - if ( ProtoServiceExists(proto, PS_GETAVATARCAPS)) - return CallProtoService(proto, PS_GETAVATARCAPS, AF_FORMATSUPPORTED, format); - - if (format >= PA_FORMAT_SWF) - return FALSE; - - return TRUE; -} - -int Proto_AvatarImageProportion(const char *proto) -{ - if ( ProtoServiceExists(proto, PS_GETAVATARCAPS)) - return CallProtoService(proto, PS_GETAVATARCAPS, AF_PROPORTION, 0); - - return 0; -} - -void Proto_GetAvatarMaxSize(const char *proto, int *width, int *height) -{ - if ( ProtoServiceExists(proto, PS_GETAVATARCAPS)) { - POINT maxSize; - CallProtoService(proto, PS_GETAVATARCAPS, AF_MAXSIZE, (LPARAM) &maxSize); - *width = maxSize.y; - *height = maxSize.x; - } - else { - *width = 300; - *height = 300; - } - - if (*width < 0) - *width = 0; - else if (*width > 300) - *width = 300; - - if (*height < 0) - *height = 0; - else if (*height > 300) - *height = 300; -} - -BOOL Proto_NeedDelaysForAvatars(const char *proto) -{ - if ( ProtoServiceExists(proto, PS_GETAVATARCAPS)) { - int ret = CallProtoService(proto, PS_GETAVATARCAPS, AF_DONTNEEDDELAYS, 0); - if (ret > 0) - return FALSE; - else - return TRUE; - } - - return TRUE; -} - -int Proto_GetAvatarMaxFileSize(const char *proto) -{ - if ( ProtoServiceExists(proto, PS_GETAVATARCAPS)) - return CallProtoService(proto, PS_GETAVATARCAPS, AF_MAXFILESIZE, 0); - - return 0; -} - -int Proto_GetDelayAfterFail(const char *proto) -{ - if ( ProtoServiceExists(proto, PS_GETAVATARCAPS)) - return CallProtoService(proto, PS_GETAVATARCAPS, AF_DELAYAFTERFAIL, 0); - return 0; } - -BOOL Proto_IsFetchingAlwaysAllowed(const char *proto) -{ - if ( ProtoServiceExists(proto, PS_GETAVATARCAPS)) - return CallProtoService(proto, PS_GETAVATARCAPS, AF_FETCHALWAYS, 0); - - return FALSE; -} -- cgit v1.2.3