From 7b3a959a784a2c6f36ca7cf60f272cdb9b0f37a8 Mon Sep 17 00:00:00 2001 From: Tobias Weimer Date: Sun, 11 Nov 2012 22:49:57 +0000 Subject: log path without HistoryEvents git-svn-id: http://svn.miranda-ng.org/main/trunk@2295 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/AvatarHistory/src/AvatarHistory.cpp | 1857 +++++++++++++-------------- 1 file changed, 928 insertions(+), 929 deletions(-) diff --git a/plugins/AvatarHistory/src/AvatarHistory.cpp b/plugins/AvatarHistory/src/AvatarHistory.cpp index 33d3b0873d..0cd94a15f2 100644 --- a/plugins/AvatarHistory/src/AvatarHistory.cpp +++ b/plugins/AvatarHistory/src/AvatarHistory.cpp @@ -1,939 +1,938 @@ -/* -Avatar History Plugin ---------- - - This plugin uses the event provided by Avatar Service to - automatically back up contacts' avatars when they change. - Copyright (C) 2006 Matthew Wild - Email: mwild1@gmail.com - - 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. - -*/ -#include "AvatarHistory.h" - -HINSTANCE hInst; - -DWORD mirVer; - -HANDLE hHooks[6] = {0}; -HANDLE hServices[3] = {0}; - -HANDLE hFolder = NULL; - -char *metacontacts_proto = NULL; - -TCHAR profilePath[MAX_PATH]; // database profile path (read at startup only) -TCHAR basedir[MAX_PATH]; -int hLangpack = 0; -HANDLE hAvatarWindowsList = NULL; - -static int ModulesLoaded(WPARAM wParam, LPARAM lParam); -static int PreShutdown(WPARAM wParam, LPARAM lParam); -static int AvatarChanged(WPARAM wParam, LPARAM lParam); -int OptInit(WPARAM wParam,LPARAM lParam); - -TCHAR * GetHistoryFolder(TCHAR *fn); -TCHAR * GetProtocolFolder(TCHAR *fn, char *proto); -TCHAR * GetOldStyleAvatarName(TCHAR *fn, HANDLE hContact); - -void InitMenuItem(); - -void * GetHistoryEventText(HANDLE hContact, HANDLE hDbEvent, DBEVENTINFO *dbe, int format); - -// Services -static INT_PTR IsEnabled(WPARAM wParam, LPARAM lParam); -static INT_PTR GetCachedAvatar(WPARAM wParam, LPARAM lParam); -TCHAR * GetCachedAvatar(char *proto, TCHAR *hash); -BOOL CreateShortcut(TCHAR *file, TCHAR *shortcut); - -PLUGININFOEX pluginInfo = { - sizeof(PLUGININFOEX), - __PLUGIN_NAME, - PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), - __DESCRIPTION, - __AUTHOR, - __AUTHOREMAIL, - __COPYRIGHT, - __AUTHORWEB, - UNICODE_AWARE, - // {DBE8C990-7AA0-458d-BAB7-33EB07238E71} - {0xdbe8c990, 0x7aa0, 0x458d, {0xba, 0xb7, 0x33, 0xeb, 0x7, 0x23, 0x8e, 0x71}} -}; - -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - hInst = hinstDLL; - return TRUE; -} - -extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) -{ - return &pluginInfo; -} - -static INT_PTR CALLBACK FirstRunDlgProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) -{ - switch(uMsg) - { - case WM_INITDIALOG: - { - SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) createDefaultOverlayedIcon(TRUE)); - SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) createDefaultOverlayedIcon(FALSE)); - TranslateDialogDefault(hwnd); - - CheckDlgButton(hwnd, IDC_MIR_PROTO, BST_CHECKED); - break; - } - case WM_COMMAND: - { - switch(LOWORD(wParam)) - { - case IDOK: - { - int ret = 0; - - if (IsDlgButtonChecked(hwnd, IDC_MIR_SAME)) - ret = IDC_MIR_SAME; - else if (IsDlgButtonChecked(hwnd, IDC_MIR_PROTO)) - ret = IDC_MIR_PROTO; - else if (IsDlgButtonChecked(hwnd, IDC_MIR_SHORT)) - ret = IDC_MIR_SHORT; - else if (IsDlgButtonChecked(hwnd, IDC_SHORT)) - ret = IDC_SHORT; - else if (IsDlgButtonChecked(hwnd, IDC_DUP)) - ret = IDC_DUP; - - EndDialog(hwnd, ret); - return TRUE; - } - } - break; - } - case WM_CLOSE: - { - EndDialog(hwnd, 0); - return TRUE; - } - } - - return FALSE; -} - -extern "C" __declspec(dllexport) int Load(void) -{ - mir_getLP(&pluginInfo); - - // Is first run? - if (DBGetContactSettingByte(NULL, MODULE_NAME, "FirstRun", 1)) - { - // Show dialog - int ret = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_FIRST_RUN), NULL, FirstRunDlgProc, 0); - if (ret == 0) - return -1; - - // Write settings - - DBWriteContactSettingByte(NULL, MODULE_NAME, "LogToDisk", 1); - - if (ret == IDC_MIR_SAME) - DBWriteContactSettingByte(NULL, MODULE_NAME, "LogKeepSameFolder", 1); - else - DBWriteContactSettingByte(NULL, MODULE_NAME, "LogKeepSameFolder", 0); - - if (ret == IDC_MIR_SHORT || ret == IDC_SHORT || ret == IDC_DUP) - DBWriteContactSettingByte(NULL, MODULE_NAME, "LogPerContactFolders", 1); - else - DBWriteContactSettingByte(NULL, MODULE_NAME, "LogPerContactFolders", 0); - - if (ret == IDC_DUP) - DBWriteContactSettingByte(NULL, MODULE_NAME, "StoreAsHash", 0); - else - DBWriteContactSettingByte(NULL, MODULE_NAME, "StoreAsHash", 1); - - if (ret == IDC_MIR_SAME || ret == IDC_MIR_PROTO || ret == IDC_MIR_SHORT) - DBWriteContactSettingByte(NULL, MODULE_NAME, "LogToHistory", 1); - else - DBWriteContactSettingByte(NULL, MODULE_NAME, "LogToHistory", 0); - - DBWriteContactSettingByte(NULL, MODULE_NAME, "FirstRun", 0); - } - - LoadOptions(); - - hHooks[0] = HookEvent(ME_SYSTEM_MODULESLOADED,ModulesLoaded); - hHooks[1] = HookEvent(ME_SYSTEM_PRESHUTDOWN, PreShutdown); - hHooks[3] = HookEvent(ME_OPT_INITIALISE, OptInit); - hHooks[4] = HookEvent(ME_SKIN2_ICONSCHANGED, IcoLibIconsChanged); - hHooks[5] = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PreBuildContactMenu); - - hServices[0] = CreateServiceFunction(MS_AVATARHISTORY_ENABLED, IsEnabled); - hServices[1] = CreateServiceFunction(MS_AVATARHISTORY_GET_CACHED_AVATAR, GetCachedAvatar); - - if(CallService(MS_DB_GETPROFILEPATHT, MAX_PATH, (LPARAM)profilePath) != 0) - _tcscpy(profilePath, _T(".")); // Failed, use current dir - - SkinAddNewSoundExT("avatar_changed",LPGENT("Avatar History"),LPGENT("Contact changed avatar")); - SkinAddNewSoundExT("avatar_removed",LPGENT("Avatar History"),LPGENT("Contact removed avatar")); - - hAvatarWindowsList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0); - - SetupIcoLib(); - InitMenuItem(); - - return 0; -} - -static int ModulesLoaded(WPARAM wParam, LPARAM lParam) -{ - mir_sntprintf(basedir, MAX_REGS(basedir), _T("%s\\Avatars History"), profilePath); - - hFolder = FoldersRegisterCustomPathT(LPGEN("Avatars"), LPGEN("Avatar History"), - PROFILE_PATHT _T("\\") CURRENT_PROFILET _T("\\Avatars History")); - InitPopups(); - - if (ServiceExists(MS_MC_GETPROTOCOLNAME)) - metacontacts_proto = (char *) CallService(MS_MC_GETPROTOCOLNAME, 0, 0); - - if (DBGetContactSettingByte(NULL, MODULE_NAME, "LogToHistory", AVH_DEF_LOGTOHISTORY)) - { - char *templates[] = { "Avatar change\nchanged his/her avatar", - "Avatar removal\nremoved his/her avatar" }; - HICON hIcon = createDefaultOverlayedIcon(FALSE); - HistoryEvents_RegisterWithTemplates(MODULE_NAME, "avatarchange", "Avatar change", EVENTTYPE_AVATAR_CHANGE, hIcon, - HISTORYEVENTS_FORMAT_CHAR | HISTORYEVENTS_FORMAT_WCHAR | HISTORYEVENTS_FORMAT_RICH_TEXT, - HISTORYEVENTS_FLAG_SHOW_IM_SRMM | HISTORYEVENTS_FLAG_EXPECT_CONTACT_NAME_BEFORE, - GetHistoryEventText, templates, MAX_REGS(templates)); - DestroyIcon(hIcon); - } - - hHooks[2] = HookEvent(ME_AV_CONTACTAVATARCHANGED, AvatarChanged); - - return 0; -} - -static int PreShutdown(WPARAM wParam, LPARAM lParam) -{ - int i; - - for (i = 0; i < MAX_REGS(hHooks); i++) - UnhookEvent(hHooks[i]); - - for (i = 0; i < MAX_REGS(hServices); i++) - DestroyServiceFunction(hServices[i]); - - WindowList_Broadcast(hAvatarWindowsList,WM_CLOSE,0,0); - - return 0; -} - -BOOL ProtocolEnabled(const char *proto) -{ - if (proto == NULL) - return FALSE; - - char setting[256]; - mir_snprintf(setting, sizeof(setting), "%sEnabled", proto); - return (BOOL) DBGetContactSettingByte(NULL, MODULE_NAME, setting, TRUE); -} - -BOOL ContactEnabled(HANDLE hContact, char *setting, int def) -{ - if (hContact == NULL) - return FALSE; - - char *proto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); - if (!ProtocolEnabled(proto)) - return FALSE; - - BYTE globpref = db_get_b(NULL, MODULE_NAME, setting, def); - BYTE userpref = db_get_b(hContact, MODULE_NAME, setting, BST_INDETERMINATE); - - return (globpref && userpref == BST_INDETERMINATE) || userpref == BST_CHECKED; -} - -// Returns true if the unicode buffer only contains 7-bit characters. -BOOL IsUnicodeAscii(const WCHAR * pBuffer, int nSize) -{ - BOOL bResult = TRUE; - int nIndex; - - for (nIndex = 0; nIndex < nSize; nIndex++) { - if (pBuffer[nIndex] > 0x7F) { - bResult = FALSE; - break; - } - } - return bResult; -} - -void ConvertToFilename(TCHAR *str, size_t size) { - for(size_t i = 0; i < size && str[i] != '\0'; i++) { - switch(str[i]) { - case '/': - case '\\': - case ':': - case '*': - case '?': - case '"': - case '<': - case '>': - case '|': - //case '.': - str[i] = '_'; - } - } -} - -void ErrorExit(HANDLE hContact,LPTSTR lpszFunction) -{ - // Retrieve the system error message for the last-error code - - LPVOID lpMsgBuf; - LPVOID lpDisplayBuf; - DWORD dw = GetLastError(); - - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER | - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - dw, - MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), - (LPTSTR) &lpMsgBuf, - 0, NULL ); - - // Display the error message and exit the process - - lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, - (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); - StringCchPrintf((LPTSTR)lpDisplayBuf, - LocalSize(lpDisplayBuf) / sizeof(TCHAR), - TEXT("%s failed with error %d: %s"), - lpszFunction, dw, lpMsgBuf); - ShowDebugPopup(hContact,TEXT("Error"), (LPCTSTR)lpDisplayBuf); - - LocalFree(lpMsgBuf); - LocalFree(lpDisplayBuf); -} - -#ifdef _UNICODE - -#define CS "%S" - -#else - -#define CS "%s" - -#endif - - -TCHAR * GetExtension(TCHAR *file) -{ - if(file == NULL) return _T(""); - TCHAR *ext = _tcsrchr(file, _T('.')); - if (ext != NULL) - ext++; - else - ext = _T(""); - - return ext; -} - - -void CreateOldStyleShortcut(HANDLE hContact, TCHAR *history_filename) -{ - TCHAR shortcut[MAX_PATH] = _T(""); - - GetOldStyleAvatarName(shortcut, hContact); - - mir_sntprintf(shortcut, MAX_REGS(shortcut), _T("%s.%s.lnk"), shortcut, - GetExtension(history_filename)); - - if (!CreateShortcut(history_filename, shortcut)) - { - ShowPopup(hContact, _T("Avatar History: Unable to create shortcut"), shortcut); - } - else - { - ShowDebugPopup(hContact, _T("AVH Debug: Shortcut created successfully"), shortcut); - } -} - - -BOOL CopyImageFile(TCHAR *old_file, TCHAR *new_file) -{ - TCHAR *ext = GetExtension(old_file); - mir_sntprintf(new_file, MAX_PATH, _T("%s.%s"), new_file, ext); - - BOOL ret = CopyFile(old_file, new_file, TRUE); - if(!ret) - ErrorExit(NULL,_T("CopyImageFile")); - return !ret; -} - -// fired when the contacts avatar changes -// wParam = hContact -// lParam = struct avatarCacheEntry *cacheEntry -// the event CAN pass a NULL pointer in lParam which means that the avatar has changed, -// but is no longer valid (happens, when a contact removes his avatar, for example). -// DONT DESTROY the bitmap handle passed in the struct avatarCacheEntry * -// -// It is also possible that this event passes 0 as wParam (hContact), in which case, -// a protocol picture (pseudo - avatar) has been changed. -static int AvatarChanged(WPARAM wParam, LPARAM lParam) -{ - HANDLE hContact = (HANDLE)wParam; - CONTACTAVATARCHANGEDNOTIFICATION* avatar = (CONTACTAVATARCHANGEDNOTIFICATION*)lParam; - - if (hContact == NULL) - { - ShowDebugPopup(NULL, _T("AVH Debug"), _T("Invalid contact/avatar... skipping")); - return 0; - } - - char *proto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); - if (proto == NULL) - { - ShowDebugPopup(hContact, _T("AVH Debug"), _T("Invalid protocol... skipping")); - return 0; - } - else if (metacontacts_proto != NULL && strcmp(metacontacts_proto, proto) == 0) - { - ShowDebugPopup(hContact, _T("AVH Debug"), _T("Ignoring metacontacts notification")); - return 0; - } - - DBVARIANT dbvOldHash = {0}; - bool ret = (DBGetContactSettingTString(hContact,MODULE_NAME,"AvatarHash",&dbvOldHash) == 0); - - if (avatar == NULL) - { - if (!ret || !_tcscmp(dbvOldHash.ptszVal, _T("-"))) - { - //avoid duplicate "removed avatar" notifications - //do not notify on an empty profile - ShowDebugPopup(hContact, _T("AVH Debug"), _T("Removed avatar, no avatar before...skipping")); - DBFreeVariant(&dbvOldHash); - return 0; - } - SkinPlaySound("avatar_removed"); - - // Is a flash avatar or avs could not load it - DBWriteContactSettingTString(hContact, MODULE_NAME, "AvatarHash", _T("-")); - - if (ContactEnabled(hContact, "AvatarPopups", AVH_DEF_AVPOPUPS) && opts.popup_show_removed) - ShowPopup(hContact, NULL, opts.popup_removed); - - if (ContactEnabled(hContact, "LogToHistory", AVH_DEF_LOGTOHISTORY)) - HistoryEvents_AddToHistorySimple(hContact, EVENTTYPE_AVATAR_CHANGE, 1, DBEF_READ); - } - else - { - if(ret && !_tcscmp(dbvOldHash.ptszVal, avatar->hash)) - { - // same avatar hash, skipping - ShowDebugPopup(hContact, _T("AVH Debug"), _T("Hashes are the same... skipping")); - DBFreeVariant(&dbvOldHash); - return 0; - } - SkinPlaySound("avatar_changed"); - DBWriteContactSettingTString(hContact, "AvatarHistory", "AvatarHash", avatar->hash); - - TCHAR history_filename[MAX_PATH] = _T(""); - - if (ContactEnabled(hContact, "LogToDisk", AVH_DEF_LOGTODISK)) - { - if (!opts.log_store_as_hash) - { - if (opts.log_per_contact_folders) - { - GetOldStyleAvatarName(history_filename, hContact); - if (CopyImageFile(avatar->filename, history_filename)) - ShowPopup(hContact, _T("Avatar History: Unable to save avatar"), history_filename); - else - ShowDebugPopup(hContact, _T("AVH Debug: File copied successfully"), history_filename); - - if (ServiceExists(MS_MC_GETMETACONTACT)) - { - HANDLE hMetaContact = (HANDLE) CallService(MS_MC_GETMETACONTACT, wParam, 0); - - if (hMetaContact != NULL && ContactEnabled(hMetaContact, "LogToDisk", AVH_DEF_LOGTOHISTORY)) - { - TCHAR filename[MAX_PATH] = _T(""); - - GetOldStyleAvatarName(filename, hMetaContact); - if (CopyImageFile(avatar->filename, filename)) - ShowPopup(hContact, _T("Avatar History: Unable to save avatar"), filename); - else - ShowDebugPopup(hContact, _T("AVH Debug: File copied successfully"), filename); - } - } - } - } - else - { - // See if we already have the avatar - TCHAR hash[128]; - lstrcpyn(hash, avatar->hash, sizeof(hash)); - ConvertToFilename(hash, sizeof(hash)); - - TCHAR *file = GetCachedAvatar(proto, hash); - - if (file != NULL) - { - lstrcpyn(history_filename, file, MAX_REGS(history_filename)); - mir_free(file); - } - else - { - if (opts.log_keep_same_folder) - GetHistoryFolder(history_filename); - else - GetProtocolFolder(history_filename, proto); - - mir_sntprintf(history_filename, MAX_REGS(history_filename), - _T("%s\\%s"), history_filename, hash); - - if (CopyImageFile(avatar->filename, history_filename)) - ShowPopup(hContact, _T("Avatar History: Unable to save avatar"), history_filename); - else - ShowDebugPopup(hContact, _T("AVH Debug: File copied successfully"), history_filename); - } - - if (opts.log_per_contact_folders) - { - CreateOldStyleShortcut(hContact, history_filename); - - if (ServiceExists(MS_MC_GETMETACONTACT)) - { - HANDLE hMetaContact = (HANDLE) CallService(MS_MC_GETMETACONTACT, wParam, 0); - - if (hMetaContact != NULL && ContactEnabled(hMetaContact, "LogToDisk", AVH_DEF_LOGTOHISTORY)) - CreateOldStyleShortcut(hMetaContact, history_filename); - } - } - } - } - - - if (ContactEnabled(hContact, "AvatarPopups", AVH_DEF_AVPOPUPS) && opts.popup_show_changed) - ShowPopup(hContact, NULL, opts.popup_changed); - - if (ContactEnabled(hContact, "LogToHistory", AVH_DEF_LOGTOHISTORY)) - { - TCHAR rel_path[MAX_PATH] = _T(""); - CallService(MS_UTILS_PATHTORELATIVET,(WPARAM)history_filename,(LPARAM)rel_path); - char *blob = mir_utf8encodeT(rel_path); - int flags = DBEF_READ | DBEF_UTF; - if(ServiceExists(MS_HISTORYEVENTS_ADD_TO_HISTORY)) - { - HistoryEvents_AddToHistoryEx(hContact, EVENTTYPE_AVATAR_CHANGE, 0, NULL, 0, (PBYTE) blob, (int) strlen(blob) + 1, flags); - } +/* +Avatar History Plugin +--------- + + This plugin uses the event provided by Avatar Service to + automatically back up contacts' avatars when they change. + Copyright (C) 2006 Matthew Wild - Email: mwild1@gmail.com + + 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. + +*/ +#include "AvatarHistory.h" + +HINSTANCE hInst; + +DWORD mirVer; + +HANDLE hHooks[6] = {0}; +HANDLE hServices[3] = {0}; + +HANDLE hFolder = NULL; + +char *metacontacts_proto = NULL; + +TCHAR profilePath[MAX_PATH]; // database profile path (read at startup only) +TCHAR basedir[MAX_PATH]; +int hLangpack = 0; +HANDLE hAvatarWindowsList = NULL; + +static int ModulesLoaded(WPARAM wParam, LPARAM lParam); +static int PreShutdown(WPARAM wParam, LPARAM lParam); +static int AvatarChanged(WPARAM wParam, LPARAM lParam); +int OptInit(WPARAM wParam,LPARAM lParam); + +TCHAR * GetHistoryFolder(TCHAR *fn); +TCHAR * GetProtocolFolder(TCHAR *fn, char *proto); +TCHAR * GetOldStyleAvatarName(TCHAR *fn, HANDLE hContact); + +void InitMenuItem(); + +void * GetHistoryEventText(HANDLE hContact, HANDLE hDbEvent, DBEVENTINFO *dbe, int format); + +// Services +static INT_PTR IsEnabled(WPARAM wParam, LPARAM lParam); +static INT_PTR GetCachedAvatar(WPARAM wParam, LPARAM lParam); +TCHAR * GetCachedAvatar(char *proto, TCHAR *hash); +BOOL CreateShortcut(TCHAR *file, TCHAR *shortcut); + +PLUGININFOEX pluginInfo = { + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESCRIPTION, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + // {DBE8C990-7AA0-458d-BAB7-33EB07238E71} + {0xdbe8c990, 0x7aa0, 0x458d, {0xba, 0xb7, 0x33, 0xeb, 0x7, 0x23, 0x8e, 0x71}} +}; + +BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) +{ + hInst = hinstDLL; + return TRUE; +} + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +static INT_PTR CALLBACK FirstRunDlgProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) +{ + switch(uMsg) + { + case WM_INITDIALOG: + { + SendMessage(hwnd, WM_SETICON, ICON_BIG, (LPARAM) createDefaultOverlayedIcon(TRUE)); + SendMessage(hwnd, WM_SETICON, ICON_SMALL, (LPARAM) createDefaultOverlayedIcon(FALSE)); + TranslateDialogDefault(hwnd); + + CheckDlgButton(hwnd, IDC_MIR_PROTO, BST_CHECKED); + break; + } + case WM_COMMAND: + { + switch(LOWORD(wParam)) + { + case IDOK: + { + int ret = 0; + + if (IsDlgButtonChecked(hwnd, IDC_MIR_SAME)) + ret = IDC_MIR_SAME; + else if (IsDlgButtonChecked(hwnd, IDC_MIR_PROTO)) + ret = IDC_MIR_PROTO; + else if (IsDlgButtonChecked(hwnd, IDC_MIR_SHORT)) + ret = IDC_MIR_SHORT; + else if (IsDlgButtonChecked(hwnd, IDC_SHORT)) + ret = IDC_SHORT; + else if (IsDlgButtonChecked(hwnd, IDC_DUP)) + ret = IDC_DUP; + + EndDialog(hwnd, ret); + return TRUE; + } + } + break; + } + case WM_CLOSE: + { + EndDialog(hwnd, 0); + return TRUE; + } + } + + return FALSE; +} + +extern "C" __declspec(dllexport) int Load(void) +{ + mir_getLP(&pluginInfo); + + // Is first run? + if (DBGetContactSettingByte(NULL, MODULE_NAME, "FirstRun", 1)) + { + // Show dialog + int ret = DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_FIRST_RUN), NULL, FirstRunDlgProc, 0); + if (ret == 0) + return -1; + + // Write settings + + DBWriteContactSettingByte(NULL, MODULE_NAME, "LogToDisk", 1); + + if (ret == IDC_MIR_SAME) + DBWriteContactSettingByte(NULL, MODULE_NAME, "LogKeepSameFolder", 1); + else + DBWriteContactSettingByte(NULL, MODULE_NAME, "LogKeepSameFolder", 0); + + if (ret == IDC_MIR_SHORT || ret == IDC_SHORT || ret == IDC_DUP) + DBWriteContactSettingByte(NULL, MODULE_NAME, "LogPerContactFolders", 1); + else + DBWriteContactSettingByte(NULL, MODULE_NAME, "LogPerContactFolders", 0); + + if (ret == IDC_DUP) + DBWriteContactSettingByte(NULL, MODULE_NAME, "StoreAsHash", 0); + else + DBWriteContactSettingByte(NULL, MODULE_NAME, "StoreAsHash", 1); + + if (ret == IDC_MIR_SAME || ret == IDC_MIR_PROTO || ret == IDC_MIR_SHORT) + DBWriteContactSettingByte(NULL, MODULE_NAME, "LogToHistory", 1); + else + DBWriteContactSettingByte(NULL, MODULE_NAME, "LogToHistory", 0); + + DBWriteContactSettingByte(NULL, MODULE_NAME, "FirstRun", 0); + } + + LoadOptions(); + + hHooks[0] = HookEvent(ME_SYSTEM_MODULESLOADED,ModulesLoaded); + hHooks[1] = HookEvent(ME_SYSTEM_PRESHUTDOWN, PreShutdown); + hHooks[3] = HookEvent(ME_OPT_INITIALISE, OptInit); + hHooks[4] = HookEvent(ME_SKIN2_ICONSCHANGED, IcoLibIconsChanged); + hHooks[5] = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PreBuildContactMenu); + + hServices[0] = CreateServiceFunction(MS_AVATARHISTORY_ENABLED, IsEnabled); + hServices[1] = CreateServiceFunction(MS_AVATARHISTORY_GET_CACHED_AVATAR, GetCachedAvatar); + + if(CallService(MS_DB_GETPROFILEPATHT, MAX_PATH, (LPARAM)profilePath) != 0) + _tcscpy(profilePath, _T(".")); // Failed, use current dir + + SkinAddNewSoundExT("avatar_changed",LPGENT("Avatar History"),LPGENT("Contact changed avatar")); + SkinAddNewSoundExT("avatar_removed",LPGENT("Avatar History"),LPGENT("Contact removed avatar")); + + hAvatarWindowsList = (HANDLE)CallService(MS_UTILS_ALLOCWINDOWLIST, 0, 0); + + SetupIcoLib(); + InitMenuItem(); + + return 0; +} + +static int ModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + mir_sntprintf(basedir, MAX_REGS(basedir), _T("%s\\Avatars History"), profilePath); + + hFolder = FoldersRegisterCustomPathT(LPGEN("Avatars"), LPGEN("Avatar History"), + PROFILE_PATHT _T("\\") CURRENT_PROFILET _T("\\Avatars History")); + InitPopups(); + + if (ServiceExists(MS_MC_GETPROTOCOLNAME)) + metacontacts_proto = (char *) CallService(MS_MC_GETPROTOCOLNAME, 0, 0); + + if (DBGetContactSettingByte(NULL, MODULE_NAME, "LogToHistory", AVH_DEF_LOGTOHISTORY)) + { + char *templates[] = { "Avatar change\nchanged his/her avatar", + "Avatar removal\nremoved his/her avatar" }; + HICON hIcon = createDefaultOverlayedIcon(FALSE); + HistoryEvents_RegisterWithTemplates(MODULE_NAME, "avatarchange", "Avatar change", EVENTTYPE_AVATAR_CHANGE, hIcon, + HISTORYEVENTS_FORMAT_CHAR | HISTORYEVENTS_FORMAT_WCHAR | HISTORYEVENTS_FORMAT_RICH_TEXT, + HISTORYEVENTS_FLAG_SHOW_IM_SRMM | HISTORYEVENTS_FLAG_EXPECT_CONTACT_NAME_BEFORE, + GetHistoryEventText, templates, MAX_REGS(templates)); + DestroyIcon(hIcon); + } + + hHooks[2] = HookEvent(ME_AV_CONTACTAVATARCHANGED, AvatarChanged); + + return 0; +} + +static int PreShutdown(WPARAM wParam, LPARAM lParam) +{ + int i; + + for (i = 0; i < MAX_REGS(hHooks); i++) + UnhookEvent(hHooks[i]); + + for (i = 0; i < MAX_REGS(hServices); i++) + DestroyServiceFunction(hServices[i]); + + WindowList_Broadcast(hAvatarWindowsList,WM_CLOSE,0,0); + + return 0; +} + +BOOL ProtocolEnabled(const char *proto) +{ + if (proto == NULL) + return FALSE; + + char setting[256]; + mir_snprintf(setting, sizeof(setting), "%sEnabled", proto); + return (BOOL) DBGetContactSettingByte(NULL, MODULE_NAME, setting, TRUE); +} + +BOOL ContactEnabled(HANDLE hContact, char *setting, int def) +{ + if (hContact == NULL) + return FALSE; + + char *proto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM) hContact, 0); + if (!ProtocolEnabled(proto)) + return FALSE; + + BYTE globpref = db_get_b(NULL, MODULE_NAME, setting, def); + BYTE userpref = db_get_b(hContact, MODULE_NAME, setting, BST_INDETERMINATE); + + return (globpref && userpref == BST_INDETERMINATE) || userpref == BST_CHECKED; +} + +// Returns true if the unicode buffer only contains 7-bit characters. +BOOL IsUnicodeAscii(const WCHAR * pBuffer, int nSize) +{ + BOOL bResult = TRUE; + int nIndex; + + for (nIndex = 0; nIndex < nSize; nIndex++) { + if (pBuffer[nIndex] > 0x7F) { + bResult = FALSE; + break; + } + } + return bResult; +} + +void ConvertToFilename(TCHAR *str, size_t size) { + for(size_t i = 0; i < size && str[i] != '\0'; i++) { + switch(str[i]) { + case '/': + case '\\': + case ':': + case '*': + case '?': + case '"': + case '<': + case '>': + case '|': + //case '.': + str[i] = '_'; + } + } +} + +void ErrorExit(HANDLE hContact,LPTSTR lpszFunction) +{ + // Retrieve the system error message for the last-error code + + LPVOID lpMsgBuf; + LPVOID lpDisplayBuf; + DWORD dw = GetLastError(); + + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER | + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + dw, + MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), + (LPTSTR) &lpMsgBuf, + 0, NULL ); + + // Display the error message and exit the process + + lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, + (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR)); + StringCchPrintf((LPTSTR)lpDisplayBuf, + LocalSize(lpDisplayBuf) / sizeof(TCHAR), + TEXT("%s failed with error %d: %s"), + lpszFunction, dw, lpMsgBuf); + ShowDebugPopup(hContact,TEXT("Error"), (LPCTSTR)lpDisplayBuf); + + LocalFree(lpMsgBuf); + LocalFree(lpDisplayBuf); +} + +#ifdef _UNICODE + +#define CS "%S" + +#else + +#define CS "%s" + +#endif + + +TCHAR * GetExtension(TCHAR *file) +{ + if(file == NULL) return _T(""); + TCHAR *ext = _tcsrchr(file, _T('.')); + if (ext != NULL) + ext++; + else + ext = _T(""); + + return ext; +} + + +void CreateOldStyleShortcut(HANDLE hContact, TCHAR *history_filename) +{ + TCHAR shortcut[MAX_PATH] = _T(""); + + GetOldStyleAvatarName(shortcut, hContact); + + mir_sntprintf(shortcut, MAX_REGS(shortcut), _T("%s.%s.lnk"), shortcut, + GetExtension(history_filename)); + + if (!CreateShortcut(history_filename, shortcut)) + { + ShowPopup(hContact, _T("Avatar History: Unable to create shortcut"), shortcut); + } + else + { + ShowDebugPopup(hContact, _T("AVH Debug: Shortcut created successfully"), shortcut); + } +} + + +BOOL CopyImageFile(TCHAR *old_file, TCHAR *new_file) +{ + TCHAR *ext = GetExtension(old_file); + mir_sntprintf(new_file, MAX_PATH, _T("%s.%s"), new_file, ext); + + BOOL ret = CopyFile(old_file, new_file, TRUE); + if(!ret) + ErrorExit(NULL,_T("CopyImageFile")); + return !ret; +} + +// fired when the contacts avatar changes +// wParam = hContact +// lParam = struct avatarCacheEntry *cacheEntry +// the event CAN pass a NULL pointer in lParam which means that the avatar has changed, +// but is no longer valid (happens, when a contact removes his avatar, for example). +// DONT DESTROY the bitmap handle passed in the struct avatarCacheEntry * +// +// It is also possible that this event passes 0 as wParam (hContact), in which case, +// a protocol picture (pseudo - avatar) has been changed. +static int AvatarChanged(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + CONTACTAVATARCHANGEDNOTIFICATION* avatar = (CONTACTAVATARCHANGEDNOTIFICATION*)lParam; + + if (hContact == NULL) + { + ShowDebugPopup(NULL, _T("AVH Debug"), _T("Invalid contact/avatar... skipping")); + return 0; + } + + char *proto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO, wParam, 0); + if (proto == NULL) + { + ShowDebugPopup(hContact, _T("AVH Debug"), _T("Invalid protocol... skipping")); + return 0; + } + else if (metacontacts_proto != NULL && strcmp(metacontacts_proto, proto) == 0) + { + ShowDebugPopup(hContact, _T("AVH Debug"), _T("Ignoring metacontacts notification")); + return 0; + } + + DBVARIANT dbvOldHash = {0}; + bool ret = (DBGetContactSettingTString(hContact,MODULE_NAME,"AvatarHash",&dbvOldHash) == 0); + + if (avatar == NULL) + { + if (!ret || !_tcscmp(dbvOldHash.ptszVal, _T("-"))) + { + //avoid duplicate "removed avatar" notifications + //do not notify on an empty profile + ShowDebugPopup(hContact, _T("AVH Debug"), _T("Removed avatar, no avatar before...skipping")); + DBFreeVariant(&dbvOldHash); + return 0; + } + SkinPlaySound("avatar_removed"); + + // Is a flash avatar or avs could not load it + DBWriteContactSettingTString(hContact, MODULE_NAME, "AvatarHash", _T("-")); + + if (ContactEnabled(hContact, "AvatarPopups", AVH_DEF_AVPOPUPS) && opts.popup_show_removed) + ShowPopup(hContact, NULL, opts.popup_removed); + + if (ContactEnabled(hContact, "LogToHistory", AVH_DEF_LOGTOHISTORY)) + HistoryEvents_AddToHistorySimple(hContact, EVENTTYPE_AVATAR_CHANGE, 1, DBEF_READ); + } + else + { + if(ret && !_tcscmp(dbvOldHash.ptszVal, avatar->hash)) + { + // same avatar hash, skipping + ShowDebugPopup(hContact, _T("AVH Debug"), _T("Hashes are the same... skipping")); + DBFreeVariant(&dbvOldHash); + return 0; + } + SkinPlaySound("avatar_changed"); + DBWriteContactSettingTString(hContact, "AvatarHistory", "AvatarHash", avatar->hash); + + TCHAR history_filename[MAX_PATH] = _T(""); + + if (ContactEnabled(hContact, "LogToDisk", AVH_DEF_LOGTODISK)) + { + if (!opts.log_store_as_hash) + { + if (opts.log_per_contact_folders) + { + GetOldStyleAvatarName(history_filename, hContact); + if (CopyImageFile(avatar->filename, history_filename)) + ShowPopup(hContact, _T("Avatar History: Unable to save avatar"), history_filename); + else + ShowDebugPopup(hContact, _T("AVH Debug: File copied successfully"), history_filename); + + if (ServiceExists(MS_MC_GETMETACONTACT)) + { + HANDLE hMetaContact = (HANDLE) CallService(MS_MC_GETMETACONTACT, wParam, 0); + + if (hMetaContact != NULL && ContactEnabled(hMetaContact, "LogToDisk", AVH_DEF_LOGTOHISTORY)) + { + TCHAR filename[MAX_PATH] = _T(""); + + GetOldStyleAvatarName(filename, hMetaContact); + if (CopyImageFile(avatar->filename, filename)) + ShowPopup(hContact, _T("Avatar History: Unable to save avatar"), filename); + else + ShowDebugPopup(hContact, _T("AVH Debug: File copied successfully"), filename); + } + } + } + } + else + { + // See if we already have the avatar + TCHAR hash[128]; + lstrcpyn(hash, avatar->hash, sizeof(hash)); + ConvertToFilename(hash, sizeof(hash)); + + TCHAR *file = GetCachedAvatar(proto, hash); + + if (file != NULL) + { + lstrcpyn(history_filename, file, MAX_REGS(history_filename)); + mir_free(file); + } + else + { + if (opts.log_keep_same_folder) + GetHistoryFolder(history_filename); + else + GetProtocolFolder(history_filename, proto); + + mir_sntprintf(history_filename, MAX_REGS(history_filename), + _T("%s\\%s"), history_filename, hash); + + if (CopyImageFile(avatar->filename, history_filename)) + ShowPopup(hContact, _T("Avatar History: Unable to save avatar"), history_filename); + else + ShowDebugPopup(hContact, _T("AVH Debug: File copied successfully"), history_filename); + } + + if (opts.log_per_contact_folders) + { + CreateOldStyleShortcut(hContact, history_filename); + + if (ServiceExists(MS_MC_GETMETACONTACT)) + { + HANDLE hMetaContact = (HANDLE) CallService(MS_MC_GETMETACONTACT, wParam, 0); + + if (hMetaContact != NULL && ContactEnabled(hMetaContact, "LogToDisk", AVH_DEF_LOGTOHISTORY)) + CreateOldStyleShortcut(hMetaContact, history_filename); + } + } + } + } + + + if (ContactEnabled(hContact, "AvatarPopups", AVH_DEF_AVPOPUPS) && opts.popup_show_changed) + ShowPopup(hContact, NULL, opts.popup_changed); + + if (ContactEnabled(hContact, "LogToHistory", AVH_DEF_LOGTOHISTORY)) + { + TCHAR rel_path[MAX_PATH] = _T(""); + CallService(MS_UTILS_PATHTORELATIVET,(WPARAM)history_filename,(LPARAM)rel_path); + char *blob = mir_utf8encodeT(rel_path); + int flags = DBEF_READ | DBEF_UTF; + if(ServiceExists(MS_HISTORYEVENTS_ADD_TO_HISTORY)) + { + HistoryEvents_AddToHistoryEx(hContact, EVENTTYPE_AVATAR_CHANGE, 0, NULL, 0, (PBYTE) blob, (int) strlen(blob) + 1, flags); + } else { DBEVENTINFO AvatarEvent = { 0 }; AvatarEvent.cbSize = sizeof(AvatarEvent); AvatarEvent.szModule = (char*)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); - char *blob = mir_utf8encodeT(rel_path); - AvatarEvent.flags = DBEF_SENT | DBEF_UTF; + AvatarEvent.flags = flags; AvatarEvent.timestamp = (DWORD) time(NULL); AvatarEvent.eventType = EVENTTYPE_AVATAR_CHANGE; AvatarEvent.cbBlob = (DWORD) strlen(blob) + 1; AvatarEvent.pBlob = (PBYTE) blob; CallService(MS_DB_EVENT_ADD,(WPARAM)hContact,(LPARAM)&AvatarEvent); - mir_free(blob); - } - } - } - - return 0; -} - -extern "C" __declspec(dllexport) int Unload(void) -{ - return 0; -} - - -static INT_PTR IsEnabled(WPARAM wParam, LPARAM lParam) -{ - HANDLE hContact = (HANDLE) wParam; - return ContactEnabled(hContact, "LogToDisk", AVH_DEF_LOGTODISK) - || ContactEnabled(hContact, "AvatarPopups", AVH_DEF_AVPOPUPS) - || ContactEnabled(hContact, "LogToHistory", AVH_DEF_LOGTOHISTORY); -} - - -/* -Get cached avatar - -wParam: (char *) protocol name -lParam: (TCHAR *) hash -return: (TCHAR *) NULL if none is found or the path to the avatar. You need to free this string - with mir_free. -*/ -static INT_PTR GetCachedAvatar(WPARAM wParam, LPARAM lParam) -{ - TCHAR hash[128]; - lstrcpyn(hash, (TCHAR *) lParam, sizeof(hash)); - ConvertToFilename(hash, sizeof(hash)); - return (INT_PTR) GetCachedAvatar((char *) wParam, hash); -} - -TCHAR * GetCachedAvatar(char *proto, TCHAR *hash) -{ - TCHAR *ret = NULL; - TCHAR file[1024] = _T(""); - TCHAR search[1024] = _T(""); - if (opts.log_keep_same_folder) - GetHistoryFolder(file); - else - GetProtocolFolder(file, proto); - - mir_sntprintf(search, MAX_REGS(search), _T("%s\\%s.*"), file, hash); - - WIN32_FIND_DATA finddata; - HANDLE hFind = FindFirstFile(search, &finddata); - if (hFind == INVALID_HANDLE_VALUE) - return NULL; - - do - { - size_t len = lstrlen(finddata.cFileName); - if (len > 4 - && (!lstrcmpi(&finddata.cFileName[len-4], _T(".png")) - || !lstrcmpi(&finddata.cFileName[len-4], _T(".bmp")) - || !lstrcmpi(&finddata.cFileName[len-4], _T(".gif")) - || !lstrcmpi(&finddata.cFileName[len-4], _T(".jpg")) - || !lstrcmpi(&finddata.cFileName[len-5], _T(".jpeg")))) - { - mir_sntprintf(file, MAX_REGS(file), _T("%s\\%s"), file, finddata.cFileName); - ret = mir_tstrdup(file); - break; - } - } while(FindNextFile(hFind, &finddata)); - FindClose(hFind); - - return ret; -} - - -int GetUIDFromHContact(HANDLE contact, TCHAR* uinout, size_t uinout_len) -{ - CONTACTINFO cinfo; - - ZeroMemory(&cinfo,sizeof(CONTACTINFO)); - cinfo.cbSize = sizeof(CONTACTINFO); - cinfo.hContact = contact; - cinfo.dwFlag = CNF_UNIQUEID | CNF_TCHAR; - - bool found = true; - if(CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&cinfo)==0) - { - if(cinfo.type == CNFT_ASCIIZ) - { - lstrcpyn(uinout, cinfo.pszVal, uinout_len); - // It is up to us to free the string - // The catch? We need to use Miranda's free(), not our CRT's :) - mir_free(cinfo.pszVal); - } - else if(cinfo.type == CNFT_DWORD) - { - _itot(cinfo.dVal,uinout,10); - } - else if(cinfo.type == CNFT_WORD) - { - _itot(cinfo.wVal,uinout,10); - } - else found = false; - } - else found = false; - - if (!found) - { - lstrcpyn(uinout, TranslateT("Unknown UIN"),uinout_len); - } - return 0; -} - - -TCHAR * GetHistoryFolder(TCHAR *fn) -{ - if (fn == NULL) return NULL; - FoldersGetCustomPathT(hFolder, fn, MAX_PATH, basedir); - if(!CreateDirectory(fn, NULL)) - ErrorExit(NULL,_T("GetHistoryFolder")); - - return fn; -} - - -TCHAR * GetProtocolFolder(TCHAR *fn, char *proto) -{ - GetHistoryFolder(fn); - - if (proto == NULL) - proto = Translate("Unknown Protocol"); - - mir_sntprintf(fn, MAX_PATH, _T("%s\\") _T(CS), fn, proto); - if(!CreateDirectory(fn, NULL)) - ErrorExit(NULL,_T("CreateDirectory")); - - return fn; -} - - -TCHAR * GetContactFolder(TCHAR *fn, HANDLE hContact) -{ - TCHAR uin[MAX_PATH]; - - char *proto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM) hContact, 0); - GetProtocolFolder(fn, proto); - - GetUIDFromHContact(hContact, uin, MAX_REGS(uin)); - mir_sntprintf(fn, MAX_PATH, _T("%s\\%s"), fn, uin); - if(!CreateDirectory(fn, NULL)) - ErrorExit(hContact,_T("CreateDirectory")); - ConvertToFilename(uin, sizeof(uin)); //added so that weather id's like "yw/CI0000" work - -#ifdef DBGPOPUPS - TCHAR log[1024]; - mir_sntprintf(log, MAX_REGS(log), _T("Path: %s\nProto: ") _T(CS) _T("\nUIN: %s"), fn, proto, uin); - ShowPopup(hContact, _T("AVH Debug: GetContactFolder"), log); -#endif - - return fn; -} - -TCHAR * GetOldStyleAvatarName(TCHAR *fn, HANDLE hContact) -{ - GetContactFolder(fn, hContact); - - SYSTEMTIME curtime; - GetLocalTime(&curtime); - mir_sntprintf(fn, MAX_PATH, - _T("%s\\%04d-%02d-%02d %02dh%02dm%02ds"), fn, - curtime.wYear, curtime.wMonth, curtime.wDay, - curtime.wHour, curtime.wMinute, curtime.wSecond); - ShowDebugPopup(hContact,_T("AVH Debug: GetOldStyleAvatarName"),fn); - return fn; -} - -BOOL CreateShortcut(TCHAR *file, TCHAR *shortcut) -{ - CoInitialize(NULL); - - IShellLink* psl = NULL; - - HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) &psl); - - if (SUCCEEDED(hr)) - { - psl->SetPath(file); - - IPersistFile* ppf = NULL; - hr = psl->QueryInterface(IID_IPersistFile, (void **) &ppf); - - if (SUCCEEDED(hr)) - { -#ifdef _UNICODE - hr = ppf->Save(shortcut, TRUE); -#else - WCHAR tmp[MAX_PATH]; - MultiByteToWideChar(CP_ACP, 0, shortcut, -1, tmp, MAX_PATH); - hr = ppf->Save(tmp, TRUE); -#endif - ppf->Release(); - } - - psl->Release(); - } - - if(FAILED(hr)) - ErrorExit(NULL,_T("CreateShortcut")); - return SUCCEEDED(hr); -} - - -BOOL ResolveShortcut(TCHAR *shortcut, TCHAR *file) -{ - CoInitialize(NULL); - - IShellLink* psl = NULL; - - HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) &psl); - - if (SUCCEEDED(hr)) - { - IPersistFile* ppf = NULL; - hr = psl->QueryInterface(IID_IPersistFile, (void **) &ppf); - - if (SUCCEEDED(hr)) - { -#ifdef _UNICODE - hr = ppf->Load(shortcut, STGM_READ); -#else - WCHAR tmp[MAX_PATH]; - MultiByteToWideChar(CP_ACP, 0, shortcut, -1, tmp, MAX_PATH); - hr = ppf->Load(tmp, STGM_READ); -#endif - - if (SUCCEEDED(hr)) - { - hr = psl->Resolve(NULL, SLR_UPDATE); - - if (SUCCEEDED(hr)) - { - WIN32_FIND_DATA wfd; - hr = psl->GetPath(file, MAX_PATH, &wfd, SLGP_RAWPATH); - } - } - - ppf->Release(); - } - psl->Release(); - } - - if(FAILED(hr)) - ErrorExit(NULL,_T("CreateShortcut")); - return SUCCEEDED(hr); -} - - -template -void ConvertToRTF(Buffer *buffer, T *line) -{ - buffer->append("{\\uc1 ", 6); - - for (; *line; line++) - { - if (*line == (T)'\r' && line[1] == (T)'\n') { - buffer->append("\\line ", 6); - line++; - } - else if (*line == (T)'\n') { - buffer->append("\\line ", 6); - } - else if (*line == (T)'\t') { - buffer->append("\\tab ", 5); - } - else if (*line == (T)'\\' || *line == (T)'{' || *line == (T)'}') { - buffer->append('\\'); - buffer->append((char) *line); - } - else if (*line < 128) { - buffer->append((char) *line); - } - else - buffer->appendPrintf("\\u%d ?", *line); - } - - buffer->append('}'); -} - - -void GetRTFFor(Buffer *buffer, HBITMAP hBitmap) -{ - BITMAP bmp; - GetObject(hBitmap, sizeof(bmp), &bmp); - - DWORD dwLen = bmp.bmWidth * bmp.bmHeight * (bmp.bmBitsPixel / 8); - BYTE *p = (BYTE *) malloc(dwLen); - if (p == NULL) - return; - - dwLen = GetBitmapBits(hBitmap, dwLen, p); - - buffer->appendPrintf("{\\pict\\wbitmap0\\wbmbitspixel%u\\wbmplanes%u\\wbmwidthbytes%u\\picw%u\\pich%u ", - bmp.bmBitsPixel, bmp.bmPlanes, bmp.bmWidthBytes, bmp.bmWidth, bmp.bmHeight); - - for (DWORD i = 0; i < dwLen; i++) - buffer->appendPrintf("%02X", p[i]); - - buffer->append('}'); - - -/* - BITMAPINFOHEADER bih = { 0 }; - HDC hdc = GetDC(NULL); - GetDIBits(hdc, hBitmap, 0, bmp.bmHeight, p, (BITMAPINFO *) & bih, DIB_RGB_COLORS); - - buffer->appendPrintf("{\\pict\\wbitmap0\\wbmbitspixel%u\\wbmplanes%u\\wbmwidthbytes%u\\picw%u\\pich%u ", - bmp.bmBitsPixel, bmp.bmPlanes, bmp.bmWidthBytes, bmp.bmWidth, bmp.bmHeight); - - DWORD i; - for (i = 0; i < sizeof(BITMAPINFOHEADER); i++) - buffer->appendPrintf("%02X", ((PBYTE) & bih)[i]); - - for (i = 0; i < dwLen; i++) - buffer->appendPrintf("%02X", p[i]); - - buffer->append('}'); -*/ - - free(p); -} - - -void * GetHistoryEventText(HANDLE hContact, HANDLE hDbEvent, DBEVENTINFO *dbe, int format) -{ - void *ret; - - if (format & HISTORYEVENTS_FORMAT_CHAR) - { - ret = DbGetEventTextA(dbe, CP_ACP); - } - else if (format & HISTORYEVENTS_FORMAT_WCHAR) - { - ret = DbGetEventTextW(dbe, CP_ACP); - } - else if (format & HISTORYEVENTS_FORMAT_RICH_TEXT) - { - Buffer buffer; - - TCHAR *tmp = DbGetEventTextT(dbe, CP_ACP); - ConvertToRTF(&buffer, tmp); - mir_free(tmp); - - // Load the image - size_t i; - for(i = dbe->cbBlob-2; i > 0 && dbe->pBlob[i] != 0; i--) ; - i++; - - if (dbe->pBlob[i] != 0) - { - TCHAR absFile[MAX_PATH] = _T(""); - CallService(MS_UTILS_PATHTOABSOLUTET,(WPARAM) &dbe->pBlob[i], (LPARAM)absFile); - if(absFile != NULL) - { - HBITMAP hBmp = (HBITMAP) CallService(MS_IMG_LOAD, (WPARAM) absFile, IMGL_TCHAR); - - if (hBmp != NULL) - { - buffer.append("\\line ", 7); - GetRTFFor(&buffer, hBmp); - DeleteObject(hBmp); - } - } - } - - buffer.append(' '); - buffer.pack(); - ret = buffer.detach(); - } - - return ret; -} - + } + mir_free(blob); + } + } + + return 0; +} + +extern "C" __declspec(dllexport) int Unload(void) +{ + return 0; +} + + +static INT_PTR IsEnabled(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE) wParam; + return ContactEnabled(hContact, "LogToDisk", AVH_DEF_LOGTODISK) + || ContactEnabled(hContact, "AvatarPopups", AVH_DEF_AVPOPUPS) + || ContactEnabled(hContact, "LogToHistory", AVH_DEF_LOGTOHISTORY); +} + + +/* +Get cached avatar + +wParam: (char *) protocol name +lParam: (TCHAR *) hash +return: (TCHAR *) NULL if none is found or the path to the avatar. You need to free this string + with mir_free. +*/ +static INT_PTR GetCachedAvatar(WPARAM wParam, LPARAM lParam) +{ + TCHAR hash[128]; + lstrcpyn(hash, (TCHAR *) lParam, sizeof(hash)); + ConvertToFilename(hash, sizeof(hash)); + return (INT_PTR) GetCachedAvatar((char *) wParam, hash); +} + +TCHAR * GetCachedAvatar(char *proto, TCHAR *hash) +{ + TCHAR *ret = NULL; + TCHAR file[1024] = _T(""); + TCHAR search[1024] = _T(""); + if (opts.log_keep_same_folder) + GetHistoryFolder(file); + else + GetProtocolFolder(file, proto); + + mir_sntprintf(search, MAX_REGS(search), _T("%s\\%s.*"), file, hash); + + WIN32_FIND_DATA finddata; + HANDLE hFind = FindFirstFile(search, &finddata); + if (hFind == INVALID_HANDLE_VALUE) + return NULL; + + do + { + size_t len = lstrlen(finddata.cFileName); + if (len > 4 + && (!lstrcmpi(&finddata.cFileName[len-4], _T(".png")) + || !lstrcmpi(&finddata.cFileName[len-4], _T(".bmp")) + || !lstrcmpi(&finddata.cFileName[len-4], _T(".gif")) + || !lstrcmpi(&finddata.cFileName[len-4], _T(".jpg")) + || !lstrcmpi(&finddata.cFileName[len-5], _T(".jpeg")))) + { + mir_sntprintf(file, MAX_REGS(file), _T("%s\\%s"), file, finddata.cFileName); + ret = mir_tstrdup(file); + break; + } + } while(FindNextFile(hFind, &finddata)); + FindClose(hFind); + + return ret; +} + + +int GetUIDFromHContact(HANDLE contact, TCHAR* uinout, size_t uinout_len) +{ + CONTACTINFO cinfo; + + ZeroMemory(&cinfo,sizeof(CONTACTINFO)); + cinfo.cbSize = sizeof(CONTACTINFO); + cinfo.hContact = contact; + cinfo.dwFlag = CNF_UNIQUEID | CNF_TCHAR; + + bool found = true; + if(CallService(MS_CONTACT_GETCONTACTINFO,0,(LPARAM)&cinfo)==0) + { + if(cinfo.type == CNFT_ASCIIZ) + { + lstrcpyn(uinout, cinfo.pszVal, uinout_len); + // It is up to us to free the string + // The catch? We need to use Miranda's free(), not our CRT's :) + mir_free(cinfo.pszVal); + } + else if(cinfo.type == CNFT_DWORD) + { + _itot(cinfo.dVal,uinout,10); + } + else if(cinfo.type == CNFT_WORD) + { + _itot(cinfo.wVal,uinout,10); + } + else found = false; + } + else found = false; + + if (!found) + { + lstrcpyn(uinout, TranslateT("Unknown UIN"),uinout_len); + } + return 0; +} + + +TCHAR * GetHistoryFolder(TCHAR *fn) +{ + if (fn == NULL) return NULL; + FoldersGetCustomPathT(hFolder, fn, MAX_PATH, basedir); + if(!CreateDirectory(fn, NULL)) + ErrorExit(NULL,_T("GetHistoryFolder")); + + return fn; +} + + +TCHAR * GetProtocolFolder(TCHAR *fn, char *proto) +{ + GetHistoryFolder(fn); + + if (proto == NULL) + proto = Translate("Unknown Protocol"); + + mir_sntprintf(fn, MAX_PATH, _T("%s\\") _T(CS), fn, proto); + if(!CreateDirectory(fn, NULL)) + ErrorExit(NULL,_T("CreateDirectory")); + + return fn; +} + + +TCHAR * GetContactFolder(TCHAR *fn, HANDLE hContact) +{ + TCHAR uin[MAX_PATH]; + + char *proto = (char *) CallService(MS_PROTO_GETCONTACTBASEPROTO,(WPARAM) hContact, 0); + GetProtocolFolder(fn, proto); + + GetUIDFromHContact(hContact, uin, MAX_REGS(uin)); + mir_sntprintf(fn, MAX_PATH, _T("%s\\%s"), fn, uin); + if(!CreateDirectory(fn, NULL)) + ErrorExit(hContact,_T("CreateDirectory")); + ConvertToFilename(uin, sizeof(uin)); //added so that weather id's like "yw/CI0000" work + +#ifdef DBGPOPUPS + TCHAR log[1024]; + mir_sntprintf(log, MAX_REGS(log), _T("Path: %s\nProto: ") _T(CS) _T("\nUIN: %s"), fn, proto, uin); + ShowPopup(hContact, _T("AVH Debug: GetContactFolder"), log); +#endif + + return fn; +} + +TCHAR * GetOldStyleAvatarName(TCHAR *fn, HANDLE hContact) +{ + GetContactFolder(fn, hContact); + + SYSTEMTIME curtime; + GetLocalTime(&curtime); + mir_sntprintf(fn, MAX_PATH, + _T("%s\\%04d-%02d-%02d %02dh%02dm%02ds"), fn, + curtime.wYear, curtime.wMonth, curtime.wDay, + curtime.wHour, curtime.wMinute, curtime.wSecond); + ShowDebugPopup(hContact,_T("AVH Debug: GetOldStyleAvatarName"),fn); + return fn; +} + +BOOL CreateShortcut(TCHAR *file, TCHAR *shortcut) +{ + CoInitialize(NULL); + + IShellLink* psl = NULL; + + HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) &psl); + + if (SUCCEEDED(hr)) + { + psl->SetPath(file); + + IPersistFile* ppf = NULL; + hr = psl->QueryInterface(IID_IPersistFile, (void **) &ppf); + + if (SUCCEEDED(hr)) + { +#ifdef _UNICODE + hr = ppf->Save(shortcut, TRUE); +#else + WCHAR tmp[MAX_PATH]; + MultiByteToWideChar(CP_ACP, 0, shortcut, -1, tmp, MAX_PATH); + hr = ppf->Save(tmp, TRUE); +#endif + ppf->Release(); + } + + psl->Release(); + } + + if(FAILED(hr)) + ErrorExit(NULL,_T("CreateShortcut")); + return SUCCEEDED(hr); +} + + +BOOL ResolveShortcut(TCHAR *shortcut, TCHAR *file) +{ + CoInitialize(NULL); + + IShellLink* psl = NULL; + + HRESULT hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (void **) &psl); + + if (SUCCEEDED(hr)) + { + IPersistFile* ppf = NULL; + hr = psl->QueryInterface(IID_IPersistFile, (void **) &ppf); + + if (SUCCEEDED(hr)) + { +#ifdef _UNICODE + hr = ppf->Load(shortcut, STGM_READ); +#else + WCHAR tmp[MAX_PATH]; + MultiByteToWideChar(CP_ACP, 0, shortcut, -1, tmp, MAX_PATH); + hr = ppf->Load(tmp, STGM_READ); +#endif + + if (SUCCEEDED(hr)) + { + hr = psl->Resolve(NULL, SLR_UPDATE); + + if (SUCCEEDED(hr)) + { + WIN32_FIND_DATA wfd; + hr = psl->GetPath(file, MAX_PATH, &wfd, SLGP_RAWPATH); + } + } + + ppf->Release(); + } + psl->Release(); + } + + if(FAILED(hr)) + ErrorExit(NULL,_T("CreateShortcut")); + return SUCCEEDED(hr); +} + + +template +void ConvertToRTF(Buffer *buffer, T *line) +{ + buffer->append("{\\uc1 ", 6); + + for (; *line; line++) + { + if (*line == (T)'\r' && line[1] == (T)'\n') { + buffer->append("\\line ", 6); + line++; + } + else if (*line == (T)'\n') { + buffer->append("\\line ", 6); + } + else if (*line == (T)'\t') { + buffer->append("\\tab ", 5); + } + else if (*line == (T)'\\' || *line == (T)'{' || *line == (T)'}') { + buffer->append('\\'); + buffer->append((char) *line); + } + else if (*line < 128) { + buffer->append((char) *line); + } + else + buffer->appendPrintf("\\u%d ?", *line); + } + + buffer->append('}'); +} + + +void GetRTFFor(Buffer *buffer, HBITMAP hBitmap) +{ + BITMAP bmp; + GetObject(hBitmap, sizeof(bmp), &bmp); + + DWORD dwLen = bmp.bmWidth * bmp.bmHeight * (bmp.bmBitsPixel / 8); + BYTE *p = (BYTE *) malloc(dwLen); + if (p == NULL) + return; + + dwLen = GetBitmapBits(hBitmap, dwLen, p); + + buffer->appendPrintf("{\\pict\\wbitmap0\\wbmbitspixel%u\\wbmplanes%u\\wbmwidthbytes%u\\picw%u\\pich%u ", + bmp.bmBitsPixel, bmp.bmPlanes, bmp.bmWidthBytes, bmp.bmWidth, bmp.bmHeight); + + for (DWORD i = 0; i < dwLen; i++) + buffer->appendPrintf("%02X", p[i]); + + buffer->append('}'); + + +/* + BITMAPINFOHEADER bih = { 0 }; + HDC hdc = GetDC(NULL); + GetDIBits(hdc, hBitmap, 0, bmp.bmHeight, p, (BITMAPINFO *) & bih, DIB_RGB_COLORS); + + buffer->appendPrintf("{\\pict\\wbitmap0\\wbmbitspixel%u\\wbmplanes%u\\wbmwidthbytes%u\\picw%u\\pich%u ", + bmp.bmBitsPixel, bmp.bmPlanes, bmp.bmWidthBytes, bmp.bmWidth, bmp.bmHeight); + + DWORD i; + for (i = 0; i < sizeof(BITMAPINFOHEADER); i++) + buffer->appendPrintf("%02X", ((PBYTE) & bih)[i]); + + for (i = 0; i < dwLen; i++) + buffer->appendPrintf("%02X", p[i]); + + buffer->append('}'); +*/ + + free(p); +} + + +void * GetHistoryEventText(HANDLE hContact, HANDLE hDbEvent, DBEVENTINFO *dbe, int format) +{ + void *ret; + + if (format & HISTORYEVENTS_FORMAT_CHAR) + { + ret = DbGetEventTextA(dbe, CP_ACP); + } + else if (format & HISTORYEVENTS_FORMAT_WCHAR) + { + ret = DbGetEventTextW(dbe, CP_ACP); + } + else if (format & HISTORYEVENTS_FORMAT_RICH_TEXT) + { + Buffer buffer; + + TCHAR *tmp = DbGetEventTextT(dbe, CP_ACP); + ConvertToRTF(&buffer, tmp); + mir_free(tmp); + + // Load the image + size_t i; + for(i = dbe->cbBlob-2; i > 0 && dbe->pBlob[i] != 0; i--) ; + i++; + + if (dbe->pBlob[i] != 0) + { + TCHAR absFile[MAX_PATH] = _T(""); + CallService(MS_UTILS_PATHTOABSOLUTET,(WPARAM) &dbe->pBlob[i], (LPARAM)absFile); + if(absFile != NULL) + { + HBITMAP hBmp = (HBITMAP) CallService(MS_IMG_LOAD, (WPARAM) absFile, IMGL_TCHAR); + + if (hBmp != NULL) + { + buffer.append("\\line ", 7); + GetRTFFor(&buffer, hBmp); + DeleteObject(hBmp); + } + } + } + + buffer.append(' '); + buffer.pack(); + ret = buffer.detach(); + } + + return ret; +} + -- cgit v1.2.3