/* Miranda IM: the free IM client for Microsoft* Windows* Copyright 2000-2010 Miranda ICQ/IM project, all portions of this codebase are copyrighted to the people listed in contributors.txt. 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. */ #include "..\..\core\commonheaders.h" #include "clc.h" SortedList* clistCache = NULL; static int compareContacts(ClcCacheEntryBase* p1, ClcCacheEntryBase* p2) { return (char*)p1->hContact - (char*)p2->hContact; } void InitDisplayNameCache(void) { clistCache = List_Create(0, 50); clistCache->sortFunc = (FSortFunc)compareContacts; } void FreeDisplayNameCache(void) { if (clistCache != NULL) { int i; for (i = 0; i < clistCache->realCount; i++) { cli.pfnFreeCacheItem((ClcCacheEntryBase*)clistCache->items[i]); mir_free(clistCache->items[i]); } List_Destroy(clistCache); mir_free(clistCache); clistCache = NULL; } } // default handlers for the cache item creation and destruction ClcCacheEntryBase* fnCreateCacheItem(HANDLE hContact) { ClcCacheEntryBase* p = (ClcCacheEntryBase*)mir_calloc(sizeof(ClcCacheEntryBase)); if (p == NULL) return NULL; p->hContact = hContact; return p; } void fnCheckCacheItem(ClcCacheEntryBase* p) { DBVARIANT dbv; if (p->group == NULL) { if ( !DBGetContactSettingTString(p->hContact, "CList", "Group", &dbv)) { p->group = mir_tstrdup(dbv.ptszVal); mir_free(dbv.ptszVal); } else p->group = mir_tstrdup(_T("")); } if (p->isHidden == -1) p->isHidden = DBGetContactSettingByte(p->hContact, "CList", "Hidden", 0); } void fnFreeCacheItem(ClcCacheEntryBase* p) { if (p->name) { mir_free(p->name); p->name = NULL; } if (p->szName) { mir_free(p->szName); p->szName = NULL; } if (p->group) { mir_free(p->group); p->group = NULL; } p->isHidden = -1; } ClcCacheEntryBase* fnGetCacheEntry(HANDLE hContact) { ClcCacheEntryBase* p; int idx; if ( !List_GetIndex(clistCache, &hContact, &idx)) { if ((p = cli.pfnCreateCacheItem(hContact)) != NULL) { List_Insert(clistCache, p, idx); cli.pfnInvalidateDisplayNameCacheEntry(p); } } else p = (ClcCacheEntryBase*)clistCache->items[idx]; cli.pfnCheckCacheItem(p); return p; } void fnInvalidateDisplayNameCacheEntry(HANDLE hContact) { if (hContact == INVALID_HANDLE_VALUE) { FreeDisplayNameCache(); InitDisplayNameCache(); SendMessage(cli.hwndContactTree, CLM_AUTOREBUILD, 0, 0); } else { int idx; if (List_GetIndex(clistCache, &hContact, &idx)) cli.pfnFreeCacheItem((ClcCacheEntryBase*)clistCache->items[idx]); } } TCHAR* fnGetContactDisplayName(HANDLE hContact, int mode) { CONTACTINFO ci; TCHAR *buffer; ClcCacheEntryBase* cacheEntry = NULL; if (mode & GCDNF_NOCACHE) mode &= ~GCDNF_NOCACHE; else if (mode != GCDNF_NOMYHANDLE) { cacheEntry = cli.pfnGetCacheEntry(hContact); if (cacheEntry->name) return cacheEntry->name; } ZeroMemory(&ci, sizeof(ci)); ci.cbSize = sizeof(ci); ci.hContact = hContact; if (ci.hContact == NULL) ci.szProto = "ICQ"; ci.dwFlag = ((mode == GCDNF_NOMYHANDLE) ? CNF_DISPLAYNC : CNF_DISPLAY) | CNF_TCHAR; if ( !CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) { if (ci.type == CNFT_ASCIIZ) { if (cacheEntry == NULL) return ci.pszVal; cacheEntry->name = ci.pszVal; cacheEntry->szName = mir_u2a(ci.pszVal); return ci.pszVal; } if (ci.type == CNFT_DWORD) { if (cacheEntry == NULL) { buffer = (TCHAR*) mir_alloc(15 * sizeof(TCHAR)); _ltot(ci.dVal, buffer, 10); return buffer; } else { buffer = (TCHAR*) mir_alloc(15 * sizeof(TCHAR)); _ltot(ci.dVal, buffer, 10); cacheEntry->name = buffer; cacheEntry->szName = mir_u2a(buffer); return buffer; } } } CallContactService(hContact, PSS_GETINFO, SGIF_MINIMAL, 0); buffer = TranslateT("(Unknown Contact)"); return (cacheEntry == NULL) ? mir_tstrdup(buffer) : buffer; } INT_PTR GetContactDisplayName(WPARAM wParam, LPARAM lParam) { CONTACTINFO ci; ClcCacheEntryBase* cacheEntry = NULL; char *buffer; HANDLE hContact = (HANDLE)wParam; if (lParam & GCDNF_UNICODE) return (INT_PTR)cli.pfnGetContactDisplayName(hContact, lParam & ~GCDNF_UNICODE); if ((int) lParam != GCDNF_NOMYHANDLE) { cacheEntry = cli.pfnGetCacheEntry(hContact); if (cacheEntry->szName) return (INT_PTR)cacheEntry->szName; } ZeroMemory(&ci, sizeof(ci)); ci.cbSize = sizeof(ci); ci.hContact = hContact; if (ci.hContact == NULL) ci.szProto = "ICQ"; ci.dwFlag = ((lParam == GCDNF_NOMYHANDLE) ? CNF_DISPLAYNC : CNF_DISPLAY) | CNF_TCHAR; if ( !CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) { if (ci.type == CNFT_ASCIIZ) { if (cacheEntry == NULL) { buffer = mir_u2a(ci.pszVal); mir_free(ci.pszVal); return (INT_PTR) buffer; } else { cacheEntry->name = ci.pszVal; cacheEntry->szName = mir_u2a(ci.pszVal); return (INT_PTR)cacheEntry->szName; } } if (ci.type == CNFT_DWORD) { if (cacheEntry == NULL) { buffer = (char*)mir_alloc(15); _ltoa(ci.dVal, buffer, 10); return (INT_PTR) buffer; } else { buffer = (char*)mir_alloc(15); _ltoa(ci.dVal, buffer, 10); cacheEntry->szName = buffer; cacheEntry->name = mir_a2u(buffer); return (INT_PTR) buffer; } } } CallContactService(hContact, PSS_GETINFO, SGIF_MINIMAL, 0); buffer = Translate("(Unknown Contact)"); return (INT_PTR) buffer; } INT_PTR InvalidateDisplayName(WPARAM wParam, LPARAM) { cli.pfnInvalidateDisplayNameCacheEntry((HANDLE)wParam); return 0; } int ContactAdded(WPARAM wParam, LPARAM) { cli.pfnChangeContactIcon((HANDLE)wParam, cli.pfnIconFromStatusMode((char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0), ID_STATUS_OFFLINE, NULL), 1); cli.pfnSortContacts(); return 0; } int ContactDeleted(WPARAM wParam, LPARAM) { CallService(MS_CLUI_CONTACTDELETED, wParam, 0); return 0; } int ContactSettingChanged(WPARAM wParam, LPARAM lParam) { DBCONTACTWRITESETTING *cws = (DBCONTACTWRITESETTING *) lParam; DBVARIANT dbv; HANDLE hContact = (HANDLE)wParam; // Early exit if (hContact == NULL) return 0; dbv.pszVal = NULL; if ( !DBGetContactSetting(hContact, "Protocol", "p", &dbv)) { if ( !strcmp(cws->szModule, dbv.pszVal)) { cli.pfnInvalidateDisplayNameCacheEntry(hContact); if ( !strcmp(cws->szSetting, "UIN") || !strcmp(cws->szSetting, "Nick") || !strcmp(cws->szSetting, "FirstName") || !strcmp(cws->szSetting, "LastName") || !strcmp(cws->szSetting, "e-mail")) { CallService(MS_CLUI_CONTACTRENAMED, wParam, 0); } else if ( !strcmp(cws->szSetting, "Status")) { if ( !DBGetContactSettingByte(hContact, "CList", "Hidden", 0)) { if (DBGetContactSettingByte(NULL, "CList", "HideOffline", SETTING_HIDEOFFLINE_DEFAULT)) { // User's state is changing, and we are hideOffline-ing if (cws->value.wVal == ID_STATUS_OFFLINE) { cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(cws->szModule, cws->value.wVal, hContact), 0); CallService(MS_CLUI_CONTACTDELETED, wParam, 0); mir_free(dbv.pszVal); return 0; } cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(cws->szModule, cws->value.wVal, hContact), 1); } cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(cws->szModule, cws->value.wVal, hContact), 0); } } else { mir_free(dbv.pszVal); return 0; } cli.pfnSortContacts(); } } if ( !strcmp(cws->szModule, "CList")) { if ( !strcmp(cws->szSetting, "Hidden")) { if (cws->value.type == DBVT_DELETED || cws->value.bVal == 0) { char *szProto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(szProto, szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE), hContact), 1); } else CallService(MS_CLUI_CONTACTDELETED, wParam, 0); } if ( !strcmp(cws->szSetting, "MyHandle")) cli.pfnInvalidateDisplayNameCacheEntry(hContact); } if ( !strcmp(cws->szModule, "Protocol")) { if ( !strcmp(cws->szSetting, "p")) { char *szProto; if (cws->value.type == DBVT_DELETED) szProto = NULL; else szProto = cws->value.pszVal; cli.pfnChangeContactIcon(hContact, cli.pfnIconFromStatusMode(szProto, szProto == NULL ? ID_STATUS_OFFLINE : DBGetContactSettingWord(hContact, szProto, "Status", ID_STATUS_OFFLINE), hContact), 0); } } // Clean up if (dbv.pszVal) mir_free(dbv.pszVal); return 0; }