From 3a56ba391bf176c11cc5bde6f860759a3ce4477c Mon Sep 17 00:00:00 2001 From: Vadim Dashevskiy Date: Thu, 5 Jul 2012 13:27:02 +0000 Subject: BasicHistory: folder structure change git-svn-id: http://svn.miranda-ng.org/main/trunk@773 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/BasicHistory/src/BasicHistory.cpp | 425 +++++ plugins/BasicHistory/src/BinaryExport.cpp | 231 +++ plugins/BasicHistory/src/BinaryExport.h | 47 + plugins/BasicHistory/src/DatExport.cpp | 214 +++ plugins/BasicHistory/src/DatExport.h | 53 + plugins/BasicHistory/src/EventList.cpp | 907 +++++++++ plugins/BasicHistory/src/EventList.h | 161 ++ plugins/BasicHistory/src/ExportManager.cpp | 391 ++++ plugins/BasicHistory/src/ExportManager.h | 59 + plugins/BasicHistory/src/HistoryWindow.cpp | 2572 ++++++++++++++++++++++++++ plugins/BasicHistory/src/HistoryWindow.h | 95 + plugins/BasicHistory/src/HotkeyHelper.cpp | 105 ++ plugins/BasicHistory/src/HotkeyHelper.h | 24 + plugins/BasicHistory/src/IExport.h | 49 + plugins/BasicHistory/src/IImport.h | 53 + plugins/BasicHistory/src/ImageDataObject.cpp | 171 ++ plugins/BasicHistory/src/ImageDataObject.h | 133 ++ plugins/BasicHistory/src/Options.cpp | 2170 ++++++++++++++++++++++ plugins/BasicHistory/src/Options.h | 199 ++ plugins/BasicHistory/src/PlainHtmlExport.cpp | 106 ++ plugins/BasicHistory/src/PlainHtmlExport.h | 37 + plugins/BasicHistory/src/RichHtmlExport.cpp | 545 ++++++ plugins/BasicHistory/src/RichHtmlExport.h | 44 + plugins/BasicHistory/src/Scheduler.cpp | 1576 ++++++++++++++++ plugins/BasicHistory/src/SearchContext.h | 55 + plugins/BasicHistory/src/Searcher.cpp | 388 ++++ plugins/BasicHistory/src/Searcher.h | 119 ++ plugins/BasicHistory/src/TxtExport.cpp | 65 + plugins/BasicHistory/src/TxtExport.h | 38 + plugins/BasicHistory/src/codecvt_CodePage.h | 98 + plugins/BasicHistory/src/dllmain.cpp | 14 + plugins/BasicHistory/src/resource.h | 157 ++ plugins/BasicHistory/src/stdafx.cpp | 8 + plugins/BasicHistory/src/stdafx.h | 88 + plugins/BasicHistory/src/targetver.h | 8 + plugins/BasicHistory/src/version.h | 20 + 36 files changed, 11425 insertions(+) create mode 100644 plugins/BasicHistory/src/BasicHistory.cpp create mode 100644 plugins/BasicHistory/src/BinaryExport.cpp create mode 100644 plugins/BasicHistory/src/BinaryExport.h create mode 100644 plugins/BasicHistory/src/DatExport.cpp create mode 100644 plugins/BasicHistory/src/DatExport.h create mode 100644 plugins/BasicHistory/src/EventList.cpp create mode 100644 plugins/BasicHistory/src/EventList.h create mode 100644 plugins/BasicHistory/src/ExportManager.cpp create mode 100644 plugins/BasicHistory/src/ExportManager.h create mode 100644 plugins/BasicHistory/src/HistoryWindow.cpp create mode 100644 plugins/BasicHistory/src/HistoryWindow.h create mode 100644 plugins/BasicHistory/src/HotkeyHelper.cpp create mode 100644 plugins/BasicHistory/src/HotkeyHelper.h create mode 100644 plugins/BasicHistory/src/IExport.h create mode 100644 plugins/BasicHistory/src/IImport.h create mode 100644 plugins/BasicHistory/src/ImageDataObject.cpp create mode 100644 plugins/BasicHistory/src/ImageDataObject.h create mode 100644 plugins/BasicHistory/src/Options.cpp create mode 100644 plugins/BasicHistory/src/Options.h create mode 100644 plugins/BasicHistory/src/PlainHtmlExport.cpp create mode 100644 plugins/BasicHistory/src/PlainHtmlExport.h create mode 100644 plugins/BasicHistory/src/RichHtmlExport.cpp create mode 100644 plugins/BasicHistory/src/RichHtmlExport.h create mode 100644 plugins/BasicHistory/src/Scheduler.cpp create mode 100644 plugins/BasicHistory/src/SearchContext.h create mode 100644 plugins/BasicHistory/src/Searcher.cpp create mode 100644 plugins/BasicHistory/src/Searcher.h create mode 100644 plugins/BasicHistory/src/TxtExport.cpp create mode 100644 plugins/BasicHistory/src/TxtExport.h create mode 100644 plugins/BasicHistory/src/codecvt_CodePage.h create mode 100644 plugins/BasicHistory/src/dllmain.cpp create mode 100644 plugins/BasicHistory/src/resource.h create mode 100644 plugins/BasicHistory/src/stdafx.cpp create mode 100644 plugins/BasicHistory/src/stdafx.h create mode 100644 plugins/BasicHistory/src/targetver.h create mode 100644 plugins/BasicHistory/src/version.h (limited to 'plugins/BasicHistory/src') diff --git a/plugins/BasicHistory/src/BasicHistory.cpp b/plugins/BasicHistory/src/BasicHistory.cpp new file mode 100644 index 0000000000..e28278e68b --- /dev/null +++ b/plugins/BasicHistory/src/BasicHistory.cpp @@ -0,0 +1,425 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#include "stdafx.h" +#include "version.h" +#include "HistoryWindow.h" +#include "resource.h" +#include "Options.h" + +// {E25367A2-51AE-4044-BE28-131BC18B71A4} +#define MIID_BASICHISTORY { 0xe25367a2, 0x51ae, 0x4044, { 0xbe, 0x28, 0x13, 0x1b, 0xc1, 0x8b, 0x71, 0xa4 } } + +#define MS_HISTORY_DELETEALLCONTACTHISTORY "BasicHistory/DeleteAllContactHistory" +#define MS_HISTORY_EXECUTE_TASK "BasicHistory/ExecuteTask" + +HCURSOR hCurSplitNS, hCurSplitWE; +HANDLE g_hMainThread=NULL; + +extern HINSTANCE hInst; + +HANDLE hModulesLoaded, hOptionsInit, hPrebuildContactMenu, hServiceShowContactHistory, hServiceDeleteAllContactHistory, hServiceExecuteTask, hPreShutdownHistoryModule, hHistoryContactDelete, hFontsChanged,hToolBarLoaded, hSysOK; +HANDLE *hEventIcons = NULL; +int iconsNum; +HANDLE hPlusIcon, hMinusIcon, hFindNextIcon, hFindPrevIcon; +HANDLE hPlusExIcon, hMinusExIcon; +HANDLE hToolbarButton; +HGENMENU hContactMenu, hDeleteContactMenu; +HGENMENU hTaskMainMenu; +std::vector taskMenus; +bool g_SmileyAddAvail = false; +char* metaContactProto = NULL; +const IID IID_ITextDocument={0x8CC497C0, 0xA1DF, 0x11ce, {0x80, 0x98, 0x00, 0xAA, 0x00, 0x47, 0xBE, 0x5D}}; + +#define MODULE "BasicHistory" + +PLUGININFOEX pluginInfo = +{ + sizeof(PLUGININFOEX), + __PLUGIN_NAME, + PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), + __DESCRIPTION, + __AUTHOR, + __AUTHOREMAIL, + __COPYRIGHT, + __AUTHORWEB, + UNICODE_AWARE, + MIID_BASICHISTORY +}; + +TIME_API tmi = {0}; +int hLangpack = 0; + +extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion) +{ + return &pluginInfo; +} + +static const MUUID interfaces[] = {MIID_UIHISTORY, MIID_LAST}; +extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void) +{ + return interfaces; +} + +void InitScheduler(); +void DeinitScheduler(); +int DoLastTask(WPARAM, LPARAM); +INT_PTR ExecuteTaskService(WPARAM wParam, LPARAM lParam); + +int PrebuildContactMenu(WPARAM wParam, LPARAM lParam) +{ + int count = EventList::GetContactMessageNumber((HANDLE)wParam); + bool isInList = HistoryWindow::IsInList(GetForegroundWindow()); + CLISTMENUITEM mi = {0}; + mi.cbSize = sizeof(mi); + mi.flags = CMIM_FLAGS; + + if (!count) mi.flags |= CMIF_HIDDEN; + else mi.flags &= ~CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hContactMenu, (LPARAM)&mi); + + mi.flags = CMIM_FLAGS; + if (!count || !isInList) mi.flags |= CMIF_HIDDEN; + else mi.flags &= ~CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hDeleteContactMenu, (LPARAM)&mi); + + return 0; +} + +int ToolbarModuleLoaded(WPARAM wParam,LPARAM lParam) +{ + if(ServiceExists(MS_TB_ADDBUTTON)) + { + TBButton tbb = {0}; + tbb.cbSize = sizeof(tbb); + tbb.pszButtonID = "open_history"; + tbb.pszButtonName = LPGEN("Open History"); + tbb.pszServiceName = MS_HISTORY_SHOWCONTACTHISTORY; + tbb.lParam = 0; + tbb.pszTooltipUp = LPGEN("Open History"); + tbb.pszTooltipDn = LPGEN("Open History"); + tbb.defPos = 200; + tbb.tbbFlags = TBBF_SHOWTOOLTIP; + tbb.hPrimaryIconHandle = LoadSkinnedIconHandle(SKINICON_OTHER_HISTORY); + tbb.hSecondaryIconHandle = LoadSkinnedIconHandle(SKINICON_OTHER_HISTORY); + hToolbarButton = (HANDLE) CallService(MS_TB_ADDBUTTON,0, (LPARAM)&tbb); + } + return 0; +} + +void InitMenuItems() +{ + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof(mi); + mi.position = 1000090000; + mi.flags = CMIF_ICONFROMICOLIB; + mi.icolibItem = LoadSkinnedIconHandle(SKINICON_OTHER_HISTORY); + mi.pszName = LPGEN("View &History"); + mi.pszService = MS_HISTORY_SHOWCONTACTHISTORY; + hContactMenu = Menu_AddContactMenuItem(&mi); + + mi.position = 500060000; + mi.pszService = MS_HISTORY_SHOWCONTACTHISTORY; + Menu_AddMainMenuItem(&mi); + + mi.position = 1000090001; + mi.flags = CMIF_ICONFROMICOLIB; + mi.icolibItem = LoadSkinnedIconHandle(SKINICON_OTHER_DELETE); + mi.pszName = LPGEN("Delete All User History"); + mi.pszService = MS_HISTORY_DELETEALLCONTACTHISTORY; + hDeleteContactMenu = Menu_AddContactMenuItem(&mi); + + hPrebuildContactMenu = HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PrebuildContactMenu); +} + +void InitTaskMenuItems() +{ + if(Options::instance->taskOptions.size() > 0) + { + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof(mi); + if(hTaskMainMenu == NULL) + { + mi.position = 500060005; + mi.flags = CMIF_ROOTPOPUP | CMIF_ICONFROMICOLIB; + mi.icolibItem = LoadSkinnedIconHandle(SKINICON_OTHER_HISTORY); + mi.pszName = LPGEN("Execute history task"); + hTaskMainMenu = Menu_AddMainMenuItem(&mi); + } + + std::vector::iterator taskIt = Options::instance->taskOptions.begin(); + std::vector::iterator it = taskMenus.begin(); + for(; it != taskMenus.end() && taskIt != Options::instance->taskOptions.end(); ++it, ++taskIt) + { + memset(&mi, 0, sizeof(mi)); + mi.cbSize = sizeof(mi); + mi.flags = CMIM_FLAGS | CMIM_NAME | CMIF_CHILDPOPUP | CMIF_ROOTHANDLE | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; + mi.hParentMenu = hTaskMainMenu; + mi.ptszName = (TCHAR*)taskIt->taskName.c_str(); + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)(HGENMENU)*it, (LPARAM)&mi); + } + + for(; it != taskMenus.end(); ++it) + { + memset(&mi, 0, sizeof(mi)); + mi.cbSize = sizeof(mi); + mi.flags = CMIM_FLAGS | CMIF_CHILDPOPUP | CMIF_ROOTHANDLE | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED | CMIF_HIDDEN; + mi.hParentMenu = hTaskMainMenu; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)(HGENMENU)*it, (LPARAM)&mi); + } + + int pos = (int)taskMenus.size(); + for(; taskIt != Options::instance->taskOptions.end(); ++taskIt) + { + memset(&mi, 0, sizeof(mi)); + mi.cbSize = sizeof(mi); + mi.flags = CMIF_CHILDPOPUP | CMIF_ROOTHANDLE | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED; + mi.pszService = MS_HISTORY_EXECUTE_TASK; + mi.hParentMenu = hTaskMainMenu; + mi.popupPosition = pos++; + mi.ptszName = (TCHAR*)taskIt->taskName.c_str(); + HGENMENU menu = Menu_AddMainMenuItem(&mi); + taskMenus.push_back(menu); + } + } + else if(hTaskMainMenu != NULL) + { + CLISTMENUITEM mi = { 0 }; + mi.cbSize = sizeof(mi); + mi.flags = CMIM_FLAGS | CMIF_ROOTPOPUP | CMIF_HIDDEN; + CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hTaskMainMenu, (LPARAM)&mi); + } +} + +void InitIcolib() +{ + TCHAR stzFile[MAX_PATH]; + + SKINICONDESC sid = {0}; + sid.cbSize = sizeof(sid); + sid.cx = sid.cy = 16; + sid.ptszDefaultFile = stzFile; + sid.ptszSection = LPGENT("History"); + sid.flags = SIDF_ALL_TCHAR; + + GetModuleFileName(hInst, stzFile, MAX_PATH); + + iconsNum = 3; + hEventIcons = new HANDLE[iconsNum]; + sid.pszName = "BasicHistory_in"; + sid.ptszDescription = LPGENT("Incoming message"); + sid.iDefaultIndex = -IDI_INM; + hEventIcons[0] = Skin_AddIcon(&sid); + + sid.pszName = "BasicHistory_out"; + sid.ptszDescription = LPGENT("Outgoing message"); + sid.iDefaultIndex = -IDI_OUTM; + hEventIcons[1] = Skin_AddIcon(&sid); + + sid.pszName = "BasicHistory_status"; + sid.ptszDescription = LPGENT("Statuschange"); + sid.iDefaultIndex = -IDI_STATUS; + hEventIcons[2] = Skin_AddIcon(&sid); + + sid.pszName = "BasicHistory_show"; + sid.ptszDescription = LPGENT("Show Contacts"); + sid.iDefaultIndex = -IDI_SHOW; + hPlusIcon = Skin_AddIcon(&sid); + + sid.pszName = "BasicHistory_hide"; + sid.ptszDescription = LPGENT("Hide Contacts"); + sid.iDefaultIndex = -IDI_HIDE; + hMinusIcon = Skin_AddIcon(&sid); + + sid.pszName = "BasicHistory_findnext"; + sid.ptszDescription = LPGENT("Find Next"); + sid.iDefaultIndex = -IDI_FINDNEXT; + hFindNextIcon = Skin_AddIcon(&sid); + + sid.pszName = "BasicHistory_findprev"; + sid.ptszDescription = LPGENT("Find Previous"); + sid.iDefaultIndex = -IDI_FINDPREV; + hFindPrevIcon = Skin_AddIcon(&sid); + + sid.pszName = "BasicHistory_plusex"; + sid.ptszDescription = LPGENT("Plus in export"); + sid.iDefaultIndex = -IDI_PLUSEX; + hPlusExIcon = Skin_AddIcon(&sid); + + sid.pszName = "BasicHistory_minusex"; + sid.ptszDescription = LPGENT("Minus in export"); + sid.iDefaultIndex = -IDI_MINUSEX; + hMinusExIcon = Skin_AddIcon(&sid); +} + +void InitUpdater() +{ + if (ServiceExists(MS_UPDATE_REGISTER)) + { + Update update = {0}; + char szVersion[16]; + update.cbSize = sizeof(Update); + update.szComponentName = pluginInfo.shortName; + update.pbVersion = (BYTE *)CreateVersionStringPluginEx(&pluginInfo, szVersion); + update.cpbVersion = (int)strlen((char *)update.pbVersion); + +#ifdef _WIN64 + update.szUpdateURL = "http://programista.free.of.pl/miranda/BasicHistory64.zip"; + update.szVersionURL = "http://programista.free.of.pl/miranda/pluginversion.php?plugin=basichistory&x64=yes"; + update.szBetaUpdateURL = "http://programista.free.of.pl/miranda/BasicHistoryBeta64.zip"; + update.szBetaVersionURL = "http://programista.free.of.pl/miranda/pluginversion.php?plugin=basichistory&beta=yes&x64=yes"; + update.szBetaChangelogURL = "http://programista.free.of.pl/miranda/BasicHistoryChangelog.txt"; +#else + update.szUpdateURL = "http://programista.free.of.pl/miranda/BasicHistory.zip"; + update.szVersionURL = "http://programista.free.of.pl/miranda/pluginversion.php?plugin=basichistory"; + update.szBetaUpdateURL = "http://programista.free.of.pl/miranda/BasicHistoryBeta.zip"; + update.szBetaVersionURL = "http://programista.free.of.pl/miranda/pluginversion.php?plugin=basichistory&beta=yes"; + update.szBetaChangelogURL = "http://programista.free.of.pl/miranda/BasicHistoryChangelog.txt"; + +#endif + update.pbBetaVersionPrefix = update.pbVersionPrefix = (BYTE *)"Basic History "; + update.cpbBetaVersionPrefix = update.cpbVersionPrefix = (int)strlen((char *)update.pbVersionPrefix); + CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update); + } +} + +INT_PTR ShowContactHistory(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + HistoryWindow::Open(hContact); + return 0; +} + +int PreShutdownHistoryModule(WPARAM, LPARAM) +{ + HistoryWindow::Deinit(); + DeinitScheduler(); + return 0; +} + +int HistoryContactDelete(WPARAM wParam, LPARAM) +{ + HistoryWindow::Close((HANDLE)wParam); + return 0; +} + +int ModulesLoaded(WPARAM wParam, LPARAM lParam) +{ + InitMenuItems(); + InitUpdater(); + + TCHAR ftpExe[MAX_PATH]; + if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, ftpExe))) + { + _tcscat_s(ftpExe, _T("\\WinSCP\\WinSCP.exe")); + DWORD atr = GetFileAttributes(ftpExe); + if(atr == INVALID_FILE_ATTRIBUTES || atr & FILE_ATTRIBUTE_DIRECTORY) + { +#ifdef _WIN64 + if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL, SHGFP_TYPE_CURRENT, ftpExe))) + { + _tcscat_s(ftpExe, _T("\\WinSCP\\WinSCP.exe")); + atr = GetFileAttributes(ftpExe); + if(!(atr == INVALID_FILE_ATTRIBUTES || atr & FILE_ATTRIBUTE_DIRECTORY)) + { + Options::instance->ftpExePathDef = ftpExe; + } + } +#endif + } + else + Options::instance->ftpExePathDef = ftpExe; + } + + TCHAR* log = _T("%miranda_logpath%\\BasicHistory\\ftplog.txt"); + TCHAR* logAbsolute = Utils_ReplaceVarsT(log); + Options::instance->ftpLogPath = logAbsolute; + mir_free(logAbsolute); + Options::instance->Load(); + InitTaskMenuItems(); + + hPreShutdownHistoryModule = HookEvent(ME_SYSTEM_PRESHUTDOWN,PreShutdownHistoryModule); + hHistoryContactDelete = HookEvent(ME_DB_CONTACT_DELETED,HistoryContactDelete); + hFontsChanged = HookEvent(ME_FONT_RELOAD, HistoryWindow::FontsChanged); + hSysOK = HookEvent(ME_SYSTEM_OKTOEXIT, DoLastTask); + if (ServiceExists(MS_SMILEYADD_REPLACESMILEYS)) + { + g_SmileyAddAvail = true; + } + if (ServiceExists(MS_MC_GETPROTOCOLNAME)) + { + metaContactProto = (char*)CallService(MS_MC_GETPROTOCOLNAME, 0, 0); + } + + InitScheduler(); + return 0; +} + +extern "C" int __declspec(dllexport) Load(void) +{ + hTaskMainMenu = NULL; + DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&g_hMainThread,0,FALSE,DUPLICATE_SAME_ACCESS); + mir_getTMI(&tmi); + mir_getLP(&pluginInfo); + hCurSplitNS = LoadCursor(NULL, IDC_SIZENS); + hCurSplitWE = LoadCursor(NULL, IDC_SIZEWE); + hServiceShowContactHistory = CreateServiceFunction(MS_HISTORY_SHOWCONTACTHISTORY, ShowContactHistory); + hServiceDeleteAllContactHistory = CreateServiceFunction(MS_HISTORY_DELETEALLCONTACTHISTORY, HistoryWindow::DeleteAllUserHistory); + hServiceExecuteTask = CreateServiceFunction(MS_HISTORY_EXECUTE_TASK, ExecuteTaskService); + Options::instance = new Options(); + hModulesLoaded = HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded); + hOptionsInit = HookEvent(ME_OPT_INITIALISE, Options::InitOptions); + hToolBarLoaded = HookEvent(ME_TB_MODULELOADED,ToolbarModuleLoaded); + EventList::Init(); + InitIcolib(); + return 0; +} + +extern "C" int __declspec(dllexport) Unload(void) +{ + if(g_hMainThread) CloseHandle(g_hMainThread); + g_hMainThread=NULL; + UnhookEvent(hModulesLoaded); + UnhookEvent(hPrebuildContactMenu); + UnhookEvent(hPreShutdownHistoryModule); + UnhookEvent(hHistoryContactDelete); + UnhookEvent(hOptionsInit); + UnhookEvent(hFontsChanged); + UnhookEvent(hToolBarLoaded); + UnhookEvent(hSysOK); + DestroyServiceFunction(hServiceShowContactHistory); + DestroyServiceFunction(hServiceDeleteAllContactHistory); + DestroyServiceFunction(hServiceExecuteTask); + HistoryWindow::Deinit(); + DestroyCursor(hCurSplitNS); + DestroyCursor(hCurSplitWE); + EventList::Deinit(); + if(Options::instance != NULL) + { + Options::instance->Unload(); + delete Options::instance; + Options::instance = NULL; + } + + if(hEventIcons != NULL) + { + delete [] hEventIcons; + } + + return 0; +} diff --git a/plugins/BasicHistory/src/BinaryExport.cpp b/plugins/BasicHistory/src/BinaryExport.cpp new file mode 100644 index 0000000000..f57343cff0 --- /dev/null +++ b/plugins/BasicHistory/src/BinaryExport.cpp @@ -0,0 +1,231 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#include "StdAfx.h" +#include "BinaryExport.h" + +#define EXP_FILE (*((std::ofstream*)IExport::stream)) +#define IMP_FILE (*((std::ifstream*)IImport::stream)) + +std::wstring GetProtocolName(HANDLE hContact); +std::wstring GetContactId(HANDLE hContact); + +#pragma pack(push, 1) + +struct BinaryFileHeader +{ + unsigned char signature[4]; + unsigned char version; + unsigned char extraFlags; + unsigned short int reserved; + unsigned int codepage; + unsigned short int dataStart; +}; + +struct BinaryFileMessageHeader +{ + DWORD timestamp; + WORD eventType; + WORD flags; +}; + +#pragma pack(pop) + +BinaryExport::~BinaryExport() +{ +} + +void BinaryExport::WriteString(const std::wstring &str) +{ + int conv = WideCharToMultiByte(codepage, 0, str.c_str(), (int)str.length() + 1, NULL, 0, NULL, NULL); + char* buf = new char[conv]; + conv = WideCharToMultiByte(codepage, 0, str.c_str(), (int)str.length() + 1, buf, conv, NULL, NULL); + EXP_FILE.write(buf, conv); + delete[] buf; +} + +bool BinaryExport::ReadString(std::wstring &str) +{ + std::string buf; + int size = 1024; + int pos = 0; + int totalSize = 0; + while(1) + { + buf.resize(size); + if(IMP_FILE.peek() == 0) + { + IMP_FILE.get(); + break; + } + + IMP_FILE.get(((char*)buf.c_str()) + pos, size - pos, 0); + if(!IMP_FILE.good()) + return false; + + int readed = IMP_FILE.gcount(); + totalSize += readed; + char end; + IMP_FILE.get(end); + if(!IMP_FILE.good()) + return false; + if(end == 0) + break; + if(size - pos - 1 != readed) + return false; + buf[size - 1] = end; + ++totalSize; + size += 1024; + pos += 1024; + } + + if(totalSize == 0) + return true; + int sizeW = MultiByteToWideChar(codepage, 0, (char*)buf.c_str(), totalSize, NULL, 0); + str.resize(sizeW); + MultiByteToWideChar(codepage, 0, (char*)buf.c_str(), totalSize, (wchar_t*)str.c_str(), sizeW); + return true; +} + +void BinaryExport::WriteHeader(const std::wstring &fileName, const std::wstring &filterName, const std::wstring &myName, const std::wstring &myId, const std::wstring &name1, const std::wstring &proto1, const std::wstring &id1, const std::string& baseProto1, const std::wstring& encoding) +{ + BinaryFileHeader header; + memset(&header, 0, sizeof(BinaryFileHeader)); + memcpy(header.signature, "BHBF", 4); + header.codepage = codepage = CP_UTF8; + EXP_FILE.write((char*)&header, sizeof(BinaryFileHeader)); + WriteString(filterName); + WriteString(myName); + WriteString(myId); + WriteString(name1); + WriteString(proto1); + WriteString(id1); + size_t pos = EXP_FILE.tellp(); + header.dataStart = (unsigned short)pos; + EXP_FILE.seekp(offsetof(BinaryFileHeader, dataStart), std::ios_base::beg); + EXP_FILE.write((char*)&(header.dataStart), sizeof(header.dataStart)); + EXP_FILE.seekp(pos, std::ios_base::beg); + lTime = 0; +} + +void BinaryExport::WriteFooter() +{ +} + +void BinaryExport::WriteGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText) +{ +} + +void BinaryExport::WriteMessage(bool isMe, const std::wstring &longDate, const std::wstring &shortDate, const std::wstring &user, const std::wstring &message, const DBEVENTINFO& dbei) +{ + if(dbei.timestamp >= lTime) + { + BinaryFileMessageHeader header; + header.eventType = dbei.eventType; + header.flags = dbei.flags & (~(0x800)); + header.timestamp = dbei.timestamp; + EXP_FILE.write((char*)&header, sizeof(BinaryFileMessageHeader)); + WriteString(message); + lTime = dbei.timestamp; + } +} + +bool ReadHeader(BinaryFileHeader& header, std::istream* stream) +{ + stream->read((char*)&header, sizeof(BinaryFileHeader)); + if(!stream->good()) + return false; + if(memcmp(header.signature, "BHBF", 4) != 0) + return false; + if(header.version != 0 || header.codepage == 12000 || header.codepage == 12001) + return false; + + return true; +} + +int BinaryExport::IsContactInFile(const std::vector& contacts) +{ + BinaryFileHeader header; + if(!ReadHeader(header, IImport::stream)) + return -2; + codepage = header.codepage; + std::wstring filterName; + std::wstring myName; + std::wstring myId; + std::wstring name1; + std::wstring proto1; + std::wstring id1; + if(!ReadString(filterName)) + return -2; + if(!ReadString(myName)) + return -2; + if(!ReadString(myId)) + return -2; + if(!ReadString(name1)) + return -2; + if(!ReadString(proto1)) + return -2; + if(!ReadString(id1)) + return -2; + + size_t pos = IMP_FILE.tellg(); + if(header.dataStart < pos) + return -2; + + IMP_FILE.seekg(0, std::ios_base::beg); + for(int i = 0; i < (int)contacts.size(); ++i) + { + std::wstring pn = GetProtocolName(contacts[i]); + std::wstring id = GetContactId(contacts[i]); + if(pn == proto1 && id == id1) + { + return i; + } + } + + return -1; +} + +bool BinaryExport::GetEventList(std::vector& eventList) +{ + BinaryFileHeader header; + if(!ReadHeader(header, IImport::stream)) + return false; + codepage = header.codepage; + IMP_FILE.seekg(header.dataStart, std::ios_base::beg); + BinaryFileMessageHeader messageHeader; + while(1) + { + IMP_FILE.read((char*)&messageHeader, sizeof(BinaryFileMessageHeader)); + if(IMP_FILE.eof()) + break; + if(!IMP_FILE.good()) + return false; + + IImport::ExternalMessage exMsg; + exMsg.eventType = messageHeader.eventType; + exMsg.flags = messageHeader.flags; + exMsg.timestamp = messageHeader.timestamp; + if(!ReadString(exMsg.message)) + return false; + + eventList.push_back(exMsg); + } + + return true; +} diff --git a/plugins/BasicHistory/src/BinaryExport.h b/plugins/BasicHistory/src/BinaryExport.h new file mode 100644 index 0000000000..386625226f --- /dev/null +++ b/plugins/BasicHistory/src/BinaryExport.h @@ -0,0 +1,47 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once +#include "IExport.h" +#include "IImport.h" + +class BinaryExport : + public IExport, + public IImport +{ +public: + virtual const TCHAR* GetExt() + { + return _T("bin"); + } + + virtual void WriteHeader(const std::wstring &fileName, const std::wstring &filterName, const std::wstring &myName, const std::wstring &myId, const std::wstring &name1, const std::wstring &proto1, const std::wstring &id1, const std::string& baseProto1, const std::wstring& encoding); + virtual void WriteFooter(); + virtual void WriteGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText); + virtual void WriteMessage(bool isMe, const std::wstring &longDate, const std::wstring &shortDate, const std::wstring &user, const std::wstring &message, const DBEVENTINFO& dbei); + virtual int IsContactInFile(const std::vector& contacts); + virtual bool GetEventList(std::vector& eventList); + + virtual ~BinaryExport(); +private: + unsigned int codepage; + inline void WriteString(const std::wstring &str); + inline bool ReadString(std::wstring &str); + DWORD lTime; +}; + diff --git a/plugins/BasicHistory/src/DatExport.cpp b/plugins/BasicHistory/src/DatExport.cpp new file mode 100644 index 0000000000..bd74546393 --- /dev/null +++ b/plugins/BasicHistory/src/DatExport.cpp @@ -0,0 +1,214 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#include "StdAfx.h" +#include "DatExport.h" +#include "EventList.h" + +#define EXP_FILE (*((std::ofstream*)IExport::stream)) +#define IMP_FILE (*((std::ifstream*)IImport::stream)) + +std::wstring GetProtocolName(HANDLE hContact); +std::wstring GetContactId(HANDLE hContact); + +#pragma pack(push, 1) + +struct MCHeader +{ + unsigned char signature[2]; + unsigned int version; + unsigned int dataSize; +}; + +#pragma pack(pop) + +typedef struct { + int cbSize; //size of the structure in bytes + DWORD szModule; //pointer to name of the module that 'owns' this + //event, ie the one that is in control of the data format + DWORD timestamp; //seconds since 00:00, 01/01/1970. Gives us times until + //2106 unless you use the standard C library which is + //signed and can only do until 2038. In GMT. + DWORD flags; //the omnipresent flags + WORD eventType; //module-defined event type field + DWORD cbBlob; //size of pBlob in bytes + DWORD pBlob; //pointer to buffer containing module-defined event data +} DBEVENTINFO86; + + +DatExport::~DatExport() +{ +} + + +int DatExport::WriteString(const std::wstring &str) +{ + int conv = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int)str.length() + 1, NULL, 0, NULL, NULL); + if(conv > (int)memBuf.size()) + { + memBuf.resize(conv); + } + + conv = WideCharToMultiByte(CP_UTF8, 0, str.c_str(), (int)str.length() + 1, (char*)memBuf.c_str(), conv, NULL, NULL); + return conv; +} + +void DatExport::WriteHeader(const std::wstring &fileName, const std::wstring &filterName, const std::wstring &myName, const std::wstring &myId, const std::wstring &name1, const std::wstring &proto1, const std::wstring &id1, const std::string& baseProto1, const std::wstring& encoding) +{ + MCHeader header; + memset(&header, 0, sizeof(MCHeader)); + memcpy(header.signature, "HB", 2); + header.version = -1; + header.dataSize = 0; + dataSize = 0; + EXP_FILE.write((char*)&header, sizeof(MCHeader)); +} + +void DatExport::WriteFooter() +{ + size_t pos = EXP_FILE.tellp(); + EXP_FILE.seekp(offsetof(MCHeader, dataSize), std::ios_base::beg); + EXP_FILE.write((char*)&dataSize, sizeof(dataSize)); + EXP_FILE.seekp(pos, std::ios_base::beg); + memBuf.resize(0); +#ifdef _WIN64 + memBuf.shrink_to_fit(); +#endif +} + +void DatExport::WriteGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText) +{ +} + +void DatExport::WriteMessage(bool isMe, const std::wstring &longDate, const std::wstring &shortDate, const std::wstring &user, const std::wstring &message, const DBEVENTINFO& dbei) +{ + DBEVENTINFO86 header; + header.cbSize = sizeof(DBEVENTINFO86); + header.eventType = dbei.eventType; + header.flags = dbei.flags & (~(0x800)); + header.timestamp = dbei.timestamp; + header.szModule = 0; + header.pBlob = 0; + if(dbei.flags & 0x800) + { + //Imported + header.flags |= DBEF_UTF; + header.cbBlob = WriteString(message); + EXP_FILE.write((char*)&header, header.cbSize); + EXP_FILE.write(memBuf.c_str(), header.cbBlob); + } + else + { + //Internal + header.cbBlob = dbei.cbBlob; + EXP_FILE.write((char*)&header, header.cbSize); + EXP_FILE.write((char*)dbei.pBlob, header.cbBlob); + } + + dataSize += header.cbSize + header.cbBlob; +} + +bool ReadHeader(MCHeader& header, std::istream* stream) +{ + stream->read((char*)&header, sizeof(MCHeader)); + if(!stream->good()) + return false; + if(memcmp(header.signature, "HB", 2) != 0) + return false; + + return true; +} + +int DatExport::IsContactInFile(const std::vector& contacts) +{ + MCHeader header; + if(!ReadHeader(header, IImport::stream)) + return -2; + + if(contacts.size() == 1) + { + hContact = contacts[0]; + } + + IMP_FILE.seekg(0, std::ios_base::beg); + return -3; +} + +bool DatExport::GetEventList(std::vector& eventList) +{ + MCHeader header; + if(!ReadHeader(header, IImport::stream)) + return false; + dataSize = header.dataSize; + DBEVENTINFO86 messageHeader; + DBEVENTINFO info = {0}; + info.cbSize = sizeof(DBEVENTINFO); + info.szModule = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + TCHAR _str[MAXSELECTSTR + 8]; // for safety reason + std::multimap sortedEvents; + while(dataSize > 0) + { + messageHeader.cbSize = 0; + IMP_FILE.read((char*)&messageHeader, sizeof(DBEVENTINFO86)); + if(!IMP_FILE.good()) + return false; + + if(messageHeader.cbSize < sizeof(DBEVENTINFO86)) + return false; + + if(messageHeader.cbSize > sizeof(DBEVENTINFO86)) + { + IMP_FILE.seekg(messageHeader.cbSize - sizeof(DBEVENTINFO86), std::ios_base::cur); + } + + IImport::ExternalMessage exMsg; + exMsg.eventType = messageHeader.eventType; + exMsg.flags = messageHeader.flags; + exMsg.timestamp = messageHeader.timestamp; + if(messageHeader.cbBlob > memBuf.size()) + { + memBuf.resize(messageHeader.cbBlob); + } + + IMP_FILE.read((char*)memBuf.c_str(), messageHeader.cbBlob); + if(!IMP_FILE.good()) + return false; + + info.eventType = messageHeader.eventType; + info.flags = messageHeader.flags; + info.timestamp = messageHeader.timestamp; + info.cbBlob = messageHeader.cbBlob; + info.pBlob = (PBYTE)memBuf.c_str(); + EventList::GetObjectDescription(&info, _str, MAXSELECTSTR); + exMsg.message = _str; + sortedEvents.insert(std::pair(messageHeader.timestamp, exMsg)); + dataSize -= messageHeader.cbSize + messageHeader.cbBlob; + } + + memBuf.resize(0); +#ifdef _WIN64 + memBuf.shrink_to_fit(); +#endif + + for(std::multimap::iterator it = sortedEvents.begin(); it != sortedEvents.end(); ++it) + { + eventList.push_back(it->second); + } + + return true; +} diff --git a/plugins/BasicHistory/src/DatExport.h b/plugins/BasicHistory/src/DatExport.h new file mode 100644 index 0000000000..980a12d148 --- /dev/null +++ b/plugins/BasicHistory/src/DatExport.h @@ -0,0 +1,53 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once +#include "IExport.h" +#include "IImport.h" + +class DatExport : + public IExport, + public IImport +{ +public: + virtual const TCHAR* GetExt() + { + return _T("dat"); + } + + virtual void WriteHeader(const std::wstring &fileName, const std::wstring &filterName, const std::wstring &myName, const std::wstring &myId, const std::wstring &name1, const std::wstring &proto1, const std::wstring &id1, const std::string& baseProto1, const std::wstring& encoding); + virtual void WriteFooter(); + virtual void WriteGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText); + virtual void WriteMessage(bool isMe, const std::wstring &longDate, const std::wstring &shortDate, const std::wstring &user, const std::wstring &message, const DBEVENTINFO& dbei); + virtual int IsContactInFile(const std::vector& contacts); + virtual bool GetEventList(std::vector& eventList); + + DatExport() + { + hContact = NULL; + } + + virtual ~DatExport(); +private: + int dataSize; + HANDLE hContact; + std::string memBuf; + inline int WriteString(const std::wstring &str); + //inline bool ReadString(std::wstring &str, int size); +}; + diff --git a/plugins/BasicHistory/src/EventList.cpp b/plugins/BasicHistory/src/EventList.cpp new file mode 100644 index 0000000000..8ac9e2eb37 --- /dev/null +++ b/plugins/BasicHistory/src/EventList.cpp @@ -0,0 +1,907 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#include "StdAfx.h" +#include "EventList.h" +#include "Options.h" +#include "ExportManager.h" +#include + +extern int iconsNum; + +bool DeleteDirectory(LPCTSTR lpszDir, bool noRecycleBin = true); +std::wstring GetName(const std::wstring &path); + +EventList::EventList() + :hWnd(NULL), + isWnd(false), + hContact(NULL), + deltaTime(0), + isFlat(false), + useImportedMessages(true) +{ + memset(&gdbei, 0, sizeof(DBEVENTINFO)); + gdbei.cbSize = sizeof(DBEVENTINFO); + goldBlobSize = 0; +} + +EventList::EventList(HANDLE _hContact, int filter) + :hWnd(NULL), + isWnd(false), + hContact(_hContact), + deltaTime(0), + isFlat(false), + useImportedMessages(true) +{ + memset(&gdbei, 0, sizeof(DBEVENTINFO)); + gdbei.cbSize = sizeof(DBEVENTINFO); + goldBlobSize = 0; + SetDefFilter(filter); +} + + +EventList::~EventList() +{ + mir_free(gdbei.pBlob); + eventList.clear(); +} + +bool EventList::CanShowHistory(DBEVENTINFO* dbei) +{ + if(deltaTime != 0) + { + if(deltaTime > 0) + { + if(now - deltaTime < dbei->timestamp) + return false; + } + else + { + if(now + deltaTime > dbei->timestamp) + return false; + } + } + + if(hContact == NULL || defFilter == 1) + return true; + + else if(defFilter < 1) + { + switch( dbei->eventType ) + { + case EVENTTYPE_MESSAGE: + case EVENTTYPE_URL: + case EVENTTYPE_FILE: + return true; + + default: + { + DBEVENTTYPEDESCR* et = ( DBEVENTTYPEDESCR* )CallService( MS_DB_EVENT_GETTYPE, ( WPARAM )dbei->szModule, ( LPARAM )dbei->eventType ); + if ( et && ( et->flags & DETF_HISTORY )) + { + return true; + } + } + } + + return false; + } + else + { + if(filterMap.find(dbei->eventType) != filterMap.end()) + { + if(onlyInFilter) + { + return !(dbei->flags & DBEF_SENT); + } + else if(onlyOutFilter) + { + return (dbei->flags & DBEF_SENT) != 0; + } + return true; + } + return false; + } +} + +bool EventList::CanShowHistory(const IImport::ExternalMessage& message) +{ + if(deltaTime != 0) + { + if(deltaTime > 0) + { + if(now - deltaTime < message.timestamp) + return false; + } + else + { + if(now + deltaTime > message.timestamp) + return false; + } + } + + if(hContact == NULL || defFilter == 1) + return true; + + else if(defFilter < 1) + { + switch(message.eventType ) + { + case EVENTTYPE_MESSAGE: + case EVENTTYPE_URL: + case EVENTTYPE_FILE: + return true; + } + + return false; + } + else + { + if(filterMap.find(message.eventType) != filterMap.end()) + { + if(onlyInFilter) + { + return !(message.flags & DBEF_SENT); + } + else if(onlyOutFilter) + { + return (message.flags & DBEF_SENT) != 0; + } + return true; + } + return false; + } +} + +void EventList::InitFilters() +{ + filterMap.clear(); + onlyInFilter = false; + onlyOutFilter = false; + if(defFilter >= 2) + { + defFilter = 0; + for(int i = 0; i < (int)Options::instance->customFilters.size(); ++i) + { + if(filterName == Options::instance->customFilters[i].name) + { + defFilter = i + 2; + if(Options::instance->customFilters[i].onlyIncomming && !Options::instance->customFilters[i].onlyOutgoing) + { + onlyInFilter = true; + } + else if(Options::instance->customFilters[i].onlyOutgoing && !Options::instance->customFilters[i].onlyIncomming) + { + onlyOutFilter = true; + } + + for(std::vector::iterator it = Options::instance->customFilters[i].events.begin(); it != Options::instance->customFilters[i].events.end(); ++it) + { + filterMap[*it] = true; + } + + break; + } + } + } + else + filterName = L""; +} + +void EventList::SetDefFilter(int filter) +{ + defFilter = filter; + if(filter >= 2 && filter - 2 < (int)Options::instance->customFilters.size()) + { + filterName = Options::instance->customFilters[filter - 2].name; + } + else if(filter == 1) + { + filterName = TranslateT("All events"); + } + else + { + filterName = TranslateT("Default history events"); + } +} + +int EventList::GetFilterNr() +{ + return defFilter; +} + +std::wstring EventList::GetFilterName() +{ + return filterName; +} + +void EventList::GetTempList(std::list& tempList, bool noFilter, bool noExt, HANDLE _hContact) +{ + HANDLE hDbEvent; + bool isWndLocal = isWnd; + EventTempIndex ti; + EventIndex ei; + EventData data; + ti.isExternal = false; + ei.isExternal = false; + hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDFIRST,(WPARAM)_hContact,0); + while ( hDbEvent != NULL ) + { + if (isWndLocal && !IsWindow( hWnd )) + break; + ei.hEvent = hDbEvent; + if(GetEventData(ei, data)) + { + if(noFilter || CanShowHistory(&gdbei)) + { + ti.hEvent = hDbEvent; + ti.timestamp = data.timestamp; + tempList.push_back(ti); + } + } + hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDNEXT,(WPARAM)hDbEvent,0); + } + + if(!noExt) + { + std::list::iterator itL = tempList.begin(); + ti.isExternal = true; + for(int i = 0; i < (int)importedMessages.size(); ++i) + { + if(noFilter || CanShowHistory(importedMessages[i])) + { + DWORD ts = importedMessages[i].timestamp; + while(itL != tempList.end() && itL->timestamp < ts)++itL; + if(itL == tempList.end() || itL->timestamp > ts) + { + ti.exIdx = i; + ti.timestamp = ts; + tempList.insert(itL, ti); + } + } + } + } +} + +void EventList::RefreshEventList() +{ + InitNames(); + InitFilters(); + + if(useImportedMessages) + { + std::vector messages; + + EnterCriticalSection(&criticalSection); + std::map::iterator it = contactFileMap.find(hContact); + if(it != contactFileMap.end()) + { + ExportManager imp(hWnd, hContact, 1); + imp.SetAutoImport(it->second.file); + if(!imp.Import(it->second.type, messages, NULL)) + { + messages.clear(); + } + } + + LeaveCriticalSection(&criticalSection); + + ImportMessages(messages); + } + + std::list tempList; + GetTempList(tempList, false, false, hContact); + std::list revTempList; + std::list& nrTempList = tempList; + bool isNewOnTop = Options::instance->groupNewOnTop; + if(isNewOnTop) + { + revTempList.insert(revTempList.begin(), tempList.rbegin(), tempList.rend()); + nrTempList = revTempList; + } + + eventList.clear(); + eventList.push_back(std::deque()); + DWORD lastTime = MAXDWORD; + DWORD groupTime = Options::instance->groupTime * 60 * 60; + int maxMess = Options::instance->groupMessagesNumber; + int limitator = 0; + EventIndex ei; + for(std::list::iterator itL = nrTempList.begin(); itL != nrTempList.end(); ++itL) + { + DWORD tm = isNewOnTop ? lastTime - itL->timestamp : itL->timestamp - lastTime; + if(isFlat || tm < groupTime && limitator < maxMess) + { + lastTime = itL->timestamp; + ei.isExternal = itL->isExternal; + ei.hEvent = itL->hEvent; + if(isNewOnTop) + eventList.back().push_front(ei); + else + eventList.back().push_back(ei); + ++limitator; + } + else + { + limitator = 0; + lastTime = itL->timestamp; + if(!eventList.back().empty()) + { + ei = eventList.back().front(); + AddGroup(ei); + eventList.push_back(std::deque()); + } + ei.isExternal = itL->isExternal; + ei.hEvent = itL->hEvent; + eventList.back().push_front(ei); + } + } + + if(!eventList.back().empty()) + { + ei = eventList.back().front(); + AddGroup(ei); + } +} + +bool EventList::SearchInContact(HANDLE hContact, TCHAR *strFind, ComparatorInterface* compFun) +{ + InitFilters(); + + if(useImportedMessages) + { + std::vector messages; + + EnterCriticalSection(&criticalSection); + std::map::iterator it = contactFileMap.find(hContact); + if(it != contactFileMap.end()) + { + ExportManager imp(hWnd, hContact, 1); + imp.SetAutoImport(it->second.file); + if(!imp.Import(it->second.type, messages, NULL)) + { + messages.clear(); + } + } + + LeaveCriticalSection(&criticalSection); + for(int i = 0; i < (int)importedMessages.size(); ++i) + { + if(compFun->Compare((importedMessages[i].flags & DBEF_SENT) != 0, importedMessages[i].message, strFind)) + { + return true; + } + } + } + + std::list tempList; + GetTempList(tempList, false, true, hContact); + + EventIndex ei; + EventData ed; + TCHAR str[MAXSELECTSTR + 8]; // for safety reason + for(std::list::iterator itL = tempList.begin(); itL != tempList.end(); ++itL) + { + ei.isExternal = itL->isExternal; + ei.hEvent = itL->hEvent; + if(GetEventData(ei, ed)) + { + GetEventMessage(ei, str); + if(compFun->Compare(ed.isMe, str, strFind)) + { + return true; + } + } + } + + return false; +} + +void EventList::InitNames() +{ + TCHAR str[200]; + if(hContact) + { + _tcscpy_s(contactName, 256, (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, GCDNF_TCHAR )); + mir_sntprintf(str,200,TranslateT("History for %s"),contactName); + } + else + { + _tcscpy_s(contactName, 256, TranslateT("System")); + mir_sntprintf(str,200,TranslateT("History")); + } + + if(isWnd) + { + SetWindowText(hWnd,str); + } + + _tcscpy_s(myName, GetMyName().c_str()); +} + +void EventList::AddGroup(const EventIndex& ev) +{ + EventData data; + GetEventData(ev, data); + TCHAR eventText[256]; + int i; + eventText[0] = 0; + tmi.printTimeStamp(NULL, data.timestamp, _T("d t"), eventText, 64, 0); + std::wstring time = eventText; + std::wstring user; + if(data.isMe) + user = myName; + else + user = contactName; + GetEventMessage(ev, eventText, 256); + for(i = 0; eventText[i] != 0 && eventText[i] != _T('\r') && eventText[i] != _T('\n'); ++i); + eventText[i] = 0; + if(i > Options::instance->groupMessageLen) + { + eventText[Options::instance->groupMessageLen - 3] = '.'; + eventText[Options::instance->groupMessageLen - 2] = '.'; + eventText[Options::instance->groupMessageLen - 1] = '.'; + eventText[Options::instance->groupMessageLen] = 0; + } + + int ico = 0; + GetEventIcon(data.isMe, data.eventType, ico); + AddGroup(data.isMe, time, user, eventText, ico); +} + +std::wstring EventList::GetContactName() +{ + if(hContact) + { + return (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, GCDNF_TCHAR ); + } + else + { + return TranslateT("System"); + } +} + +void GetInfo(CONTACTINFO& ci, std::wstring& str) +{ + if (!CallService(MS_CONTACT_GETCONTACTINFO, 0, (LPARAM) & ci)) + { + if (ci.type == CNFT_ASCIIZ) + { + str = ci.pszVal; + mir_free(ci.pszVal); + + } + else if (ci.type == CNFT_DWORD) + { + TCHAR buf[20]; + _ltot_s(ci.dVal, buf, 10 ); + str = buf; + } + else if (ci.type == CNFT_WORD) + { + TCHAR buf[20]; + _ltot_s(ci.wVal, buf, 10 ); + str = buf; + } + } +} + +std::wstring EventList::GetMyName() +{ + std::wstring myName; + CONTACTINFO ci; + ZeroMemory(&ci, sizeof(ci)); + ci.cbSize = sizeof(ci); + ci.szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + ci.hContact = 0; + ci.dwFlag = CNF_DISPLAY | CNF_TCHAR; + GetInfo(ci, myName); + if(myName.empty()) + { + return TranslateT("Me"); + } + + return myName; +} + +inline std::wstring GetProtocolName(HANDLE hContact) +{ + char* ac = (char *)CallService(MS_PROTO_GETCONTACTBASEACCOUNT, (WPARAM)hContact, 0); + std::wstring proto1; + if(ac != NULL) + { + PROTOACCOUNT* acnt = ProtoGetAccount(ac); + if(acnt != NULL && acnt->szModuleName != NULL) + { + wchar_t* proto = mir_a2u(acnt->szProtoName); + proto1 = proto; + mir_free(proto); + } + } + + return proto1; +} + +std::wstring EventList::GetProtocolName() +{ + return ::GetProtocolName(hContact); +} + +std::string EventList::GetBaseProtocol() +{ + char* proto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + return proto == NULL ? "" : proto; +} + +std::wstring EventList::GetMyId() +{ + std::wstring myId; + CONTACTINFO ci; + ZeroMemory(&ci, sizeof(ci)); + ci.cbSize = sizeof(ci); + ci.szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + ci.hContact = 0; + ci.dwFlag = CNF_DISPLAYUID | CNF_TCHAR; + GetInfo(ci, myId); + return myId; +} + +inline std::wstring GetContactId(HANDLE hContact) +{ + std::wstring id; + CONTACTINFO ci; + ZeroMemory(&ci, sizeof(ci)); + ci.cbSize = sizeof(ci); + ci.szProto = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + ci.hContact = hContact; + ci.dwFlag = CNF_DISPLAYUID | CNF_TCHAR; + GetInfo(ci, id); + return id; +} + +std::wstring EventList::GetContactId() +{ + return ::GetContactId(hContact); +} + +static void GetMessageDescription( DBEVENTINFO *dbei, TCHAR* buf, int cbBuf ) +{ + TCHAR* msg = DbGetEventTextT( dbei, CP_ACP ); + _tcsncpy_s(buf, cbBuf, msg ? msg : TranslateT("Invalid Message"), cbBuf - 1 ); + buf[ cbBuf-1 ] = 0; + mir_free( msg ); +} + +static void GetAuthRequestDescription( DBEVENTINFO *dbei, TCHAR* buf, int cbBuf ) +{ + std::wstring allName; + buf[0] = 0; + size_t pos = sizeof( DWORD ) + sizeof( HANDLE ); + if(pos >= dbei->cbBlob) + return; + DWORD uin = *((DWORD*)dbei->pBlob); + HANDLE hContact = *((HANDLE*)(dbei->pBlob + sizeof( DWORD ))); + char* nick, *firstName, *lastName, *jid, *reason; + nick = ( char* )( dbei->pBlob + sizeof( DWORD )+ sizeof( HANDLE )); + pos += strnlen_s(nick, dbei->cbBlob - pos) + 1; + if(pos >= dbei->cbBlob) + return; + firstName = ( char* )dbei->pBlob + pos; + pos += strnlen_s(firstName, dbei->cbBlob - pos) + 1; + if(pos >= dbei->cbBlob) + return; + lastName = ( char* )dbei->pBlob + pos; + pos += strnlen_s(lastName, dbei->cbBlob - pos) + 1; + if(pos >= dbei->cbBlob) + return; + jid = (char*)dbei->pBlob + pos; + pos += strnlen_s(jid, dbei->cbBlob - pos) + 1; + if(pos >= dbei->cbBlob) + return; + reason = (char*)dbei->pBlob + pos; + TCHAR *newNick, *newFirstName, *newLastName, *newJid, *newReason; + if(dbei->flags & DBEF_UTF) + { + newNick = mir_utf8decodeT( nick ); + newFirstName = mir_utf8decodeT( firstName ); + newLastName = mir_utf8decodeT( lastName ); + newJid = mir_utf8decodeT( jid ); + newReason = mir_utf8decodeT( reason ); + } + else + { + newNick = mir_a2t( nick ); + newFirstName = mir_a2t( firstName ); + newLastName = mir_a2t( lastName ); + newJid = mir_a2t( jid ); + newReason = mir_a2t( reason ); + } + + if(newFirstName[0] != 0) + { + allName += newFirstName; + if(newLastName[0] != 0) + allName += _T(" "); + } + + if(newLastName[0] != 0) + allName += newLastName; + if(!allName.empty()) + allName += _T(", "); + if(newJid[0] != 0) + { + allName += newJid; + allName += _T(", "); + } + + _sntprintf_s(buf, cbBuf, _TRUNCATE, TranslateT("Authorisation request by %s (%s%d): %s"), + (newNick[0] == 0 ? (TCHAR*)CallService(MS_CLIST_GETCONTACTDISPLAYNAME, (WPARAM) hContact, GCDNF_TCHAR) : newNick), + allName.c_str(), uin, newReason); + mir_free( newNick ); + mir_free( newFirstName ); + mir_free( newLastName ); + mir_free( newJid ); + mir_free( newReason ); +} + +void EventList::GetObjectDescription( DBEVENTINFO *dbei, TCHAR* str, int cbStr ) +{ + switch( dbei->eventType ) + { + case EVENTTYPE_AUTHREQUEST: + GetAuthRequestDescription( dbei, str, cbStr ); + break; + + default: + GetMessageDescription( dbei, str, cbStr ); + } +} + +bool EventList::GetEventIcon(bool isMe, int eventType, int &id) +{ + switch(eventType) + { + case EVENTTYPE_MESSAGE: + id = isMe ? 1 : 0; + return true; + case EVENTTYPE_STATUSCHANGE: + id = 2; + return true; + case EVENTTYPE_FILE: + id = iconsNum; + return true; + case EVENTTYPE_URL: + id = iconsNum + 1; + return true; + case EVENTTYPE_AUTHREQUEST: + id = iconsNum + 2; + return true; + default: + id = isMe ? 1 : 0; + return false; + } +} + +void EventList::ImportMessages(const std::vector& messages) +{ + DWORD lastTime = 0; + importedMessages.clear(); + for(int i = 0; i < (int)messages.size(); ++i) + { + if(messages[i].timestamp >= lastTime) + { + importedMessages.push_back(messages[i]); + lastTime = messages[i].timestamp; + } + else + { + assert(FALSE); + } + } +} + +void EventList::MargeMessages(const std::vector& messages) +{ + ImportMessages(messages); + std::list tempList; + GetTempList(tempList, true, false, hContact); + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(DBEVENTINFO); + dbei.szModule = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + CallService(MS_DB_SETSAFETYMODE, (WPARAM)FALSE, 0); + for(std::list::iterator it = tempList.begin(); it != tempList.end(); ++it) + { + if(it->isExternal) + { + IImport::ExternalMessage& msg = importedMessages[it->exIdx]; + dbei.flags = msg.flags & (~(DBEF_FIRST)); + dbei.flags |= DBEF_READ; + dbei.timestamp = msg.timestamp; + // For now I do not convert event data from string to blob, and event type must be message to handle it properly + dbei.eventType = EVENTTYPE_MESSAGE; + UINT cp = dbei.flags & DBEF_UTF ? CP_UTF8 : CP_ACP; + dbei.cbBlob = WideCharToMultiByte(cp, 0, msg.message.c_str(), (int)msg.message.length() + 1, NULL, 0, NULL, NULL); + char* buf = new char[dbei.cbBlob]; + dbei.cbBlob = WideCharToMultiByte(cp, 0, msg.message.c_str(), (int)msg.message.length() + 1, buf, dbei.cbBlob, NULL, NULL); + dbei.pBlob = (PBYTE)buf; + CallService(MS_DB_EVENT_ADD, (WPARAM) hContact, (LPARAM) & dbei); + delete buf; + } + } + + CallService(MS_DB_SETSAFETYMODE, (WPARAM)TRUE, 0); + std::vector emessages; + ImportMessages(emessages); +} + +bool EventList::GetEventData(const EventIndex& ev, EventData& data) +{ + if(!ev.isExternal) + { + DWORD newBlobSize=CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)ev.hEvent,0); + if(newBlobSize>goldBlobSize) + { + gdbei.pBlob=(PBYTE)mir_realloc(gdbei.pBlob,newBlobSize); + goldBlobSize=newBlobSize; + } + + gdbei.cbBlob = goldBlobSize; + if (CallService(MS_DB_EVENT_GET,(WPARAM)ev.hEvent,(LPARAM)&gdbei) == 0) + { + data.isMe = (gdbei.flags & DBEF_SENT) != 0; + data.eventType = gdbei.eventType; + data.timestamp = gdbei.timestamp; + return true; + } + } + else + { + if(ev.exIdx >= 0 && ev.exIdx < (int)importedMessages.size()) + { + IImport::ExternalMessage& em = importedMessages[ev.exIdx]; + data.isMe = (em.flags & DBEF_SENT) != 0; + data.eventType = em.eventType; + data.timestamp = em.timestamp; + return true; + } + } + + return false; +} + +void EventList::GetExtEventDBei(const EventIndex& ev) +{ + IImport::ExternalMessage& em = importedMessages[ev.exIdx]; + gdbei.flags = (em.flags & (~(DBEF_FIRST))) | 0x800; + gdbei.eventType = em.eventType; + gdbei.timestamp = em.timestamp; +} + +HICON EventList::GetEventCoreIcon(const EventIndex& ev) +{ + if(ev.isExternal) + return NULL; + HICON ico; + ico = (HICON)CallService(MS_DB_EVENT_GETICON, LR_SHARED, (LPARAM)&gdbei); + HICON icoMsg = LoadSkinnedIcon(SKINICON_EVENT_MESSAGE); + if(icoMsg == ico) + { + return NULL; + } + + return ico; +} + +void EventList::RebuildGroup(int selected) +{ + std::deque newGroup; + for(size_t i = 0; i < eventList[selected].size(); ++i) + { + EventIndex& ev = eventList[selected][i]; + if(!ev.isExternal) + { + if(CallService(MS_DB_EVENT_GETBLOBSIZE,(WPARAM)(HANDLE)ev.hEvent,0) >= 0) + { + // If event exist, we add it to new group + newGroup.push_back(eventList[selected][i]); + } + } + else + { + newGroup.push_back(eventList[selected][i]); + } + } + eventList[selected].clear(); + eventList[selected].insert(eventList[selected].begin(), newGroup.begin(), newGroup.end()); +} + +CRITICAL_SECTION EventList::criticalSection; +std::map EventList::contactFileMap; +std::wstring EventList::contactFileDir; + +void EventList::AddImporter(HANDLE hContact, IImport::ImportType type, const std::wstring& file) +{ + EnterCriticalSection(&criticalSection); + TCHAR buf[32]; + _stprintf_s(buf, _T("%016llx"), (unsigned long long int)hContact); + std::wstring internalFile = contactFileDir; + ImportDiscData data; + data.file = contactFileDir + buf; + data.type = type; + CopyFile(file.c_str(), data.file.c_str(), FALSE); + contactFileMap[hContact] = data; + LeaveCriticalSection(&criticalSection); +} + +void EventList::Init() +{ + InitializeCriticalSection(&EventList::criticalSection); + TCHAR temp[MAX_PATH]; + temp[0] = 0; + GetTempPath(MAX_PATH, temp); + contactFileDir = temp; + contactFileDir += L"BasicHistoryImportDir\\"; + DeleteDirectory(contactFileDir.c_str()); + CreateDirectory(contactFileDir.c_str(), NULL); +} + +void EventList::Deinit() +{ + DeleteCriticalSection(&EventList::criticalSection); +} + +int EventList::GetContactMessageNumber(HANDLE hContact) +{ + int count = CallService(MS_DB_EVENT_GETCOUNT,(WPARAM)hContact,0); + EnterCriticalSection(&criticalSection); + std::map::iterator it = contactFileMap.find(hContact); + if(it != contactFileMap.end()) + { + ++count; + } + + LeaveCriticalSection(&criticalSection); + return count; +} + +bool EventList::IsImportedHistory(HANDLE hContact) +{ + bool count = false; + EnterCriticalSection(&criticalSection); + std::map::iterator it = contactFileMap.find(hContact); + if(it != contactFileMap.end()) + { + count = true; + } + + LeaveCriticalSection(&criticalSection); + return count; +} + +void EventList::DeleteImporter(HANDLE hContact) +{ + EnterCriticalSection(&criticalSection); + std::map::iterator it = contactFileMap.find(hContact); + if(it != contactFileMap.end()) + { + DeleteFile(it->second.file.c_str()); + contactFileMap.erase(it); + } + + LeaveCriticalSection(&criticalSection); +} diff --git a/plugins/BasicHistory/src/EventList.h b/plugins/BasicHistory/src/EventList.h new file mode 100644 index 0000000000..36628ff278 --- /dev/null +++ b/plugins/BasicHistory/src/EventList.h @@ -0,0 +1,161 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once +#include "IImport.h" + +#define MAXSELECTSTR 8184 + +class ComparatorInterface +{ +public: + virtual bool Compare(const bool isMe, const std::wstring& message, TCHAR *strFind) = 0; +}; + +class EventList +{ +public: + struct EventData + { + bool isMe; + WORD eventType; + DWORD timestamp; + }; + struct EventIndex + { + union + { + HANDLE hEvent; + int exIdx; + }; + bool isExternal; + }; +private: + std::map filterMap; + bool onlyInFilter; + bool onlyOutFilter; + int defFilter; + std::wstring filterName; + std::vector importedMessages; + DWORD goldBlobSize; + static CRITICAL_SECTION criticalSection; + + struct EventTempIndex + { + union + { + HANDLE hEvent; + int exIdx; + }; + bool isExternal; + DWORD timestamp; + }; + + struct ImportDiscData + { + IImport::ImportType type; + std::wstring file; + }; + + static std::map contactFileMap; + static std::wstring contactFileDir; + + bool CanShowHistory(DBEVENTINFO* dbei); + bool CanShowHistory(const IImport::ExternalMessage& message); + void InitFilters(); + void InitNames(); + void AddGroup(const EventIndex& ev); + void GetTempList(std::list& tempList, bool noFilter, bool noExt, HANDLE _hContact); + void ImportMessages(const std::vector& messages); +protected: + TCHAR contactName[256]; + TCHAR myName[256]; + bool isWnd; + int deltaTime; + DWORD now; + bool isFlat; + DBEVENTINFO gdbei; + + virtual void AddGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText, int ico) = 0; + bool GetEventIcon(bool isMe, int eventType, int &id); + void DeleteEvent(const EventIndex& ev) + { + if(!ev.isExternal) + CallService(MS_DB_EVENT_DELETE,(WPARAM)hContact,(LPARAM)(HANDLE)ev.hEvent); + } + + void RebuildGroup(int selected); +public: + EventList(); + EventList(HANDLE _hContact, int filter); + ~EventList(); + + HWND hWnd; + HANDLE hContact; + std::vector > eventList; + bool useImportedMessages; + + static void Init(); + static void Deinit(); + void SetDefFilter(int filter); + int GetFilterNr(); + std::wstring GetFilterName(); + void RefreshEventList(); + bool SearchInContact(HANDLE hContact, TCHAR *strFind, ComparatorInterface* compFun); + std::wstring GetContactName(); + std::wstring GetMyName(); + std::wstring GetProtocolName(); + std::wstring GetMyId(); + std::wstring GetContactId(); + std::string GetBaseProtocol(); + void MargeMessages(const std::vector& messages); + static void AddImporter(HANDLE hContact, IImport::ImportType type, const std::wstring& file); + static int GetContactMessageNumber(HANDLE hContact); + static bool IsImportedHistory(HANDLE hContact); + static void DeleteImporter(HANDLE hContact); + static void GetObjectDescription( DBEVENTINFO *dbei, TCHAR* str, int cbStr ); + bool GetEventData(const EventIndex& ev, EventData& data); + void GetExtEventDBei(const EventIndex& ev); + HICON GetEventCoreIcon(const EventIndex& ev); + void GetEventMessage(const EventIndex& ev, TCHAR* message) // must be allocated with MAXSELECTSTR len + { + if(!ev.isExternal) + GetObjectDescription(&gdbei, message, MAXSELECTSTR); + else + _tcscpy_s(message, MAXSELECTSTR, importedMessages[ev.exIdx].message.c_str()); + } + void GetEventMessage(const EventIndex& ev, TCHAR* message, int strLen) + { + if(!ev.isExternal) + GetObjectDescription(&gdbei, message, strLen); + else + { + std::wstring& meg = importedMessages[ev.exIdx].message; + if((int)meg.size() >= strLen) + { + memcpy_s(message, strLen * sizeof(TCHAR), meg.c_str(), (strLen - 1) * sizeof(TCHAR)); + message[strLen - 1] = 0; + } + else + { + _tcscpy_s(message, strLen, meg.c_str()); + } + } + } +}; + diff --git a/plugins/BasicHistory/src/ExportManager.cpp b/plugins/BasicHistory/src/ExportManager.cpp new file mode 100644 index 0000000000..897561ef26 --- /dev/null +++ b/plugins/BasicHistory/src/ExportManager.cpp @@ -0,0 +1,391 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#include "StdAfx.h" +#include "ExportManager.h" +#include "TxtExport.h" +#include "PlainHtmlExport.h" +#include "RichHtmlExport.h" +#include "BinaryExport.h" +#include "DatExport.h" +#include "Options.h" +#include "codecvt_CodePage.h" + +ExportManager::ExportManager(HWND _hwnd, HANDLE _hContact, int filter) + :EventList(_hContact, filter), + hwnd(_hwnd), + oldOnTop(false) +{ +} + +std::wstring GetFile(const TCHAR* ext, HWND hwnd, bool open) +{ + TCHAR filter[512]; + std::locale loc; + TCHAR extUpper[32]; + _tcscpy_s(extUpper, ext); + extUpper[0] = std::toupper(ext[0], loc); + _stprintf_s(filter, TranslateT("%s Files (*.%s)"), extUpper, ext); + size_t len = _tcslen(filter) + 1; + _stprintf_s(filter + len, 512 - len, TranslateT("*.%s"), ext); + len += _tcslen(filter + len); + filter[++len] = 0; + TCHAR stzFilePath[1024]; + _tcscpy_s(stzFilePath, TranslateT("History")); + _tcscat_s(stzFilePath, _T(".")); + _tcscat_s(stzFilePath, ext); + len = _tcslen(stzFilePath) + 1; + stzFilePath[len] = 0; + OPENFILENAME ofn = {0}; + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwnd; + ofn.lpstrFilter = filter; + ofn.nFilterIndex = 1; + ofn.lpstrFile = stzFilePath; + ofn.lpstrTitle = open ? TranslateT("Import") : TranslateT("Export"); + ofn.nMaxFile = 1024; + ofn.lpstrDefExt = ext; + if(open) + { + ofn.Flags = OFN_PATHMUSTEXIST | OFN_EXPLORER | OFN_NOCHANGEDIR | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + if(GetOpenFileName(&ofn)) + { + return stzFilePath; + } + } + else + { + ofn.Flags = OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST | OFN_EXPLORER | OFN_OVERWRITEPROMPT | OFN_NOCHANGEDIR; + if(GetSaveFileName(&ofn)) + { + return stzFilePath; + } + } + + return L""; +} + +std::wstring ReplaceExt(const std::wstring& file, const TCHAR* ext) +{ + size_t pos = file.find(_T("")); + if(pos < file.length()) + { + std::wstring fileName = file.substr(0, pos); + fileName += ext; + fileName += file.substr(pos + 5); + return fileName; + } + + return file; +} + +bool ExportManager::Export(IExport::ExportType type) +{ + exp = NULL; + UINT cp; + std::wstring encoding; + bool isBin = false; + switch(type) + { + case IExport::Txt: + exp = new TxtExport(); + cp = Options::instance->codepageTxt; + encoding = Options::instance->encodingTxt; + isFlat = true; + break; + case IExport::PlainHtml: + exp = new PlainHtmlExport(); + cp = Options::instance->codepageHtml1; + encoding = Options::instance->encodingHtml1; + break; + case IExport::RichHtml: + exp = new RichHtmlExport(); + cp = Options::instance->codepageHtml2; + encoding = Options::instance->encodingHtml2; + break; + case IExport::Binary: + exp = new BinaryExport(); + cp = CP_UTF8; + encoding = L"UTF8"; + isFlat = true; + oldOnTop = true; + isBin = true; + break; + case IExport::Dat: + exp = new DatExport(); + cp = CP_UTF8; + encoding = L"UTF8"; + isFlat = true; + oldOnTop = true; + isBin = true; + break; + default: + return false; + } + + std::wstring fileName; + if(file.empty()) + fileName = GetFile(exp->GetExt(), hwnd, false); + else + { + fileName = ReplaceExt(file, exp->GetExt()); + } + + if(fileName.empty()) + return false; + + std::wofstream* stream; + if(!isBin) + { + stream = new std::wofstream (fileName.c_str()); + if(!stream->is_open()) + return false; + + std::locale filelocale(std::locale(), new codecvt_CodePage(cp)); + stream->imbue(filelocale); + exp->SetStream(stream); + } + else + { + std::ofstream* cstream = new std::ofstream (fileName.c_str(), std::ios_base::binary); + if(!cstream->is_open()) + return false; + + stream = (std::wofstream*)cstream; + exp->SetStream(stream); + } + + exp->WriteHeader(fileName, GetFilterName(), GetMyName(), GetMyId(), GetContactName(), GetProtocolName(), GetContactId(), GetBaseProtocol(), encoding); + + RefreshEventList(); + + exp->WriteFooter(); + if(!isBin) + { + stream->close(); + delete stream; + } + else + { + std::ofstream* cstream = (std::ofstream*)stream; + cstream->close(); + delete cstream; + } + + delete exp; + return true; +} + +const TCHAR* ExportManager::GetExt(IImport::ImportType type) +{ + IImport* imp = NULL; + switch(type) + { + case IImport::Binary: + imp = new BinaryExport(); + break; + case IImport::Dat: + imp = new DatExport(); + break; + default: + return L""; + } + + const TCHAR* ext = imp->GetExt(); + delete imp; + return ext; +} + +int ExportManager::Import(IImport::ImportType type, const std::vector& contacts) +{ + IImport* imp = NULL; + switch(type) + { + case IImport::Binary: + imp = new BinaryExport(); + break; + case IImport::Dat: + imp = new DatExport(); + break; + default: + return -2; + } + + std::wstring fileName; + if(file.empty()) + return -2; + else + { + fileName = ReplaceExt(file, imp->GetExt()); + } + + if(fileName.empty()) + return -2; + + std::ifstream* stream = new std::ifstream (fileName.c_str(), std::ios_base::binary); + if(!stream->is_open()) + return -2; + + imp->SetStream(stream); + int t = imp->IsContactInFile(contacts); + stream->close(); + delete stream; + delete imp; + return t; +} + +bool ExportManager::Import(IImport::ImportType type, std::vector& eventList, std::wstring* err) +{ + IImport* imp = NULL; + switch(type) + { + case IImport::Binary: + imp = new BinaryExport(); + break; + case IImport::Dat: + imp = new DatExport(); + break; + default: + return false; + } + + std::wstring fileName; + if(file.empty()) + file = fileName = GetFile(imp->GetExt(), hwnd, true); + else + { + fileName = ReplaceExt(file, imp->GetExt()); + } + + std::ifstream* stream = new std::ifstream (fileName.c_str(), std::ios_base::binary); + if(!stream->is_open()) + return false; + + imp->SetStream(stream); + std::vector v; + v.push_back(hContact); + bool ret = true; + int contInFile = imp->IsContactInFile(v); + if(contInFile != 0 && contInFile != -3) + { + ret = false; + if(err != NULL) + *err = TranslateT("File do not contain selected contact"); + } + else + { + ret = imp->GetEventList(eventList); + if(!ret && err != NULL) + *err = TranslateT("File is corrupted"); + } + stream->close(); + delete stream; + delete imp; + return ret; +} + +void ExportManager::AddGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText, int ico) +{ + if(exp == NULL) + return; + exp->WriteGroup(isMe, time, user, eventText); + TCHAR str[MAXSELECTSTR + 8]; // for safety reason + str[0] = 0; + tm lastTime; + bool isFirst = true; + bool lastMe = false; + EventData data; + std::deque revDeq; + std::deque& deq = eventList.back(); + if(!oldOnTop && Options::instance->messagesNewOnTop) + { + revDeq.insert(revDeq.begin(), deq.rbegin(), deq.rend()); + deq = revDeq; + } + for(std::deque::iterator it = deq.begin(); it != deq.end(); ++it) + { + EventIndex hDbEvent = *it; + if(GetEventData(hDbEvent, data)) + { + lastMe = data.isMe; + + TCHAR* formatDate = Options::instance->messagesShowSec ? _T("d s") : _T("d t"); + TCHAR* longFormatDate = Options::instance->messagesShowSec ? _T("d s") : _T("d t"); + if(!Options::instance->messagesShowDate) + { + if(isFirst) + { + isFirst = false; + formatDate = Options::instance->messagesShowSec ? _T("s") : _T("t"); + time_t tt = data.timestamp; + localtime_s(&lastTime, &tt); + } + else + { + time_t tt = data.timestamp; + tm t; + localtime_s(&t, &tt); + if(lastTime.tm_yday == t.tm_yday && lastTime.tm_year == t.tm_year) + formatDate = Options::instance->messagesShowSec ? _T("s") : _T("t"); + } + } + + tmi.printTimeStamp(NULL, data.timestamp, longFormatDate, str , MAXSELECTSTR, 0); + std::wstring longDate = str; + tmi.printTimeStamp(NULL, data.timestamp, formatDate, str , MAXSELECTSTR, 0); + std::wstring shortDate = str; + + std::wstring user; + if(lastMe) + user = myName; + else + user = contactName; + + GetEventMessage(hDbEvent, str); + std::wstring strMessage = str; + if(strMessage.length() + 1 >= MAXSELECTSTR) + continue; + + if(hDbEvent.isExternal) + { + GetExtEventDBei(hDbEvent); + } + + exp->WriteMessage(lastMe, longDate, shortDate, user, strMessage, gdbei); + } + } +} + +void ExportManager::DeleteExportedEvents() +{ + for(size_t j = 0; j < eventList.size(); ++j) + { + for(size_t i = 0; i < eventList[j].size(); ++i) + { + DeleteEvent(eventList[j][i]); + } + } +} + +void ExportManager::SetDeleteWithoutExportEvents(int _deltaTime, DWORD _now) +{ + exp = NULL; + deltaTime = _deltaTime; + now = _now; + RefreshEventList(); +} diff --git a/plugins/BasicHistory/src/ExportManager.h b/plugins/BasicHistory/src/ExportManager.h new file mode 100644 index 0000000000..d99ff077a6 --- /dev/null +++ b/plugins/BasicHistory/src/ExportManager.h @@ -0,0 +1,59 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once +#include "EventList.h" +#include "IExport.h" +#include "IImport.h" +class ExportManager : public EventList +{ +private: + IExport* exp; + std::wstring file; + HWND hwnd; + bool oldOnTop; +protected: + virtual void AddGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText, int ico); +public: + ExportManager(HWND _hwnd, HANDLE _hContact, int filter); + + void SetAutoExport(const std::wstring _file, int _deltaTime, DWORD _now) + { + file = _file; + deltaTime = _deltaTime; + now = _now; + } + + void SetAutoImport(const std::wstring _file) + { + file = _file; + } + + std::wstring GetFileName() + { + return file; + } + + bool Export(IExport::ExportType type); + void SetDeleteWithoutExportEvents(int _deltaTime, DWORD _now); + void DeleteExportedEvents(); + int Import(IImport::ImportType type, const std::vector& contacts); + bool Import(IImport::ImportType type, std::vector& eventList, std::wstring* err = NULL); + static const TCHAR* GetExt(IImport::ImportType type); +}; + diff --git a/plugins/BasicHistory/src/HistoryWindow.cpp b/plugins/BasicHistory/src/HistoryWindow.cpp new file mode 100644 index 0000000000..d5c3948cb7 --- /dev/null +++ b/plugins/BasicHistory/src/HistoryWindow.cpp @@ -0,0 +1,2572 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#include "StdAfx.h" +#include "HistoryWindow.h" +#include "resource.h" +#include "Options.h" +#include "HotkeyHelper.h" +#include "ImageDataObject.h" +#include "ExportManager.h" + +#define MODULE "BasicHistory" +extern HINSTANCE hInst; +extern HCURSOR hCurSplitNS, hCurSplitWE; +extern HANDLE *hEventIcons; +extern int iconsNum; +extern HANDLE hPlusIcon, hMinusIcon, hFindNextIcon, hFindPrevIcon; +extern bool g_SmileyAddAvail; +extern char* metaContactProto; +#define DM_HREBUILD (WM_USER+11) +#define DM_SPLITTERMOVED (WM_USER+15) + +#define MIN_PANELHEIGHT 40 + +void ResetCList(HWND hWnd); + +HistoryWindow::HistoryWindow(HANDLE _hContact) : + isDestroyed(true), + OldSplitterProc(0), + splitterY(0), + splitterOrgY(0), + splitterX(0), + splitterOrgX(0), + plusIco(NULL), + minusIco(NULL), + findNextIco(NULL), + findPrevIco(NULL), + configIco(NULL), + deleteIco(NULL), + isContactList(false), + isLoading(false), + isGroupImages(false), + allIconNumber(0), + eventIcoms(NULL), + bkBrush(NULL), + bkFindBrush(NULL), + hSystem(NULL), + splitterXhWnd(NULL), + splitterYhWnd(NULL) +{ + searcher.SetContect(this); + hContact = _hContact; + selected = -1; + searcher.SetMatchCase(Options::instance->searchMatchCase); + searcher.SetMatchWholeWords(Options::instance->searchMatchWhole); + searcher.SetOnlyIn(Options::instance->searchOnlyIn); + searcher.SetOnlyOut(Options::instance->searchOnlyOut); + searcher.SetOnlyGroup(Options::instance->searchOnlyGroup); + searcher.SetAllUsers(Options::instance->searchAllContacts); + searcher.SetSearchForInLG(Options::instance->searchForInList); + searcher.SetSearchForInMes(Options::instance->searchForInMess); +} + + +HistoryWindow::~HistoryWindow() +{ + if(eventIcoms != NULL) + { + for(int i = 0; i < iconsNum; ++i) + { + if(eventIcoms[i] != NULL) + { + CallService(MS_SKIN2_RELEASEICON, (LPARAM)eventIcoms[i], 0); + } + } + + delete[] eventIcoms; + } + + if(plusIco != NULL) + { + CallService(MS_SKIN2_RELEASEICON, (LPARAM)plusIco, 0); + } + if(minusIco != NULL) + { + CallService(MS_SKIN2_RELEASEICON, (LPARAM)minusIco, 0); + } + if(findNextIco != NULL) + { + CallService(MS_SKIN2_RELEASEICON, (LPARAM)findNextIco, 0); + } + if(findPrevIco != NULL) + { + CallService(MS_SKIN2_RELEASEICON, (LPARAM)findPrevIco, 0); + } + if(himlSmall != NULL) + { + ImageList_Destroy(himlSmall); + } + if(himlNone != NULL) + { + ImageList_Destroy(himlNone); + } + if(bkBrush != NULL) + { + DeleteObject(bkBrush); + } + if(bkFindBrush != NULL) + { + DeleteObject(bkFindBrush); + } +} + +std::map HistoryWindow::windows; +std::vector HistoryWindow::freeWindows; + +void HistoryWindow::Deinit() +{ + bool destroyed = true; + std::vector keys; + for(std::map::iterator it = windows.begin(); it != windows.end(); ++it) + { + if(!it->second->isDestroyed) + { + keys.push_back(it->first); + } + } + for(std::vector::iterator it = keys.begin(); it != keys.end(); ++it) + { + std::map::iterator it1 = windows.find(*it); + if(it1 != windows.end()) + { + DestroyWindow(it1->second->hWnd); + it1 = windows.find(*it); + destroyed &= it1 == windows.end(); + } + } + + std::vector keys1; + for(std::vector::iterator it = freeWindows.begin(); it != freeWindows.end(); ++it) + { + if(!(*it)->isDestroyed) + { + keys1.push_back(*it); + } + } + for(std::vector::iterator it = keys1.begin(); it != keys1.end(); ++it) + { + DestroyWindow((*it)->hWnd); + } + for(std::vector::iterator it = freeWindows.begin(); it != freeWindows.end(); ++it) + { + if(!(*it)->isDestroyed) + { + destroyed = false; + break; + } + } + + if(destroyed) + { + for(std::map::iterator it = windows.begin(); it != windows.end(); ++it) + { + delete it->second; + } + + windows.clear(); + + for(std::vector::iterator it = freeWindows.begin(); it != freeWindows.end(); ++it) + { + delete *it; + } + + freeWindows.clear(); + } +} + +void HistoryWindow::Open(HANDLE hContact) +{ + if(hContact == NULL) + { + HistoryWindow *hw = new HistoryWindow(hContact); + freeWindows.push_back(hw); + hw->Show(); + } + else + { + std::map::iterator it = windows.find(hContact); + if(it != windows.end()) + { + it->second->Focus(); + } + else + { + windows[hContact] = new HistoryWindow(hContact); + windows[hContact]->Show(); + } + } +} + +void HistoryWindow::Close(HANDLE hContact) +{ + std::map::iterator it = windows.find(hContact); + if(it != windows.end()) + { + if(it->second->isDestroyed) + { + delete it->second; + windows.erase(it); + } + else + { + DestroyWindow(it->second->hWnd); + } + } +} + +void HistoryWindow::Close(HistoryWindow* historyWindow) +{ + if(!historyWindow->isDestroyed) + { + DestroyWindow(historyWindow->hWnd); + return; + } + std::map::iterator it = windows.find(historyWindow->hContact); + if(it != windows.end() && it->second == historyWindow) + { + delete it->second; + windows.erase(it); + } + else + { + for(std::vector::iterator it = freeWindows.begin(); it != freeWindows.end(); ++it) + { + if(*it == historyWindow) + { + freeWindows.erase(it); + delete historyWindow; + return; + } + } + } +} + +void HistoryWindow::RebuildEvents(HANDLE hContact) +{ + if(hContact != NULL) + { + std::map::iterator it = windows.find(hContact); + if(it != windows.end() && !it->second->isDestroyed) + { + SendMessage(it->second->hWnd,DM_HREBUILD,0,0); + } + } + + for(std::vector::iterator it = freeWindows.begin(); it != freeWindows.end(); ++it) + { + if((*it)->hContact == hContact && !(*it)->isDestroyed) + { + SendMessage((*it)->hWnd,DM_HREBUILD,0,0); + } + } +} + +void HistoryWindow::ChangeToFreeWindow(HistoryWindow* historyWindow) +{ + std::map::iterator it = windows.find(historyWindow->hContact); + if(it != windows.end() && it->second == historyWindow) + { + windows.erase(it); + freeWindows.push_back(historyWindow); + } +} + +void HistoryWindow::Show() +{ + CreateDialogParam(hInst,MAKEINTRESOURCE(IDD_HISTORY),NULL,HistoryWindow::DlgProcHistory,(LPARAM)this); +} + +void HistoryWindow::Focus() +{ + if(IsIconic(hWnd)) + { + ShowWindow(hWnd, SW_RESTORE); + } + else + { + SetForegroundWindow(hWnd); + SetFocus(hWnd); + } + SendMessage(hWnd,DM_HREBUILD,0,0); +} + +int HistoryWindow::FontsChanged(WPARAM wParam, LPARAM lParam) +{ + for(std::map::iterator it = windows.begin(); it != windows.end(); ++it) + { + if(!it->second->isDestroyed) + { + it->second->FontsChanged(); + } + } + + for(std::vector::iterator it = freeWindows.begin(); it != freeWindows.end(); ++it) + { + if(!(*it)->isDestroyed) + { + (*it)->FontsChanged(); + } + } + + return 0; +} + +void HistoryWindow::FontsChanged() +{ + if(bkBrush != NULL) + { + DeleteObject(bkBrush); + } + if(bkFindBrush != NULL) + { + DeleteObject(bkFindBrush); + } + + bkBrush = CreateSolidBrush(Options::instance->GetColor(Options::WindowBackground)); + bkFindBrush = CreateSolidBrush(Options::instance->GetColor(Options::FindBackground)); + + ResetCList(hWnd); + COLORREF bkColor = Options::instance->GetColor(Options::GroupListBackground); + ListView_SetBkColor(listWindow, bkColor); + ListView_SetTextBkColor(listWindow, bkColor); + LOGFONT font; + ListView_SetTextColor(listWindow, Options::instance->GetFont(Options::GroupList, &font)); + InvalidateRect(listWindow, NULL, TRUE); + InvalidateRect(hWnd, NULL, TRUE); + SelectEventGroup(selected); +} + +void OptionsGroupChanged() +{ + HistoryWindow::OptionsGroupChanged(); +} + +void HistoryWindow::OptionsGroupChanged() +{ + for(std::map::iterator it = windows.begin(); it != windows.end(); ++it) + { + if(!it->second->isDestroyed) + { + it->second->GroupImagesChanged(); + SendMessage(it->second->hWnd,DM_HREBUILD,0,0); + } + } + + for(std::vector::iterator it = freeWindows.begin(); it != freeWindows.end(); ++it) + { + if(!(*it)->isDestroyed) + { + (*it)->GroupImagesChanged(); + SendMessage((*it)->hWnd,DM_HREBUILD,0,0); + } + } +} + +void OptionsMainChanged() +{ + HistoryWindow::OptionsMainChanged(); +} + +void HistoryWindow::OptionsMainChanged() +{ + for(std::map::iterator it = windows.begin(); it != windows.end(); ++it) + { + if(!it->second->isDestroyed) + { + it->second->ReloadMainOptions(); + } + } + + for(std::vector::iterator it = freeWindows.begin(); it != freeWindows.end(); ++it) + { + if(!(*it)->isDestroyed) + { + (*it)->ReloadMainOptions(); + } + } +} + +void HistoryWindow::ReloadMainOptions() +{ + SendDlgItemMessage(hWnd, IDC_LIST_CONTACTS, CLM_SETUSEGROUPS, Options::instance->showContactGroups, 0); + SendMessage(hWnd,DM_HREBUILD,0,0); +} + +void OptionsMessageChanged() +{ + HistoryWindow::FontsChanged(0, 0); +} + +void OptionsSearchingChanged() +{ + HistoryWindow::OptionsSearchingChanged(); +} + +void HistoryWindow::OptionsSearchingChanged() +{ + for(std::map::iterator it = windows.begin(); it != windows.end(); ++it) + { + if(!it->second->isDestroyed) + { + it->second->searcher.SetSearchForInLG(Options::instance->searchForInList); + it->second->searcher.SetSearchForInMes(Options::instance->searchForInMess); + } + } + + for(std::vector::iterator it = freeWindows.begin(); it != freeWindows.end(); ++it) + { + if(!(*it)->isDestroyed) + { + (*it)->searcher.SetSearchForInLG(Options::instance->searchForInList); + (*it)->searcher.SetSearchForInMes(Options::instance->searchForInMess); + } + } +} + +INT_PTR HistoryWindow::DeleteAllUserHistory(WPARAM wParam, LPARAM lParam) +{ + HANDLE hContact = (HANDLE)wParam; + HWND hWnd = NULL; + int start = 0; + int end = 0; + int count = EventList::GetContactMessageNumber(hContact); + if(!count) + return FALSE; + + for(std::map::iterator it = windows.begin(); it != windows.end(); ++it) + { + if(!it->second->isDestroyed) + { + if(it->second->hContact == hContact) + { + if(hWnd == NULL) + { + hWnd = it->second->hWnd; + } + else if(GetForegroundWindow() == it->second->hWnd) + { + hWnd = it->second->hWnd; + } + } + } + } + + for(std::vector::iterator it = freeWindows.begin(); it != freeWindows.end(); ++it) + { + if(!(*it)->isDestroyed) + { + if((*it)->hContact == hContact) + { + if(hWnd == NULL) + { + hWnd = (*it)->hWnd; + } + else if(GetForegroundWindow() == (*it)->hWnd) + { + hWnd = (*it)->hWnd; + } + } + } + } + + TCHAR *message = TranslateT("This operation will PERMANENTLY REMOVE all history for this contact.\nAre you sure you want to do this?"); + if(MessageBox(hWnd, message, TranslateT("Are You sure?"), MB_OKCANCEL | MB_ICONERROR) != IDOK) + return FALSE; + + std::deque toRemove; + HANDLE hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDFIRST,(WPARAM)hContact,0); + while ( hDbEvent != NULL ) + { + toRemove.push_back(hDbEvent); + hDbEvent=(HANDLE)CallService(MS_DB_EVENT_FINDNEXT,(WPARAM)hDbEvent,0); + } + + for(std::deque::iterator it = toRemove.begin(); it != toRemove.end(); ++it) + { + CallService(MS_DB_EVENT_DELETE,(WPARAM)hContact,(LPARAM)(HANDLE)*it); + } + + if(EventList::IsImportedHistory(hContact)) + { + TCHAR *message = TranslateT("Do you want delete all imported messages for this contact?\nNote that next scheduler task import this messages again."); + if(MessageBox(hWnd, message, TranslateT("Are You sure?"), MB_YESNO | MB_ICONERROR) == IDYES) + { + EventList::DeleteImporter(hContact); + } + } + + RebuildEvents(hContact); + return TRUE; +} + +bool HistoryWindow::IsInList(HWND hWnd) +{ + for(std::map::iterator it = windows.begin(); it != windows.end(); ++it) + { + if(!it->second->isDestroyed) + { + if(it->second->hWnd == hWnd) + { + return true; + } + } + } + + for(std::vector::iterator it = freeWindows.begin(); it != freeWindows.end(); ++it) + { + if(!(*it)->isDestroyed) + { + if((*it)->hWnd == hWnd) + { + return true; + } + } + } + + return false; +} + +void ClickLink(HWND hwnd, ENLINK *penLink) +{ + TCHAR buf[1024]; + if(penLink->msg != WM_LBUTTONUP) + return; + if(penLink->chrg.cpMin >= 0 && penLink->chrg.cpMax > penLink->chrg.cpMin) + { + // selection + int len = penLink->chrg.cpMax - penLink->chrg.cpMin; + if(len < 1023) + { + TEXTRANGE tr; + CHARRANGE sel; + + SendMessage(hwnd, EM_EXGETSEL, 0, (LPARAM) & sel); + if (sel.cpMin != sel.cpMax) + return; + tr.chrg = penLink->chrg; + tr.lpstrText = buf; + SendMessage(hwnd, EM_GETTEXTRANGE, 0, (LPARAM) & tr); + CallService(MS_UTILS_OPENURL, (penLink->nmhdr.code == IDM_OPENNEW ? OUF_NEWWINDOW : 0) | OUF_TCHAR, (LPARAM) tr.lpstrText); + } + } +} + +void ConvertSize(HWND hwndSrc, HWND hwndDest, RECT& rc) +{ + POINT pt; + pt.x = rc.left; + pt.y = rc.top; + ClientToScreen(hwndSrc, &pt); + ScreenToClient(hwndDest, &pt); + rc.left = pt.x; + rc.top = pt.y; + + pt.x = rc.right; + pt.y = rc.bottom; + ClientToScreen(hwndSrc, &pt); + ScreenToClient(hwndDest, &pt); + rc.right = pt.x; + rc.bottom = pt.y; +} + +void OpenOptions(char* group, char* page, char* tab = NULL) +{ + OPENOPTIONSDIALOG op; + op.cbSize = sizeof(OPENOPTIONSDIALOG); + op.pszGroup = group; + op.pszPage = page; + op.pszTab = tab; + CallService(MS_OPT_OPENOPTIONS, 0, (LPARAM)&op); +} + +#define DlgReturn(ret){\ + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (ret));\ + return (ret);\ +} + +class ShowMessageData +{ +public: + ShowMessageData(HANDLE _hContact) + :hContact(_hContact) + { + } + + ShowMessageData(HANDLE _hContact, const std::wstring &_str) + :hContact(_hContact), + str(_str) + { + } + + HANDLE hContact; + std::wstring str; +}; + +void __stdcall ShowMessageWindow(void* arg) +{ + ShowMessageData* dt = (ShowMessageData*)arg; + if(dt->str.empty()) + CallService(MS_MSG_SENDMESSAGE, (WPARAM)dt->hContact, 0); + else + CallService(MS_MSG_SENDMESSAGET, (WPARAM)dt->hContact, (LPARAM)dt->str.c_str()); + delete dt; +} + +INT_PTR CALLBACK HistoryWindow::DlgProcHistory(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_GETMINMAXINFO: + ((MINMAXINFO*)lParam)->ptMinTrackSize.x=500; + ((MINMAXINFO*)lParam)->ptMinTrackSize.y=380; + + case WM_SIZE: + { + UTILRESIZEDIALOG urd={0}; + urd.cbSize=sizeof(urd); + urd.hwndDlg=hwndDlg; + urd.hInstance=hInst; + urd.lpTemplate=MAKEINTRESOURCEA(IDD_HISTORY); + urd.lParam=(LPARAM)NULL; + urd.pfnResizer=HistoryWindow::HistoryDlgResizer; + CallService(MS_UTILS_RESIZEDIALOG,0,(LPARAM)&urd); + ListView_SetColumnWidth(GetDlgItem(hwndDlg,IDC_LIST), 0, LVSCW_AUTOSIZE_USEHEADER); + DlgReturn(TRUE); + } + case WM_COMMAND: + switch ( LOWORD( wParam )) { + case IDOK: + case IDCANCEL: + DestroyWindow(hwndDlg); + DlgReturn(TRUE); + + case IDM_FIND: + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + historyWindow->searcher.Find(); + DlgReturn(TRUE); + } + + case IDM_CONFIG: + { + OPENOPTIONSDIALOG opd = {0}; + opd.cbSize = sizeof(OPENOPTIONSDIALOG); + opd.pszPage = LPGEN("History"); + CallService(MS_OPT_OPENOPTIONS, 0, (LPARAM)&opd); + DlgReturn(TRUE); + } + + case IDM_DELETE: + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + historyWindow->Delete(0); + DlgReturn(TRUE); + } + + case IDC_FIND_TEXT: + if(HIWORD(wParam) == EN_CHANGE) + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + historyWindow->searcher.ClearFind(); + } + + DlgReturn(TRUE); + + case IDC_SHOWHIDE: + { + if(HIWORD( wParam ) == BN_CLICKED) + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + if(Button_GetCheck(GetDlgItem(hwndDlg,IDC_SHOWHIDE)) & BST_CHECKED) + { + SendDlgItemMessage( hwndDlg, IDC_SHOWHIDE, BM_SETIMAGE, IMAGE_ICON, (LPARAM)historyWindow->minusIco); + SendDlgItemMessage( hwndDlg, IDC_SHOWHIDE, BUTTONADDTOOLTIP, (WPARAM)LPGENT("Hide Contacts"), BATF_TCHAR); + historyWindow->isContactList = true; + ShowWindow(GetDlgItem(hwndDlg,IDC_LIST_CONTACTS), SW_SHOW); + ShowWindow(historyWindow->splitterYhWnd, SW_SHOW); + } + else + { + SendDlgItemMessage( hwndDlg, IDC_SHOWHIDE, BM_SETIMAGE, IMAGE_ICON, (LPARAM)historyWindow->plusIco); + SendDlgItemMessage( hwndDlg, IDC_SHOWHIDE, BUTTONADDTOOLTIP, (WPARAM)LPGENT("Show Contacts"), BATF_TCHAR); + historyWindow->isContactList = false; + ShowWindow(GetDlgItem(hwndDlg,IDC_LIST_CONTACTS), SW_HIDE); + ShowWindow(historyWindow->splitterYhWnd, SW_HIDE); + } + + SendMessage(hwndDlg, WM_SIZE, 0, 0); + } + + DlgReturn(TRUE); + } + } + break; + case WM_NOTIFY: + { + LPNMHDR pNmhdr; + + pNmhdr = (LPNMHDR)lParam; + switch(pNmhdr->idFrom) + { + case IDC_LIST_CONTACTS: + if(pNmhdr->code == CLN_LISTREBUILT)// || pNmhdr->code == CLN_CONTACTMOVED || pNmhdr->code == CLN_NEWCONTACT) + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + if(historyWindow != NULL) + { + historyWindow->ReloadContacts(); + } + + DlgReturn(TRUE); + } + else if(pNmhdr->code == CLN_MYSELCHANGED) + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + if(historyWindow->ContactChanged()) + { + MSGFILTER* msgFilter = (MSGFILTER *) lParam; + if(msgFilter->msg == WM_LBUTTONDOWN) + { + SendMessage(pNmhdr->hwndFrom, WM_LBUTTONUP, msgFilter->wParam, msgFilter->lParam); + } + } + + DlgReturn(TRUE); + } + else if(pNmhdr->code == CLN_OPTIONSCHANGED) + { + ResetCList(hwndDlg); + return FALSE; + } + + //fall through + //case IDC_LIST_CONTACTS: + case IDC_SHOWHIDE: + case IDC_FIND_TEXT: + case IDC_EDIT: + if ( pNmhdr->code == EN_LINK ) + { + ClickLink(GetDlgItem(hwndDlg, IDC_EDIT), (ENLINK *) lParam); + return FALSE; + } + else if( pNmhdr->code == EN_SELCHANGE) + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + historyWindow->searcher.ClearFind(); + } + else if(pNmhdr->code == EN_MSGFILTER) + { + MSGFILTER* msgFilter = (MSGFILTER *) lParam; + if (msgFilter->msg == WM_KEYDOWN || msgFilter->msg == WM_SYSKEYDOWN) + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + if(historyWindow->DoHotkey(msgFilter->msg, msgFilter->lParam, msgFilter->wParam, pNmhdr->idFrom)) + DlgReturn(TRUE); + } + else if (msgFilter->msg == WM_RBUTTONDOWN || msgFilter->msg == WM_RBUTTONDBLCLK || msgFilter->msg == WM_NCRBUTTONUP || msgFilter->msg == WM_NCRBUTTONDBLCLK || msgFilter->msg == WM_NCRBUTTONDOWN) + { + DlgReturn(TRUE); + } + else if (msgFilter->msg == WM_RBUTTONUP) + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + POINT clicked; + LPNMITEMACTIVATE nmlv = (LPNMITEMACTIVATE)lParam; + HWND window = historyWindow->editWindow; + POINTL p; + POINT scrool; + LVHITTESTINFO info = {0}; + p.x = clicked.x = info.pt.x = GET_X_LPARAM(msgFilter->lParam); + p.y = clicked.y = info.pt.y = GET_Y_LPARAM(msgFilter->lParam); + ClientToScreen(window, &clicked); + SetFocus(window); + int selChar = SendMessage(window, EM_CHARFROMPOS, 0, (LPARAM)&p); + CHARRANGE chrg; + SendMessage(window,EM_EXGETSEL,0,(LPARAM)&chrg); + SendMessage(window,EM_GETSCROLLPOS,0,(LPARAM)&scrool); + if(selChar < chrg.cpMin || selChar > chrg.cpMax) + { + chrg.cpMin = chrg.cpMax = selChar; + } + + if(chrg.cpMin == chrg.cpMax) + { + CHARRANGE chrgNew; + chrgNew.cpMin = chrg.cpMin; + chrgNew.cpMax = chrg.cpMax + 1; + SendMessage(window,EM_EXSETSEL,0,(LPARAM)&chrgNew); + } + CHARFORMAT2 chf; + memset(&chf, 0, sizeof(CHARFORMAT2)); + chf.cbSize = sizeof(CHARFORMAT2); + chf.dwMask = CFM_LINK; + SendMessage(window, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&chf); + if(chrg.cpMin == chrg.cpMax) + SendMessage(window,EM_EXSETSEL,0,(LPARAM)&chrg); + + HMENU hPopupMenu = CreatePopupMenu(); + if(hPopupMenu != NULL) + { + if(chf.dwEffects & CFE_LINK) + { + AppendMenu(hPopupMenu, MF_STRING, IDM_OPENNEW, TranslateT("Open in &new window")); + AppendMenu(hPopupMenu, MF_STRING, IDM_OPENEXISTING, TranslateT("&Open in existing window")); + AppendMenu(hPopupMenu, MF_STRING, IDM_COPYLINK, TranslateT("&Copy link")); + } + else + { + AppendMenu(hPopupMenu, MF_STRING, IDM_COPY, TranslateT("Copy")); + AppendMenu(hPopupMenu, MF_STRING, IDM_DELETE, TranslateT("Delete")); + AppendMenu(hPopupMenu, MFT_SEPARATOR, 0, NULL); + AppendMenu(hPopupMenu, MF_STRING, IDM_MESSAGE, TranslateT("Send Message")); + AppendMenu(hPopupMenu, MF_STRING, IDM_QUOTE, TranslateT("Reply &Quoted")); + AppendMenu(hPopupMenu, MF_STRING, IDM_DELETEGROUP, TranslateT("Delete Group")); + AppendMenu(hPopupMenu, MF_STRING, IDM_DELETEUSER, TranslateT("Delete All User History")); + } + + int selected = TrackPopupMenu(hPopupMenu, TPM_RETURNCMD, clicked.x, clicked.y, 0, hwndDlg, 0); + switch (selected) + { + case IDM_COPY: + { + if(chrg.cpMax == chrg.cpMin && historyWindow->currentGroup.size() > 0) + { + size_t start = 0; + while(start < historyWindow->currentGroup.size() && chrg.cpMin >= historyWindow->currentGroup[start].endPos) ++start; + if(start < historyWindow->currentGroup.size()) + { + CHARRANGE chrgNew; + chrgNew.cpMin = 0; + if(start > 0) + chrgNew.cpMin = historyWindow->currentGroup[start - 1].endPos; + chrgNew.cpMax = historyWindow->currentGroup[start].endPos; + SendMessage(window,EM_EXSETSEL,0,(LPARAM)&chrgNew); + SendMessage(window,WM_COPY,0,0); + SendMessage(window,EM_EXSETSEL,0,(LPARAM)&chrg); + } + } + else + { + SendMessage(window,WM_COPY,0,0); + } + } + break; + case IDM_MESSAGE: + //CallService(MS_MSG_SENDMESSAGE, (WPARAM)historyWindow->hContact, 0); + CallFunctionAsync(ShowMessageWindow, new ShowMessageData(historyWindow->hContact)); + break; + case IDM_QUOTE: + { + if(historyWindow->currentGroup.size() > 0) + { + std::wstring quote; + if(chrg.cpMax == chrg.cpMin) + { + size_t start = 0; + while(start < historyWindow->currentGroup.size() && chrg.cpMin >= historyWindow->currentGroup[start].endPos) ++start; + if(start < historyWindow->currentGroup.size()) + { + historyWindow->FormatQuote(quote, historyWindow->currentGroup[start], historyWindow->currentGroup[start].description); + } + } + else + { + size_t start = 0; + while(start < historyWindow->currentGroup.size() && chrg.cpMin >= historyWindow->currentGroup[start].endPos) ++start; + size_t end = 0; + while(end < historyWindow->currentGroup.size() && chrg.cpMax > historyWindow->currentGroup[end].endPos) ++end; + if(end >= historyWindow->currentGroup.size()) + end = historyWindow->currentGroup.size() - 1; + if(start == end && start < historyWindow->currentGroup.size()) + { + int iStart = historyWindow->currentGroup[start].startPos; + if(chrg.cpMin > iStart) + iStart = chrg.cpMin; + int iEnd = historyWindow->currentGroup[start].endPos; + if(chrg.cpMax < iEnd) + iEnd = chrg.cpMax; + if(iEnd > iStart) + { + TEXTRANGE tr; + tr.chrg.cpMin = iStart; + tr.chrg.cpMax = iEnd; + tr.lpstrText = new TCHAR[iEnd - iStart + 1]; + SendMessage(historyWindow->editWindow, EM_GETTEXTRANGE, 0, (LPARAM) & tr); + historyWindow->FormatQuote(quote, historyWindow->currentGroup[start], tr.lpstrText); + delete [] tr.lpstrText; + } + } + else + { + while(start <= end) + { + historyWindow->FormatQuote(quote, historyWindow->currentGroup[start], historyWindow->currentGroup[start].description); + ++start; + } + } + } + + if(!quote.empty()) + { + CallFunctionAsync(ShowMessageWindow, new ShowMessageData(historyWindow->hContact, quote)); + } + } + } + break; + case IDM_DELETE: + historyWindow->Delete(0); + break; + case IDM_DELETEGROUP: + historyWindow->Delete(1); + break; + case IDM_DELETEUSER: + historyWindow->Delete(2); + break; + case IDM_OPENNEW: + case IDM_OPENEXISTING: + case IDM_COPYLINK: + { + int start = chrg.cpMin, end = chrg.cpMin; + CHARRANGE chrgNew; + chrgNew.cpMin = start-1; + chrgNew.cpMax = start; + do + { + memset(&chf, 0, sizeof(CHARFORMAT2)); + chf.cbSize = sizeof(CHARFORMAT2); + chf.dwMask = CFM_LINK; + int sel = SendMessage(window,EM_EXSETSEL,0,(LPARAM)&chrgNew); + if(sel != chrgNew.cpMax) + break; + SendMessage(window, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&chf); + --chrgNew.cpMin; + --chrgNew.cpMax; + --start; + } while(start >= 0 && chf.dwEffects & CFE_LINK); + + ++start; + chrgNew.cpMin = end; + chrgNew.cpMax = end + 1; + do + { + memset(&chf, 0, sizeof(CHARFORMAT2)); + chf.cbSize = sizeof(CHARFORMAT2); + chf.dwMask = CFM_LINK; + int sel = SendMessage(window,EM_EXSETSEL,0,(LPARAM)&chrgNew); + if(sel != chrgNew.cpMax) + break; + SendMessage(window, EM_GETCHARFORMAT, SCF_SELECTION, (LPARAM)&chf); + ++chrgNew.cpMin; + ++chrgNew.cpMax; + ++end; + } while(chf.dwEffects & CFE_LINK); + + --end; + if(selected == IDM_COPYLINK) + { + chrgNew.cpMin = start; + chrgNew.cpMax = end; + SendMessage(window,EM_EXSETSEL,0,(LPARAM)&chrgNew); + SendMessage(window,WM_COPY,0,0); + SendMessage(window,EM_EXSETSEL,0,(LPARAM)&chrg); + } + else + { + ENLINK link; + link.chrg.cpMin = start; + link.chrg.cpMax = end; + link.msg = WM_LBUTTONUP; + link.nmhdr.code = selected; + SendMessage(window,EM_EXSETSEL,0,(LPARAM)&chrg); + ClickLink(window, &link); + } + } + break; + } + + DestroyMenu(hPopupMenu); + } + SendMessage(window,EM_SETSCROLLPOS,0,(LPARAM)&scrool); + DlgReturn(TRUE); + } + } + break; + case IDC_LIST: + if( pNmhdr->code == LVN_ITEMCHANGED) + { + NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam; + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + if((nmlv->uChanged & LVIF_STATE) && (nmlv->uNewState & LVIS_SELECTED) && historyWindow->selected != nmlv->iItem && nmlv->iItem >= 0) + { + historyWindow->SelectEventGroup(nmlv->iItem); + DlgReturn(TRUE); + } + } + else if( pNmhdr->code == LVN_KEYDOWN) + { + LPNMLVKEYDOWN nmlv = (LPNMLVKEYDOWN)lParam; + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + if(historyWindow->DoHotkey(WM_KEYDOWN, 0, nmlv->wVKey, IDC_LIST)) + DlgReturn(TRUE); + } + else if(pNmhdr->code == NM_RCLICK) + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + POINT clicked; + LPNMITEMACTIVATE nmlv = (LPNMITEMACTIVATE)lParam; + HWND window = historyWindow->listWindow; + LVHITTESTINFO info = {0}; + clicked.x = info.pt.x = nmlv->ptAction.x; + clicked.y = info.pt.y = nmlv->ptAction.y; + ClientToScreen(window, &clicked); + int newSel = SendMessage(window, LVM_SUBITEMHITTEST, 0, (LPARAM)&info); + int curSel = historyWindow->selected; + + if(newSel >= 0) + { + HMENU hPopupMenu = CreatePopupMenu(); + if(hPopupMenu != NULL) + { + AppendMenu(hPopupMenu, MF_STRING, IDM_COPY, TranslateT("Copy")); + AppendMenu(hPopupMenu, MF_STRING, IDM_DELETEGROUP, TranslateT("Delete Group")); + AppendMenu(hPopupMenu, MFT_SEPARATOR, 0, NULL); + AppendMenu(hPopupMenu, MF_STRING, IDM_MESSAGE, TranslateT("Send Message")); + AppendMenu(hPopupMenu, MF_STRING, IDM_DELETEUSER, TranslateT("Delete All User History")); + + int selected = TrackPopupMenu(hPopupMenu, TPM_RETURNCMD, clicked.x, clicked.y, 0, hwndDlg, 0); + switch (selected) + { + case IDM_COPY: + { + CHARRANGE chrg; + SendMessage(historyWindow->editWindow,EM_EXGETSEL,0,(LPARAM)&chrg); + CHARRANGE chrgNew; + chrgNew.cpMin = 0; + chrgNew.cpMax = -1; + SendMessage(historyWindow->editWindow,EM_EXSETSEL,0,(LPARAM)&chrgNew); + SendMessage(historyWindow->editWindow,WM_COPY,0,0); + SendMessage(historyWindow->editWindow,EM_EXSETSEL,0,(LPARAM)&chrg); + } + break; + case IDM_MESSAGE: + CallService(MS_MSG_SENDMESSAGE, (WPARAM)historyWindow->hContact, 0); + break; + case IDM_DELETEGROUP: + historyWindow->Delete(1); + break; + case IDM_DELETEUSER: + historyWindow->Delete(2); + break; + } + + DestroyMenu(hPopupMenu); + } + } + + DlgReturn(TRUE); + } + + break; + case IDC_TOOLBAR: + if( pNmhdr->code == TBN_DROPDOWN) + { + LPNMTOOLBAR lpnmTB= (LPNMTOOLBAR)lParam; + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + if(lpnmTB->iItem == IDM_FIND) + { + historyWindow->FindToolbarClicked(lpnmTB); + } + else if(lpnmTB->iItem == IDM_CONFIG) + { + historyWindow->ConfigToolbarClicked(lpnmTB); + } + else if(lpnmTB->iItem == IDM_DELETE) + { + historyWindow->DeleteToolbarClicked(lpnmTB); + } + + DlgReturn(TBDDRET_DEFAULT); + } + else if( pNmhdr->code == NM_KEYDOWN) + { + LPNMKEY nmlv = (LPNMKEY)lParam; + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + if(historyWindow->DoHotkey(WM_KEYDOWN, 0, nmlv->nVKey, IDC_TOOLBAR)) + DlgReturn(TRUE); + } + break; + } + break; + } + case WM_CTLCOLORDLG: + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + DlgReturn((LONG_PTR)historyWindow->bkBrush); + } + case WM_CTLCOLORSTATIC: + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + HWND curhWnd = (HWND)lParam; + if(historyWindow->splitterXhWnd == curhWnd || historyWindow->splitterYhWnd == curhWnd) + { + DlgReturn((LONG_PTR)historyWindow->bkBrush); + } + + break; + } + case WM_CTLCOLOREDIT: + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + HWND curhWnd = (HWND)lParam; + if(historyWindow->findWindow == curhWnd) + { + HDC edithdc = (HDC)wParam; + LOGFONT font; + SetTextColor(edithdc, Options::instance->GetFont(Options::Find, &font)); + SetBkColor(edithdc, Options::instance->GetColor(Options::FindBackground)); + DlgReturn((LONG_PTR)historyWindow->bkFindBrush); + } + + break; + } + case DM_SPLITTERMOVED: + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + historyWindow->SplitterMoved((HWND)lParam, wParam, true); + break; + } + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + HistoryWindow* historyWindow = (HistoryWindow*)lParam; + historyWindow->hWnd = hwndDlg; + historyWindow->isWnd = true; + SetWindowLongPtr(hwndDlg,GWLP_USERDATA,(LONG_PTR)lParam); + historyWindow->Initialise(); + } + DlgReturn(TRUE); + + case DM_HREBUILD: + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + if(!historyWindow->isLoading) + { + historyWindow->isLoading = true; + historyWindow->ReloadContacts(); + mir_forkthread(HistoryWindow::FillHistoryThread, historyWindow); + } + } + DlgReturn(TRUE); + + case WM_DESTROY: + { + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwndDlg,GWLP_USERDATA); + historyWindow->Destroy(); + } + DlgReturn(TRUE); + } + return FALSE; +} + +void HistoryWindow::Initialise() +{ + splitterXhWnd = GetDlgItem(hWnd, IDC_SPLITTER); + splitterYhWnd = GetDlgItem(hWnd, IDC_SPLITTERV); + OldSplitterProc = (WNDPROC)SetWindowLongPtr(splitterXhWnd, GWLP_WNDPROC, (LONG_PTR) SplitterSubclassProc); + SetWindowLongPtr(splitterYhWnd, GWLP_WNDPROC, (LONG_PTR) SplitterSubclassProc); + + editWindow = GetDlgItem(hWnd, IDC_EDIT); + findWindow = GetDlgItem(hWnd, IDC_FIND_TEXT); + toolbarWindow = GetDlgItem(hWnd, IDC_TOOLBAR); + listWindow = GetDlgItem(hWnd, IDC_LIST); + + RECT rc; + POINT pt; + GetWindowRect(splitterXhWnd, &rc); + pt.y = (rc.top + rc.bottom) / 2; + pt.x = 0; + ScreenToClient(hWnd, &pt); + splitterOrgY = pt.y; + splitterY = pt.y; + GetWindowRect(splitterYhWnd, &rc); + pt.y = 0; + pt.x = (rc.left + rc.right) / 2; + ScreenToClient(hWnd, &pt); + splitterOrgX = pt.x; + splitterX = pt.x; + GetWindowRect(GetDlgItem(hWnd, IDC_LIST_CONTACTS), &rc); + pt.y = rc.top; + pt.x = rc.left; + ScreenToClient(hWnd, &pt); + listOryginalPos = pt.x; + + plusIco = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 1, (LPARAM)hPlusIcon); + minusIco = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 1, (LPARAM)hMinusIcon); + SendDlgItemMessage( hWnd, IDC_SHOWHIDE, BUTTONSETASPUSHBTN, TRUE, 0 ); + SendDlgItemMessage( hWnd, IDC_SHOWHIDE, BUTTONSETASFLATBTN, TRUE, 0 ); + if(hContact == NULL || Options::instance->showContacts) + { + SendDlgItemMessage( hWnd, IDC_SHOWHIDE, BM_SETIMAGE, IMAGE_ICON, (LPARAM)minusIco); + SendDlgItemMessage( hWnd, IDC_SHOWHIDE, BUTTONADDTOOLTIP, (WPARAM)LPGENT("Hide Contacts"), BATF_TCHAR); + Button_SetCheck(GetDlgItem(hWnd,IDC_SHOWHIDE), BST_CHECKED); + isContactList = true; + } + else + { + SendDlgItemMessage( hWnd, IDC_SHOWHIDE, BM_SETIMAGE, IMAGE_ICON, (LPARAM)plusIco); + SendDlgItemMessage( hWnd, IDC_SHOWHIDE, BUTTONADDTOOLTIP, (WPARAM)LPGENT("Show Contacts"), BATF_TCHAR); + Button_SetCheck(GetDlgItem(hWnd,IDC_SHOWHIDE), BST_UNCHECKED); + ShowWindow(GetDlgItem(hWnd,IDC_LIST_CONTACTS), SW_HIDE); + ShowWindow(splitterYhWnd, SW_HIDE); + isContactList = false; + } + RegisterHotkeyControl(GetDlgItem(hWnd, IDC_SHOWHIDE)); + RegisterHotkeyControl(GetDlgItem(hWnd, IDC_LIST_CONTACTS)); + + ResetCList(hWnd); + + RestorePos(); + SendMessage(hWnd, WM_SETICON, ICON_BIG, ( LPARAM )LoadSkinnedIconBig( SKINICON_OTHER_HISTORY )); + SendMessage(hWnd, WM_SETICON, ICON_SMALL, ( LPARAM )LoadSkinnedIcon( SKINICON_OTHER_HISTORY )); + SendMessage(editWindow,EM_AUTOURLDETECT,TRUE,0); + SendMessage(editWindow,EM_SETEVENTMASK,0,ENM_LINK | ENM_SELCHANGE | ENM_KEYEVENTS | ENM_MOUSEEVENTS); + SendMessage(editWindow,EM_SETEDITSTYLE,SES_EXTENDBACKCOLOR,SES_EXTENDBACKCOLOR); + + himlSmall = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 2, 2); + himlNone = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 2, 2); + ImageList_SetIconSize(himlNone, 0, 16); + if(himlSmall) + { + allIconNumber = iconsNum + 3; + eventIcoms = new HICON[allIconNumber]; + for(int i = 0; i < iconsNum; ++i) + { + eventIcoms[i] = hEventIcons[i] == NULL ? NULL : (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)hEventIcons[i]); + ImageList_AddIcon(himlSmall, eventIcoms[i]); + } + + int id = iconsNum; + eventIcoms[id] = LoadSkinnedIcon(SKINICON_EVENT_FILE); + ImageList_AddIcon(himlSmall, eventIcoms[id]); + + eventIcoms[++id] = LoadSkinnedIcon(SKINICON_EVENT_URL); + ImageList_AddIcon(himlSmall, eventIcoms[id]); + + eventIcoms[++id] = LoadSkinnedIcon(SKINICON_OTHER_WINDOWS); + ImageList_AddIcon(himlSmall, eventIcoms[id]); + + if((isGroupImages = Options::instance->groupShowEvents) != false) + ListView_SetImageList(listWindow, himlSmall, LVSIL_SMALL); + } + + bkBrush = CreateSolidBrush(Options::instance->GetColor(Options::WindowBackground)); + bkFindBrush = CreateSolidBrush(Options::instance->GetColor(Options::FindBackground)); + + LVCOLUMN col = {0}; + col.mask = LVCF_WIDTH | LVCF_TEXT; + col.cx = 470; + col.pszText = _T(""); + ListView_InsertColumn(listWindow, 0, &col); + ListView_SetColumnWidth(listWindow, 0, LVSCW_AUTOSIZE_USEHEADER); + ListView_SetExtendedListViewStyleEx(listWindow, LVS_EX_FULLROWSELECT, LVS_EX_FULLROWSELECT); + COLORREF bkColor = Options::instance->GetColor(Options::GroupListBackground); + ListView_SetBkColor(listWindow, bkColor); + ListView_SetTextBkColor(listWindow, bkColor); + LOGFONT font; + ListView_SetTextColor(listWindow, Options::instance->GetFont(Options::GroupList, &font)); + + Edit_LimitText(findWindow, 100); + RegisterHotkeyControl(findWindow); + + HIMAGELIST himlButtons = ImageList_Create(16, 16, ILC_COLOR32 | ILC_MASK, 3, 3); + if(himlButtons) + { + findNextIco = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)hFindNextIcon); + ImageList_AddIcon(himlButtons, findNextIco); + findPrevIco = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)hFindPrevIcon); + ImageList_AddIcon(himlButtons, findPrevIco); + configIco = LoadSkinnedIcon(SKINICON_OTHER_OPTIONS); + ImageList_AddIcon(himlButtons, configIco); + deleteIco = LoadSkinnedIcon(SKINICON_OTHER_DELETE); + ImageList_AddIcon(himlButtons, deleteIco); + + // Set the image list. + SendMessage(toolbarWindow, TB_SETIMAGELIST, (WPARAM)0, (LPARAM)himlButtons); + + // Load the button images. + SendMessage(toolbarWindow, TB_LOADIMAGES, (WPARAM)IDB_STD_SMALL_COLOR, (LPARAM)HINST_COMMCTRL); + } + + TBBUTTON tbButtons[] = + { + { 0, IDM_FIND, TBSTATE_ENABLED, BTNS_DROPDOWN, {0}, 0, (INT_PTR)TranslateT("Find Next") }, + { 3, IDM_DELETE, TBSTATE_ENABLED, BTNS_DROPDOWN, {0}, 0, (INT_PTR)TranslateT("Delete")}, + { 2, IDM_CONFIG, TBSTATE_ENABLED, BTNS_DROPDOWN, {0}, 0, (INT_PTR)TranslateT("Options")}, + }; + SendMessage(toolbarWindow, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0); + SendMessage(toolbarWindow, TB_ADDBUTTONS, (WPARAM)SIZEOF(tbButtons), (LPARAM)&tbButtons); + SendMessage(toolbarWindow, TB_SETBUTTONSIZE, 0, MAKELPARAM(16, 16)); + SendMessage(toolbarWindow, TB_SETEXTENDEDSTYLE, 0, TBSTYLE_EX_DRAWDDARROWS); + SendMessage(toolbarWindow, TB_SETMAXTEXTROWS, 0, 0); + + SetDefFilter(Options::instance->defFilter); + + SendMessage(hWnd, DM_SETDEFID, IDM_FIND, 0); + SendMessage(hWnd, WM_SIZE, 0, 0); + SendMessage(hWnd,DM_HREBUILD,0,0); + isDestroyed = false; +} + +void HistoryWindow::Destroy() +{ + HICON hIcon = (HICON)SendMessage(hWnd, WM_SETICON, ICON_BIG, 0); + CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); + + hIcon = (HICON)SendMessage(hWnd, WM_SETICON, ICON_SMALL, 0); + CallService(MS_SKIN2_RELEASEICON, (WPARAM)hIcon, 0); + + UnregisterHotkeyControl(GetDlgItem(hWnd, IDC_SHOWHIDE)); + UnregisterHotkeyControl(GetDlgItem(hWnd, IDC_LIST_CONTACTS)); + UnregisterHotkeyControl(findWindow); + + isDestroyed = true; + HistoryWindow::Close(this); +} + +void HistoryWindow::SplitterMoved(HWND splitter, LONG pos, bool screenPos) +{ + POINT pt; + RECT rc1; + RECT rc2; + POINT pt1; + POINT pt2; + + if(splitter == splitterXhWnd) + { + GetWindowRect(listWindow, &rc1); + GetWindowRect(editWindow, &rc2); + pt.x = 0; + pt.y = pos; + pt1.x = rc1.left; + pt1.y = rc1.top; + pt2.x = rc2.right; + pt2.y = rc2.bottom; + if(screenPos) + ScreenToClient(hWnd, &pt); + ScreenToClient(hWnd, &pt1); + ScreenToClient(hWnd, &pt2); + if ((pt.y >= pt1.y + MIN_PANELHEIGHT) && (pt.y < pt2.y - MIN_PANELHEIGHT)) + { + splitterY = pt.y; + if(!screenPos) + SendMessage(hWnd, WM_SIZE, 0, 0); + //if(M->isAero()) + // InvalidateRect(GetParent(hwndDlg), NULL, FALSE); + } + } + else + { + GetWindowRect(GetDlgItem(hWnd, IDC_LIST_CONTACTS), &rc1); + GetWindowRect(listWindow, &rc2); + pt.x = pos; + pt.y = 0; + pt1.x = rc1.left; + pt1.y = rc1.top; + pt2.x = rc2.right; + pt2.y = rc2.bottom; + if(screenPos) + ScreenToClient(hWnd, &pt); + ScreenToClient(hWnd, &pt1); + ScreenToClient(hWnd, &pt2); + if ((pt.x >= pt1.x + MIN_PANELHEIGHT) && (pt.x < pt2.x - MIN_PANELHEIGHT)) + { + splitterX = pt.x; + if(!screenPos) + SendMessage(hWnd, WM_SIZE, 0, 0); + //if(M->isAero()) + // InvalidateRect(GetParent(hwndDlg), NULL, FALSE); + } + } +} + +int HistoryWindow::HistoryDlgResizer(HWND hwnd, LPARAM, UTILRESIZECONTROL *urc) +{ + HistoryWindow* historyWindow =(HistoryWindow*)GetWindowLongPtr(hwnd,GWLP_USERDATA); + switch(urc->wId) { + case IDC_LIST: + { + urc->rcItem.bottom += historyWindow->splitterY - historyWindow->splitterOrgY; + urc->rcItem.left += historyWindow->splitterX - historyWindow->splitterOrgX; + if(!historyWindow->isContactList) + urc->rcItem.left = historyWindow->listOryginalPos; + return RD_ANCHORX_WIDTH|RD_ANCHORY_TOP; + } + case IDC_LIST_CONTACTS: + { + urc->rcItem.right += historyWindow->splitterX - historyWindow->splitterOrgX; + return RD_ANCHORX_LEFT|RD_ANCHORY_HEIGHT; + } + case IDC_SPLITTER: + { + urc->rcItem.top += historyWindow->splitterY - historyWindow->splitterOrgY; + urc->rcItem.bottom += historyWindow->splitterY - historyWindow->splitterOrgY; + urc->rcItem.left += historyWindow->splitterX - historyWindow->splitterOrgX; + if(!historyWindow->isContactList) + urc->rcItem.left = 0; + return RD_ANCHORX_WIDTH|RD_ANCHORY_TOP; + } + case IDC_SPLITTERV: + { + urc->rcItem.left += historyWindow->splitterX - historyWindow->splitterOrgX; + urc->rcItem.right += historyWindow->splitterX - historyWindow->splitterOrgX; + return RD_ANCHORX_LEFT|RD_ANCHORY_HEIGHT; + } + case IDC_EDIT: + { + urc->rcItem.top += historyWindow->splitterY - historyWindow->splitterOrgY; + urc->rcItem.left += historyWindow->splitterX - historyWindow->splitterOrgX; + if(!historyWindow->isContactList) + urc->rcItem.left = historyWindow->listOryginalPos; + return RD_ANCHORX_WIDTH|RD_ANCHORY_HEIGHT; + } + case IDC_FIND_TEXT: + return RD_ANCHORX_WIDTH|RD_ANCHORY_TOP; + case IDC_SHOWHIDE: + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; + case IDC_TOOLBAR: + return RD_ANCHORX_RIGHT|RD_ANCHORY_TOP; + } + return RD_ANCHORX_LEFT|RD_ANCHORY_TOP; +} + +void HistoryWindow::FillHistoryThread(void* param) +{ + HistoryWindow *hInfo = ( HistoryWindow* )param; + HWND hwndList = hInfo->listWindow; + ListView_DeleteAllItems(hwndList); + hInfo->SelectEventGroup(-1); + hInfo->EnableWindows(FALSE); + bool isNewOnTop = Options::instance->groupNewOnTop; + + hInfo->RefreshEventList(); + + LVITEM item = {0}; + item.mask = LVIF_STATE; + item.iItem = 0; + item.state = LVIS_SELECTED; + item.stateMask = LVIS_SELECTED; + if(!isNewOnTop) + { + item.iItem = ListView_GetItemCount(hwndList) - 1; + if(item.iItem < 0) + item.iItem = 0; + } + + ListView_SetItem(hwndList, &item); + ListView_SetColumnWidth(hwndList, 0, LVSCW_AUTOSIZE_USEHEADER); + ListView_EnsureVisible(hwndList, item.iItem, FALSE); + hInfo->EnableWindows(TRUE); + SetFocus(hwndList); +} + +void HistoryWindow::AddGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText, int ico) +{ + TCHAR msg[256]; + msg[0] = 0; + if(Options::instance->groupShowTime) + { + _tcscpy_s(msg, time.c_str()); + } + if(Options::instance->groupShowName) + { + if(msg[0] != 0) + _tcscat_s(msg, _T(" ")); + _tcscat_s(msg, user.c_str()); + } + + if(Options::instance->groupShowMessage) + { + if(msg[0] != 0) + _tcscat_s(msg, _T(" ")); + _tcscat_s(msg, eventText.c_str()); + } + + LVITEM item = {0}; + item.mask = LVIF_TEXT | LVIF_IMAGE; + item.iItem = MAXINT; + item.pszText = msg; + item.iImage = ico; + ListView_InsertItem(listWindow, &item); +} + +void HistoryWindow::ReplaceIcons(HWND hwndDlg, int selStart, BOOL isSent) +{ + if(g_SmileyAddAvail) + { + CHARRANGE sel; + SMADD_RICHEDIT3 smadd = {0}; + + sel.cpMin = selStart; + sel.cpMax = -1; + + smadd.cbSize = sizeof(smadd); + smadd.hwndRichEditControl = hwndDlg; + smadd.Protocolname = (char *)CallService(MS_PROTO_GETCONTACTBASEPROTO, (WPARAM)hContact, 0); + smadd.hContact = hContact; + smadd.flags = isSent ? SAFLRE_OUTGOING : 0; + if (selStart > 0) + smadd.rangeToReplace = &sel; + CallService(MS_SMILEYADD_REPLACESMILEYS, 0, (LPARAM)&smadd); + } +} + +void SetFontFromOptions(ITextFont *TextFont, int caps, Options::Fonts fontId) +{ + COLORREF fontColor; + LOGFONT font; + fontColor = Options::instance->GetFont(fontId, &font); + BSTR bstrFont = SysAllocString(font.lfFaceName); + TextFont->SetName(bstrFont); + SysFreeString(bstrFont); + TextFont->SetForeColor(fontColor); + TextFont->SetWeight(font.lfWeight); + font.lfHeight = (font.lfHeight * 72) / caps; + TextFont->SetSize(font.lfHeight < 0 ? -font.lfHeight : font.lfHeight); + TextFont->SetItalic(font.lfItalic ? tomTrue : tomFalse); + TextFont->SetItalic(font.lfUnderline ? tomTrue : tomFalse); + TextFont->SetItalic(font.lfStrikeOut ? tomTrue : tomFalse); +} + +void HistoryWindow::SelectEventGroup(int sel) +{ + SendMessage(editWindow, WM_SETTEXT, 0, (LPARAM)_T("")); + currentGroup.clear(); + selected = sel; + if(sel < 0 || sel >= (int)eventList.size()) + return; + + TCHAR _str[MAXSELECTSTR + 8]; // for safety reason + TCHAR *str = _str + sizeof(int)/sizeof(TCHAR); + BSTR pStr = str; + unsigned int *strLen = (unsigned int*)_str; + str[0] = 0; + tm lastTime; + bool isFirst = true; + bool lastMe = false; + long startAt, endAt; + long cnt; + std::wstring strStl; + IRichEditOle* RichEditOle; + EventData data; + if (SendMessage(editWindow, EM_GETOLEINTERFACE, 0, (LPARAM)&RichEditOle) == 0) + return; + ITextDocument* TextDocument; + if (RichEditOle->QueryInterface(IID_ITextDocument, (void**)&TextDocument) != S_OK) + { + RichEditOle->Release(); + return; + } + ITextSelection* TextSelection; + ITextFont *TextFont; + SendMessage(editWindow, EM_SETREADONLY, FALSE, 0); + TextDocument->Freeze(&cnt); + TextDocument->GetSelection(&TextSelection); + HDC hDC = GetDC(NULL); + int caps = GetDeviceCaps(hDC, LOGPIXELSY); + std::deque revDeq; + std::deque& deq = eventList[sel]; + if(Options::instance->messagesNewOnTop) + { + revDeq.insert(revDeq.begin(), deq.rbegin(), deq.rend()); + deq = revDeq; + } + COLORREF backColor = GetSysColor(COLOR_WINDOW); + for(std::deque::iterator it = deq.begin(); it != deq.end(); ++it) + { + EventIndex hDbEvent = *it; + if(GetEventData(hDbEvent, data)) + { + bool isUser = Options::instance->messagesShowName && (isFirst || (!lastMe && data.isMe) || (lastMe && !data.isMe)); + lastMe = data.isMe; + backColor = Options::instance->GetColor(lastMe ? Options::OutBackground : Options::InBackground); + if(Options::instance->messagesShowEvents) + { + str[0] = _T('>'); + str[1] = 0; + *strLen = 1 * sizeof(TCHAR); + TextSelection->SetStart(MAXLONG); + TextSelection->GetFont(&TextFont); + TextFont->SetBackColor(backColor); + TextSelection->SetText(pStr); + TextFont->Release(); + int imId; + HICON ico; + if(GetEventIcon(lastMe, data.eventType, imId)) + { + ico = eventIcoms[imId]; + } + else + { + ico = GetEventCoreIcon(hDbEvent); + if(ico == NULL) + { + ico = eventIcoms[imId]; + } + } + + ImageDataObject::InsertIcon(RichEditOle, ico, backColor, 16, 16); + } + + TCHAR* formatDate = Options::instance->messagesShowSec ? (isUser ? _T("d s ") : _T("d s\n")) : (isUser ? _T("d t ") : _T("d t\n")); + if(!Options::instance->messagesShowDate) + { + if(isFirst) + { + isFirst = false; + formatDate = Options::instance->messagesShowSec ? (isUser ? _T("s ") : _T("s\n")) : (isUser ? _T("t ") : _T("t\n")); + time_t tt = data.timestamp; + localtime_s(&lastTime, &tt); + } + else + { + time_t tt = data.timestamp; + tm t; + localtime_s(&t, &tt); + if(lastTime.tm_yday == t.tm_yday && lastTime.tm_year == t.tm_year) + formatDate = Options::instance->messagesShowSec ? (isUser ? _T("s ") : _T("s\n")) : (isUser ? _T("t ") : _T("t\n")); + } + } + + tmi.printTimeStamp(NULL, data.timestamp, formatDate, str , MAXSELECTSTR, 0); + *strLen = (unsigned int)_tcslen(str) * sizeof(TCHAR); + TextSelection->SetStart(MAXLONG); + TextSelection->GetFont(&TextFont); + SetFontFromOptions(TextFont, caps, lastMe ? Options::OutTimestamp : Options::InTimestamp); + TextFont->SetBackColor(backColor); + TextSelection->SetText(pStr); + TextFont->Release(); + + if(isUser) + { + if(lastMe) + mir_sntprintf( str, MAXSELECTSTR, _T("%s\n"), myName ); + else + mir_sntprintf( str, MAXSELECTSTR, _T("%s\n"), contactName ); + *strLen = (unsigned int)_tcslen(str) * sizeof(TCHAR); + TextSelection->SetStart(MAXLONG); + TextSelection->GetFont(&TextFont); + SetFontFromOptions(TextFont, caps, lastMe ? Options::OutName : Options::InName); + TextSelection->SetText(pStr); + TextFont->Release(); + } + + GetEventMessage(hDbEvent, str); + strStl = str; + size_t i = strStl.length(); + if(i + 1 >= MAXSELECTSTR) + continue; + str[i++] = _T('\n'); + str[i] = 0; + *strLen = (unsigned int)i * sizeof(TCHAR); + TextSelection->SetStart(MAXLONG); + TextSelection->GetFont(&TextFont); + SetFontFromOptions(TextFont, caps, lastMe ? Options::OutMessages : Options::InMessages); + TextFont->SetBackColor(backColor); + TextSelection->GetStart(&startAt); + TextSelection->SetText(pStr); + TextFont->Release(); + + if(Options::instance->messagesUseSmileys) + ReplaceIcons(editWindow, startAt, lastMe); + TextSelection->SetStart(MAXLONG); + TextSelection->GetStart(&endAt); + currentGroup.push_back(MessageData(strStl, startAt, endAt, lastMe, data.timestamp)); + } + } + + TextSelection->SetRange(0, 0); + TextSelection->Release(); + TextDocument->Unfreeze(&cnt); + TextDocument->Release(); + RichEditOle->Release(); + SendMessage(editWindow, EM_SETREADONLY, TRUE, 0); + SendMessage(editWindow,EM_SETBKGNDCOLOR,0, backColor); + if (cnt == 0) + { + UpdateWindow(editWindow); + } +} + +LRESULT CALLBACK HistoryWindow::SplitterSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + HWND hwndParent = GetParent(hwnd); + HistoryWindow *dat = (HistoryWindow*)GetWindowLongPtr(hwndParent, GWLP_USERDATA); + if(dat == NULL || dat->isDestroyed) + return FALSE; + + switch (msg) { + case WM_NCHITTEST: + return HTCLIENT; + case WM_SETCURSOR: { + RECT rc; + GetClientRect(hwnd, &rc); + SetCursor(rc.right > rc.bottom ? hCurSplitNS : hCurSplitWE); + return TRUE; + } + case WM_LBUTTONDOWN: { + SetCapture(hwnd); + return 0; + } + case WM_MOUSEMOVE: + if (GetCapture() == hwnd) { + RECT rc; + GetClientRect(hwnd, &rc); + SendMessage(hwndParent, DM_SPLITTERMOVED, rc.right > rc.bottom ? (short) HIWORD(GetMessagePos()) + rc.bottom / 2 : (short) LOWORD(GetMessagePos()) + rc.right / 2, (LPARAM) hwnd); + } + return 0; + case WM_ERASEBKGND: + return(1); + case WM_LBUTTONUP: { + HWND hwndCapture = GetCapture(); + + ReleaseCapture(); + SendMessage(hwndParent, WM_SIZE, 0, 0); + RedrawWindow(hwndParent, NULL, NULL, RDW_ALLCHILDREN | RDW_INVALIDATE | RDW_UPDATENOW); + return 0; + } + } + return CallWindowProc(dat->OldSplitterProc, hwnd, msg, wParam, lParam); +} + +void HistoryWindow::EnableWindows(BOOL enable) +{ + EnableWindow(GetDlgItem(hWnd,IDC_LIST_CONTACTS), enable); + EnableWindow(listWindow, enable); + EnableWindow(findWindow, enable); + EnableWindow(toolbarWindow, enable); + isLoading = !enable; +} + +void HistoryWindow::ReloadContacts() +{ + HWND contactList = GetDlgItem(hWnd,IDC_LIST_CONTACTS); + if(EventList::GetContactMessageNumber(NULL)) + { + if(hSystem == NULL) + { + CLCINFOITEM cii = { 0 }; + cii.cbSize = sizeof(cii); + cii.flags = CLCIIF_GROUPFONT | CLCIIF_BELOWCONTACTS; + cii.pszText = TranslateT("System"); + hSystem = (HANDLE) SendMessage(contactList, CLM_ADDINFOITEM, 0, (LPARAM) & cii); + } + } + else + { + if(hSystem != NULL) + { + SendMessage(contactList, CLM_DELETEITEM, (WPARAM)hSystem, 0); + hSystem = NULL; + } + } + + HANDLE _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while(_hContact) + { + if(EventList::GetContactMessageNumber(_hContact) && (metaContactProto == NULL || DBGetContactSettingByte(_hContact, metaContactProto, "IsSubcontact", 0) == 0)) + { + HANDLE hItem = (HANDLE)SendMessage(contactList, CLM_FINDCONTACT, (WPARAM)_hContact, 0); + if(hItem == NULL) + { + SendMessage(contactList, CLM_ADDCONTACT, (WPARAM)_hContact, 0); + } + } + else + { + HANDLE hItem = (HANDLE)SendMessage(contactList, CLM_FINDCONTACT, (WPARAM)_hContact, 0); + if(hItem != NULL) + { + SendMessage(contactList, CLM_DELETEITEM, (WPARAM)_hContact, 0); + } + } + + _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)_hContact, 0); + } + + if(hContact != NULL) + { + HANDLE hItem = (HANDLE)SendMessage(contactList, CLM_FINDCONTACT, (WPARAM)hContact, 0); + if(hItem != NULL) + { + SendMessage(contactList, CLM_ENSUREVISIBLE, (WPARAM)hItem, 0); + SendMessage(contactList, CLM_SELECTITEM, (WPARAM)hItem, 0); + } + } + else if(hSystem != NULL) + { + SendMessage(contactList, CLM_ENSUREVISIBLE, (WPARAM)hSystem, 0); + SendMessage(contactList, CLM_SELECTITEM, (WPARAM)hSystem, 0); + } +} + +bool HistoryWindow::DoHotkey(UINT msg, LPARAM lParam, WPARAM wParam, int window) +{ + MSG message; + message.hwnd = hWnd; + message.message = msg; + message.lParam = lParam; + message.wParam = wParam; + LRESULT mim_hotkey_check = CallService(MS_HOTKEY_CHECK, (WPARAM)&message, (LPARAM)("History")); + switch(mim_hotkey_check) + { + case HISTORY_HK_FIND: + SetFocus(findWindow); + Edit_SetSel(findWindow, 0, -1); + break; + case HISTORY_HK_FINDNEXT: + searcher.ChangeFindDirection(false); + break; + case HISTORY_HK_FINDPREV: + searcher.ChangeFindDirection(true); + break; + case HISTORY_HK_MATCHCASE: + searcher.SetMatchCase(!searcher.IsMatchCase()); + break; + case HISTORY_HK_MATCHWHOLE: + searcher.SetMatchWholeWords(!searcher.IsMatchWholeWords()); + break; + case HISTORY_HK_SHOWCONTACTS: + Button_SetCheck(GetDlgItem(hWnd, IDC_SHOWHIDE), Button_GetCheck(GetDlgItem(hWnd, IDC_SHOWHIDE)) & BST_CHECKED ? BST_UNCHECKED : BST_CHECKED); + SendMessage(hWnd, WM_COMMAND, MAKELONG(IDC_SHOWHIDE, BN_CLICKED), NULL); + break; + case HISTORY_HK_ONLYIN: + searcher.SetOnlyIn(!searcher.IsOnlyIn()); + break; + case HISTORY_HK_ONLYOUT: + searcher.SetOnlyOut(!searcher.IsOnlyOut()); + break; + case HISTORY_HK_ONLYGROUP: + searcher.SetOnlyGroup(!searcher.IsOnlyGroup()); + break; + case HISTORY_HK_ALLCONTACTS: + searcher.SetAllUsers(!searcher.IsAllUsers()); + break; + case HISTORY_HK_EXRHTML: + { + ExportManager exp(hWnd, hContact, GetFilterNr()); + exp.Export(IExport::RichHtml); + } + break; + case HISTORY_HK_EXPHTML: + { + ExportManager exp(hWnd, hContact, GetFilterNr()); + exp.Export(IExport::PlainHtml); + } + break; + case HISTORY_HK_EXTXT: + { + ExportManager exp(hWnd, hContact, GetFilterNr()); + exp.Export(IExport::Txt); + } + break; + case HISTORY_HK_EXBIN: + { + ExportManager exp(hWnd, hContact, GetFilterNr()); + exp.Export(IExport::Binary); + } + break; + case HISTORY_HK_EXDAT: + { + ExportManager exp(hWnd, hContact, GetFilterNr()); + exp.Export(IExport::Dat); + } + break; + case HISTORY_HK_IMPBIN: + { + DoImport(IImport::Binary); + } + break; + case HISTORY_HK_IMPDAT: + { + DoImport(IImport::Dat); + } + break; + case HISTORY_HK_DELETE: + { + int what = window == IDC_EDIT ? 0 : (window == IDC_LIST ? 1 : (window == IDC_LIST_CONTACTS ? 2 : -1)); + Delete(what); + return what != -1; + } + break; + default: + return false; + } + + return true; +} + +void HistoryWindow::RestorePos() +{ + HANDLE contactToLoad = hContact; + if(hContact == NULL) + { + Utils_RestoreWindowPosition(hWnd,NULL,MODULE,"history_"); + contactToLoad = NULL; + } + else if(Utils_RestoreWindowPosition(hWnd,hContact,MODULE,"history_") != 0) + { + Utils_RestoreWindowPosition(hWnd,NULL,MODULE,"history_"); + contactToLoad = NULL; + } + if(DBGetContactSettingByte(contactToLoad, MODULE, "history_ismax", 0)) + { + ShowWindow(hWnd, SW_SHOWMAXIMIZED); + } + + LONG pos = DBGetContactSettingDword(contactToLoad, MODULE, "history_splitterv", 0); + if(pos > 0) + { + SplitterMoved(splitterYhWnd, pos, false); + } + + pos = DBGetContactSettingDword(contactToLoad, MODULE, "history_splitter", 0); + if(pos > 0) + { + SplitterMoved(splitterXhWnd, pos, false); + } +} + +void HistoryWindow::SavePos(bool all) +{ + HANDLE contactToSave = hContact; + if(all) + { + HANDLE _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while(_hContact) + { + DBDeleteContactSetting(_hContact, MODULE, "history_x"); + DBDeleteContactSetting(_hContact, MODULE, "history_y"); + DBDeleteContactSetting(_hContact, MODULE, "history_width"); + DBDeleteContactSetting(_hContact, MODULE, "history_height"); + DBDeleteContactSetting(_hContact, MODULE, "history_ismax"); + DBDeleteContactSetting(_hContact, MODULE, "history_splitterv"); + DBDeleteContactSetting(_hContact, MODULE, "history_splitter"); + _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)_hContact, 0); + } + + contactToSave = NULL; + } + + Utils_SaveWindowPosition(hWnd,contactToSave,MODULE,"history_"); + WINDOWPLACEMENT wp; + wp.length=sizeof(wp); + GetWindowPlacement(hWnd,&wp); + DBWriteContactSettingByte(contactToSave, MODULE, "history_ismax", wp.showCmd == SW_MAXIMIZE ? 1 : 0); + DBWriteContactSettingDword(contactToSave, MODULE, "history_splitterv", splitterX); + DBWriteContactSettingDword(contactToSave, MODULE, "history_splitter", splitterY); +} + +#define DEF_FILTERS_START 50000 +void HistoryWindow::FindToolbarClicked(LPNMTOOLBAR lpnmTB) +{ + RECT rc; + SendMessage(lpnmTB->hdr.hwndFrom, TB_GETRECT, (WPARAM)lpnmTB->iItem, (LPARAM)&rc); + MapWindowPoints(lpnmTB->hdr.hwndFrom, HWND_DESKTOP, (LPPOINT)&rc, 2); + HMENU hPopupMenu = CreatePopupMenu(); + if(hPopupMenu != NULL) + { + AppendMenu(hPopupMenu, MF_STRING, IDM_FINDNEXT, TranslateT("Find Next")); + AppendMenu(hPopupMenu, MF_STRING, IDM_FINDPREV, TranslateT("Find Previous")); + AppendMenu(hPopupMenu, MFT_SEPARATOR, 0, NULL); + AppendMenu(hPopupMenu, searcher.IsMatchCase() ? MF_STRING | MF_CHECKED : MF_STRING, IDM_MATCHCASE, TranslateT("Match Case")); + AppendMenu(hPopupMenu, searcher.IsMatchWholeWords() ? MF_STRING | MF_CHECKED : MF_STRING, IDM_MATCHWHOLE, TranslateT("Match Whole Word")); + AppendMenu(hPopupMenu, searcher.IsOnlyIn() ? MF_STRING | MF_CHECKED : MF_STRING, IDM_ONLYIN, TranslateT("Only Incomming Messages")); + AppendMenu(hPopupMenu, searcher.IsOnlyOut() ? MF_STRING | MF_CHECKED : MF_STRING, IDM_ONLYOUT, TranslateT("Only Outgoing Messages")); + AppendMenu(hPopupMenu, searcher.IsOnlyGroup() ? MF_STRING | MF_CHECKED : MF_STRING, IDM_ONLYGROUP, TranslateT("Only Selected Group")); + AppendMenu(hPopupMenu, searcher.IsAllUsers() ? MF_STRING | MF_CHECKED : MF_STRING, IDM_ALLUSERS, TranslateT("All Contacts")); + AppendMenu(hPopupMenu, MFT_SEPARATOR, 0, NULL); + HMENU hFilterMenu = CreatePopupMenu(); + int filter = GetFilterNr(); + AppendMenu(hFilterMenu, filter == 0 ? MF_STRING | MF_CHECKED : MF_STRING, IDM_FILTERDEF, TranslateT("Default history events")); + AppendMenu(hFilterMenu, filter == 1 ? MF_STRING | MF_CHECKED : MF_STRING, IDM_FILTERALL, TranslateT("All events")); + for(size_t i = 0 ; i < Options::instance->customFilters.size(); ++i) + { + UINT flags = MF_STRING; + if(filter - 2 == i) + flags |= MF_CHECKED; + + AppendMenu(hFilterMenu, flags, DEF_FILTERS_START + i, Options::instance->customFilters[i].name.c_str()); + } + AppendMenu(hPopupMenu, MF_STRING | MF_POPUP, (UINT_PTR)hFilterMenu, TranslateT("Filters")); + if(searcher.IsFindBack()) + SetMenuDefaultItem(hPopupMenu, IDM_FINDPREV, FALSE); + else + SetMenuDefaultItem(hPopupMenu, IDM_FINDNEXT, FALSE); + + int selected = TrackPopupMenu(hPopupMenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hWnd, 0); + switch (selected) + { + case IDM_FINDNEXT: + searcher.ChangeFindDirection(false); + break; + case IDM_FINDPREV: + searcher.ChangeFindDirection(true); + break; + case IDM_MATCHCASE: + searcher.SetMatchCase(!searcher.IsMatchCase()); + break; + case IDM_MATCHWHOLE: + searcher.SetMatchWholeWords(!searcher.IsMatchWholeWords()); + break; + case IDM_ONLYIN: + searcher.SetOnlyIn(!searcher.IsOnlyIn()); + break; + case IDM_ONLYOUT: + searcher.SetOnlyOut(!searcher.IsOnlyOut()); + break; + case IDM_ONLYGROUP: + searcher.SetOnlyGroup(!searcher.IsOnlyGroup()); + break; + case IDM_ALLUSERS: + searcher.SetAllUsers(!searcher.IsAllUsers()); + break; + case IDM_FILTERDEF: + SetDefFilter(0); + SendMessage(hWnd,DM_HREBUILD,0,0); + break; + case IDM_FILTERALL: + SetDefFilter(1); + SendMessage(hWnd,DM_HREBUILD,0,0); + break; + default: + if(selected >= DEF_FILTERS_START) + { + SetDefFilter(selected - DEF_FILTERS_START + 2); + SendMessage(hWnd,DM_HREBUILD,0,0); + } + break; + } + + DestroyMenu(hFilterMenu); + DestroyMenu(hPopupMenu); + } +} + +void HistoryWindow::ConfigToolbarClicked(LPNMTOOLBAR lpnmTB) +{ + RECT rc; + SendMessage(lpnmTB->hdr.hwndFrom, TB_GETRECT, (WPARAM)lpnmTB->iItem, (LPARAM)&rc); + MapWindowPoints(lpnmTB->hdr.hwndFrom, HWND_DESKTOP, (LPPOINT)&rc, 2); + HMENU hPopupMenu = CreatePopupMenu(); + if(hPopupMenu != NULL) + { + AppendMenu(hPopupMenu, MF_STRING, IDM_OPTIONS, TranslateT("Options")); + AppendMenu(hPopupMenu, MF_STRING, IDM_FONTS, TranslateT("Fonts & Colors")); + AppendMenu(hPopupMenu, MF_STRING, IDM_ICONS, TranslateT("Icons")); + AppendMenu(hPopupMenu, MF_STRING, IDM_HOTKEYS, TranslateT("Hotkeys")); + AppendMenu(hPopupMenu, MFT_SEPARATOR, 0, NULL); + + HMENU hExportMenu = CreatePopupMenu(); + AppendMenu(hExportMenu, MF_STRING, IDM_EXPORTRHTML, TranslateT("Rich Html")); + AppendMenu(hExportMenu, MF_STRING, IDM_EXPORTPHTML, TranslateT("Plain Html")); + AppendMenu(hExportMenu, MF_STRING, IDM_EXPORTTXT, TranslateT("Txt")); + AppendMenu(hExportMenu, MF_STRING, IDM_EXPORTBINARY, TranslateT("Binary")); + AppendMenu(hExportMenu, MF_STRING, IDM_EXPORTDAT, TranslateT("Dat (mContacts)")); + + HMENU hImportMenu = CreatePopupMenu(); + AppendMenu(hImportMenu, MF_STRING, IDM_IMPORTBINARY, TranslateT("Binary")); + AppendMenu(hImportMenu, MF_STRING, IDM_IMPORTDAT, TranslateT("Dat (mContacts)")); + + AppendMenu(hPopupMenu, MF_STRING | MF_POPUP, (UINT_PTR)hExportMenu, TranslateT("Export")); + AppendMenu(hPopupMenu, MF_STRING | MF_POPUP, (UINT_PTR)hImportMenu, TranslateT("Import")); + + AppendMenu(hPopupMenu, MFT_SEPARATOR, 0, NULL); + AppendMenu(hPopupMenu, MF_STRING, IDM_SAVEPOS, TranslateT("Save window position as default")); + AppendMenu(hPopupMenu, MF_STRING, IDM_SAVEPOSALL, TranslateT("Save window position for all contacts")); + SetMenuDefaultItem(hPopupMenu, IDM_OPTIONS, FALSE); + + int selected = TrackPopupMenu(hPopupMenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hWnd, 0); + switch (selected) + { + case IDM_OPTIONS: + SendMessage(hWnd, WM_COMMAND, IDM_CONFIG, 0); + break; + case IDM_FONTS: + OpenOptions("Customize", "Fonts & Colors"); + break; + case IDM_ICONS: + OpenOptions("Customize", "Icons"); + break; + case IDM_HOTKEYS: + OpenOptions("Customize", "Hotkeys"); + break; + case IDM_SAVEPOS: + SavePos(false); + break; + case IDM_SAVEPOSALL: + SavePos(true); + break; + case IDM_EXPORTRHTML: + { + ExportManager exp(hWnd, hContact, GetFilterNr()); + exp.Export(IExport::RichHtml); + } + + break; + case IDM_EXPORTPHTML: + { + ExportManager exp(hWnd, hContact, GetFilterNr()); + exp.Export(IExport::PlainHtml); + } + + break; + case IDM_EXPORTTXT: + { + ExportManager exp(hWnd, hContact, GetFilterNr()); + exp.Export(IExport::Txt); + } + + break; + case IDM_EXPORTBINARY: + { + ExportManager exp(hWnd, hContact, GetFilterNr()); + exp.Export(IExport::Binary); + } + + break; + case IDM_EXPORTDAT: + { + ExportManager exp(hWnd, hContact, GetFilterNr()); + exp.Export(IExport::Dat); + } + + break; + case IDM_IMPORTBINARY: + { + DoImport(IImport::Binary); + } + + break; + case IDM_IMPORTDAT: + { + DoImport(IImport::Dat); + } + + break; + } + + DestroyMenu(hExportMenu); + DestroyMenu(hImportMenu); + DestroyMenu(hPopupMenu); + } +} + +void HistoryWindow::DoImport(IImport::ImportType type) +{ + ExportManager exp(hWnd, hContact, GetFilterNr()); + std::vector messages; + std::wstring err; + if(exp.Import(type, messages, &err)) + { + int act = MessageBox(hWnd, TranslateT("Do you want save imported messages to local profile?"), TranslateT("Import"), MB_ICONQUESTION | MB_YESNOCANCEL | MB_DEFBUTTON2); + if(act == IDYES) + { + MargeMessages(messages); + HistoryWindow::RebuildEvents(hContact); + } + else if(act == IDNO) + { + EventList::AddImporter(hContact, type, exp.GetFileName()); + HistoryWindow::RebuildEvents(hContact); + } + } + else if(!err.empty()) + { + MessageBox(hWnd, err.c_str(), TranslateT("Error"), MB_ICONERROR); + } +} + +void HistoryWindow::DeleteToolbarClicked(LPNMTOOLBAR lpnmTB) +{ + RECT rc; + SendMessage(lpnmTB->hdr.hwndFrom, TB_GETRECT, (WPARAM)lpnmTB->iItem, (LPARAM)&rc); + MapWindowPoints(lpnmTB->hdr.hwndFrom, HWND_DESKTOP, (LPPOINT)&rc, 2); + HMENU hPopupMenu = CreatePopupMenu(); + if(hPopupMenu != NULL) + { + AppendMenu(hPopupMenu, MF_STRING, IDM_DELETE, TranslateT("Delete")); + AppendMenu(hPopupMenu, MF_STRING, IDM_DELETEGROUP, TranslateT("Delete Group")); + AppendMenu(hPopupMenu, MF_STRING, IDM_DELETEUSER, TranslateT("Delete All User History")); + SetMenuDefaultItem(hPopupMenu, IDM_DELETE, FALSE); + + int selected = TrackPopupMenu(hPopupMenu, TPM_RETURNCMD, rc.left, rc.bottom, 0, hWnd, 0); + switch (selected) + { + case IDM_DELETE: + Delete(0); + break; + case IDM_DELETEGROUP: + Delete(1); + break; + case IDM_DELETEUSER: + Delete(2); + break; + } + + DestroyMenu(hPopupMenu); + } +} + +void HistoryWindow::Delete(int what) +{ + int toDelete = 1; + size_t start = 0; + size_t end = 0; + if(selected < 0 || selected >= (int)eventList.size() || what > 2 || what < 0) + return; + if(what == 0) + { + CHARRANGE chrg; + SendMessage(editWindow,EM_EXGETSEL,0,(LPARAM)&chrg); + if(chrg.cpMin == 0 && chrg.cpMax == -1) + { + toDelete = (int)currentGroup.size(); + } + else + { + while(start < currentGroup.size() && chrg.cpMin >= currentGroup[start].endPos) ++start; + end = start; + while(end < currentGroup.size() && chrg.cpMax > currentGroup[end].endPos) ++end; + if(start >= currentGroup.size()) + return; + if(end < currentGroup.size()) + ++end; + toDelete = (int)(end - start); + } + } + else if(what == 1) + { + end = currentGroup.size(); + toDelete = (int)end; + } + else + { + if(eventList.size() == 0) + return; + toDelete = 1; + } + + if(toDelete == 0) + return; + TCHAR message[256]; + if(what == 2) + _tcscpy_s(message, TranslateT("This operation will PERMANENTLY REMOVE all history for this contact.\nAre you sure you want to do this?")); + else + _stprintf_s(message, TranslateT("Number of history items to delete: %d.\nAre you sure you want to do this?"), toDelete); + if(MessageBox(hWnd, message, TranslateT("Are You sure?"), MB_OKCANCEL | MB_ICONERROR) != IDOK) + return; + + bool areImpMessages = false; + bool rebuild = false; + if(what == 2) + { + for(size_t j = 0; j < eventList.size(); ++j) + { + for(size_t i = 0; i < eventList[j].size(); ++i) + { + DeleteEvent(eventList[j][i]); + } + } + + areImpMessages = EventList::IsImportedHistory(hContact); + rebuild = true; + } + else + { + for(size_t i = start; i < end; ++i) + { + EventIndex& ev = eventList[selected][i]; + DeleteEvent(ev); + areImpMessages |= ev.isExternal; + } + + if(start == 0 && end == currentGroup.size()) + { + rebuild = true; + } + else + { + rebuild = false; + } + } + + if(areImpMessages) + { + TCHAR *message = TranslateT("Do you want delete all imported messages for this contact?\nNote that next scheduler task import this messages again."); + if(MessageBox(hWnd, message, TranslateT("Are You sure?"), MB_YESNO | MB_ICONERROR) == IDYES) + { + EventList::DeleteImporter(hContact); + rebuild = true; + } + } + + if(rebuild) + { + RebuildEvents(hContact); + } + else + { + RebuildGroup(selected); + SelectEventGroup(selected); + } +} + +bool HistoryWindow::ContactChanged(bool sync) +{ + if(!isLoading) + { + HANDLE hItem = (HANDLE)SendDlgItemMessage(hWnd, IDC_LIST_CONTACTS, CLM_GETSELECTION, 0, 0); + if(hItem != NULL) + { + int typeOf = SendDlgItemMessage(hWnd, IDC_LIST_CONTACTS, CLM_GETITEMTYPE,(WPARAM)hItem,0); + if(typeOf == CLCIT_CONTACT) + { + if(hContact != hItem) + { + ChangeToFreeWindow(this); + isLoading = true; + hContact = hItem; + ReloadContacts(); + if(sync) + FillHistoryThread(this); + else + mir_forkthread(HistoryWindow::FillHistoryThread, this); + return true; + } + } + else if(typeOf == CLCIT_INFO && hSystem == hItem) + { + if(hContact != NULL) + { + ChangeToFreeWindow(this); + isLoading = true; + hContact = NULL; + ReloadContacts(); + if(sync) + FillHistoryThread(this); + else + mir_forkthread(HistoryWindow::FillHistoryThread, this); + return true; + } + } + } + } + + return false; +} + +void HistoryWindow::GroupImagesChanged() +{ + if(isGroupImages != Options::instance->groupShowEvents) + { + isGroupImages = Options::instance->groupShowEvents; + if(isGroupImages) + { + ListView_SetImageList(listWindow, himlSmall, LVSIL_SMALL); + } + else + { + ListView_SetImageList(listWindow, himlNone, LVSIL_SMALL); + } + } +} + +void HistoryWindow::FormatQuote(std::wstring& quote, const MessageData& md, const std::wstring& msg) +{ + if(md.isMe) + quote += myName; + else + quote += contactName; + TCHAR str[32]; + tmi.printTimeStamp(NULL, md.timestamp, _T("d t"), str , 32, 0); + quote += _T(", "); + quote += str; + quote += _T("\n"); + int f = 0; + do + { + int nf = (int)msg.find_first_of(_T("\r\n"), f); + if(nf >= 0 && nf < (int)msg.length()) + { + if(nf - f >= 0 ) + { + quote += _T(">"); + quote += msg.substr(f, nf - f); + quote += _T("\n"); + } + + f = nf + 1; + if(msg[nf] == _T('\r') && f < (int)msg.length() && msg[f] == _T('\n')) + ++f; + } + else if(msg.length() - f > 0) + { + quote += _T(">"); + quote += msg.substr(f, msg.length() - f); + quote += _T("\n"); + f = -1; + } + else + f = -1; + } + while(f > 0 && f < (int)msg.length()); +} + +HANDLE HistoryWindow::GetNextContact(HANDLE hContact, int adder) +{ + HWND contactList = GetDlgItem(hWnd,IDC_LIST_CONTACTS); + bool find = false; + HANDLE _hContact; + if(adder > 0) + { + if(hContact != NULL) + { + _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + while(_hContact) + { + HANDLE hItem = (HANDLE)SendMessage(contactList, CLM_FINDCONTACT, (WPARAM)_hContact, 0); + if(hItem != NULL) + { + find = true; + break; + } + + _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)_hContact, 0); + } + + if(!find && EventList::GetContactMessageNumber(NULL)) + { + _hContact = NULL; + find = true; + } + } + + if(!find) + { + _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while(_hContact && _hContact != hContact) + { + HANDLE hItem = (HANDLE)SendMessage(contactList, CLM_FINDCONTACT, (WPARAM)_hContact, 0); + if(hItem != NULL) + { + find = true; + break; + } + + _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)_hContact, 0); + } + } + } + else + { + HANDLE lastContact = NULL; + _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + while(_hContact && _hContact != hContact) + { + HANDLE hItem = (HANDLE)SendMessage(contactList, CLM_FINDCONTACT, (WPARAM)_hContact, 0); + if(hItem != NULL) + { + lastContact = _hContact; + } + + _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)_hContact, 0); + } + + if(hContact != NULL) + { + if(lastContact == NULL && !EventList::GetContactMessageNumber(NULL)) + { + _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)hContact, 0); + while(_hContact) + { + HANDLE hItem = (HANDLE)SendMessage(contactList, CLM_FINDCONTACT, (WPARAM)_hContact, 0); + if(hItem != NULL) + { + lastContact = _hContact; + } + + _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)_hContact, 0); + } + } + + if(lastContact != NULL || EventList::GetContactMessageNumber(NULL)) + { + _hContact = lastContact; + find = true; + } + } + else if(lastContact != NULL) + { + _hContact = lastContact; + find = true; + } + } + + if(find) + { + return _hContact; + } + else + { + return hContact; + } +} + +void HistoryWindow::SelectContact(HANDLE _hContact) +{ + if(hContact != _hContact) + { + HWND contactList = GetDlgItem(hWnd,IDC_LIST_CONTACTS); + if(_hContact != NULL) + { + HANDLE hItem = (HANDLE)SendMessage(contactList, CLM_FINDCONTACT, (WPARAM)_hContact, 0); + if(hItem != NULL) + { + SendMessage(contactList, CLM_ENSUREVISIBLE, (WPARAM)hItem, 0); + SendMessage(contactList, CLM_SELECTITEM, (WPARAM)hItem, 0); + } + } + else + { + SendMessage(contactList, CLM_ENSUREVISIBLE, (WPARAM)hSystem, 0); + SendMessage(contactList, CLM_SELECTITEM, (WPARAM)hSystem, 0); + } + + while(isLoading) + Sleep(100); + ContactChanged(true); + } +} + +void ResetCList(HWND hWnd) +{ + COLORREF bkCLColor = Options::instance->GetColor(Options::ContactListBackground); + SendDlgItemMessage(hWnd, IDC_LIST_CONTACTS, CLM_SETBKBITMAP, 0, (LPARAM)(HBITMAP) NULL); + SendDlgItemMessage(hWnd, IDC_LIST_CONTACTS, CLM_SETBKCOLOR, bkCLColor, 0); + SendDlgItemMessage(hWnd, IDC_LIST_CONTACTS, CLM_SETUSEGROUPS, Options::instance->showContactGroups, 0); +} diff --git a/plugins/BasicHistory/src/HistoryWindow.h b/plugins/BasicHistory/src/HistoryWindow.h new file mode 100644 index 0000000000..8a31d9194a --- /dev/null +++ b/plugins/BasicHistory/src/HistoryWindow.h @@ -0,0 +1,95 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once +#include "Searcher.h" + +class HistoryWindow : public SearchContext +{ +private: + HistoryWindow(HANDLE _hContact); + void Initialise(); + void Destroy(); + void SplitterMoved(HWND splitter, LONG pos, bool screenPos); + static INT_PTR CALLBACK DlgProcHistory(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + static LRESULT CALLBACK SplitterSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + static int HistoryDlgResizer(HWND, LPARAM, UTILRESIZECONTROL *urc); + static void FillHistoryThread(void* param); + static void Close(HistoryWindow* historyWindow); + static void ChangeToFreeWindow(HistoryWindow* historyWindow); + void ReplaceIcons(HWND hwndDlg, int selStart, BOOL isSent); + void EnableWindows(BOOL enable); + void ReloadContacts(); + bool DoHotkey(UINT msg, LPARAM lParam, WPARAM wParam, int window); + void RestorePos(); + void SavePos(bool all); + void FindToolbarClicked(LPNMTOOLBAR lpnmTB); + void ConfigToolbarClicked(LPNMTOOLBAR lpnmTB); + void DeleteToolbarClicked(LPNMTOOLBAR lpnmTB); + void Delete(int what); + bool ContactChanged(bool sync = false); + void GroupImagesChanged(); + void FormatQuote(std::wstring& quote, const MessageData& md, const std::wstring& msg); + void FontsChanged(); + void ReloadMainOptions(); + void DoImport(IImport::ImportType type); + + static std::map windows; + static std::vector freeWindows; + bool isDestroyed; + LONG splitterY; + LONG splitterOrgY; + LONG splitterX; + LONG splitterOrgX; + HICON *eventIcoms; + int allIconNumber; + HICON plusIco, minusIco, findNextIco, findPrevIco, configIco, deleteIco; + WNDPROC OldSplitterProc; + bool isContactList; + LONG listOryginalPos; + bool isLoading; + Searcher searcher; + bool isGroupImages; + HIMAGELIST himlSmall, himlNone; + HBRUSH bkBrush; + HBRUSH bkFindBrush; + HANDLE hSystem; + HWND splitterXhWnd, splitterYhWnd; +protected: + virtual void AddGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText, int ico); +public: + ~HistoryWindow(); + static void Deinit(); + static void Open(HANDLE hContact); + static void Close(HANDLE hContact); + static void RebuildEvents(HANDLE hContact); + static bool IsInList(HWND hWnd); + static int FontsChanged(WPARAM wParam, LPARAM lParam); + static INT_PTR DeleteAllUserHistory(WPARAM wParam, LPARAM lParam); + static void OptionsMainChanged(); + static void OptionsGroupChanged(); + static void OptionsSearchingChanged(); + void Show(); + void Focus(); + + // SearchContext interface + virtual void SelectEventGroup(int sel); + virtual HANDLE GetNextContact(HANDLE hContact, int adder); + virtual void SelectContact(HANDLE _hContact); +}; + diff --git a/plugins/BasicHistory/src/HotkeyHelper.cpp b/plugins/BasicHistory/src/HotkeyHelper.cpp new file mode 100644 index 0000000000..eeb537456a --- /dev/null +++ b/plugins/BasicHistory/src/HotkeyHelper.cpp @@ -0,0 +1,105 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#include "StdAfx.h" +#include "HotkeyHelper.h" + +LRESULT CALLBACK HotkeySubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +void RegisterHotkeyControl(HWND control) +{ + WNDPROC oldProc = (WNDPROC)SetWindowLongPtr(control, GWLP_WNDPROC, (LONG_PTR) HotkeySubclassProc); + SetWindowLongPtr(control, GWLP_USERDATA, (LONG_PTR) oldProc); +} + +void UnregisterHotkeyControl(HWND control) +{ + WNDPROC oldProc = (WNDPROC)GetWindowLongPtr(control, GWLP_USERDATA); + if(oldProc != NULL) + { + SetWindowLongPtr(control, GWLP_WNDPROC, (LONG_PTR) oldProc); + SetWindowLongPtr(control, GWLP_USERDATA, NULL); + } +} + +static bool isPresed = false; + +LRESULT CALLBACK HotkeySubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + WNDPROC oldProc = (WNDPROC)GetWindowLongPtr(hwnd, GWLP_USERDATA); + + switch (msg) { + case WM_CHAR: + case WM_SYSCHAR: + case WM_UNICHAR: + case WM_DEADCHAR: + case WM_SYSDEADCHAR: + if(isPresed) + return 0; + break; + case WM_KEYUP: + case WM_SYSKEYUP: + if(isPresed) + { + isPresed = false; + return 0; + } + break; + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + { + isPresed = false; + HWND hwndParent = GetParent(hwnd); + MSGFILTER filter; + filter.msg = msg; + filter.lParam = lParam; + filter.wParam = wParam; + filter.nmhdr.hwndFrom = hwnd; + filter.nmhdr.code = EN_MSGFILTER; + filter.nmhdr.idFrom = GetDlgCtrlID(hwnd); + if(SendMessage(hwndParent, WM_NOTIFY, NULL, (LPARAM)&filter)) + { + isPresed = true; + return 0; + } + + LRESULT res = CallWindowProc(oldProc, hwnd, msg, wParam, lParam); + filter.nmhdr.code = CLN_MYSELCHANGED; + SendMessage(hwndParent, WM_NOTIFY, NULL, (LPARAM)&filter); + return res; + } + break; + case WM_LBUTTONDOWN: + { + HWND hwndParent = GetParent(hwnd); + MSGFILTER filter; + filter.msg = msg; + filter.lParam = lParam; + filter.wParam = wParam; + filter.nmhdr.hwndFrom = hwnd; + filter.nmhdr.code = CLN_MYSELCHANGED; + filter.nmhdr.idFrom = GetDlgCtrlID(hwnd); + + LRESULT res = CallWindowProc(oldProc, hwnd, msg, wParam, lParam); + SendMessage(hwndParent, WM_NOTIFY, NULL, (LPARAM)&filter); + return res; + } + break; + } + return CallWindowProc(oldProc, hwnd, msg, wParam, lParam); +} \ No newline at end of file diff --git a/plugins/BasicHistory/src/HotkeyHelper.h b/plugins/BasicHistory/src/HotkeyHelper.h new file mode 100644 index 0000000000..f31b1c6666 --- /dev/null +++ b/plugins/BasicHistory/src/HotkeyHelper.h @@ -0,0 +1,24 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once + +#define CLN_MYSELCHANGED (CLN_FIRST-50) + +void RegisterHotkeyControl(HWND control); +void UnregisterHotkeyControl(HWND control); diff --git a/plugins/BasicHistory/src/IExport.h b/plugins/BasicHistory/src/IExport.h new file mode 100644 index 0000000000..d024a084e4 --- /dev/null +++ b/plugins/BasicHistory/src/IExport.h @@ -0,0 +1,49 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once +class IExport +{ +protected: + std::wostream* stream; +public: + enum ExportType + { + RichHtml, + PlainHtml, + Txt, + Binary, + Dat + }; + + void SetStream(std::wostream *str) + { + stream = str; + } + + virtual const TCHAR* GetExt() = 0; + virtual void WriteHeader(const std::wstring &fileName, const std::wstring &filterName, const std::wstring &myName, const std::wstring &myId, const std::wstring &name1, const std::wstring &proto1, const std::wstring &id1, const std::string& baseProto1, const std::wstring& encoding) = 0; + virtual void WriteFooter() = 0; + virtual void WriteGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText) = 0; + virtual void WriteMessage(bool isMe, const std::wstring &longDate, const std::wstring &shortDate, const std::wstring &user, const std::wstring &message, const DBEVENTINFO& dbei) = 0; + + virtual ~IExport() + { + } +}; + diff --git a/plugins/BasicHistory/src/IImport.h b/plugins/BasicHistory/src/IImport.h new file mode 100644 index 0000000000..aef3b35179 --- /dev/null +++ b/plugins/BasicHistory/src/IImport.h @@ -0,0 +1,53 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once + +class IImport +{ +protected: + std::istream* stream; +public: + enum ImportType + { + Binary, + Dat + }; + + struct ExternalMessage + { + DWORD timestamp; + WORD eventType; + WORD flags; + std::wstring message; + }; + + void SetStream(std::istream *str) + { + stream = str; + } + + virtual const TCHAR* GetExt() = 0; + virtual int IsContactInFile(const std::vector& contacts) = 0; + virtual bool GetEventList(std::vector& eventList) = 0; + + virtual ~IImport() + { + } +}; + diff --git a/plugins/BasicHistory/src/ImageDataObject.cpp b/plugins/BasicHistory/src/ImageDataObject.cpp new file mode 100644 index 0000000000..15cb67f6ce --- /dev/null +++ b/plugins/BasicHistory/src/ImageDataObject.cpp @@ -0,0 +1,171 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +//code taken partly from public example on the internet, source unknown. + +#include "StdAfx.h" +#include "ImageDataObject.h" + +HBITMAP CacheIconToBMP(HICON hIcon, COLORREF backgroundColor, int sizeX, int sizeY) +{ + RECT rc; + HBRUSH hBkgBrush = CreateSolidBrush(backgroundColor); + rc.top = rc.left = 0; + rc.right = sizeY; + rc.bottom = sizeX; + HDC hdc = GetDC(0); + HBITMAP hBmp = CreateCompatibleBitmap(hdc, sizeY, sizeX); + HDC hdcMem = CreateCompatibleDC(hdc); + HBITMAP hoBmp = (HBITMAP)SelectObject(hdcMem, hBmp); + FillRect(hdcMem, &rc, hBkgBrush); + DrawIconEx(hdcMem, 0, 0, hIcon, sizeY, sizeX, 0, NULL, DI_NORMAL); + SelectObject(hdcMem, hoBmp); + DeleteDC(hdcMem); + ReleaseDC(NULL, hdc); + DeleteObject(hBkgBrush); + return hBmp; +} + +// returns true on success, false on failure +bool ImageDataObject::InsertIcon(IRichEditOle* pRichEditOle, HICON hIcon, + COLORREF backgroundColor, int sizeX, int sizeY) +{ + bool result; + HBITMAP hBmp = CacheIconToBMP(hIcon, backgroundColor, sizeX, sizeY); + result = InsertBitmap(pRichEditOle, hBmp); + DeleteObject(hBmp); + return result; +} + +// returns true on success, false on failure +bool ImageDataObject::InsertBitmap(IRichEditOle* pRichEditOle, HBITMAP hBitmap) +{ + SCODE sc; + BITMAP bminfo; + + // Get the image data object + // + ImageDataObject *pods = new ImageDataObject; + + GetObject(hBitmap, sizeof(bminfo), &bminfo); + pods->SetBitmap(hBitmap); + + // Get the RichEdit container site + // + IOleClientSite *pOleClientSite; + pRichEditOle->GetClientSite(&pOleClientSite); + + // Initialize a Storage Object + // + IStorage *pStorage; + + LPLOCKBYTES lpLockBytes = NULL; + sc = ::CreateILockBytesOnHGlobal(NULL, TRUE, &lpLockBytes); + if (sc != S_OK) { + pOleClientSite->Release(); + return false; + } + sc = ::StgCreateDocfileOnILockBytes(lpLockBytes, + STGM_SHARE_EXCLUSIVE | STGM_CREATE | STGM_READWRITE, 0, &pStorage); + if (sc != S_OK) { + lpLockBytes = NULL; + pOleClientSite->Release(); + return false; + } + // The final ole object which will be inserted in the richedit control + // + IOleObject *pOleObject; + pOleObject = pods->GetOleObject(pOleClientSite, pStorage); + if (pOleObject == NULL) { + pStorage->Release(); + pOleClientSite->Release(); + return false; + } + + // all items are "contained" -- this makes our reference to this object + // weak -- which is needed for links to embedding silent update. + OleSetContainedObject(pOleObject, TRUE); + + // Now Add the object to the RichEdit + // + REOBJECT reobject; + ZeroMemory(&reobject, sizeof(REOBJECT)); + reobject.cbStruct = sizeof(REOBJECT); + + CLSID clsid; + sc = pOleObject->GetUserClassID(&clsid); + if (sc != S_OK) { + pOleObject->Release(); + pStorage->Release(); + pOleClientSite->Release(); + return false; + } + + reobject.clsid = clsid; + reobject.cp = REO_CP_SELECTION ; + reobject.dvaspect = DVASPECT_CONTENT; + reobject.poleobj = pOleObject; + reobject.polesite = pOleClientSite; + reobject.pstg = pStorage; + reobject.dwFlags = bminfo.bmHeight <= 12 ? 0 : REO_BELOWBASELINE; + + // Insert the bitmap at the current location in the richedit control + // + sc = pRichEditOle->InsertObject(&reobject); + + // Release all unnecessary interfaces + // + pOleObject->Release(); + pOleClientSite->Release(); + lpLockBytes->Release(); + pStorage->Release(); + if (sc != S_OK) + return false; + else + return true; +} + + +void ImageDataObject::SetBitmap(HBITMAP hBitmap) +{ + STGMEDIUM stgm; + stgm.tymed = TYMED_GDI; // Storage medium = HBITMAP handle + stgm.hBitmap = hBitmap; + stgm.pUnkForRelease = NULL; // Use ReleaseStgMedium + + FORMATETC fm; + fm.cfFormat = CF_BITMAP; // Clipboard format = CF_BITMAP + fm.ptd = NULL; // Target Device = Screen + fm.dwAspect = DVASPECT_CONTENT; // Level of detail = Full content + fm.lindex = -1; // Index = Not applicaple + fm.tymed = TYMED_GDI; // Storage medium = HBITMAP handle + + this->SetData(&fm, &stgm, TRUE); +} + + +IOleObject *ImageDataObject::GetOleObject(IOleClientSite *pOleClientSite, IStorage *pStorage) +{ + SCODE sc; + IOleObject *pOleObject; + sc = ::OleCreateStaticFromData(this, IID_IOleObject, OLERENDER_FORMAT, + &m_format, pOleClientSite, pStorage, (void **) & pOleObject); + if (sc != S_OK) + pOleObject = NULL; + return pOleObject; +} diff --git a/plugins/BasicHistory/src/ImageDataObject.h b/plugins/BasicHistory/src/ImageDataObject.h new file mode 100644 index 0000000000..309c220e36 --- /dev/null +++ b/plugins/BasicHistory/src/ImageDataObject.h @@ -0,0 +1,133 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +//code taken partly from public example on the internet, source unknown. + +#pragma once + +class ImageDataObject : IDataObject +{ +public: + // returns true on success, false on failure + static bool InsertBitmap(IRichEditOle* pRichEditOle, HBITMAP hBitmap); + // returns true on success, false on failure + static bool InsertIcon(IRichEditOle* pRichEditOle, HICON hIcon, + COLORREF backgroundColor, int sizeX = 0, int sizeY = 0); + +private: + ULONG m_ulRefCnt; + BOOL m_bRelease; + + STGMEDIUM m_stgmed; + FORMATETC m_format; + + // ULONG m_nIndex; // current enumerator index + +public: + ImageDataObject() : m_ulRefCnt(0) + { + m_bRelease = FALSE; + } + + ~ImageDataObject() + { + if (m_bRelease) + ::ReleaseStgMedium(&m_stgmed); + } + + // IUnknown interface + STDMETHOD(QueryInterface)(REFIID iid, void ** ppvObject) + { + if (iid == IID_IUnknown || iid == IID_IDataObject) + { + *ppvObject = this; + AddRef(); + return S_OK; + } + else + return E_NOINTERFACE; + } + + STDMETHOD_(ULONG, AddRef)(void) + { + m_ulRefCnt++; + return m_ulRefCnt; + } + + STDMETHOD_(ULONG, Release)(void) + { + m_ulRefCnt--; + if (m_ulRefCnt == 0) + delete this; + return m_ulRefCnt; + } + + // IDataObject Interface + STDMETHOD(GetData)(FORMATETC *pformatetcIn, STGMEDIUM *pmedium) { + HANDLE hDst; + hDst = ::OleDuplicateData(m_stgmed.hBitmap, CF_BITMAP, 0); + if (hDst == NULL) + return E_HANDLE; + + pmedium->tymed = TYMED_GDI; + pmedium->hBitmap = (HBITMAP)hDst; + pmedium->pUnkForRelease = NULL; + return S_OK; + } + + STDMETHOD(GetDataHere)(FORMATETC* pformatetc, STGMEDIUM* pmedium ) { + return E_NOTIMPL; + } + + STDMETHOD(QueryGetData)(FORMATETC* pformatetc ) { + return E_NOTIMPL; + } + + STDMETHOD(GetCanonicalFormatEtc)(FORMATETC* pformatectIn ,FORMATETC* pformatetcOut ) { + return E_NOTIMPL; + } + + STDMETHOD(SetData)(FORMATETC* pformatetc , STGMEDIUM* pmedium , BOOL fRelease ) { + m_format = *pformatetc; + m_stgmed = *pmedium; + + return S_OK; + } + + STDMETHOD(EnumFormatEtc)(DWORD dwDirection , IEnumFORMATETC** ppenumFormatEtc ) { + return E_NOTIMPL; + } + + STDMETHOD(DAdvise)(FORMATETC *pformatetc, DWORD advf, IAdviseSink *pAdvSink, + DWORD *pdwConnection) { + return E_NOTIMPL; + } + + STDMETHOD(DUnadvise)(DWORD dwConnection) { + return E_NOTIMPL; + } + + STDMETHOD(EnumDAdvise)(IEnumSTATDATA **ppenumAdvise) { + return E_NOTIMPL; + } + + // Other + void SetBitmap(HBITMAP hBitmap); + IOleObject *GetOleObject(IOleClientSite *pOleClientSite, IStorage *pStorage); +}; + diff --git a/plugins/BasicHistory/src/Options.cpp b/plugins/BasicHistory/src/Options.cpp new file mode 100644 index 0000000000..218e721f03 --- /dev/null +++ b/plugins/BasicHistory/src/Options.cpp @@ -0,0 +1,2170 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#include "StdAfx.h" +#include "Options.h" +#include "resource.h" + +extern HINSTANCE hInst; +extern bool g_SmileyAddAvail; +extern bool bPopupsEnabled; + +#define MODULE "BasicHistory" + +Options *Options::instance; + +struct EventNamesType +{ + int id; + TCHAR* name; +} EventNames[] = +{ + EVENTTYPE_MESSAGE, LPGENT("Message"), + EVENTTYPE_FILE, LPGENT("File transfer"), + EVENTTYPE_URL, LPGENT("Link"), + EVENTTYPE_STATUSCHANGE, LPGENT("Status change"), + EVENTTYPE_AUTHREQUEST, LPGENT("Authorization request"), + EVENTTYPE_ADDED, LPGENT("You were added"), + EVENTTYPE_CONTACTS, LPGENT("Contacts recieved"), + EVENTTYPE_SMTPSIMPLE, LPGENT("SMTP Simple Email"), + ICQEVENTTYPE_SMS, LPGENT("SMS message") +}; + +struct TCpTable { + UINT cpId; + TCHAR *cpName; +} +cpTable[] = { + { CP_UTF8, _T("UTF-8") }, + { 1250, _T("windows-1250") }, + { 1251, _T("windows-1251") }, + { 1252, _T("windows-1252") }, + { 1253, _T("windows-1253") }, + { 1254, _T("windows-1254") }, + { 1255, _T("windows-1255") }, + { 1256, _T("windows-1256") }, + { 1257, _T("windows-1257") }, + { 1258, _T("windows-1258") }, + { 28591, _T("iso-8859-1") }, + { 28592, _T("iso-8859-2") }, + { 28593, _T("iso-8859-3") }, + { 28594, _T("iso-8859-4") }, + { 28595, _T("iso-8859-5") }, + { 28596, _T("iso-8859-6") }, + { 28597, _T("iso-8859-7") }, + { 28598, _T("iso-8859-8") }, + { 28599, _T("iso-8859-9") }, + { 28603, _T("iso-8859-13") }, + { 28605, _T("iso-8859-15") }, +}; + +Options::Options() +{ + showContacts = false; + showContactGroups = true; + groupNewOnTop = true; + groupShowEvents = true; + groupShowTime = true; + groupShowName = false; + groupShowMessage = true; + groupMessageLen = 43; + groupTime = 5; + groupMessagesNumber = 100; + messagesNewOnTop = false; + messagesShowDate = false; + messagesShowSec = false; + messagesShowName = true; + messagesShowEvents = false; + messagesUseSmileys = true; + searchForInList = true; + searchForInMess = true; + searchMatchCase = false; + searchMatchWhole = false; + searchOnlyIn = false; + searchOnlyOut = false; + searchOnlyGroup = false; + searchAllContacts = false; + schedulerAlerts = true; + schedulerHistoryAlerts = true; + defFilter = 0; + codepageTxt = CP_UTF8; + codepageHtml1 = CP_UTF8; + codepageHtml2 = CP_UTF8; + encodingTxt = _T("UTF-8"); + encodingHtml1 = _T("UTF-8"); + encodingHtml2 = _T("UTF-8"); + exportHtml1ShowDate = true; + exportHtml2ShowDate = false; + exportHtml2UseSmileys = true; +} + +Options::~Options() +{ +} + +int Options::InitOptions(WPARAM wParam, LPARAM lParam) +{ + OPTIONSDIALOGPAGE odp = {0}; + + odp.cbSize = sizeof(odp); + odp.position = 100000000; + odp.hInstance = hInst; + odp.flags = ODPF_BOLDGROUPS | ODPF_TCHAR; + odp.ptszTitle = LPGENT("History"); + + odp.ptszTab = LPGENT("Group list"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_GROUPLIST); + odp.pfnDlgProc = Options::DlgProcOptsGroupList; + Options_AddPage(wParam, &odp); + + odp.ptszTab = LPGENT("Messages"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MESSAGES); + odp.pfnDlgProc = Options::DlgProcOptsMessages; + Options_AddPage(wParam, &odp); + + odp.ptszTab = LPGENT("Searching"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SEARCHING); + odp.pfnDlgProc = Options::DlgProcOptsSearching; + Options_AddPage(wParam, &odp); + + odp.ptszTab = LPGENT("Export"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_EXPORT); + odp.pfnDlgProc = Options::DlgProcOptsExport; + Options_AddPage(wParam, &odp); + + odp.ptszTab = LPGENT("Scheduler"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SCHEDULER); + odp.pfnDlgProc = Options::DlgProcOptsScheduler; + Options_AddPage(wParam, &odp); + + odp.ptszTab = LPGENT("Advanced"); + odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MAIN); + odp.pfnDlgProc = Options::DlgProcOptsMain; + Options_AddPage(wParam, &odp); + + return 0; +} + +struct FontOptionsList { + TCHAR* szDescr; + COLORREF defColour; + TCHAR* szDefFace; + BYTE defStyle; + char defSize; + TCHAR* szBackgroundName; + DWORD flags; +}; + +struct ColorOptionsList { + TCHAR* tszName; + COLORREF def; +}; + +struct HotkeyOptionsList { + const char *pszName; + const TCHAR *ptszDescription; + const TCHAR *ptszSection; + const char *pszService; + WORD DefHotKey; + LPARAM lParam; +}; + +static FontOptionsList g_FontOptionsList[] = { + {LPGENT(">> Outgoing timestamp"), RGB(0, 0, 0), _T("MS Shell Dlg 2"), DBFONTF_BOLD, -11, LPGENT("Outgoing background"), FIDF_ALLOWEFFECTS}, + {LPGENT("<< Incoming timestamp"), RGB(0, 0, 0), _T("MS Shell Dlg 2"), DBFONTF_BOLD, -11, LPGENT("Incoming background"), FIDF_ALLOWEFFECTS}, + {LPGENT(">> Outgoing name"), RGB(100,100,100), _T("MS Shell Dlg 2"), DBFONTF_BOLD, -11, LPGENT("Outgoing background"), FIDF_ALLOWEFFECTS}, + {LPGENT("<< Incoming name"), RGB(90,160,90), _T("MS Shell Dlg 2"), DBFONTF_BOLD, -11, LPGENT("Incoming background"), FIDF_ALLOWEFFECTS}, + {LPGENT(">> Outgoing messages"), RGB(0, 0, 0), _T("MS Shell Dlg 2"), 0, -11, LPGENT("Outgoing background"), FIDF_ALLOWEFFECTS}, + {LPGENT("<< Incoming messages"), RGB(0, 0, 0), _T("MS Shell Dlg 2"), 0, -11, LPGENT("Incoming background"), FIDF_ALLOWEFFECTS}, + {LPGENT("Group list"), RGB(0, 0, 0), _T("MS Shell Dlg 2"), 0, -11, LPGENT("Group list background"), FIDF_DISABLESTYLES}, + {LPGENT("Find window"), RGB(0, 0, 0), _T("MS Shell Dlg 2"), 0, -11, LPGENT("Find window background"), FIDF_DISABLESTYLES}, +}; + +static ColorOptionsList g_ColorOptionsList[] = { + LPGENT("Outgoing background"), RGB(245,245,255), + LPGENT("Incoming background"), RGB(245,255,245), + LPGENT("Group list background"), GetSysColor(COLOR_3DFACE), + LPGENT("Window background"), GetSysColor(COLOR_3DFACE), + LPGENT("Contact list background"), GetSysColor(COLOR_3DFACE), + LPGENT("Find window background"), GetSysColor(COLOR_WINDOW), +}; + +static HotkeyOptionsList g_HotkeyOptionsList[] = { + { "basichistory_hot_showall", LPGENT("Open global history"), LPGENT("History"), MS_HISTORY_SHOWCONTACTHISTORY, HOTKEYCODE(HOTKEYF_CONTROL|HOTKEYF_SHIFT, 'H') | HKF_MIRANDA_LOCAL, 0 }, + { "basichistory_hot_find", LPGENT("Find"), LPGENT("History"), 0, HOTKEYCODE(HOTKEYF_CONTROL, 'F'), HISTORY_HK_FIND }, + { "basichistory_hot_findnext", LPGENT("Find Next"), LPGENT("History"), 0, VK_F3, HISTORY_HK_FINDNEXT }, + { "basichistory_hot_findprev", LPGENT("Find Previous"), LPGENT("History"), 0, VK_F2, HISTORY_HK_FINDPREV }, + { "basichistory_hot_matchcase", LPGENT("Switch Match Case"), LPGENT("History"), 0, 0, HISTORY_HK_MATCHCASE }, + { "basichistory_hot_matchwhole", LPGENT("Switch Match Whole Word"), LPGENT("History"), 0, 0, HISTORY_HK_MATCHWHOLE }, + { "basichistory_hot_showcontacts", LPGENT("Show/Hide Contacts"), LPGENT("History"), 0, 0, HISTORY_HK_SHOWCONTACTS }, + { "basichistory_hot_onlyin", LPGENT("Switch Only Incomming Messages"), LPGENT("History"), 0, 0, HISTORY_HK_ONLYIN }, + { "basichistory_hot_onlyout", LPGENT("Switch Only Outgoing Messages"), LPGENT("History"), 0, 0, HISTORY_HK_ONLYOUT }, + { "basichistory_hot_onlygroup", LPGENT("Switch Only Selected Group"), LPGENT("History"), 0, 0, HISTORY_HK_ONLYGROUP }, + { "basichistory_hot_allcontacts", LPGENT("Switch All Contacts"), LPGENT("History"), 0, 0, HISTORY_HK_ALLCONTACTS }, + { "basichistory_hot_delete", LPGENT("Delete"), LPGENT("History"), 0, VK_DELETE, HISTORY_HK_DELETE }, + { "basichistory_hot_exrhtml", LPGENT("Export To Rich Html"), LPGENT("History"), 0, 0, HISTORY_HK_EXRHTML }, + { "basichistory_hot_exphtml", LPGENT("Export To Plain Html"), LPGENT("History"), 0, 0, HISTORY_HK_EXPHTML }, + { "basichistory_hot_extxt", LPGENT("Export To Txt"), LPGENT("History"), 0, 0, HISTORY_HK_EXTXT }, + { "basichistory_hot_exbin", LPGENT("Export To Binary"), LPGENT("History"), 0, 0, HISTORY_HK_EXBIN }, + { "basichistory_hot_impbin", LPGENT("Import From Binary"), LPGENT("History"), 0, 0, HISTORY_HK_IMPBIN }, + { "basichistory_hot_exdat", LPGENT("Export To Dat (mContacts)"), LPGENT("History"), 0, 0, HISTORY_HK_EXDAT }, + { "basichistory_hot_impdat", LPGENT("Import From Dat (mContacts)"), LPGENT("History"), 0, 0, HISTORY_HK_IMPDAT }, +}; + +const int g_fontsSize = SIZEOF(g_FontOptionsList); + +const int g_colorsSize = SIZEOF(g_ColorOptionsList); + +const int g_hotkeysSize = SIZEOF(g_HotkeyOptionsList); + +void Options::Unload() +{ + DeleteCriticalSection(&criticalSection); +} + +void Options::Load(void) +{ + InitializeCriticalSection(&criticalSection); + FontIDT fid = {0}; + ColourIDT cid = {0}; + HOTKEYDESC hid = {0}; + fid.cbSize = sizeof(FontIDT); + cid.cbSize = sizeof(ColourIDT); + hid.cbSize = sizeof(HOTKEYDESC); + strncpy_s(fid.dbSettingsGroup, "BasicHistory_Fonts", SIZEOF(fid.dbSettingsGroup)); + _tcsncpy_s(fid.backgroundGroup, _T("History"), SIZEOF(fid.backgroundGroup)); + _tcsncpy_s(fid.group, LPGENT("History"), SIZEOF(fid.group)); + for(int i = 0; i < g_fontsSize; ++i) + { + fid.order = i; + _tcsncpy_s(fid.deffontsettings.szFace, g_FontOptionsList[i].szDefFace, LF_FACESIZE); + fid.deffontsettings.size = g_FontOptionsList[i].defSize; + fid.deffontsettings.colour = g_FontOptionsList[i].defColour; + fid.deffontsettings.style = g_FontOptionsList[i].defStyle; + fid.deffontsettings.charset = DEFAULT_CHARSET; + sprintf_s(fid.prefix, SIZEOF(fid.prefix), "Font%d", i); + _tcsncpy_s(fid.name, g_FontOptionsList[i].szDescr, SIZEOF(fid.name)); + _tcsncpy_s(fid.backgroundName, g_FontOptionsList[i].szBackgroundName, SIZEOF(fid.name)); + fid.flags = FIDF_DEFAULTVALID | FIDF_CLASSGENERAL | g_FontOptionsList[i].flags; + FontRegisterT(&fid); + } + + strncpy_s(cid.dbSettingsGroup, "BasicHistory_Fonts", SIZEOF(fid.dbSettingsGroup)); + _tcsncpy_s(cid.group, LPGENT("History"), SIZEOF(fid.group)); + for(int i = 0; i < g_colorsSize; ++i) + { + _tcsncpy_s(cid.name, g_ColorOptionsList[i].tszName, SIZEOF(cid.name)); + sprintf_s(cid.setting, SIZEOF(cid.setting), "Color%d", i); + cid.order = i; + cid.defcolour = g_ColorOptionsList[i].def; + ColourRegisterT(&cid); + } + + hid.dwFlags = HKD_TCHAR; + for(int i = 0; i < g_hotkeysSize; ++i) + { + hid.pszName = g_HotkeyOptionsList[i].pszName; + hid.ptszDescription = g_HotkeyOptionsList[i].ptszDescription; + hid.ptszSection = g_HotkeyOptionsList[i].ptszSection; + hid.pszService = g_HotkeyOptionsList[i].pszService; + hid.DefHotKey = g_HotkeyOptionsList[i].DefHotKey; + hid.lParam = g_HotkeyOptionsList[i].lParam; + Hotkey_Register(&hid); + } + + showContacts = DBGetContactSettingByte(0, MODULE, "showContacts", 0) ? true : false; + showContactGroups = DBGetContactSettingByte(0, MODULE, "showContactGroups", 1) ? true : false; + groupNewOnTop = DBGetContactSettingByte(0, MODULE, "groupNewOnTop", 1) ? true : false; + groupShowEvents = DBGetContactSettingByte(0, MODULE, "groupShowEvents", 1) ? true : false; + groupShowTime = DBGetContactSettingByte(0, MODULE, "groupShowTime", 1) ? true : false; + groupShowName = DBGetContactSettingByte(0, MODULE, "groupShowName", 0) ? true : false; + groupShowMessage = DBGetContactSettingByte(0, MODULE, "groupShowMessage", 1) ? true : false; + groupMessageLen = DBGetContactSettingDword(0, MODULE, "groupMessageLen", 43); + if(groupMessageLen < 5) groupMessageLen = 5; + groupTime = DBGetContactSettingDword(0, MODULE, "groupTime", 5); + if(groupTime < 1) groupTime = 1; + groupMessagesNumber = DBGetContactSettingDword(0, MODULE, "groupMessagesNumber", 100); + if(groupMessagesNumber < 1) groupMessagesNumber = 1; + messagesNewOnTop = DBGetContactSettingByte(0, MODULE, "messagesNewOnTop", 0) ? true : false; + messagesShowDate = DBGetContactSettingByte(0, MODULE, "messagesShowDate", 0) ? true : false; + messagesShowSec = DBGetContactSettingByte(0, MODULE, "messagesShowSec", 0) ? true : false; + messagesShowName = DBGetContactSettingByte(0, MODULE, "messagesShowName", 1) ? true : false; + messagesShowEvents = DBGetContactSettingByte(0, MODULE, "messagesShowEvents", 0) ? true : false; + messagesUseSmileys = DBGetContactSettingByte(0, MODULE, "messagesUseSmileys", 1) ? true : false; + searchForInList = DBGetContactSettingByte(0, MODULE, "searchForInList", 1) ? true : false; + searchForInMess = DBGetContactSettingByte(0, MODULE, "searchForInMess", 1) ? true : false; + searchMatchCase = DBGetContactSettingByte(0, MODULE, "searchMatchCase", 0) ? true : false; + searchMatchWhole = DBGetContactSettingByte(0, MODULE, "searchMatchWhole", 0) ? true : false; + searchOnlyIn = DBGetContactSettingByte(0, MODULE, "searchOnlyIn", 0) ? true : false; + searchOnlyOut = DBGetContactSettingByte(0, MODULE, "searchOnlyOut", 0) ? true : false; + searchOnlyGroup = DBGetContactSettingByte(0, MODULE, "searchOnlyGroup", 0) ? true : false; + searchAllContacts = DBGetContactSettingByte(0, MODULE, "searchAllContacts", 0) ? true : false; + schedulerAlerts = DBGetContactSettingByte(0, MODULE, "schedulerAlerts", 1) ? true : false; + schedulerHistoryAlerts = DBGetContactSettingByte(0, MODULE, "schedulerHistoryAlerts", 1) ? true : false; + + defFilter = DBGetContactSettingByte(0, MODULE, "defFilter", defFilter); + int filtersCount = DBGetContactSettingDword(0, MODULE, "customFiltersCount", 0); + for(int i = 0; i < filtersCount; ++i) + { + char buf[256]; + FilterOptions fo; + sprintf_s(buf, "filterName_%d", i); + DBVARIANT nameV; + if(!DBGetContactSettingWString(0, MODULE, buf, &nameV)) + { + fo.name = nameV.pwszVal; + DBFreeVariant(&nameV); + } + else break; + sprintf_s(buf, "filterInOut_%d", i); + int inOut = DBGetContactSettingByte(0, MODULE, buf, 0); + if(inOut == 1) + fo.onlyIncomming = true; + else if(inOut == 2) + fo.onlyOutgoing = true; + sprintf_s(buf, "filterEvents_%d", i); + DBVARIANT eventsV; + if(!DBGetContactSettingString(0, MODULE, buf, &eventsV)) + { + int k = 0; + char* id = eventsV.pszVal; + while(eventsV.pszVal[k]) + { + if(eventsV.pszVal[k] == ';') + { + eventsV.pszVal[k] = 0; + fo.events.push_back(strtol(id, NULL, 16)); + id = eventsV.pszVal + k + 1; + } + + ++k; + } + DBFreeVariant(&eventsV); + } + else break; + + customFilters.insert(customFilters.end(), fo); + } + + if(defFilter > 1) + { + defFilter = 0; + + DBVARIANT defFilterStrV; + if(!DBGetContactSettingWString(0, MODULE, "defFilterStr", &defFilterStrV)) + { + std::wstring filterName = defFilterStrV.pwszVal; + for(int i = 0; i < (int)customFilters.size(); ++i) + { + if(filterName == customFilters[i].name) + { + defFilter = i + 2; + break; + } + } + DBFreeVariant(&defFilterStrV); + } + } + + codepageTxt = DBGetContactSettingDword(0, MODULE, "codepageTxt", CP_UTF8); + codepageHtml1 = DBGetContactSettingDword(0, MODULE, "codepageHtml1", CP_UTF8); + codepageHtml2 = DBGetContactSettingDword(0, MODULE, "codepageHtml2", CP_UTF8); + DBVARIANT encodingV; + if(!DBGetContactSettingWString(0, MODULE, "encodingTxt", &encodingV)) + { + encodingTxt = encodingV.pwszVal; + DBFreeVariant(&encodingV); + } + else + { + encodingTxt = _T("UTF-8"); + } + if(!DBGetContactSettingWString(0, MODULE, "encodingHtml1", &encodingV)) + { + encodingHtml1 = encodingV.pwszVal; + DBFreeVariant(&encodingV); + } + else + { + encodingHtml1 = _T("UTF-8"); + } + if(!DBGetContactSettingWString(0, MODULE, "encodingHtml2", &encodingV)) + { + encodingHtml2 = encodingV.pwszVal; + DBFreeVariant(&encodingV); + } + else + { + encodingHtml2 = _T("UTF-8"); + } + + exportHtml1ShowDate = DBGetContactSettingByte(0, MODULE, "exportHtml1ShowDate", 1) ? true : false; + exportHtml2ShowDate = DBGetContactSettingByte(0, MODULE, "exportHtml2ShowDate", 0) ? true : false; + exportHtml2UseSmileys = DBGetContactSettingByte(0, MODULE, "exportHtml2UseSmileys", 1) ? true : false; + if(!DBGetContactSettingWString(0, MODULE, "extCssHtml2", &encodingV)) + { + extCssHtml2 = encodingV.pwszVal; + DBFreeVariant(&encodingV); + } + else + { + extCssHtml2 = _T(""); + } + + if(!DBGetContactSettingWString(0, MODULE, "ftpLogPath", &encodingV)) + { + ftpLogPath = encodingV.pwszVal; + DBFreeVariant(&encodingV); + } + + if(!DBGetContactSettingWString(0, MODULE, "ftpExePath", &encodingV)) + { + ftpExePath = encodingV.pwszVal; + DBFreeVariant(&encodingV); + } + else + { + ftpExePath = ftpExePathDef; + } + + LoadTasks(); +} + +COLORREF Options::GetFont(Fonts fontId, PLOGFONT font) +{ + FontIDT fid = {0}; + fid.cbSize = sizeof(FontIDT); + _tcsncpy_s(fid.group, LPGENT("History"), SIZEOF(fid.group)); + _tcsncpy_s(fid.name, g_FontOptionsList[fontId].szDescr, SIZEOF(fid.name)); + return (COLORREF)CallService(MS_FONT_GETT, (WPARAM)&fid, (LPARAM)font); +} + +COLORREF Options::GetColor(Colors colorId) +{ + ColourIDT cid = {0}; + cid.cbSize = sizeof(ColourIDT); + _tcsncpy_s(cid.group, LPGENT("History"), SIZEOF(cid.group)); + _tcsncpy_s(cid.name, g_ColorOptionsList[colorId].tszName, SIZEOF(cid.name)); + return (COLORREF)CallService(MS_COLOUR_GETT, (WPARAM)&cid, NULL); +} + +void Options::Save() +{ + DBWriteContactSettingByte(0, MODULE, "showContacts", showContacts ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "showContactGroups", showContactGroups ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "groupNewOnTop", groupNewOnTop ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "groupShowEvents", groupShowEvents ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "groupShowTime", groupShowTime ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "groupShowName", groupShowName ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "groupShowMessage", groupShowMessage ? 1 : 0); + if(groupMessageLen < 5) groupMessageLen = 5; + DBWriteContactSettingDword(0, MODULE, "groupMessageLen", groupMessageLen); + if(groupTime < 1) groupTime = 1; + DBWriteContactSettingDword(0, MODULE, "groupTime", groupTime); + if(groupMessagesNumber < 1) groupMessagesNumber = 1; + DBWriteContactSettingDword(0, MODULE, "groupMessagesNumber", groupMessagesNumber); + DBWriteContactSettingByte(0, MODULE, "messagesNewOnTop", messagesNewOnTop ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "messagesShowDate", messagesShowDate ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "messagesShowSec", messagesShowSec ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "messagesShowName", messagesShowName ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "messagesShowEvents", messagesShowEvents ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "messagesUseSmileys", messagesUseSmileys ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "searchForInList", searchForInList ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "searchForInMess", searchForInMess ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "searchMatchCase", searchMatchCase ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "searchMatchWhole", searchMatchWhole ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "searchOnlyIn", searchOnlyIn ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "searchOnlyOut", searchOnlyOut ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "searchOnlyGroup", searchOnlyGroup ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "searchAllContacts", searchAllContacts ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "schedulerAlerts", schedulerAlerts ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "schedulerHistoryAlerts", schedulerHistoryAlerts ? 1 : 0); + if(defFilter < 0 || defFilter - 2 >= (int)customFilters.size()) defFilter = 0; + DBWriteContactSettingByte(0, MODULE, "defFilter", defFilter < 2 ? defFilter : 2); + if(defFilter >= 2) + DBWriteContactSettingWString(0, MODULE, "defFilterStr", customFilters[defFilter - 2].name.c_str()); + DBWriteContactSettingDword(0, MODULE, "customFiltersCount", (DWORD)customFilters.size()); + for(int i = 0 ; i < (int)customFilters.size(); ++i) + { + char buf[256]; + sprintf_s(buf, "filterName_%d", i); + DBWriteContactSettingWString(0, MODULE, buf, customFilters[i].name.c_str()); + sprintf_s(buf, "filterInOut_%d", i); + DBWriteContactSettingByte(0, MODULE, buf, customFilters[i].onlyIncomming ? 1 : (customFilters[i].onlyOutgoing ? 2 : 0)); + std::string events; + for(std::vector::iterator it = customFilters[i].events.begin(); it != customFilters[i].events.end(); ++it) + { + _itoa_s(*it, buf, 16); + events += buf; + events += ";"; + } + + sprintf_s(buf, "filterEvents_%d", i); + DBWriteContactSettingString(0, MODULE, buf, events.c_str()); + } + + DBWriteContactSettingDword(0, MODULE, "codepageTxt", codepageTxt); + DBWriteContactSettingDword(0, MODULE, "codepageHtml1", codepageHtml1); + DBWriteContactSettingDword(0, MODULE, "codepageHtml2", codepageHtml2); + DBWriteContactSettingWString(0, MODULE, "encodingTxt", encodingTxt.c_str()); + DBWriteContactSettingWString(0, MODULE, "encodingHtml1", encodingHtml1.c_str()); + DBWriteContactSettingWString(0, MODULE, "encodingHtml2", encodingHtml2.c_str()); + DBWriteContactSettingByte(0, MODULE, "exportHtml1ShowDate", exportHtml1ShowDate ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "exportHtml2ShowDate", exportHtml2ShowDate ? 1 : 0); + DBWriteContactSettingByte(0, MODULE, "exportHtml2UseSmileys", exportHtml2UseSmileys ? 1 : 0); + DBWriteContactSettingWString(0, MODULE, "extCssHtml2", extCssHtml2.c_str()); + DBWriteContactSettingWString(0, MODULE, "ftpLogPath", ftpLogPath.c_str()); + if(ftpExePath != ftpExePathDef) + { + DBWriteContactSettingWString(0, MODULE, "ftpExePath", ftpExePath.c_str()); + } + else + { + DBDeleteContactSetting(0, MODULE, "ftpExePath"); + } +} + +void Options::SaveTasks(std::list* tasks) +{ + EnterCriticalSection(&criticalSection); + int oldTaskNr = (int)taskOptions.size(); + taskOptions.clear(); + int i = 0; + char buf[256]; + for(std::list::iterator it = tasks->begin(); it != tasks->end(); ++it) + { + sprintf_s(buf, "Task_compress_%d", i); + DBWriteContactSettingByte(0, MODULE, buf, it->compress); + sprintf_s(buf, "Task_useFtp_%d", i); + DBWriteContactSettingByte(0, MODULE, buf, it->useFtp); + sprintf_s(buf, "Task_isSystem_%d", i); + DBWriteContactSettingByte(0, MODULE, buf, it->isSystem); + sprintf_s(buf, "Task_active_%d", i); + DBWriteContactSettingByte(0, MODULE, buf, it->active); + sprintf_s(buf, "Task_exportImported_%d", i); + DBWriteContactSettingByte(0, MODULE, buf, it->exportImported); + sprintf_s(buf, "Task_type_%d", i); + DBWriteContactSettingByte(0, MODULE, buf, it->type); + sprintf_s(buf, "Task_eventUnit_%d", i); + DBWriteContactSettingByte(0, MODULE, buf, it->eventUnit); + sprintf_s(buf, "Task_trigerType_%d", i); + DBWriteContactSettingByte(0, MODULE, buf, it->trigerType); + sprintf_s(buf, "Task_exportType_%d", i); + DBWriteContactSettingByte(0, MODULE, buf, it->exportType); + sprintf_s(buf, "Task_importType_%d", i); + DBWriteContactSettingByte(0, MODULE, buf, it->importType); + sprintf_s(buf, "Task_eventDeltaTime_%d", i); + DBWriteContactSettingDword(0, MODULE, buf, it->eventDeltaTime); + sprintf_s(buf, "Task_filterId_%d", i); + DBWriteContactSettingDword(0, MODULE, buf, it->filterId); + sprintf_s(buf, "Task_dayTime_%d", i); + DBWriteContactSettingDword(0, MODULE, buf, it->dayTime); + sprintf_s(buf, "Task_dayOfWeek_%d", i); + DBWriteContactSettingDword(0, MODULE, buf, it->dayOfWeek); + sprintf_s(buf, "Task_dayOfMonth_%d", i); + DBWriteContactSettingDword(0, MODULE, buf, it->dayOfMonth); + sprintf_s(buf, "Task_deltaTime_%d", i); + DBWriteContactSettingDword(0, MODULE, buf, it->deltaTime); + sprintf_s(buf, "Task_lastExport_low_%d", i); + DBWriteContactSettingDword(0, MODULE, buf, (int)it->lastExport); + sprintf_s(buf, "Task_lastExport_hi_%d", i); + DBWriteContactSettingDword(0, MODULE, buf, ((unsigned long long int)it->lastExport) >> 32); + sprintf_s(buf, "Task_ftpName_%d", i); + DBWriteContactSettingWString(0, MODULE, buf, it->ftpName.c_str()); + sprintf_s(buf, "Task_filterName_%d", i); + DBWriteContactSettingWString(0, MODULE, buf, it->filterName.c_str()); + sprintf_s(buf, "Task_filePath_%d", i); + DBWriteContactSettingWString(0, MODULE, buf, it->filePath.c_str()); + sprintf_s(buf, "Task_taskName_%d", i); + DBWriteContactSettingWString(0, MODULE, buf, it->taskName.c_str()); + sprintf_s(buf, "Task_zipPassword_%d", i); + DBWriteContactSettingString(0, MODULE, buf, it->zipPassword.c_str()); + + HANDLE _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + sprintf_s(buf, "IsInTask_%d", i); + while(_hContact) + { + DBDeleteContactSetting(_hContact, MODULE, buf); + _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)_hContact, 0); + } + + for(size_t j = 0; j < it->contacts.size(); ++j) + { + DBWriteContactSettingByte(it->contacts[j], MODULE, buf, 1); + } + + it->orderNr = i++; + taskOptions.push_back(*it); + } + + DBWriteContactSettingDword(0, MODULE, "Task_count", i); + + for(i = (int)tasks->size(); i < oldTaskNr; ++i) + { + sprintf_s(buf, "Task_compress_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_useFtp_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_isSystem_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_active_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_type_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_eventUnit_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_trigerType_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_exportType_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_eventDeltaTime_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_filterId_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_dayTime_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_dayOfWeek_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_dayOfMonth_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_deltaTime_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_lastExport_low_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_lastExport_hi_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_ftpName_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_filterName_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_filePath_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + sprintf_s(buf, "Task_taskName_%d", i); + DBDeleteContactSetting(NULL, MODULE, buf); + + HANDLE _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + sprintf_s(buf, "IsInTask_%d", i); + while(_hContact) + { + DBDeleteContactSetting(_hContact, MODULE, buf); + _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)_hContact, 0); + } + } + + LeaveCriticalSection(&criticalSection); +} + +void Options::SaveTaskTime(TaskOptions& to) +{ + int i = to.orderNr; + char buf[256]; + sprintf_s(buf, "Task_lastExport_low_%d", i); + DBWriteContactSettingDword(0, MODULE, buf, (int)to.lastExport); + sprintf_s(buf, "Task_lastExport_hi_%d", i); + DBWriteContactSettingDword(0, MODULE, buf, ((unsigned long long int)to.lastExport) >> 32); +} + +void Options::LoadTasks() +{ + int taskCount = DBGetContactSettingDword(0, MODULE, "Task_count", 0); + char buf[256]; + for(int i = 0; i < taskCount; ++i) + { + TaskOptions to; + sprintf_s(buf, "Task_compress_%d", i); + to.compress = DBGetContactSettingByte(0, MODULE, buf, to.compress) != 0; + sprintf_s(buf, "Task_useFtp_%d", i); + to.useFtp = DBGetContactSettingByte(0, MODULE, buf, to.useFtp) != 0; + sprintf_s(buf, "Task_isSystem_%d", i); + to.isSystem = DBGetContactSettingByte(0, MODULE, buf, to.isSystem) != 0; + sprintf_s(buf, "Task_active_%d", i); + to.active = DBGetContactSettingByte(0, MODULE, buf, to.active) != 0; + sprintf_s(buf, "Task_exportImported_%d", i); + to.exportImported = DBGetContactSettingByte(0, MODULE, buf, to.exportImported) != 0; + sprintf_s(buf, "Task_type_%d", i); + to.type = (TaskOptions::TaskType)DBGetContactSettingByte(0, MODULE, buf, to.type); + sprintf_s(buf, "Task_eventUnit_%d", i); + to.eventUnit = (TaskOptions::EventUnit)DBGetContactSettingByte(0, MODULE, buf, to.eventUnit); + sprintf_s(buf, "Task_trigerType_%d", i); + to.trigerType = (TaskOptions::TrigerType)DBGetContactSettingByte(0, MODULE, buf, to.trigerType); + sprintf_s(buf, "Task_exportType_%d", i); + to.exportType = (IExport::ExportType)DBGetContactSettingByte(0, MODULE, buf, to.exportType); + sprintf_s(buf, "Task_importType_%d", i); + to.importType = (IImport::ImportType)DBGetContactSettingByte(0, MODULE, buf, to.importType); + sprintf_s(buf, "Task_eventDeltaTime_%d", i); + to.eventDeltaTime = DBGetContactSettingDword(0, MODULE, buf, to.eventDeltaTime); + sprintf_s(buf, "Task_filterId_%d", i); + to.filterId = DBGetContactSettingDword(0, MODULE, buf, to.filterId); + sprintf_s(buf, "Task_dayTime_%d", i); + to.dayTime = DBGetContactSettingDword(0, MODULE, buf, to.dayTime); + sprintf_s(buf, "Task_dayOfWeek_%d", i); + to.dayOfWeek = DBGetContactSettingDword(0, MODULE, buf, to.dayOfWeek); + sprintf_s(buf, "Task_dayOfMonth_%d", i); + to.dayOfMonth = DBGetContactSettingDword(0, MODULE, buf, to.dayOfMonth); + sprintf_s(buf, "Task_deltaTime_%d", i); + to.deltaTime = DBGetContactSettingDword(0, MODULE, buf, to.deltaTime); + unsigned long long int le = to.lastExport; + sprintf_s(buf, "Task_lastExport_low_%d", i); + to.lastExport = DBGetContactSettingDword(0, MODULE, buf, (int)le) & 0xffffffff; + sprintf_s(buf, "Task_lastExport_hi_%d", i); + to.lastExport |= ((unsigned long long int)DBGetContactSettingDword(0, MODULE, buf, le >> 32)) << 32; + sprintf_s(buf, "Task_ftpName_%d", i); + DBVARIANT var; + if(!DBGetContactSettingWString(0, MODULE, buf, &var)) + { + to.ftpName = var.ptszVal; + DBFreeVariant(&var); + } + sprintf_s(buf, "Task_filterName_%d", i); + if(!DBGetContactSettingWString(0, MODULE, buf, &var)) + { + to.filterName = var.ptszVal; + DBFreeVariant(&var); + } + sprintf_s(buf, "Task_filePath_%d", i); + if(!DBGetContactSettingWString(0, MODULE, buf, &var)) + { + to.filePath = var.ptszVal; + DBFreeVariant(&var); + } + sprintf_s(buf, "Task_taskName_%d", i); + if(!DBGetContactSettingWString(0, MODULE, buf, &var)) + { + to.taskName = var.ptszVal; + DBFreeVariant(&var); + } + sprintf_s(buf, "Task_zipPassword_%d", i); + if(!DBGetContactSettingString(0, MODULE, buf, &var)) + { + to.zipPassword = var.pszVal; + DBFreeVariant(&var); + } + + HANDLE _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + sprintf_s(buf, "IsInTask_%d", i); + while(_hContact) + { + if(DBGetContactSettingByte(_hContact, MODULE, buf, 0) == 1) + { + to.contacts.push_back(_hContact); + } + + _hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM)_hContact, 0); + } + + to.orderNr = i; + taskOptions.push_back(to); + } +} + +void OptionsMainChanged(); +void OptionsGroupChanged(); +void OptionsMessageChanged(); +void OptionsSearchingChanged(); +void OptionsSchedulerChanged(); +void InitTaskMenuItems(); + +void SetEventCB(HWND hwndCB, int eventId) +{ + int cpCount = SIZEOF(EventNames); + int selCpIdx = -1; + for(int i = 0; i < cpCount; ++i) + { + if(EventNames[i].id == eventId) + selCpIdx = i; + } + + if(selCpIdx == -1) + { + TCHAR buf[24]; + _stprintf_s(buf, 24, _T("%d"), eventId); + ComboBox_SetText(hwndCB, buf); + } + else + { + ComboBox_SetCurSel(hwndCB, selCpIdx); + } +} + +int GetEventCB(HWND hwndCB, bool errorReport, int &eventId) +{ + int selCpIdx = ComboBox_GetCurSel(hwndCB); + if(selCpIdx < 0) + { + TCHAR text[24]; + ComboBox_GetText(hwndCB, text, 24); + TCHAR * stopOn = NULL; + long cp = _tcstol(text, &stopOn, 10); + if(errorReport && (stopOn == text || *stopOn != '\0' || cp < 0)) + { + MessageBox(GetParent(hwndCB), TranslateT("Invalid event number"), TranslateT("Error"), MB_OK | MB_ICONERROR); + SetFocus(hwndCB); + return -1; + } + + eventId = cp; + } + else if(selCpIdx > 1) + eventId = EventNames[selCpIdx - 2].id; + else + return selCpIdx + 1; + + return 0; +} + +void ClearLB(HWND hwndLB) +{ + while(ListBox_GetCount(hwndLB) > 0) + ListBox_DeleteString(hwndLB, 0); +} + +void ReloadEventLB(HWND hwndLB, const FilterOptions &sel) +{ + while(ListBox_GetCount(hwndLB) > 0) + ListBox_DeleteString(hwndLB, 0); + if(sel.onlyIncomming && !sel.onlyOutgoing) + { + ListBox_AddString(hwndLB, TranslateT("Incoming events")); + } + else if(sel.onlyOutgoing && !sel.onlyIncomming) + { + ListBox_AddString(hwndLB, TranslateT("Outgoing events")); + } + + for(std::vector::const_iterator it = sel.events.begin(); it != sel.events.end(); ++it) + { + int cpCount = SIZEOF(EventNames); + int selCpIdx = -1; + for(int i = 0; i < cpCount; ++i) + { + if(EventNames[i].id == *it) + selCpIdx = i; + } + if(selCpIdx == -1) + { + TCHAR buf[24]; + _stprintf_s(buf, 24, _T("%d"), *it); + ListBox_AddString(hwndLB, buf); + } + else + { + ListBox_AddString(hwndLB, TranslateTS(EventNames[selCpIdx].name)); + } + } +} + +bool CheckFile(HWND hwndEdit) +{ + TCHAR buf[MAX_PATH]; + Edit_GetText(hwndEdit, buf, MAX_PATH); + DWORD atr = GetFileAttributes(buf); + if(atr == INVALID_FILE_ATTRIBUTES || atr & FILE_ATTRIBUTE_DIRECTORY) + { + MessageBox(GetParent(hwndEdit), TranslateT("File do not exist. Enter correct file path."), TranslateT("Invalid file"), MB_OK | MB_ICONERROR); + SetFocus(hwndEdit); + return false; + } + + return true; +} + +bool OpenFileDlg(HWND hwndDlg, HWND hwndEdit, const TCHAR* defName, const TCHAR* ext, const TCHAR* title, bool open) +{ + TCHAR filter[1024]; + std::locale loc; + TCHAR extUpper[32]; + _tcscpy_s(extUpper, ext); + extUpper[0] = std::toupper(ext[0], loc); + _stprintf_s(filter, TranslateT("%s Files (*.%s)"), extUpper, ext); + size_t len = _tcslen(filter) + 1; + _stprintf_s(filter + len, 1024 - len, _T("*.%s"), ext); + len += _tcslen(filter + len) + 1; + _tcscpy_s(filter + len, 1024 - len, TranslateT("All Files (*.*)")); + len += _tcslen(filter + len) + 1; + _tcscpy_s(filter + len, 1024 - len, _T("*.*")); + len += _tcslen(filter + len) + 1; + filter[len] = 0; + TCHAR stzFilePath[1024]; + + Edit_GetText(hwndEdit, stzFilePath, 1023); + if(stzFilePath[0] == 0) + { + _tcscpy_s(stzFilePath, defName); + len = _tcslen(stzFilePath) + 1; + stzFilePath[len] = 0; + } + else + { + len = _tcslen(stzFilePath) + 1; + stzFilePath[len] = 0; + } + + OPENFILENAME ofn = {0}; + ofn.lStructSize = sizeof(ofn); + ofn.hwndOwner = hwndDlg; + ofn.lpstrFilter = filter; + ofn.nFilterIndex = 1; + ofn.lpstrFile = stzFilePath; + ofn.lpstrTitle = title; + ofn.nMaxFile = 1024; + ofn.lpstrDefExt = ext; + if(open) + { + ofn.Flags = OFN_PATHMUSTEXIST | OFN_EXPLORER | OFN_NOCHANGEDIR | OFN_FILEMUSTEXIST | OFN_HIDEREADONLY; + if(GetOpenFileName(&ofn)) + { + Edit_SetText(hwndEdit, stzFilePath); + return true; + } + } + else + { + ofn.Flags = OFN_NOREADONLYRETURN | OFN_PATHMUSTEXIST | OFN_EXPLORER | OFN_NOCHANGEDIR; + if(GetSaveFileName(&ofn)) + { + Edit_SetText(hwndEdit, stzFilePath); + return true; + } + } + + return false; +} + +INT_PTR CALLBACK Options::DlgProcOptsMain(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)FALSE); + CheckDlgButton(hwndDlg, IDC_SHOWCONTACTS, instance->showContacts ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_SHOWCONTACTGROUPS, instance->showContactGroups ? 1 : 0); + HWND events = GetDlgItem(hwndDlg, IDC_EVENT); + HWND defFilter = GetDlgItem(hwndDlg, IDC_DEFFILTER); + HWND listFilter = GetDlgItem(hwndDlg, IDC_LIST_FILTERS); + HWND ftp = GetDlgItem(hwndDlg, IDC_WINSCP); + HWND ftpLog = GetDlgItem(hwndDlg, IDC_WINSCPLOG); + ComboBox_AddString(events, TranslateT("Incoming events")); + ComboBox_AddString(events, TranslateT("Outgoing events")); + for(int i = 0 ; i < SIZEOF(EventNames); ++i) + { + ComboBox_AddString(events, TranslateTS(EventNames[i].name)); + } + + ComboBox_AddString(defFilter, TranslateT("Default history events")); + ComboBox_AddString(defFilter, TranslateT("All events")); + Edit_LimitText(GetDlgItem(hwndDlg, IDC_FILTER_NAME), 20); + ComboBox_LimitText(events, 20); + + instance->customFiltersTemp.clear(); + instance->customFiltersTemp.insert(instance->customFiltersTemp.begin(), instance->customFilters.begin(), instance->customFilters.end()); + for(std::vector::iterator it = instance->customFiltersTemp.begin(); it != instance->customFiltersTemp.end(); ++it) + { + ComboBox_AddString(defFilter, it->name.c_str()); + ListBox_AddString(listFilter, it->name.c_str()); + } + ComboBox_SetCurSel(defFilter, instance->defFilter); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_FILTER), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_EVENT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ADD_EVENT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_EVENT), FALSE); + + Edit_LimitText(ftp, MAX_PATH); + Edit_LimitText(ftpLog, MAX_PATH); + Edit_SetText(ftp, instance->ftpExePath.c_str()); + Edit_SetText(ftpLog, instance->ftpLogPath.c_str()); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)TRUE); + return TRUE; + } + case WM_COMMAND: + { + BOOL init = (BOOL)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if (HIWORD(wParam) == BN_CLICKED) + { + HWND listFilter = GetDlgItem(hwndDlg, IDC_LIST_FILTERS); + HWND listEvents = GetDlgItem(hwndDlg, IDC_LIST_EVENTS); + HWND nameFilter = GetDlgItem(hwndDlg, IDC_FILTER_NAME); + HWND defFilter = GetDlgItem(hwndDlg, IDC_DEFFILTER); + HWND eventCB = GetDlgItem(hwndDlg, IDC_EVENT); + switch(LOWORD(wParam)) + { + case IDC_ADD_FILTER: + { + TCHAR name[24]; + Edit_GetText(nameFilter, name, 24); + if(name[0] == 0) + { + MessageBox(hwndDlg, TranslateT("Enter filter name"), TranslateT("Error"), MB_ICONERROR); + return TRUE; + } + + FilterOptions fo(name); + for(std::vector::iterator it = instance->customFiltersTemp.begin(); it != instance->customFiltersTemp.end(); ++it) + { + if(it->name == fo.name) + { + MessageBox(hwndDlg, TranslateT("Filter name exists"), TranslateT("Error"), MB_ICONERROR); + return TRUE; + } + } + + instance->customFiltersTemp.insert(instance->customFiltersTemp.end(), fo); + int i = ListBox_AddString(listFilter, name); + ListBox_SetCurSel(listFilter, i); + ComboBox_AddString(defFilter, name); + name[0] = 0; + Edit_SetText(nameFilter, name); + ReloadEventLB(listEvents, instance->customFiltersTemp[i]); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_FILTER), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_EVENT), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ADD_EVENT), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_EVENT), FALSE); + } + break; + case IDC_DELETE_FILTER: + { + int sel = ListBox_GetCurSel(listFilter); + if(sel < 0) + return TRUE; + for(size_t i = sel; i < instance->customFiltersTemp.size() - 1; ++i) + { + instance->customFiltersTemp[i] = instance->customFiltersTemp[i + 1]; + } + + instance->customFiltersTemp.resize(instance->customFiltersTemp.size() - 1); + ListBox_DeleteString(listFilter, sel); + ComboBox_DeleteString(defFilter, sel + 2); + if(ComboBox_GetCurSel(defFilter) < 0) + { + ComboBox_SetCurSel(defFilter, 0); + } + + ClearLB(listEvents); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_FILTER), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_EVENT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_ADD_EVENT), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_EVENT), FALSE); + } + break; + case IDC_ADD_EVENT: + { + int sel = ListBox_GetCurSel(listFilter); + if(sel < 0) + return TRUE; + int eventId; + int selCB = GetEventCB(eventCB, true, eventId); + if(selCB < 0) + return TRUE; + if(selCB == 1) + { + if(instance->customFiltersTemp[sel].onlyIncomming) + { + MessageBox(hwndDlg, TranslateT("Event already exists"), TranslateT("Error"), MB_ICONERROR); + return TRUE; + } + + if(instance->customFiltersTemp[sel].onlyOutgoing) + instance->customFiltersTemp[sel].onlyOutgoing = false; + else + instance->customFiltersTemp[sel].onlyIncomming = true; + } + else if(selCB == 2) + { + if(instance->customFiltersTemp[sel].onlyOutgoing) + { + MessageBox(hwndDlg, TranslateT("Event already exists"), TranslateT("Error"), MB_ICONERROR); + return TRUE; + } + + if(instance->customFiltersTemp[sel].onlyIncomming) + instance->customFiltersTemp[sel].onlyIncomming = false; + else + instance->customFiltersTemp[sel].onlyOutgoing = true; + } + else + { + if(std::find(instance->customFiltersTemp[sel].events.begin(), instance->customFiltersTemp[sel].events.end(), eventId) != instance->customFiltersTemp[sel].events.end()) + { + MessageBox(hwndDlg, TranslateT("Event already exists"), TranslateT("Error"), MB_ICONERROR); + return TRUE; + } + + instance->customFiltersTemp[sel].events.push_back(eventId); + } + + ReloadEventLB(listEvents, instance->customFiltersTemp[sel]); + ComboBox_SetCurSel(eventCB, -1); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_EVENT), FALSE); + } + break; + case IDC_DELETE_EVENT: + { + int sel = ListBox_GetCurSel(listFilter); + if(sel < 0) + return TRUE; + int eventSel = ListBox_GetCurSel(listEvents); + if(eventSel < 0) + return TRUE; + int stId = 0; + if(instance->customFiltersTemp[sel].onlyIncomming || instance->customFiltersTemp[sel].onlyOutgoing) + ++stId; + if(eventSel >= stId) + { + --eventSel; + for(int i = eventSel; i < (int)instance->customFiltersTemp[sel].events.size() - 1; ++i) + { + instance->customFiltersTemp[sel].events[i] = instance->customFiltersTemp[sel].events[i + 1]; + } + + instance->customFiltersTemp[sel].events.resize(instance->customFiltersTemp[sel].events.size() - 1); + } + else + { + instance->customFiltersTemp[sel].onlyIncomming = false; + instance->customFiltersTemp[sel].onlyOutgoing = false; + } + + ReloadEventLB(listEvents, instance->customFiltersTemp[sel]); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_EVENT), FALSE); + } + break; + case IDC_WINSCP_BROWSE: + if(!OpenFileDlg(hwndDlg, GetDlgItem(hwndDlg, IDC_WINSCP), _T("WinSCP.exe"), _T("exe"), TranslateT("Browse WinSCP file"), true)) + { + return TRUE; + } + + break; + case IDC_WINSCPLOG_BROWSE: + if(!OpenFileDlg(hwndDlg, GetDlgItem(hwndDlg, IDC_WINSCPLOG), _T("ftplog.txt"), _T("txt"), TranslateT("Save WinSCP log file"), false)) + { + return TRUE; + } + + break; + } + } + else if(HIWORD(wParam) == CBN_SELCHANGE && LOWORD(wParam) == IDC_LIST_FILTERS) + { + HWND listFilter = GetDlgItem(hwndDlg, IDC_LIST_FILTERS); + HWND listEvents = GetDlgItem(hwndDlg, IDC_LIST_EVENTS); + int sel = ListBox_GetCurSel(listFilter); + if(sel < 0) + ClearLB(listEvents); + else + ReloadEventLB(listEvents, instance->customFiltersTemp[sel]); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_FILTER), sel >= 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_EVENT), sel >= 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_ADD_EVENT), sel >= 0); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_EVENT), FALSE); + } + else if(HIWORD(wParam) == CBN_SELCHANGE && LOWORD(wParam) == IDC_LIST_EVENTS) + { + HWND listEvents = GetDlgItem(hwndDlg, IDC_LIST_EVENTS); + int sel = ListBox_GetCurSel(listEvents); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_EVENT), sel >= 0); + } + + if (init && (HIWORD(wParam) == BN_CLICKED || (HIWORD(wParam) == CBN_SELCHANGE && LOWORD(wParam) == IDC_DEFFILTER) || (HIWORD(wParam) == EN_CHANGE && LOWORD(wParam) != IDC_FILTER_NAME))) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + return TRUE; + } + case WM_NOTIFY: + { + if(((LPNMHDR)lParam)->code == PSN_APPLY) + { + HWND ftp = GetDlgItem(hwndDlg, IDC_WINSCP); + TCHAR buf[MAX_PATH]; + Edit_GetText(ftp, buf, MAX_PATH); + if(buf[0] != 0 && !CheckFile(ftp)) + { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); + return TRUE; + } + + instance->ftpExePath = buf; + Edit_GetText(GetDlgItem(hwndDlg, IDC_WINSCPLOG), buf, MAX_PATH); + instance->ftpLogPath = buf; + + instance->showContacts = IsDlgButtonChecked(hwndDlg, IDC_SHOWCONTACTS) ? true : false; + instance->showContactGroups = IsDlgButtonChecked(hwndDlg, IDC_SHOWCONTACTGROUPS) ? true : false; + instance->defFilter = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_DEFFILTER)); + instance->customFilters.clear(); + instance->customFilters.insert(instance->customFilters.begin(), instance->customFiltersTemp.begin(), instance->customFiltersTemp.end()); + Options::instance->Save(); + OptionsMainChanged(); + } + return TRUE; + } + } + + return FALSE; +} + +class OptsData +{ +public: + OptsData() + { + init = false; + } + + bool init; +}; + +INT_PTR CALLBACK Options::DlgProcOptsGroupList(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + OptsData* optsData = new OptsData(); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)optsData); + + CheckDlgButton(hwndDlg, IDC_NEWONTOP, instance->groupNewOnTop ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_SHOWEVENTS, instance->groupShowEvents ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_SHOWTIME, instance->groupShowTime ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_SHOWNAME, instance->groupShowName ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_SHOWMESSAGE, instance->groupShowMessage ? 1 : 0); + Edit_LimitText(GetDlgItem(hwndDlg, IDC_MESSAGELEN), 4); + SetDlgItemInt(hwndDlg, IDC_MESSAGELEN, instance->groupMessageLen, FALSE); + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_SHOWMESSAGE, BN_CLICKED), NULL); + Edit_LimitText(GetDlgItem(hwndDlg, IDC_GROUPTIME), 2); + Edit_LimitText(GetDlgItem(hwndDlg, IDC_LIMITMESSAGES), 3); + SetDlgItemInt(hwndDlg, IDC_GROUPTIME, instance->groupTime, FALSE); + SetDlgItemInt(hwndDlg, IDC_LIMITMESSAGES, instance->groupMessagesNumber, FALSE); + + optsData->init = true; + return TRUE; + } + case WM_COMMAND: + { + OptsData* optsData = (OptsData*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if(HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_SHOWMESSAGE) + { + if(IsDlgButtonChecked(hwndDlg, IDC_SHOWMESSAGE)) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_MESSAGELEN), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_MESSAGELEN_DESC), TRUE); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_MESSAGELEN), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_MESSAGELEN_DESC), FALSE); + } + } + if (optsData->init && (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam) == EN_CHANGE)) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + return TRUE; + } + case WM_NOTIFY: + { + if(((LPNMHDR)lParam)->code == PSN_APPLY) + { + instance->groupNewOnTop = IsDlgButtonChecked(hwndDlg, IDC_NEWONTOP) ? true : false; + instance->groupShowEvents = IsDlgButtonChecked(hwndDlg, IDC_SHOWEVENTS) ? true : false; + instance->groupShowTime = IsDlgButtonChecked(hwndDlg, IDC_SHOWTIME) ? true : false; + instance->groupShowName = IsDlgButtonChecked(hwndDlg, IDC_SHOWNAME) ? true : false; + instance->groupShowMessage = IsDlgButtonChecked(hwndDlg, IDC_SHOWMESSAGE) ? true : false; + BOOL success; + instance->groupMessageLen = GetDlgItemInt(hwndDlg, IDC_MESSAGELEN, &success, FALSE); + instance->groupTime = GetDlgItemInt(hwndDlg, IDC_GROUPTIME, &success, FALSE); + instance->groupMessagesNumber = GetDlgItemInt(hwndDlg, IDC_LIMITMESSAGES, &success, FALSE); + + Options::instance->Save(); + OptionsGroupChanged(); + } + return TRUE; + } + } + + return FALSE; +} + +INT_PTR CALLBACK Options::DlgProcOptsMessages(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + + CheckDlgButton(hwndDlg, IDC_NEWONTOP, instance->messagesNewOnTop ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_SHOWDATE, instance->messagesShowDate ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_SHOWSECOND, instance->messagesShowSec ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_SHOWNAME, instance->messagesShowName ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_SHOWEVENTS, instance->messagesShowEvents ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_SHOWSMILEYS, instance->messagesUseSmileys ? 1 : 0); + if(!g_SmileyAddAvail) + EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWSMILEYS), FALSE); + return TRUE; + } + case WM_COMMAND: + { + if (HIWORD(wParam) == BN_CLICKED) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + return TRUE; + } + case WM_NOTIFY: + { + if(((LPNMHDR)lParam)->code == PSN_APPLY) + { + instance->messagesNewOnTop = IsDlgButtonChecked(hwndDlg, IDC_NEWONTOP) ? true : false; + instance->messagesShowDate = IsDlgButtonChecked(hwndDlg, IDC_SHOWDATE) ? true : false; + instance->messagesShowSec = IsDlgButtonChecked(hwndDlg, IDC_SHOWSECOND) ? true : false; + instance->messagesShowName = IsDlgButtonChecked(hwndDlg, IDC_SHOWNAME) ? true : false; + instance->messagesShowEvents = IsDlgButtonChecked(hwndDlg, IDC_SHOWEVENTS) ? true : false; + instance->messagesUseSmileys = IsDlgButtonChecked(hwndDlg, IDC_SHOWSMILEYS) ? true : false; + + Options::instance->Save(); + OptionsMessageChanged(); + } + return TRUE; + } + } + + return FALSE; +} + +INT_PTR CALLBACK Options::DlgProcOptsSearching(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + + CheckDlgButton(hwndDlg, IDC_FORLIST, instance->searchForInList ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_FORMES, instance->searchForInMess ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_MATCHCASE, instance->searchMatchCase ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_MATCHWHOLE, instance->searchMatchWhole ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_ONLYIN, instance->searchOnlyIn ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_ONLYOUT, instance->searchOnlyOut ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_ONLYGROUP, instance->searchOnlyGroup ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_ALLCONTACTS, instance->searchAllContacts ? 1 : 0); + return TRUE; + } + case WM_COMMAND: + { + if(HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_ONLYIN) + { + if(IsDlgButtonChecked(hwndDlg, IDC_ONLYIN) && IsDlgButtonChecked(hwndDlg, IDC_ONLYOUT)) + { + CheckDlgButton(hwndDlg, IDC_ONLYOUT, 0); + } + } + else if(HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_ONLYOUT) + { + if(IsDlgButtonChecked(hwndDlg, IDC_ONLYOUT) && IsDlgButtonChecked(hwndDlg, IDC_ONLYIN)) + { + CheckDlgButton(hwndDlg, IDC_ONLYIN, 0); + } + } + + if (HIWORD(wParam) == BN_CLICKED) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + return TRUE; + } + case WM_NOTIFY: + { + if(((LPNMHDR)lParam)->code == PSN_APPLY) + { + instance->searchForInList = IsDlgButtonChecked(hwndDlg, IDC_FORLIST) ? true : false; + instance->searchForInMess = IsDlgButtonChecked(hwndDlg, IDC_FORMES) ? true : false; + instance->searchMatchCase = IsDlgButtonChecked(hwndDlg, IDC_MATCHCASE) ? true : false; + instance->searchMatchWhole = IsDlgButtonChecked(hwndDlg, IDC_MATCHWHOLE) ? true : false; + instance->searchOnlyIn = IsDlgButtonChecked(hwndDlg, IDC_ONLYIN) ? true : false; + instance->searchOnlyOut = IsDlgButtonChecked(hwndDlg, IDC_ONLYOUT) ? true : false; + instance->searchOnlyGroup = IsDlgButtonChecked(hwndDlg, IDC_ONLYGROUP) ? true : false; + instance->searchAllContacts = IsDlgButtonChecked(hwndDlg, IDC_ALLCONTACTS) ? true : false; + + Options::instance->Save(); + OptionsSearchingChanged(); + } + return TRUE; + } + } + + return FALSE; +} + +void InitCodepageCB(HWND hwndCB, unsigned int codepage, const std::wstring& name) +{ + int cpCount = sizeof(cpTable) / sizeof(cpTable[0]); + int selCpIdx = -1; + ComboBox_LimitText(hwndCB, 256); + for(int i = 0; i < cpCount; ++i) + { + ComboBox_AddString(hwndCB, TranslateTS(cpTable[i].cpName)); + if(cpTable[i].cpId == codepage && name == cpTable[i].cpName) + selCpIdx = i; + } + + if(selCpIdx == -1) + { + TCHAR buf[300]; + _stprintf_s(buf, 300, _T("%d;%s"), codepage, name.c_str()); + ComboBox_SetText(hwndCB, buf); + } + else + { + ComboBox_SetCurSel(hwndCB, selCpIdx); + } + + ComboBox_LimitText(hwndCB, 127); +} + +unsigned int GetCodepageCB(HWND hwndCB, bool errorReport, unsigned int defCp, const std::wstring& defName, std::wstring& name) +{ + int selCpIdx = ComboBox_GetCurSel(hwndCB); + if(selCpIdx < 0) + { + TCHAR text[128]; + ComboBox_GetText(hwndCB, text, 128); + std::wstring str = text; + name = _T(""); + size_t pos = str.find_first_of(_T(';')); + if(pos < str.length()) + { + text[pos] = 0; + name = str.substr(pos + 1); + } + + TCHAR * stopOn = NULL; + long cp = _tcstol(text, &stopOn, 10); + if((pos >= str.length() || name.empty() || stopOn == text || *stopOn != '\0' || cp < 0 || cp > 0xffff)) + { + if(errorReport) + { + MessageBox(GetParent(hwndCB), TranslateT("You've entered invalid codepage. Select codepage from combo box or enter correct number."), TranslateT("Invalid codepage"), MB_OK | MB_ICONERROR); + SetFocus(hwndCB); + } + + name = defName; + return -1; + } + + return cp; + } + else + { + name = cpTable[selCpIdx].cpName; + return cpTable[selCpIdx].cpId; + } +} + +INT_PTR CALLBACK Options::DlgProcOptsExport(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)FALSE); + InitCodepageCB(GetDlgItem(hwndDlg, IDC_TXTENC), instance->codepageTxt, instance->encodingTxt); + InitCodepageCB(GetDlgItem(hwndDlg, IDC_HTML1ENC), instance->codepageHtml1, instance->encodingHtml1); + InitCodepageCB(GetDlgItem(hwndDlg, IDC_HTML2ENC), instance->codepageHtml2, instance->encodingHtml2); + CheckDlgButton(hwndDlg, IDC_HTML1DATE, instance->exportHtml1ShowDate ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_HTML2DATE, instance->exportHtml2ShowDate ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_HTML2SHOWSMILEYS, instance->exportHtml2UseSmileys ? 1 : 0); + Edit_LimitText(GetDlgItem(hwndDlg, IDC_HTML2EXTCSSFILE), MAX_PATH); + if(instance->extCssHtml2.empty()) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_HTML2EXTCSSFILE), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_CSS_BROWSE), FALSE); + } + else + { + CheckDlgButton(hwndDlg, IDC_HTML2EXTCSS, TRUE); + Edit_SetText(GetDlgItem(hwndDlg, IDC_HTML2EXTCSSFILE), instance->extCssHtml2.c_str()); + } + + if(!g_SmileyAddAvail) + EnableWindow(GetDlgItem(hwndDlg, IDC_HTML2SHOWSMILEYS), FALSE); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)TRUE); + return TRUE; + } + case WM_COMMAND: + { + BOOL init = (BOOL)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + if(HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_HTML2EXTCSS) + { + BOOL en = (BOOL)IsDlgButtonChecked(hwndDlg, IDC_HTML2EXTCSS); + EnableWindow(GetDlgItem(hwndDlg, IDC_HTML2EXTCSSFILE), en); + EnableWindow(GetDlgItem(hwndDlg, IDC_CSS_BROWSE), en); + } + else if(HIWORD(wParam) == BN_CLICKED && LOWORD(wParam) == IDC_CSS_BROWSE) + { + if(!OpenFileDlg(hwndDlg, GetDlgItem(hwndDlg, IDC_HTML2EXTCSSFILE), _T(""), _T("css"), TranslateT("Browse CSS file"), true)) + { + return TRUE; + } + } + + if (init && (HIWORD(wParam) == BN_CLICKED || HIWORD(wParam)==CBN_SELCHANGE || HIWORD(wParam)==CBN_EDITCHANGE || HIWORD(wParam) == EN_CHANGE)) + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + return TRUE; + } + case WM_NOTIFY: + { + if(((LPNMHDR)lParam)->code == PSN_APPLY) + { + std::wstring newName1, newName2, newName3; + unsigned int cp1 = GetCodepageCB(GetDlgItem(hwndDlg, IDC_TXTENC), true, instance->codepageTxt, instance->encodingTxt, newName1); + if(cp1 == -1) + { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); + return TRUE; + } + unsigned int cp2 = GetCodepageCB(GetDlgItem(hwndDlg, IDC_HTML1ENC), true, instance->codepageHtml1, instance->encodingHtml1, newName2); + if(cp2 == -1) + { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); + return TRUE; + } + unsigned int cp3 = GetCodepageCB(GetDlgItem(hwndDlg, IDC_HTML2ENC), true, instance->codepageHtml2, instance->encodingHtml2, newName3); + if(cp3 == -1) + { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); + return TRUE; + } + if(IsDlgButtonChecked(hwndDlg, IDC_HTML2EXTCSS)) + { + if(!CheckFile(GetDlgItem(hwndDlg, IDC_HTML2EXTCSSFILE))) + { + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, PSNRET_INVALID_NOCHANGEPAGE); + return TRUE; + } + + TCHAR buf[MAX_PATH]; + Edit_GetText(GetDlgItem(hwndDlg, IDC_HTML2EXTCSSFILE), buf, MAX_PATH); + instance->extCssHtml2 = buf; + } + else + { + instance->extCssHtml2 = _T(""); + } + + instance->codepageTxt = cp1; + instance->encodingTxt = newName1; + instance->codepageHtml1 = cp2; + instance->encodingHtml1 = newName2; + instance->codepageHtml2 = cp3; + instance->encodingHtml2 = newName3; + instance->exportHtml1ShowDate = IsDlgButtonChecked(hwndDlg, IDC_HTML1DATE) ? true : false; + instance->exportHtml2ShowDate = IsDlgButtonChecked(hwndDlg, IDC_HTML2DATE) ? true : false; + instance->exportHtml2UseSmileys = IsDlgButtonChecked(hwndDlg, IDC_HTML2SHOWSMILEYS) ? true : false; + + Options::instance->Save(); + } + return TRUE; + } + } + + return FALSE; +} + + +struct DlgTaskOpt +{ + std::list* tasks; + TaskOptions* to; +}; + +INT_PTR CALLBACK Options::DlgProcOptsScheduler(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + switch(msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + std::list* tasks = new std::list(Options::instance->taskOptions.begin(), Options::instance->taskOptions.end()); + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, (LONG_PTR)tasks); + HWND listTasks = GetDlgItem(hwndDlg, IDC_LIST_TASKS); + for(std::list::iterator it = tasks->begin(); it != tasks->end(); ++it) + { + ListBox_AddString(listTasks, it->taskName.c_str()); + } + + if(!bPopupsEnabled) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_SCHEDULER_ALERTS), FALSE); + } + + CheckDlgButton(hwndDlg, IDC_SCHEDULER_ALERTS, instance->schedulerAlerts ? 1 : 0); + CheckDlgButton(hwndDlg, IDC_SCHEDULER_HISTORY_ALERTS, instance->schedulerHistoryAlerts ? 1 : 0); + + EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT_TASK), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_TASK), FALSE); + return TRUE; + } + case WM_COMMAND: + { + if(HIWORD(wParam) == BN_CLICKED) + { + std::list* tasks = (std::list*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + HWND listTasks = GetDlgItem(hwndDlg, IDC_LIST_TASKS); + int sel = ListBox_GetCurSel(listTasks); + TaskOptions toAdd; + TaskOptions* to = &toAdd; + switch(LOWORD(wParam)) + { + case IDC_EDIT_TASK: + if(sel >= 0) + { + std::list::iterator it = tasks->begin(); + while(sel-- > 0 && it != tasks->end()) + ++it; + if(it == tasks->end()) + break; + to = &(*it); + } + else + break; + case IDC_ADD_TASK: + { + DlgTaskOpt top; + top.tasks = tasks; + top.to = to; + if(DialogBoxParam(hInst, MAKEINTRESOURCE(IDD_DLG_TASK), hwndDlg, DlgProcOptsTask, (LPARAM)&top) == IDOK) + { + if(LOWORD(wParam) == IDC_ADD_TASK) + { + tasks->push_back(*to); + ListBox_AddString(listTasks, to->taskName.c_str()); + ListBox_SetCurSel(listTasks, tasks->size() - 1); + } + else + { + sel = ListBox_GetCurSel(listTasks); + ListBox_DeleteString(listTasks, sel); + ListBox_InsertString(listTasks, sel, to->taskName.c_str()); + ListBox_SetCurSel(listTasks, sel); + } + EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT_TASK), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_TASK), TRUE); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + + break; + case IDC_DELETE_TASK: + if(sel >= 0) + { + ListBox_DeleteString(listTasks, sel); + std::list::iterator it = tasks->begin(); + while(sel-- > 0 && it != tasks->end()) + ++it; + if(it != tasks->end()) + tasks->erase(it); + EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT_TASK), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_TASK), FALSE); + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + + break; + default: + SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0); + } + } + else if(HIWORD(wParam) == CBN_SELCHANGE && LOWORD(wParam) == IDC_LIST_TASKS) + { + HWND listTasks = GetDlgItem(hwndDlg, IDC_LIST_TASKS); + int sel = ListBox_GetCurSel(listTasks); + if(sel < 0) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT_TASK), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_TASK), FALSE); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_EDIT_TASK), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_DELETE_TASK), TRUE); + } + } + return TRUE; + } + case WM_NOTIFY: + { + if(((LPNMHDR)lParam)->code == PSN_APPLY) + { + std::list* tasks = (std::list*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + instance->schedulerAlerts = IsDlgButtonChecked(hwndDlg, IDC_SCHEDULER_ALERTS) ? true : false; + instance->schedulerHistoryAlerts = IsDlgButtonChecked(hwndDlg, IDC_SCHEDULER_HISTORY_ALERTS) ? true : false; + Options::instance->SaveTasks(tasks); + OptionsSchedulerChanged(); + InitTaskMenuItems(); + } + return TRUE; + } + case WM_DESTROY: + { + std::list* tasks = (std::list*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + delete tasks; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, NULL); + break; + } + } + + return FALSE; +} + +void ResetListOptions(HWND hwnd) +{ + SendMessage(hwnd, CLM_SETGREYOUTFLAGS, 0, 0); + SendMessage(hwnd, CLM_SETLEFTMARGIN, 2, 0); + SendMessage(hwnd, CLM_SETBKBITMAP, 0, (LPARAM)(HBITMAP) NULL); + SendMessage(hwnd, CLM_SETBKCOLOR, GetSysColor(COLOR_WINDOW), 0); + SendMessage(hwnd, CLM_SETINDENT, 10, 0); + for (int i = 0; i <= FONTID_MAX; i++) + SendMessage(hwnd, CLM_SETTEXTCOLOR, i, GetSysColor(COLOR_WINDOWTEXT)); +} + +void RebuildList(HWND hwnd, HANDLE hSystem, TaskOptions* to) +{ + HANDLE hItem; + if(to->isSystem && hSystem) + { + SendMessage(hwnd, CLM_SETCHECKMARK, (WPARAM) hSystem, 1); + } + + for(size_t i = 0; i < to->contacts.size(); ++i) + { + hItem = (HANDLE) SendMessage(hwnd, CLM_FINDCONTACT, (WPARAM) to->contacts[i], 0); + if (hItem) + SendMessage(hwnd, CLM_SETCHECKMARK, (WPARAM) hItem, 1); + } +} + +void SaveList(HWND hwnd, HANDLE hSystem, TaskOptions* to) +{ + HANDLE hContact, hItem; + + to->contacts.clear(); + if (hSystem) + to->isSystem = SendMessage(hwnd, CLM_GETCHECKMARK, (WPARAM) hSystem, 0) != 0; + hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDFIRST, 0, 0); + do + { + hItem = (HANDLE) SendMessage(hwnd, CLM_FINDCONTACT, (WPARAM) hContact, 0); + if (hItem && SendMessage(hwnd, CLM_GETCHECKMARK, (WPARAM) hItem, 0)) + to->contacts.push_back(hContact); + } + while (hContact = (HANDLE) CallService(MS_DB_CONTACT_FINDNEXT, (WPARAM) hContact, 0)); +} + +bool IsValidTask(TaskOptions& to, std::list* top = NULL, std::wstring* err = NULL, std::wstring* errDescr = NULL); + +#ifndef LOCALE_SSHORTTIME +#define LOCALE_SSHORTTIME 0x00000079 +#endif + +INT_PTR CALLBACK Options::DlgProcOptsTask(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static HANDLE hSystem; + switch(msg) + { + case WM_INITDIALOG: + { + TranslateDialogDefault(hwndDlg); + DlgTaskOpt* top = (DlgTaskOpt*)lParam; + TaskOptions* to = top->to; + SetWindowLongPtr(hwndDlg, GWLP_USERDATA, lParam); + HWND comboType = GetDlgItem(hwndDlg, IDC_TASK_TYPE); + HWND filter = GetDlgItem(hwndDlg, IDC_TASK_FILTER); + HWND eventUnit = GetDlgItem(hwndDlg, IDC_EVENT_UNIT); + HWND trigerType = GetDlgItem(hwndDlg, IDC_TRIGER_TYPE); + HWND exportType = GetDlgItem(hwndDlg, IDC_EXPORT_TYPE); + HWND importType = GetDlgItem(hwndDlg, IDC_IMPORT_TYPE); + HWND compress = GetDlgItem(hwndDlg, IDC_COMPRESS); + HWND exportPath = GetDlgItem(hwndDlg, IDC_EXPORT_PATH); + HWND ftpFile = GetDlgItem(hwndDlg, IDC_FTP); + HWND ftpFileButton = GetDlgItem(hwndDlg, IDC_UPLOAD); + HWND contactList = GetDlgItem(hwndDlg, IDC_LIST_CONTACTSEX); + HWND weekList = GetDlgItem(hwndDlg, IDC_TRIGER_WEEK); + HWND day = GetDlgItem(hwndDlg, IDC_TRIGER_DAY); + HWND deltaTime = GetDlgItem(hwndDlg, IDC_TRIGER_DELTA_TIME); + HWND time = GetDlgItem(hwndDlg, IDC_TRIGER_TIME); + HWND name = GetDlgItem(hwndDlg, IDC_TASK_NAME); + HWND active = GetDlgItem(hwndDlg, IDC_TASK_ACTIVE); + HWND star = GetDlgItem(hwndDlg, IDC_TASK_STAR); + HWND password = GetDlgItem(hwndDlg, IDC_PASSWORD); + HWND expImp = GetDlgItem(hwndDlg, IDC_EXPIMP); + + Edit_LimitText(name, 16); + Edit_SetText(name, to->taskName.c_str()); + + Button_SetCheck(active, to->active); + + Button_SetCheck(expImp, to->exportImported); + + ComboBox_AddString(comboType, TranslateT("Export")); + ComboBox_AddString(comboType, TranslateT("Delete")); + ComboBox_AddString(comboType, TranslateT("Export and Delete")); + ComboBox_AddString(comboType, TranslateT("Import")); + ComboBox_AddString(comboType, TranslateT("Import and Marge")); + ComboBox_SetCurSel(comboType, to->type); + + Edit_LimitText(GetDlgItem(hwndDlg, IDC_EVENT_TIME), 6); + SetDlgItemInt(hwndDlg, IDC_EVENT_TIME, to->eventDeltaTime, TRUE); + ComboBox_AddString(eventUnit, TranslateT("Minute")); + ComboBox_AddString(eventUnit, TranslateT("Hour")); + ComboBox_AddString(eventUnit, TranslateT("Day")); + ComboBox_SetCurSel(eventUnit, to->eventUnit); + + ComboBox_AddString(filter, TranslateT("Default history events")); + ComboBox_AddString(filter, TranslateT("All events")); + int selFilter = to->filterId; + if(selFilter > 1) + selFilter = 0; + int i = 1; + for(std::vector::iterator it = instance->customFilters.begin(); it != instance->customFilters.end(); ++it) + { + ++i; + ComboBox_AddString(filter, it->name.c_str()); + if(to->filterId > 1 && it->name == to->filterName) + { + selFilter = i; + } + } + ComboBox_SetCurSel(filter, selFilter); + + ComboBox_AddString(trigerType, TranslateT("At Start")); + ComboBox_AddString(trigerType, TranslateT("At Finish")); + ComboBox_AddString(trigerType, TranslateT("Daily")); + ComboBox_AddString(trigerType, TranslateT("Weekly")); + ComboBox_AddString(trigerType, TranslateT("Monthly")); + ComboBox_AddString(trigerType, TranslateT("Delta time (minutes)")); + ComboBox_AddString(trigerType, TranslateT("Delta time (hours)")); + ComboBox_SetCurSel(trigerType, to->trigerType); + + ComboBox_AddString(exportType, TranslateT("Rich Html")); + ComboBox_AddString(exportType, TranslateT("Plain Html")); + ComboBox_AddString(exportType, TranslateT("Txt")); + ComboBox_AddString(exportType, TranslateT("Binary")); + ComboBox_AddString(exportType, TranslateT("Dat (mContacts)")); + ComboBox_SetCurSel(exportType, to->exportType); + + ComboBox_AddString(importType, TranslateT("Binary")); + ComboBox_AddString(importType, TranslateT("Dat (mContacts)")); + ComboBox_SetCurSel(importType, to->importType); + + Button_SetCheck(compress, to->compress); + Edit_LimitText(password, 99); + SetWindowTextA(password, to->zipPassword.c_str()); + + Edit_LimitText(exportPath, MAX_PATH); + Edit_SetText(exportPath, to->filePath.c_str()); + + if(!FTPAvail()) + { + EnableWindow(ftpFile, FALSE); + EnableWindow(ftpFileButton, FALSE); + to->useFtp = false; + } + + Button_SetCheck(ftpFileButton, to->useFtp); + Edit_SetText(ftpFile, to->ftpName.c_str()); + + ComboBox_AddString(weekList, TranslateT("Monday")); + ComboBox_AddString(weekList, TranslateT("Tuesday")); + ComboBox_AddString(weekList, TranslateT("Wednesday")); + ComboBox_AddString(weekList, TranslateT("Thursday")); + ComboBox_AddString(weekList, TranslateT("Friday")); + ComboBox_AddString(weekList, TranslateT("Saturday")); + ComboBox_AddString(weekList, TranslateT("Sunday")); + ComboBox_SetCurSel(weekList, to->dayOfWeek); + + Edit_LimitText(day, 2); + SetDlgItemInt(hwndDlg, IDC_TRIGER_DAY, to->dayOfMonth, FALSE); + + Edit_LimitText(deltaTime, 4); + SetDlgItemInt(hwndDlg, IDC_TRIGER_DELTA_TIME, to->deltaTime, FALSE); + + TCHAR timeFormat[10]; + if(GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_SSHORTTIME, timeFormat, 10) == 0) + { + TCHAR sep = _T(':'); + if(GetLocaleInfo(LOCALE_USER_DEFAULT, LOCALE_STIME, timeFormat, 10) > 0) + sep = timeFormat[0]; + _stprintf_s(timeFormat, _T("HH%cmm"), sep); + } + + SYSTEMTIME st; + GetSystemTime (&st); + st.wHour = to->dayTime/60; + st.wMinute = to->dayTime%60; + st.wSecond = 0; + st.wMilliseconds = 0; + DateTime_SetFormat(time, timeFormat); + DateTime_SetSystemtime(time, GDT_VALID, &st); + + CLCINFOITEM cii = { 0 }; + cii.cbSize = sizeof(cii); + cii.flags = CLCIIF_GROUPFONT | CLCIIF_CHECKBOX | CLCIIF_BELOWCONTACTS; + cii.pszText = TranslateT("System"); + hSystem = (HANDLE) SendMessage(contactList, CLM_ADDINFOITEM, 0, (LPARAM) & cii); + SendMessage(contactList, CLM_AUTOREBUILD, 0, 0); + ResetListOptions(contactList); + RebuildList(contactList, hSystem, to); + + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_TASK_TYPE, CBN_SELCHANGE), NULL); + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_TRIGER_TYPE, CBN_SELCHANGE), NULL); + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_COMPRESS, BN_CLICKED), NULL); + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_UPLOAD, BN_CLICKED), NULL); + SendMessage(hwndDlg, WM_COMMAND, MAKEWPARAM(IDC_COMPRESS, BN_CLICKED), NULL); + return TRUE; + } + case WM_COMMAND: + { + if (HIWORD(wParam) == BN_CLICKED) + { + if (LOWORD(wParam) == IDOK) + { + DlgTaskOpt* top = (DlgTaskOpt*)GetWindowLongPtr(hwndDlg, GWLP_USERDATA); + TaskOptions* to = top->to; + TaskOptions toCp(*to); + toCp.taskName.resize(17); + int nameLen = Edit_GetText(GetDlgItem(hwndDlg, IDC_TASK_NAME), (wchar_t*)toCp.taskName.c_str(), 17); + toCp.taskName.resize(nameLen); + toCp.active = Button_GetCheck(GetDlgItem(hwndDlg, IDC_TASK_ACTIVE)) != 0; + toCp.exportImported = Button_GetCheck(GetDlgItem(hwndDlg, IDC_EXPIMP)) != 0; + toCp.type = (enum TaskOptions::TaskType)ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_TASK_TYPE)); + toCp.filterId = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_TASK_FILTER)); + if(toCp.filterId > 1) + toCp.filterName = instance->customFilters[toCp.filterId - 2].name; + BOOL isOK = FALSE; + toCp.eventDeltaTime = GetDlgItemInt(hwndDlg, IDC_EVENT_TIME, &isOK, TRUE); + if(!isOK) + { + TCHAR msg[256]; + _stprintf_s(msg, TranslateT("Invalid '%s' value."), TranslateT("Events older than")); + MessageBox(hwndDlg, msg, TranslateT("Error"), MB_ICONERROR); + break; + } + toCp.eventUnit = (enum TaskOptions::EventUnit)ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_EVENT_UNIT)); + toCp.trigerType = (enum TaskOptions::TrigerType)ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_TRIGER_TYPE)); + toCp.exportType = (enum IExport::ExportType)ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_EXPORT_TYPE)); + toCp.importType = (enum IImport::ImportType)ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_IMPORT_TYPE)); + toCp.compress = Button_GetCheck(GetDlgItem(hwndDlg, IDC_COMPRESS)) != 0; + char bufC[100]; + GetWindowTextA(GetDlgItem(hwndDlg, IDC_PASSWORD), bufC, 100); + toCp.zipPassword = bufC; + HWND exportPath = GetDlgItem(hwndDlg, IDC_EXPORT_PATH); + int exLen = Edit_GetTextLength(exportPath); + toCp.filePath.resize(exLen + 1); + Edit_GetText(exportPath, (wchar_t*)toCp.filePath.c_str(), exLen + 1); + toCp.filePath.resize(exLen); + toCp.useFtp = Button_GetCheck(GetDlgItem(hwndDlg, IDC_UPLOAD)) != 0; + HWND ftpFile = GetDlgItem(hwndDlg, IDC_FTP); + exLen = Edit_GetTextLength(ftpFile); + toCp.ftpName.resize(exLen + 1); + Edit_GetText(ftpFile, (wchar_t*)toCp.ftpName.c_str(), exLen + 1); + toCp.ftpName.resize(exLen); + SYSTEMTIME st; + DateTime_GetSystemtime(GetDlgItem(hwndDlg, IDC_TRIGER_TIME), &st); + toCp.dayTime = st.wHour * 60 + st.wMinute; + toCp.dayOfWeek = ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_TRIGER_WEEK)); + toCp.dayOfMonth = GetDlgItemInt(hwndDlg, IDC_TRIGER_DAY, &isOK, FALSE); + if(!isOK) + { + if(toCp.trigerType == TaskOptions::Monthly) + { + TCHAR msg[256]; + _stprintf_s(msg, TranslateT("Invalid '%s' value."), TranslateT("Day")); + MessageBox(hwndDlg, msg, TranslateT("Error"), MB_ICONERROR); + break; + } + else + toCp.dayOfMonth = to->dayOfMonth; + } + toCp.deltaTime = GetDlgItemInt(hwndDlg, IDC_TRIGER_DELTA_TIME, &isOK, FALSE); + if(!isOK) + { + if(toCp.trigerType == TaskOptions::DeltaMin || toCp.trigerType == TaskOptions::DeltaHour) + { + TCHAR msg[256]; + _stprintf_s(msg, TranslateT("Invalid '%s' value."), TranslateT("Delta time")); + MessageBox(hwndDlg, msg, TranslateT("Error"), MB_ICONERROR); + break; + } + else + toCp.deltaTime = to->deltaTime; + } + SaveList(GetDlgItem(hwndDlg, IDC_LIST_CONTACTSEX), hSystem, &toCp); + std::wstring err; + std::wstring errDescr; + std::wstring lastName = to->taskName; + to->taskName = L""; + if(!IsValidTask(toCp, top->tasks, &err, &errDescr)) + { + to->taskName = lastName; + TCHAR msg[256]; + if(err.empty()) + _tcscpy_s(msg, TranslateT("Some value is invalid")); + else if(errDescr.empty()) + { + _stprintf_s(msg, TranslateT("Invalid '%s' value."), err.c_str()); + } + else + { + _stprintf_s(msg, TranslateT("Invalid '%s' value.\n%s"), err.c_str(), errDescr.c_str()); + } + + MessageBox(hwndDlg, msg, TranslateT("Error"), MB_ICONERROR); + break; + } + + toCp.lastExport = time(NULL); + + *to = toCp; + EndDialog(hwndDlg, IDOK); + } + else if (LOWORD(wParam) == IDCANCEL) + { + EndDialog(hwndDlg, IDCANCEL); + } + else if (LOWORD(wParam) == IDC_UPLOAD) + { + if(Button_GetCheck(GetDlgItem(hwndDlg, IDC_UPLOAD)) == 0) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_FTP), FALSE); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_FTP), TRUE); + } + } + else if(LOWORD(wParam) == IDC_COMPRESS) + { + if(Button_GetCheck(GetDlgItem(hwndDlg, IDC_COMPRESS)) == 0) + { + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), FALSE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD_LABEL), FALSE); + } + else + { + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), TRUE); + EnableWindow(GetDlgItem(hwndDlg, IDC_PASSWORD_LABEL), TRUE); + } + } + } + else if (HIWORD(wParam) == CBN_SELCHANGE) + { + if(LOWORD(wParam) == IDC_TASK_TYPE) + { + TaskOptions::TaskType sel = (enum TaskOptions::TaskType)ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_TASK_TYPE)); + int show = sel == TaskOptions::Delete ? SW_HIDE : SW_SHOW; + int showFilter = (sel == TaskOptions::Import || sel == TaskOptions::ImportAndMarge) ? SW_HIDE : SW_SHOW; + int showImport = (sel == TaskOptions::Import || sel == TaskOptions::ImportAndMarge) ? SW_SHOW : SW_HIDE; + ShowWindow(GetDlgItem(hwndDlg, IDC_EXPORT_TYPE), show); + ShowWindow(GetDlgItem(hwndDlg, IDC_EXPORT_TYPE_LABEL), show); + ShowWindow(GetDlgItem(hwndDlg, IDC_COMPRESS), show); + ShowWindow(GetDlgItem(hwndDlg, IDC_PASSWORD), show); + ShowWindow(GetDlgItem(hwndDlg, IDC_PASSWORD_LABEL), show); + ShowWindow(GetDlgItem(hwndDlg, IDC_EXPORT_PATH), show); + ShowWindow(GetDlgItem(hwndDlg, IDC_EXPORT_PATH_LABEL), show); + ShowWindow(GetDlgItem(hwndDlg, IDC_FTP), show); + ShowWindow(GetDlgItem(hwndDlg, IDC_UPLOAD), show); + ShowWindow(GetDlgItem(hwndDlg, IDC_FTP_LABEL), show); + ShowWindow(GetDlgItem(hwndDlg, IDC_EXPIMP), show); + ShowWindow(GetDlgItem(hwndDlg, IDC_TASK_FILTER), showFilter); + ShowWindow(GetDlgItem(hwndDlg, IDC_TASK_FILTER_LABEL), showFilter); + ShowWindow(GetDlgItem(hwndDlg, IDC_EVENT_TIME), showFilter); + ShowWindow(GetDlgItem(hwndDlg, IDC_EVENT_UNIT), showFilter); + ShowWindow(GetDlgItem(hwndDlg, IDC_EVENT_LABEL), showFilter); + if(show != showFilter) + { + ShowWindow(GetDlgItem(hwndDlg, IDC_EXPORT_TYPE), SW_HIDE); + ShowWindow(GetDlgItem(hwndDlg, IDC_EXPIMP), SW_HIDE); + } + + ShowWindow(GetDlgItem(hwndDlg, IDC_IMPORT_TYPE), showImport); + std::wstring str; + TCHAR* compressText = TranslateT("Compress output files"); + TCHAR* uploadText = TranslateT("Upload to FTP (WinSCP requred)"); + TCHAR* typeText = TranslateT("Export to"); + if(showFilter == SW_HIDE) + { + str = TranslateT("** Use to insert extension, to insert contact name"); + compressText = TranslateT("Input files are compressed"); + uploadText = TranslateT("Download from FTP (WinSCP requred)"); + typeText = TranslateT("Import from"); + } + else if(show == SW_HIDE) + { + str = TranslateT("* Use negative values to filter younger events"); + } + else + { + str = TranslateT("* Use negative values to filter younger events"); + str += _T("\n"); + str += TranslateT("** Use to insert date, to insert extension, to insert contact name"); + } + + Static_SetText(GetDlgItem(hwndDlg, IDC_TASK_STAR), str.c_str()); + Button_SetText(GetDlgItem(hwndDlg, IDC_COMPRESS), compressText); + Button_SetText(GetDlgItem(hwndDlg, IDC_UPLOAD), uploadText); + Static_SetText(GetDlgItem(hwndDlg, IDC_EXPORT_TYPE_LABEL), typeText); + } + else if(LOWORD(wParam) == IDC_TRIGER_TYPE) + { + TaskOptions::TrigerType sel = (enum TaskOptions::TrigerType)ComboBox_GetCurSel(GetDlgItem(hwndDlg, IDC_TRIGER_TYPE)); + int showT = (sel == TaskOptions::Daily || sel == TaskOptions::Weekly || sel == TaskOptions::Monthly) ? SW_SHOW : SW_HIDE; + int showW = sel == TaskOptions::Weekly ? SW_SHOW : SW_HIDE; + int showM = sel == TaskOptions::Monthly ? SW_SHOW : SW_HIDE; + int showDT = (sel == TaskOptions::DeltaMin || sel == TaskOptions::DeltaHour) ? SW_SHOW : SW_HIDE; + ShowWindow(GetDlgItem(hwndDlg, IDC_TRIGER_TIME), showT); + ShowWindow(GetDlgItem(hwndDlg, IDC_TRIGER_TIME_LABEL), showT); + ShowWindow(GetDlgItem(hwndDlg, IDC_TRIGER_WEEK), showW); + ShowWindow(GetDlgItem(hwndDlg, IDC_TRIGER_WEEK_LABEL), showW); + ShowWindow(GetDlgItem(hwndDlg, IDC_TRIGER_DAY), showM); + ShowWindow(GetDlgItem(hwndDlg, IDC_TRIGER_DAY_LABEL), showM); + ShowWindow(GetDlgItem(hwndDlg, IDC_TRIGER_DELTA_TIME), showDT); + ShowWindow(GetDlgItem(hwndDlg, IDC_TRIGER_DELTA_TIME_LABEL), showDT); + } + } + return TRUE; + } + case WM_NOTIFY: + { + NMHDR* nmhdr = (NMHDR *) lParam; + if (nmhdr->idFrom == IDC_LIST_CONTACTSEX && nmhdr->code == CLN_OPTIONSCHANGED) + { + ResetListOptions(hwndDlg); + } + + return TRUE; + } + } + + return FALSE; +} + +bool Options::FTPAvail() +{ + DWORD atr = GetFileAttributes(instance->ftpExePath.c_str()); + return !(atr == INVALID_FILE_ATTRIBUTES || atr & FILE_ATTRIBUTE_DIRECTORY); +} diff --git a/plugins/BasicHistory/src/Options.h b/plugins/BasicHistory/src/Options.h new file mode 100644 index 0000000000..4a5d17229c --- /dev/null +++ b/plugins/BasicHistory/src/Options.h @@ -0,0 +1,199 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once +#include "IImport.h" +#include "IExport.h" + +struct FilterOptions +{ + FilterOptions() + :onlyIncomming(false), + onlyOutgoing(false) + { + } + + FilterOptions(const std::wstring& _name) + :name(_name), + onlyIncomming(false), + onlyOutgoing(false) + { + } + + std::wstring name; + std::vector events; + bool onlyIncomming; + bool onlyOutgoing; +}; + +struct TaskOptions +{ + bool compress; + bool useFtp; + bool isSystem; + bool active; + bool forceExecute; + bool showMBAfterExecute; + bool exportImported; + enum TaskType + { + Export, + Delete, + ExportAndDelete, + Import, + ImportAndMarge + } type; + + enum EventUnit + { + Minute, + Hour, + Day + } eventUnit; + + enum TrigerType + { + AtStart, + AtEnd, + Daily, + Weekly, + Monthly, + DeltaMin, + DeltaHour + } trigerType; + + IExport::ExportType exportType; + IImport::ImportType importType; + int eventDeltaTime; + int filterId; + int dayTime; + int dayOfWeek; + int dayOfMonth; + int deltaTime; + int orderNr; + time_t lastExport; + std::wstring ftpName; + std::wstring filterName; + std::wstring filePath; + std::wstring taskName; + std::string zipPassword; // char* because zip file using ANSI password + std::vector contacts; + TaskOptions() + { + forceExecute = false; + showMBAfterExecute = false; + exportImported = true; + type = Export; + eventUnit = Hour; + trigerType = AtStart; + exportType = IExport::RichHtml; + importType = IImport::Binary; + eventDeltaTime = 0; + filterId = 0; + compress = true; + useFtp = false; + isSystem = false; + active = true; + dayTime = 20 * 60; + dayOfWeek = 0; + dayOfMonth = 1; + deltaTime = 24; + orderNr = 0; + TCHAR buf[MAX_PATH]; + if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, buf))) + { + filePath = buf; + filePath += _T("\\"); + } + + filePath += TranslateT("History"); + filePath += _T("__."); + lastExport = time(NULL); + } +}; + +class Options +{ +private: + std::vector customFiltersTemp; +public: + Options(); + ~Options(); + static int InitOptions(WPARAM wParam, LPARAM lParam); + + static INT_PTR CALLBACK DlgProcOptsMain(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK DlgProcOptsGroupList(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK DlgProcOptsMessages(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK DlgProcOptsSearching(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK DlgProcOptsExport(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK DlgProcOptsScheduler(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + static INT_PTR CALLBACK DlgProcOptsTask(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam); + static bool FTPAvail(); + + static Options *instance; + void Save(); + void SaveTasks(std::list* tasks); + void SaveTaskTime(TaskOptions& to); + void Load(void); + void LoadTasks(); + void Unload(); + + bool showContacts, showContactGroups, groupNewOnTop, groupShowEvents, groupShowTime, groupShowName, groupShowMessage; + bool messagesNewOnTop, messagesShowDate, messagesShowSec, messagesShowName, messagesShowEvents, messagesUseSmileys; + bool searchForInList, searchForInMess, searchMatchCase, searchMatchWhole, searchOnlyIn, searchOnlyOut, searchOnlyGroup, searchAllContacts; + bool schedulerAlerts, schedulerHistoryAlerts; + int groupMessageLen, groupTime, groupMessagesNumber; + + std::vector customFilters; + int defFilter; + unsigned int codepageTxt, codepageHtml1, codepageHtml2; + std::wstring encodingTxt, encodingHtml1, encodingHtml2; + bool exportHtml1ShowDate, exportHtml2ShowDate, exportHtml2UseSmileys; + std::wstring extCssHtml2; + std::vector taskOptions; + std::wstring ftpLogPath; + std::wstring ftpExePathDef; + std::wstring ftpExePath; + CRITICAL_SECTION criticalSection; + + enum Fonts + { + OutTimestamp = 0, + InTimestamp, + OutName, + InName, + OutMessages, + InMessages, + GroupList, + Find, + }; + + enum Colors + { + OutBackground = 0, + InBackground, + GroupListBackground, + WindowBackground, + ContactListBackground, + FindBackground, + }; + + COLORREF GetFont(Fonts fontId, PLOGFONT font); + COLORREF GetColor(Colors colorId); +}; + diff --git a/plugins/BasicHistory/src/PlainHtmlExport.cpp b/plugins/BasicHistory/src/PlainHtmlExport.cpp new file mode 100644 index 0000000000..050b4e457e --- /dev/null +++ b/plugins/BasicHistory/src/PlainHtmlExport.cpp @@ -0,0 +1,106 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#include "StdAfx.h" +#include "PlainHtmlExport.h" +#include "Options.h" +#define EXP_FILE (*stream) + +PlainHtmlExport::~PlainHtmlExport() +{ +} + +extern std::wstring MakeTextHtmled(const std::wstring& message, std::queue >* positionMap = NULL); +extern std::wstring UrlHighlightHtml(const std::wstring& message, bool& isUrl); + +void PlainHtmlExport::WriteHeader(const std::wstring &fileName, const std::wstring &filterName, const std::wstring &myName, const std::wstring &myId, const std::wstring &name1, const std::wstring &proto1, const std::wstring &id1, const std::string& baseProto1, const std::wstring& encoding) +{ + EXP_FILE << _T("\n"); + EXP_FILE << _T("\n\n"); + EXP_FILE << _T("") << TranslateT("History Log") << _T(" [") << MakeTextHtmled(myName) << _T("] - [") << MakeTextHtmled(name1) << _T("]\n"); + EXP_FILE << _T("\n\n

") << TranslateT("History Log") << _T("

\n

"); + EXP_FILE << MakeTextHtmled(myName); + if(proto1.length() || myId.length()) + { + EXP_FILE << _T(" (") << MakeTextHtmled(proto1) << _T(": ") << MakeTextHtmled(myId) << _T(") - "); + } + else + { + EXP_FILE << _T(" - "); + } + + EXP_FILE << MakeTextHtmled(name1); + if(proto1.length() || id1.length()) + { + EXP_FILE << _T(" (") << MakeTextHtmled(proto1) << _T(": ") << MakeTextHtmled(id1) << _T(")

\n"); + } + else + { + EXP_FILE << _T("\n"); + } + + EXP_FILE << _T("
") << TranslateT("Filter:") << _T(" ") << MakeTextHtmled(filterName) << _T("
\n"); +} + +void PlainHtmlExport::WriteFooter() +{ + EXP_FILE << _T("
\n\n"); +} + +void PlainHtmlExport::WriteGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText) +{ + TCHAR buf[256]; + EXP_FILE << _T("
\n"); + _stprintf_s(buf, TranslateT("Conversation started at %s"), time.c_str()); + EXP_FILE << _T("
") << buf << _T("
\n"); + EXP_FILE << _T("
\n"); +} + +void PlainHtmlExport::WriteMessage(bool isMe, const std::wstring &longDate, const std::wstring &shortDate, const std::wstring &user, const std::wstring &message, const DBEVENTINFO& dbei) +{ + TCHAR *id = isMe ? _T("out") : _T("inc"); + TCHAR* ev = (isMe ? _T("1") : _T("0")); + bool isUrl = false; + std::wstring& mes = UrlHighlightHtml(MakeTextHtmled(message), isUrl); + if(isUrl) + ev = _T("2"); + EXP_FILE << _T("
\n"); + EXP_FILE << _T("
") << MakeTextHtmled(user) << _T(":
\n"); + EXP_FILE << _T("
") << (Options::instance->exportHtml1ShowDate ? longDate : shortDate) << _T("
\n"); + EXP_FILE << _T("
\n"); + EXP_FILE << mes; + EXP_FILE << _T("\n
\n"); + EXP_FILE << _T("
\n"); +} diff --git a/plugins/BasicHistory/src/PlainHtmlExport.h b/plugins/BasicHistory/src/PlainHtmlExport.h new file mode 100644 index 0000000000..bb1c971ea3 --- /dev/null +++ b/plugins/BasicHistory/src/PlainHtmlExport.h @@ -0,0 +1,37 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once +#include "IExport.h" +class PlainHtmlExport : + public IExport +{ +public: + virtual const TCHAR* GetExt() + { + return _T("html"); + } + + virtual void WriteHeader(const std::wstring &fileName, const std::wstring &filterName, const std::wstring &myName, const std::wstring &myId, const std::wstring &name1, const std::wstring &proto1, const std::wstring &id1, const std::string& baseProto1, const std::wstring& encoding); + virtual void WriteFooter(); + virtual void WriteGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText); + virtual void WriteMessage(bool isMe, const std::wstring &longDate, const std::wstring &shortDate, const std::wstring &user, const std::wstring &message, const DBEVENTINFO& dbei); + + virtual ~PlainHtmlExport(); +}; + diff --git a/plugins/BasicHistory/src/RichHtmlExport.cpp b/plugins/BasicHistory/src/RichHtmlExport.cpp new file mode 100644 index 0000000000..5a772a4914 --- /dev/null +++ b/plugins/BasicHistory/src/RichHtmlExport.cpp @@ -0,0 +1,545 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#include "StdAfx.h" +#include "RichHtmlExport.h" +#include "Options.h" +#include "resource.h" +#define EXP_FILE (*stream) + +RichHtmlExport::~RichHtmlExport() +{ +} + +extern HINSTANCE hInst; +extern HANDLE *hEventIcons; +extern HANDLE hPlusExIcon, hMinusExIcon; +extern bool g_SmileyAddAvail; + +std::wstring MakeTextHtmled(const std::wstring& message, std::queue >* positionMap = NULL) +{ + std::wstring ret; + std::wstring search = _T("&<>\t\r\n"); + size_t start = 0; + size_t find; + size_t currentAdd = 0; + while((find = message.find_first_of(search, start)) < message.length()) + { + ret += message.substr(start, find - start); + switch(message[find]) + { + case _T('&'): + ret += _T("&"); + break; + case _T('<'): + ret += _T("<"); + break; + case _T('>'): + ret += _T(">"); + break; + case _T('\t'): + ret += _T(" "); + break; + case _T('\n'): + ret += _T("
"); + break; + } + + start = find + 1; + if(positionMap != NULL) + { + size_t len = ret.length() - start - currentAdd; + if(len != 0) + { + positionMap->push(std::pair(start + currentAdd, len)); + currentAdd += len; + } + } + } + + ret += message.substr(start, message.length() - start); + return ret; +} + +std::wstring UrlHighlightHtml(const std::wstring& message, bool& isUrl) +{ + std::wstring ret; + std::wstring htmlStop = _T("\'\" []<>\r\n"); + std::wstring search = _T("://"); + size_t start = 0; + size_t find; + while((find = message.find(search, start)) < message.length()) + { + size_t urlStart = message.find_last_of(htmlStop, find); + size_t urlEnd = message.find_first_of(htmlStop, find + 3); + if(urlStart >= message.length()) + urlStart = -1; + if(urlEnd >= message.length()) + urlEnd = message.length(); + if(((int)urlEnd -3 - (int)find > 0) && ((int)find - (int)urlStart -1 > 0)) + { + ret += message.substr(start, (urlStart + 1) - start); + std::wstring url = message.substr(urlStart + 1, urlEnd - urlStart - 1); + start = urlEnd; + ret += _T("") + url + _T(""); + isUrl = true; + } + else + { + ret += message.substr(start, (find + 3) - start); + start = find + 3; + } + } + + ret += message.substr(start, message.length() - start); + return ret; +} + +std::wstring RemoveExt(const std::wstring &fileName) +{ + size_t find = fileName.find_last_of(L'.'); + if(find < fileName.length()) + { + return fileName.substr(0, find); + } + + return fileName; +} + +std::wstring GetName(const std::wstring &path) +{ + size_t find = path.find_last_of(L"\\/"); + if(find < path.length()) + { + return path.substr(find + 1); + } + + return path; +} + +void ExtractFile(short int res, const std::wstring &fileName) +{ + HRSRC rSrc = FindResource(hInst, MAKEINTRESOURCE(res), MAKEINTRESOURCE(CUSTOMRES)); + if(rSrc != NULL) + { + HGLOBAL res = LoadResource(hInst, rSrc); + int size = SizeofResource(hInst, rSrc); + if(res != NULL) + { + char* resData = (char*)LockResource(res); + if(resData != NULL) + { + std::ofstream stream (fileName.c_str(), std::ios_base::binary); + if(stream.is_open()) + { + stream.write(resData, size); + stream.close(); + } + } + + FreeResource(res); + } + } +} + +#pragma pack(push, 2) +typedef struct +{ + BYTE bWidth; // Width, in pixels, of the image + BYTE bHeight; // Height, in pixels, of the image + BYTE bColorCount; // Number of colors in image (0 if >=8bpp) + BYTE bReserved; // Reserved ( must be 0) + WORD wPlanes; // Color Planes + WORD wBitCount; // Bits per pixel + DWORD dwBytesInRes; // How many bytes in this resource? + DWORD dwImageOffset; // Where in the file is this image? +} ICONDIRENTRY, *LPICONDIRENTRY; + +typedef struct +{ + WORD idReserved; // Reserved (must be 0) + WORD idType; // Resource Type (1 for icons) + WORD idCount; // How many images? + //ICONDIRENTRY idEntries; // An entry for each image (idCount of 'em) +} ICONDIR, *LPICONDIR; + +#pragma pack(pop) + +typedef struct tagMyBITMAPINFO { + BITMAPINFOHEADER bmiHeader; + RGBQUAD bmiColors[256]; +} MYBITMAPINFO; + +void IcoSave(const std::wstring &fileName, HICON hicon) +{ + std::ofstream store (fileName.c_str(), std::ios_base::binary); + if(!store.is_open()) + return; + ICONINFO ii; + if(!GetIconInfo(hicon,&ii)) + { + store.close(); + return; + } + + HBITMAP hbmMask = ii.hbmMask; + HBITMAP hbmColor = ii.hbmColor; + BITMAP bmiMask; + BITMAP bmiColor; + if( + GetObject(hbmColor,sizeof(bmiColor),&bmiColor) && + GetObject(hbmMask,sizeof(bmiMask),&bmiMask) && + (bmiColor.bmWidth==bmiMask.bmWidth) && + (bmiColor.bmHeight==bmiMask.bmHeight) && + (bmiMask.bmHeight) > 0 && + (bmiMask.bmWidth) > 0 + ) + { + BITMAPINFOHEADER icobmi = {0}; + MYBITMAPINFO info1 = {0}; + MYBITMAPINFO info2 = {0}; + + HDC hDC = CreateCompatibleDC(NULL); + info1.bmiHeader.biSize = sizeof(info1.bmiHeader); + info1.bmiHeader.biWidth = bmiColor.bmWidth; + info1.bmiHeader.biHeight = bmiColor.bmHeight; + info1.bmiHeader.biPlanes = 1; + info1.bmiHeader.biBitCount = bmiColor.bmBitsPixel; + unsigned int size = GetDIBits(hDC,hbmColor,0,info1.bmiHeader.biHeight,NULL,(BITMAPINFO*)&info1,DIB_RGB_COLORS); + char* bits1 = new char[info1.bmiHeader.biSizeImage]; + size = GetDIBits(hDC,hbmColor,0,info1.bmiHeader.biHeight,bits1,(BITMAPINFO*)&info1,DIB_RGB_COLORS); + info2.bmiHeader.biSize = sizeof(info2.bmiHeader); + info2.bmiHeader.biWidth = bmiMask.bmWidth; + info2.bmiHeader.biHeight = bmiMask.bmHeight; + info2.bmiHeader.biPlanes = 1; + info2.bmiHeader.biBitCount = bmiMask.bmBitsPixel; + size = GetDIBits(hDC,hbmColor,0,info1.bmiHeader.biHeight,NULL,(BITMAPINFO*)&info2,DIB_RGB_COLORS); + char* bits2 = new char[info2.bmiHeader.biSizeImage]; + size = GetDIBits(hDC,hbmMask,0,info2.bmiHeader.biHeight,bits2,(BITMAPINFO*)&info2,DIB_RGB_COLORS); + + ICONDIR icodir; + ICONDIRENTRY icoent; + icodir.idReserved = 0; + icodir.idType = 1; + icodir.idCount = 1; + + icoent.bWidth = (unsigned char)bmiColor.bmWidth; + icoent.bHeight = (unsigned char)bmiColor.bmHeight; + icoent.bColorCount = 8<=bmiColor.bmBitsPixel?0:1<extCssHtml2.empty()) + { + cssCopied = CopyFile(Options::instance->extCssHtml2.c_str(), css.c_str(), FALSE); + } + + if(!cssCopied) + ExtractFile(IDR_CSS, css); + ExtractFile(IDR_JS, folder + _T("\\history.js")); + + HICON ico = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)hPlusExIcon); + IcoSave(folder + _T("\\pnode.ico"), ico); + CallService(MS_SKIN2_RELEASEICON, (LPARAM)ico, 0); + ico = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)hMinusExIcon); + IcoSave(folder + _T("\\mnode.ico"), ico); + CallService(MS_SKIN2_RELEASEICON, (LPARAM)ico, 0); + ico = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)hEventIcons[0]); + IcoSave(folder + _T("\\event0.ico"), ico); + CallService(MS_SKIN2_RELEASEICON, (LPARAM)ico, 0); + ico = (HICON)CallService(MS_SKIN2_GETICONBYHANDLE, 0, (LPARAM)hEventIcons[1]); + IcoSave(folder + _T("\\event1.ico"), ico); + CallService(MS_SKIN2_RELEASEICON, (LPARAM)ico, 0); + + EXP_FILE << _T("\n"); + EXP_FILE << _T("\n\n"); + EXP_FILE << _T("") << TranslateT("History Log") << _T(" [") << MakeTextHtmled(myName) << _T("] - [") << MakeTextHtmled(name1) << _T("]\n"); + EXP_FILE << _T("\n"); + EXP_FILE << _T("\n"); + EXP_FILE << _T("\n"); + + EXP_FILE << _T("\n"); + EXP_FILE << _T("") << TranslateT("Menu") << _T("\n"); + EXP_FILE << _T("\n"); + EXP_FILE << _T("\n"); + EXP_FILE << _T("\n"); + EXP_FILE << _T("
\n"); + EXP_FILE << _T("\n"); + + EXP_FILE << _T("

") << TranslateT("History Log") << _T("

\n

"); + EXP_FILE << MakeTextHtmled(myName); + if(proto1.length() || myId.length()) + { + EXP_FILE << _T(" (") << MakeTextHtmled(proto1) << _T(": ") << MakeTextHtmled(myId) << _T(") - "); + } + else + { + EXP_FILE << _T(" - "); + } + + EXP_FILE << MakeTextHtmled(name1); + if(proto1.length() || id1.length()) + { + EXP_FILE << _T(" (") << MakeTextHtmled(proto1) << _T(": ") << MakeTextHtmled(id1) << _T(")

\n"); + } + else + { + EXP_FILE << _T("\n"); + } + + EXP_FILE << _T("
") << TranslateT("Filter:") << _T(" ") << MakeTextHtmled(filterName) << _T("
\n"); + groupId = 0; +} + +void RichHtmlExport::WriteFooter() +{ + if(groupId > 0) + { + EXP_FILE << _T("\n"); + } + + EXP_FILE << _T("
\n\n"); +} + +void RichHtmlExport::WriteGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText) +{ + TCHAR *id = isMe ? _T("out") : _T("inc"); + TCHAR* ev = (isMe ? _T("1") : _T("0")); + if(groupId > 0) + { + EXP_FILE << _T("\n"); + } + + bool isUrl = false; + std::wstring& mes = ReplaceSmileys(isMe, eventText, isUrl); + EXP_FILE << _T("
\n"); + EXP_FILE << _T(""); + EXP_FILE << _T("\n"); + EXP_FILE << _T("") << time << _T("\n\n") << mes; + EXP_FILE << _T("\n
\n"); + EXP_FILE << _T("
\n"); + ++groupId; +} + +void RichHtmlExport::WriteMessage(bool isMe, const std::wstring &longDate, const std::wstring &shortDate, const std::wstring &user, const std::wstring &message, const DBEVENTINFO& dbei) +{ + TCHAR *id = isMe ? _T("out") : _T("inc"); + TCHAR* ev = (isMe ? _T("1") : _T("0")); + TCHAR* ev1 = ev; + bool isUrl = false; + std::wstring& mes = ReplaceSmileys(isMe, message, isUrl); + if(isUrl) + ev = _T("2"); + EXP_FILE << _T("
\n"); + EXP_FILE << _T("
") << _T("
\n"); + EXP_FILE << _T("
") << (Options::instance->exportHtml2ShowDate ? longDate : shortDate) << _T("
\n"); + EXP_FILE << _T("
") << MakeTextHtmled(user) << _T("
\n"); + EXP_FILE << _T("
\n"); + EXP_FILE << mes; + EXP_FILE << _T("\n
\n"); + EXP_FILE << _T("
\n"); +} + +std::wstring RichHtmlExport::ReplaceSmileys(bool isMe, const std::wstring &msg, bool &isUrl) +{ + if(Options::instance->exportHtml2UseSmileys && g_SmileyAddAvail) + { + TCHAR* msgbuf = new TCHAR[msg.length() + 1]; + memcpy_s(msgbuf, (msg.length() + 1) * sizeof(TCHAR), msg.c_str(), (msg.length() + 1) * sizeof(TCHAR)); + SMADD_BATCHPARSE2 sp = {0}; + SMADD_BATCHPARSERES *spr; + sp.cbSize = sizeof(sp); + sp.Protocolname = baseProto.length() == 0 ? NULL : baseProto.c_str(); + sp.str = msgbuf; + sp.flag = SAFL_TCHAR | SAFL_PATH | (isMe ? SAFL_OUTGOING : 0); + spr = (SMADD_BATCHPARSERES*)CallService(MS_SMILEYADD_BATCHPARSE, 0, (LPARAM)&sp); + delete[] msgbuf; + + if (spr == NULL || (INT_PTR)spr == CALLSERVICE_NOTFOUND) + { + // Did not find a simley + return UrlHighlightHtml(MakeTextHtmled(msg), isUrl); + } + + std::queue > positionMap; + std::wstring newMsg = MakeTextHtmled(msg, &positionMap); + std::wstring smileyMsg; + + size_t last_pos=0; + std::pair pos(0, 0); + size_t currentAdd = 0; + if(!positionMap.empty()) + { + pos = positionMap.front(); + positionMap.pop(); + } + + for (unsigned i = 0; i < sp.numSmileys; ++i) + { + size_t startChar = spr[i].startChar + currentAdd; + while(startChar >= pos.first && pos.second) + { + startChar += pos.second; + currentAdd += pos.second; + if(!positionMap.empty()) + { + pos = positionMap.front(); + positionMap.pop(); + } + else + { + pos = std::pair(0, 0); + } + } + + size_t endChar = spr[i].startChar + spr[i].size + currentAdd; + while(endChar >= pos.first && pos.second) + { + endChar += pos.second; + currentAdd += pos.second; + if(!positionMap.empty()) + { + pos = positionMap.front(); + positionMap.pop(); + } + else + { + pos = std::pair(0, 0); + } + } + + size_t size = endChar - startChar; + + if (spr[i].filepath != NULL) // For deffective smileypacks + { + // Add text + if (startChar - last_pos > 0) + { + smileyMsg += newMsg.substr(last_pos, startChar - last_pos); + } + + std::wstring smileyName = GetName(spr[i].filepath); + if(smileys.find(smileyName) == smileys.end()) + { + smileys.insert(smileyName); + CopyFile(spr[i].filepath, (folder + _T("\\") + smileyName).c_str(), FALSE); + } + + std::wstring smileyText = newMsg.substr(startChar, size); + smileyMsg += _T("\"");"); + } + + // Get next + last_pos = endChar; + } + + // Add rest of text + if (last_pos < newMsg.length()) + { + smileyMsg += newMsg.substr(last_pos); + } + + CallService(MS_SMILEYADD_BATCHFREE, 0, (LPARAM)spr); + return UrlHighlightHtml(smileyMsg, isUrl); + } + else + { + return UrlHighlightHtml(MakeTextHtmled(msg), isUrl); + } +} diff --git a/plugins/BasicHistory/src/RichHtmlExport.h b/plugins/BasicHistory/src/RichHtmlExport.h new file mode 100644 index 0000000000..f4f6686964 --- /dev/null +++ b/plugins/BasicHistory/src/RichHtmlExport.h @@ -0,0 +1,44 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once +#include "IExport.h" +class RichHtmlExport : + public IExport +{ +private: + int groupId; + std::wstring folder; + std::wstring folderName; + std::string baseProto; + stdext::hash_set smileys; + std::wstring ReplaceSmileys(bool isMe, const std::wstring &msg, bool &isUrl); +public: + virtual const TCHAR* GetExt() + { + return _T("html"); + } + + virtual void WriteHeader(const std::wstring &fileName, const std::wstring &filterName, const std::wstring &myName, const std::wstring &myId, const std::wstring &name1, const std::wstring &proto1, const std::wstring &id1, const std::string& baseProto1, const std::wstring& encoding); + virtual void WriteFooter(); + virtual void WriteGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText); + virtual void WriteMessage(bool isMe, const std::wstring &longDate, const std::wstring &shortDate, const std::wstring &user, const std::wstring &message, const DBEVENTINFO& dbei); + + virtual ~RichHtmlExport(); +}; + diff --git a/plugins/BasicHistory/src/Scheduler.cpp b/plugins/BasicHistory/src/Scheduler.cpp new file mode 100644 index 0000000000..3b2ba18ab9 --- /dev/null +++ b/plugins/BasicHistory/src/Scheduler.cpp @@ -0,0 +1,1576 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#include "StdAfx.h" +#include "Options.h" +#include "ExportManager.h" +#include "HistoryWindow.h" +#include "zip\zip.h" +#include "zip\unzip.h" +#include "zip\iowin32.h" + +// Sorry for plain C implementation +#define MODULE "BasicHistory" +extern HANDLE g_hMainThread; +bool bPopupsEnabled; +bool DoTask(TaskOptions& to); +bool IsValidTask(TaskOptions& to, std::list* top = NULL, std::wstring* err = NULL, std::wstring* errDescr = NULL); +std::wstring GetFileName(const std::wstring &baseName, std::wstring contactName, std::map& existingContacts, bool replaceContact); +std::wstring GetDirectoryName(const std::wstring &path); +std::wstring GetName(const std::wstring &path); +bool DeleteDirectory(LPCTSTR lpszDir, bool noRecycleBin = true); +void ListDirectory(const std::wstring &basePath, const std::wstring &path, std::list& files); +std::wstring ReplaceStr(const std::wstring& str, wchar_t oldCh, wchar_t newCh); +time_t GetNextExportTime(TaskOptions& to); +void SchedulerThreadFunc(void*); +volatile bool finishThread = false; +bool initTask = false; +HANDLE thread = NULL; +HANDLE threadEvent; +time_t nextExportTime; +void StartThread(bool init); +void StopThread(); +bool GetNextExportTime(bool init, time_t now); +bool ExecuteCurrentTask(time_t now); +void GetZipFileTime(const TCHAR *file, uLong *dt); +std::wstring ReplaceExt(const std::wstring& file, const TCHAR* ext); +bool ZipFiles(const std::wstring& dir, std::wstring zipFilePath, const std::string& password); +bool UnzipFiles(const std::wstring& dir, std::wstring& zipFilePath, const std::string& password); +bool FtpFiles(const std::wstring& dir, const std::wstring& filePath, const std::wstring& ftpName); +bool FtpGetFiles(const std::wstring& dir, const std::list& files, const std::wstring& ftpName); +void CreatePath(const TCHAR *szDir); +void DoError(const TaskOptions& to, const std::wstring error); + +void OptionsSchedulerChanged() +{ + StartThread(false); +} + +void InitScheduler() +{ + bPopupsEnabled = ServiceExists(MS_POPUP_ADDPOPUPT) || ServiceExists(MS_POPUP_ADDPOPUPCLASS); + if (ServiceExists(MS_POPUP_REGISTERCLASS)) + { + //hPopupIcon = LoadIconEx(I_CHKUPD); + POPUPCLASS test = {0}; + test.cbSize = sizeof(POPUPCLASS); + test.flags = PCF_TCHAR; + test.hIcon = LoadSkinnedIcon(SKINICON_OTHER_HISTORY); + test.iSeconds = 10; + test.ptszDescription = TranslateT("History task"); + test.pszName = MODULE; + CallService(MS_POPUP_REGISTERCLASS, 0, (WPARAM)&test); + } + + StartThread(true); +} + +void DeinitScheduler() +{ + StopThread(); +} + +int DoLastTask(WPARAM, LPARAM) +{ + for(std::vector::iterator it = Options::instance->taskOptions.begin(); it != Options::instance->taskOptions.end(); ++it) + { + if(it->trigerType == TaskOptions::AtEnd && it->active) + { + DoTask(*it); + } + } + + return 0; +} + +bool IsValidTask(TaskOptions& to, std::list* top, std::wstring* err, std::wstring* errDescr) +{ + if(to.taskName.empty()) + { + if(err != NULL) + *err = TranslateT("Name"); + return false; + } + if(top != NULL) + { + for(std::list::iterator it = top->begin(); it != top->end(); ++it) + { + if(it->taskName == to.taskName) + { + if(err != NULL) + *err = TranslateT("Name"); + return false; + } + } + } + if(!to.isSystem && to.contacts.size() == 0) + { + if(err != NULL) + *err = TranslateT("Contacts"); + if(errDescr != NULL) + *errDescr = TranslateT("At least one contact should be selected."); + return false; + } + + bool isImportTask = to.type == TaskOptions::Import || to.type == TaskOptions::ImportAndMarge; + if(!isImportTask) + { + if(to.filterId > 1) + { + int filter = 0; + + for(int i = 0; i < (int)Options::instance->customFilters.size(); ++i) + { + if(to.filterName == Options::instance->customFilters[i].name) + { + filter = i + 2; + break; + } + } + + if(filter < 2) + { + if(err != NULL) + *err = TranslateT("Filter"); + return false; + } + + to.filterId = filter; + } + else if(to.filterId < 0) + { + if(err != NULL) + *err = TranslateT("Filter"); + return false; + } + } + + if(to.type == TaskOptions::Delete) + { + return true; + } + + if(!Options::FTPAvail() && to.useFtp) + { + if(err != NULL) + *err = TranslateT("Upload to FTP"); + return false; + } + if(to.filePath.empty()) + { + if(err != NULL) + *err = TranslateT("Path to output file"); + return false; + } + if(to.useFtp && to.ftpName.empty()) + { + if(err != NULL) + *err = TranslateT("Session name"); + if(errDescr != NULL) + *errDescr = TranslateT("To create session open WinSCP, click New Session, enter data and save with specific name. Remember if FTP server using password you should save it in WinSCP."); + return false; + } + if(to.useFtp && (to.filePath.find(_T('\\')) < to.filePath.length() || to.filePath.find(_T(':')) < to.filePath.length() || to.filePath[0] != L'/')) + { + if(err != NULL) + *err = TranslateT("Path to file"); + if(errDescr != NULL) + *errDescr = TranslateT("FTP path must contains '/' instead '\\' and starts from '/'."); + return false; + } + if(isImportTask && to.filePath.find(_T("")) < to.filePath.length()) + { + if(err != NULL) + *err = TranslateT("Path to file"); + if(errDescr != NULL) + *errDescr = TranslateT("FTP path cannot contain in import task."); + return false; + } + if(!isImportTask && (to.exportType < IExport::RichHtml || to.exportType > IExport::Dat)) + { + if(err != NULL) + *err = TranslateT("Export to"); + return false; + } + if(isImportTask && (to.importType < IImport::Binary || to.importType > IImport::Dat)) + { + if(err != NULL) + *err = TranslateT("Import from"); + return false; + } + if((to.trigerType == TaskOptions::Daily || to.trigerType == TaskOptions::Weekly || to.trigerType == TaskOptions::Monthly) && (to.dayTime < 0 || to.dayTime >= 24 * 60)) + { + if(err != NULL) + *err = TranslateT("Time"); + return false; + } + if(to.trigerType == TaskOptions::Weekly && (to.dayOfWeek < 0 || to.dayOfWeek >= 7)) + { + if(err != NULL) + *err = TranslateT("Day of week"); + return false; + } + if(to.trigerType == TaskOptions::Monthly && (to.dayOfMonth <= 0 || to.dayOfMonth >= 32)) + { + if(err != NULL) + *err = TranslateT("Day"); + return false; + } + if((to.trigerType == TaskOptions::DeltaMin || to.trigerType == TaskOptions::DeltaHour) && (to.deltaTime < 0 || to.deltaTime >= 10000)) + { + if(err != NULL) + *err = TranslateT("Delta time"); + return false; + } + + return true; +} + +static void CALLBACK DoRebuildEventsInMainAPCFunc(ULONG_PTR dwParam) +{ + HANDLE* contacts = (HANDLE*) dwParam; + size_t size = (size_t)contacts[0]; + for(size_t i = 1; i <= size; ++i) + { + HistoryWindow::RebuildEvents(contacts[i]); + } + + delete[] contacts; +} + +bool DoTask(TaskOptions& to) +{ + std::wstring err; + std::wstring errDescr; + if(!IsValidTask(to, NULL, &err, &errDescr)) + { + TCHAR msg[256]; + if(err.empty()) + _tcscpy_s(msg, TranslateT("Some value is invalid")); + else if(errDescr.empty()) + { + _stprintf_s(msg, TranslateT("Invalid '%s' value."), err.c_str()); + } + else + { + _stprintf_s(msg, TranslateT("Invalid '%s' value.\n%s"), err.c_str(), errDescr.c_str()); + } + DoError(to, msg); + return true; + } + + DWORD now = time(NULL); + long long int t = to.eventDeltaTime * 60; + if(to.eventUnit > TaskOptions::Minute) + t *= 60LL; + if(to.eventUnit > TaskOptions::Hour) + t *= 24LL; + if(t > 2147483647LL) + { + DoError(to, TranslateT("Unknown error")); + return true; + } + + bool error = false; + std::wstring errorStr; + std::list managers; + if(to.type == TaskOptions::Delete) + { + if(to.isSystem) + { + ExportManager *exp = new ExportManager(NULL, NULL, to.filterId); + exp->SetDeleteWithoutExportEvents(t, now); + managers.push_back(exp); + } + + for(size_t i = 0; i < to.contacts.size(); ++i) + { + ExportManager *exp = new ExportManager(NULL, to.contacts[i], to.filterId); + exp->SetDeleteWithoutExportEvents(t, now); + managers.push_back(exp); + } + } + else if(to.type == TaskOptions::Import || to.type == TaskOptions::ImportAndMarge) + { + std::map existingContacts1; + ExportManager mExp = ExportManager(NULL, NULL, 1); + std::wstring filePath = to.filePath; + std::wstring dir; + std::list files; + std::vector contacts; + if(to.useFtp || to.compress) + { + std::map existingContacts; + TCHAR temp[MAX_PATH]; + temp[0] = 0; + GetTempPath(MAX_PATH, temp); + dir = temp; + dir += GetName(filePath); + dir = GetFileName(dir, L"", existingContacts, true); + dir = ReplaceExt(dir, L""); + size_t pos = dir.find_last_of(_T('.')); + if(pos < dir.length()) + { + dir = dir.substr(0, pos); + } + + DeleteDirectory(dir.c_str()); + CreateDirectory(dir.c_str(), NULL); + } + + const TCHAR* ext = ExportManager::GetExt(to.importType); + if(to.isSystem) + { + std::wstring n = GetFileName(filePath, mExp.GetContactName(), existingContacts1, true); + n = ReplaceExt(n, ext); + files.push_back(n); + contacts.push_back(NULL); + } + + for(size_t i = 0; i < to.contacts.size(); ++i) + { + mExp.hContact = to.contacts[i]; + std::wstring n = GetFileName(filePath, mExp.GetContactName(), existingContacts1, true); + n = ReplaceExt(n, ext); + files.push_back(n); + contacts.push_back(to.contacts[i]); + } + + if(to.useFtp) + { + if(to.compress) + { + std::map existingContacts; + std::wstring n = GetFileName(filePath, L"", existingContacts, true); + n = ReplaceExt(n, L"zip"); + files.clear(); + files.push_back(n); + filePath = dir + L"\\" + GetName(filePath); + } + + error = FtpGetFiles(dir, files, to.ftpName); + if(error) + { + if(!errorStr.empty()) + { + errorStr += L"\n"; + } + + errorStr += TranslateT("Cannot get FTP file(s)."); + } + } + + if(!error && to.compress) + { + error = UnzipFiles(dir, filePath, to.zipPassword); + if(error) + { + if(!errorStr.empty()) + { + errorStr += L"\n"; + } + + errorStr += TranslateT("Cannot unzip file(s)."); + } + + if(to.useFtp) + DeleteFile(filePath.c_str()); + } + + if(!error && (to.useFtp || to.compress)) + { + files.clear(); + std::list files1; + ListDirectory(dir, L"\\", files1); + for(std::list::iterator it = files1.begin(); it != files1.end(); ++it) + { + files.push_back(dir + *it); + } + } + + if(!error) + { + std::list contactList; + for(std::list::iterator it = files.begin(); it != files.end(); ++it) + { + mExp.SetAutoImport(*it); + int ret = mExp.Import(to.importType, contacts); + if(ret == -3) + { + if(contacts.size() == 1) + { + ret = 0; + } + else + { + std::map existingContacts; + std::wstring name = GetName(*it); + for(ret = 0; ret < (int)contacts.size(); ++ret) + { + mExp.hContact = contacts[ret]; + std::wstring n = GetFileName(to.filePath, mExp.GetContactName(), existingContacts, true); + n = ReplaceExt(n, ext); + n = GetName(n); + if(n == name) + break; + } + + if(ret >= (int)contacts.size()) + ret = -1; + } + } + + if(ret >= 0) + { + mExp.hContact = contacts[ret]; + if(to.type == TaskOptions::Import) + { + EventList::AddImporter(mExp.hContact, to.importType, *it); + contactList.push_back(mExp.hContact); + } + else + { + std::vector messages; + if(mExp.Import(to.importType, messages, NULL)) + { + mExp.MargeMessages(messages); + contactList.push_back(mExp.hContact); + } + } + } + else if(ret != -1) + { + if(!errorStr.empty()) + { + errorStr += L"\n"; + } + + TCHAR msg[1024]; + + _stprintf_s(msg, TranslateT("Incorrect file format: %s."), GetName(*it).c_str()); + errorStr += msg; + } + else + { + if(!errorStr.empty()) + { + errorStr += L"\n"; + } + + TCHAR msg[1024]; + + _stprintf_s(msg, TranslateT("Unknown contact in file: %s."), GetName(*it).c_str()); + errorStr += msg; + } + } + + if(contactList.size() > 0) + { + HANDLE* contacts = new HANDLE[contactList.size() + 1]; + contacts[0] = (HANDLE)contactList.size(); + int i = 1; + for(std::list::iterator it = contactList.begin(); it != contactList.end(); ++it) + { + contacts[i++] = *it; + } + + QueueUserAPC(DoRebuildEventsInMainAPCFunc, g_hMainThread, (ULONG_PTR) contacts); + } + } + + if(to.useFtp || to.compress) + { + DeleteDirectory(dir.c_str()); + } + } + else + { + std::map existingContacts; + std::wstring filePath = to.filePath; + std::wstring dir; + if(!to.useFtp && !to.compress) + { + dir = GetDirectoryName(filePath); + if(!dir.empty()) + { + CreateDirectory(dir.c_str(), NULL); + } + } + else + { + filePath = GetName(filePath); + TCHAR temp[MAX_PATH]; + temp[0] = 0; + GetTempPath(MAX_PATH, temp); + dir = temp; + dir += filePath; + dir = GetFileName(dir, L"", existingContacts, true); + dir = ReplaceExt(dir, L""); + size_t pos = dir.find_last_of(_T('.')); + if(pos < dir.length()) + { + dir = dir.substr(0, pos); + } + + DeleteDirectory(dir.c_str()); + CreateDirectory(dir.c_str(), NULL); + filePath = dir + L"\\" + filePath; + } + if(to.isSystem) + { + ExportManager *exp = new ExportManager(NULL, NULL, to.filterId); + exp->SetAutoExport(GetFileName(filePath, exp->GetContactName(), existingContacts, true), t, now); + exp->useImportedMessages = to.exportImported; + if(!exp->Export(to.exportType)) + { + error = true; + if(!errorStr.empty()) + { + errorStr += L"\n"; + } + + TCHAR msg[1024]; + + _stprintf_s(msg, TranslateT("Cannot export history for contact: %s."), exp->GetContactName().c_str()); + errorStr += msg; + } + + if(to.type == TaskOptions::Export) + { + delete exp; + } + else + { + managers.push_back(exp); + } + } + + if(!error) + { + for(size_t i = 0; i < to.contacts.size(); ++i) + { + ExportManager *exp = new ExportManager(NULL, to.contacts[i], to.filterId); + exp->SetAutoExport(GetFileName(filePath, exp->GetContactName(), existingContacts, true), t, now); + exp->useImportedMessages = to.exportImported; + if(!exp->Export(to.exportType)) + { + error = true; + if(!errorStr.empty()) + { + errorStr += L"\n"; + } + + TCHAR msg[1024]; + + _stprintf_s(msg, TranslateT("Cannot export history for contact: %s."), exp->GetContactName().c_str()); + errorStr += msg; + break; + } + + if(to.type == TaskOptions::Export) + { + delete exp; + } + else + { + managers.push_back(exp); + } + } + } + + if(error) + { + if(to.compress && !to.useFtp) + { + DeleteDirectory(dir.c_str()); + } + } + else if(to.compress) + { + std::wstring zipFilePath = to.filePath; + std::wstring zipDir = dir; + if(!to.useFtp) + { + zipDir = GetDirectoryName(zipFilePath); + if(!zipDir.empty()) + { + CreateDirectory(zipDir.c_str(), NULL); + } + } + else + { + zipFilePath = GetName(zipFilePath); + TCHAR temp[MAX_PATH]; + temp[0] = 0; + GetTempPath(MAX_PATH, temp); + zipDir = temp; + zipDir += L"zip"; + zipDir = GetFileName(zipDir, L"", existingContacts, true); + DeleteDirectory(zipDir.c_str()); + CreateDirectory(zipDir.c_str(), NULL); + zipFilePath = zipDir + L"\\" + zipFilePath; + } + error = ZipFiles(dir + L"\\", zipFilePath, to.zipPassword); + dir = zipDir; + if(error) + { + if(!errorStr.empty()) + { + errorStr += L"\n"; + } + + errorStr += TranslateT("Cannot compress file(s)."); + } + } + + if(to.useFtp) + { + if(!error) + { + error = FtpFiles(dir, to.filePath, to.ftpName); + if(error) + { + if(!errorStr.empty()) + { + errorStr += L"\n"; + } + + errorStr += TranslateT("Cannot send FTP file(s)."); + } + } + + DeleteDirectory(dir.c_str()); + } + } + + if(to.type == TaskOptions::Delete || to.type == TaskOptions::ExportAndDelete) + { + for(std::list::iterator it = managers.begin(); it != managers.end(); ++it) + { + if(!error) + { + (*it)->DeleteExportedEvents(); + } + + delete *it; + } + } + + if(error) + { + DoError(to, errorStr.empty() ? TranslateT("Unknown error") : errorStr); + } + + return error; +} + +std::wstring GetFileName(const std::wstring &baseName, std::wstring contactName, std::map& existingContacts, bool replaceContact) +{ + std::wstring str = baseName; + size_t pos = baseName.find(_T("")); + if(replaceContact && pos < baseName.length()) + { + str = baseName.substr(0, pos); + std::wstring baseName1 = contactName; + if(!baseName1.empty()) + { + std::wstring name = baseName1; + int i = 0; + TCHAR buf[32]; + std::map::iterator it = existingContacts.find(name); + while(it != existingContacts.end()) + { + _itot_s(++i, buf, 10); + name = baseName1 + buf; + it = existingContacts.find(name); + } + + str += name; + existingContacts[name] = true; + } + str += baseName.substr(pos + 9); + } + + pos = str.find(_T("")); + if(pos < str.length()) + { + TCHAR time[256]; + SYSTEMTIME st; + GetLocalTime(&st); + _stprintf_s(time, _T("%d-%02d-%02d %02d%02d"), st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute); + std::wstring str1 = str.substr(0, pos); + str1 += time; + str1 += str.substr(pos + 6); + str = str1; + } + + return str; +} + +std::wstring GetDirectoryName(const std::wstring &path) +{ + size_t find = path.find_last_of(L"\\/"); + if(find < path.length()) + { + return path.substr(0, find); + } + + return L""; +} + +void ListDirectory(const std::wstring &basePath, const std::wstring &path, std::list& files) +{ + WIN32_FIND_DATA findFileData; + HANDLE hFind = FindFirstFile((basePath + path + _T("*")).c_str(), &findFileData); + if (hFind == INVALID_HANDLE_VALUE) + return; + do + { + if(findFileData.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) + { + std::wstring name = findFileData.cFileName; + if(name != L"." && name != L"..") + ListDirectory(basePath, path + findFileData.cFileName + _T("\\"), files); + } + else + { + files.push_back(path + findFileData.cFileName); + } + } + while(FindNextFile(hFind, &findFileData)); + FindClose(hFind); +} + +std::wstring ReplaceStr(const std::wstring& str, wchar_t oldCh, wchar_t newCh) +{ + std::wstring ret; + size_t start = 0; + size_t find; + while((find = str.find_first_of(oldCh, start)) < str.length()) + { + ret += str.substr(start, find - start); + ret += newCh; + start = find + 1; + } + + ret += str.substr(start, str.length() - start); + return ret; +} + +time_t GetNextExportTime(TaskOptions& to) +{ + switch(to.trigerType) + { + case TaskOptions::Daily: + { + tm t; + localtime_s(&t, &to.lastExport); + t.tm_hour = to.dayTime/60; + t.tm_min = to.dayTime%60; + t.tm_sec = 0; + time_t newTime = mktime(&t); + if(newTime <= to.lastExport) + { + newTime += 60 * 60 * 24; + } + + return newTime; + } + case TaskOptions::Weekly: + { + tm t; + localtime_s(&t, &to.lastExport); + t.tm_hour = to.dayTime/60; + t.tm_min = to.dayTime%60; + t.tm_sec = 0; + int dow = (to.dayOfWeek + 1) % 7; + time_t newTime = mktime(&t); + while(dow != t.tm_wday) + { + newTime += 60 * 60 * 24; + localtime_s(&t, &newTime); + newTime = mktime(&t); + } + + if(newTime <= to.lastExport) + { + newTime += 7 * 60 * 60 * 24; + } + + return newTime; + } + case TaskOptions::Monthly: + { + tm t; + localtime_s(&t, &to.lastExport); + t.tm_hour = to.dayTime/60; + t.tm_min = to.dayTime%60; + t.tm_sec = 0; + time_t newTime = mktime(&t); + int lastM = t.tm_mon; + int lastD; + while(to.dayOfMonth != t.tm_mday || newTime <= to.lastExport) + { + lastD = t.tm_mday; + newTime += 60 * 60 * 24; + localtime_s(&t, &newTime); + newTime = mktime(&t); + if(to.dayOfMonth > 28 && t.tm_mon != lastM && (newTime - 60 * 60 * 24) > to.lastExport) + { + lastM = t.tm_mon; + if(to.dayOfMonth > lastD) + { + newTime -= 60 * 60 * 24; + break; + } + } + } + + return newTime; + } + case TaskOptions::DeltaMin: + return to.lastExport + to.deltaTime * 60; + case TaskOptions::DeltaHour: + return to.lastExport + to.deltaTime * 60 * 60; + default: + return to.lastExport; + } +} + +void SchedulerThreadFunc(void*) +{ + if(initTask) + { + WaitForSingleObject(threadEvent, 5 * 1000); + initTask = false; + } + + while(!finishThread) + { + DWORD timeWait; + time_t now = time(NULL); + while(nextExportTime <= now) + { + if(!ExecuteCurrentTask(now)) + return; + } + + time_t dif = nextExportTime - now; + timeWait = (dif > 60 * 60 * 24) ? (60 * 60 * 1000) : (60 * 1000); + + WaitForSingleObject(threadEvent, timeWait); + } +} + +void StartThread(bool init) +{ + StopThread(); + + initTask = false; + bool isExport = GetNextExportTime(init, time(NULL)); + if(isExport) + { + finishThread = false; + threadEvent = CreateEvent(NULL, TRUE, FALSE, NULL); + thread = mir_forkthread(SchedulerThreadFunc, NULL); + } +} + +void StopThread() +{ + if(thread != NULL) + { + finishThread = true; + SetEvent(threadEvent); + WaitForSingleObject(thread, INFINITE); + //CloseHandle(thread); + CloseHandle(threadEvent); + thread = NULL; + threadEvent = NULL; + } +} + +bool GetNextExportTime(bool init, time_t now) +{ + EnterCriticalSection(&Options::instance->criticalSection); + bool isExport = false; + for(std::vector::iterator it = Options::instance->taskOptions.begin(); it != Options::instance->taskOptions.end(); ++it) + { + if(it->forceExecute) + { + nextExportTime = now; + isExport = true; + initTask = init; + break; + } + else if(it->active && it->trigerType != TaskOptions::AtStart && it->trigerType != TaskOptions::AtEnd) + { + time_t t = GetNextExportTime(*it); + if(isExport) + { + if(t < nextExportTime) + nextExportTime = t; + } + else + { + nextExportTime = t; + isExport = true; + initTask = init; + } + } + else if(it->active && it->trigerType == TaskOptions::AtStart && init) + { + it->forceExecute = true; + it->showMBAfterExecute = false; + nextExportTime = now; + isExport = true; + initTask = true; + } + } + + LeaveCriticalSection(&Options::instance->criticalSection); + return isExport; +} + +static void CALLBACK DoTaskFinishInMainAPCFunc(ULONG_PTR dwParam) +{ + TCHAR *item = (TCHAR*) dwParam; + MessageBox(NULL, item, TranslateT("Task finished"), MB_OK | MB_ICONINFORMATION); + delete[] item; +} + +bool ExecuteCurrentTask(time_t now) +{ + EnterCriticalSection(&Options::instance->criticalSection); + TaskOptions to; + bool isExport = false; + for(std::vector::iterator it = Options::instance->taskOptions.begin(); it != Options::instance->taskOptions.end(); ++it) + { + if(it->forceExecute) + { + it->lastExport = time(NULL); + Options::instance->SaveTaskTime(*it); + to = *it; + isExport = true; + break; + } + else if(it->active && it->trigerType != TaskOptions::AtStart && it->trigerType != TaskOptions::AtEnd) + { + time_t t = GetNextExportTime(*it); + if(t <= now) + { + it->lastExport = time(NULL); + Options::instance->SaveTaskTime(*it); + to = *it; + isExport = true; + break; + } + } + } + + LeaveCriticalSection(&Options::instance->criticalSection); + + if(isExport) + { + bool error = DoTask(to); + if(to.forceExecute) + { + EnterCriticalSection(&Options::instance->criticalSection); + for(std::vector::iterator it = Options::instance->taskOptions.begin(); it != Options::instance->taskOptions.end(); ++it) + { + if(it->taskName == to.taskName) + { + it->forceExecute = false; + it->showMBAfterExecute = false; + break; + } + } + + LeaveCriticalSection(&Options::instance->criticalSection); + + if(to.showMBAfterExecute) + { + size_t size = to.taskName.size() + 1024; + TCHAR* name = new TCHAR[size]; + if(error) + { + _stprintf_s(name, size, TranslateT("Task '%s' execution failed"), to.taskName.c_str()); + } + else + { + _stprintf_s(name, size, TranslateT("Task '%s' finished successfully"), to.taskName.c_str()); + } + + QueueUserAPC(DoTaskFinishInMainAPCFunc, g_hMainThread, (ULONG_PTR) name); + } + } + } + + return GetNextExportTime(false, now); +} + +void GetZipFileTime(const TCHAR *file, uLong *dt) +{ + FILETIME ftLocal; + HANDLE hFind; + WIN32_FIND_DATA ff32; + + hFind = FindFirstFile(file, &ff32); + if (hFind != INVALID_HANDLE_VALUE) + { + FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal); + FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0); + FindClose(hFind); + } +} + +/* calculate the CRC32 of a file, + because to encrypt a file, we need known the CRC32 of the file before */ +bool GetFileCrc(const TCHAR* filenameinzip, unsigned char* buf, unsigned long size_buf, unsigned long* result_crc) +{ + unsigned long calculate_crc = 0; + bool error = true; + HANDLE hFile = CreateFile(filenameinzip, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + DWORD readed; + do + { + if(!ReadFile(hFile, buf, 1024, &readed, NULL)) + { + error = false; + break; + } + + if (readed > 0) + { + calculate_crc = crc32(calculate_crc, buf, readed); + } + } + while (readed > 0); + CloseHandle(hFile); + } + else + { + error = false; + } + + *result_crc=calculate_crc; + return error; +} + +bool ZipFiles(const std::wstring& dir, std::wstring zipFilePath, const std::string& password) +{ + std::list files; + std::map existingContacts; + ListDirectory(dir, L"", files); + bool error = false; + if(files.size() > 0) + { + zlib_filefunc_def pzlib_filefunc_def; + fill_win32_filefunc(&pzlib_filefunc_def); + zipFilePath = GetFileName(zipFilePath, L"", existingContacts, true); + zipFilePath = ReplaceExt(zipFilePath, L"zip"); + zipFile zf = zipOpen2((LPCSTR)(LPTSTR)zipFilePath.c_str(), APPEND_STATUS_CREATE, NULL, &pzlib_filefunc_def); + if (zf != NULL) + { + unsigned char buf[1024]; + char bufF[MAX_PATH + 20]; + while(files.size() > 0) + { + std::wstring zipDir = *files.begin(); + std::wstring localDir = dir + L"\\" + zipDir; + zip_fileinfo zi = {0}; + GetZipFileTime(localDir.c_str(), &zi.dosDate); + if(zipDir.size() > MAX_PATH + 19) + { + error = true; + break; + } + + BOOL badChar; + WideCharToMultiByte(CP_OEMCP, WC_NO_BEST_FIT_CHARS, zipDir.c_str(), -1, bufF, MAX_PATH + 20, NULL, &badChar); + int flag = 0; + if(badChar) + { + flag = 0x800; // UTF + WideCharToMultiByte(CP_UTF8, 0, zipDir.c_str(), -1, bufF, MAX_PATH + 20, NULL, NULL); + } + + unsigned long calculate_crc = 0; + const char* passwordCh = NULL; + if(password.size() > 0) + { + if(!GetFileCrc(localDir.c_str(), buf, 1024, &calculate_crc)) + { + error = true; + break; + } + + passwordCh = password.c_str(); + } + + int err = zipOpenNewFileInZip4_64 (zf, bufF, &zi, NULL, 0, NULL, 0, NULL, Z_DEFLATED, Z_DEFAULT_COMPRESSION, 0, + -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, passwordCh, calculate_crc, 0, flag, 0); + if (err == ZIP_OK) + { + HANDLE hFile = CreateFile(localDir.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + DWORD readed; + do + { + err = ZIP_OK; + if(!ReadFile(hFile, buf, 1024, &readed, NULL)) + { + error = true; + break; + } + + if (readed > 0) + { + err = zipWriteInFileInZip(zf, buf, readed); + } + } + while ((err == ZIP_OK) && (readed > 0)); + CloseHandle(hFile); + } + + if(zipCloseFileInZip(zf) != ZIP_OK) + { + error = true; + break; + } + } + else + { + error = true; + break; + } + + files.pop_front(); + } + + zipClose(zf, NULL); + } + else + { + error = true; + } + } + + DeleteDirectory(dir.c_str()); + return error; +} + +bool UnzipFiles(const std::wstring& dir, std::wstring& zipFilePath, const std::string& password) +{ + std::list files; + bool error = false; + zlib_filefunc_def pzlib_filefunc_def; + fill_win32_filefunc(&pzlib_filefunc_def); + std::wstring fileNameInZip; + std::map existingContacts; + zipFilePath = GetFileName(zipFilePath, L"", existingContacts, true); + zipFilePath = ReplaceExt(zipFilePath, L"zip"); + unzFile zf = unzOpen2((LPCSTR)(LPTSTR)zipFilePath.c_str(), &pzlib_filefunc_def); + if (zf != NULL) + { + char buf[8192]; + char bufF[MAX_PATH + 20]; + unz_file_info file_info; + do + { + int err = unzGetCurrentFileInfo(zf, &file_info, bufF, MAX_PATH + 20, buf, 8192, NULL, 0); + if (err == UNZ_OK) + { + UINT cp = CP_OEMCP; + if(file_info.flag & 0x800)// UTF + { + cp = CP_UTF8; + } + + // Get Unicode file name for InfoZip style archives, otherwise assume PKZip/WinZip style + if (file_info.size_file_extra) + { + char *p = buf; + unsigned long size = min(file_info.size_file_extra, 8192); + while (size > 0) + { + unsigned short id = *(unsigned short*)p; + unsigned len = *(unsigned short*)(p + 2); + + if (size < (len + 4)) break; + + if (id == 0x7075 && len > 5 && (len - 5) < MAX_PATH + 20 && *(p + 4) == 1) + { + memcpy(bufF, p + 9, len - 5); + bufF[len - 5] = 0; + cp = CP_UTF8; + break; + } + size -= len + 4; + p += len + 4; + } + } + + int sizeC = (int)strlen(bufF); + int sizeW = MultiByteToWideChar(cp, 0, bufF, sizeC, NULL, 0); + fileNameInZip.resize(sizeW); + MultiByteToWideChar(cp, 0, bufF, sizeC, (wchar_t*)fileNameInZip.c_str(), sizeW); + fileNameInZip = dir + L"\\" + fileNameInZip; + for (size_t i = 0; i < fileNameInZip.length(); ++i) + { + if (fileNameInZip[i] == L'/') + fileNameInZip[i] = L'\\'; + } + + if (file_info.external_fa & FILE_ATTRIBUTE_DIRECTORY) + CreatePath(fileNameInZip.c_str()); + else + { + const char* passwordCh = NULL; + if(password.size() > 0) + { + passwordCh = password.c_str(); + } + + err = unzOpenCurrentFilePassword(zf, passwordCh); + if (err == UNZ_OK) + { + CreatePath(GetDirectoryName(fileNameInZip).c_str()); + HANDLE hFile = CreateFile(fileNameInZip.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, NULL, CREATE_ALWAYS, 0, NULL); + if(hFile != INVALID_HANDLE_VALUE) + { + DWORD writed; + for (;;) + { + err = unzReadCurrentFile(zf, buf, 8192); + if (err <= 0) break; + + if (!WriteFile(hFile, buf, err, &writed, FALSE)) + { + err = -1; + break; + } + } + + CloseHandle(hFile); + if(err < 0) + { + error = true; + break; + } + } + else + { + unzCloseCurrentFile(zf); + error = true; + break; + } + + if(unzCloseCurrentFile(zf) != ZIP_OK) + { + error = true; + break; + } + } + else + { + error = true; + break; + } + } + } + else + { + error = true; + break; + } + } + while (unzGoToNextFile(zf) == UNZ_OK); + + unzClose(zf); + } + else + { + error = true; + } + + return error; +} + +bool FtpFiles(const std::wstring& dir, const std::wstring& filePath, const std::wstring& ftpName) +{ + std::list files; + std::map existingContacts; + ListDirectory(dir, L"\\", files); + if(files.size() > 0) + { + std::wofstream stream ((dir + _T("\\script.sc")).c_str()); + if(stream.is_open()) + { + std::wstring ftpDir = GetDirectoryName(filePath); + ftpDir = GetFileName(ftpDir, L"", existingContacts, false); + stream << "option batch continue\noption confirm off\nopen \"" + << ftpName << "\"\noption transfer binary\n"; + std::wstring lastCD; + size_t filSize = files.size(); + while(files.size() > 0) + { + std::wstring localDir = *files.begin(); + std::wstring currentCD = ftpDir + GetDirectoryName(ReplaceStr(localDir, L'\\', L'/')); + if(currentCD != lastCD) + { + if(!currentCD.empty() && currentCD != L"/") + stream << "mkdir \"" << currentCD << "\"\n"; + stream << "cd \"" << currentCD << "\"\n"; + lastCD = currentCD; + } + + std::wstring name = GetName(localDir); + stream << "call MDTM " << name << "\n"; + stream << "put \"." << localDir << "\"\n"; + stream << "call MDTM " << name << "\n"; + files.pop_front(); + } + + stream.close(); + std::wstring &log = Options::instance->ftpLogPath; + CreateDirectory(GetDirectoryName(log).c_str(), NULL); + DeleteFile(log.c_str()); + TCHAR cmdLine[MAX_PATH]; + _stprintf_s(cmdLine, _T("\"%s\" /nointeractiveinput /log=\"%s\" /script=script.sc"), Options::instance->ftpExePath.c_str(), log.c_str()); + STARTUPINFO startupInfo = {0}; + PROCESS_INFORMATION processInfo; + startupInfo.cb = sizeof(STARTUPINFO); + if(CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, dir.c_str(), &startupInfo, &processInfo)) + { + WaitForSingleObject(processInfo.hProcess, INFINITE); + CloseHandle(processInfo.hThread); + CloseHandle(processInfo.hProcess); + if(log.empty()) + { + return false; + } + + std::wifstream logStream (log.c_str()); + if(logStream.is_open()) + { + bool isInMDTM = false; + std::list dates; + while(!logStream.eof()) + { + std::wstring lineStr; + std::getline(logStream, lineStr); + if(lineStr.length() > 1) + { + if(lineStr[0] == L'>') + { + if(isInMDTM) + { + if(lineStr.find(L"Script:") < lineStr.length()) + { + dates.push_back(L""); + isInMDTM = false; + } + } + + if(lineStr.find(L"Script: call MDTM") < lineStr.length()) + { + isInMDTM = true; + } + } + else if(isInMDTM && lineStr[0] == L'<') + { + size_t ss = lineStr.find(L"Script: 213 "); + if(ss < lineStr.length()) + { + ss += 12; + if(ss < lineStr.length()) + { + lineStr = lineStr.substr(ss); + if(lineStr.size() == 14) + { + dates.push_back(lineStr); + isInMDTM = false; + } + } + } + } + } + } + + if(dates.size() > 0 && dates.size() == filSize * 2) + { + for(std::list::const_iterator it = dates.begin(); it != dates.end(); ++it) + { + std::wstring date1 = *it++; + if(it->empty() || date1 == *it) + return true; + + } + + return false; + } + } + } + } + } + + return true; +} + +bool FtpGetFiles(const std::wstring& dir, const std::list& files, const std::wstring& ftpName) +{ + std::map existingContacts; + std::wstring script = dir + _T("\\script.sc"); + std::wofstream stream (script.c_str()); + if(stream.is_open()) + { + stream << "option batch continue\noption confirm off\nopen \"" + << ftpName << "\"\noption transfer binary\n"; + std::wstring lastCD; + std::list localFiles; + for(std::list::const_iterator it = files.begin(); it != files.end(); ++it) + { + std::wstring fileName = GetName(*it); + localFiles.push_back(dir + L"\\" + fileName); + std::wstring currentCD = GetDirectoryName(*it); + if(currentCD != lastCD) + { + stream << "cd \"" << currentCD << "\"\n"; + lastCD = currentCD; + } + + stream << "get \"" << fileName << "\"\n"; + } + + stream.close(); + std::wstring &log = Options::instance->ftpLogPath; + CreateDirectory(GetDirectoryName(log).c_str(), NULL); + DeleteFile(log.c_str()); + TCHAR cmdLine[MAX_PATH]; + _stprintf_s(cmdLine, _T("\"%s\" /nointeractiveinput /log=\"%s\" /script=script.sc"), Options::instance->ftpExePath.c_str(), log.c_str()); + STARTUPINFO startupInfo = {0}; + PROCESS_INFORMATION processInfo; + startupInfo.cb = sizeof(STARTUPINFO); + if(CreateProcess(NULL, cmdLine, NULL, NULL, FALSE, 0, NULL, dir.c_str(), &startupInfo, &processInfo)) + { + WaitForSingleObject(processInfo.hProcess, INFINITE); + CloseHandle(processInfo.hThread); + CloseHandle(processInfo.hProcess); + } + + DeleteFile(script.c_str()); + for(std::list::const_iterator it = localFiles.begin(); it != localFiles.end(); ++it) + { + DWORD atr = GetFileAttributes(it->c_str()); + if(atr == INVALID_FILE_ATTRIBUTES || atr & FILE_ATTRIBUTE_DIRECTORY) + { + return true; + } + } + + return false; + } + + return true; +} + +void CreatePath(const TCHAR *szDir) +{ + if (!szDir) return; + + DWORD dwAttributes; + TCHAR *pszLastBackslash, szTestDir[ MAX_PATH ]; + + lstrcpyn( szTestDir, szDir, SIZEOF( szTestDir )); + if (( dwAttributes = GetFileAttributes( szTestDir )) != INVALID_FILE_ATTRIBUTES && ( dwAttributes & FILE_ATTRIBUTE_DIRECTORY )) + return; + + pszLastBackslash = _tcsrchr( szTestDir, '\\' ); + if ( pszLastBackslash == NULL ) + return; + + *pszLastBackslash = '\0'; + CreatePath( szTestDir ); + *pszLastBackslash = '\\'; + + CreateDirectory( szTestDir, NULL ); +} + +INT_PTR ExecuteTaskService(WPARAM wParam, LPARAM lParam) +{ + EnterCriticalSection(&Options::instance->criticalSection); + int taskNr = (int)wParam; + if(taskNr < 0 || taskNr >= (int)Options::instance->taskOptions.size()) + { + LeaveCriticalSection(&Options::instance->criticalSection); + return FALSE; + } + + Options::instance->taskOptions[taskNr].forceExecute = true; + Options::instance->taskOptions[taskNr].showMBAfterExecute = true; + LeaveCriticalSection(&Options::instance->criticalSection); + StartThread(false); + return TRUE; +} + +void DoError(const TaskOptions& to, const std::wstring _error) +{ + TCHAR msg[256]; + _stprintf_s(msg, TranslateT("Task '%s' execution failed:"), to.taskName.c_str()); + if(Options::instance->schedulerHistoryAlerts) + { + std::wstring error = msg; + error += L"\n"; + error += _error; + DBEVENTINFO dbei = {0}; + dbei.cbSize = sizeof(DBEVENTINFO); + dbei.szModule = MODULE; + dbei.flags = DBEF_UTF | DBEF_READ; + dbei.timestamp = time(NULL); + // For now I do not convert event data from string to blob, and event type must be message to handle it properly + dbei.eventType = EVENTTYPE_MESSAGE; + int len = (int)error.length() + 1; + dbei.cbBlob = WideCharToMultiByte(CP_UTF8, 0, error.c_str(), len, NULL, 0, NULL, NULL); + char* buf = new char[dbei.cbBlob]; + dbei.cbBlob = WideCharToMultiByte(CP_UTF8, 0, error.c_str(), len, buf, dbei.cbBlob, NULL, NULL); + dbei.pBlob = (PBYTE)buf; + CallService(MS_DB_EVENT_ADD, NULL, (LPARAM) & dbei); + } + + + if(Options::instance->schedulerAlerts) + { + if(CallService(MS_SYSTEM_TERMINATED, 0, 0)) return; + if(ServiceExists(MS_POPUP_ADDPOPUPCLASS)) + { + ShowClassPopupT(MODULE, msg, (wchar_t*)_error.c_str()); + } + else if (ServiceExists( MS_POPUP_ADDPOPUPT )) + { + POPUPDATAT ppd = {0}; + ppd.lchIcon = LoadSkinnedIcon(SKINICON_OTHER_HISTORY); + _tcscpy_s(ppd.lptzContactName, msg); + _tcscpy_s(ppd.lptzText, _error.c_str()); + CallService(MS_POPUP_ADDPOPUPT, (WPARAM)&ppd, 0); + } + } +} diff --git a/plugins/BasicHistory/src/SearchContext.h b/plugins/BasicHistory/src/SearchContext.h new file mode 100644 index 0000000000..6b1655d857 --- /dev/null +++ b/plugins/BasicHistory/src/SearchContext.h @@ -0,0 +1,55 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once +#include "EventList.h" + +class SearchContext : public EventList +{ +public: + HWND editWindow; + HWND findWindow; + HWND toolbarWindow; + HWND listWindow; + int selected; + + virtual void SelectEventGroup(int sel) = 0; + virtual HANDLE GetNextContact(HANDLE hContact, int adder) = 0; + virtual void SelectContact(HANDLE _hContact) = 0; + + struct MessageData + { + MessageData(const std::wstring& _description, int _startPos, int _endPos, bool _isMe, DWORD _timestamp) + :description(_description) + { + startPos = _startPos; + endPos = _endPos; + isMe = _isMe; + timestamp = _timestamp; + } + + std::wstring description; + int startPos; + int endPos; + bool isMe; + DWORD timestamp; + }; + + std::vector currentGroup; +}; + diff --git a/plugins/BasicHistory/src/Searcher.cpp b/plugins/BasicHistory/src/Searcher.cpp new file mode 100644 index 0000000000..c93685bcf3 --- /dev/null +++ b/plugins/BasicHistory/src/Searcher.cpp @@ -0,0 +1,388 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#include "StdAfx.h" +#include "Searcher.h" +#include "resource.h" + +Searcher::Searcher() + :lastFindSelection(-1), + findBack(false), + matchCase(false), + matchWholeWords(false), + onlyIn(false), + onlyOut(false), + context(NULL) +{ +} + +void Searcher::ChangeFindDirection(bool isBack) +{ + if(isBack != findBack) + { + findBack = isBack; + ClearFind(); + TBBUTTONINFO tbInfo; + tbInfo.cbSize = sizeof(TBBUTTONINFO); + tbInfo.dwMask = TBIF_TEXT | TBIF_IMAGE; + if(isBack) + { + tbInfo.pszText = TranslateT("Find Previous"); + tbInfo.iImage = 1; + } + else + { + tbInfo.pszText = TranslateT("Find Next"); + tbInfo.iImage = 0; + } + SendMessage(context->toolbarWindow, TB_SETBUTTONINFO, (WPARAM)IDM_FIND, (LPARAM)&tbInfo); + } + + Find(); +} + +void Searcher::ClearFind() +{ + if(lastFindSelection != -1) + { + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_AND,~ECO_NOHIDESEL); + lastFindSelection = -1; + } +} + +inline TCHAR mytoupper(TCHAR a, std::locale* loc) +{ + return std::toupper(a, *loc); +} + +bool Searcher::CompareStr(std::wstring str, TCHAR *strFind) +{ + std::locale loc; + if(!matchCase) + std::transform(str.begin(), str.end(), str.begin(), std::bind2nd(std::ptr_fun(mytoupper), &loc)); + if(!matchWholeWords) + return str.find(strFind) < str.length(); + size_t findid = str.find(strFind); + size_t findLen = _tcslen(strFind); + while(findid < str.length()) + { + if((findid == 0 || std::isspace(str[findid - 1], loc) || std::ispunct(str[findid - 1], loc)) && + (findid + findLen >= str.length() || std::isspace(str[findid + findLen], loc) || std::ispunct(str[findid + findLen], loc))) + return true; + findid = str.find(strFind, findid + 1); + } + + return false; +} + +void Searcher::Find() +{ + FINDTEXTEX ft; + TCHAR str[128]; + int curSel = 0; + bool isStart = false; + bool finished = false; + ft.chrg.cpMin = 0; + ft.chrg.cpMax = -1; + ft.lpstrText = str; + if(context->currentGroup.size() < 1) + { + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_AND,~ECO_NOHIDESEL); + lastFindSelection = -1; + return; + } + + GetWindowText(context->findWindow, str, 128); + if(!str[0]) + { + TCHAR buf[256]; + mir_sntprintf(buf, 256, TranslateT("\"%s\" not found"), str); + MessageBox(context->hWnd, buf, TranslateT("Search"), MB_OK | MB_ICONINFORMATION); + return; + } + if(!matchCase) + { + std::locale loc; + std::transform(str, str + _tcslen(str), str, std::bind2nd(std::ptr_fun(mytoupper), &loc)); + } + + bool findBack1 = findBack ^ !searchForInMes; + bool findBack2 = findBack ^ !searchForInLG; + int adder1 = findBack1 ? -1 : 1; + int adder2 = findBack2 ? -1 : 1; + WPARAM findStyle = (findBack1 ? 0 : FR_DOWN) | (matchCase ? FR_MATCHCASE : 0) | (matchWholeWords ? FR_WHOLEWORD : 0); + if(lastFindSelection >= 0 && lastFindSelection < (int)context->currentGroup.size()) + { + if(onlyIn && context->currentGroup[lastFindSelection].isMe || onlyOut && !context->currentGroup[lastFindSelection].isMe) + { + curSel = lastFindSelection + adder1; + } + else + { + SendDlgItemMessage(context->hWnd,IDC_EDIT,EM_EXGETSEL,0,(LPARAM)&ft.chrg); + if(findBack1) + { + ft.chrg.cpMin = ft.chrg.cpMin < context->currentGroup[lastFindSelection].endPos ? ft.chrg.cpMin : context->currentGroup[lastFindSelection].endPos; + ft.chrg.cpMax = context->currentGroup[lastFindSelection].startPos; + } + else + { + ft.chrg.cpMin = ft.chrg.cpMax > context->currentGroup[lastFindSelection].startPos ? ft.chrg.cpMax : context->currentGroup[lastFindSelection].startPos; + ft.chrg.cpMax = context->currentGroup[lastFindSelection].endPos; + } + SendMessage(context->editWindow,EM_FINDTEXTEX, findStyle,(LPARAM)&ft); + if(ft.chrgText.cpMin < 0 || ft.chrgText.cpMax < 0) + { + curSel = lastFindSelection + adder1; + } + else + { + if(isFindContactChanged && startFindContact == context->hContact && isFindSelChanged && context->selected == startFindSel && ((!findBack1 && ft.chrg.cpMin >= startFindPos) || (findBack1 && ft.chrg.cpMax <= startFindPos))) + { + finished = true; + } + else + { + curSel = lastFindSelection; + SendMessage(context->editWindow,EM_EXSETSEL,0,(LPARAM)&ft.chrgText); + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_OR,ECO_NOHIDESEL); + lastFindSelection = curSel; + return; + } + } + } + } + else + { + isStart = true; + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_OR,ECO_NOHIDESEL); + SendMessage(context->editWindow,EM_EXGETSEL,0,(LPARAM)&ft.chrg); + startFindPos = findBack1 ? ft.chrg.cpMin : (ft.chrg.cpMax >= 0 ? ft.chrg.cpMax : ft.chrg.cpMin); + startFindSel = context->selected; + if(startFindPos < 0) + startFindPos = 0; + isFindSelChanged = false; + startFindContact = context->hContact; + isFindContactChanged = !allUsers; + if(findBack1) + for(curSel = (int)context->currentGroup.size() - 1; curSel >= 0; --curSel) + { + if(context->currentGroup[curSel].startPos < startFindPos) + break; + } + else + for(; curSel < (int)context->currentGroup.size(); ++curSel) + { + if(context->currentGroup[curSel].endPos > startFindPos) + break; + } + } + + if(!finished) + { + for(; curSel < (int)context->currentGroup.size() && curSel >= 0; curSel += adder1) + { + if(onlyIn && context->currentGroup[curSel].isMe || onlyOut && !context->currentGroup[curSel].isMe) + continue; + if(CompareStr(context->currentGroup[curSel].description, str)) + { + if(findBack1) + { + ft.chrg.cpMin = context->currentGroup[curSel].endPos; + ft.chrg.cpMax = context->currentGroup[curSel].startPos; + if(!isFindSelChanged && ft.chrg.cpMin > startFindPos) + ft.chrg.cpMin = startFindPos; + } + else + { + ft.chrg.cpMin = context->currentGroup[curSel].startPos; + ft.chrg.cpMax = context->currentGroup[curSel].endPos; + if(!isFindSelChanged && ft.chrg.cpMin < startFindPos) + ft.chrg.cpMin = startFindPos; + } + SendMessage(context->editWindow,EM_FINDTEXTEX, findStyle,(LPARAM)&ft); + if(!(ft.chrgText.cpMin < 0 || ft.chrgText.cpMax < 0)) + { + if(isFindContactChanged && startFindContact == context->hContact && isFindSelChanged && context->selected == startFindSel && ((!findBack1 && ft.chrg.cpMin >= startFindPos) || (findBack1 && ft.chrg.cpMax <= startFindPos))) + { + finished = true; + break; + } + SendMessage(context->editWindow,EM_EXSETSEL,0,(LPARAM)&ft.chrgText); + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_OR,ECO_NOHIDESEL); + lastFindSelection = curSel; + return; + } + } + } + } + + if(isFindContactChanged && startFindContact == context->hContact && isFindSelChanged && context->selected == startFindSel) + { + finished = true; + } + + if(!finished) + { + isFindSelChanged = true; + if(onlyGroup) + { + if(IsInSel(context->selected, str)) + { + CHARRANGE ch; + ch.cpMin = ch.cpMax = findBack1 ? MAXLONG : 0; + SendMessage(context->editWindow,EM_EXSETSEL,0,(LPARAM)&ch); + lastFindSelection = findBack1 ? (int)context->currentGroup.size() - 1 : 0; + Find(); + return; + } + } + else + { + for(int sel = context->selected + adder2; ; sel += adder2) + { + if(sel < 0) + { + isFindContactChanged = true; + if(allUsers) + { + HANDLE hNext = context->hContact; + do + { + hNext = context->GetNextContact(hNext, adder2); + } + while(hNext != startFindContact && !context->SearchInContact(hNext, str, this)); + context->SelectContact(hNext); + } + + sel = (int)context->eventList.size() - 1; + } + else if(sel >= (int)context->eventList.size()) + { + isFindContactChanged = true; + if(allUsers) + { + HANDLE hNext = context->hContact; + do + { + hNext = context->GetNextContact(hNext, adder2); + } + while(hNext != startFindContact && !context->SearchInContact(hNext, str, this)); + context->SelectContact(hNext); + } + + sel = 0; + } + if(IsInSel(sel, str)) + { + LVITEM item = {0}; + item.mask = LVIF_STATE; + item.iItem = context->selected; + item.state = 0; + item.stateMask = LVIS_SELECTED; + ListView_SetItem(context->listWindow, &item); + item.iItem = sel; + item.state = LVIS_SELECTED; + ListView_SetItem(context->listWindow, &item); + ListView_EnsureVisible(context->listWindow, sel, FALSE); + CHARRANGE ch; + ch.cpMin = ch.cpMax = findBack1 ? MAXLONG : 0; + SendMessage(context->editWindow,EM_EXSETSEL,0,(LPARAM)&ch); + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_OR,ECO_NOHIDESEL); + lastFindSelection = findBack1 ? (int)context->currentGroup.size() - 1 : 0; + isFindSelChanged = true; + Find(); + return; + } + if(startFindContact == context->hContact && sel == startFindSel) + break; + } + } + } + + if(startFindContact != context->hContact) + { + context->SelectContact(startFindContact); + } + + if(startFindSel != context->selected) + { + LVITEM item = {0}; + item.mask = LVIF_STATE; + item.iItem = context->selected; + item.state = 0; + item.stateMask = LVIS_SELECTED; + ListView_SetItem(context->listWindow, &item); + item.iItem = startFindSel; + item.state = LVIS_SELECTED; + ListView_SetItem(context->listWindow, &item); + ListView_EnsureVisible(context->listWindow, startFindSel, FALSE); + context->SelectEventGroup(startFindSel); + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_OR,ECO_NOHIDESEL); + } + ft.chrgText.cpMin = startFindPos; + ft.chrgText.cpMax = startFindPos; + SendMessage(context->editWindow,EM_EXSETSEL,0,(LPARAM)&ft.chrgText); + SendMessage(context->editWindow,EM_SETOPTIONS,ECOOP_AND,~ECO_NOHIDESEL); + lastFindSelection = -1; + if(isStart) + { + TCHAR buf[256]; + GetWindowText(context->findWindow, str, 128); + mir_sntprintf(buf, 256, TranslateT("\"%s\" not found"), str); + MessageBox(context->hWnd, buf, TranslateT("Search"), MB_OK | MB_ICONINFORMATION); + } + else + { + MessageBox(context->hWnd, TranslateTS(onlyGroup ? LPGENT("You have reached the end of the group.") : LPGENT("You have reached the end of the history.")), TranslateT("Search"), MB_OK | MB_ICONINFORMATION); + } +} + +bool Searcher::IsInSel(int sel, TCHAR *strFind) +{ + if(sel < 0 || sel >= (int)context->eventList.size()) + return false; + + TCHAR str[MAXSELECTSTR + 8]; // for safety reason + EventList::EventData data; + for(std::deque::iterator it = context->eventList[sel].begin(); it != context->eventList[sel].end(); ++it) + { + EventList::EventIndex hDbEvent = *it; + if(context->GetEventData(hDbEvent, data)) + { + bool isMe = data.isMe; + if(onlyIn && isMe || onlyOut && !isMe) + continue; + context->GetEventMessage(hDbEvent, str); + if(CompareStr(str, strFind)) + { + return true; + } + } + } + + return false; +} + +bool Searcher::Compare(const bool isMe, const std::wstring& message, TCHAR *strFind) +{ + if(onlyIn && isMe || onlyOut && !isMe) + return false; + + return CompareStr(message, strFind); +} diff --git a/plugins/BasicHistory/src/Searcher.h b/plugins/BasicHistory/src/Searcher.h new file mode 100644 index 0000000000..2f5aff6e8b --- /dev/null +++ b/plugins/BasicHistory/src/Searcher.h @@ -0,0 +1,119 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once +#include "SearchContext.h" + +class Searcher : ComparatorInterface +{ +private: + SearchContext* context; + int lastFindSelection; + int startFindPos; + int startFindSel; + HANDLE startFindContact; + bool isFindSelChanged; + bool isFindContactChanged; + bool findBack, matchCase, matchWholeWords, onlyIn, onlyOut, onlyGroup, allUsers, searchForInLG, searchForInMes; + + bool CompareStr(std::wstring str, TCHAR *strFind); + bool IsInSel(int sel, TCHAR *strFind); +public: + Searcher(); + virtual bool Compare(const bool isMe, const std::wstring& message, TCHAR *strFind); + void Find(); + void ChangeFindDirection(bool isBack); + void ClearFind(); + void SetContect(SearchContext* _context){ + context = _context; + } + void SetMatchCase(bool val){ + matchCase = val; + ClearFind(); + } + void SetMatchWholeWords(bool val){ + matchWholeWords = val; + ClearFind(); + } + bool IsMatchCase(){ + return matchCase; + } + bool IsMatchWholeWords(){ + return matchWholeWords; + } + bool IsFindBack(){ + return findBack; + } + void SetOnlyIn(bool val){ + onlyIn = val; + if(val && onlyOut) + onlyOut = false; + ClearFind(); + } + void SetOnlyOut(bool val){ + onlyOut = val; + if(val && onlyIn) + onlyIn = false; + ClearFind(); + } + bool IsOnlyIn(){ + return onlyIn; + } + bool IsOnlyOut(){ + return onlyOut; + } + void SetOnlyGroup(bool val){ + onlyGroup = val; + if(onlyGroup) + allUsers = false; + ClearFind(); + } + bool IsOnlyGroup(){ + return onlyGroup; + } + void SetAllUsers(bool val){ + allUsers = val; + if(allUsers) + onlyGroup = false; + ClearFind(); + } + bool IsAllUsers(){ + return allUsers; + } + void SetSearchForInLG(bool val){ + if(searchForInLG != val) + { + searchForInLG = val; + ClearFind(); + } + } + void SetSearchForInMes(bool val){ + if(searchForInMes != val) + { + searchForInMes = val; + ClearFind(); + } + } + bool IsSearchForInLG(){ + return searchForInLG; + } + bool IsSearchForInMes(){ + return searchForInMes; + } +}; + diff --git a/plugins/BasicHistory/src/TxtExport.cpp b/plugins/BasicHistory/src/TxtExport.cpp new file mode 100644 index 0000000000..a5ca8afddf --- /dev/null +++ b/plugins/BasicHistory/src/TxtExport.cpp @@ -0,0 +1,65 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#include "StdAfx.h" +#include "TxtExport.h" +#define EXP_FILE (*stream) + +TxtExport::~TxtExport() +{ +} + +void TxtExport::WriteHeader(const std::wstring &fileName, const std::wstring &filterName, const std::wstring &myName, const std::wstring &myId, const std::wstring &name1, const std::wstring &proto1, const std::wstring &id1, const std::string& baseProto1, const std::wstring& encoding) +{ + TCHAR* start = TranslateT("###"); + EXP_FILE << start << "\n" << start << _T(" ") << TranslateT("History Log") << _T("\n"); + EXP_FILE << start << _T(" ") << myName; + if(proto1.length() || myId.length()) + { + EXP_FILE << _T(" (") << proto1 << _T(": ") << myId << _T(") - "); + } + else + { + EXP_FILE << _T(" - "); + } + + EXP_FILE << name1; + if(proto1.length() || id1.length()) + { + EXP_FILE << _T(" (") << proto1 << _T(": ") << id1 << _T(")\n"); + } + else + { + EXP_FILE << _T("\n"); + } + + EXP_FILE << start << _T(" ") << TranslateT("Filter:") << _T(" ") << filterName << _T("\n") << start << _T("\n"); +} + +void TxtExport::WriteFooter() +{ +} + +void TxtExport::WriteGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText) +{ +} + +void TxtExport::WriteMessage(bool isMe, const std::wstring &longDate, const std::wstring &shortDate, const std::wstring &user, const std::wstring &message, const DBEVENTINFO& dbei) +{ + EXP_FILE << "\n[" << longDate << "] " << user << ":\n" << message << "\n"; +} diff --git a/plugins/BasicHistory/src/TxtExport.h b/plugins/BasicHistory/src/TxtExport.h new file mode 100644 index 0000000000..bee2718649 --- /dev/null +++ b/plugins/BasicHistory/src/TxtExport.h @@ -0,0 +1,38 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once +#include "IExport.h" + +class TxtExport : + public IExport +{ +public: + virtual const TCHAR* GetExt() + { + return _T("txt"); + } + + virtual void WriteHeader(const std::wstring &fileName, const std::wstring &filterName, const std::wstring &myName, const std::wstring &myId, const std::wstring &name1, const std::wstring &proto1, const std::wstring &id1, const std::string& baseProto1, const std::wstring& encoding); + virtual void WriteFooter(); + virtual void WriteGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText); + virtual void WriteMessage(bool isMe, const std::wstring &longDate, const std::wstring &shortDate, const std::wstring &user, const std::wstring &message, const DBEVENTINFO& dbei); + + virtual ~TxtExport(); +}; + diff --git a/plugins/BasicHistory/src/codecvt_CodePage.h b/plugins/BasicHistory/src/codecvt_CodePage.h new file mode 100644 index 0000000000..37b6b7d26f --- /dev/null +++ b/plugins/BasicHistory/src/codecvt_CodePage.h @@ -0,0 +1,98 @@ +/* +Basic History plugin +Copyright (C) 2011-2012 Krzysztof Kral + +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 version 2 +of the License. + +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, see . +*/ + +#pragma once + +template +class codecvt_CodePage : public std::codecvt<_Elem, char, mbstate_t> +{ +private: + UINT codePage; +public: + typedef std::codecvt<_Elem, char, mbstate_t> _Mybase; + typedef typename _Mybase::result result; + typedef char _Byte; + typedef _Elem intern_type; + typedef _Byte extern_type; + typedef mbstate_t state_type; + + explicit codecvt_CodePage(UINT _codePage) + : _Mybase(0), + codePage(_codePage) + { // construct with ref count + } + + virtual ~codecvt_CodePage() + { // destroy the object + } + +protected: + virtual result do_in(mbstate_t& _State, const _Byte *_First1, const _Byte *_Last1, const _Byte *& _Mid1, _Elem *_First2, _Elem *_Last2, _Elem *& _Mid2) const + { // convert bytes [_First1, _Last1) to [_First2, _Last) + return (_Mybase::error); // not implemented + } + + virtual result do_out(mbstate_t& _State, const _Elem *_First1, const _Elem *_Last1, const _Elem *& _Mid1, _Byte *_First2, _Byte *_Last2, _Byte *& _Mid2) const + { // convert [_First1, _Last1) to bytes [_First2, _Last) + _Mid1 = _First1; + _Mid2 = _First2; + + int conv = WideCharToMultiByte(codePage, 0, _First1, _Last1 - _First1, _First2, _Last2 - _First2, NULL, NULL); + if(conv == 0) + { + if(GetLastError() == ERROR_INSUFFICIENT_BUFFER) + return (_Mybase::partial); + else + return (_Mybase::error); + } + else + { + _Mid1 = _Last1; + _Mid2 = _First2 + conv; + } + + return (_Mybase::ok); + } + + virtual result do_unshift(mbstate_t&, + _Byte *_First2, _Byte *, _Byte *& _Mid2) const + { // generate bytes to return to default shift state + _Mid2 = _First2; + return (_Mybase::ok); + } + + virtual int do_length(const mbstate_t& _State, const _Byte *_First1, const _Byte *_Last1, size_t _Count) const _THROW0() + { // return min(_Count, converted length of bytes [_First1, _Last1)) + return (int)_Count; // not implemented + } + + virtual bool do_always_noconv() const _THROW0() + { // return true if conversions never change input + return (false); + } + + virtual int do_max_length() const _THROW0() + { // return maximum length required for a conversion + return 6; + } + + virtual int do_encoding() const _THROW0() + { // return length of code sequence (from codecvt) + return 0; // -1 => state dependent, 0 => varying length + } +}; diff --git a/plugins/BasicHistory/src/dllmain.cpp b/plugins/BasicHistory/src/dllmain.cpp new file mode 100644 index 0000000000..ad89773ec8 --- /dev/null +++ b/plugins/BasicHistory/src/dllmain.cpp @@ -0,0 +1,14 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "stdafx.h" + +HINSTANCE hInst; + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + hInst = hModule; + return TRUE; +} + diff --git a/plugins/BasicHistory/src/resource.h b/plugins/BasicHistory/src/resource.h new file mode 100644 index 0000000000..71484f2343 --- /dev/null +++ b/plugins/BasicHistory/src/resource.h @@ -0,0 +1,157 @@ + +#define IDD_HISTORY 101 +#define IDD_OPT_MAIN 102 +#define IDD_OPT_GROUPLIST 103 +#define IDD_OPT_MESSAGES 104 +#define IDD_OPT_SEARCHING 105 +#define IDD_OPT_EXPORT 106 +#define IDD_OPT_SCHEDULER 107 +#define IDD_DLG_TASK 108 +#define IDC_EDIT 1001 +#define IDC_LIST 1002 +#define IDC_DELETEHISTORY 1004 +#define IDC_SPLITTER 1005 +#define IDC_FIND_TEXT 1006 +#define IDC_LIST_CONTACTS 1007 +#define IDC_SPLITTERV 1008 +#define IDC_SHOWHIDE 1009 +#define IDC_TOOLBAR 1010 +#define IDC_SHOWCONTACTS 1011 +#define IDC_NEWONTOP 1012 +#define IDC_SHOWEVENTS 1013 +#define IDC_SHOWTIME 1014 +#define IDC_SHOWNAME 1015 +#define IDC_SHOWMESSAGE 1016 +#define IDC_MESSAGELEN 1017 +#define IDC_MESSAGELEN_DESC 1018 +#define IDC_GROUPTIME 1019 +#define IDC_LIMITMESSAGES 1020 +#define IDC_SHOWDATE 1021 +#define IDC_SHOWSECOND 1022 +#define IDC_SHOWSMILEYS 1023 +#define IDC_FORLIST 1024 +#define IDC_FORMES 1025 +#define IDC_MATCHCASE 1026 +#define IDC_MATCHWHOLE 1027 +#define IDC_ONLYIN 1028 +#define IDC_ONLYOUT 1029 +#define IDC_ONLYGROUP 1030 +#define IDC_DEFFILTER 1031 +#define IDC_LIST_FILTERS 1032 +#define IDC_LIST_EVENTS 1033 +#define IDC_ADD_FILTER 1034 +#define IDC_DELETE_FILTER 1035 +#define IDC_FILTER_NAME 1036 +#define IDC_EVENT 1037 +#define IDC_ADD_EVENT 1038 +#define IDC_DELETE_EVENT 1039 +#define IDC_SHOWCONTACTGROUPS 1040 +#define IDC_TXTENC 1041 +#define IDC_HTML1ENC 1042 +#define IDC_HTML1DATE 1043 +#define IDC_HTML2ENC 1044 +#define IDC_HTML2DATE 1045 +#define IDC_HTML2SHOWSMILEYS 1046 +#define IDC_HTML2EXTCSS 1047 +#define IDC_HTML2EXTCSSFILE 1048 +#define IDC_LIST_TASKS 1049 +#define IDC_ADD_TASK 1050 +#define IDC_EDIT_TASK 1051 +#define IDC_DELETE_TASK 1052 +#define IDC_TASK_TYPE 1053 +#define IDC_TASK_FILTER 1054 +#define IDC_LIST_CONTACTSEX 1055 +#define IDC_EVENT_TIME 1056 +#define IDC_EVENT_UNIT 1057 +#define IDC_TRIGER_TYPE 1058 +#define IDC_EXPORT_TYPE 1059 +#define IDC_EXPORT_TYPE_LABEL 1060 +#define IDC_COMPRESS 1061 +#define IDC_EXPORT_PATH 1062 +#define IDC_EXPORT_PATH_LABEL 1063 +#define IDC_TASK_STAR 1064 +#define IDC_FTP 1065 +#define IDC_UPLOAD 1066 +#define IDC_FTP_LABEL 1067 +#define IDC_TRIGER_TIME 1068 +#define IDC_TRIGER_TIME_LABEL 1069 +#define IDC_TRIGER_WEEK 1070 +#define IDC_TRIGER_WEEK_LABEL 1071 +#define IDC_TRIGER_DAY 1072 +#define IDC_TRIGER_DAY_LABEL 1073 +#define IDC_TRIGER_DELTA_TIME 1074 +#define IDC_TRIGER_DELTA_TIME_LABEL 1075 +#define IDC_WINSCP 1076 +#define IDC_WINSCPLOG 1077 +#define IDC_TASK_NAME 1078 +#define IDC_TASK_ACTIVE 1079 +#define IDC_TASK_FILTER_LABEL 1080 +#define IDC_EVENT_LABEL 1081 +#define IDC_IMPORT_TYPE 1082 +#define IDC_PASSWORD 1083 +#define IDC_PASSWORD_LABEL 1084 +#define IDC_EXPIMP 1085 +#define IDC_WINSCP_BROWSE 1086 +#define IDC_WINSCPLOG_BROWSE 1087 +#define IDC_CSS_BROWSE 1088 +#define IDC_SCHEDULER_ALERTS 1089 +#define IDC_SCHEDULER_HISTORY_ALERTS 1090 +#define IDC_ALLCONTACTS 1091 +#define IDI_INM 20000 +#define IDI_OUTM 20001 +#define IDI_SHOW 20002 +#define IDI_HIDE 20003 +#define IDI_FINDNEXT 20004 +#define IDI_FINDPREV 20005 +#define IDI_STATUS 20008 +#define IDR_CSS 20009 +#define IDR_JS 20010 +#define IDI_PLUSEX 20011 +#define IDI_MINUSEX 20012 +#define IDM_FIND 40001 +#define IDM_CONFIG 40002 +#define IDM_FINDNEXT 40003 +#define IDM_FINDPREV 40004 +#define IDM_MATCHCASE 40005 +#define IDM_MATCHWHOLE 40006 +#define IDM_OPTIONS 40007 +#define IDM_FONTS 40008 +#define IDM_ICONS 40009 +#define IDM_HOTKEYS 40010 +#define IDM_SAVEPOS 40011 +#define IDM_SAVEPOSALL 40012 +#define IDM_ONLYIN 40013 +#define IDM_ONLYOUT 40014 +#define IDM_DELETE 40015 +#define IDM_DELETEGROUP 40016 +#define IDM_DELETEUSER 40017 +#define IDM_MESSAGE 40018 +#define IDM_COPY 40019 +#define IDM_OPENNEW 40020 +#define IDM_OPENEXISTING 40021 +#define IDM_COPYLINK 40022 +#define IDM_ONLYGROUP 40023 +#define IDM_QUOTE 40024 +#define IDM_FILTERDEF 40025 +#define IDM_FILTERALL 40026 +#define IDM_EXPORTRHTML 40027 +#define IDM_EXPORTPHTML 40028 +#define IDM_EXPORTTXT 40029 +#define IDM_EXPORTBINARY 40030 +#define IDM_IMPORTBINARY 40031 +#define IDM_EXPORTDAT 40032 +#define IDM_IMPORTDAT 40033 +#define IDM_ALLUSERS 40034 + +#define CUSTOMRES 300 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 106 +#define _APS_NEXT_COMMAND_VALUE 40024 +#define _APS_NEXT_CONTROL_VALUE 1030 +#define _APS_NEXT_SYMED_VALUE 106 +#endif +#endif diff --git a/plugins/BasicHistory/src/stdafx.cpp b/plugins/BasicHistory/src/stdafx.cpp new file mode 100644 index 0000000000..dd47c41552 --- /dev/null +++ b/plugins/BasicHistory/src/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// BasicHistory.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/plugins/BasicHistory/src/stdafx.h b/plugins/BasicHistory/src/stdafx.h new file mode 100644 index 0000000000..bc670d4358 --- /dev/null +++ b/plugins/BasicHistory/src/stdafx.h @@ -0,0 +1,88 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#ifndef _WIN64 +#define _USE_32BIT_TIME_T +#endif + +#define _CRT_SECURE_NO_WARNINGS +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define MIRANDA_VER 0x0900 +#define MIRANDA_CUSTOM_LP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "m_updater.h" +#include "m_smileyadd.h" +#include "m_toolbar.h" +#include "m_metacontacts.h" + +#define HISTORY_HK_FIND 100 +#define HISTORY_HK_FINDNEXT 101 +#define HISTORY_HK_FINDPREV 102 +#define HISTORY_HK_MATCHCASE 103 +#define HISTORY_HK_MATCHWHOLE 104 +#define HISTORY_HK_SHOWCONTACTS 105 +#define HISTORY_HK_ONLYIN 106 +#define HISTORY_HK_ONLYOUT 107 +#define HISTORY_HK_DELETE 108 +#define HISTORY_HK_ONLYGROUP 109 +#define HISTORY_HK_EXRHTML 110 +#define HISTORY_HK_EXPHTML 111 +#define HISTORY_HK_EXTXT 112 +#define HISTORY_HK_EXBIN 113 +#define HISTORY_HK_IMPBIN 114 +#define HISTORY_HK_EXDAT 115 +#define HISTORY_HK_IMPDAT 116 +#define HISTORY_HK_ALLCONTACTS 117 + +#define EVENTTYPE_STATUSCHANGE 25368 +#define EVENTTYPE_SMTPSIMPLE 2350 \ No newline at end of file diff --git a/plugins/BasicHistory/src/targetver.h b/plugins/BasicHistory/src/targetver.h new file mode 100644 index 0000000000..90e767bfce --- /dev/null +++ b/plugins/BasicHistory/src/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/plugins/BasicHistory/src/version.h b/plugins/BasicHistory/src/version.h new file mode 100644 index 0000000000..8b7d5ce949 --- /dev/null +++ b/plugins/BasicHistory/src/version.h @@ -0,0 +1,20 @@ +#define __MAJOR_VERSION 1 +#define __MINOR_VERSION 0 +#define __RELEASE_NUM 1 +#define __BUILD_NUM 6 + +#define __FILEVERSION_STRING __MAJOR_VERSION,__MINOR_VERSION,__RELEASE_NUM,__BUILD_NUM +#define __FILEVERSION_DOTS __MAJOR_VERSION.__MINOR_VERSION.__RELEASE_NUM.__BUILD_NUM + +#define __STRINGIFY_IMPL(x) #x +#define __STRINGIFY(x) __STRINGIFY_IMPL(x) +#define __VERSION_STRING __STRINGIFY(__FILEVERSION_DOTS) + +#define __PLUGIN_NAME "Basic History" +#define __INTERNAL_NAME "BasicHistory" +#define __FILENAME "BasicHistory.dll" +#define __DESCRIPTION "History viewer for Miranda IM." +#define __AUTHOR "Krzysztof Kral" +#define __AUTHOREMAIL "krzysztof.kral@gmail.com" +#define __AUTHORWEB "http://programista.free.of.pl/miranda/" +#define __COPYRIGHT "Copyright (c) 2011-2012 Krzysztof Kral" -- cgit v1.2.3