/* 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 "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 defined( _UNICODE ) if ( p->szName ) { mir_free( p->szName); p->szName = NULL; } #endif 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; #if defined( _UNICODE ) cacheEntry->szName = mir_u2a( ci.pszVal ); #endif 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; #if defined( _UNICODE ) cacheEntry->szName = mir_u2a( buffer ); #endif 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 defined( _UNICODE ) if ( cacheEntry->szName ) return (INT_PTR)cacheEntry->szName; #else if ( cacheEntry->name ) return (INT_PTR)cacheEntry->name; #endif } 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) { #if defined( _UNICODE ) buffer = mir_u2a( ci.pszVal ); mir_free(ci.pszVal); #else buffer = ci.pszVal; #endif return (INT_PTR) buffer; } else { cacheEntry->name = ci.pszVal; #if defined( _UNICODE ) cacheEntry->szName = mir_u2a( ci.pszVal ); return (INT_PTR)cacheEntry->szName; #else return (INT_PTR)cacheEntry->name; #endif } } 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 ); #if defined( _UNICODE ) cacheEntry->szName = buffer; cacheEntry->name = mir_a2u( buffer ); #else cacheEntry->name = buffer; #endif 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; }