#include "common.h" HINSTANCE hInst; int hLangpack = 0; // add icon to srmm status icons static void SrmmMenu_UpdateIcon(MCONTACT hContact); static int SrmmMenu_ProcessEvent(WPARAM wParam, LPARAM lParam); static int SrmmMenu_ProcessIconClick(WPARAM wParam, LPARAM lParam); HGENMENU hMenuToggle, hMenuClear; HANDLE hServiceToggle, hServiceClear; CRITICAL_SECTION list_cs; #define MS_NOHISTORY_TOGGLE MODULE "/ToggleOnOff" #define MS_NOHISTORY_CLEAR MODULE "/Clear" #define DBSETTING_REMOVE "RemoveHistory" // a list of db events - we'll check them for the 'read' flag periodically and delete them whwen marked as read struct EventListNode { MCONTACT hContact; HANDLE hDBEvent; EventListNode *next; }; EventListNode *event_list = 0; // plugin stuff PLUGININFOEX pluginInfo = { sizeof(PLUGININFOEX), __PLUGIN_NAME, PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), __DESCRIPTION, __AUTHOR, __AUTHOREMAIL, __COPYRIGHT, __AUTHORWEB, UNICODE_AWARE, // {B25E8C7B-292B-495A-9FB8-A4C3D4EEB04B} {0xb25e8c7b, 0x292b, 0x495a, {0x9f, 0xb8, 0xa4, 0xc3, 0xd4, 0xee, 0xb0, 0x4b}} }; BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { hInst = hinstDLL; return TRUE; } extern "C" __declspec (dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) { return &pluginInfo; } void RemoveReadEvents(MCONTACT hContact = 0) { DBEVENTINFO info = { sizeof(info) }; bool remove; EnterCriticalSection(&list_cs); EventListNode *node = event_list, *prev = 0; while(node) { remove = false; if (hContact == 0 || hContact == node->hContact) { info.cbBlob = 0; if (!db_event_get(node->hDBEvent, &info)) { if ((info.flags & DBEF_READ) || (info.flags & DBEF_SENT)) // note: already checked event type when added to list remove = true; } else { // could not get event info - maybe someone else deleted it - so remove list node remove = true; } } if (remove) { if (db_get_b(node->hContact, MODULE, DBSETTING_REMOVE, 0)) // is history disabled for this contact? db_event_delete(node->hContact, node->hDBEvent); // remove list node anyway if (event_list == node) event_list = node->next; if (prev) prev->next = node->next; free(node); if (prev) node = prev->next; else node = event_list; } else { prev = node; node = node->next; } } LeaveCriticalSection(&list_cs); } void RemoveAllEvents(MCONTACT hContact) { HANDLE hDBEvent = db_event_first(hContact); while(hDBEvent) { HANDLE hDBEventNext = db_event_next(hContact, hDBEvent); db_event_delete(hContact, hDBEvent); hDBEvent = hDBEventNext; } } void CALLBACK TimerProc(HWND hWnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime) { RemoveReadEvents(); } int OnDatabaseEventAdd(WPARAM hContact, LPARAM lParam) { HANDLE hDBEvent = (HANDLE)lParam; // history not disabled for this contact if (db_get_b(hContact, MODULE, DBSETTING_REMOVE, 0) == 0) return 0; DBEVENTINFO info = { sizeof(info) }; if ( !db_event_get(hDBEvent, &info)) { if (info.eventType == EVENTTYPE_MESSAGE) { EventListNode *node = (EventListNode *)malloc(sizeof(EventListNode)); node->hContact = hContact; node->hDBEvent = hDBEvent; EnterCriticalSection(&list_cs); node->next = event_list; event_list = node; LeaveCriticalSection(&list_cs); } } return 0; } INT_PTR ServiceClear(WPARAM hContact, LPARAM lParam) { if (MessageBox(0, TranslateT("This operation will PERMANENTLY REMOVE all history for this contact.\nAre you sure you want to do this?"), TranslateT("Clear History"), MB_YESNO | MB_ICONWARNING) == IDYES) RemoveAllEvents(hContact); return 0; } int PrebuildContactMenu(WPARAM hContact, LPARAM lParam) { bool remove = db_get_b(hContact, MODULE, DBSETTING_REMOVE, 0) != 0; char *proto = GetContactProto(hContact); bool chat_room = (proto && db_get_b(hContact, proto, "ChatRoom", 0) != 0); CLISTMENUITEM mi = { sizeof(mi) }; mi.flags = CMIM_FLAGS | CMIF_TCHAR; if (chat_room) mi.flags |= CMIF_HIDDEN; else { mi.flags |= (CMIM_NAME | CMIM_ICON); mi.ptszName = (remove ? LPGENT("Enable History") : LPGENT("Disable History")); mi.hIcon = (remove ? hIconKeep : hIconRemove); } Menu_ModifyItem(hMenuToggle, &mi); Menu_ShowItem(hMenuClear, !chat_room && db_event_count(hContact) > 0); return 0; } INT_PTR ServiceToggle(WPARAM hContact, LPARAM lParam) { int remove = db_get_b(hContact, MODULE, DBSETTING_REMOVE, 0) != 0; remove = !remove; db_set_b(hContact, MODULE, DBSETTING_REMOVE, remove != 0); StatusIconData sid = { sizeof(sid) }; sid.szModule = MODULE; for (int i = 0; i < 2; ++i) { sid.dwId = i; sid.flags = (i == remove) ? 0 : MBF_HIDDEN; Srmm_ModifyIcon(hContact, &sid); } return 0; } int WindowEvent(WPARAM wParam, LPARAM lParam) { MessageWindowEventData *mwd = (MessageWindowEventData *)lParam; MCONTACT hContact = mwd->hContact; switch(mwd->uType) { case MSG_WINDOW_EVT_CLOSE: RemoveReadEvents(hContact); break; case MSG_WINDOW_EVT_OPEN: char *proto = GetContactProto(hContact); bool chat_room = (proto && db_get_b(hContact, proto, "ChatRoom", 0) != 0); int remove = db_get_b(hContact, MODULE, DBSETTING_REMOVE, 0) != 0; StatusIconData sid = { sizeof(sid) }; sid.szModule = MODULE; for (int i=0; i < 2; ++i) { sid.dwId = i; sid.flags = (chat_room ? MBF_HIDDEN : (i == remove) ? 0 : MBF_HIDDEN); Srmm_ModifyIcon(hContact, &sid); } } return 0; } int IconPressed(WPARAM hContact, LPARAM lParam) { StatusIconClickData *sicd = (StatusIconClickData *)lParam; if (sicd->cbSize < (int)sizeof(StatusIconClickData)) return 0; if (sicd->flags & MBCF_RIGHTBUTTON) return 0; // ignore right-clicks if (strcmp(sicd->szModule, MODULE) != 0) return 0; // not our event char *proto = GetContactProto(hContact); bool chat_room = (proto && db_get_b(hContact, proto, "ChatRoom", 0) != 0); if (!chat_room) ServiceToggle(hContact, 0); return 0; } // add icon to srmm status icons void SrmmMenu_Load() { StatusIconData sid = { sizeof(sid) }; sid.szModule = MODULE; sid.dwId = 0; sid.szTooltip = LPGEN("History Enabled"); sid.hIcon = sid.hIconDisabled = hIconKeep; Srmm_AddIcon(&sid); sid.dwId = 1; sid.szTooltip = LPGEN("History Disabled"); sid.hIcon = sid.hIconDisabled = hIconRemove; Srmm_AddIcon(&sid); // hook the window events so that we can can change the status of the icon HookEvent(ME_MSG_WINDOWEVENT, WindowEvent); HookEvent(ME_MSG_ICONPRESSED, IconPressed); } int ModulesLoaded(WPARAM wParam, LPARAM lParam) { // create contact menu item CLISTMENUITEM mi = { sizeof(mi) }; mi.flags = CMIF_TCHAR; mi.position = -300010; mi.ptszName = LPGENT("Disable History"); mi.pszService = MS_NOHISTORY_TOGGLE; mi.hIcon = hIconRemove; hMenuToggle = Menu_AddMainMenuItem(&mi); mi.position = -300005; mi.ptszName = LPGENT("Clear History"); mi.pszService = MS_NOHISTORY_CLEAR; mi.hIcon = hIconClear; hMenuClear = Menu_AddMainMenuItem(&mi); // add icon to srmm status icons SrmmMenu_Load(); return 0; } extern "C" __declspec (dllexport) int Load() { mir_getLP(&pluginInfo); InitializeCriticalSection(&list_cs); // Ensure that the common control DLL is loaded (for listview) INITCOMMONCONTROLSEX icex = { sizeof(icex), ICC_LISTVIEW_CLASSES }; InitCommonControlsEx(&icex); InitIcons(); InitOptions(); HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PrebuildContactMenu); HookEvent(ME_DB_EVENT_ADDED, OnDatabaseEventAdd); HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded); hServiceToggle = CreateServiceFunction(MS_NOHISTORY_TOGGLE, ServiceToggle); hServiceClear = CreateServiceFunction(MS_NOHISTORY_CLEAR, ServiceClear); return 0; } extern "C" __declspec (dllexport) int Unload(void) { DestroyServiceFunction(hServiceToggle); DestroyServiceFunction(hServiceClear); RemoveReadEvents(); DeleteCriticalSection(&list_cs); return 0; }