summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/AvatarHistory/src/AvatarHistory.cpp1857
1 files 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<class T>
-void ConvertToRTF(Buffer<char> *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<char> *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<char> 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<class T>
+void ConvertToRTF(Buffer<char> *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<char> *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<char> 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;
+}
+