summaryrefslogtreecommitdiff
path: root/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'plugins')
-rw-r--r--plugins/BasicHistory/BasicHistory.cpp437
-rw-r--r--plugins/BasicHistory/BasicHistory.rc263
-rw-r--r--plugins/BasicHistory/BasicHistory.sln26
-rw-r--r--plugins/BasicHistory/BasicHistory.vcxproj275
-rw-r--r--plugins/BasicHistory/BasicHistory.vcxproj.filters176
-rw-r--r--plugins/BasicHistory/BinaryExport.cpp231
-rw-r--r--plugins/BasicHistory/BinaryExport.h47
-rw-r--r--plugins/BasicHistory/DatExport.cpp214
-rw-r--r--plugins/BasicHistory/DatExport.h53
-rw-r--r--plugins/BasicHistory/Docs/BasicHistory_langpack_polish.txt275
-rw-r--r--plugins/BasicHistory/Docs/BasicHistory_licence.txt340
-rw-r--r--plugins/BasicHistory/Docs/BasicHistory_readme.txt106
-rw-r--r--plugins/BasicHistory/Docs/BasicHistory_translate.txt233
-rw-r--r--plugins/BasicHistory/EventList.cpp907
-rw-r--r--plugins/BasicHistory/EventList.h161
-rw-r--r--plugins/BasicHistory/ExportManager.cpp391
-rw-r--r--plugins/BasicHistory/ExportManager.h59
-rw-r--r--plugins/BasicHistory/HistoryWindow.cpp2512
-rw-r--r--plugins/BasicHistory/HistoryWindow.h93
-rw-r--r--plugins/BasicHistory/HotkeyHelper.cpp105
-rw-r--r--plugins/BasicHistory/HotkeyHelper.h24
-rw-r--r--plugins/BasicHistory/IExport.h49
-rw-r--r--plugins/BasicHistory/IImport.h53
-rw-r--r--plugins/BasicHistory/ImageDataObject.cpp171
-rw-r--r--plugins/BasicHistory/ImageDataObject.h133
-rw-r--r--plugins/BasicHistory/Options.cpp2167
-rw-r--r--plugins/BasicHistory/Options.h196
-rw-r--r--plugins/BasicHistory/PlainHtmlExport.cpp106
-rw-r--r--plugins/BasicHistory/PlainHtmlExport.h37
-rw-r--r--plugins/BasicHistory/ReadMe.txt48
-rw-r--r--plugins/BasicHistory/RichHtmlExport.cpp545
-rw-r--r--plugins/BasicHistory/RichHtmlExport.h44
-rw-r--r--plugins/BasicHistory/Scheduler.cpp1576
-rw-r--r--plugins/BasicHistory/SearchContext.h55
-rw-r--r--plugins/BasicHistory/Searcher.cpp388
-rw-r--r--plugins/BasicHistory/Searcher.h119
-rw-r--r--plugins/BasicHistory/TxtExport.cpp65
-rw-r--r--plugins/BasicHistory/TxtExport.h38
-rw-r--r--plugins/BasicHistory/codecvt_CodePage.h98
-rw-r--r--plugins/BasicHistory/dllmain.cpp14
-rw-r--r--plugins/BasicHistory/history.css34
-rw-r--r--plugins/BasicHistory/history.js95
-rw-r--r--plugins/BasicHistory/icons/FindNext.icobin0 -> 1406 bytes
-rw-r--r--plugins/BasicHistory/icons/FindPrev.icobin0 -> 1406 bytes
-rw-r--r--plugins/BasicHistory/icons/Incom.icobin0 -> 1406 bytes
-rw-r--r--plugins/BasicHistory/icons/Outg.icobin0 -> 1406 bytes
-rw-r--r--plugins/BasicHistory/icons/Status change.icobin0 -> 1406 bytes
-rw-r--r--plugins/BasicHistory/icons/minus.icobin0 -> 4286 bytes
-rw-r--r--plugins/BasicHistory/icons/mnode.icobin0 -> 1150 bytes
-rw-r--r--plugins/BasicHistory/icons/plus.icobin0 -> 4286 bytes
-rw-r--r--plugins/BasicHistory/icons/pnode.icobin0 -> 1150 bytes
-rw-r--r--plugins/BasicHistory/lib/zlib.libbin0 -> 10532 bytes
-rw-r--r--plugins/BasicHistory/lib64/zlib.libbin0 -> 10278 bytes
-rw-r--r--plugins/BasicHistory/resource.h157
-rw-r--r--plugins/BasicHistory/stdafx.cpp8
-rw-r--r--plugins/BasicHistory/stdafx.h88
-rw-r--r--plugins/BasicHistory/targetver.h8
-rw-r--r--plugins/BasicHistory/version.h20
-rw-r--r--plugins/BasicHistory/version.rc37
-rw-r--r--plugins/BasicHistory/zip/MiniZip64_Changes.txt6
-rw-r--r--plugins/BasicHistory/zip/MiniZip64_info.txt74
-rw-r--r--plugins/BasicHistory/zip/crypt.h131
-rw-r--r--plugins/BasicHistory/zip/ioapi.c235
-rw-r--r--plugins/BasicHistory/zip/ioapi.h200
-rw-r--r--plugins/BasicHistory/zip/iowin32.c389
-rw-r--r--plugins/BasicHistory/zip/iowin32.h28
-rw-r--r--plugins/BasicHistory/zip/miniunz.c648
-rw-r--r--plugins/BasicHistory/zip/minizip.c507
-rw-r--r--plugins/BasicHistory/zip/mztools.c281
-rw-r--r--plugins/BasicHistory/zip/mztools.h31
-rw-r--r--plugins/BasicHistory/zip/unzip.c2121
-rw-r--r--plugins/BasicHistory/zip/unzip.h437
-rw-r--r--plugins/BasicHistory/zip/zconf.h428
-rw-r--r--plugins/BasicHistory/zip/zip.c2004
-rw-r--r--plugins/BasicHistory/zip/zip.h362
-rw-r--r--plugins/BasicHistory/zip/zlib.h1613
76 files changed, 22772 insertions, 0 deletions
diff --git a/plugins/BasicHistory/BasicHistory.cpp b/plugins/BasicHistory/BasicHistory.cpp
new file mode 100644
index 0000000000..bbe74a1629
--- /dev/null
+++ b/plugins/BasicHistory/BasicHistory.cpp
@@ -0,0 +1,437 @@
+/*
+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 <http://www.gnu.org/licenses/>.
+*/
+
+#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"
+
+PLUGINLINK *pluginLink;
+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<HGENMENU> 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,
+ DEFMOD_UIHISTORY,
+ MIID_BASICHISTORY
+};
+
+MM_INTERFACE mmi = {0};
+TIME_API tmi = {0};
+int hLangpack = 0;
+UTF8_INTERFACE utfi = {0};
+
+extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
+{
+ if (mirandaVersion < PLUGIN_MAKE_VERSION(0, 9, 0, 0))
+ {
+ MessageBox(0, _T("This version of BasicHistory requires Miranda 0.9.0 or later. The plugin cannot be loaded."), _T("BasicHistory"), MB_OK | MB_ICONERROR);
+ return NULL;
+ }
+
+ 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 = (HGENMENU)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&mi);
+
+ mi.position = 500060000;
+ mi.pszService = MS_HISTORY_SHOWCONTACTHISTORY;
+ CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&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 = (HGENMENU)CallService(MS_CLIST_ADDCONTACTMENUITEM,0,(LPARAM)&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 = (HGENMENU)CallService(MS_CLIST_ADDMAINMENUITEM,0,(LPARAM)&mi);
+ }
+
+ std::vector<TaskOptions>::iterator taskIt = Options::instance->taskOptions.begin();
+ std::vector<HGENMENU>::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 = (HGENMENU)CallService(MS_CLIST_ADDMAINMENUITEM, 0, (LPARAM)&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] = (HANDLE)CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ sid.pszName = "BasicHistory_out";
+ sid.ptszDescription = LPGENT("Outgoing message");
+ sid.iDefaultIndex = -IDI_OUTM;
+ hEventIcons[1] = (HANDLE)CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ sid.pszName = "BasicHistory_status";
+ sid.ptszDescription = LPGENT("Statuschange");
+ sid.iDefaultIndex = -IDI_STATUS;
+ hEventIcons[2] = (HANDLE)CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ sid.pszName = "BasicHistory_show";
+ sid.ptszDescription = LPGENT("Show Contacts");
+ sid.iDefaultIndex = -IDI_SHOW;
+ hPlusIcon = (HANDLE)CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ sid.pszName = "BasicHistory_hide";
+ sid.ptszDescription = LPGENT("Hide Contacts");
+ sid.iDefaultIndex = -IDI_HIDE;
+ hMinusIcon = (HANDLE)CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ sid.pszName = "BasicHistory_findnext";
+ sid.ptszDescription = LPGENT("Find Next");
+ sid.iDefaultIndex = -IDI_FINDNEXT;
+ hFindNextIcon = (HANDLE)CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ sid.pszName = "BasicHistory_findprev";
+ sid.ptszDescription = LPGENT("Find Previous");
+ sid.iDefaultIndex = -IDI_FINDPREV;
+ hFindPrevIcon = (HANDLE)CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ sid.pszName = "BasicHistory_plusex";
+ sid.ptszDescription = LPGENT("Plus in export");
+ sid.iDefaultIndex = -IDI_PLUSEX;
+ hPlusExIcon = (HANDLE)CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&sid);
+
+ sid.pszName = "BasicHistory_minusex";
+ sid.ptszDescription = LPGENT("Minus in export");
+ sid.iDefaultIndex = -IDI_MINUSEX;
+ hMinusExIcon = (HANDLE)CallService(MS_SKIN2_ADDICON, 0, (LPARAM)&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(PLUGINLINK *link)
+{
+ hTaskMainMenu = NULL;
+ pluginLink = link;
+ DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&g_hMainThread,0,FALSE,DUPLICATE_SAME_ACCESS);
+ mir_getMMI(&mmi);
+ mir_getTMI(&tmi);
+ mir_getLP(&pluginInfo);
+ mir_getUTFI(&utfi);
+ 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/BasicHistory.rc b/plugins/BasicHistory/BasicHistory.rc
new file mode 100644
index 0000000000..4aecce1311
--- /dev/null
+++ b/plugins/BasicHistory/BasicHistory.rc
@@ -0,0 +1,263 @@
+#include "resource.h"
+
+#define APSTUDIO_READONLY_SYMBOLS
+/////////////////////////////////////////////////////////////////////////////
+//
+// Generated from the TEXTINCLUDE 2 resource.
+//
+//#include "afxres.h"
+
+/////////////////////////////////////////////////////////////////////////////
+#undef APSTUDIO_READONLY_SYMBOLS
+
+#include <winres.h>
+#include <windows.h>
+#include <richedit.h>
+#include <commctrl.h>
+#include <tchar.h>
+#include <m_clc.h>
+
+/////////////////////////////////////////////////////////////////////////////
+// Neutral resources
+
+#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEU)
+#ifdef _WIN32
+LANGUAGE LANG_NEUTRAL, SUBLANG_NEUTRAL
+#pragma code_page(1250)
+#endif //_WIN32
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Dialog
+//
+
+IDD_HISTORY DIALOGEX 0, 0, 496, 366
+STYLE DS_SETFONT | DS_FIXEDSYS | DS_CENTER | WS_MINIMIZEBOX | WS_MAXIMIZEBOX | WS_POPUP | WS_VISIBLE | WS_CAPTION | WS_SYSMENU | WS_THICKFRAME
+EXSTYLE WS_EX_CONTROLPARENT
+CAPTION "Message History"
+FONT 8, "MS Shell Dlg", 0, 0, 0x1
+BEGIN
+ CONTROL "",IDC_LIST,WC_LISTVIEW, WS_TABSTOP | WS_BORDER | LVS_REPORT | LVS_NOCOLUMNHEADER | LVS_SHOWSELALWAYS | LVS_SINGLESEL | LVS_SHAREIMAGELISTS ,102,27,387,73
+ CONTROL "",IDC_SPLITTER,WC_STATIC,SS_ENHMETAFILE,102,100,413,2
+ CONTROL "", IDC_EDIT, RICHEDIT_CLASS, WS_VSCROLL | WS_TABSTOP | WS_BORDER | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY | ES_DISABLENOSCROLL, 102,102,387,252
+ CONTROL "", IDC_SHOWHIDE,"MButtonClass", WS_TABSTOP,7,7,16,14
+ EDITTEXT IDC_FIND_TEXT,25,8,380,12,ES_AUTOHSCROLL
+ CONTROL "", IDC_TOOLBAR,TOOLBARCLASSNAME, WS_TABSTOP | TBSTYLE_FLAT | TBSTYLE_TOOLTIPS | CCS_NOPARENTALIGN | CCS_NODIVIDER | CCS_NORESIZE,413,7,76,20
+ CONTROL "", IDC_LIST_CONTACTS, CLISTCONTROL_CLASS, WS_TABSTOP | CLS_USEGROUPS | CLS_NOHIDEOFFLINE | CLS_HIDEEMPTYGROUPS,7,27,93,327,WS_EX_CLIENTEDGE
+ CONTROL "",IDC_SPLITTERV,WC_STATIC,SS_ENHMETAFILE,100,27,2,338
+END
+
+IDD_OPT_MAIN DIALOGEX 0, 0, 304, 225
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Settings",IDC_STATIC,4,5,298,220
+ CONTROL "Always show contact list",IDC_SHOWCONTACTS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,23,270,10
+ CONTROL "Show groups in contact list",IDC_SHOWCONTACTGROUPS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,34,270,10
+ COMBOBOX IDC_DEFFILTER,172,45,122,30,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Default Event Filter",IDC_STATIC,12,48,145,8
+ GROUPBOX "Custom filters",IDC_STATIC,12,67,282,86
+ LISTBOX IDC_LIST_FILTERS,20,81,133,30, WS_TABSTOP | LBS_NOINTEGRALHEIGHT | WS_BORDER | WS_VSCROLL
+ LISTBOX IDC_LIST_EVENTS,20,113,133,30, WS_TABSTOP | LBS_NOINTEGRALHEIGHT | WS_BORDER | WS_VSCROLL
+ EDITTEXT IDC_FILTER_NAME,160,81,130,12,WS_TABSTOP|ES_AUTOHSCROLL
+ PUSHBUTTON "Add filter",IDC_ADD_FILTER,160,97,63,14, WS_TABSTOP
+ PUSHBUTTON "Delete filter",IDC_DELETE_FILTER,227,97,63,14, WS_TABSTOP
+ COMBOBOX IDC_EVENT,160,113,130,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
+ PUSHBUTTON "Add event",IDC_ADD_EVENT,160,129,63,14, WS_TABSTOP
+ PUSHBUTTON "Delete event",IDC_DELETE_EVENT,227,129,63,14, WS_TABSTOP
+ EDITTEXT IDC_WINSCP,107,160,165,12, ES_AUTOHSCROLL | WS_TABSTOP
+ PUSHBUTTON "...",IDC_WINSCP_BROWSE,274,160,20,12, WS_TABSTOP
+ LTEXT "WinSCP path",IDC_STATIC,12,163,94,8
+ EDITTEXT IDC_WINSCPLOG,107,178,165,12, ES_AUTOHSCROLL | WS_TABSTOP
+ PUSHBUTTON "...",IDC_WINSCPLOG_BROWSE,274,178,20,12, WS_TABSTOP
+ LTEXT "WinSCP log path",IDC_STATIC,12,181,94,8
+END
+
+IDD_OPT_GROUPLIST DIALOGEX 0, 0, 304, 225
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Settings",IDC_STATIC,4,5,298,220
+ CONTROL "New messages on top",IDC_NEWONTOP,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,23,270,10
+ CONTROL "Show event icons",IDC_SHOWEVENTS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,37,270,10
+ CONTROL "Show timestamps",IDC_SHOWTIME,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,51,270,10
+ CONTROL "Show names",IDC_SHOWNAME,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,65,270,10
+ CONTROL "Show messages",IDC_SHOWMESSAGE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,79,270,10
+ EDITTEXT IDC_MESSAGELEN,172,95,30,12,WS_TABSTOP|ES_AUTOHSCROLL|ES_NUMBER
+ LTEXT "Truncate message length to:",IDC_MESSAGELEN_DESC,24,97,145,8
+ EDITTEXT IDC_GROUPTIME,172,113,30,12,WS_TABSTOP|ES_AUTOHSCROLL|ES_NUMBER
+ LTEXT "Delta time to group messages:",IDC_STATIC,12,115,157,8
+ LTEXT "hours",IDC_STATIC,205,115,80,8
+ EDITTEXT IDC_LIMITMESSAGES,172,131,30,12,WS_TABSTOP|ES_AUTOHSCROLL|ES_NUMBER
+ LTEXT "Limit messages to:",IDC_STATIC,12,133,157,8
+END
+
+IDD_OPT_MESSAGES DIALOGEX 0, 0, 304, 225
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Settings",IDC_STATIC,4,5,298,220
+ CONTROL "New messages on top",IDC_NEWONTOP,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,23,270,10
+ CONTROL "Show date in timestamps",IDC_SHOWDATE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,37,270,10
+ CONTROL "Show seconds in timestamps",IDC_SHOWSECOND,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,51,270,10
+ CONTROL "Show names",IDC_SHOWNAME,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,65,270,10
+ CONTROL "Show event icons",IDC_SHOWEVENTS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,79,270,10
+ CONTROL "Enable Smileys",IDC_SHOWSMILEYS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,93,270,10
+END
+
+IDD_OPT_SEARCHING DIALOGEX 0, 0, 304, 225
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Settings",IDC_STATIC,4,5,298,220
+ CONTROL "Search forward in list group",IDC_FORLIST,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,23,270,10
+ CONTROL "Search forward in message window",IDC_FORMES,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,37,270,10
+ CONTROL "Match Case",IDC_MATCHCASE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,51,270,10
+ CONTROL "Match Whole Word",IDC_MATCHWHOLE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,65,270,10
+ CONTROL "Only Incomming Messages",IDC_ONLYIN,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,79,270,10
+ CONTROL "Only Outgoing Messages",IDC_ONLYOUT,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,93,270,10
+ CONTROL "Only Selected Group",IDC_ONLYGROUP,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,107,270,10
+ CONTROL "All Contacts",IDC_ALLCONTACTS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,121,270,10
+END
+
+IDD_OPT_EXPORT DIALOGEX 0, 0, 304, 225
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Export To Txt",IDC_STATIC,4,5,298,37
+ COMBOBOX IDC_TXTENC,142,20,152,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
+ LTEXT "File encoding*",IDC_STATIC,12,23,115,8
+ GROUPBOX "Export To Plain Html",IDC_STATIC,4,47,298,50
+ COMBOBOX IDC_HTML1ENC,142,62,152,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
+ LTEXT "File encoding*",IDC_STATIC,12,65,115,8
+ CONTROL "Show date in timestamps",IDC_HTML1DATE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,80,270,10
+ GROUPBOX "Export To Rich Html",IDC_STATIC,4,102,298,80
+ COMBOBOX IDC_HTML2ENC,142,117,152,30,CBS_DROPDOWN | WS_VSCROLL | WS_TABSTOP
+ LTEXT "File encoding*",IDC_STATIC,12,120,115,8
+ CONTROL "Show date in timestamps",IDC_HTML2DATE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,135,270,10
+ CONTROL "Enable Smileys",IDC_HTML2SHOWSMILEYS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,149,270,10
+ CONTROL "External CSS file",IDC_HTML2EXTCSS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,163,115,10
+ EDITTEXT IDC_HTML2EXTCSSFILE,142,162,130,12, ES_AUTOHSCROLL | WS_TABSTOP
+ PUSHBUTTON "...",IDC_CSS_BROWSE,274,162,20,12, WS_TABSTOP
+ LTEXT "* Choose encoding from combo box or enter code page number and name separated by semicolon, name is used in Content-Type header.",IDC_STATIC,12,188,270,24
+END
+
+IDD_OPT_SCHEDULER DIALOGEX 0, 0, 304, 225
+STYLE DS_SETFONT | DS_FIXEDSYS | WS_CHILD
+EXSTYLE WS_EX_CONTROLPARENT
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ GROUPBOX "Settings",IDC_STATIC,4,5,298,220
+ LISTBOX IDC_LIST_TASKS,12,23,208,174, WS_TABSTOP | LBS_NOINTEGRALHEIGHT | WS_BORDER | WS_VSCROLL
+ PUSHBUTTON "Add task",IDC_ADD_TASK,231,23,63,14, WS_TABSTOP
+ PUSHBUTTON "Edit task",IDC_EDIT_TASK,231,39,63,14, WS_TABSTOP
+ PUSHBUTTON "Delete task",IDC_DELETE_TASK,231,55,63,14, WS_TABSTOP
+ CONTROL "Display errors using popups",IDC_SCHEDULER_ALERTS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,200,270,10
+ CONTROL "Save errors to system history",IDC_SCHEDULER_HISTORY_ALERTS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,12,211,270,10
+END
+
+IDD_DLG_TASK DIALOGEX 0, 0, 359, 281
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | WS_POPUP | WS_CAPTION | WS_SYSMENU
+CAPTION "Task"
+FONT 8, "MS Shell Dlg", 400, 0, 0x1
+BEGIN
+ EDITTEXT IDC_TASK_NAME,85,10,109,12,WS_TABSTOP|ES_AUTOHSCROLL
+ LTEXT "Name",IDC_STATIC,10,13,73,8
+ CONTROL "Active",IDC_TASK_ACTIVE,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,28,180,10
+ COMBOBOX IDC_TASK_TYPE,85,40,109,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Action type",IDC_STATIC,10,43,73,8
+ COMBOBOX IDC_TASK_FILTER,85,55,109,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Filter",IDC_TASK_FILTER_LABEL,10,58,73,8
+ EDITTEXT IDC_EVENT_TIME,85,70,50,12,WS_TABSTOP | ES_AUTOHSCROLL
+ COMBOBOX IDC_EVENT_UNIT,140,70,54,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Events older than*",IDC_EVENT_LABEL,10,73,73,8
+ COMBOBOX IDC_TRIGER_TYPE,85,85,109,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Triger type",IDC_STATIC,10,88,73,8
+ CONTROL "", IDC_TRIGER_TIME, DATETIMEPICK_CLASS, WS_TABSTOP | DTS_TIMEFORMAT | DTS_UPDOWN, 85,99,109,15
+ LTEXT "Time",IDC_TRIGER_TIME_LABEL,10,103,73,8
+ EDITTEXT IDC_TRIGER_DELTA_TIME,85,100,109,12,WS_TABSTOP | ES_AUTOHSCROLL | ES_NUMBER
+ LTEXT "Delta time",IDC_TRIGER_DELTA_TIME_LABEL,10,103,73,8
+ COMBOBOX IDC_TRIGER_WEEK,85,115,109,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Day of week",IDC_TRIGER_WEEK_LABEL,10,118,73,8
+ EDITTEXT IDC_TRIGER_DAY,85,115,109,12,WS_TABSTOP|ES_AUTOHSCROLL|ES_NUMBER
+ LTEXT "Day",IDC_TRIGER_DAY_LABEL,10,118,73,8
+ COMBOBOX IDC_EXPORT_TYPE,85,130,109,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ COMBOBOX IDC_IMPORT_TYPE,85,130,109,12,CBS_DROPDOWNLIST | WS_VSCROLL | WS_TABSTOP
+ LTEXT "Export to",IDC_EXPORT_TYPE_LABEL,10,133,73,8
+ CONTROL "Compress output files",IDC_COMPRESS,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,148,180,10
+ EDITTEXT IDC_PASSWORD,85,160,109,12, ES_AUTOHSCROLL | ES_PASSWORD | WS_TABSTOP
+ LTEXT "Password",IDC_PASSWORD_LABEL,10,163,73,8
+ CONTROL "Upload to FTP (WinSCP requred)",IDC_UPLOAD,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,178,180,10
+ EDITTEXT IDC_FTP,85,190,109,12,ES_AUTOHSCROLL | WS_TABSTOP
+ LTEXT "Session name",IDC_FTP_LABEL,10,193,73,8
+ EDITTEXT IDC_EXPORT_PATH,85,205,109,12, ES_AUTOHSCROLL | WS_TABSTOP
+ LTEXT "Path to file**",IDC_EXPORT_PATH_LABEL,10,208,73,8
+ CONTROL "Export imported messages",IDC_EXPIMP,
+ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,10,223,180,10
+ LTEXT "* Use negative values to filter younger events",IDC_TASK_STAR,10,236,184,40
+ CONTROL "", IDC_LIST_CONTACTSEX, CLISTCONTROL_CLASS, WS_TABSTOP | CLS_GREYALTERNATE | CLS_GROUPCHECKBOXES | CLS_MULTICOLUMN | CLS_USEGROUPS | CLS_NOHIDEOFFLINE | CLS_CHECKBOXES,
+ 200,25,149,233,WS_EX_CLIENTEDGE
+ LTEXT "Execute task for specified contacts",IDC_STATIC,200,13,149,8
+ DEFPUSHBUTTON "OK",IDOK,245,261,50,14
+ PUSHBUTTON "Cancel",IDCANCEL,299,261,50,14
+END
+
+/////////////////////////////////////////////////////////////////////////////
+//
+// Icon
+//
+
+// Icon with lowest ID value placed first to ensure application icon
+// remains consistent on all systems.
+IDI_INM ICON "icons\\Incom.ico"
+IDI_OUTM ICON "icons\\Outg.ico"
+IDI_SHOW ICON "icons\\plus.ico"
+IDI_HIDE ICON "icons\\minus.ico"
+IDI_FINDNEXT ICON "icons\\FindNext.ico"
+IDI_FINDPREV ICON "icons\\FindPrev.ico"
+
+IDI_STATUS ICON "icons\\Status change.ico"
+
+IDR_CSS CUSTOMRES "history.css"
+IDR_JS CUSTOMRES "history.js"
+IDI_PLUSEX ICON "icons\\pnode.ico"
+IDI_MINUSEX ICON "icons\\mnode.ico"
+
+#endif // Neutral resources
+/////////////////////////////////////////////////////////////////////////////
+
diff --git a/plugins/BasicHistory/BasicHistory.sln b/plugins/BasicHistory/BasicHistory.sln
new file mode 100644
index 0000000000..b1b0ced1c3
--- /dev/null
+++ b/plugins/BasicHistory/BasicHistory.sln
@@ -0,0 +1,26 @@
+
+Microsoft Visual Studio Solution File, Format Version 11.00
+# Visual C++ Express 2010
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "BasicHistory", "BasicHistory.vcxproj", "{7DF5234A-A93A-47AD-8201-377ECF59AE5F}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Win32 = Debug|Win32
+ Debug|x64 = Debug|x64
+ Release|Win32 = Release|Win32
+ Release|x64 = Release|x64
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7DF5234A-A93A-47AD-8201-377ECF59AE5F}.Debug|Win32.ActiveCfg = Debug|Win32
+ {7DF5234A-A93A-47AD-8201-377ECF59AE5F}.Debug|Win32.Build.0 = Debug|Win32
+ {7DF5234A-A93A-47AD-8201-377ECF59AE5F}.Debug|x64.ActiveCfg = Debug|x64
+ {7DF5234A-A93A-47AD-8201-377ECF59AE5F}.Debug|x64.Build.0 = Debug|x64
+ {7DF5234A-A93A-47AD-8201-377ECF59AE5F}.Release|Win32.ActiveCfg = Release|Win32
+ {7DF5234A-A93A-47AD-8201-377ECF59AE5F}.Release|Win32.Build.0 = Release|Win32
+ {7DF5234A-A93A-47AD-8201-377ECF59AE5F}.Release|x64.ActiveCfg = Release|x64
+ {7DF5234A-A93A-47AD-8201-377ECF59AE5F}.Release|x64.Build.0 = Release|x64
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+EndGlobal
diff --git a/plugins/BasicHistory/BasicHistory.vcxproj b/plugins/BasicHistory/BasicHistory.vcxproj
new file mode 100644
index 0000000000..0adffb8582
--- /dev/null
+++ b/plugins/BasicHistory/BasicHistory.vcxproj
@@ -0,0 +1,275 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup Label="ProjectConfigurations">
+ <ProjectConfiguration Include="Debug|Win32">
+ <Configuration>Debug</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Debug|x64">
+ <Configuration>Debug</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|Win32">
+ <Configuration>Release</Configuration>
+ <Platform>Win32</Platform>
+ </ProjectConfiguration>
+ <ProjectConfiguration Include="Release|x64">
+ <Configuration>Release</Configuration>
+ <Platform>x64</Platform>
+ </ProjectConfiguration>
+ </ItemGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{7DF5234A-A93A-47AD-8201-377ECF59AE5F}</ProjectGuid>
+ <Keyword>Win32Proj</Keyword>
+ <RootNamespace>BasicHistory</RootNamespace>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v100</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>true</UseDebugLibraries>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v100</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v100</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
+ <ConfigurationType>DynamicLibrary</ConfigurationType>
+ <UseDebugLibraries>false</UseDebugLibraries>
+ <WholeProgramOptimization>true</WholeProgramOptimization>
+ <CharacterSet>Unicode</CharacterSet>
+ <PlatformToolset>v100</PlatformToolset>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <ImportGroup Label="ExtensionSettings">
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="PropertySheets">
+ <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
+ </ImportGroup>
+ <PropertyGroup Label="UserMacros" />
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(SolutionDir)$(Configuration)\Plugins\</OutDir>
+ <IntDir>$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <LinkIncremental>true</LinkIncremental>
+ <OutDir>$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
+ <IntDir>$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(SolutionDir)$(Configuration)\Plugins\</OutDir>
+ <IntDir>$(SolutionDir)$(Configuration)\Obj\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <LinkIncremental>false</LinkIncremental>
+ <OutDir>$(SolutionDir)$(Configuration)64\Plugins\</OutDir>
+ <IntDir>$(SolutionDir)$(Configuration)64\Obj\$(ProjectName)\</IntDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;BASICHISTORY_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include;..\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>Comctl32.lib;lib\zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>..\..\include\msapi;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ <ClCompile>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <WarningLevel>Level3</WarningLevel>
+ <Optimization>Disabled</Optimization>
+ <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;BASICHISTORY_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include;..\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <AdditionalDependencies>Comctl32.lib;lib64\zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>..\..\include\msapi;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;BASICHISTORY_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include;..\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>Comctl32.lib;lib\zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>..\..\include\msapi;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <PostBuildEvent>
+ <Command>if not exist "$(TargetDir)Docs\" mkdir "$(TargetDir)Docs\"
+copy "$(ProjectDir)Docs\*.*" "$(TargetDir)Docs\"</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ <ClCompile>
+ <WarningLevel>Level3</WarningLevel>
+ <PrecompiledHeader>Use</PrecompiledHeader>
+ <Optimization>MaxSpeed</Optimization>
+ <FunctionLevelLinking>true</FunctionLevelLinking>
+ <IntrinsicFunctions>true</IntrinsicFunctions>
+ <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;BASICHISTORY_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <AdditionalIncludeDirectories>..\..\include;..\ExternalAPI;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ClCompile>
+ <Link>
+ <SubSystem>Windows</SubSystem>
+ <GenerateDebugInformation>true</GenerateDebugInformation>
+ <EnableCOMDATFolding>true</EnableCOMDATFolding>
+ <OptimizeReferences>true</OptimizeReferences>
+ <AdditionalDependencies>Comctl32.lib;lib64\zlib.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
+ </Link>
+ <ResourceCompile>
+ <AdditionalIncludeDirectories>..\..\include\msapi;..\..\include;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
+ </ResourceCompile>
+ <PostBuildEvent>
+ <Command>if not exist "$(TargetDir)Docs\" mkdir "$(TargetDir)Docs\"
+copy "$(ProjectDir)Docs\*.*" "$(TargetDir)Docs\"</Command>
+ </PostBuildEvent>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <None Include="Docs\BasicHistory_langpack_polish.txt" />
+ <None Include="Docs\BasicHistory_licence.txt" />
+ <None Include="Docs\BasicHistory_readme.txt" />
+ <None Include="Docs\BasicHistory_translate.txt" />
+ <None Include="history.css" />
+ <None Include="history.js" />
+ <None Include="ReadMe.txt" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="BinaryExport.h" />
+ <ClInclude Include="codecvt_CodePage.h" />
+ <ClInclude Include="DatExport.h" />
+ <ClInclude Include="EventList.h" />
+ <ClInclude Include="ExportManager.h" />
+ <ClInclude Include="HistoryWindow.h" />
+ <ClInclude Include="HotkeyHelper.h" />
+ <ClInclude Include="IExport.h" />
+ <ClInclude Include="IImport.h" />
+ <ClInclude Include="ImageDataObject.h" />
+ <ClInclude Include="Options.h" />
+ <ClInclude Include="PlainHtmlExport.h" />
+ <ClInclude Include="resource.h" />
+ <ClInclude Include="RichHtmlExport.h" />
+ <ClInclude Include="SearchContext.h" />
+ <ClInclude Include="Searcher.h" />
+ <ClInclude Include="stdafx.h" />
+ <ClInclude Include="targetver.h" />
+ <ClInclude Include="TxtExport.h" />
+ <ClInclude Include="version.h" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="BasicHistory.cpp" />
+ <ClCompile Include="BinaryExport.cpp" />
+ <ClCompile Include="DatExport.cpp" />
+ <ClCompile Include="dllmain.cpp">
+ <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
+ <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</CompileAsManaged>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
+ </PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
+ </PrecompiledHeader>
+ <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
+ <CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</CompileAsManaged>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
+ </PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
+ </PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="EventList.cpp" />
+ <ClCompile Include="ExportManager.cpp" />
+ <ClCompile Include="HistoryWindow.cpp" />
+ <ClCompile Include="HotkeyHelper.cpp" />
+ <ClCompile Include="ImageDataObject.cpp" />
+ <ClCompile Include="Options.cpp" />
+ <ClCompile Include="PlainHtmlExport.cpp" />
+ <ClCompile Include="RichHtmlExport.cpp" />
+ <ClCompile Include="Scheduler.cpp" />
+ <ClCompile Include="Searcher.cpp" />
+ <ClCompile Include="stdafx.cpp">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="TxtExport.cpp" />
+ <ClCompile Include="zip\ioapi.c">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="zip\iowin32.c">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="zip\unzip.c">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
+ </ClCompile>
+ <ClCompile Include="zip\zip.c">
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">NotUsing</PrecompiledHeader>
+ <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">NotUsing</PrecompiledHeader>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="BasicHistory.rc" />
+ <ResourceCompile Include="version.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+ <ImportGroup Label="ExtensionTargets">
+ </ImportGroup>
+</Project> \ No newline at end of file
diff --git a/plugins/BasicHistory/BasicHistory.vcxproj.filters b/plugins/BasicHistory/BasicHistory.vcxproj.filters
new file mode 100644
index 0000000000..b9b18ec09f
--- /dev/null
+++ b/plugins/BasicHistory/BasicHistory.vcxproj.filters
@@ -0,0 +1,176 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <ItemGroup>
+ <Filter Include="Source Files">
+ <UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
+ <Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
+ </Filter>
+ <Filter Include="Header Files">
+ <UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
+ <Extensions>h;hpp;hxx;hm;inl;inc;xsd</Extensions>
+ </Filter>
+ <Filter Include="Resource Files">
+ <UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
+ <Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
+ </Filter>
+ <Filter Include="Resource Files\Docs">
+ <UniqueIdentifier>{21b9175b-8a7e-4272-8524-2aa48728760e}</UniqueIdentifier>
+ </Filter>
+ <Filter Include="Source Files\zip">
+ <UniqueIdentifier>{c8854079-e3d6-4f7c-82fc-bd494a11567f}</UniqueIdentifier>
+ </Filter>
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="ReadMe.txt" />
+ <None Include="Docs\BasicHistory_licence.txt">
+ <Filter>Resource Files\Docs</Filter>
+ </None>
+ <None Include="Docs\BasicHistory_readme.txt">
+ <Filter>Resource Files\Docs</Filter>
+ </None>
+ <None Include="Docs\BasicHistory_langpack_polish.txt">
+ <Filter>Resource Files\Docs</Filter>
+ </None>
+ <None Include="Docs\BasicHistory_translate.txt">
+ <Filter>Resource Files\Docs</Filter>
+ </None>
+ <None Include="history.css">
+ <Filter>Resource Files</Filter>
+ </None>
+ <None Include="history.js">
+ <Filter>Resource Files</Filter>
+ </None>
+ </ItemGroup>
+ <ItemGroup>
+ <ClInclude Include="stdafx.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="targetver.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="resource.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="version.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="HistoryWindow.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Options.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="HotkeyHelper.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="Searcher.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="SearchContext.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ImageDataObject.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="IExport.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="TxtExport.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="EventList.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="PlainHtmlExport.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="RichHtmlExport.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="codecvt_CodePage.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="BinaryExport.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="IImport.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="ExportManager.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ <ClInclude Include="DatExport.h">
+ <Filter>Header Files</Filter>
+ </ClInclude>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="stdafx.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="BasicHistory.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="dllmain.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="HistoryWindow.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Options.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="HotkeyHelper.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Searcher.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="ImageDataObject.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="TxtExport.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="EventList.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="PlainHtmlExport.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="RichHtmlExport.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="Scheduler.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="zip\zip.c">
+ <Filter>Source Files\zip</Filter>
+ </ClCompile>
+ <ClCompile Include="zip\iowin32.c">
+ <Filter>Source Files\zip</Filter>
+ </ClCompile>
+ <ClCompile Include="zip\ioapi.c">
+ <Filter>Source Files\zip</Filter>
+ </ClCompile>
+ <ClCompile Include="BinaryExport.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="zip\unzip.c">
+ <Filter>Source Files\zip</Filter>
+ </ClCompile>
+ <ClCompile Include="ExportManager.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ <ClCompile Include="DatExport.cpp">
+ <Filter>Source Files</Filter>
+ </ClCompile>
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="BasicHistory.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ <ResourceCompile Include="version.rc">
+ <Filter>Resource Files</Filter>
+ </ResourceCompile>
+ </ItemGroup>
+</Project> \ No newline at end of file
diff --git a/plugins/BasicHistory/BinaryExport.cpp b/plugins/BasicHistory/BinaryExport.cpp
new file mode 100644
index 0000000000..f57343cff0
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<HANDLE>& 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<IImport::ExternalMessage>& 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/BinaryExport.h b/plugins/BasicHistory/BinaryExport.h
new file mode 100644
index 0000000000..386625226f
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<HANDLE>& contacts);
+ virtual bool GetEventList(std::vector<IImport::ExternalMessage>& 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/DatExport.cpp b/plugins/BasicHistory/DatExport.cpp
new file mode 100644
index 0000000000..bd74546393
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<HANDLE>& 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<IImport::ExternalMessage>& 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<DWORD, IImport::ExternalMessage> 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<DWORD, IImport::ExternalMessage>(messageHeader.timestamp, exMsg));
+ dataSize -= messageHeader.cbSize + messageHeader.cbBlob;
+ }
+
+ memBuf.resize(0);
+#ifdef _WIN64
+ memBuf.shrink_to_fit();
+#endif
+
+ for(std::multimap<DWORD, IImport::ExternalMessage>::iterator it = sortedEvents.begin(); it != sortedEvents.end(); ++it)
+ {
+ eventList.push_back(it->second);
+ }
+
+ return true;
+}
diff --git a/plugins/BasicHistory/DatExport.h b/plugins/BasicHistory/DatExport.h
new file mode 100644
index 0000000000..980a12d148
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<HANDLE>& contacts);
+ virtual bool GetEventList(std::vector<IImport::ExternalMessage>& 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/Docs/BasicHistory_langpack_polish.txt b/plugins/BasicHistory/Docs/BasicHistory_langpack_polish.txt
new file mode 100644
index 0000000000..e94099a121
--- /dev/null
+++ b/plugins/BasicHistory/Docs/BasicHistory_langpack_polish.txt
@@ -0,0 +1,275 @@
+;Basic History
+;==========
+
+;To jest tylko czêœciowe t³umaczenie
+;Nale¿y go dodaæ do koñca pliku langpack_polish.txt
+
+;Main
+;------
+
+;Error messages
+;----------------
+[Invalid Message]
+Nieprawid³owa Wiadomoœæ
+[Number of history items to delete: %d.\nAre you sure you want to do this?]
+Iloœæ wpisów historii do usuniêcia: %d\nCzy na pewno chcesz to zrobiæ?
+[You have reached the end of the group.]
+Doszed³eœ na koniec grupy.
+[Invalid event number]
+Nieprawid³owy numer zdarzenia
+[Enter filter name]
+WprowadŸ nazwê filtra
+[Filter name exists]
+Nazwa filtra istnieje
+[Event already exists]
+Zdarzenie ju¿ istnieje
+[You've entered invalid codepage. Select codepage from combo box or enter correct number.]
+Wprowadzi³eœ nieprawid³ow¹ stronê kodow¹. Wybierz j¹ z combo boxa lub wprowadŸ poprawn¹ liczbê.
+[Invalid codepage]
+Nieprawid³owa strona kodowa
+[File do not exist. Enter correct file path.]
+Plik nie istnieje. WprowadŸ poprawn¹ œcie¿kê do pliku.
+[Invalid file]
+Nieprawid³owy plik
+[Invalid '%s' value.]
+Nieprawid³owa wartoœæ '%s'.
+[Invalid '%s' value.\n%s]
+Nieprawid³owa wartoœæ '%s'.\n%s
+[At least one contact should be selected.]
+Przynajmniej jeden kontakt powinien byæ zaznaczony.
+[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.]
+Aby utworzyæ sesiê: otwórz WinSCP, naciœniej Nowa Sesia, wprowadŸ dane i zapisz z okreœlon¹ nazw¹. Pamiêtaj, je¿eli serwer FTP u¿ywa has³a, powinienieœ zapisaæ go w WinSCP.
+[FTP path must contains '/' instead '\\' and starts from '/'.]
+Œcie¿ka FTP musi zawieraæ '/' zamiast '\\' i zaczynaæ siê z '/'.
+[File do not contain selected contact]
+Plik nie zawiera zaznaczonego kontaktu
+[File is corrupted]
+Plik jest nieprawid³owy
+[Do you want save imported messages to local profile?]
+Czy chcesz zapisaæ importowane wiadomoœci do lokalnego profilu?
+[Do you want delete all imported messages for this contact?\nNote that next scheduler task import this messages again.]
+Czy chcesz usun¹æ wszystkie zimportowane wiadomoœci dla tego kontaktu?\nZauwa¿ ¿e nastepne zadanie harmonogramu zimportuje t¹ wiadomoœæ ponownie.
+[FTP path cannot contain <date> in import task.]
+Œcie¿ka FTP nie mo¿e zawieraæ <date> w zadaniu importu.
+[Some value is invalid]
+Jakaœ wartoœæ jest nieprawid³owa
+[Cannot get FTP file(s).]
+Niemo¿na pobraæ plik(ów) FTP.
+[Cannot unzip file(s).]
+Niemo¿na rozpakowaæ plik(ów).
+[Incorrect file format: %s.]
+Nieprawid³owy format pliku: %s.
+[Unknown contact in file: %s.]
+Nieznany kontakt w pliku: %s.
+[Cannot export history for contact: %s.]
+Niemo¿na eksportowaæ historii dla kuntaktu: %s.
+[Cannot compress file(s).]
+Nie mo¿na spakowaæ plik(ów).
+[Task '%s' execution failed:]
+Zadanie '%s' niepowiod³o siê:
+[Task '%s' finished successfully]
+Zadanie '%s' zakoñczy³o siê prawid³owo
+[Task '%s' execution failed]
+Zadanie '%s' niepowiod³o siê
+[Task finished]
+Zadanie zakoñczone
+[Cannot send FTP file(s).]
+Niemo¿na wys³aæ plik(ów) FTP.
+
+;Options and Menus
+;-------------------
+[Open global history]
+Otwórz globaln¹ historiê
+[Find Next]
+ZnajdŸ Nastêpny
+[Find Previous]
+ZnajdŸ Poprzedni
+[Switch Match Case]
+Prze³¹cz Porównywanie Wielkoœci Znaków
+[Switch Match Whole Word]
+Prze³¹cz Porównywanie Ca³ych S³ów
+[Show/Hide Contacts]
+Poka¿/Ukryj Kontakty
+[Switch Only Incomming Messages]
+Prze³¹cz Tylko Przychodz¹ce Wiadomoœci
+[Switch Only Outgoing Messages]
+Prze³¹cz Tylko Wychodz¹ce Wiadomoœci
+[Hide Contacts]
+Ukryj Kontakty
+[Show Contacts]
+Poka¿ Kontakty
+[Match Case]
+Porównywanie Wielkoœci Znaków
+[Match Whole Word]
+Porównywanie Ca³ych S³ów
+[Only Incomming Messages]
+Tylko Przychodz¹ce Wiadomoœci
+[Only Outgoing Messages]
+Tylko Wychodz¹ce Wiadomoœci
+[Save window position as default]
+Zapisz pazycjê okna jako domyœln¹
+[Save window position for all contacts]
+Zapisz pozycjê okna dla wszystkich kontaktów
+[Delete All User History]
+Usuñ Ca³¹ Historiê U¿ytkownika
+[Always show contact list]
+Zawsze pokazuj listê kontaktów
+[New messages on top]
+Nowe wiadomoœci na szczycie
+[Delta time to group messages:]
+Ró¿nica czasu do grupowania wiadomoœci:
+[Limit messages to:]
+Limituj wiadomoœci do:
+[Search forward in list group]
+Wyszukuj do przodu na liœcie grup
+[Search forward in message window]
+Wyszukuj do przodu w oknie wiadomoœci
+[Only Selected Group]
+Tylko Zaznaczona Grupa
+[Group list]
+Lista grup
+[Switch Only Selected Group]
+Prze³¹cz Tylko Zaznaczona Grupa
+[Default history events]
+Domyœlne zdarzenia historii
+[You were added]
+Zosta³eœ dodany
+[Contacts recieved]
+Pobrane kontakty
+[Custom filters]
+Filtry u¿ytkownika
+[Add filter]
+Dodaj filtr
+[Delete filter]
+Usuñ filtr
+[Add event]
+Dodaj zdarzenie
+[Delete event]
+Usuñ zdarzenie
+[Show groups in contact list]
+Poka¿ grupy w liœcie kontaktów
+[Window background]
+T³o okna
+[Plus in export]
+Plus w eksporcie
+[Minus in export]
+Minus w eksporcie
+[Rich Html]
+Rozszerzony Html
+[Plain Html]
+Czysty Html
+[_files]
+_pliki
+[Open all]
+Otwórz wszystkie
+[Close all]
+Zamknij wszystkie
+[Export To Rich Html]
+Eksport Do Rozszerzonego Html
+[Export To Plain Html]
+Eksport Do Czystego Html
+[Export To Txt]
+Eksport Do Txt
+[File encoding*]
+Kodowanie pliku*
+[External CSS file]
+Zewnêtrzny plik CSS
+[* Choose encoding from combo box or enter code page number and name separated by semicolon, name is used in Content-Type header.]
+* Wybierz kodowanie z combo boxa lub wpisz stronê kodow¹ i nazwê rozdzielone œrednikiem, nazwa jest u¿ywana w nag³ówku Content-Type.
+[WinSCP path]
+Œcie¿ka do programu WinSCP
+[WinSCP log path]
+Œcie¿ka do loga WinSCP
+[Add task]
+Dodaj zadanie
+[Edit task]
+Edytuj zadanie
+[Delete task]
+Usuñ zadanie
+[Action type]
+Typ akcji
+[Events older than*]
+Zdarzenia starsze ni¿*
+[Events older than]
+Zdarzenia starsze ni¿
+[Triger type]
+Typ wyzwalacza
+[Delta time]
+Ró¿nica czasu
+[Day of week]
+Dzieñ tygodnia
+[Export to]
+Eksportuj do
+[Compress output files]
+Kompresuj pliki wynikowe
+[Upload to FTP (WinSCP requred)]
+Wyœlij do FTP (wymagany WinSCP)
+[Upload to FTP]
+Wyœlij do FTP
+[Session name]
+Nazwa sesji
+[Path to file**]
+Œcie¿ka do pliku**
+[Path to file]
+Œcie¿ka do pliku
+[* Use negative values to filter younger events]
+* U¿yj ujemnych wartoœci do filtrowania m³odszych zdarzeñ
+[** Use <date> to insert date, <ext> to insert extension, <contact> to insert contact name]
+** U¿yj <date> do wstawienia daty, <ext> do wstawienia rozszerzenia, <contact> do wstawienia nazwy kontaktu
+[Execute task for specified contacts]
+Wykonaj zadanie dla nastêpuj¹cych kontaktów
+[Export and Delete]
+Eksport i usuwanie
+[Minute]
+Minuta
+[Hour]
+Godzina
+[At Start]
+Podczas startu
+[At Finish]
+Przy wy³¹czaniu
+[Delta time (minutes)]
+Ró¿nica czasu (minuty)
+[Delta time (hours)]
+Ró¿nica czasu (godziny)
+[Scheduler]
+Harmonogram
+[Binary]
+Binarny
+[Export To Binary]
+Eksportuj Do Binarnego
+[Import From Binary]
+Importuj Z Binarnego
+[Execute history task]
+Wykonaj zadanie historii
+[Export To Dat (mContacts)]
+Exportuj Do Dat (mContacts)
+[Import From Dat (mContacts)]
+Importuj Z Dat (mContacts)]
+[Import and Marge]
+Importuj i Z³¹cz
+[Input files are compressed]
+Pliki wejœciowe s¹ skompresowane
+[Download from FTP (WinSCP requred)]
+Sci¹gnij z FTP (wymagany WinSCP)
+[Import from]
+Importuj z
+[** Use <ext> to insert extension, <contact> to insert contact name]
+** U¿yj <ext> do wstawienia rozszerzenia, <contact> do wstawienia nazwy kontaktu
+[Save errors to system history]
+Zapisz b³êdy do historii systemu
+[%s Files (*.%s)]
+%s Pliki (*.%s)
+[Browse WinSCP file]
+Wybierz plik WinSCP
+[Save WinSCP log file]
+Zapisz log WinSCP
+[Browse CSS file]
+Wybierz plik CSS
+[History task]
+Zadanie historii
+[Switch All Contacts]
+Prze³¹cz Wszystkie Kontakty
+[Filter:]
+#muuid {E25367A2-51AE-4044-BE28-131BC18B71A4}
+Filtr:
diff --git a/plugins/BasicHistory/Docs/BasicHistory_licence.txt b/plugins/BasicHistory/Docs/BasicHistory_licence.txt
new file mode 100644
index 0000000000..7f1161073d
--- /dev/null
+++ b/plugins/BasicHistory/Docs/BasicHistory_licence.txt
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/plugins/BasicHistory/Docs/BasicHistory_readme.txt b/plugins/BasicHistory/Docs/BasicHistory_readme.txt
new file mode 100644
index 0000000000..5f38c1cede
--- /dev/null
+++ b/plugins/BasicHistory/Docs/BasicHistory_readme.txt
@@ -0,0 +1,106 @@
+********
+Basic History
+********
+
+Description
+===========
+History viewer for Miranda IM.
+
+Main features
+=============
+- display history in RichEdit
+- grouping events
+- contact list to change distlayed history
+- searching
+- filtering
+- export and import
+- scheduler to export, delete or import messages
+
+!!! Requirements !!!
+====================
+Microsoft Visual C++ 2010 Redistributable Package for x64 version
+Microsoft Visual C++ 2008 Redistributable Package for x86 version (included in Miranda`s installer)
+
+Changelog
+=========
+
+--- 1.0.1.5 ---
++ added browse buttons in Options
++ added searching in all contacts
++ added showing scheduler error messages
++ added System label in contact list
+
+--- 1.0.1.4 ---
++ added dat (mContacts) export and import
++ added scheduled import
++ added "Execute history task" menu
++ added password to protect exported messages
+* fixed importing messages with this same time
+
+--- 1.0.1.3 ---
++ added binary export
++ added import
+
+--- 1.0.1.2 ---
+* fixed exporting system history
++ added export configuration
++ added export scheduler
+
+--- 1.0.1.1 ---
++ export
+* fixed "View &History" menu
+
+--- 1.0.1.0 ---
++ changed contact list to look better
++ configurable color of main window and group list
+* saving splitter position
+* improvements in RichEdit colors
+* ability to delete system history
+* x86 version now using Microsoft Visual C++ 2008 Redistributable Package
++ updater beta version link to future use
+
+--- 1.0.0.5 ---
+* fixed bug with setting "All events" filter as default
+* fixed "buffer overrun" error in some cases
++ metacontacts improvements
+
+--- 1.0.0.4 ---
++ added filters
++ added System history
++ added more event icons
++ added "Reply Quoted" in context menu
+* fixed "New messages on top" option in group list
+* history window can be maximized
++ added toolbar support
+
+--- 1.0.0.3 ---
+* fixed clicking URLs
++ added deleting history
++ added option pages
++ added context menu
++ added menu to open srmm message window
++ special context menu to links
+
+--- 1.0.0.2 ---
++ added toolbar
++ more search options
++ save window position
++ hotkeys
++ customising fonts and colors
+
+--- 1.0.0.1 ---
+* fixed bug in 32 bit Miranda with timestamp
+* support for new langpacks
+* fixed unhooking events
++ contact can be changed in history window
+
+--- 1.0.0.0 ---
++ initial release
+
+Author
+======
+Krzysztof Kral
+
+email: krzysztof.kral@gmail.com
+www: http://programista.free.of.pl/miranda/
+svn: http://xp-dev.com/svn/BasicHistory/
diff --git a/plugins/BasicHistory/Docs/BasicHistory_translate.txt b/plugins/BasicHistory/Docs/BasicHistory_translate.txt
new file mode 100644
index 0000000000..d16dbd8a1a
--- /dev/null
+++ b/plugins/BasicHistory/Docs/BasicHistory_translate.txt
@@ -0,0 +1,233 @@
+;Basic History
+;==========
+
+;Main
+;------
+[History]
+[Search]
+[History for %s]
+[Authorisation request by %s (%s%d): %s]
+[System]
+
+;Error messages
+;----------------
+["%s" not found]
+[You have reached the end of the history.]
+[Invalid Message]
+[This operation will PERMANENTLY REMOVE all history for this contact.\nAre you sure you want to do this?]
+[Number of history items to delete: %d.\nAre you sure you want to do this?]
+[You have reached the end of the group.]
+[Error]
+[Invalid event number]
+[Enter filter name]
+[Filter name exists]
+[Event already exists]
+[You've entered invalid codepage. Select codepage from combo box or enter correct number.]
+[Invalid codepage]
+[File do not exist. Enter correct file path.]
+[Invalid file]
+[Invalid '%s' value.]
+[Invalid '%s' value.\n%s]
+[Contacts]
+[At least one contact should be selected.]
+[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.]
+[FTP path must contains '/' instead '\\' and starts from '/'.]
+[File do not contain selected contact]
+[File is corrupted]
+[Do you want save imported messages to current profile?]
+[Are You sure?]
+[Do you want delete all imported messages for this contact?\nNote that next scheduler task import this messages again.]
+[FTP path cannot contain <date> in import task.]
+[Some value is invalid]
+[Unknown error]
+[Cannot get FTP file(s).]
+[Cannot unzip file(s).]
+[Incorrect file format: %s.]
+[Unknown contact in file: %s.]
+[Cannot export history for contact: %s.]
+[Cannot compress file(s).]
+[Task '%s' execution failed:]
+[Task '%s' finished successfully]
+[Task '%s' execution failed]
+[Task finished]
+[Cannot send FTP file(s).]
+
+;Options and Menus
+;-------------------
+[>> Outgoing timestamp]
+[<< Incoming timestamp]
+[>> Outgoing name]
+[<< Incoming name]
+[>> Outgoing messages]
+[<< Incoming messages]
+[Outgoing background]
+[Incoming background]
+[Open global history]
+[Find]
+[Find Next]
+[Find Previous]
+[Switch Match Case]
+[Switch Match Whole Word]
+[Show/Hide Contacts]
+[Switch Only Incomming Messages]
+[Switch Only Outgoing Messages]
+[View &History]
+[Incoming message]
+[Outgoing message]
+[Show contact list]
+[Hide contact list]
+[Options]
+[Hide Contacts]
+[Show Contacts]
+[Match Case]
+[Match Whole Word]
+[Only Incomming Messages]
+[Only Outgoing Messages]
+[Fonts & Colors]
+[Icons]
+[Hotkeys]
+[Save window position as default]
+[Save window position for all contacts]
+[Delete]
+[Delete Group]
+[Delete All User History]
+[Settings]
+[Always show contact list]
+[New messages on top]
+[Show event icons]
+[Show timestamps]
+[Show names]
+[Show messages]
+[Truncate message length to:]
+[Delta time to group messages:]
+[hours]
+[Limit messages to:]
+[Show date in timestamps]
+[Show seconds in timestamps]
+[Enable Smileys]
+[Search forward in list group]
+[Search forward in message window]
+[Only Selected Group]
+[Open in &new window]
+[&Open in existing window]
+[&Copy link]
+[Copy]
+[Send Message]
+[Group list]
+[Messages]
+[Searching]
+[Switch Only Selected Group]
+[Open History]
+[Reply &Quoted]
+[Statuschange]
+[Default history events]
+[All events]
+[Message]
+[File transfer]
+[Link]
+[Status change]
+[Authorization request]
+[You were added]
+[Contacts recieved]
+[SMTP Simple Email]
+[SMS message]
+[Incoming events]
+[Outgoing events]
+[Default Event Filter]
+[Custom filters]
+[Add filter]
+[Delete filter]
+[Add event]
+[Delete event]
+[Show groups in contact list]
+[Window background]
+[Plus in export]
+[Minus in export]
+[Export]
+[Rich Html]
+[Plain Html]
+[Txt]
+[History Log]
+[_files]
+[Menu]
+[Open all]
+[Close all]
+[Filter:]
+[###]
+[Export To Rich Html]
+[Export To Plain Html]
+[Export To Txt]
+[File encoding*]
+[External CSS file]
+[* Choose encoding from combo box or enter code page number and name separated by semicolon, name is used in Content-Type header.]
+[Advanced]
+[WinSCP path]
+[WinSCP log path]
+[Add task]
+[Edit task]
+[Delete task]
+[Name]
+[Active]
+[Action type]
+[Filter]
+[Events older than*]
+[Events older than]
+[Triger type]
+[Time]
+[Delta time]
+[Day of week]
+[Day]
+[Export to]
+[Compress output files]
+[Upload to FTP (WinSCP requred)]
+[Upload to FTP]
+[Session name]
+[Path to file**]
+[Path to file]
+[* Use negative values to filter younger events]
+[** Use <date> to insert date, <ext> to insert extension, <contact> to insert contact name]
+[Execute task for specified contacts]
+[OK]
+[Cancel]
+[Export and Delete]
+[Minute]
+[Hour]
+[At Start]
+[At Finish]
+[Daily]
+[Weekly]
+[Monthly]
+[Delta time (minutes)]
+[Delta time (hours)]
+[Monday]
+[Tuesday]
+[Wednesday]
+[Thursday]
+[Friday]
+[Saturday]
+[Sunday]
+[Scheduler]
+[Binary]
+[Export To Binary]
+[Import]
+[Import From Binary]
+[Execute history task]
+[Password]
+[Dat (mContacts)]
+[Export To Dat (mContacts)]
+[Import From Dat (mContacts)]
+[Import and Marge]
+[Input files are compressed]
+[Download from FTP (WinSCP requred)]
+[Import from]
+[** Use <ext> to insert extension, <contact> to insert contact name]
+[Display errors using popups]
+[Save errors to system history]
+[All Contacts]
+[%s Files (*.%s)]
+[All Files (*.*)]
+[Browse WinSCP file]
+[Save WinSCP log file]
+[Browse CSS file]
+[History task]
+[Switch All Contacts]
diff --git a/plugins/BasicHistory/EventList.cpp b/plugins/BasicHistory/EventList.cpp
new file mode 100644
index 0000000000..45d6735883
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#include "StdAfx.h"
+#include "EventList.h"
+#include "Options.h"
+#include "ExportManager.h"
+#include <assert.h>
+
+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<int>::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<EventTempIndex>& 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<EventTempIndex>::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<IImport::ExternalMessage> messages;
+
+ EnterCriticalSection(&criticalSection);
+ std::map<HANDLE, EventList::ImportDiscData>::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<EventTempIndex> tempList;
+ GetTempList(tempList, false, false, hContact);
+ std::list<EventTempIndex> revTempList;
+ std::list<EventTempIndex>& 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<EventIndex>());
+ DWORD lastTime = MAXDWORD;
+ DWORD groupTime = Options::instance->groupTime * 60 * 60;
+ int maxMess = Options::instance->groupMessagesNumber;
+ int limitator = 0;
+ EventIndex ei;
+ for(std::list<EventTempIndex>::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<EventIndex>());
+ }
+ 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<IImport::ExternalMessage> messages;
+
+ EnterCriticalSection(&criticalSection);
+ std::map<HANDLE, EventList::ImportDiscData>::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<EventTempIndex> tempList;
+ GetTempList(tempList, false, true, hContact);
+
+ EventIndex ei;
+ EventData ed;
+ TCHAR str[MAXSELECTSTR + 8]; // for safety reason
+ for(std::list<EventTempIndex>::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<IImport::ExternalMessage>& 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<IImport::ExternalMessage>& messages)
+{
+ ImportMessages(messages);
+ std::list<EventTempIndex> 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<EventTempIndex>::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<IImport::ExternalMessage> 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<EventIndex> 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<HANDLE, EventList::ImportDiscData> 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<HANDLE, EventList::ImportDiscData>::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<HANDLE, EventList::ImportDiscData>::iterator it = contactFileMap.find(hContact);
+ if(it != contactFileMap.end())
+ {
+ count = true;
+ }
+
+ LeaveCriticalSection(&criticalSection);
+ return count;
+}
+
+void EventList::DeleteImporter(HANDLE hContact)
+{
+ EnterCriticalSection(&criticalSection);
+ std::map<HANDLE, EventList::ImportDiscData>::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/EventList.h b/plugins/BasicHistory/EventList.h
new file mode 100644
index 0000000000..36628ff278
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<int, bool> filterMap;
+ bool onlyInFilter;
+ bool onlyOutFilter;
+ int defFilter;
+ std::wstring filterName;
+ std::vector<IImport::ExternalMessage> 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<HANDLE, ImportDiscData> 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<EventTempIndex>& tempList, bool noFilter, bool noExt, HANDLE _hContact);
+ void ImportMessages(const std::vector<IImport::ExternalMessage>& 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<std::deque<EventIndex> > 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<IImport::ExternalMessage>& 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/ExportManager.cpp b/plugins/BasicHistory/ExportManager.cpp
new file mode 100644
index 0000000000..897561ef26
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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("<ext>"));
+ 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<wchar_t>(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<HANDLE>& 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<IImport::ExternalMessage>& 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<HANDLE> 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<EventIndex> revDeq;
+ std::deque<EventIndex>& deq = eventList.back();
+ if(!oldOnTop && Options::instance->messagesNewOnTop)
+ {
+ revDeq.insert(revDeq.begin(), deq.rbegin(), deq.rend());
+ deq = revDeq;
+ }
+ for(std::deque<EventIndex>::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/ExportManager.h b/plugins/BasicHistory/ExportManager.h
new file mode 100644
index 0000000000..d99ff077a6
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<HANDLE>& contacts);
+ bool Import(IImport::ImportType type, std::vector<IImport::ExternalMessage>& eventList, std::wstring* err = NULL);
+ static const TCHAR* GetExt(IImport::ImportType type);
+};
+
diff --git a/plugins/BasicHistory/HistoryWindow.cpp b/plugins/BasicHistory/HistoryWindow.cpp
new file mode 100644
index 0000000000..894be667b4
--- /dev/null
+++ b/plugins/BasicHistory/HistoryWindow.cpp
@@ -0,0 +1,2512 @@
+/*
+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 <http://www.gnu.org/licenses/>.
+*/
+
+#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
+
+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),
+ hSystem(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);
+ }
+}
+
+std::map<HANDLE, HistoryWindow*> HistoryWindow::windows;
+std::vector<HistoryWindow*> HistoryWindow::freeWindows;
+
+void HistoryWindow::Deinit()
+{
+ bool destroyed = true;
+ std::vector<HANDLE> keys;
+ for(std::map<HANDLE, HistoryWindow*>::iterator it = windows.begin(); it != windows.end(); ++it)
+ {
+ if(!it->second->isDestroyed)
+ {
+ keys.push_back(it->first);
+ }
+ }
+ for(std::vector<HANDLE>::iterator it = keys.begin(); it != keys.end(); ++it)
+ {
+ std::map<HANDLE, HistoryWindow*>::iterator it1 = windows.find(*it);
+ if(it1 != windows.end())
+ {
+ DestroyWindow(it1->second->hWnd);
+ it1 = windows.find(*it);
+ destroyed &= it1 == windows.end();
+ }
+ }
+
+ std::vector<HistoryWindow*> keys1;
+ for(std::vector<HistoryWindow*>::iterator it = freeWindows.begin(); it != freeWindows.end(); ++it)
+ {
+ if(!(*it)->isDestroyed)
+ {
+ keys1.push_back(*it);
+ }
+ }
+ for(std::vector<HistoryWindow*>::iterator it = keys1.begin(); it != keys1.end(); ++it)
+ {
+ DestroyWindow((*it)->hWnd);
+ }
+ for(std::vector<HistoryWindow*>::iterator it = freeWindows.begin(); it != freeWindows.end(); ++it)
+ {
+ if(!(*it)->isDestroyed)
+ {
+ destroyed = false;
+ break;
+ }
+ }
+
+ if(destroyed)
+ {
+ for(std::map<HANDLE, HistoryWindow*>::iterator it = windows.begin(); it != windows.end(); ++it)
+ {
+ delete it->second;
+ }
+
+ windows.clear();
+
+ for(std::vector<HistoryWindow*>::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<HANDLE, HistoryWindow*>::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<HANDLE, HistoryWindow*>::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<HANDLE, HistoryWindow*>::iterator it = windows.find(historyWindow->hContact);
+ if(it != windows.end() && it->second == historyWindow)
+ {
+ delete it->second;
+ windows.erase(it);
+ }
+ else
+ {
+ for(std::vector<HistoryWindow*>::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<HANDLE, HistoryWindow*>::iterator it = windows.find(hContact);
+ if(it != windows.end() && !it->second->isDestroyed)
+ {
+ SendMessage(it->second->hWnd,DM_HREBUILD,0,0);
+ }
+ }
+
+ for(std::vector<HistoryWindow*>::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<HANDLE, HistoryWindow*>::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<HANDLE, HistoryWindow*>::iterator it = windows.begin(); it != windows.end(); ++it)
+ {
+ if(!it->second->isDestroyed)
+ {
+ it->second->FontsChanged();
+ }
+ }
+
+ for(std::vector<HistoryWindow*>::iterator it = freeWindows.begin(); it != freeWindows.end(); ++it)
+ {
+ if(!(*it)->isDestroyed)
+ {
+ (*it)->FontsChanged();
+ }
+ }
+
+ return 0;
+}
+
+void HistoryWindow::FontsChanged()
+{
+ if(bkBrush != NULL)
+ {
+ DeleteObject(bkBrush);
+ }
+
+ bkBrush = CreateSolidBrush(Options::instance->GetColor(Options::WindowBackground));
+
+ 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<HANDLE, HistoryWindow*>::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<HistoryWindow*>::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<HANDLE, HistoryWindow*>::iterator it = windows.begin(); it != windows.end(); ++it)
+ {
+ if(!it->second->isDestroyed)
+ {
+ it->second->ReloadMainOptions();
+ }
+ }
+
+ for(std::vector<HistoryWindow*>::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<HANDLE, HistoryWindow*>::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<HistoryWindow*>::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<HANDLE, HistoryWindow*>::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<HistoryWindow*>::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<HANDLE> 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<HANDLE>::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<HANDLE, HistoryWindow*>::iterator it = windows.begin(); it != windows.end(); ++it)
+ {
+ if(!it->second->isDestroyed)
+ {
+ if(it->second->hWnd == hWnd)
+ {
+ return true;
+ }
+ }
+ }
+
+ for(std::vector<HistoryWindow*>::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;
+ char* pszUrl;
+
+ 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);
+ pszUrl = mir_t2a( tr.lpstrText );
+ CallService(MS_UTILS_OPENURL, penLink->nmhdr.code == IDM_OPENNEW ? 1 : 0, (LPARAM) pszUrl);
+ mir_free(pszUrl);
+ }
+ }
+}
+
+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(GetDlgItem(hwndDlg,IDC_SPLITTERV), 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(GetDlgItem(hwndDlg,IDC_SPLITTERV), 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);
+ 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);
+ }
+
+ //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 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()
+{
+ OldSplitterProc = (WNDPROC)SetWindowLongPtr(GetDlgItem(hWnd, IDC_SPLITTER), GWLP_WNDPROC, (LONG_PTR) SplitterSubclassProc);
+ SetWindowLongPtr(GetDlgItem(hWnd, IDC_SPLITTERV), 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(GetDlgItem(hWnd, IDC_SPLITTER), &rc);
+ pt.y = (rc.top + rc.bottom) / 2;
+ pt.x = 0;
+ ScreenToClient(hWnd, &pt);
+ splitterOrgY = pt.y;
+ splitterY = pt.y;
+ GetWindowRect(GetDlgItem(hWnd, IDC_SPLITTERV), &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, 0, 0 );
+ SendDlgItemMessage( hWnd, IDC_SHOWHIDE, BUTTONSETASFLATBTN, 0, 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(GetDlgItem(hWnd,IDC_SPLITTERV), SW_HIDE);
+ isContactList = false;
+ }
+ RegisterHotkeyControl(GetDlgItem(hWnd, IDC_SHOWHIDE));
+ RegisterHotkeyControl(GetDlgItem(hWnd, IDC_LIST_CONTACTS));
+
+ SendDlgItemMessage(hWnd, IDC_LIST_CONTACTS, CLM_SETUSEGROUPS, Options::instance->showContactGroups, 0);
+
+ 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));
+
+ 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 == GetDlgItem(hWnd, IDC_SPLITTER))
+ {
+ 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<EventIndex> revDeq;
+ std::deque<EventIndex>& 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<EventIndex>::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);
+
+ 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(GetDlgItem(hWnd, IDC_SPLITTERV), pos, false);
+ }
+
+ pos = DBGetContactSettingDword(contactToLoad, MODULE, "history_splitter", 0);
+ if(pos > 0)
+ {
+ SplitterMoved(GetDlgItem(hWnd, IDC_SPLITTER), 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<IImport::ExternalMessage> 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);
+ }
+}
diff --git a/plugins/BasicHistory/HistoryWindow.h b/plugins/BasicHistory/HistoryWindow.h
new file mode 100644
index 0000000000..a28f014c89
--- /dev/null
+++ b/plugins/BasicHistory/HistoryWindow.h
@@ -0,0 +1,93 @@
+/*
+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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<HANDLE, HistoryWindow*> windows;
+ static std::vector<HistoryWindow*> 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;
+ HANDLE hSystem;
+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/HotkeyHelper.cpp b/plugins/BasicHistory/HotkeyHelper.cpp
new file mode 100644
index 0000000000..eeb537456a
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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/HotkeyHelper.h b/plugins/BasicHistory/HotkeyHelper.h
new file mode 100644
index 0000000000..f31b1c6666
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+#define CLN_MYSELCHANGED (CLN_FIRST-50)
+
+void RegisterHotkeyControl(HWND control);
+void UnregisterHotkeyControl(HWND control);
diff --git a/plugins/BasicHistory/IExport.h b/plugins/BasicHistory/IExport.h
new file mode 100644
index 0000000000..d024a084e4
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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/IImport.h b/plugins/BasicHistory/IImport.h
new file mode 100644
index 0000000000..aef3b35179
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<HANDLE>& contacts) = 0;
+ virtual bool GetEventList(std::vector<ExternalMessage>& eventList) = 0;
+
+ virtual ~IImport()
+ {
+ }
+};
+
diff --git a/plugins/BasicHistory/ImageDataObject.cpp b/plugins/BasicHistory/ImageDataObject.cpp
new file mode 100644
index 0000000000..15cb67f6ce
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+//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/ImageDataObject.h b/plugins/BasicHistory/ImageDataObject.h
new file mode 100644
index 0000000000..309c220e36
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+//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/Options.cpp b/plugins/BasicHistory/Options.cpp
new file mode 100644
index 0000000000..86abbf88c1
--- /dev/null
+++ b/plugins/BasicHistory/Options.cpp
@@ -0,0 +1,2167 @@
+/*
+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 <http://www.gnu.org/licenses/>.
+*/
+
+#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;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp);
+
+ odp.ptszTab = LPGENT("Messages");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MESSAGES);
+ odp.pfnDlgProc = Options::DlgProcOptsMessages;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp);
+
+ odp.ptszTab = LPGENT("Searching");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SEARCHING);
+ odp.pfnDlgProc = Options::DlgProcOptsSearching;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp);
+
+ odp.ptszTab = LPGENT("Export");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_EXPORT);
+ odp.pfnDlgProc = Options::DlgProcOptsExport;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp);
+
+ odp.ptszTab = LPGENT("Scheduler");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_SCHEDULER);
+ odp.pfnDlgProc = Options::DlgProcOptsScheduler;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&odp);
+
+ odp.ptszTab = LPGENT("Advanced");
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_MAIN);
+ odp.pfnDlgProc = Options::DlgProcOptsMain;
+ CallService(MS_OPT_ADDPAGE, wParam, (LPARAM)&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},
+};
+
+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),
+};
+
+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()
+{
+ 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;
+ CallService(MS_FONT_REGISTERT, (WPARAM)&fid, 0);
+ }
+
+ 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;
+ CallService(MS_COLOUR_REGISTERT, (WPARAM)&cid, 0);
+ }
+
+ 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;
+ CallService(MS_HOTKEY_REGISTER, 0, (LPARAM)&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<int>::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<TaskOptions>* tasks)
+{
+ EnterCriticalSection(&criticalSection);
+ int oldTaskNr = (int)taskOptions.size();
+ taskOptions.clear();
+ int i = 0;
+ char buf[256];
+ for(std::list<TaskOptions>::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<int>::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<FilterOptions>::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<FilterOptions>::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<TaskOptions>* 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<TaskOptions>* tasks = new std::list<TaskOptions>(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<TaskOptions>::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<TaskOptions>* tasks = (std::list<TaskOptions>*)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<TaskOptions>::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<TaskOptions>::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<TaskOptions>* tasks = (std::list<TaskOptions>*)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<TaskOptions>* tasks = (std::list<TaskOptions>*)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<TaskOptions>* 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<FilterOptions>::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 <ext> to insert extension, <contact> 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 <date> to insert date, <ext> to insert extension, <contact> 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/Options.h b/plugins/BasicHistory/Options.h
new file mode 100644
index 0000000000..6eab65d08a
--- /dev/null
+++ b/plugins/BasicHistory/Options.h
@@ -0,0 +1,196 @@
+/*
+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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<int> 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<HANDLE> 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("_<contact>_<date>.<ext>");
+ lastExport = time(NULL);
+ }
+};
+
+class Options
+{
+private:
+ std::vector<FilterOptions> 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<TaskOptions>* tasks);
+ void SaveTaskTime(TaskOptions& to);
+ void Load();
+ 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<FilterOptions> customFilters;
+ int defFilter;
+ unsigned int codepageTxt, codepageHtml1, codepageHtml2;
+ std::wstring encodingTxt, encodingHtml1, encodingHtml2;
+ bool exportHtml1ShowDate, exportHtml2ShowDate, exportHtml2UseSmileys;
+ std::wstring extCssHtml2;
+ std::vector<TaskOptions> taskOptions;
+ std::wstring ftpLogPath;
+ std::wstring ftpExePathDef;
+ std::wstring ftpExePath;
+ CRITICAL_SECTION criticalSection;
+
+ enum Fonts
+ {
+ OutTimestamp = 0,
+ InTimestamp,
+ OutName,
+ InName,
+ OutMessages,
+ InMessages,
+ GroupList,
+ };
+
+ enum Colors
+ {
+ OutBackground = 0,
+ InBackground,
+ GroupListBackground,
+ WindowBackground,
+ };
+
+ COLORREF GetFont(Fonts fontId, PLOGFONT font);
+ COLORREF GetColor(Colors colorId);
+};
+
diff --git a/plugins/BasicHistory/PlainHtmlExport.cpp b/plugins/BasicHistory/PlainHtmlExport.cpp
new file mode 100644
index 0000000000..050b4e457e
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<std::pair<size_t, size_t> >* 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("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
+ EXP_FILE << _T("<html><head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=") << encoding << _T("\">\n");
+ EXP_FILE << _T("<title>") << TranslateT("History Log") << _T(" [") << MakeTextHtmled(myName) << _T("] - [") << MakeTextHtmled(name1) << _T("]</title>\n");
+ EXP_FILE << _T("<style type=\"text/css\"><!--\n");
+ EXP_FILE << _T("h3 { color: #666666; text-align: center; font-family: Verdana, Helvetica, Arial, sans-serif; font-size: 16pt; }\n");
+ EXP_FILE << _T("h4 { text-align: center; font-family: Verdana, Helvetica, Arial, sans-serif; font-size: 14pt; }\n");
+ EXP_FILE << _T("h6 { font-weight: normal; color: #000000; text-align: center; font-family: Verdana, Helvetica, Arial, sans-serif; font-size: 8pt; }\n");
+ EXP_FILE << _T(".mes { border-top-width: 1px; border-right-width: 0px; border-bottom-width: 0px;border-left-width: 0px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #666666; border-bottom-color: #666666; padding: 4px; color: #000000; font: normal normal normal 8pt normal Tahoma, Tahoma, Verdana, Arial, sans-serif; text-decoration: none; }\n");
+ EXP_FILE << _T(".text { clear: both; }\n");
+ EXP_FILE << _T(".nick { float: left; font: normal normal bold 8pt normal Tahoma, Tahoma, Verdana, Arial, sans-serif; text-decoration: none; }\n");
+ EXP_FILE << _T(".date { float: right; clear: right; font: normal normal bold 8pt normal Tahoma, Tahoma, Verdana, Arial, sans-serif; text-decoration: none; }\n");
+ EXP_FILE << _T(".url { color: #0000FF; }\n");
+ EXP_FILE << _T(".nick#inc { color: #C83F6B; }\n");
+ EXP_FILE << _T(".nick#out { color: #0860BD; }\n");
+ EXP_FILE << _T(".date#inc { color: #000000; }\n");
+ EXP_FILE << _T(".date#out { color: #000000; }\n");
+ EXP_FILE << _T(".mes#event0 { background-color: #DBDBDB; }\n");
+ EXP_FILE << _T(".mes#event1 { background-color: #EEEEEE; }\n");
+ EXP_FILE << _T(".mes#event2 { background-color: #CCD9F4; }\n");
+ EXP_FILE << _T(".mes#session { background-color: #FFFDD7; }\n");
+ EXP_FILE << _T("--></style>\n</head><body>\n<h4>") << TranslateT("History Log") << _T("</h4>\n<h3>");
+ 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(")</h3>\n");
+ }
+ else
+ {
+ EXP_FILE << _T("</h3>\n");
+ }
+
+ EXP_FILE << _T("<h6>") << TranslateT("Filter:") << _T(" ") << MakeTextHtmled(filterName) << _T("</h6>\n");
+}
+
+void PlainHtmlExport::WriteFooter()
+{
+ EXP_FILE << _T("<div class=mes></div>\n</body></html>\n");
+}
+
+void PlainHtmlExport::WriteGroup(bool isMe, const std::wstring &time, const std::wstring &user, const std::wstring &eventText)
+{
+ TCHAR buf[256];
+ EXP_FILE << _T("<div class=mes id=session>\n");
+ _stprintf_s(buf, TranslateT("Conversation started at %s"), time.c_str());
+ EXP_FILE << _T("<div class=text>") << buf << _T("</div>\n");
+ EXP_FILE << _T("</div>\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("<div class=mes id=event") << ev << _T(">\n");
+ EXP_FILE << _T("<div class=nick id=") << id << _T(">") << MakeTextHtmled(user) << _T(":</div>\n");
+ EXP_FILE << _T("<div class=date id=") << id << _T(">") << (Options::instance->exportHtml1ShowDate ? longDate : shortDate) << _T("</div>\n");
+ EXP_FILE << _T("<div class=text>\n");
+ EXP_FILE << mes;
+ EXP_FILE << _T("\n</div>\n");
+ EXP_FILE << _T("</div>\n");
+}
diff --git a/plugins/BasicHistory/PlainHtmlExport.h b/plugins/BasicHistory/PlainHtmlExport.h
new file mode 100644
index 0000000000..bb1c971ea3
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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/ReadMe.txt b/plugins/BasicHistory/ReadMe.txt
new file mode 100644
index 0000000000..284d52b6c7
--- /dev/null
+++ b/plugins/BasicHistory/ReadMe.txt
@@ -0,0 +1,48 @@
+========================================================================
+ DYNAMIC LINK LIBRARY : BasicHistory Project Overview
+========================================================================
+
+AppWizard has created this BasicHistory DLL for you.
+
+This file contains a summary of what you will find in each of the files that
+make up your BasicHistory application.
+
+
+BasicHistory.vcxproj
+ This is the main project file for VC++ projects generated using an Application Wizard.
+ It contains information about the version of Visual C++ that generated the file, and
+ information about the platforms, configurations, and project features selected with the
+ Application Wizard.
+
+BasicHistory.vcxproj.filters
+ This is the filters file for VC++ projects generated using an Application Wizard.
+ It contains information about the association between the files in your project
+ and the filters. This association is used in the IDE to show grouping of files with
+ similar extensions under a specific node (for e.g. ".cpp" files are associated with the
+ "Source Files" filter).
+
+BasicHistory.cpp
+ This is the main DLL source file.
+
+ When created, this DLL does not export any symbols. As a result, it
+ will not produce a .lib file when it is built. If you wish this project
+ to be a project dependency of some other project, you will either need to
+ add code to export some symbols from the DLL so that an export library
+ will be produced, or you can set the Ignore Input Library property to Yes
+ on the General propert page of the Linker folder in the project's Property
+ Pages dialog box.
+
+/////////////////////////////////////////////////////////////////////////////
+Other standard files:
+
+StdAfx.h, StdAfx.cpp
+ These files are used to build a precompiled header (PCH) file
+ named BasicHistory.pch and a precompiled types file named StdAfx.obj.
+
+/////////////////////////////////////////////////////////////////////////////
+Other notes:
+
+AppWizard uses "TODO:" comments to indicate parts of the source code you
+should add to or customize.
+
+/////////////////////////////////////////////////////////////////////////////
diff --git a/plugins/BasicHistory/RichHtmlExport.cpp b/plugins/BasicHistory/RichHtmlExport.cpp
new file mode 100644
index 0000000000..5a772a4914
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<std::pair<size_t, size_t> >* 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("&amp;");
+ break;
+ case _T('<'):
+ ret += _T("&lt;");
+ break;
+ case _T('>'):
+ ret += _T("&gt;");
+ break;
+ case _T('\t'):
+ ret += _T(" ");
+ break;
+ case _T('\n'):
+ ret += _T("<br>");
+ break;
+ }
+
+ start = find + 1;
+ if(positionMap != NULL)
+ {
+ size_t len = ret.length() - start - currentAdd;
+ if(len != 0)
+ {
+ positionMap->push(std::pair<size_t, size_t>(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("<a class=url target=_blank href=\"");
+ ret += url + _T("\">") + url + _T("</a>");
+ 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<<bmiColor.bmBitsPixel;
+ icoent.bReserved = 0;
+ icoent.wPlanes = bmiColor.bmPlanes;
+ icoent.wBitCount = bmiColor.bmBitsPixel;
+ icoent.dwBytesInRes = sizeof(BITMAPINFOHEADER) + info1.bmiHeader.biSizeImage + info2.bmiHeader.biSizeImage;
+
+ icoent.dwImageOffset = sizeof(icodir) + sizeof(icoent);
+
+ store.write((char*)&icodir,sizeof(icodir));
+ store.write((char*)&icoent,sizeof(icoent));
+
+ icobmi.biSize = sizeof(icobmi);
+ icobmi.biWidth = bmiColor.bmWidth;
+ icobmi.biHeight = bmiColor.bmHeight + bmiMask.bmHeight;
+ icobmi.biPlanes = info1.bmiHeader.biPlanes;
+ icobmi.biBitCount = bmiColor.bmBitsPixel;
+ icobmi.biSizeImage = 0;
+
+ store.write((char*)&icobmi,sizeof(icobmi));
+
+ store.write(bits1, info1.bmiHeader.biSizeImage);
+ store.write(bits2, info2.bmiHeader.biSizeImage);
+ DeleteDC(hDC);
+ delete [] bits1;
+ delete [] bits2;
+ }
+
+ store.close();
+ if(ii.hbmColor) DeleteObject(ii.hbmColor);
+ if(ii.hbmMask ) DeleteObject(ii.hbmMask );
+}
+
+bool DeleteDirectory(LPCTSTR lpszDir, bool noRecycleBin = true)
+{
+ size_t len = _tcslen(lpszDir);
+ TCHAR *pszFrom = new TCHAR[len+2];
+ _tcscpy_s(pszFrom, len+2, lpszDir);
+ pszFrom[len] = 0;
+ pszFrom[len+1] = 0;
+
+ SHFILEOPSTRUCT fileop;
+ fileop.hwnd = NULL; // no status display
+ fileop.wFunc = FO_DELETE; // delete operation
+ fileop.pFrom = pszFrom; // source file name as double null terminated string
+ fileop.pTo = NULL; // no destination needed
+ fileop.fFlags = FOF_NOCONFIRMATION|FOF_SILENT; // do not prompt the user
+
+ if(!noRecycleBin)
+ fileop.fFlags |= FOF_ALLOWUNDO;
+
+ fileop.fAnyOperationsAborted = FALSE;
+ fileop.lpszProgressTitle = NULL;
+ fileop.hNameMappings = NULL;
+
+ int ret = SHFileOperation(&fileop);
+ delete [] pszFrom;
+ return (ret == 0);
+}
+
+void RichHtmlExport::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)
+{
+ baseProto = baseProto1;
+ folder = RemoveExt(fileName) + TranslateT("_files");
+ folderName = GetName(folder);
+ DeleteDirectory(folder.c_str());
+ CreateDirectory(folder.c_str(), NULL);
+ std::wstring css = folder + _T("\\history.css");
+ BOOL cssCopied = FALSE;
+ if(!Options::instance->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("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\">\n");
+ EXP_FILE << _T("<html><head>\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=") << encoding << _T("\">\n");
+ EXP_FILE << _T("<title>") << TranslateT("History Log") << _T(" [") << MakeTextHtmled(myName) << _T("] - [") << MakeTextHtmled(name1) << _T("]</title>\n");
+ EXP_FILE << _T("<link rel=\"Stylesheet\" href=\"") << folderName << _T("\\history.css\" type=\"text/css\">\n");
+ EXP_FILE << _T("<script type=\"text/javascript\" src=\"") << folderName << _T("\\history.js\"></script>\n");
+ EXP_FILE << _T("</head><body>\n");
+
+ EXP_FILE << _T("<span id=\"menubar\">\n");
+ EXP_FILE << _T("<a class=mainmenu onmouseover='this.className=\"mainmenusel\";' href=\"javascript:void(0)\" onClick=\"ShowMenu(1)\" onMouseOut='HideMenu();this.className=\"mainmenu\";'>") << TranslateT("Menu") << _T("</a></span>\n");
+ EXP_FILE << _T("<span class=floatmenu id=L1 onmouseover=clearTimeout(timer) onmouseout=HideMenu()>\n");
+ EXP_FILE << _T("<table><tr>\n");
+ EXP_FILE << _T("<td class=menuitemunsel onmouseover='this.className=\"menuitemsel\"' onmouseout='this.className=\"menuitemunsel\"'>\n");
+ EXP_FILE << _T("<a class=menuitem onmouseover=ShowMenu(1) href=\"javascript:void(0)\" onclick=OpenAll(1)>") << TranslateT("Open all") << _T("</a>\n");
+ EXP_FILE << _T("</td></tr><tr>\n");
+ EXP_FILE << _T("<td class=menuitemunsel onmouseover='this.className=\"menuitemsel\"' onmouseout='this.className=\"menuitemunsel\"'>\n");
+ EXP_FILE << _T("<a class=menuitem onmouseover=ShowMenu(1) href=\"javascript:void(0)\" onclick=OpenAll(0)>") << TranslateT("Close all") << _T("</a>\n");
+ EXP_FILE << _T("</td></tr></table></span>\n");
+ EXP_FILE << _T("<script language=\"JavaScript\">\n");
+ EXP_FILE << _T("<!--\n");
+ EXP_FILE << _T("var menu = document.getElementById(\"menubar\");\n");
+ EXP_FILE << _T("if(menu != null)\n");
+ EXP_FILE << _T(" menu.style.visibility = \"visible\";\n");
+ EXP_FILE << _T("// -->\n");
+ EXP_FILE << _T("</script>\n");
+
+ EXP_FILE << _T("<h4>") << TranslateT("History Log") << _T("</h4>\n<h3>");
+ 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(")</h3>\n");
+ }
+ else
+ {
+ EXP_FILE << _T("</h3>\n");
+ }
+
+ EXP_FILE << _T("<h6>") << TranslateT("Filter:") << _T(" ") << MakeTextHtmled(filterName) << _T("</h6>\n");
+ groupId = 0;
+}
+
+void RichHtmlExport::WriteFooter()
+{
+ if(groupId > 0)
+ {
+ EXP_FILE << _T("</div>\n");
+ }
+
+ EXP_FILE << _T("<div class=mes id=bottom></div>\n</body></html>\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("</div>\n");
+ }
+
+ bool isUrl = false;
+ std::wstring& mes = ReplaceSmileys(isMe, eventText, isUrl);
+ EXP_FILE << _T("<div class=mes id=session>\n");
+ EXP_FILE << _T("<span class=eventimg id=") << id << _T("><img src=\"") << folderName << _T("\\pnode.ico\" class=sessionimage width=\"16\" height=\"16\" onclick=\"toggleFolder('group") << groupId << _T("', this)\"/>");
+ EXP_FILE << _T("<img src=\"") << folderName << _T("\\event") << ev << _T(".ico\" class=sessionimage width=\"16\" height=\"16\" onclick=\"toggleFolder('group") << groupId << _T("', this)\"/></span>\n");
+ EXP_FILE << _T("<span class=date id=") << id << _T(">") << time << _T("</span>\n<span class=text>\n") << mes;
+ EXP_FILE << _T("</span>\n</div>\n");
+ EXP_FILE << _T("<div class=group id=group") << groupId << _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("<div class=mes id=event") << ev << _T(">\n");
+ EXP_FILE << _T("<div class=eventimg id=") << id << _T(">") << _T("<img src=\"") << folderName << _T("\\event") << ev1 << _T(".ico\" class=sessionimage width=\"16\" height=\"16\"/></div>\n");
+ EXP_FILE << _T("<div class=date id=") << id << _T(">") << (Options::instance->exportHtml2ShowDate ? longDate : shortDate) << _T("</div>\n");
+ EXP_FILE << _T("<div class=nick id=") << id << _T(">") << MakeTextHtmled(user) << _T("</div>\n");
+ EXP_FILE << _T("<div class=text>\n");
+ EXP_FILE << mes;
+ EXP_FILE << _T("\n</div>\n");
+ EXP_FILE << _T("</div>\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<std::pair<size_t, size_t> > positionMap;
+ std::wstring newMsg = MakeTextHtmled(msg, &positionMap);
+ std::wstring smileyMsg;
+
+ size_t last_pos=0;
+ std::pair<size_t, size_t> 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<size_t, size_t>(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<size_t, size_t>(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("<img class=smiley src=\"");
+ smileyMsg += folderName;
+ smileyMsg += _T("\\");
+ smileyMsg += smileyName;
+ smileyMsg += _T("\" alt=\"");
+ smileyMsg += smileyText;
+ 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/RichHtmlExport.h b/plugins/BasicHistory/RichHtmlExport.h
new file mode 100644
index 0000000000..f4f6686964
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+#include "IExport.h"
+class RichHtmlExport :
+ public IExport
+{
+private:
+ int groupId;
+ std::wstring folder;
+ std::wstring folderName;
+ std::string baseProto;
+ stdext::hash_set<std::wstring> 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/Scheduler.cpp b/plugins/BasicHistory/Scheduler.cpp
new file mode 100644
index 0000000000..3b2ba18ab9
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<TaskOptions>* top = NULL, std::wstring* err = NULL, std::wstring* errDescr = NULL);
+std::wstring GetFileName(const std::wstring &baseName, std::wstring contactName, std::map<std::wstring, bool>& 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<std::wstring>& 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<std::wstring>& 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<TaskOptions>::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<TaskOptions>* 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<TaskOptions>::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("<date>")) < to.filePath.length())
+ {
+ if(err != NULL)
+ *err = TranslateT("Path to file");
+ if(errDescr != NULL)
+ *errDescr = TranslateT("FTP path cannot contain <date> 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<ExportManager*> 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<std::wstring, bool> existingContacts1;
+ ExportManager mExp = ExportManager(NULL, NULL, 1);
+ std::wstring filePath = to.filePath;
+ std::wstring dir;
+ std::list<std::wstring> files;
+ std::vector<HANDLE> contacts;
+ if(to.useFtp || to.compress)
+ {
+ std::map<std::wstring, bool> 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<std::wstring, bool> 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<std::wstring> files1;
+ ListDirectory(dir, L"\\", files1);
+ for(std::list<std::wstring>::iterator it = files1.begin(); it != files1.end(); ++it)
+ {
+ files.push_back(dir + *it);
+ }
+ }
+
+ if(!error)
+ {
+ std::list<HANDLE> contactList;
+ for(std::list<std::wstring>::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<std::wstring, bool> 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<IImport::ExternalMessage> 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<HANDLE>::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<std::wstring, bool> 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<date>";
+ 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<ExportManager*>::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<std::wstring, bool>& existingContacts, bool replaceContact)
+{
+ std::wstring str = baseName;
+ size_t pos = baseName.find(_T("<contact>"));
+ 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<std::wstring, bool>::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("<date>"));
+ 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<std::wstring>& 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<TaskOptions>::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<TaskOptions>::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<TaskOptions>::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<std::wstring> files;
+ std::map<std::wstring, bool> 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<std::wstring> files;
+ bool error = false;
+ zlib_filefunc_def pzlib_filefunc_def;
+ fill_win32_filefunc(&pzlib_filefunc_def);
+ std::wstring fileNameInZip;
+ std::map<std::wstring, bool> 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<std::wstring> files;
+ std::map<std::wstring, bool> 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<std::wstring> 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<std::wstring>::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<std::wstring>& files, const std::wstring& ftpName)
+{
+ std::map<std::wstring, bool> 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<std::wstring> localFiles;
+ for(std::list<std::wstring>::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<std::wstring>::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/SearchContext.h b/plugins/BasicHistory/SearchContext.h
new file mode 100644
index 0000000000..6b1655d857
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<MessageData> currentGroup;
+};
+
diff --git a/plugins/BasicHistory/Searcher.cpp b/plugins/BasicHistory/Searcher.cpp
new file mode 100644
index 0000000000..c93685bcf3
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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<TCHAR>(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<EventList::EventIndex>::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/Searcher.h b/plugins/BasicHistory/Searcher.h
new file mode 100644
index 0000000000..2f5aff6e8b
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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/TxtExport.cpp b/plugins/BasicHistory/TxtExport.cpp
new file mode 100644
index 0000000000..a5ca8afddf
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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/TxtExport.h b/plugins/BasicHistory/TxtExport.h
new file mode 100644
index 0000000000..bee2718649
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#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/codecvt_CodePage.h b/plugins/BasicHistory/codecvt_CodePage.h
new file mode 100644
index 0000000000..37b6b7d26f
--- /dev/null
+++ b/plugins/BasicHistory/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 <http://www.gnu.org/licenses/>.
+*/
+
+#pragma once
+
+template<class _Elem>
+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/dllmain.cpp b/plugins/BasicHistory/dllmain.cpp
new file mode 100644
index 0000000000..ad89773ec8
--- /dev/null
+++ b/plugins/BasicHistory/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/history.css b/plugins/BasicHistory/history.css
new file mode 100644
index 0000000000..43a584597d
--- /dev/null
+++ b/plugins/BasicHistory/history.css
@@ -0,0 +1,34 @@
+h3 { color: #666666; text-align: center; font-family: Verdana, Helvetica, Arial, sans-serif; font-size: 16pt; }
+h4 { text-align: center; font-family: Verdana, Helvetica, Arial, sans-serif; font-size: 14pt; }
+h6 { font-weight: normal; color: #000000; text-align: center; font-family: Verdana, Helvetica, Arial, sans-serif; font-size: 8pt; }
+.mes { border-top-width: 1px; border-right-width: 1px; border-bottom-width: 0px;border-left-width: 1px; border-top-style: solid; border-right-style: solid; border-bottom-style: solid; border-left-style: solid; border-top-color: #666666; border-bottom-color: #666666; border-left-color: #666666; border-right-color: #666666; padding: 4px; color: #000000; font: normal normal normal 8pt normal Tahoma, Tahoma, Verdana, Arial, sans-serif; text-decoration: none; }
+.text { clear: both; }
+.nick { float: left; font: normal normal bold 8pt normal Tahoma, Tahoma, Verdana, Arial, sans-serif; text-decoration: none; }
+.date { float: left; padding-left:5px; padding-right:5px; font: normal normal bold 8pt normal Tahoma, Tahoma, Verdana, Arial, sans-serif; text-decoration: none; }
+.eventimg { float: left; }
+.nick#inc { color: #C83F6B; }
+.nick#out { color: #0860BD; }
+.date#inc { color: #000000; }
+.date#out { color: #000000; }
+.url { color: #0000FF; }
+.mes#event0 { background-color: #DBDBDB; }
+.mes#event1 { background-color: #EEEEEE; }
+.mes#event2 { background-color: #CCD9F4; }
+.mes#session { background-color: #FFFDD7; }
+.mes#bottom { border-right-width: 0px; border-left-width: 0px; }
+.mes .eventimg {padding-left:16px; }
+.mes#session .eventimg {padding-left:0px; }
+.mes .text {padding-left:37px; display:table; }
+.mes#session .text {padding-left:0px; clear: none; line-height: 16px; }
+.mes#session .date {line-height: 16px; }
+.group { display: none; margin: 0px; }
+.sessionimage { vertical-align:middle; }
+.smiley { vertical-align:middle; }
+#menubar { position:absolute; left:10px; top:10px; visibility:hidden; border: 1px solid #000000; background-color:#dddddd; padding: 3px 3px 3px 3px; }
+.mainmenu { text-decoration:none; color:#6666AA; background-color: transparent; }
+.mainmenusel { text-decoration:none; color:#6666AA; background-color: #BBBBBB; }
+.floatmenu { position: absolute; background-color: #dddddd; visibility: hidden; top: 36px; left: 10px; }
+.floatmenu table { border: 1px solid #000000; }
+.menuitem { text-decoration:none; color:#0860BD; }
+.menuitemunsel { background-color: transparent; }
+.menuitemsel { background-color: #BBBBBB; } \ No newline at end of file
diff --git a/plugins/BasicHistory/history.js b/plugins/BasicHistory/history.js
new file mode 100644
index 0000000000..4d2156ac24
--- /dev/null
+++ b/plugins/BasicHistory/history.js
@@ -0,0 +1,95 @@
+
+function toggleFolder(id, imageNode)
+{
+ var folder = document.getElementById(id);
+ if (imageNode.previousSibling != null)
+ {
+ imageNode = imageNode.previousSibling;
+ }
+ var l = imageNode.src.length;
+ if (folder == null)
+ {
+ }
+ else if (folder.style.display == "block")
+ {
+ if (imageNode != null)
+ {
+ if (imageNode.src.substring(l-9,l) == "mnode.ico")
+ {
+ imageNode.src = imageNode.src.substring(0, l-9) + "pnode.ico";
+ }
+ }
+ folder.style.display = "none";
+ }
+ else
+ {
+ if (imageNode != null)
+ {
+ if (imageNode.src.substring(l-9,l) == "pnode.ico")
+ {
+ imageNode.src = imageNode.src.substring(0, l-9) + "mnode.ico";
+ }
+ }
+ folder.style.display = "block";
+ }
+}
+
+var timer;
+
+function ShowMenu(isShow)
+{
+ if(timer)
+ clearTimeout(timer);
+
+ var menu = document.getElementById("L1");
+ if(isShow == 1)
+ menu.style.visibility = "visible";
+ else
+ menu.style.visibility = "hidden";
+}
+
+function HideMenu()
+{
+ timer = setTimeout("ShowMenu(0)", 500);
+}
+
+function OpenAll(isOpen)
+{
+ var idMod = 0;
+ while(gr = document.getElementById("group" + idMod))
+ {
+ var imageNode = gr.previousSibling;
+ if(imageNode.tagName == null)
+ imageNode = imageNode.previousSibling;
+ imageNode = imageNode.getElementsByTagName("span")[0].getElementsByTagName("img")[0];
+ var l = imageNode.src.length;
+ if(gr.style.display == "block")
+ {
+ if(!isOpen)
+ {
+ if (imageNode != null)
+ {
+ if (imageNode.src.substring(l-9,l) == "mnode.ico")
+ {
+ imageNode.src = imageNode.src.substring(0, l-9) + "pnode.ico";
+ }
+ }
+ gr.style.display = "none";
+ }
+ }
+ else if(isOpen)
+ {
+ if (imageNode != null)
+ {
+ if (imageNode.src.substring(l-9,l) == "pnode.ico")
+ {
+ imageNode.src = imageNode.src.substring(0, l-9) + "mnode.ico";
+ }
+ }
+ gr.style.display = "block";
+ }
+ ++idMod;
+ }
+
+ ShowMenu(0);
+}
diff --git a/plugins/BasicHistory/icons/FindNext.ico b/plugins/BasicHistory/icons/FindNext.ico
new file mode 100644
index 0000000000..dd1c62f113
--- /dev/null
+++ b/plugins/BasicHistory/icons/FindNext.ico
Binary files differ
diff --git a/plugins/BasicHistory/icons/FindPrev.ico b/plugins/BasicHistory/icons/FindPrev.ico
new file mode 100644
index 0000000000..ba8c3ba5df
--- /dev/null
+++ b/plugins/BasicHistory/icons/FindPrev.ico
Binary files differ
diff --git a/plugins/BasicHistory/icons/Incom.ico b/plugins/BasicHistory/icons/Incom.ico
new file mode 100644
index 0000000000..9c618335c5
--- /dev/null
+++ b/plugins/BasicHistory/icons/Incom.ico
Binary files differ
diff --git a/plugins/BasicHistory/icons/Outg.ico b/plugins/BasicHistory/icons/Outg.ico
new file mode 100644
index 0000000000..8bfeef6344
--- /dev/null
+++ b/plugins/BasicHistory/icons/Outg.ico
Binary files differ
diff --git a/plugins/BasicHistory/icons/Status change.ico b/plugins/BasicHistory/icons/Status change.ico
new file mode 100644
index 0000000000..b9b270228a
--- /dev/null
+++ b/plugins/BasicHistory/icons/Status change.ico
Binary files differ
diff --git a/plugins/BasicHistory/icons/minus.ico b/plugins/BasicHistory/icons/minus.ico
new file mode 100644
index 0000000000..39d1f72f79
--- /dev/null
+++ b/plugins/BasicHistory/icons/minus.ico
Binary files differ
diff --git a/plugins/BasicHistory/icons/mnode.ico b/plugins/BasicHistory/icons/mnode.ico
new file mode 100644
index 0000000000..d332fbda16
--- /dev/null
+++ b/plugins/BasicHistory/icons/mnode.ico
Binary files differ
diff --git a/plugins/BasicHistory/icons/plus.ico b/plugins/BasicHistory/icons/plus.ico
new file mode 100644
index 0000000000..1230b5de32
--- /dev/null
+++ b/plugins/BasicHistory/icons/plus.ico
Binary files differ
diff --git a/plugins/BasicHistory/icons/pnode.ico b/plugins/BasicHistory/icons/pnode.ico
new file mode 100644
index 0000000000..811dfd0f84
--- /dev/null
+++ b/plugins/BasicHistory/icons/pnode.ico
Binary files differ
diff --git a/plugins/BasicHistory/lib/zlib.lib b/plugins/BasicHistory/lib/zlib.lib
new file mode 100644
index 0000000000..33f583fb5f
--- /dev/null
+++ b/plugins/BasicHistory/lib/zlib.lib
Binary files differ
diff --git a/plugins/BasicHistory/lib64/zlib.lib b/plugins/BasicHistory/lib64/zlib.lib
new file mode 100644
index 0000000000..3bb413f686
--- /dev/null
+++ b/plugins/BasicHistory/lib64/zlib.lib
Binary files differ
diff --git a/plugins/BasicHistory/resource.h b/plugins/BasicHistory/resource.h
new file mode 100644
index 0000000000..71484f2343
--- /dev/null
+++ b/plugins/BasicHistory/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/stdafx.cpp b/plugins/BasicHistory/stdafx.cpp
new file mode 100644
index 0000000000..dd47c41552
--- /dev/null
+++ b/plugins/BasicHistory/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/stdafx.h b/plugins/BasicHistory/stdafx.h
new file mode 100644
index 0000000000..bc670d4358
--- /dev/null
+++ b/plugins/BasicHistory/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 <windows.h>
+#include <windowsx.h>
+#include <richedit.h>
+#include <time.h>
+#include <commctrl.h>
+#include <commdlg.h>
+#include <tom.h>
+#include <richole.h>
+#include <Shlobj.h>
+#include <shellapi.h>
+
+#include <map>
+#include <hash_set>
+#include <vector>
+#include <queue>
+#include <locale>
+#include <string>
+#include <fstream>
+
+#define MIRANDA_VER 0x0900
+#define MIRANDA_CUSTOM_LP
+
+#include <newpluginapi.h>
+#include <m_langpack.h>
+#include <m_system.h>
+#include <m_clist.h>
+#include <m_skin.h>
+#include <m_history.h>
+#include <m_database.h>
+#include <m_icolib.h>
+#include <m_timezones.h>
+#include <m_contacts.h>
+#include <m_protocols.h>
+#include <m_button.h>
+#include <m_options.h>
+#include <m_fontservice.h>
+#include <m_hotkeys.h>
+#include <m_message.h>
+#include <m_protosvc.h>
+#include <m_icq.h>
+#include <m_clc.h>
+#include <m_utils.h>
+#include <m_popup.h>
+
+#include <win2k.h>
+
+#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/targetver.h b/plugins/BasicHistory/targetver.h
new file mode 100644
index 0000000000..90e767bfce
--- /dev/null
+++ b/plugins/BasicHistory/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 <SDKDDKVer.h>
diff --git a/plugins/BasicHistory/version.h b/plugins/BasicHistory/version.h
new file mode 100644
index 0000000000..691fb07ebd
--- /dev/null
+++ b/plugins/BasicHistory/version.h
@@ -0,0 +1,20 @@
+#define __MAJOR_VERSION 1
+#define __MINOR_VERSION 0
+#define __RELEASE_NUM 1
+#define __BUILD_NUM 5
+
+#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"
diff --git a/plugins/BasicHistory/version.rc b/plugins/BasicHistory/version.rc
new file mode 100644
index 0000000000..3fcaa468d0
--- /dev/null
+++ b/plugins/BasicHistory/version.rc
@@ -0,0 +1,37 @@
+
+#include <windows.h>
+#include "version.h"
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION __FILEVERSION_STRING
+ PRODUCTVERSION __FILEVERSION_STRING
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+#ifdef _DEBUG
+ FILEFLAGS VS_FF_DEBUG
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS VOS_NT_WINDOWS32
+ FILETYPE VFT_DLL
+ FILESUBTYPE VFT2_UNKNOWN
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "000004b0"
+ BEGIN
+ VALUE "Author", "Krzysztof Kral"
+ VALUE "CompanyName", "Krzysztof Kral"
+ VALUE "FileDescription", __DESCRIPTION
+ VALUE "FileVersion", __VERSION_STRING
+ VALUE "InternalName", __INTERNAL_NAME
+ VALUE "LegalCopyright", __COPYRIGHT
+ VALUE "OriginalFilename", __FILENAME
+ VALUE "ProductName", __PLUGIN_NAME
+ VALUE "ProductVersion", __VERSION_STRING
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x0, 1200
+ END
+END
diff --git a/plugins/BasicHistory/zip/MiniZip64_Changes.txt b/plugins/BasicHistory/zip/MiniZip64_Changes.txt
new file mode 100644
index 0000000000..13a1bd91a9
--- /dev/null
+++ b/plugins/BasicHistory/zip/MiniZip64_Changes.txt
@@ -0,0 +1,6 @@
+
+MiniZip 1.1 was derrived from MiniZip at version 1.01f
+
+Change in 1.0 (Okt 2009)
+ - **TODO - Add history**
+
diff --git a/plugins/BasicHistory/zip/MiniZip64_info.txt b/plugins/BasicHistory/zip/MiniZip64_info.txt
new file mode 100644
index 0000000000..57d7152420
--- /dev/null
+++ b/plugins/BasicHistory/zip/MiniZip64_info.txt
@@ -0,0 +1,74 @@
+MiniZip - Copyright (c) 1998-2010 - by Gilles Vollant - version 1.1 64 bits from Mathias Svensson
+
+Introduction
+---------------------
+MiniZip 1.1 is built from MiniZip 1.0 by Gilles Vollant ( http://www.winimage.com/zLibDll/minizip.html )
+
+When adding ZIP64 support into minizip it would result into risk of breaking compatibility with minizip 1.0.
+All possible work was done for compatibility.
+
+
+Background
+---------------------
+When adding ZIP64 support Mathias Svensson found that Even Rouault have added ZIP64
+support for unzip.c into minizip for a open source project called gdal ( http://www.gdal.org/ )
+
+That was used as a starting point. And after that ZIP64 support was added to zip.c
+some refactoring and code cleanup was also done.
+
+
+Changed from MiniZip 1.0 to MiniZip 1.1
+---------------------------------------
+* Added ZIP64 support for unzip ( by Even Rouault )
+* Added ZIP64 support for zip ( by Mathias Svensson )
+* Reverted some changed that Even Rouault did.
+* Bunch of patches received from Gulles Vollant that he received for MiniZip from various users.
+* Added unzip patch for BZIP Compression method (patch create by Daniel Borca)
+* Added BZIP Compress method for zip
+* Did some refactoring and code cleanup
+
+
+Credits
+
+ Gilles Vollant - Original MiniZip author
+ Even Rouault - ZIP64 unzip Support
+ Daniel Borca - BZip Compression method support in unzip
+ Mathias Svensson - ZIP64 zip support
+ Mathias Svensson - BZip Compression method support in zip
+
+ Resources
+
+ ZipLayout http://result42.com/projects/ZipFileLayout
+ Command line tool for Windows that shows the layout and information of the headers in a zip archive.
+ Used when debugging and validating the creation of zip files using MiniZip64
+
+
+ ZIP App Note http://www.pkware.com/documents/casestudies/APPNOTE.TXT
+ Zip File specification
+
+
+Notes.
+ * To be able to use BZip compression method in zip64.c or unzip64.c the BZIP2 lib is needed and HAVE_BZIP2 need to be defined.
+
+License
+----------------------------------------------------------
+ Condition of use and distribution are the same than zlib :
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+----------------------------------------------------------
+
diff --git a/plugins/BasicHistory/zip/crypt.h b/plugins/BasicHistory/zip/crypt.h
new file mode 100644
index 0000000000..a01d08d932
--- /dev/null
+++ b/plugins/BasicHistory/zip/crypt.h
@@ -0,0 +1,131 @@
+/* crypt.h -- base code for crypt/uncrypt ZIPfile
+
+
+ Version 1.01e, February 12th, 2005
+
+ Copyright (C) 1998-2005 Gilles Vollant
+
+ This code is a modified version of crypting code in Infozip distribution
+
+ The encryption/decryption parts of this source code (as opposed to the
+ non-echoing password parts) were originally written in Europe. The
+ whole source package can be freely distributed, including from the USA.
+ (Prior to January 2000, re-export from the US was a violation of US law.)
+
+ This encryption code is a direct transcription of the algorithm from
+ Roger Schlafly, described by Phil Katz in the file appnote.txt. This
+ file (appnote.txt) is distributed with the PKZIP program (even in the
+ version without encryption capabilities).
+
+ If you don't need crypting in your application, just define symbols
+ NOCRYPT and NOUNCRYPT.
+
+ This code support the "Traditional PKWARE Encryption".
+
+ The new AES encryption added on Zip format by Winzip (see the page
+ http://www.winzip.com/aes_info.htm ) and PKWare PKZip 5.x Strong
+ Encryption is not supported.
+*/
+
+#define CRC32(c, b) ((*(pcrc_32_tab+(((int)(c) ^ (b)) & 0xff))) ^ ((c) >> 8))
+
+/***********************************************************************
+ * Return the next byte in the pseudo-random sequence
+ */
+static int decrypt_byte(unsigned long* pkeys, const unsigned long* pcrc_32_tab)
+{
+ unsigned temp; /* POTENTIAL BUG: temp*(temp^1) may overflow in an
+ * unpredictable manner on 16-bit systems; not a problem
+ * with any known compiler so far, though */
+
+ temp = ((unsigned)(*(pkeys+2)) & 0xffff) | 2;
+ return (int)(((temp * (temp ^ 1)) >> 8) & 0xff);
+}
+
+/***********************************************************************
+ * Update the encryption keys with the next byte of plain text
+ */
+static int update_keys(unsigned long* pkeys,const unsigned long* pcrc_32_tab,int c)
+{
+ (*(pkeys+0)) = CRC32((*(pkeys+0)), c);
+ (*(pkeys+1)) += (*(pkeys+0)) & 0xff;
+ (*(pkeys+1)) = (*(pkeys+1)) * 134775813L + 1;
+ {
+ register int keyshift = (int)((*(pkeys+1)) >> 24);
+ (*(pkeys+2)) = CRC32((*(pkeys+2)), keyshift);
+ }
+ return c;
+}
+
+
+/***********************************************************************
+ * Initialize the encryption keys and the random header according to
+ * the given password.
+ */
+static void init_keys(const char* passwd,unsigned long* pkeys,const unsigned long* pcrc_32_tab)
+{
+ *(pkeys+0) = 305419896L;
+ *(pkeys+1) = 591751049L;
+ *(pkeys+2) = 878082192L;
+ while (*passwd != '\0') {
+ update_keys(pkeys,pcrc_32_tab,(int)*passwd);
+ passwd++;
+ }
+}
+
+#define zdecode(pkeys,pcrc_32_tab,c) \
+ (update_keys(pkeys,pcrc_32_tab,c ^= decrypt_byte(pkeys,pcrc_32_tab)))
+
+#define zencode(pkeys,pcrc_32_tab,c,t) \
+ (t=decrypt_byte(pkeys,pcrc_32_tab), update_keys(pkeys,pcrc_32_tab,c), t^(c))
+
+#ifdef INCLUDECRYPTINGCODE_IFCRYPTALLOWED
+
+#define RAND_HEAD_LEN 12
+ /* "last resort" source for second part of crypt seed pattern */
+# ifndef ZCR_SEED2
+# define ZCR_SEED2 3141592654UL /* use PI as default pattern */
+# endif
+
+static int crypthead(const char* passwd, /* password string */
+ unsigned char* buf, /* where to write header */
+ int bufSize,
+ unsigned long* pkeys,
+ const unsigned long* pcrc_32_tab,
+ unsigned long crcForCrypting)
+{
+ int n; /* index in random header */
+ int t; /* temporary */
+ int c; /* random byte */
+ unsigned char header[RAND_HEAD_LEN-2]; /* random header */
+ static unsigned calls = 0; /* ensure different random header each time */
+
+ if (bufSize<RAND_HEAD_LEN)
+ return 0;
+
+ /* First generate RAND_HEAD_LEN-2 random bytes. We encrypt the
+ * output of rand() to get less predictability, since rand() is
+ * often poorly implemented.
+ */
+ if (++calls == 1)
+ {
+ srand((unsigned)(time(NULL) ^ ZCR_SEED2));
+ }
+ init_keys(passwd, pkeys, pcrc_32_tab);
+ for (n = 0; n < RAND_HEAD_LEN-2; n++)
+ {
+ c = (rand() >> 7) & 0xff;
+ header[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, c, t);
+ }
+ /* Encrypt random header (last two bytes is high word of crc) */
+ init_keys(passwd, pkeys, pcrc_32_tab);
+ for (n = 0; n < RAND_HEAD_LEN-2; n++)
+ {
+ buf[n] = (unsigned char)zencode(pkeys, pcrc_32_tab, header[n], t);
+ }
+ buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 16) & 0xff, t);
+ buf[n++] = (unsigned char)zencode(pkeys, pcrc_32_tab, (int)(crcForCrypting >> 24) & 0xff, t);
+ return n;
+}
+
+#endif
diff --git a/plugins/BasicHistory/zip/ioapi.c b/plugins/BasicHistory/zip/ioapi.c
new file mode 100644
index 0000000000..49958f61ff
--- /dev/null
+++ b/plugins/BasicHistory/zip/ioapi.c
@@ -0,0 +1,235 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+*/
+
+#if (defined(_WIN32))
+ #define _CRT_SECURE_NO_WARNINGS
+#endif
+
+#include "ioapi.h"
+
+voidpf call_zopen64 (const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode)
+{
+ if (pfilefunc->zfile_func64.zopen64_file != NULL)
+ return (*(pfilefunc->zfile_func64.zopen64_file)) (pfilefunc->zfile_func64.opaque,filename,mode);
+ else
+ {
+ return (*(pfilefunc->zopen32_file))(pfilefunc->zfile_func64.opaque,(const char*)filename,mode);
+ }
+}
+
+long call_zseek64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin)
+{
+ if (pfilefunc->zfile_func64.zseek64_file != NULL)
+ return (*(pfilefunc->zfile_func64.zseek64_file)) (pfilefunc->zfile_func64.opaque,filestream,offset,origin);
+ else
+ {
+ uLong offsetTruncated = (uLong)offset;
+ if (offsetTruncated != offset)
+ return -1;
+ else
+ return (*(pfilefunc->zseek32_file))(pfilefunc->zfile_func64.opaque,filestream,offsetTruncated,origin);
+ }
+}
+
+ZPOS64_T call_ztell64 (const zlib_filefunc64_32_def* pfilefunc,voidpf filestream)
+{
+ if (pfilefunc->zfile_func64.zseek64_file != NULL)
+ return (*(pfilefunc->zfile_func64.ztell64_file)) (pfilefunc->zfile_func64.opaque,filestream);
+ else
+ {
+ uLong tell_uLong = (*(pfilefunc->ztell32_file))(pfilefunc->zfile_func64.opaque,filestream);
+ if ((tell_uLong) == ((uLong)-1))
+ return (ZPOS64_T)-1;
+ else
+ return tell_uLong;
+ }
+}
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32)
+{
+ p_filefunc64_32->zfile_func64.zopen64_file = NULL;
+ p_filefunc64_32->zopen32_file = p_filefunc32->zopen_file;
+ p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+ p_filefunc64_32->zfile_func64.zread_file = p_filefunc32->zread_file;
+ p_filefunc64_32->zfile_func64.zwrite_file = p_filefunc32->zwrite_file;
+ p_filefunc64_32->zfile_func64.ztell64_file = NULL;
+ p_filefunc64_32->zfile_func64.zseek64_file = NULL;
+ p_filefunc64_32->zfile_func64.zclose_file = p_filefunc32->zclose_file;
+ p_filefunc64_32->zfile_func64.zerror_file = p_filefunc32->zerror_file;
+ p_filefunc64_32->zfile_func64.opaque = p_filefunc32->opaque;
+ p_filefunc64_32->zseek32_file = p_filefunc32->zseek_file;
+ p_filefunc64_32->ztell32_file = p_filefunc32->ztell_file;
+}
+
+
+
+static voidpf ZCALLBACK fopen_file_func OF((voidpf opaque, const char* filename, int mode));
+static uLong ZCALLBACK fread_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+static uLong ZCALLBACK fwrite_file_func OF((voidpf opaque, voidpf stream, const void* buf,uLong size));
+static ZPOS64_T ZCALLBACK ftell64_file_func OF((voidpf opaque, voidpf stream));
+static long ZCALLBACK fseek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+static int ZCALLBACK fclose_file_func OF((voidpf opaque, voidpf stream));
+static int ZCALLBACK ferror_file_func OF((voidpf opaque, voidpf stream));
+
+static voidpf ZCALLBACK fopen_file_func (voidpf opaque, const char* filename, int mode)
+{
+ FILE* file = NULL;
+ const char* mode_fopen = NULL;
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+ mode_fopen = "rb";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ mode_fopen = "r+b";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ mode_fopen = "wb";
+
+ if ((filename!=NULL) && (mode_fopen != NULL))
+ file = fopen(filename, mode_fopen);
+ return file;
+}
+
+static voidpf ZCALLBACK fopen64_file_func (voidpf opaque, const void* filename, int mode)
+{
+ FILE* file = NULL;
+ const char* mode_fopen = NULL;
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+ mode_fopen = "rb";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ mode_fopen = "r+b";
+ else
+ if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ mode_fopen = "wb";
+
+ if ((filename!=NULL) && (mode_fopen != NULL))
+ file = fopen64((const char*)filename, mode_fopen);
+ return file;
+}
+
+
+static uLong ZCALLBACK fread_file_func (voidpf opaque, voidpf stream, void* buf, uLong size)
+{
+ uLong ret;
+ ret = (uLong)fread(buf, 1, (size_t)size, (FILE *)stream);
+ return ret;
+}
+
+static uLong ZCALLBACK fwrite_file_func (voidpf opaque, voidpf stream, const void* buf, uLong size)
+{
+ uLong ret;
+ ret = (uLong)fwrite(buf, 1, (size_t)size, (FILE *)stream);
+ return ret;
+}
+
+static long ZCALLBACK ftell_file_func (voidpf opaque, voidpf stream)
+{
+ long ret;
+ ret = ftell((FILE *)stream);
+ return ret;
+}
+
+
+static ZPOS64_T ZCALLBACK ftell64_file_func (voidpf opaque, voidpf stream)
+{
+ ZPOS64_T ret;
+ ret = ftello64((FILE *)stream);
+ return ret;
+}
+
+static long ZCALLBACK fseek_file_func (voidpf opaque, voidpf stream, uLong offset, int origin)
+{
+ int fseek_origin=0;
+ long ret;
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ fseek_origin = SEEK_CUR;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ fseek_origin = SEEK_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ fseek_origin = SEEK_SET;
+ break;
+ default: return -1;
+ }
+ ret = 0;
+ if (fseek((FILE *)stream, offset, fseek_origin) != 0)
+ ret = -1;
+ return ret;
+}
+
+static long ZCALLBACK fseek64_file_func (voidpf opaque, voidpf stream, ZPOS64_T offset, int origin)
+{
+ int fseek_origin=0;
+ long ret;
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ fseek_origin = SEEK_CUR;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ fseek_origin = SEEK_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ fseek_origin = SEEK_SET;
+ break;
+ default: return -1;
+ }
+ ret = 0;
+
+ if(fseeko64((FILE *)stream, offset, fseek_origin) != 0)
+ ret = -1;
+
+ return ret;
+}
+
+
+static int ZCALLBACK fclose_file_func (voidpf opaque, voidpf stream)
+{
+ int ret;
+ ret = fclose((FILE *)stream);
+ return ret;
+}
+
+static int ZCALLBACK ferror_file_func (voidpf opaque, voidpf stream)
+{
+ int ret;
+ ret = ferror((FILE *)stream);
+ return ret;
+}
+
+void fill_fopen_filefunc (pzlib_filefunc_def)
+ zlib_filefunc_def* pzlib_filefunc_def;
+{
+ pzlib_filefunc_def->zopen_file = fopen_file_func;
+ pzlib_filefunc_def->zread_file = fread_file_func;
+ pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+ pzlib_filefunc_def->ztell_file = ftell_file_func;
+ pzlib_filefunc_def->zseek_file = fseek_file_func;
+ pzlib_filefunc_def->zclose_file = fclose_file_func;
+ pzlib_filefunc_def->zerror_file = ferror_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
+
+void fill_fopen64_filefunc (zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen64_file = fopen64_file_func;
+ pzlib_filefunc_def->zread_file = fread_file_func;
+ pzlib_filefunc_def->zwrite_file = fwrite_file_func;
+ pzlib_filefunc_def->ztell64_file = ftell64_file_func;
+ pzlib_filefunc_def->zseek64_file = fseek64_file_func;
+ pzlib_filefunc_def->zclose_file = fclose_file_func;
+ pzlib_filefunc_def->zerror_file = ferror_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
diff --git a/plugins/BasicHistory/zip/ioapi.h b/plugins/BasicHistory/zip/ioapi.h
new file mode 100644
index 0000000000..8309c4cf8f
--- /dev/null
+++ b/plugins/BasicHistory/zip/ioapi.h
@@ -0,0 +1,200 @@
+/* ioapi.h -- IO base function header for compress/uncompress .zip
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+ Changes
+
+ Oct-2009 - Defined ZPOS64_T to fpos_t on windows and u_int64_t on linux. (might need to find a better why for this)
+ Oct-2009 - Change to fseeko64, ftello64 and fopen64 so large files would work on linux.
+ More if/def section may be needed to support other platforms
+ Oct-2009 - Defined fxxxx64 calls to normal fopen/ftell/fseek so they would compile on windows.
+ (but you should use iowin32.c for windows instead)
+
+*/
+
+#ifndef _ZLIBIOAPI64_H
+#define _ZLIBIOAPI64_H
+
+#if (!defined(_WIN32)) && (!defined(WIN32))
+
+ // Linux needs this to support file operation on files larger then 4+GB
+ // But might need better if/def to select just the platforms that needs them.
+
+ #ifndef __USE_FILE_OFFSET64
+ #define __USE_FILE_OFFSET64
+ #endif
+ #ifndef __USE_LARGEFILE64
+ #define __USE_LARGEFILE64
+ #endif
+ #ifndef _LARGEFILE64_SOURCE
+ #define _LARGEFILE64_SOURCE
+ #endif
+ #ifndef _FILE_OFFSET_BIT
+ #define _FILE_OFFSET_BIT 64
+ #endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "zlib.h"
+
+#if defined(USE_FILE32API)
+#define fopen64 fopen
+#define ftello64 ftell
+#define fseeko64 fseek
+#else
+#ifdef _MSC_VER
+ #define fopen64 fopen
+ #if (_MSC_VER >= 1400) && (!(defined(NO_MSCVER_FILE64_FUNC)))
+ #define ftello64 _ftelli64
+ #define fseeko64 _fseeki64
+ #else // old MSC
+ #define ftello64 ftell
+ #define fseeko64 fseek
+ #endif
+#endif
+#endif
+
+/*
+#ifndef ZPOS64_T
+ #ifdef _WIN32
+ #define ZPOS64_T fpos_t
+ #else
+ #include <stdint.h>
+ #define ZPOS64_T uint64_t
+ #endif
+#endif
+*/
+
+#ifdef HAVE_MINIZIP64_CONF_H
+#include "mz64conf.h"
+#endif
+
+/* a type choosen by DEFINE */
+#ifdef HAVE_64BIT_INT_CUSTOM
+typedef 64BIT_INT_CUSTOM_TYPE ZPOS64_T;
+#else
+#ifdef HAS_STDINT_H
+#include "stdint.h"
+typedef uint64_t ZPOS64_T;
+#else
+
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef unsigned __int64 ZPOS64_T;
+#else
+typedef unsigned long long int ZPOS64_T;
+#endif
+#endif
+#endif
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#define ZLIB_FILEFUNC_SEEK_CUR (1)
+#define ZLIB_FILEFUNC_SEEK_END (2)
+#define ZLIB_FILEFUNC_SEEK_SET (0)
+
+#define ZLIB_FILEFUNC_MODE_READ (1)
+#define ZLIB_FILEFUNC_MODE_WRITE (2)
+#define ZLIB_FILEFUNC_MODE_READWRITEFILTER (3)
+
+#define ZLIB_FILEFUNC_MODE_EXISTING (4)
+#define ZLIB_FILEFUNC_MODE_CREATE (8)
+
+
+#ifndef ZCALLBACK
+ #if (defined(WIN32) || defined(_WIN32) || defined (WINDOWS) || defined (_WINDOWS)) && defined(CALLBACK) && defined (USEWINDOWS_CALLBACK)
+ #define ZCALLBACK CALLBACK
+ #else
+ #define ZCALLBACK
+ #endif
+#endif
+
+
+
+
+typedef voidpf (ZCALLBACK *open_file_func) OF((voidpf opaque, const char* filename, int mode));
+typedef uLong (ZCALLBACK *read_file_func) OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+typedef uLong (ZCALLBACK *write_file_func) OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
+typedef int (ZCALLBACK *close_file_func) OF((voidpf opaque, voidpf stream));
+typedef int (ZCALLBACK *testerror_file_func) OF((voidpf opaque, voidpf stream));
+
+typedef long (ZCALLBACK *tell_file_func) OF((voidpf opaque, voidpf stream));
+typedef long (ZCALLBACK *seek_file_func) OF((voidpf opaque, voidpf stream, uLong offset, int origin));
+
+
+/* here is the "old" 32 bits structure structure */
+typedef struct zlib_filefunc_def_s
+{
+ open_file_func zopen_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell_file_func ztell_file;
+ seek_file_func zseek_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ voidpf opaque;
+} zlib_filefunc_def;
+
+typedef ZPOS64_T (ZCALLBACK *tell64_file_func) OF((voidpf opaque, voidpf stream));
+typedef long (ZCALLBACK *seek64_file_func) OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+typedef voidpf (ZCALLBACK *open64_file_func) OF((voidpf opaque, const void* filename, int mode));
+
+typedef struct zlib_filefunc64_def_s
+{
+ open64_file_func zopen64_file;
+ read_file_func zread_file;
+ write_file_func zwrite_file;
+ tell64_file_func ztell64_file;
+ seek64_file_func zseek64_file;
+ close_file_func zclose_file;
+ testerror_file_func zerror_file;
+ voidpf opaque;
+} zlib_filefunc64_def;
+
+void fill_fopen64_filefunc OF((zlib_filefunc64_def* pzlib_filefunc_def));
+void fill_fopen_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
+
+/* now internal definition, only for zip.c and unzip.h */
+typedef struct zlib_filefunc64_32_def_s
+{
+ zlib_filefunc64_def zfile_func64;
+ open_file_func zopen32_file;
+ tell_file_func ztell32_file;
+ seek_file_func zseek32_file;
+} zlib_filefunc64_32_def;
+
+
+#define ZREAD64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zread_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
+#define ZWRITE64(filefunc,filestream,buf,size) ((*((filefunc).zfile_func64.zwrite_file)) ((filefunc).zfile_func64.opaque,filestream,buf,size))
+//#define ZTELL64(filefunc,filestream) ((*((filefunc).ztell64_file)) ((filefunc).opaque,filestream))
+//#define ZSEEK64(filefunc,filestream,pos,mode) ((*((filefunc).zseek64_file)) ((filefunc).opaque,filestream,pos,mode))
+#define ZCLOSE64(filefunc,filestream) ((*((filefunc).zfile_func64.zclose_file)) ((filefunc).zfile_func64.opaque,filestream))
+#define ZERROR64(filefunc,filestream) ((*((filefunc).zfile_func64.zerror_file)) ((filefunc).zfile_func64.opaque,filestream))
+
+voidpf call_zopen64 OF((const zlib_filefunc64_32_def* pfilefunc,const void*filename,int mode));
+long call_zseek64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream, ZPOS64_T offset, int origin));
+ZPOS64_T call_ztell64 OF((const zlib_filefunc64_32_def* pfilefunc,voidpf filestream));
+
+void fill_zlib_filefunc64_32_def_from_filefunc32(zlib_filefunc64_32_def* p_filefunc64_32,const zlib_filefunc_def* p_filefunc32);
+
+#define ZOPEN64(filefunc,filename,mode) (call_zopen64((&(filefunc)),(filename),(mode)))
+#define ZTELL64(filefunc,filestream) (call_ztell64((&(filefunc)),(filestream)))
+#define ZSEEK64(filefunc,filestream,pos,mode) (call_zseek64((&(filefunc)),(filestream),(pos),(mode)))
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/plugins/BasicHistory/zip/iowin32.c b/plugins/BasicHistory/zip/iowin32.c
new file mode 100644
index 0000000000..6a2a883be7
--- /dev/null
+++ b/plugins/BasicHistory/zip/iowin32.c
@@ -0,0 +1,389 @@
+/* iowin32.c -- IO base function header for compress/uncompress .zip
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+*/
+
+#include <stdlib.h>
+
+#include "zlib.h"
+#include "ioapi.h"
+#include "iowin32.h"
+
+#ifndef INVALID_HANDLE_VALUE
+#define INVALID_HANDLE_VALUE (0xFFFFFFFF)
+#endif
+
+#ifndef INVALID_SET_FILE_POINTER
+#define INVALID_SET_FILE_POINTER ((DWORD)-1)
+#endif
+
+voidpf ZCALLBACK win32_open_file_func OF((voidpf opaque, const char* filename, int mode));
+uLong ZCALLBACK win32_read_file_func OF((voidpf opaque, voidpf stream, void* buf, uLong size));
+uLong ZCALLBACK win32_write_file_func OF((voidpf opaque, voidpf stream, const void* buf, uLong size));
+ZPOS64_T ZCALLBACK win32_tell64_file_func OF((voidpf opaque, voidpf stream));
+long ZCALLBACK win32_seek64_file_func OF((voidpf opaque, voidpf stream, ZPOS64_T offset, int origin));
+int ZCALLBACK win32_close_file_func OF((voidpf opaque, voidpf stream));
+int ZCALLBACK win32_error_file_func OF((voidpf opaque, voidpf stream));
+
+typedef struct
+{
+ HANDLE hf;
+ int error;
+} WIN32FILE_IOWIN;
+
+
+static void win32_translate_open_mode(int mode,
+ DWORD* lpdwDesiredAccess,
+ DWORD* lpdwCreationDisposition,
+ DWORD* lpdwShareMode,
+ DWORD* lpdwFlagsAndAttributes)
+{
+ *lpdwDesiredAccess = *lpdwShareMode = *lpdwFlagsAndAttributes = *lpdwCreationDisposition = 0;
+
+ if ((mode & ZLIB_FILEFUNC_MODE_READWRITEFILTER)==ZLIB_FILEFUNC_MODE_READ)
+ {
+ *lpdwDesiredAccess = GENERIC_READ;
+ *lpdwCreationDisposition = OPEN_EXISTING;
+ *lpdwShareMode = FILE_SHARE_READ;
+ }
+ else if (mode & ZLIB_FILEFUNC_MODE_EXISTING)
+ {
+ *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ;
+ *lpdwCreationDisposition = OPEN_EXISTING;
+ }
+ else if (mode & ZLIB_FILEFUNC_MODE_CREATE)
+ {
+ *lpdwDesiredAccess = GENERIC_WRITE | GENERIC_READ;
+ *lpdwCreationDisposition = CREATE_ALWAYS;
+ }
+}
+
+static voidpf win32_build_iowin(HANDLE hFile)
+{
+ voidpf ret=NULL;
+
+ if ((hFile != NULL) && (hFile != INVALID_HANDLE_VALUE))
+ {
+ WIN32FILE_IOWIN w32fiow;
+ w32fiow.hf = hFile;
+ w32fiow.error = 0;
+ ret = malloc(sizeof(WIN32FILE_IOWIN));
+
+ if (ret==NULL)
+ CloseHandle(hFile);
+ else
+ *((WIN32FILE_IOWIN*)ret) = w32fiow;
+ }
+ return ret;
+}
+
+voidpf ZCALLBACK win32_open64_file_func (voidpf opaque,const void* filename,int mode)
+{
+ const char* mode_fopen = NULL;
+ DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
+ HANDLE hFile = NULL;
+
+ win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
+
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
+
+ return win32_build_iowin(hFile);
+}
+
+
+voidpf ZCALLBACK win32_open64_file_funcA (voidpf opaque,const void* filename,int mode)
+{
+ const char* mode_fopen = NULL;
+ DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
+ HANDLE hFile = NULL;
+
+ win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
+
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ hFile = CreateFileA((LPCSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
+
+ return win32_build_iowin(hFile);
+}
+
+
+voidpf ZCALLBACK win32_open64_file_funcW (voidpf opaque,const void* filename,int mode)
+{
+ const char* mode_fopen = NULL;
+ DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
+ HANDLE hFile = NULL;
+
+ win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
+
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ hFile = CreateFileW((LPCWSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
+
+ return win32_build_iowin(hFile);
+}
+
+
+voidpf ZCALLBACK win32_open_file_func (voidpf opaque,const char* filename,int mode)
+{
+ const char* mode_fopen = NULL;
+ DWORD dwDesiredAccess,dwCreationDisposition,dwShareMode,dwFlagsAndAttributes ;
+ HANDLE hFile = NULL;
+
+ win32_translate_open_mode(mode,&dwDesiredAccess,&dwCreationDisposition,&dwShareMode,&dwFlagsAndAttributes);
+
+ if ((filename!=NULL) && (dwDesiredAccess != 0))
+ hFile = CreateFile((LPCTSTR)filename, dwDesiredAccess, dwShareMode, NULL, dwCreationDisposition, dwFlagsAndAttributes, NULL);
+
+ return win32_build_iowin(hFile);
+}
+
+
+uLong ZCALLBACK win32_read_file_func (voidpf opaque, voidpf stream, void* buf,uLong size)
+{
+ uLong ret=0;
+ HANDLE hFile = NULL;
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+
+ if (hFile != NULL)
+ {
+ if (!ReadFile(hFile, buf, size, &ret, NULL))
+ {
+ DWORD dwErr = GetLastError();
+ if (dwErr == ERROR_HANDLE_EOF)
+ dwErr = 0;
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ }
+ }
+
+ return ret;
+}
+
+
+uLong ZCALLBACK win32_write_file_func (voidpf opaque,voidpf stream,const void* buf,uLong size)
+{
+ uLong ret=0;
+ HANDLE hFile = NULL;
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+
+ if (hFile != NULL)
+ {
+ if (!WriteFile(hFile, buf, size, &ret, NULL))
+ {
+ DWORD dwErr = GetLastError();
+ if (dwErr == ERROR_HANDLE_EOF)
+ dwErr = 0;
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ }
+ }
+
+ return ret;
+}
+
+long ZCALLBACK win32_tell_file_func (voidpf opaque,voidpf stream)
+{
+ long ret=-1;
+ HANDLE hFile = NULL;
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+ if (hFile != NULL)
+ {
+ DWORD dwSet = SetFilePointer(hFile, 0, NULL, FILE_CURRENT);
+ if (dwSet == INVALID_SET_FILE_POINTER)
+ {
+ DWORD dwErr = GetLastError();
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ ret = -1;
+ }
+ else
+ ret=(long)dwSet;
+ }
+ return ret;
+}
+
+ZPOS64_T ZCALLBACK win32_tell64_file_func (voidpf opaque, voidpf stream)
+{
+ ZPOS64_T ret= (ZPOS64_T)-1;
+ HANDLE hFile = NULL;
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream)->hf;
+
+ if (hFile)
+ {
+ LARGE_INTEGER li;
+ li.QuadPart = 0;
+ li.u.LowPart = SetFilePointer(hFile, li.u.LowPart, &li.u.HighPart, FILE_CURRENT);
+ if ( (li.LowPart == 0xFFFFFFFF) && (GetLastError() != NO_ERROR))
+ {
+ DWORD dwErr = GetLastError();
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ ret = (ZPOS64_T)-1;
+ }
+ else
+ ret=li.QuadPart;
+ }
+ return ret;
+}
+
+
+long ZCALLBACK win32_seek_file_func (voidpf opaque,voidpf stream,uLong offset,int origin)
+{
+ DWORD dwMoveMethod=0xFFFFFFFF;
+ HANDLE hFile = NULL;
+
+ long ret=-1;
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ dwMoveMethod = FILE_CURRENT;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ dwMoveMethod = FILE_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ dwMoveMethod = FILE_BEGIN;
+ break;
+ default: return -1;
+ }
+
+ if (hFile != NULL)
+ {
+ DWORD dwSet = SetFilePointer(hFile, offset, NULL, dwMoveMethod);
+ if (dwSet == INVALID_SET_FILE_POINTER)
+ {
+ DWORD dwErr = GetLastError();
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ ret = -1;
+ }
+ else
+ ret=0;
+ }
+ return ret;
+}
+
+long ZCALLBACK win32_seek64_file_func (voidpf opaque, voidpf stream,ZPOS64_T offset,int origin)
+{
+ DWORD dwMoveMethod=0xFFFFFFFF;
+ HANDLE hFile = NULL;
+ long ret=-1;
+
+ if (stream!=NULL)
+ hFile = ((WIN32FILE_IOWIN*)stream)->hf;
+
+ switch (origin)
+ {
+ case ZLIB_FILEFUNC_SEEK_CUR :
+ dwMoveMethod = FILE_CURRENT;
+ break;
+ case ZLIB_FILEFUNC_SEEK_END :
+ dwMoveMethod = FILE_END;
+ break;
+ case ZLIB_FILEFUNC_SEEK_SET :
+ dwMoveMethod = FILE_BEGIN;
+ break;
+ default: return -1;
+ }
+
+ if (hFile)
+ {
+ LARGE_INTEGER* li = (LARGE_INTEGER*)&offset;
+ DWORD dwSet = SetFilePointer(hFile, li->u.LowPart, &li->u.HighPart, dwMoveMethod);
+ if (dwSet == INVALID_SET_FILE_POINTER)
+ {
+ DWORD dwErr = GetLastError();
+ ((WIN32FILE_IOWIN*)stream) -> error=(int)dwErr;
+ ret = -1;
+ }
+ else
+ ret=0;
+ }
+ return ret;
+}
+
+int ZCALLBACK win32_close_file_func (voidpf opaque, voidpf stream)
+{
+ int ret=-1;
+
+ if (stream!=NULL)
+ {
+ HANDLE hFile;
+ hFile = ((WIN32FILE_IOWIN*)stream) -> hf;
+ if (hFile != NULL)
+ {
+ CloseHandle(hFile);
+ ret=0;
+ }
+ free(stream);
+ }
+ return ret;
+}
+
+int ZCALLBACK win32_error_file_func (voidpf opaque,voidpf stream)
+{
+ int ret=-1;
+ if (stream!=NULL)
+ {
+ ret = ((WIN32FILE_IOWIN*)stream) -> error;
+ }
+ return ret;
+}
+
+void fill_win32_filefunc (zlib_filefunc_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen_file = win32_open_file_func;
+ pzlib_filefunc_def->zread_file = win32_read_file_func;
+ pzlib_filefunc_def->zwrite_file = win32_write_file_func;
+ pzlib_filefunc_def->ztell_file = win32_tell_file_func;
+ pzlib_filefunc_def->zseek_file = win32_seek_file_func;
+ pzlib_filefunc_def->zclose_file = win32_close_file_func;
+ pzlib_filefunc_def->zerror_file = win32_error_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
+
+void fill_win32_filefunc64(zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen64_file = win32_open64_file_func;
+ pzlib_filefunc_def->zread_file = win32_read_file_func;
+ pzlib_filefunc_def->zwrite_file = win32_write_file_func;
+ pzlib_filefunc_def->ztell64_file = win32_tell64_file_func;
+ pzlib_filefunc_def->zseek64_file = win32_seek64_file_func;
+ pzlib_filefunc_def->zclose_file = win32_close_file_func;
+ pzlib_filefunc_def->zerror_file = win32_error_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
+
+
+void fill_win32_filefunc64A(zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen64_file = win32_open64_file_funcA;
+ pzlib_filefunc_def->zread_file = win32_read_file_func;
+ pzlib_filefunc_def->zwrite_file = win32_write_file_func;
+ pzlib_filefunc_def->ztell64_file = win32_tell64_file_func;
+ pzlib_filefunc_def->zseek64_file = win32_seek64_file_func;
+ pzlib_filefunc_def->zclose_file = win32_close_file_func;
+ pzlib_filefunc_def->zerror_file = win32_error_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
+
+
+void fill_win32_filefunc64W(zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ pzlib_filefunc_def->zopen64_file = win32_open64_file_funcW;
+ pzlib_filefunc_def->zread_file = win32_read_file_func;
+ pzlib_filefunc_def->zwrite_file = win32_write_file_func;
+ pzlib_filefunc_def->ztell64_file = win32_tell64_file_func;
+ pzlib_filefunc_def->zseek64_file = win32_seek64_file_func;
+ pzlib_filefunc_def->zclose_file = win32_close_file_func;
+ pzlib_filefunc_def->zerror_file = win32_error_file_func;
+ pzlib_filefunc_def->opaque = NULL;
+}
diff --git a/plugins/BasicHistory/zip/iowin32.h b/plugins/BasicHistory/zip/iowin32.h
new file mode 100644
index 0000000000..0ca0969a7d
--- /dev/null
+++ b/plugins/BasicHistory/zip/iowin32.h
@@ -0,0 +1,28 @@
+/* iowin32.h -- IO base function header for compress/uncompress .zip
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+*/
+
+#include <windows.h>
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+void fill_win32_filefunc OF((zlib_filefunc_def* pzlib_filefunc_def));
+void fill_win32_filefunc64 OF((zlib_filefunc64_def* pzlib_filefunc_def));
+void fill_win32_filefunc64A OF((zlib_filefunc64_def* pzlib_filefunc_def));
+void fill_win32_filefunc64W OF((zlib_filefunc64_def* pzlib_filefunc_def));
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/plugins/BasicHistory/zip/miniunz.c b/plugins/BasicHistory/zip/miniunz.c
new file mode 100644
index 0000000000..9ed009fbd9
--- /dev/null
+++ b/plugins/BasicHistory/zip/miniunz.c
@@ -0,0 +1,648 @@
+/*
+ miniunz.c
+ Version 1.1, February 14h, 2010
+ sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications of Unzip for Zip64
+ Copyright (C) 2007-2008 Even Rouault
+
+ Modifications for Zip64 support on both zip and unzip
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+*/
+
+#ifndef _WIN32
+ #ifndef __USE_FILE_OFFSET64
+ #define __USE_FILE_OFFSET64
+ #endif
+ #ifndef __USE_LARGEFILE64
+ #define __USE_LARGEFILE64
+ #endif
+ #ifndef _LARGEFILE64_SOURCE
+ #define _LARGEFILE64_SOURCE
+ #endif
+ #ifndef _FILE_OFFSET_BIT
+ #define _FILE_OFFSET_BIT 64
+ #endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef unix
+# include <unistd.h>
+# include <utime.h>
+#else
+# include <direct.h>
+# include <io.h>
+#endif
+
+#include "unzip.h"
+
+#define CASESENSITIVITY (0)
+#define WRITEBUFFERSIZE (8192)
+#define MAXFILENAME (256)
+
+#ifdef _WIN32
+#define USEWIN32IOAPI
+#include "iowin32.h"
+#endif
+/*
+ mini unzip, demo of unzip package
+
+ usage :
+ Usage : miniunz [-exvlo] file.zip [file_to_extract] [-d extractdir]
+
+ list the file in the zipfile, and print the content of FILE_ID.ZIP or README.TXT
+ if it exists
+*/
+
+
+/* change_file_date : change the date/time of a file
+ filename : the filename of the file where date/time must be modified
+ dosdate : the new date at the MSDos format (4 bytes)
+ tmu_date : the SAME new date at the tm_unz format */
+void change_file_date(filename,dosdate,tmu_date)
+ const char *filename;
+ uLong dosdate;
+ tm_unz tmu_date;
+{
+#ifdef _WIN32
+ HANDLE hFile;
+ FILETIME ftm,ftLocal,ftCreate,ftLastAcc,ftLastWrite;
+
+ hFile = CreateFileA(filename,GENERIC_READ | GENERIC_WRITE,
+ 0,NULL,OPEN_EXISTING,0,NULL);
+ GetFileTime(hFile,&ftCreate,&ftLastAcc,&ftLastWrite);
+ DosDateTimeToFileTime((WORD)(dosdate>>16),(WORD)dosdate,&ftLocal);
+ LocalFileTimeToFileTime(&ftLocal,&ftm);
+ SetFileTime(hFile,&ftm,&ftLastAcc,&ftm);
+ CloseHandle(hFile);
+#else
+#ifdef unix
+ struct utimbuf ut;
+ struct tm newdate;
+ newdate.tm_sec = tmu_date.tm_sec;
+ newdate.tm_min=tmu_date.tm_min;
+ newdate.tm_hour=tmu_date.tm_hour;
+ newdate.tm_mday=tmu_date.tm_mday;
+ newdate.tm_mon=tmu_date.tm_mon;
+ if (tmu_date.tm_year > 1900)
+ newdate.tm_year=tmu_date.tm_year - 1900;
+ else
+ newdate.tm_year=tmu_date.tm_year ;
+ newdate.tm_isdst=-1;
+
+ ut.actime=ut.modtime=mktime(&newdate);
+ utime(filename,&ut);
+#endif
+#endif
+}
+
+
+/* mymkdir and change_file_date are not 100 % portable
+ As I don't know well Unix, I wait feedback for the unix portion */
+
+int mymkdir(dirname)
+ const char* dirname;
+{
+ int ret=0;
+#ifdef _WIN32
+ ret = _mkdir(dirname);
+#else
+#ifdef unix
+ ret = mkdir (dirname,0775);
+#endif
+#endif
+ return ret;
+}
+
+int makedir (newdir)
+ char *newdir;
+{
+ char *buffer ;
+ char *p;
+ int len = (int)strlen(newdir);
+
+ if (len <= 0)
+ return 0;
+
+ buffer = (char*)malloc(len+1);
+ if (buffer==NULL)
+ {
+ printf("Error allocating memory\n");
+ return UNZ_INTERNALERROR;
+ }
+ strcpy(buffer,newdir);
+
+ if (buffer[len-1] == '/') {
+ buffer[len-1] = '\0';
+ }
+ if (mymkdir(buffer) == 0)
+ {
+ free(buffer);
+ return 1;
+ }
+
+ p = buffer+1;
+ while (1)
+ {
+ char hold;
+
+ while(*p && *p != '\\' && *p != '/')
+ p++;
+ hold = *p;
+ *p = 0;
+ if ((mymkdir(buffer) == -1) && (errno == ENOENT))
+ {
+ printf("couldn't create directory %s\n",buffer);
+ free(buffer);
+ return 0;
+ }
+ if (hold == 0)
+ break;
+ *p++ = hold;
+ }
+ free(buffer);
+ return 1;
+}
+
+void do_banner()
+{
+ printf("MiniUnz 1.01b, demo of zLib + Unz package written by Gilles Vollant\n");
+ printf("more info at http://www.winimage.com/zLibDll/unzip.html\n\n");
+}
+
+void do_help()
+{
+ printf("Usage : miniunz [-e] [-x] [-v] [-l] [-o] [-p password] file.zip [file_to_extr.] [-d extractdir]\n\n" \
+ " -e Extract without pathname (junk paths)\n" \
+ " -x Extract with pathname\n" \
+ " -v list files\n" \
+ " -l list files\n" \
+ " -d directory to extract into\n" \
+ " -o overwrite files without prompting\n" \
+ " -p extract crypted file using password\n\n");
+}
+
+void Display64BitsSize(ZPOS64_T n, int size_char)
+{
+ /* to avoid compatibility problem , we do here the conversion */
+ char number[21];
+ int offset=19;
+ int pos_string = 19;
+ number[20]=0;
+ for (;;) {
+ number[offset]=(char)((n%10)+'0');
+ if (number[offset] != '0')
+ pos_string=offset;
+ n/=10;
+ if (offset==0)
+ break;
+ offset--;
+ }
+ {
+ int size_display_string = 19-pos_string;
+ while (size_char > size_display_string)
+ {
+ size_char--;
+ printf(" ");
+ }
+ }
+
+ printf("%s",&number[pos_string]);
+}
+
+int do_list(uf)
+ unzFile uf;
+{
+ uLong i;
+ unz_global_info64 gi;
+ int err;
+
+ err = unzGetGlobalInfo64(uf,&gi);
+ if (err!=UNZ_OK)
+ printf("error %d with zipfile in unzGetGlobalInfo \n",err);
+ printf(" Length Method Size Ratio Date Time CRC-32 Name\n");
+ printf(" ------ ------ ---- ----- ---- ---- ------ ----\n");
+ for (i=0;i<gi.number_entry;i++)
+ {
+ char filename_inzip[256];
+ unz_file_info64 file_info;
+ uLong ratio=0;
+ const char *string_method;
+ char charCrypt=' ';
+ err = unzGetCurrentFileInfo64(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
+ break;
+ }
+ if (file_info.uncompressed_size>0)
+ ratio = (uLong)((file_info.compressed_size*100)/file_info.uncompressed_size);
+
+ /* display a '*' if the file is crypted */
+ if ((file_info.flag & 1) != 0)
+ charCrypt='*';
+
+ if (file_info.compression_method==0)
+ string_method="Stored";
+ else
+ if (file_info.compression_method==Z_DEFLATED)
+ {
+ uInt iLevel=(uInt)((file_info.flag & 0x6)/2);
+ if (iLevel==0)
+ string_method="Defl:N";
+ else if (iLevel==1)
+ string_method="Defl:X";
+ else if ((iLevel==2) || (iLevel==3))
+ string_method="Defl:F"; /* 2:fast , 3 : extra fast*/
+ }
+ else
+ if (file_info.compression_method==Z_BZIP2ED)
+ {
+ string_method="BZip2 ";
+ }
+ else
+ string_method="Unkn. ";
+
+ Display64BitsSize(file_info.uncompressed_size,7);
+ printf(" %6s%c",string_method,charCrypt);
+ Display64BitsSize(file_info.compressed_size,7);
+ printf(" %3lu%% %2.2lu-%2.2lu-%2.2lu %2.2lu:%2.2lu %8.8lx %s\n",
+ ratio,
+ (uLong)file_info.tmu_date.tm_mon + 1,
+ (uLong)file_info.tmu_date.tm_mday,
+ (uLong)file_info.tmu_date.tm_year % 100,
+ (uLong)file_info.tmu_date.tm_hour,(uLong)file_info.tmu_date.tm_min,
+ (uLong)file_info.crc,filename_inzip);
+ if ((i+1)<gi.number_entry)
+ {
+ err = unzGoToNextFile(uf);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzGoToNextFile\n",err);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+int do_extract_currentfile(uf,popt_extract_without_path,popt_overwrite,password)
+ unzFile uf;
+ const int* popt_extract_without_path;
+ int* popt_overwrite;
+ const char* password;
+{
+ char filename_inzip[256];
+ char* filename_withoutpath;
+ char* p;
+ int err=UNZ_OK;
+ FILE *fout=NULL;
+ void* buf;
+ uInt size_buf;
+
+ unz_file_info64 file_info;
+ uLong ratio=0;
+ err = unzGetCurrentFileInfo64(uf,&file_info,filename_inzip,sizeof(filename_inzip),NULL,0,NULL,0);
+
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzGetCurrentFileInfo\n",err);
+ return err;
+ }
+
+ size_buf = WRITEBUFFERSIZE;
+ buf = (void*)malloc(size_buf);
+ if (buf==NULL)
+ {
+ printf("Error allocating memory\n");
+ return UNZ_INTERNALERROR;
+ }
+
+ p = filename_withoutpath = filename_inzip;
+ while ((*p) != '\0')
+ {
+ if (((*p)=='/') || ((*p)=='\\'))
+ filename_withoutpath = p+1;
+ p++;
+ }
+
+ if ((*filename_withoutpath)=='\0')
+ {
+ if ((*popt_extract_without_path)==0)
+ {
+ printf("creating directory: %s\n",filename_inzip);
+ mymkdir(filename_inzip);
+ }
+ }
+ else
+ {
+ const char* write_filename;
+ int skip=0;
+
+ if ((*popt_extract_without_path)==0)
+ write_filename = filename_inzip;
+ else
+ write_filename = filename_withoutpath;
+
+ err = unzOpenCurrentFilePassword(uf,password);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzOpenCurrentFilePassword\n",err);
+ }
+
+ if (((*popt_overwrite)==0) && (err==UNZ_OK))
+ {
+ char rep=0;
+ FILE* ftestexist;
+ ftestexist = fopen64(write_filename,"rb");
+ if (ftestexist!=NULL)
+ {
+ fclose(ftestexist);
+ do
+ {
+ char answer[128];
+ int ret;
+
+ printf("The file %s exists. Overwrite ? [y]es, [n]o, [A]ll: ",write_filename);
+ ret = scanf("%1s",answer);
+ if (ret != 1)
+ {
+ exit(EXIT_FAILURE);
+ }
+ rep = answer[0] ;
+ if ((rep>='a') && (rep<='z'))
+ rep -= 0x20;
+ }
+ while ((rep!='Y') && (rep!='N') && (rep!='A'));
+ }
+
+ if (rep == 'N')
+ skip = 1;
+
+ if (rep == 'A')
+ *popt_overwrite=1;
+ }
+
+ if ((skip==0) && (err==UNZ_OK))
+ {
+ fout=fopen64(write_filename,"wb");
+
+ /* some zipfile don't contain directory alone before file */
+ if ((fout==NULL) && ((*popt_extract_without_path)==0) &&
+ (filename_withoutpath!=(char*)filename_inzip))
+ {
+ char c=*(filename_withoutpath-1);
+ *(filename_withoutpath-1)='\0';
+ makedir(write_filename);
+ *(filename_withoutpath-1)=c;
+ fout=fopen64(write_filename,"wb");
+ }
+
+ if (fout==NULL)
+ {
+ printf("error opening %s\n",write_filename);
+ }
+ }
+
+ if (fout!=NULL)
+ {
+ printf(" extracting: %s\n",write_filename);
+
+ do
+ {
+ err = unzReadCurrentFile(uf,buf,size_buf);
+ if (err<0)
+ {
+ printf("error %d with zipfile in unzReadCurrentFile\n",err);
+ break;
+ }
+ if (err>0)
+ if (fwrite(buf,err,1,fout)!=1)
+ {
+ printf("error in writing extracted file\n");
+ err=UNZ_ERRNO;
+ break;
+ }
+ }
+ while (err>0);
+ if (fout)
+ fclose(fout);
+
+ if (err==0)
+ change_file_date(write_filename,file_info.dosDate,
+ file_info.tmu_date);
+ }
+
+ if (err==UNZ_OK)
+ {
+ err = unzCloseCurrentFile (uf);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzCloseCurrentFile\n",err);
+ }
+ }
+ else
+ unzCloseCurrentFile(uf); /* don't lose the error */
+ }
+
+ free(buf);
+ return err;
+}
+
+
+int do_extract(uf,opt_extract_without_path,opt_overwrite,password)
+ unzFile uf;
+ int opt_extract_without_path;
+ int opt_overwrite;
+ const char* password;
+{
+ uLong i;
+ unz_global_info64 gi;
+ int err;
+ FILE* fout=NULL;
+
+ err = unzGetGlobalInfo64(uf,&gi);
+ if (err!=UNZ_OK)
+ printf("error %d with zipfile in unzGetGlobalInfo \n",err);
+
+ for (i=0;i<gi.number_entry;i++)
+ {
+ if (do_extract_currentfile(uf,&opt_extract_without_path,
+ &opt_overwrite,
+ password) != UNZ_OK)
+ break;
+
+ if ((i+1)<gi.number_entry)
+ {
+ err = unzGoToNextFile(uf);
+ if (err!=UNZ_OK)
+ {
+ printf("error %d with zipfile in unzGoToNextFile\n",err);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+int do_extract_onefile(uf,filename,opt_extract_without_path,opt_overwrite,password)
+ unzFile uf;
+ const char* filename;
+ int opt_extract_without_path;
+ int opt_overwrite;
+ const char* password;
+{
+ int err = UNZ_OK;
+ if (unzLocateFile(uf,filename,CASESENSITIVITY)!=UNZ_OK)
+ {
+ printf("file %s not found in the zipfile\n",filename);
+ return 2;
+ }
+
+ if (do_extract_currentfile(uf,&opt_extract_without_path,
+ &opt_overwrite,
+ password) == UNZ_OK)
+ return 0;
+ else
+ return 1;
+}
+
+
+int main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ const char *zipfilename=NULL;
+ const char *filename_to_extract=NULL;
+ const char *password=NULL;
+ char filename_try[MAXFILENAME+16] = "";
+ int i;
+ int ret_value=0;
+ int opt_do_list=0;
+ int opt_do_extract=1;
+ int opt_do_extract_withoutpath=0;
+ int opt_overwrite=0;
+ int opt_extractdir=0;
+ const char *dirname=NULL;
+ unzFile uf=NULL;
+
+ do_banner();
+ if (argc==1)
+ {
+ do_help();
+ return 0;
+ }
+ else
+ {
+ for (i=1;i<argc;i++)
+ {
+ if ((*argv[i])=='-')
+ {
+ const char *p=argv[i]+1;
+
+ while ((*p)!='\0')
+ {
+ char c=*(p++);;
+ if ((c=='l') || (c=='L'))
+ opt_do_list = 1;
+ if ((c=='v') || (c=='V'))
+ opt_do_list = 1;
+ if ((c=='x') || (c=='X'))
+ opt_do_extract = 1;
+ if ((c=='e') || (c=='E'))
+ opt_do_extract = opt_do_extract_withoutpath = 1;
+ if ((c=='o') || (c=='O'))
+ opt_overwrite=1;
+ if ((c=='d') || (c=='D'))
+ {
+ opt_extractdir=1;
+ dirname=argv[i+1];
+ }
+
+ if (((c=='p') || (c=='P')) && (i+1<argc))
+ {
+ password=argv[i+1];
+ i++;
+ }
+ }
+ }
+ else
+ {
+ if (zipfilename == NULL)
+ zipfilename = argv[i];
+ else if ((filename_to_extract==NULL) && (!opt_extractdir))
+ filename_to_extract = argv[i] ;
+ }
+ }
+ }
+
+ if (zipfilename!=NULL)
+ {
+
+# ifdef USEWIN32IOAPI
+ zlib_filefunc64_def ffunc;
+# endif
+
+ strncpy(filename_try, zipfilename,MAXFILENAME-1);
+ /* strncpy doesnt append the trailing NULL, of the string is too long. */
+ filename_try[ MAXFILENAME ] = '\0';
+
+# ifdef USEWIN32IOAPI
+ fill_win32_filefunc64A(&ffunc);
+ uf = unzOpen2_64(zipfilename,&ffunc);
+# else
+ uf = unzOpen64(zipfilename);
+# endif
+ if (uf==NULL)
+ {
+ strcat(filename_try,".zip");
+# ifdef USEWIN32IOAPI
+ uf = unzOpen2_64(filename_try,&ffunc);
+# else
+ uf = unzOpen64(filename_try);
+# endif
+ }
+ }
+
+ if (uf==NULL)
+ {
+ printf("Cannot open %s or %s.zip\n",zipfilename,zipfilename);
+ return 1;
+ }
+ printf("%s opened\n",filename_try);
+
+ if (opt_do_list==1)
+ ret_value = do_list(uf);
+ else if (opt_do_extract==1)
+ {
+#ifdef _WIN32
+ if (opt_extractdir && _chdir(dirname))
+#else
+ if (opt_extractdir && chdir(dirname))
+#endif
+ {
+ printf("Error changing into %s, aborting\n", dirname);
+ exit(-1);
+ }
+
+ if (filename_to_extract == NULL)
+ ret_value = do_extract(uf, opt_do_extract_withoutpath, opt_overwrite, password);
+ else
+ ret_value = do_extract_onefile(uf, filename_to_extract, opt_do_extract_withoutpath, opt_overwrite, password);
+ }
+
+ unzClose(uf);
+
+ return ret_value;
+}
diff --git a/plugins/BasicHistory/zip/minizip.c b/plugins/BasicHistory/zip/minizip.c
new file mode 100644
index 0000000000..7a4fa5a643
--- /dev/null
+++ b/plugins/BasicHistory/zip/minizip.c
@@ -0,0 +1,507 @@
+/*
+ minizip.c
+ Version 1.1, February 14h, 2010
+ sample part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications of Unzip for Zip64
+ Copyright (C) 2007-2008 Even Rouault
+
+ Modifications for Zip64 support on both zip and unzip
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+*/
+
+
+#ifndef _WIN32
+ #ifndef __USE_FILE_OFFSET64
+ #define __USE_FILE_OFFSET64
+ #endif
+ #ifndef __USE_LARGEFILE64
+ #define __USE_LARGEFILE64
+ #endif
+ #ifndef _LARGEFILE64_SOURCE
+ #define _LARGEFILE64_SOURCE
+ #endif
+ #ifndef _FILE_OFFSET_BIT
+ #define _FILE_OFFSET_BIT 64
+ #endif
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#ifdef unix
+# include <unistd.h>
+# include <utime.h>
+# include <sys/types.h>
+# include <sys/stat.h>
+#else
+# include <direct.h>
+# include <io.h>
+#endif
+
+#include "zip.h"
+
+#ifdef _WIN32
+ #define USEWIN32IOAPI
+ #include "iowin32.h"
+#endif
+
+
+
+#define WRITEBUFFERSIZE (16384)
+#define MAXFILENAME (256)
+
+#ifdef _WIN32
+uLong filetime(f, tmzip, dt)
+ char *f; /* name of file to get info on */
+ tm_zip *tmzip; /* return value: access, modific. and creation times */
+ uLong *dt; /* dostime */
+{
+ int ret = 0;
+ {
+ FILETIME ftLocal;
+ HANDLE hFind;
+ WIN32_FIND_DATAA ff32;
+
+ hFind = FindFirstFileA(f,&ff32);
+ if (hFind != INVALID_HANDLE_VALUE)
+ {
+ FileTimeToLocalFileTime(&(ff32.ftLastWriteTime),&ftLocal);
+ FileTimeToDosDateTime(&ftLocal,((LPWORD)dt)+1,((LPWORD)dt)+0);
+ FindClose(hFind);
+ ret = 1;
+ }
+ }
+ return ret;
+}
+#else
+#ifdef unix
+uLong filetime(f, tmzip, dt)
+ char *f; /* name of file to get info on */
+ tm_zip *tmzip; /* return value: access, modific. and creation times */
+ uLong *dt; /* dostime */
+{
+ int ret=0;
+ struct stat s; /* results of stat() */
+ struct tm* filedate;
+ time_t tm_t=0;
+
+ if (strcmp(f,"-")!=0)
+ {
+ char name[MAXFILENAME+1];
+ int len = strlen(f);
+ if (len > MAXFILENAME)
+ len = MAXFILENAME;
+
+ strncpy(name, f,MAXFILENAME-1);
+ /* strncpy doesnt append the trailing NULL, of the string is too long. */
+ name[ MAXFILENAME ] = '\0';
+
+ if (name[len - 1] == '/')
+ name[len - 1] = '\0';
+ /* not all systems allow stat'ing a file with / appended */
+ if (stat(name,&s)==0)
+ {
+ tm_t = s.st_mtime;
+ ret = 1;
+ }
+ }
+ filedate = localtime(&tm_t);
+
+ tmzip->tm_sec = filedate->tm_sec;
+ tmzip->tm_min = filedate->tm_min;
+ tmzip->tm_hour = filedate->tm_hour;
+ tmzip->tm_mday = filedate->tm_mday;
+ tmzip->tm_mon = filedate->tm_mon ;
+ tmzip->tm_year = filedate->tm_year;
+
+ return ret;
+}
+#else
+uLong filetime(f, tmzip, dt)
+ char *f; /* name of file to get info on */
+ tm_zip *tmzip; /* return value: access, modific. and creation times */
+ uLong *dt; /* dostime */
+{
+ return 0;
+}
+#endif
+#endif
+
+
+
+
+int check_exist_file(filename)
+ const char* filename;
+{
+ FILE* ftestexist;
+ int ret = 1;
+ ftestexist = fopen64(filename,"rb");
+ if (ftestexist==NULL)
+ ret = 0;
+ else
+ fclose(ftestexist);
+ return ret;
+}
+
+void do_banner()
+{
+ printf("MiniZip 1.1, demo of zLib + MiniZip64 package, written by Gilles Vollant\n");
+ printf("more info on MiniZip at http://www.winimage.com/zLibDll/minizip.html\n\n");
+}
+
+void do_help()
+{
+ printf("Usage : minizip [-o] [-a] [-0 to -9] [-p password] [-j] file.zip [files_to_add]\n\n" \
+ " -o Overwrite existing file.zip\n" \
+ " -a Append to existing file.zip\n" \
+ " -0 Store only\n" \
+ " -1 Compress faster\n" \
+ " -9 Compress better\n\n" \
+ " -j exclude path. store only the file name.\n\n");
+}
+
+/* calculate the CRC32 of a file,
+ because to encrypt a file, we need known the CRC32 of the file before */
+int getFileCrc(const char* filenameinzip,void*buf,unsigned long size_buf,unsigned long* result_crc)
+{
+ unsigned long calculate_crc=0;
+ int err=ZIP_OK;
+ FILE * fin = fopen64(filenameinzip,"rb");
+ unsigned long size_read = 0;
+ unsigned long total_read = 0;
+ if (fin==NULL)
+ {
+ err = ZIP_ERRNO;
+ }
+
+ if (err == ZIP_OK)
+ do
+ {
+ err = ZIP_OK;
+ size_read = (int)fread(buf,1,size_buf,fin);
+ if (size_read < size_buf)
+ if (feof(fin)==0)
+ {
+ printf("error in reading %s\n",filenameinzip);
+ err = ZIP_ERRNO;
+ }
+
+ if (size_read>0)
+ calculate_crc = crc32(calculate_crc,buf,size_read);
+ total_read += size_read;
+
+ } while ((err == ZIP_OK) && (size_read>0));
+
+ if (fin)
+ fclose(fin);
+
+ *result_crc=calculate_crc;
+ printf("file %s crc %lx\n", filenameinzip, calculate_crc);
+ return err;
+}
+
+int isLargeFile(const char* filename)
+{
+ int largeFile = 0;
+ ZPOS64_T pos = 0;
+ FILE* pFile = fopen64(filename, "rb");
+
+ if(pFile != NULL)
+ {
+ int n = fseeko64(pFile, 0, SEEK_END);
+
+ pos = ftello64(pFile);
+
+ printf("File : %s is %lld bytes\n", filename, pos);
+
+ if(pos >= 0xffffffff)
+ largeFile = 1;
+
+ fclose(pFile);
+ }
+
+ return largeFile;
+}
+
+int main(argc,argv)
+ int argc;
+ char *argv[];
+{
+ int i;
+ int opt_overwrite=0;
+ int opt_compress_level=Z_DEFAULT_COMPRESSION;
+ int opt_exclude_path=0;
+ int zipfilenamearg = 0;
+ char filename_try[MAXFILENAME+16];
+ int zipok;
+ int err=0;
+ int size_buf=0;
+ void* buf=NULL;
+ const char* password=NULL;
+
+
+ do_banner();
+ if (argc==1)
+ {
+ do_help();
+ return 0;
+ }
+ else
+ {
+ for (i=1;i<argc;i++)
+ {
+ if ((*argv[i])=='-')
+ {
+ const char *p=argv[i]+1;
+
+ while ((*p)!='\0')
+ {
+ char c=*(p++);;
+ if ((c=='o') || (c=='O'))
+ opt_overwrite = 1;
+ if ((c=='a') || (c=='A'))
+ opt_overwrite = 2;
+ if ((c>='0') && (c<='9'))
+ opt_compress_level = c-'0';
+ if ((c=='j') || (c=='J'))
+ opt_exclude_path = 1;
+
+ if (((c=='p') || (c=='P')) && (i+1<argc))
+ {
+ password=argv[i+1];
+ i++;
+ }
+ }
+ }
+ else
+ {
+ if (zipfilenamearg == 0)
+ {
+ zipfilenamearg = i ;
+ }
+ }
+ }
+ }
+
+ size_buf = WRITEBUFFERSIZE;
+ buf = (void*)malloc(size_buf);
+ if (buf==NULL)
+ {
+ printf("Error allocating memory\n");
+ return ZIP_INTERNALERROR;
+ }
+
+ if (zipfilenamearg==0)
+ {
+ zipok=0;
+ }
+ else
+ {
+ int i,len;
+ int dot_found=0;
+
+ zipok = 1 ;
+ strncpy(filename_try, argv[zipfilenamearg],MAXFILENAME-1);
+ /* strncpy doesnt append the trailing NULL, of the string is too long. */
+ filename_try[ MAXFILENAME ] = '\0';
+
+ len=(int)strlen(filename_try);
+ for (i=0;i<len;i++)
+ if (filename_try[i]=='.')
+ dot_found=1;
+
+ if (dot_found==0)
+ strcat(filename_try,".zip");
+
+ if (opt_overwrite==2)
+ {
+ /* if the file don't exist, we not append file */
+ if (check_exist_file(filename_try)==0)
+ opt_overwrite=1;
+ }
+ else
+ if (opt_overwrite==0)
+ if (check_exist_file(filename_try)!=0)
+ {
+ char rep=0;
+ do
+ {
+ char answer[128];
+ int ret;
+ printf("The file %s exists. Overwrite ? [y]es, [n]o, [a]ppend : ",filename_try);
+ ret = scanf("%1s",answer);
+ if (ret != 1)
+ {
+ exit(EXIT_FAILURE);
+ }
+ rep = answer[0] ;
+ if ((rep>='a') && (rep<='z'))
+ rep -= 0x20;
+ }
+ while ((rep!='Y') && (rep!='N') && (rep!='A'));
+ if (rep=='N')
+ zipok = 0;
+ if (rep=='A')
+ opt_overwrite = 2;
+ }
+ }
+
+ if (zipok==1)
+ {
+ zipFile zf;
+ int errclose;
+# ifdef USEWIN32IOAPI
+ zlib_filefunc64_def ffunc;
+ fill_win32_filefunc64A(&ffunc);
+ zf = zipOpen2_64(filename_try,(opt_overwrite==2) ? 2 : 0,NULL,&ffunc);
+# else
+ zf = zipOpen64(filename_try,(opt_overwrite==2) ? 2 : 0);
+# endif
+
+ if (zf == NULL)
+ {
+ printf("error opening %s\n",filename_try);
+ err= ZIP_ERRNO;
+ }
+ else
+ printf("creating %s\n",filename_try);
+
+ for (i=zipfilenamearg+1;(i<argc) && (err==ZIP_OK);i++)
+ {
+ if (!((((*(argv[i]))=='-') || ((*(argv[i]))=='/')) &&
+ ((argv[i][1]=='o') || (argv[i][1]=='O') ||
+ (argv[i][1]=='a') || (argv[i][1]=='A') ||
+ (argv[i][1]=='p') || (argv[i][1]=='P') ||
+ ((argv[i][1]>='0') || (argv[i][1]<='9'))) &&
+ (strlen(argv[i]) == 2)))
+ {
+ FILE * fin;
+ int size_read;
+ const char* filenameinzip = argv[i];
+ const char *savefilenameinzip;
+ zip_fileinfo zi;
+ unsigned long crcFile=0;
+ int zip64 = 0;
+
+ zi.tmz_date.tm_sec = zi.tmz_date.tm_min = zi.tmz_date.tm_hour =
+ zi.tmz_date.tm_mday = zi.tmz_date.tm_mon = zi.tmz_date.tm_year = 0;
+ zi.dosDate = 0;
+ zi.internal_fa = 0;
+ zi.external_fa = 0;
+ filetime(filenameinzip,&zi.tmz_date,&zi.dosDate);
+
+/*
+ err = zipOpenNewFileInZip(zf,filenameinzip,&zi,
+ NULL,0,NULL,0,NULL / * comment * /,
+ (opt_compress_level != 0) ? Z_DEFLATED : 0,
+ opt_compress_level);
+*/
+ if ((password != NULL) && (err==ZIP_OK))
+ err = getFileCrc(filenameinzip,buf,size_buf,&crcFile);
+
+ zip64 = isLargeFile(filenameinzip);
+
+ /* The path name saved, should not include a leading slash. */
+ /*if it did, windows/xp and dynazip couldn't read the zip file. */
+ savefilenameinzip = filenameinzip;
+ while( savefilenameinzip[0] == '\\' || savefilenameinzip[0] == '/' )
+ {
+ savefilenameinzip++;
+ }
+
+ /*should the zip file contain any path at all?*/
+ if( opt_exclude_path )
+ {
+ const char *tmpptr;
+ const char *lastslash = 0;
+ for( tmpptr = savefilenameinzip; *tmpptr; tmpptr++)
+ {
+ if( *tmpptr == '\\' || *tmpptr == '/')
+ {
+ lastslash = tmpptr;
+ }
+ }
+ if( lastslash != NULL )
+ {
+ savefilenameinzip = lastslash+1; // base filename follows last slash.
+ }
+ }
+
+ /**/
+ err = zipOpenNewFileInZip3_64(zf,savefilenameinzip,&zi,
+ NULL,0,NULL,0,NULL /* comment*/,
+ (opt_compress_level != 0) ? Z_DEFLATED : 0,
+ opt_compress_level,0,
+ /* -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY, */
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ password,crcFile, zip64);
+
+ if (err != ZIP_OK)
+ printf("error in opening %s in zipfile\n",filenameinzip);
+ else
+ {
+ fin = fopen64(filenameinzip,"rb");
+ if (fin==NULL)
+ {
+ err=ZIP_ERRNO;
+ printf("error in opening %s for reading\n",filenameinzip);
+ }
+ }
+
+ if (err == ZIP_OK)
+ do
+ {
+ err = ZIP_OK;
+ size_read = (int)fread(buf,1,size_buf,fin);
+ if (size_read < size_buf)
+ if (feof(fin)==0)
+ {
+ printf("error in reading %s\n",filenameinzip);
+ err = ZIP_ERRNO;
+ }
+
+ if (size_read>0)
+ {
+ err = zipWriteInFileInZip (zf,buf,size_read);
+ if (err<0)
+ {
+ printf("error in writing %s in the zipfile\n",
+ filenameinzip);
+ }
+
+ }
+ } while ((err == ZIP_OK) && (size_read>0));
+
+ if (fin)
+ fclose(fin);
+
+ if (err<0)
+ err=ZIP_ERRNO;
+ else
+ {
+ err = zipCloseFileInZip(zf);
+ if (err!=ZIP_OK)
+ printf("error in closing %s in the zipfile\n",
+ filenameinzip);
+ }
+ }
+ }
+ errclose = zipClose(zf,NULL);
+ if (errclose != ZIP_OK)
+ printf("error in closing %s\n",filename_try);
+ }
+ else
+ {
+ do_help();
+ }
+
+ free(buf);
+ return 0;
+}
diff --git a/plugins/BasicHistory/zip/mztools.c b/plugins/BasicHistory/zip/mztools.c
new file mode 100644
index 0000000000..f9092e65ae
--- /dev/null
+++ b/plugins/BasicHistory/zip/mztools.c
@@ -0,0 +1,281 @@
+/*
+ Additional tools for Minizip
+ Code: Xavier Roche '2004
+ License: Same as ZLIB (www.gzip.org)
+*/
+
+/* Code */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "zlib.h"
+#include "unzip.h"
+
+#define READ_8(adr) ((unsigned char)*(adr))
+#define READ_16(adr) ( READ_8(adr) | (READ_8(adr+1) << 8) )
+#define READ_32(adr) ( READ_16(adr) | (READ_16((adr)+2) << 16) )
+
+#define WRITE_8(buff, n) do { \
+ *((unsigned char*)(buff)) = (unsigned char) ((n) & 0xff); \
+} while(0)
+#define WRITE_16(buff, n) do { \
+ WRITE_8((unsigned char*)(buff), n); \
+ WRITE_8(((unsigned char*)(buff)) + 1, (n) >> 8); \
+} while(0)
+#define WRITE_32(buff, n) do { \
+ WRITE_16((unsigned char*)(buff), (n) & 0xffff); \
+ WRITE_16((unsigned char*)(buff) + 2, (n) >> 16); \
+} while(0)
+
+extern int ZEXPORT unzRepair(file, fileOut, fileOutTmp, nRecovered, bytesRecovered)
+const char* file;
+const char* fileOut;
+const char* fileOutTmp;
+uLong* nRecovered;
+uLong* bytesRecovered;
+{
+ int err = Z_OK;
+ FILE* fpZip = fopen(file, "rb");
+ FILE* fpOut = fopen(fileOut, "wb");
+ FILE* fpOutCD = fopen(fileOutTmp, "wb");
+ if (fpZip != NULL && fpOut != NULL) {
+ int entries = 0;
+ uLong totalBytes = 0;
+ char header[30];
+ char filename[256];
+ char extra[1024];
+ int offset = 0;
+ int offsetCD = 0;
+ while ( fread(header, 1, 30, fpZip) == 30 ) {
+ int currentOffset = offset;
+
+ /* File entry */
+ if (READ_32(header) == 0x04034b50) {
+ unsigned int version = READ_16(header + 4);
+ unsigned int gpflag = READ_16(header + 6);
+ unsigned int method = READ_16(header + 8);
+ unsigned int filetime = READ_16(header + 10);
+ unsigned int filedate = READ_16(header + 12);
+ unsigned int crc = READ_32(header + 14); /* crc */
+ unsigned int cpsize = READ_32(header + 18); /* compressed size */
+ unsigned int uncpsize = READ_32(header + 22); /* uncompressed sz */
+ unsigned int fnsize = READ_16(header + 26); /* file name length */
+ unsigned int extsize = READ_16(header + 28); /* extra field length */
+ filename[0] = extra[0] = '\0';
+
+ /* Header */
+ if (fwrite(header, 1, 30, fpOut) == 30) {
+ offset += 30;
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+
+ /* Filename */
+ if (fnsize > 0) {
+ if (fread(filename, 1, fnsize, fpZip) == fnsize) {
+ if (fwrite(filename, 1, fnsize, fpOut) == fnsize) {
+ offset += fnsize;
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ } else {
+ err = Z_STREAM_ERROR;
+ break;
+ }
+
+ /* Extra field */
+ if (extsize > 0) {
+ if (fread(extra, 1, extsize, fpZip) == extsize) {
+ if (fwrite(extra, 1, extsize, fpOut) == extsize) {
+ offset += extsize;
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ }
+
+ /* Data */
+ {
+ int dataSize = cpsize;
+ if (dataSize == 0) {
+ dataSize = uncpsize;
+ }
+ if (dataSize > 0) {
+ char* data = malloc(dataSize);
+ if (data != NULL) {
+ if ((int)fread(data, 1, dataSize, fpZip) == dataSize) {
+ if ((int)fwrite(data, 1, dataSize, fpOut) == dataSize) {
+ offset += dataSize;
+ totalBytes += dataSize;
+ } else {
+ err = Z_ERRNO;
+ }
+ } else {
+ err = Z_ERRNO;
+ }
+ free(data);
+ if (err != Z_OK) {
+ break;
+ }
+ } else {
+ err = Z_MEM_ERROR;
+ break;
+ }
+ }
+ }
+
+ /* Central directory entry */
+ {
+ char header[46];
+ char* comment = "";
+ int comsize = (int) strlen(comment);
+ WRITE_32(header, 0x02014b50);
+ WRITE_16(header + 4, version);
+ WRITE_16(header + 6, version);
+ WRITE_16(header + 8, gpflag);
+ WRITE_16(header + 10, method);
+ WRITE_16(header + 12, filetime);
+ WRITE_16(header + 14, filedate);
+ WRITE_32(header + 16, crc);
+ WRITE_32(header + 20, cpsize);
+ WRITE_32(header + 24, uncpsize);
+ WRITE_16(header + 28, fnsize);
+ WRITE_16(header + 30, extsize);
+ WRITE_16(header + 32, comsize);
+ WRITE_16(header + 34, 0); /* disk # */
+ WRITE_16(header + 36, 0); /* int attrb */
+ WRITE_32(header + 38, 0); /* ext attrb */
+ WRITE_32(header + 42, currentOffset);
+ /* Header */
+ if (fwrite(header, 1, 46, fpOutCD) == 46) {
+ offsetCD += 46;
+
+ /* Filename */
+ if (fnsize > 0) {
+ if (fwrite(filename, 1, fnsize, fpOutCD) == fnsize) {
+ offsetCD += fnsize;
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ } else {
+ err = Z_STREAM_ERROR;
+ break;
+ }
+
+ /* Extra field */
+ if (extsize > 0) {
+ if (fwrite(extra, 1, extsize, fpOutCD) == extsize) {
+ offsetCD += extsize;
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ }
+
+ /* Comment field */
+ if (comsize > 0) {
+ if ((int)fwrite(comment, 1, comsize, fpOutCD) == comsize) {
+ offsetCD += comsize;
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ }
+
+
+ } else {
+ err = Z_ERRNO;
+ break;
+ }
+ }
+
+ /* Success */
+ entries++;
+
+ } else {
+ break;
+ }
+ }
+
+ /* Final central directory */
+ {
+ int entriesZip = entries;
+ char header[22];
+ char* comment = ""; // "ZIP File recovered by zlib/minizip/mztools";
+ int comsize = (int) strlen(comment);
+ if (entriesZip > 0xffff) {
+ entriesZip = 0xffff;
+ }
+ WRITE_32(header, 0x06054b50);
+ WRITE_16(header + 4, 0); /* disk # */
+ WRITE_16(header + 6, 0); /* disk # */
+ WRITE_16(header + 8, entriesZip); /* hack */
+ WRITE_16(header + 10, entriesZip); /* hack */
+ WRITE_32(header + 12, offsetCD); /* size of CD */
+ WRITE_32(header + 16, offset); /* offset to CD */
+ WRITE_16(header + 20, comsize); /* comment */
+
+ /* Header */
+ if (fwrite(header, 1, 22, fpOutCD) == 22) {
+
+ /* Comment field */
+ if (comsize > 0) {
+ if ((int)fwrite(comment, 1, comsize, fpOutCD) != comsize) {
+ err = Z_ERRNO;
+ }
+ }
+
+ } else {
+ err = Z_ERRNO;
+ }
+ }
+
+ /* Final merge (file + central directory) */
+ fclose(fpOutCD);
+ if (err == Z_OK) {
+ fpOutCD = fopen(fileOutTmp, "rb");
+ if (fpOutCD != NULL) {
+ int nRead;
+ char buffer[8192];
+ while ( (nRead = (int)fread(buffer, 1, sizeof(buffer), fpOutCD)) > 0) {
+ if ((int)fwrite(buffer, 1, nRead, fpOut) != nRead) {
+ err = Z_ERRNO;
+ break;
+ }
+ }
+ fclose(fpOutCD);
+ }
+ }
+
+ /* Close */
+ fclose(fpZip);
+ fclose(fpOut);
+
+ /* Wipe temporary file */
+ (void)remove(fileOutTmp);
+
+ /* Number of recovered entries */
+ if (err == Z_OK) {
+ if (nRecovered != NULL) {
+ *nRecovered = entries;
+ }
+ if (bytesRecovered != NULL) {
+ *bytesRecovered = totalBytes;
+ }
+ }
+ } else {
+ err = Z_STREAM_ERROR;
+ }
+ return err;
+}
diff --git a/plugins/BasicHistory/zip/mztools.h b/plugins/BasicHistory/zip/mztools.h
new file mode 100644
index 0000000000..88b34592bf
--- /dev/null
+++ b/plugins/BasicHistory/zip/mztools.h
@@ -0,0 +1,31 @@
+/*
+ Additional tools for Minizip
+ Code: Xavier Roche '2004
+ License: Same as ZLIB (www.gzip.org)
+*/
+
+#ifndef _zip_tools_H
+#define _zip_tools_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#include "unzip.h"
+
+/* Repair a ZIP file (missing central directory)
+ file: file to recover
+ fileOut: output file after recovery
+ fileOutTmp: temporary file name used for recovery
+*/
+extern int ZEXPORT unzRepair(const char* file,
+ const char* fileOut,
+ const char* fileOutTmp,
+ uLong* nRecovered,
+ uLong* bytesRecovered);
+
+#endif
diff --git a/plugins/BasicHistory/zip/unzip.c b/plugins/BasicHistory/zip/unzip.c
new file mode 100644
index 0000000000..a23a6bb034
--- /dev/null
+++ b/plugins/BasicHistory/zip/unzip.c
@@ -0,0 +1,2121 @@
+/* unzip.c -- IO for uncompress .zip files using zlib
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications of Unzip for Zip64
+ Copyright (C) 2007-2008 Even Rouault
+
+ Modifications for Zip64 support on both zip and unzip
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+
+ ------------------------------------------------------------------------------------
+ Decryption code comes from crypt.c by Info-ZIP but has been greatly reduced in terms of
+ compatibility with older software. The following is from the original crypt.c.
+ Code woven in by Terry Thorsen 1/2003.
+
+ Copyright (c) 1990-2000 Info-ZIP. All rights reserved.
+
+ See the accompanying file LICENSE, version 2000-Apr-09 or later
+ (the contents of which are also included in zip.h) for terms of use.
+ If, for some reason, all these files are missing, the Info-ZIP license
+ also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
+
+ crypt.c (full version) by Info-ZIP. Last revised: [see crypt.h]
+
+ The encryption/decryption parts of this source code (as opposed to the
+ non-echoing password parts) were originally written in Europe. The
+ whole source package can be freely distributed, including from the USA.
+ (Prior to January 2000, re-export from the US was a violation of US law.)
+
+ This encryption code is a direct transcription of the algorithm from
+ Roger Schlafly, described by Phil Katz in the file appnote.txt. This
+ file (appnote.txt) is distributed with the PKZIP program (even in the
+ version without encryption capabilities).
+
+ ------------------------------------------------------------------------------------
+
+ Changes in unzip.c
+
+ 2007-2008 - Even Rouault - Addition of cpl_unzGetCurrentFileZStreamPos
+ 2007-2008 - Even Rouault - Decoration of symbol names unz* -> cpl_unz*
+ 2007-2008 - Even Rouault - Remove old C style function prototypes
+ 2007-2008 - Even Rouault - Add unzip support for ZIP64
+
+ Copyright (C) 2007-2008 Even Rouault
+
+
+ Oct-2009 - Mathias Svensson - Removed cpl_* from symbol names (Even Rouault added them but since this is now moved to a new project (minizip64) I renamed them again).
+ Oct-2009 - Mathias Svensson - Fixed problem if uncompressed size was > 4G and compressed size was <4G
+ should only read the compressed/uncompressed size from the Zip64 format if
+ the size from normal header was 0xFFFFFFFF
+ Oct-2009 - Mathias Svensson - Applied some bug fixes from paches recived from Gilles Vollant
+ Oct-2009 - Mathias Svensson - Applied support to unzip files with compression mathod BZIP2 (bzip2 lib is required)
+ Patch created by Daniel Borca
+
+ Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer
+
+ Copyright (C) 1998 - 2010 Gilles Vollant, Even Rouault, Mathias Svensson
+
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "zlib.h"
+#include "unzip.h"
+
+#ifdef STDC
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+ extern int errno;
+#else
+# include <errno.h>
+#endif
+
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+
+#ifndef CASESENSITIVITYDEFAULT_NO
+# if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES)
+# define CASESENSITIVITYDEFAULT_NO
+# endif
+#endif
+
+
+#ifndef UNZ_BUFSIZE
+#define UNZ_BUFSIZE (16384)
+#endif
+
+#ifndef UNZ_MAXFILENAMEINZIP
+#define UNZ_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) free(p);}
+#endif
+
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+
+
+const char unz_copyright[] =
+ " unzip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
+
+/* unz_file_info_interntal contain internal info about a file in zipfile*/
+typedef struct unz_file_info64_internal_s
+{
+ ZPOS64_T offset_curfile;/* relative offset of local header 8 bytes */
+} unz_file_info64_internal;
+
+
+/* file_in_zip_read_info_s contain internal information about a file in zipfile,
+ when reading and decompress it */
+typedef struct
+{
+ char *read_buffer; /* internal buffer for compressed data */
+ z_stream stream; /* zLib stream structure for inflate */
+
+#ifdef HAVE_BZIP2
+ bz_stream bstream; /* bzLib stream structure for bziped */
+#endif
+
+ ZPOS64_T pos_in_zipfile; /* position in byte on the zipfile, for fseek*/
+ uLong stream_initialised; /* flag set if stream structure is initialised*/
+
+ ZPOS64_T offset_local_extrafield;/* offset of the local extra field */
+ uInt size_local_extrafield;/* size of the local extra field */
+ ZPOS64_T pos_local_extrafield; /* position in the local extra field in read*/
+ ZPOS64_T total_out_64;
+
+ uLong crc32; /* crc32 of all data uncompressed */
+ uLong crc32_wait; /* crc32 we must obtain after decompress all */
+ ZPOS64_T rest_read_compressed; /* number of byte to be decompressed */
+ ZPOS64_T rest_read_uncompressed;/*number of byte to be obtained after decomp*/
+ zlib_filefunc64_32_def z_filefunc;
+ voidpf filestream; /* io structore of the zipfile */
+ uLong compression_method; /* compression method (0==store) */
+ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+ int raw;
+} file_in_zip64_read_info_s;
+
+
+/* unz64_s contain internal information about the zipfile
+*/
+typedef struct
+{
+ zlib_filefunc64_32_def z_filefunc;
+ int is64bitOpenFunction;
+ voidpf filestream; /* io structore of the zipfile */
+ unz_global_info64 gi; /* public global information */
+ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+ ZPOS64_T num_file; /* number of the current file in the zipfile*/
+ ZPOS64_T pos_in_central_dir; /* pos of the current file in the central dir*/
+ ZPOS64_T current_file_ok; /* flag about the usability of the current file*/
+ ZPOS64_T central_pos; /* position of the beginning of the central dir*/
+
+ ZPOS64_T size_central_dir; /* size of the central directory */
+ ZPOS64_T offset_central_dir; /* offset of start of central directory with
+ respect to the starting disk number */
+
+ unz_file_info64 cur_file_info; /* public info about the current file in zip*/
+ unz_file_info64_internal cur_file_info_internal; /* private info about it*/
+ file_in_zip64_read_info_s* pfile_in_zip_read; /* structure about the current
+ file if we are decompressing it */
+ int encrypted;
+
+ int isZip64;
+
+# ifndef NOUNCRYPT
+ unsigned long keys[3]; /* keys defining the pseudo-random sequence */
+ const unsigned long* pcrc_32_tab;
+# endif
+} unz64_s;
+
+
+#ifndef NOUNCRYPT
+#include "crypt.h"
+#endif
+
+/* ===========================================================================
+ Read a byte from a gz_stream; update next_in and avail_in. Return EOF
+ for end of file.
+ IN assertion: the stream s has been sucessfully opened for reading.
+*/
+
+
+local int unz64local_getByte OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ int *pi));
+
+local int unz64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi)
+{
+ unsigned char c;
+ int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1);
+ if (err==1)
+ {
+ *pi = (int)c;
+ return UNZ_OK;
+ }
+ else
+ {
+ if (ZERROR64(*pzlib_filefunc_def,filestream))
+ return UNZ_ERRNO;
+ else
+ return UNZ_EOF;
+ }
+}
+
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets
+*/
+local int unz64local_getShort OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX));
+
+local int unz64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX)
+{
+ uLong x ;
+ int i = 0;
+ int err;
+
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((uLong)i)<<8;
+
+ if (err==UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int unz64local_getLong OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX));
+
+local int unz64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ uLong *pX)
+{
+ uLong x ;
+ int i = 0;
+ int err;
+
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((uLong)i)<<8;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((uLong)i)<<16;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<24;
+
+ if (err==UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int unz64local_getLong64 OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ ZPOS64_T *pX));
+
+
+local int unz64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream,
+ ZPOS64_T *pX)
+{
+ ZPOS64_T x ;
+ int i = 0;
+ int err;
+
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (ZPOS64_T)i;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<8;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<16;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<24;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<32;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<40;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<48;
+
+ if (err==UNZ_OK)
+ err = unz64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x |= ((ZPOS64_T)i)<<56;
+
+ if (err==UNZ_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+/* My own strcmpi / strcasecmp */
+local int strcmpcasenosensitive_internal (const char* fileName1, const char* fileName2)
+{
+ for (;;)
+ {
+ char c1=*(fileName1++);
+ char c2=*(fileName2++);
+ if ((c1>='a') && (c1<='z'))
+ c1 -= 0x20;
+ if ((c2>='a') && (c2<='z'))
+ c2 -= 0x20;
+ if (c1=='\0')
+ return ((c2=='\0') ? 0 : -1);
+ if (c2=='\0')
+ return 1;
+ if (c1<c2)
+ return -1;
+ if (c1>c2)
+ return 1;
+ }
+}
+
+
+#ifdef CASESENSITIVITYDEFAULT_NO
+#define CASESENSITIVITYDEFAULTVALUE 2
+#else
+#define CASESENSITIVITYDEFAULTVALUE 1
+#endif
+
+#ifndef STRCMPCASENOSENTIVEFUNCTION
+#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal
+#endif
+
+/*
+ Compare two filename (fileName1,fileName2).
+ If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+ If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+ or strcasecmp)
+ If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+ (like 1 on Unix, 2 on Windows)
+
+*/
+extern int ZEXPORT unzStringFileNameCompare (const char* fileName1,
+ const char* fileName2,
+ int iCaseSensitivity)
+
+{
+ if (iCaseSensitivity==0)
+ iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE;
+
+ if (iCaseSensitivity==1)
+ return strcmp(fileName1,fileName2);
+
+ return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2);
+}
+
+#ifndef BUFREADCOMMENT
+#define BUFREADCOMMENT (0x400)
+#endif
+
+/*
+ Locate the Central directory of a zipfile (at the end, just before
+ the global comment)
+*/
+local ZPOS64_T unz64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
+local ZPOS64_T unz64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
+{
+ unsigned char* buf;
+ ZPOS64_T uSizeFile;
+ ZPOS64_T uBackRead;
+ ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+ ZPOS64_T uPosFound=0;
+
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+ return 0;
+
+
+ uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize;
+ ZPOS64_T uReadPos ;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ break;
+
+ if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;)
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
+ ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+
+ if (uPosFound!=0)
+ break;
+ }
+ TRYFREE(buf);
+ return uPosFound;
+}
+
+
+/*
+ Locate the Central directory 64 of a zipfile (at the end, just before
+ the global comment)
+*/
+local ZPOS64_T unz64local_SearchCentralDir64 OF((
+ const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream));
+
+local ZPOS64_T unz64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def,
+ voidpf filestream)
+{
+ unsigned char* buf;
+ ZPOS64_T uSizeFile;
+ ZPOS64_T uBackRead;
+ ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+ ZPOS64_T uPosFound=0;
+ uLong uL;
+ ZPOS64_T relativeOffset;
+
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+ return 0;
+
+
+ uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize;
+ ZPOS64_T uReadPos;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ break;
+
+ if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;)
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
+ ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+
+ if (uPosFound!=0)
+ break;
+ }
+ TRYFREE(buf);
+ if (uPosFound == 0)
+ return 0;
+
+ /* Zip64 end of central directory locator */
+ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return 0;
+
+ /* the signature, already checked */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+ return 0;
+
+ /* number of the disk with the start of the zip64 end of central directory */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+ return 0;
+ if (uL != 0)
+ return 0;
+
+ /* relative offset of the zip64 end of central directory record */
+ if (unz64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=UNZ_OK)
+ return 0;
+
+ /* total number of disks */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+ return 0;
+ if (uL != 1)
+ return 0;
+
+ /* Goto end of central directory record */
+ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return 0;
+
+ /* the signature */
+ if (unz64local_getLong(pzlib_filefunc_def,filestream,&uL)!=UNZ_OK)
+ return 0;
+
+ if (uL != 0x06064b50)
+ return 0;
+
+ return relativeOffset;
+}
+
+/*
+ Open a Zip file. path contain the full pathname (by example,
+ on a Windows NT computer "c:\\test\\zlib114.zip" or on an Unix computer
+ "zlib/zlib114.zip".
+ If the zipfile cannot be opened (file doesn't exist or in not valid), the
+ return value is NULL.
+ Else, the return value is a unzFile Handle, usable with other function
+ of this unzip package.
+*/
+local unzFile unzOpenInternal (const void *path,
+ zlib_filefunc64_32_def* pzlib_filefunc64_32_def,
+ int is64bitOpenFunction)
+{
+ unz64_s us;
+ unz64_s *s;
+ ZPOS64_T central_pos;
+ uLong uL;
+
+ uLong number_disk; /* number of the current dist, used for
+ spaning ZIP, unsupported, always 0*/
+ uLong number_disk_with_CD; /* number the the disk with central dir, used
+ for spaning ZIP, unsupported, always 0*/
+ ZPOS64_T number_entry_CD; /* total number of entries in
+ the central dir
+ (same than number_entry on nospan) */
+
+ int err=UNZ_OK;
+
+ if (unz_copyright[0]!=' ')
+ return NULL;
+
+ us.z_filefunc.zseek32_file = NULL;
+ us.z_filefunc.ztell32_file = NULL;
+ if (pzlib_filefunc64_32_def==NULL)
+ fill_fopen64_filefunc(&us.z_filefunc.zfile_func64);
+ else
+ us.z_filefunc = *pzlib_filefunc64_32_def;
+ us.is64bitOpenFunction = is64bitOpenFunction;
+
+
+
+ us.filestream = ZOPEN64(us.z_filefunc,
+ path,
+ ZLIB_FILEFUNC_MODE_READ |
+ ZLIB_FILEFUNC_MODE_EXISTING);
+ if (us.filestream==NULL)
+ return NULL;
+
+ central_pos = unz64local_SearchCentralDir64(&us.z_filefunc,us.filestream);
+ if (central_pos)
+ {
+ uLong uS;
+ ZPOS64_T uL64;
+
+ us.isZip64 = 1;
+
+ if (ZSEEK64(us.z_filefunc, us.filestream,
+ central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=UNZ_ERRNO;
+
+ /* the signature, already checked */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* size of zip64 end of central directory record */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&uL64)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* version made by */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* version needed to extract */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uS)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of this disk */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* total number of entries in the central directory on this disk */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.gi.number_entry)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* total number of entries in the central directory */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&number_entry_CD)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if ((number_entry_CD!=us.gi.number_entry) ||
+ (number_disk_with_CD!=0) ||
+ (number_disk!=0))
+ err=UNZ_BADZIPFILE;
+
+ /* size of the central directory */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.size_central_dir)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* offset of start of central directory with respect to the
+ starting disk number */
+ if (unz64local_getLong64(&us.z_filefunc, us.filestream,&us.offset_central_dir)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ us.gi.size_comment = 0;
+ }
+ else
+ {
+ central_pos = unz64local_SearchCentralDir(&us.z_filefunc,us.filestream);
+ if (central_pos==0)
+ err=UNZ_ERRNO;
+
+ us.isZip64 = 0;
+
+ if (ZSEEK64(us.z_filefunc, us.filestream,
+ central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=UNZ_ERRNO;
+
+ /* the signature, already checked */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of this disk */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&number_disk_with_CD)!=UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* total number of entries in the central dir on this disk */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ us.gi.number_entry = uL;
+
+ /* total number of entries in the central dir */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ number_entry_CD = uL;
+
+ if ((number_entry_CD!=us.gi.number_entry) ||
+ (number_disk_with_CD!=0) ||
+ (number_disk!=0))
+ err=UNZ_BADZIPFILE;
+
+ /* size of the central directory */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ us.size_central_dir = uL;
+
+ /* offset of start of central directory with respect to the
+ starting disk number */
+ if (unz64local_getLong(&us.z_filefunc, us.filestream,&uL)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ us.offset_central_dir = uL;
+
+ /* zipfile comment length */
+ if (unz64local_getShort(&us.z_filefunc, us.filestream,&us.gi.size_comment)!=UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ if ((central_pos<us.offset_central_dir+us.size_central_dir) &&
+ (err==UNZ_OK))
+ err=UNZ_BADZIPFILE;
+
+ if (err!=UNZ_OK)
+ {
+ ZCLOSE64(us.z_filefunc, us.filestream);
+ return NULL;
+ }
+
+ us.byte_before_the_zipfile = central_pos -
+ (us.offset_central_dir+us.size_central_dir);
+ us.central_pos = central_pos;
+ us.pfile_in_zip_read = NULL;
+ us.encrypted = 0;
+
+
+ s=(unz64_s*)ALLOC(sizeof(unz64_s));
+ if( s != NULL)
+ {
+ *s=us;
+ unzGoToFirstFile((unzFile)s);
+ }
+ return (unzFile)s;
+}
+
+
+extern unzFile ZEXPORT unzOpen2 (const char *path,
+ zlib_filefunc_def* pzlib_filefunc32_def)
+{
+ if (pzlib_filefunc32_def != NULL)
+ {
+ zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+ fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);
+ return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 0);
+ }
+ else
+ return unzOpenInternal(path, NULL, 0);
+}
+
+extern unzFile ZEXPORT unzOpen2_64 (const void *path,
+ zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ if (pzlib_filefunc_def != NULL)
+ {
+ zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+ zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+ zlib_filefunc64_32_def_fill.ztell32_file = NULL;
+ zlib_filefunc64_32_def_fill.zseek32_file = NULL;
+ return unzOpenInternal(path, &zlib_filefunc64_32_def_fill, 1);
+ }
+ else
+ return unzOpenInternal(path, NULL, 1);
+}
+
+extern unzFile ZEXPORT unzOpen (const char *path)
+{
+ return unzOpenInternal(path, NULL, 0);
+}
+
+extern unzFile ZEXPORT unzOpen64 (const void *path)
+{
+ return unzOpenInternal(path, NULL, 1);
+}
+
+/*
+ Close a ZipFile opened with unzipOpen.
+ If there is files inside the .Zip opened with unzipOpenCurrentFile (see later),
+ these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+ return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzClose (unzFile file)
+{
+ unz64_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+
+ if (s->pfile_in_zip_read!=NULL)
+ unzCloseCurrentFile(file);
+
+ ZCLOSE64(s->z_filefunc, s->filestream);
+ TRYFREE(s);
+ return UNZ_OK;
+}
+
+
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem. */
+extern int ZEXPORT unzGetGlobalInfo64 (unzFile file, unz_global_info64* pglobal_info)
+{
+ unz64_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ *pglobal_info=s->gi;
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetGlobalInfo (unzFile file, unz_global_info* pglobal_info32)
+{
+ unz64_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ /* to do : check if number_entry is not truncated */
+ pglobal_info32->number_entry = (uLong)s->gi.number_entry;
+ pglobal_info32->size_comment = s->gi.size_comment;
+ return UNZ_OK;
+}
+/*
+ Translate date/time from Dos format to tm_unz (readable more easilty)
+*/
+local void unz64local_DosDateToTmuDate (ZPOS64_T ulDosDate, tm_unz* ptm)
+{
+ ZPOS64_T uDate;
+ uDate = (ZPOS64_T)(ulDosDate>>16);
+ ptm->tm_mday = (uInt)(uDate&0x1f) ;
+ ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ;
+ ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ;
+
+ ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800);
+ ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ;
+ ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ;
+}
+
+/*
+ Get Info about the current file in the zipfile, with internal only info
+*/
+local int unz64local_GetCurrentFileInfoInternal OF((unzFile file,
+ unz_file_info64 *pfile_info,
+ unz_file_info64_internal
+ *pfile_info_internal,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize));
+
+local int unz64local_GetCurrentFileInfoInternal (unzFile file,
+ unz_file_info64 *pfile_info,
+ unz_file_info64_internal
+ *pfile_info_internal,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize)
+{
+ unz64_s* s;
+ unz_file_info64 file_info;
+ unz_file_info64_internal file_info_internal;
+ int err=UNZ_OK;
+ uLong uMagic;
+ long lSeek=0;
+ uLong uL;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (ZSEEK64(s->z_filefunc, s->filestream,
+ s->pos_in_central_dir+s->byte_before_the_zipfile,
+ ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=UNZ_ERRNO;
+
+
+ /* we check the magic */
+ if (err==UNZ_OK)
+ {
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if (uMagic!=0x02014b50)
+ err=UNZ_BADZIPFILE;
+ }
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.version_needed) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.flag) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.compression_method) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.dosDate) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ unz64local_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date);
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.crc) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+ err=UNZ_ERRNO;
+ file_info.compressed_size = uL;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+ err=UNZ_ERRNO;
+ file_info.uncompressed_size = uL;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_filename) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_extra) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.size_file_comment) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.disk_num_start) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&file_info.internal_fa) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&file_info.external_fa) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ // relative offset of local header
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+ err=UNZ_ERRNO;
+ file_info_internal.offset_curfile = uL;
+
+ lSeek+=file_info.size_filename;
+ if ((err==UNZ_OK) && (szFileName!=NULL))
+ {
+ uLong uSizeRead ;
+ if (file_info.size_filename<fileNameBufferSize)
+ {
+ *(szFileName+file_info.size_filename)='\0';
+ uSizeRead = file_info.size_filename;
+ }
+ else
+ uSizeRead = fileNameBufferSize;
+
+ if ((file_info.size_filename>0) && (fileNameBufferSize>0))
+ if (ZREAD64(s->z_filefunc, s->filestream,szFileName,uSizeRead)!=uSizeRead)
+ err=UNZ_ERRNO;
+ lSeek -= uSizeRead;
+ }
+
+ // Read extrafield
+ if ((err==UNZ_OK) && (extraField!=NULL))
+ {
+ ZPOS64_T uSizeRead ;
+ if (file_info.size_file_extra<extraFieldBufferSize)
+ uSizeRead = file_info.size_file_extra;
+ else
+ uSizeRead = extraFieldBufferSize;
+
+ if (lSeek!=0)
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
+ lSeek=0;
+ else
+ err=UNZ_ERRNO;
+ }
+
+ if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0))
+ if (ZREAD64(s->z_filefunc, s->filestream,extraField,(uLong)uSizeRead)!=uSizeRead)
+ err=UNZ_ERRNO;
+
+ lSeek += file_info.size_file_extra - (uLong)uSizeRead;
+ }
+ else
+ lSeek += file_info.size_file_extra;
+
+
+ if ((err==UNZ_OK) && (file_info.size_file_extra != 0))
+ {
+ uLong acc = 0;
+
+ // since lSeek now points to after the extra field we need to move back
+ lSeek -= file_info.size_file_extra;
+
+ if (lSeek!=0)
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
+ lSeek=0;
+ else
+ err=UNZ_ERRNO;
+ }
+
+ while(acc < file_info.size_file_extra)
+ {
+ uLong headerId;
+ uLong dataSize;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&headerId) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&dataSize) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ /* ZIP64 extra fields */
+ if (headerId == 0x0001)
+ {
+ uLong uL;
+
+ if(file_info.uncompressed_size == (ZPOS64_T)(unsigned long)-1)
+ {
+ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.uncompressed_size) != UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ if(file_info.compressed_size == (ZPOS64_T)(unsigned long)-1)
+ {
+ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info.compressed_size) != UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ if(file_info_internal.offset_curfile == (ZPOS64_T)(unsigned long)-1)
+ {
+ /* Relative Header offset */
+ if (unz64local_getLong64(&s->z_filefunc, s->filestream,&file_info_internal.offset_curfile) != UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ if(file_info.disk_num_start == (unsigned long)-1)
+ {
+ /* Disk Start Number */
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uL) != UNZ_OK)
+ err=UNZ_ERRNO;
+ }
+
+ }
+ else
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream,dataSize,ZLIB_FILEFUNC_SEEK_CUR)!=0)
+ err=UNZ_ERRNO;
+ }
+
+ acc += 2 + 2 + dataSize;
+ }
+ }
+
+ if ((err==UNZ_OK) && (szComment!=NULL))
+ {
+ uLong uSizeRead ;
+ if (file_info.size_file_comment<commentBufferSize)
+ {
+ *(szComment+file_info.size_file_comment)='\0';
+ uSizeRead = file_info.size_file_comment;
+ }
+ else
+ uSizeRead = commentBufferSize;
+
+ if (lSeek!=0)
+ {
+ if (ZSEEK64(s->z_filefunc, s->filestream,lSeek,ZLIB_FILEFUNC_SEEK_CUR)==0)
+ lSeek=0;
+ else
+ err=UNZ_ERRNO;
+ }
+
+ if ((file_info.size_file_comment>0) && (commentBufferSize>0))
+ if (ZREAD64(s->z_filefunc, s->filestream,szComment,uSizeRead)!=uSizeRead)
+ err=UNZ_ERRNO;
+ lSeek+=file_info.size_file_comment - uSizeRead;
+ }
+ else
+ lSeek+=file_info.size_file_comment;
+
+
+ if ((err==UNZ_OK) && (pfile_info!=NULL))
+ *pfile_info=file_info;
+
+ if ((err==UNZ_OK) && (pfile_info_internal!=NULL))
+ *pfile_info_internal=file_info_internal;
+
+ return err;
+}
+
+
+
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem.
+*/
+extern int ZEXPORT unzGetCurrentFileInfo64 (unzFile file,
+ unz_file_info64 * pfile_info,
+ char * szFileName, uLong fileNameBufferSize,
+ void *extraField, uLong extraFieldBufferSize,
+ char* szComment, uLong commentBufferSize)
+{
+ return unz64local_GetCurrentFileInfoInternal(file,pfile_info,NULL,
+ szFileName,fileNameBufferSize,
+ extraField,extraFieldBufferSize,
+ szComment,commentBufferSize);
+}
+
+extern int ZEXPORT unzGetCurrentFileInfo (unzFile file,
+ unz_file_info * pfile_info,
+ char * szFileName, uLong fileNameBufferSize,
+ void *extraField, uLong extraFieldBufferSize,
+ char* szComment, uLong commentBufferSize)
+{
+ int err;
+ unz_file_info64 file_info64;
+ err = unz64local_GetCurrentFileInfoInternal(file,&file_info64,NULL,
+ szFileName,fileNameBufferSize,
+ extraField,extraFieldBufferSize,
+ szComment,commentBufferSize);
+ if (err==UNZ_OK)
+ {
+ pfile_info->version = file_info64.version;
+ pfile_info->version_needed = file_info64.version_needed;
+ pfile_info->flag = file_info64.flag;
+ pfile_info->compression_method = file_info64.compression_method;
+ pfile_info->dosDate = file_info64.dosDate;
+ pfile_info->crc = file_info64.crc;
+
+ pfile_info->size_filename = file_info64.size_filename;
+ pfile_info->size_file_extra = file_info64.size_file_extra;
+ pfile_info->size_file_comment = file_info64.size_file_comment;
+
+ pfile_info->disk_num_start = file_info64.disk_num_start;
+ pfile_info->internal_fa = file_info64.internal_fa;
+ pfile_info->external_fa = file_info64.external_fa;
+
+ pfile_info->tmu_date = file_info64.tmu_date,
+
+
+ pfile_info->compressed_size = (uLong)file_info64.compressed_size;
+ pfile_info->uncompressed_size = (uLong)file_info64.uncompressed_size;
+
+ }
+ return err;
+}
+/*
+ Set the current file of the zipfile to the first file.
+ return UNZ_OK if there is no problem
+*/
+extern int ZEXPORT unzGoToFirstFile (unzFile file)
+{
+ int err=UNZ_OK;
+ unz64_s* s;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ s->pos_in_central_dir=s->offset_central_dir;
+ s->num_file=0;
+ err=unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+/*
+ Set the current file of the zipfile to the next file.
+ return UNZ_OK if there is no problem
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+extern int ZEXPORT unzGoToNextFile (unzFile file)
+{
+ unz64_s* s;
+ int err;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+ if (s->gi.number_entry != 0xffff) /* 2^16 files overflow hack */
+ if (s->num_file+1==s->gi.number_entry)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename +
+ s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ;
+ s->num_file++;
+ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+
+/*
+ Try locate the file szFileName in the zipfile.
+ For the iCaseSensitivity signification, see unzipStringFileNameCompare
+
+ return value :
+ UNZ_OK if the file is found. It becomes the current file.
+ UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+extern int ZEXPORT unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity)
+{
+ unz64_s* s;
+ int err;
+
+ /* We remember the 'current' position in the file so that we can jump
+ * back there if we fail.
+ */
+ unz_file_info64 cur_file_infoSaved;
+ unz_file_info64_internal cur_file_info_internalSaved;
+ ZPOS64_T num_fileSaved;
+ ZPOS64_T pos_in_central_dirSaved;
+
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+
+ if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP)
+ return UNZ_PARAMERROR;
+
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ /* Save the current state */
+ num_fileSaved = s->num_file;
+ pos_in_central_dirSaved = s->pos_in_central_dir;
+ cur_file_infoSaved = s->cur_file_info;
+ cur_file_info_internalSaved = s->cur_file_info_internal;
+
+ err = unzGoToFirstFile(file);
+
+ while (err == UNZ_OK)
+ {
+ char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1];
+ err = unzGetCurrentFileInfo64(file,NULL,
+ szCurrentFileName,sizeof(szCurrentFileName)-1,
+ NULL,0,NULL,0);
+ if (err == UNZ_OK)
+ {
+ if (unzStringFileNameCompare(szCurrentFileName,
+ szFileName,iCaseSensitivity)==0)
+ return UNZ_OK;
+ err = unzGoToNextFile(file);
+ }
+ }
+
+ /* We failed, so restore the state of the 'current file' to where we
+ * were.
+ */
+ s->num_file = num_fileSaved ;
+ s->pos_in_central_dir = pos_in_central_dirSaved ;
+ s->cur_file_info = cur_file_infoSaved;
+ s->cur_file_info_internal = cur_file_info_internalSaved;
+ return err;
+}
+
+
+/*
+///////////////////////////////////////////
+// Contributed by Ryan Haksi (mailto://cryogen@infoserve.net)
+// I need random access
+//
+// Further optimization could be realized by adding an ability
+// to cache the directory in memory. The goal being a single
+// comprehensive file read to put the file I need in a memory.
+*/
+
+/*
+typedef struct unz_file_pos_s
+{
+ ZPOS64_T pos_in_zip_directory; // offset in file
+ ZPOS64_T num_of_file; // # of file
+} unz_file_pos;
+*/
+
+extern int ZEXPORT unzGetFilePos64(unzFile file, unz64_file_pos* file_pos)
+{
+ unz64_s* s;
+
+ if (file==NULL || file_pos==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_END_OF_LIST_OF_FILE;
+
+ file_pos->pos_in_zip_directory = s->pos_in_central_dir;
+ file_pos->num_of_file = s->num_file;
+
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzGetFilePos(
+ unzFile file,
+ unz_file_pos* file_pos)
+{
+ unz64_file_pos file_pos64;
+ int err = unzGetFilePos64(file,&file_pos64);
+ if (err==UNZ_OK)
+ {
+ file_pos->pos_in_zip_directory = (uLong)file_pos64.pos_in_zip_directory;
+ file_pos->num_of_file = (uLong)file_pos64.num_of_file;
+ }
+ return err;
+}
+
+extern int ZEXPORT unzGoToFilePos64(unzFile file, const unz64_file_pos* file_pos)
+{
+ unz64_s* s;
+ int err;
+
+ if (file==NULL || file_pos==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+
+ /* jump to the right spot */
+ s->pos_in_central_dir = file_pos->pos_in_zip_directory;
+ s->num_file = file_pos->num_of_file;
+
+ /* set the current file */
+ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ /* return results */
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+extern int ZEXPORT unzGoToFilePos(
+ unzFile file,
+ unz_file_pos* file_pos)
+{
+ unz64_file_pos file_pos64;
+ if (file_pos == NULL)
+ return UNZ_PARAMERROR;
+
+ file_pos64.pos_in_zip_directory = file_pos->pos_in_zip_directory;
+ file_pos64.num_of_file = file_pos->num_of_file;
+ return unzGoToFilePos64(file,&file_pos64);
+}
+
+/*
+// Unzip Helper Functions - should be here?
+///////////////////////////////////////////
+*/
+
+/*
+ Read the local header of the current zipfile
+ Check the coherency of the local header and info in the end of central
+ directory about this file
+ store in *piSizeVar the size of extra info in local header
+ (filename and size of extra field data)
+*/
+local int unz64local_CheckCurrentFileCoherencyHeader (unz64_s* s, uInt* piSizeVar,
+ ZPOS64_T * poffset_local_extrafield,
+ uInt * psize_local_extrafield)
+{
+ uLong uMagic,uData,uFlags;
+ uLong size_filename;
+ uLong size_extra_field;
+ int err=UNZ_OK;
+
+ *piSizeVar = 0;
+ *poffset_local_extrafield = 0;
+ *psize_local_extrafield = 0;
+
+ if (ZSEEK64(s->z_filefunc, s->filestream,s->cur_file_info_internal.offset_curfile +
+ s->byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+
+ if (err==UNZ_OK)
+ {
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uMagic) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if (uMagic!=0x04034b50)
+ err=UNZ_BADZIPFILE;
+ }
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
+ err=UNZ_ERRNO;
+/*
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion))
+ err=UNZ_BADZIPFILE;
+*/
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&uFlags) != UNZ_OK)
+ err=UNZ_ERRNO;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&uData) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method))
+ err=UNZ_BADZIPFILE;
+
+ if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) &&
+/* #ifdef HAVE_BZIP2 */
+ (s->cur_file_info.compression_method!=Z_BZIP2ED) &&
+/* #endif */
+ (s->cur_file_info.compression_method!=Z_DEFLATED))
+ err=UNZ_BADZIPFILE;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* date/time */
+ err=UNZ_ERRNO;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* crc */
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size compr */
+ err=UNZ_ERRNO;
+ else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+ if (unz64local_getLong(&s->z_filefunc, s->filestream,&uData) != UNZ_OK) /* size uncompr */
+ err=UNZ_ERRNO;
+ else if (uData != 0xFFFFFFFF && (err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && ((uFlags & 8)==0))
+ err=UNZ_BADZIPFILE;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_filename) != UNZ_OK)
+ err=UNZ_ERRNO;
+ else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename))
+ err=UNZ_BADZIPFILE;
+
+ *piSizeVar += (uInt)size_filename;
+
+ if (unz64local_getShort(&s->z_filefunc, s->filestream,&size_extra_field) != UNZ_OK)
+ err=UNZ_ERRNO;
+ *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile +
+ SIZEZIPLOCALHEADER + size_filename;
+ *psize_local_extrafield = (uInt)size_extra_field;
+
+ *piSizeVar += (uInt)size_extra_field;
+
+ return err;
+}
+
+/*
+ Open for reading data the current file in the zipfile.
+ If there is no error and the file is opened, the return value is UNZ_OK.
+*/
+extern int ZEXPORT unzOpenCurrentFile3 (unzFile file, int* method,
+ int* level, int raw, const char* password)
+{
+ int err=UNZ_OK;
+ uInt iSizeVar;
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ ZPOS64_T offset_local_extrafield; /* offset of the local extra field */
+ uInt size_local_extrafield; /* size of the local extra field */
+# ifndef NOUNCRYPT
+ char source[12];
+# else
+ if (password != NULL)
+ return UNZ_PARAMERROR;
+# endif
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return UNZ_PARAMERROR;
+
+ if (s->pfile_in_zip_read != NULL)
+ unzCloseCurrentFile(file);
+
+ if (unz64local_CheckCurrentFileCoherencyHeader(s,&iSizeVar, &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK)
+ return UNZ_BADZIPFILE;
+
+ pfile_in_zip_read_info = (file_in_zip64_read_info_s*)ALLOC(sizeof(file_in_zip64_read_info_s));
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_INTERNALERROR;
+
+ pfile_in_zip_read_info->read_buffer=(char*)ALLOC(UNZ_BUFSIZE);
+ pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield;
+ pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield;
+ pfile_in_zip_read_info->pos_local_extrafield=0;
+ pfile_in_zip_read_info->raw=raw;
+
+ if (pfile_in_zip_read_info->read_buffer==NULL)
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return UNZ_INTERNALERROR;
+ }
+
+ pfile_in_zip_read_info->stream_initialised=0;
+
+ if (method!=NULL)
+ *method = (int)s->cur_file_info.compression_method;
+
+ if (level!=NULL)
+ {
+ *level = 6;
+ switch (s->cur_file_info.flag & 0x06)
+ {
+ case 6 : *level = 1; break;
+ case 4 : *level = 2; break;
+ case 2 : *level = 9; break;
+ }
+ }
+
+ if ((s->cur_file_info.compression_method!=0) &&
+/* #ifdef HAVE_BZIP2 */
+ (s->cur_file_info.compression_method!=Z_BZIP2ED) &&
+/* #endif */
+ (s->cur_file_info.compression_method!=Z_DEFLATED))
+
+ err=UNZ_BADZIPFILE;
+
+ pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc;
+ pfile_in_zip_read_info->crc32=0;
+ pfile_in_zip_read_info->total_out_64=0;
+ pfile_in_zip_read_info->compression_method = s->cur_file_info.compression_method;
+ pfile_in_zip_read_info->filestream=s->filestream;
+ pfile_in_zip_read_info->z_filefunc=s->z_filefunc;
+ pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile;
+
+ pfile_in_zip_read_info->stream.total_out = 0;
+
+ if ((s->cur_file_info.compression_method==Z_BZIP2ED) && (!raw))
+ {
+#ifdef HAVE_BZIP2
+ pfile_in_zip_read_info->bstream.bzalloc = (void *(*) (void *, int, int))0;
+ pfile_in_zip_read_info->bstream.bzfree = (free_func)0;
+ pfile_in_zip_read_info->bstream.opaque = (voidpf)0;
+ pfile_in_zip_read_info->bstream.state = (voidpf)0;
+
+ pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+ pfile_in_zip_read_info->stream.zfree = (free_func)0;
+ pfile_in_zip_read_info->stream.opaque = (voidpf)0;
+ pfile_in_zip_read_info->stream.next_in = (voidpf)0;
+ pfile_in_zip_read_info->stream.avail_in = 0;
+
+ err=BZ2_bzDecompressInit(&pfile_in_zip_read_info->bstream, 0, 0);
+ if (err == Z_OK)
+ pfile_in_zip_read_info->stream_initialised=Z_BZIP2ED;
+ else
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return err;
+ }
+#else
+ pfile_in_zip_read_info->raw=1;
+#endif
+ }
+ else if ((s->cur_file_info.compression_method==Z_DEFLATED) && (!raw))
+ {
+ pfile_in_zip_read_info->stream.zalloc = (alloc_func)0;
+ pfile_in_zip_read_info->stream.zfree = (free_func)0;
+ pfile_in_zip_read_info->stream.opaque = (voidpf)0;
+ pfile_in_zip_read_info->stream.next_in = 0;
+ pfile_in_zip_read_info->stream.avail_in = 0;
+
+ err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS);
+ if (err == Z_OK)
+ pfile_in_zip_read_info->stream_initialised=Z_DEFLATED;
+ else
+ {
+ TRYFREE(pfile_in_zip_read_info);
+ return err;
+ }
+ /* windowBits is passed < 0 to tell that there is no zlib header.
+ * Note that in this case inflate *requires* an extra "dummy" byte
+ * after the compressed stream in order to complete decompression and
+ * return Z_STREAM_END.
+ * In unzip, i don't wait absolutely Z_STREAM_END because I known the
+ * size of both compressed and uncompressed data
+ */
+ }
+ pfile_in_zip_read_info->rest_read_compressed =
+ s->cur_file_info.compressed_size ;
+ pfile_in_zip_read_info->rest_read_uncompressed =
+ s->cur_file_info.uncompressed_size ;
+
+
+ pfile_in_zip_read_info->pos_in_zipfile =
+ s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER +
+ iSizeVar;
+
+ pfile_in_zip_read_info->stream.avail_in = (uInt)0;
+
+ s->pfile_in_zip_read = pfile_in_zip_read_info;
+ s->encrypted = 0;
+
+# ifndef NOUNCRYPT
+ if (password != NULL)
+ {
+ int i;
+ s->pcrc_32_tab = get_crc_table();
+ init_keys(password,s->keys,s->pcrc_32_tab);
+ if (ZSEEK64(s->z_filefunc, s->filestream,
+ s->pfile_in_zip_read->pos_in_zipfile +
+ s->pfile_in_zip_read->byte_before_the_zipfile,
+ SEEK_SET)!=0)
+ return UNZ_INTERNALERROR;
+ if(ZREAD64(s->z_filefunc, s->filestream,source, 12)<12)
+ return UNZ_INTERNALERROR;
+
+ for (i = 0; i<12; i++)
+ zdecode(s->keys,s->pcrc_32_tab,source[i]);
+
+ s->pfile_in_zip_read->pos_in_zipfile+=12;
+ s->encrypted=1;
+ }
+# endif
+
+
+ return UNZ_OK;
+}
+
+extern int ZEXPORT unzOpenCurrentFile (unzFile file)
+{
+ return unzOpenCurrentFile3(file, NULL, NULL, 0, NULL);
+}
+
+extern int ZEXPORT unzOpenCurrentFilePassword (unzFile file, const char* password)
+{
+ return unzOpenCurrentFile3(file, NULL, NULL, 0, password);
+}
+
+extern int ZEXPORT unzOpenCurrentFile2 (unzFile file, int* method, int* level, int raw)
+{
+ return unzOpenCurrentFile3(file, method, level, raw, NULL);
+}
+
+/** Addition for GDAL : START */
+
+extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64( unzFile file)
+{
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ s=(unz64_s*)file;
+ if (file==NULL)
+ return 0; //UNZ_PARAMERROR;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+ if (pfile_in_zip_read_info==NULL)
+ return 0; //UNZ_PARAMERROR;
+ return pfile_in_zip_read_info->pos_in_zipfile +
+ pfile_in_zip_read_info->byte_before_the_zipfile;
+}
+
+/** Addition for GDAL : END */
+
+/*
+ Read bytes from the current file.
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if somes bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error
+ (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+extern int ZEXPORT unzReadCurrentFile (unzFile file, voidp buf, unsigned len)
+{
+ int err=UNZ_OK;
+ uInt iRead = 0;
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+
+ if ((pfile_in_zip_read_info->read_buffer == NULL))
+ return UNZ_END_OF_LIST_OF_FILE;
+ if (len==0)
+ return 0;
+
+ pfile_in_zip_read_info->stream.next_out = (Bytef*)buf;
+
+ pfile_in_zip_read_info->stream.avail_out = (uInt)len;
+
+ if ((len>pfile_in_zip_read_info->rest_read_uncompressed) &&
+ (!(pfile_in_zip_read_info->raw)))
+ pfile_in_zip_read_info->stream.avail_out =
+ (uInt)pfile_in_zip_read_info->rest_read_uncompressed;
+
+ if ((len>pfile_in_zip_read_info->rest_read_compressed+
+ pfile_in_zip_read_info->stream.avail_in) &&
+ (pfile_in_zip_read_info->raw))
+ pfile_in_zip_read_info->stream.avail_out =
+ (uInt)pfile_in_zip_read_info->rest_read_compressed+
+ pfile_in_zip_read_info->stream.avail_in;
+
+ while (pfile_in_zip_read_info->stream.avail_out>0)
+ {
+ if ((pfile_in_zip_read_info->stream.avail_in==0) &&
+ (pfile_in_zip_read_info->rest_read_compressed>0))
+ {
+ uInt uReadThis = UNZ_BUFSIZE;
+ if (pfile_in_zip_read_info->rest_read_compressed<uReadThis)
+ uReadThis = (uInt)pfile_in_zip_read_info->rest_read_compressed;
+ if (uReadThis == 0)
+ return UNZ_EOF;
+ if (ZSEEK64(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ pfile_in_zip_read_info->pos_in_zipfile +
+ pfile_in_zip_read_info->byte_before_the_zipfile,
+ ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+ if (ZREAD64(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ pfile_in_zip_read_info->read_buffer,
+ uReadThis)!=uReadThis)
+ return UNZ_ERRNO;
+
+
+# ifndef NOUNCRYPT
+ if(s->encrypted)
+ {
+ uInt i;
+ for(i=0;i<uReadThis;i++)
+ pfile_in_zip_read_info->read_buffer[i] =
+ zdecode(s->keys,s->pcrc_32_tab,
+ pfile_in_zip_read_info->read_buffer[i]);
+ }
+# endif
+
+
+ pfile_in_zip_read_info->pos_in_zipfile += uReadThis;
+
+ pfile_in_zip_read_info->rest_read_compressed-=uReadThis;
+
+ pfile_in_zip_read_info->stream.next_in =
+ (Bytef*)pfile_in_zip_read_info->read_buffer;
+ pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis;
+ }
+
+ if ((pfile_in_zip_read_info->compression_method==0) || (pfile_in_zip_read_info->raw))
+ {
+ uInt uDoCopy,i ;
+
+ if ((pfile_in_zip_read_info->stream.avail_in == 0) &&
+ (pfile_in_zip_read_info->rest_read_compressed == 0))
+ return (iRead==0) ? UNZ_EOF : iRead;
+
+ if (pfile_in_zip_read_info->stream.avail_out <
+ pfile_in_zip_read_info->stream.avail_in)
+ uDoCopy = pfile_in_zip_read_info->stream.avail_out ;
+ else
+ uDoCopy = pfile_in_zip_read_info->stream.avail_in ;
+
+ for (i=0;i<uDoCopy;i++)
+ *(pfile_in_zip_read_info->stream.next_out+i) =
+ *(pfile_in_zip_read_info->stream.next_in+i);
+
+ pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uDoCopy;
+
+ pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,
+ pfile_in_zip_read_info->stream.next_out,
+ uDoCopy);
+ pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy;
+ pfile_in_zip_read_info->stream.avail_in -= uDoCopy;
+ pfile_in_zip_read_info->stream.avail_out -= uDoCopy;
+ pfile_in_zip_read_info->stream.next_out += uDoCopy;
+ pfile_in_zip_read_info->stream.next_in += uDoCopy;
+ pfile_in_zip_read_info->stream.total_out += uDoCopy;
+ iRead += uDoCopy;
+ }
+ else if (pfile_in_zip_read_info->compression_method==Z_BZIP2ED)
+ {
+#ifdef HAVE_BZIP2
+ uLong uTotalOutBefore,uTotalOutAfter;
+ const Bytef *bufBefore;
+ uLong uOutThis;
+
+ pfile_in_zip_read_info->bstream.next_in = (char*)pfile_in_zip_read_info->stream.next_in;
+ pfile_in_zip_read_info->bstream.avail_in = pfile_in_zip_read_info->stream.avail_in;
+ pfile_in_zip_read_info->bstream.total_in_lo32 = pfile_in_zip_read_info->stream.total_in;
+ pfile_in_zip_read_info->bstream.total_in_hi32 = 0;
+ pfile_in_zip_read_info->bstream.next_out = (char*)pfile_in_zip_read_info->stream.next_out;
+ pfile_in_zip_read_info->bstream.avail_out = pfile_in_zip_read_info->stream.avail_out;
+ pfile_in_zip_read_info->bstream.total_out_lo32 = pfile_in_zip_read_info->stream.total_out;
+ pfile_in_zip_read_info->bstream.total_out_hi32 = 0;
+
+ uTotalOutBefore = pfile_in_zip_read_info->bstream.total_out_lo32;
+ bufBefore = (const Bytef *)pfile_in_zip_read_info->bstream.next_out;
+
+ err=BZ2_bzDecompress(&pfile_in_zip_read_info->bstream);
+
+ uTotalOutAfter = pfile_in_zip_read_info->bstream.total_out_lo32;
+ uOutThis = uTotalOutAfter-uTotalOutBefore;
+
+ pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis;
+
+ pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32,bufBefore, (uInt)(uOutThis));
+ pfile_in_zip_read_info->rest_read_uncompressed -= uOutThis;
+ iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
+
+ pfile_in_zip_read_info->stream.next_in = (Bytef*)pfile_in_zip_read_info->bstream.next_in;
+ pfile_in_zip_read_info->stream.avail_in = pfile_in_zip_read_info->bstream.avail_in;
+ pfile_in_zip_read_info->stream.total_in = pfile_in_zip_read_info->bstream.total_in_lo32;
+ pfile_in_zip_read_info->stream.next_out = (Bytef*)pfile_in_zip_read_info->bstream.next_out;
+ pfile_in_zip_read_info->stream.avail_out = pfile_in_zip_read_info->bstream.avail_out;
+ pfile_in_zip_read_info->stream.total_out = pfile_in_zip_read_info->bstream.total_out_lo32;
+
+ if (err==BZ_STREAM_END)
+ return (iRead==0) ? UNZ_EOF : iRead;
+ if (err!=BZ_OK)
+ break;
+#endif
+ } // end Z_BZIP2ED
+ else
+ {
+ ZPOS64_T uTotalOutBefore,uTotalOutAfter;
+ const Bytef *bufBefore;
+ ZPOS64_T uOutThis;
+ int flush=Z_SYNC_FLUSH;
+
+ uTotalOutBefore = pfile_in_zip_read_info->stream.total_out;
+ bufBefore = pfile_in_zip_read_info->stream.next_out;
+
+ /*
+ if ((pfile_in_zip_read_info->rest_read_uncompressed ==
+ pfile_in_zip_read_info->stream.avail_out) &&
+ (pfile_in_zip_read_info->rest_read_compressed == 0))
+ flush = Z_FINISH;
+ */
+ err=inflate(&pfile_in_zip_read_info->stream,flush);
+
+ if ((err>=0) && (pfile_in_zip_read_info->stream.msg!=NULL))
+ err = Z_DATA_ERROR;
+
+ uTotalOutAfter = pfile_in_zip_read_info->stream.total_out;
+ uOutThis = uTotalOutAfter-uTotalOutBefore;
+
+ pfile_in_zip_read_info->total_out_64 = pfile_in_zip_read_info->total_out_64 + uOutThis;
+
+ pfile_in_zip_read_info->crc32 =
+ crc32(pfile_in_zip_read_info->crc32,bufBefore,
+ (uInt)(uOutThis));
+
+ pfile_in_zip_read_info->rest_read_uncompressed -=
+ uOutThis;
+
+ iRead += (uInt)(uTotalOutAfter - uTotalOutBefore);
+
+ if (err==Z_STREAM_END)
+ return (iRead==0) ? UNZ_EOF : iRead;
+ if (err!=Z_OK)
+ break;
+ }
+ }
+
+ if (err==Z_OK)
+ return iRead;
+ return err;
+}
+
+
+/*
+ Give the current position in uncompressed data
+*/
+extern z_off_t ZEXPORT unztell (unzFile file)
+{
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ return (z_off_t)pfile_in_zip_read_info->stream.total_out;
+}
+
+extern ZPOS64_T ZEXPORT unztell64 (unzFile file)
+{
+
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return (ZPOS64_T)-1;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return (ZPOS64_T)-1;
+
+ return pfile_in_zip_read_info->total_out_64;
+}
+
+
+/*
+ return 1 if the end of file was reached, 0 elsewhere
+*/
+extern int ZEXPORT unzeof (unzFile file)
+{
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ if (pfile_in_zip_read_info->rest_read_uncompressed == 0)
+ return 1;
+ else
+ return 0;
+}
+
+
+
+/*
+Read extra field from the current file (opened by unzOpenCurrentFile)
+This is the local-header version of the extra field (sometimes, there is
+more info in the local-header version than in the central-header)
+
+ if buf==NULL, it return the size of the local extra field that can be read
+
+ if buf!=NULL, len is the size of the buffer, the extra header is copied in
+ buf.
+ the return value is the number of bytes copied in buf, or (if <0)
+ the error code
+*/
+extern int ZEXPORT unzGetLocalExtrafield (unzFile file, voidp buf, unsigned len)
+{
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ uInt read_now;
+ ZPOS64_T size_to_read;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+ size_to_read = (pfile_in_zip_read_info->size_local_extrafield -
+ pfile_in_zip_read_info->pos_local_extrafield);
+
+ if (buf==NULL)
+ return (int)size_to_read;
+
+ if (len>size_to_read)
+ read_now = (uInt)size_to_read;
+ else
+ read_now = (uInt)len ;
+
+ if (read_now==0)
+ return 0;
+
+ if (ZSEEK64(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ pfile_in_zip_read_info->offset_local_extrafield +
+ pfile_in_zip_read_info->pos_local_extrafield,
+ ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+ if (ZREAD64(pfile_in_zip_read_info->z_filefunc,
+ pfile_in_zip_read_info->filestream,
+ buf,read_now)!=read_now)
+ return UNZ_ERRNO;
+
+ return (int)read_now;
+}
+
+/*
+ Close the file in zip opened with unzipOpenCurrentFile
+ Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+extern int ZEXPORT unzCloseCurrentFile (unzFile file)
+{
+ int err=UNZ_OK;
+
+ unz64_s* s;
+ file_in_zip64_read_info_s* pfile_in_zip_read_info;
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ pfile_in_zip_read_info=s->pfile_in_zip_read;
+
+ if (pfile_in_zip_read_info==NULL)
+ return UNZ_PARAMERROR;
+
+
+ if ((pfile_in_zip_read_info->rest_read_uncompressed == 0) &&
+ (!pfile_in_zip_read_info->raw))
+ {
+ if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait)
+ err=UNZ_CRCERROR;
+ }
+
+
+ TRYFREE(pfile_in_zip_read_info->read_buffer);
+ pfile_in_zip_read_info->read_buffer = NULL;
+ if (pfile_in_zip_read_info->stream_initialised == Z_DEFLATED)
+ inflateEnd(&pfile_in_zip_read_info->stream);
+#ifdef HAVE_BZIP2
+ else if (pfile_in_zip_read_info->stream_initialised == Z_BZIP2ED)
+ BZ2_bzDecompressEnd(&pfile_in_zip_read_info->bstream);
+#endif
+
+
+ pfile_in_zip_read_info->stream_initialised = 0;
+ TRYFREE(pfile_in_zip_read_info);
+
+ s->pfile_in_zip_read=NULL;
+
+ return err;
+}
+
+
+/*
+ Get the global comment string of the ZipFile, in the szComment buffer.
+ uSizeBuf is the size of the szComment buffer.
+ return the number of byte copied or an error code <0
+*/
+extern int ZEXPORT unzGetGlobalComment (unzFile file, char * szComment, uLong uSizeBuf)
+{
+ unz64_s* s;
+ uLong uReadThis ;
+ if (file==NULL)
+ return (int)UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+
+ uReadThis = uSizeBuf;
+ if (uReadThis>s->gi.size_comment)
+ uReadThis = s->gi.size_comment;
+
+ if (ZSEEK64(s->z_filefunc,s->filestream,s->central_pos+22,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return UNZ_ERRNO;
+
+ if (uReadThis>0)
+ {
+ *szComment='\0';
+ if (ZREAD64(s->z_filefunc,s->filestream,szComment,uReadThis)!=uReadThis)
+ return UNZ_ERRNO;
+ }
+
+ if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment))
+ *(szComment+s->gi.size_comment)='\0';
+ return (int)uReadThis;
+}
+
+/* Additions by RX '2004 */
+extern ZPOS64_T ZEXPORT unzGetOffset64(unzFile file)
+{
+ unz64_s* s;
+
+ if (file==NULL)
+ return 0; //UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+ if (!s->current_file_ok)
+ return 0;
+ if (s->gi.number_entry != 0 && s->gi.number_entry != 0xffff)
+ if (s->num_file==s->gi.number_entry)
+ return 0;
+ return s->pos_in_central_dir;
+}
+
+extern uLong ZEXPORT unzGetOffset (unzFile file)
+{
+ ZPOS64_T offset64;
+
+ if (file==NULL)
+ return 0; //UNZ_PARAMERROR;
+ offset64 = unzGetOffset64(file);
+ return (uLong)offset64;
+}
+
+extern int ZEXPORT unzSetOffset64(unzFile file, ZPOS64_T pos)
+{
+ unz64_s* s;
+ int err;
+
+ if (file==NULL)
+ return UNZ_PARAMERROR;
+ s=(unz64_s*)file;
+
+ s->pos_in_central_dir = pos;
+ s->num_file = s->gi.number_entry; /* hack */
+ err = unz64local_GetCurrentFileInfoInternal(file,&s->cur_file_info,
+ &s->cur_file_info_internal,
+ NULL,0,NULL,0,NULL,0);
+ s->current_file_ok = (err == UNZ_OK);
+ return err;
+}
+
+extern int ZEXPORT unzSetOffset (unzFile file, uLong pos)
+{
+ return unzSetOffset64(file,pos);
+}
diff --git a/plugins/BasicHistory/zip/unzip.h b/plugins/BasicHistory/zip/unzip.h
new file mode 100644
index 0000000000..3183968b77
--- /dev/null
+++ b/plugins/BasicHistory/zip/unzip.h
@@ -0,0 +1,437 @@
+/* unzip.h -- IO for uncompress .zip files using zlib
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications of Unzip for Zip64
+ Copyright (C) 2007-2008 Even Rouault
+
+ Modifications for Zip64 support on both zip and unzip
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+ ---------------------------------------------------------------------------------
+
+ Condition of use and distribution are the same than zlib :
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ ---------------------------------------------------------------------------------
+
+ Changes
+
+ See header of unzip64.c
+
+*/
+
+#ifndef _unz64_H
+#define _unz64_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#ifndef _ZLIBIOAPI_H
+#include "ioapi.h"
+#endif
+
+#ifdef HAVE_BZIP2
+#include "bzlib.h"
+#endif
+
+#define Z_BZIP2ED 12
+
+#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+ from (void*) without cast */
+typedef struct TagunzFile__ { int unused; } unzFile__;
+typedef unzFile__ *unzFile;
+#else
+typedef voidp unzFile;
+#endif
+
+
+#define UNZ_OK (0)
+#define UNZ_END_OF_LIST_OF_FILE (-100)
+#define UNZ_ERRNO (Z_ERRNO)
+#define UNZ_EOF (0)
+#define UNZ_PARAMERROR (-102)
+#define UNZ_BADZIPFILE (-103)
+#define UNZ_INTERNALERROR (-104)
+#define UNZ_CRCERROR (-105)
+
+/* tm_unz contain date/time info */
+typedef struct tm_unz_s
+{
+ uInt tm_sec; /* seconds after the minute - [0,59] */
+ uInt tm_min; /* minutes after the hour - [0,59] */
+ uInt tm_hour; /* hours since midnight - [0,23] */
+ uInt tm_mday; /* day of the month - [1,31] */
+ uInt tm_mon; /* months since January - [0,11] */
+ uInt tm_year; /* years - [1980..2044] */
+} tm_unz;
+
+/* unz_global_info structure contain global data about the ZIPfile
+ These data comes from the end of central dir */
+typedef struct unz_global_info64_s
+{
+ ZPOS64_T number_entry; /* total number of entries in
+ the central dir on this disk */
+ uLong size_comment; /* size of the global comment of the zipfile */
+} unz_global_info64;
+
+typedef struct unz_global_info_s
+{
+ uLong number_entry; /* total number of entries in
+ the central dir on this disk */
+ uLong size_comment; /* size of the global comment of the zipfile */
+} unz_global_info;
+
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_info64_s
+{
+ uLong version; /* version made by 2 bytes */
+ uLong version_needed; /* version needed to extract 2 bytes */
+ uLong flag; /* general purpose bit flag 2 bytes */
+ uLong compression_method; /* compression method 2 bytes */
+ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
+ uLong crc; /* crc-32 4 bytes */
+ ZPOS64_T compressed_size; /* compressed size 8 bytes */
+ ZPOS64_T uncompressed_size; /* uncompressed size 8 bytes */
+ uLong size_filename; /* filename length 2 bytes */
+ uLong size_file_extra; /* extra field length 2 bytes */
+ uLong size_file_comment; /* file comment length 2 bytes */
+
+ uLong disk_num_start; /* disk number start 2 bytes */
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+
+ tm_unz tmu_date;
+} unz_file_info64;
+
+typedef struct unz_file_info_s
+{
+ uLong version; /* version made by 2 bytes */
+ uLong version_needed; /* version needed to extract 2 bytes */
+ uLong flag; /* general purpose bit flag 2 bytes */
+ uLong compression_method; /* compression method 2 bytes */
+ uLong dosDate; /* last mod file date in Dos fmt 4 bytes */
+ uLong crc; /* crc-32 4 bytes */
+ uLong compressed_size; /* compressed size 4 bytes */
+ uLong uncompressed_size; /* uncompressed size 4 bytes */
+ uLong size_filename; /* filename length 2 bytes */
+ uLong size_file_extra; /* extra field length 2 bytes */
+ uLong size_file_comment; /* file comment length 2 bytes */
+
+ uLong disk_num_start; /* disk number start 2 bytes */
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+
+ tm_unz tmu_date;
+} unz_file_info;
+
+extern int ZEXPORT unzStringFileNameCompare OF ((const char* fileName1,
+ const char* fileName2,
+ int iCaseSensitivity));
+/*
+ Compare two filename (fileName1,fileName2).
+ If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp)
+ If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi
+ or strcasecmp)
+ If iCaseSenisivity = 0, case sensitivity is defaut of your operating system
+ (like 1 on Unix, 2 on Windows)
+*/
+
+
+extern unzFile ZEXPORT unzOpen OF((const char *path));
+extern unzFile ZEXPORT unzOpen64 OF((const void *path));
+/*
+ Open a Zip file. path contain the full pathname (by example,
+ on a Windows XP computer "c:\\zlib\\zlib113.zip" or on an Unix computer
+ "zlib/zlib113.zip".
+ If the zipfile cannot be opened (file don't exist or in not valid), the
+ return value is NULL.
+ Else, the return value is a unzFile Handle, usable with other function
+ of this unzip package.
+ the "64" function take a const void* pointer, because the path is just the
+ value passed to the open64_file_func callback.
+ Under Windows, if UNICODE is defined, using fill_fopen64_filefunc, the path
+ is a pointer to a wide unicode string (LPCTSTR is LPCWSTR), so const char*
+ does not describe the reality
+*/
+
+
+extern unzFile ZEXPORT unzOpen2 OF((const char *path,
+ zlib_filefunc_def* pzlib_filefunc_def));
+/*
+ Open a Zip file, like unzOpen, but provide a set of file low level API
+ for read/write the zip file (see ioapi.h)
+*/
+
+extern unzFile ZEXPORT unzOpen2_64 OF((const void *path,
+ zlib_filefunc64_def* pzlib_filefunc_def));
+/*
+ Open a Zip file, like unz64Open, but provide a set of file low level API
+ for read/write the zip file (see ioapi.h)
+*/
+
+extern int ZEXPORT unzClose OF((unzFile file));
+/*
+ Close a ZipFile opened with unzipOpen.
+ If there is files inside the .Zip opened with unzOpenCurrentFile (see later),
+ these files MUST be closed with unzipCloseCurrentFile before call unzipClose.
+ return UNZ_OK if there is no problem. */
+
+extern int ZEXPORT unzGetGlobalInfo OF((unzFile file,
+ unz_global_info *pglobal_info));
+
+extern int ZEXPORT unzGetGlobalInfo64 OF((unzFile file,
+ unz_global_info64 *pglobal_info));
+/*
+ Write info about the ZipFile in the *pglobal_info structure.
+ No preparation of the structure is needed
+ return UNZ_OK if there is no problem. */
+
+
+extern int ZEXPORT unzGetGlobalComment OF((unzFile file,
+ char *szComment,
+ uLong uSizeBuf));
+/*
+ Get the global comment string of the ZipFile, in the szComment buffer.
+ uSizeBuf is the size of the szComment buffer.
+ return the number of byte copied or an error code <0
+*/
+
+
+/***************************************************************************/
+/* Unzip package allow you browse the directory of the zipfile */
+
+extern int ZEXPORT unzGoToFirstFile OF((unzFile file));
+/*
+ Set the current file of the zipfile to the first file.
+ return UNZ_OK if there is no problem
+*/
+
+extern int ZEXPORT unzGoToNextFile OF((unzFile file));
+/*
+ Set the current file of the zipfile to the next file.
+ return UNZ_OK if there is no problem
+ return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest.
+*/
+
+extern int ZEXPORT unzLocateFile OF((unzFile file,
+ const char *szFileName,
+ int iCaseSensitivity));
+/*
+ Try locate the file szFileName in the zipfile.
+ For the iCaseSensitivity signification, see unzStringFileNameCompare
+
+ return value :
+ UNZ_OK if the file is found. It becomes the current file.
+ UNZ_END_OF_LIST_OF_FILE if the file is not found
+*/
+
+
+/* ****************************************** */
+/* Ryan supplied functions */
+/* unz_file_info contain information about a file in the zipfile */
+typedef struct unz_file_pos_s
+{
+ uLong pos_in_zip_directory; /* offset in zip file directory */
+ uLong num_of_file; /* # of file */
+} unz_file_pos;
+
+extern int ZEXPORT unzGetFilePos(
+ unzFile file,
+ unz_file_pos* file_pos);
+
+extern int ZEXPORT unzGoToFilePos(
+ unzFile file,
+ unz_file_pos* file_pos);
+
+typedef struct unz64_file_pos_s
+{
+ ZPOS64_T pos_in_zip_directory; /* offset in zip file directory */
+ ZPOS64_T num_of_file; /* # of file */
+} unz64_file_pos;
+
+extern int ZEXPORT unzGetFilePos64(
+ unzFile file,
+ unz64_file_pos* file_pos);
+
+extern int ZEXPORT unzGoToFilePos64(
+ unzFile file,
+ const unz64_file_pos* file_pos);
+
+/* ****************************************** */
+
+extern int ZEXPORT unzGetCurrentFileInfo64 OF((unzFile file,
+ unz_file_info64 *pfile_info,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize));
+
+extern int ZEXPORT unzGetCurrentFileInfo OF((unzFile file,
+ unz_file_info *pfile_info,
+ char *szFileName,
+ uLong fileNameBufferSize,
+ void *extraField,
+ uLong extraFieldBufferSize,
+ char *szComment,
+ uLong commentBufferSize));
+/*
+ Get Info about the current file
+ if pfile_info!=NULL, the *pfile_info structure will contain somes info about
+ the current file
+ if szFileName!=NULL, the filemane string will be copied in szFileName
+ (fileNameBufferSize is the size of the buffer)
+ if extraField!=NULL, the extra field information will be copied in extraField
+ (extraFieldBufferSize is the size of the buffer).
+ This is the Central-header version of the extra field
+ if szComment!=NULL, the comment string of the file will be copied in szComment
+ (commentBufferSize is the size of the buffer)
+*/
+
+
+/** Addition for GDAL : START */
+
+extern ZPOS64_T ZEXPORT unzGetCurrentFileZStreamPos64 OF((unzFile file));
+
+/** Addition for GDAL : END */
+
+
+/***************************************************************************/
+/* for reading the content of the current zipfile, you can open it, read data
+ from it, and close it (you can close it before reading all the file)
+ */
+
+extern int ZEXPORT unzOpenCurrentFile OF((unzFile file));
+/*
+ Open for reading data the current file in the zipfile.
+ If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzOpenCurrentFilePassword OF((unzFile file,
+ const char* password));
+/*
+ Open for reading data the current file in the zipfile.
+ password is a crypting password
+ If there is no error, the return value is UNZ_OK.
+*/
+
+extern int ZEXPORT unzOpenCurrentFile2 OF((unzFile file,
+ int* method,
+ int* level,
+ int raw));
+/*
+ Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
+ if raw==1
+ *method will receive method of compression, *level will receive level of
+ compression
+ note : you can set level parameter as NULL (if you did not want known level,
+ but you CANNOT set method parameter as NULL
+*/
+
+extern int ZEXPORT unzOpenCurrentFile3 OF((unzFile file,
+ int* method,
+ int* level,
+ int raw,
+ const char* password));
+/*
+ Same than unzOpenCurrentFile, but open for read raw the file (not uncompress)
+ if raw==1
+ *method will receive method of compression, *level will receive level of
+ compression
+ note : you can set level parameter as NULL (if you did not want known level,
+ but you CANNOT set method parameter as NULL
+*/
+
+
+extern int ZEXPORT unzCloseCurrentFile OF((unzFile file));
+/*
+ Close the file in zip opened with unzOpenCurrentFile
+ Return UNZ_CRCERROR if all the file was read but the CRC is not good
+*/
+
+extern int ZEXPORT unzReadCurrentFile OF((unzFile file,
+ voidp buf,
+ unsigned len));
+/*
+ Read bytes from the current file (opened by unzOpenCurrentFile)
+ buf contain buffer where data must be copied
+ len the size of buf.
+
+ return the number of byte copied if somes bytes are copied
+ return 0 if the end of file was reached
+ return <0 with error code if there is an error
+ (UNZ_ERRNO for IO error, or zLib error for uncompress error)
+*/
+
+extern z_off_t ZEXPORT unztell OF((unzFile file));
+
+extern ZPOS64_T ZEXPORT unztell64 OF((unzFile file));
+/*
+ Give the current position in uncompressed data
+*/
+
+extern int ZEXPORT unzeof OF((unzFile file));
+/*
+ return 1 if the end of file was reached, 0 elsewhere
+*/
+
+extern int ZEXPORT unzGetLocalExtrafield OF((unzFile file,
+ voidp buf,
+ unsigned len));
+/*
+ Read extra field from the current file (opened by unzOpenCurrentFile)
+ This is the local-header version of the extra field (sometimes, there is
+ more info in the local-header version than in the central-header)
+
+ if buf==NULL, it return the size of the local extra field
+
+ if buf!=NULL, len is the size of the buffer, the extra header is copied in
+ buf.
+ the return value is the number of bytes copied in buf, or (if <0)
+ the error code
+*/
+
+/***************************************************************************/
+
+/* Get the current file offset */
+extern ZPOS64_T ZEXPORT unzGetOffset64 (unzFile file);
+extern uLong ZEXPORT unzGetOffset (unzFile file);
+
+/* Set the current file offset */
+extern int ZEXPORT unzSetOffset64 (unzFile file, ZPOS64_T pos);
+extern int ZEXPORT unzSetOffset (unzFile file, uLong pos);
+
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _unz64_H */
diff --git a/plugins/BasicHistory/zip/zconf.h b/plugins/BasicHistory/zip/zconf.h
new file mode 100644
index 0000000000..02ce56c431
--- /dev/null
+++ b/plugins/BasicHistory/zip/zconf.h
@@ -0,0 +1,428 @@
+/* zconf.h -- configuration of the zlib compression library
+ * Copyright (C) 1995-2010 Jean-loup Gailly.
+ * For conditions of distribution and use, see copyright notice in zlib.h
+ */
+
+/* @(#) $Id$ */
+
+#ifndef ZCONF_H
+#define ZCONF_H
+
+/*
+ * If you *really* need a unique prefix for all types and library functions,
+ * compile with -DZ_PREFIX. The "standard" zlib should be compiled without it.
+ * Even better than compiling with -DZ_PREFIX would be to use configure to set
+ * this permanently in zconf.h using "./configure --zprefix".
+ */
+#ifdef Z_PREFIX /* may be set to #if 1 by ./configure */
+
+/* all linked symbols */
+# define _dist_code z__dist_code
+# define _length_code z__length_code
+# define _tr_align z__tr_align
+# define _tr_flush_block z__tr_flush_block
+# define _tr_init z__tr_init
+# define _tr_stored_block z__tr_stored_block
+# define _tr_tally z__tr_tally
+# define adler32 z_adler32
+# define adler32_combine z_adler32_combine
+# define adler32_combine64 z_adler32_combine64
+# define compress z_compress
+# define compress2 z_compress2
+# define compressBound z_compressBound
+# define crc32 z_crc32
+# define crc32_combine z_crc32_combine
+# define crc32_combine64 z_crc32_combine64
+# define deflate z_deflate
+# define deflateBound z_deflateBound
+# define deflateCopy z_deflateCopy
+# define deflateEnd z_deflateEnd
+# define deflateInit2_ z_deflateInit2_
+# define deflateInit_ z_deflateInit_
+# define deflateParams z_deflateParams
+# define deflatePrime z_deflatePrime
+# define deflateReset z_deflateReset
+# define deflateSetDictionary z_deflateSetDictionary
+# define deflateSetHeader z_deflateSetHeader
+# define deflateTune z_deflateTune
+# define deflate_copyright z_deflate_copyright
+# define get_crc_table z_get_crc_table
+# define gz_error z_gz_error
+# define gz_intmax z_gz_intmax
+# define gz_strwinerror z_gz_strwinerror
+# define gzbuffer z_gzbuffer
+# define gzclearerr z_gzclearerr
+# define gzclose z_gzclose
+# define gzclose_r z_gzclose_r
+# define gzclose_w z_gzclose_w
+# define gzdirect z_gzdirect
+# define gzdopen z_gzdopen
+# define gzeof z_gzeof
+# define gzerror z_gzerror
+# define gzflush z_gzflush
+# define gzgetc z_gzgetc
+# define gzgets z_gzgets
+# define gzoffset z_gzoffset
+# define gzoffset64 z_gzoffset64
+# define gzopen z_gzopen
+# define gzopen64 z_gzopen64
+# define gzprintf z_gzprintf
+# define gzputc z_gzputc
+# define gzputs z_gzputs
+# define gzread z_gzread
+# define gzrewind z_gzrewind
+# define gzseek z_gzseek
+# define gzseek64 z_gzseek64
+# define gzsetparams z_gzsetparams
+# define gztell z_gztell
+# define gztell64 z_gztell64
+# define gzungetc z_gzungetc
+# define gzwrite z_gzwrite
+# define inflate z_inflate
+# define inflateBack z_inflateBack
+# define inflateBackEnd z_inflateBackEnd
+# define inflateBackInit_ z_inflateBackInit_
+# define inflateCopy z_inflateCopy
+# define inflateEnd z_inflateEnd
+# define inflateGetHeader z_inflateGetHeader
+# define inflateInit2_ z_inflateInit2_
+# define inflateInit_ z_inflateInit_
+# define inflateMark z_inflateMark
+# define inflatePrime z_inflatePrime
+# define inflateReset z_inflateReset
+# define inflateReset2 z_inflateReset2
+# define inflateSetDictionary z_inflateSetDictionary
+# define inflateSync z_inflateSync
+# define inflateSyncPoint z_inflateSyncPoint
+# define inflateUndermine z_inflateUndermine
+# define inflate_copyright z_inflate_copyright
+# define inflate_fast z_inflate_fast
+# define inflate_table z_inflate_table
+# define uncompress z_uncompress
+# define zError z_zError
+# define zcalloc z_zcalloc
+# define zcfree z_zcfree
+# define zlibCompileFlags z_zlibCompileFlags
+# define zlibVersion z_zlibVersion
+
+/* all zlib typedefs in zlib.h and zconf.h */
+# define Byte z_Byte
+# define Bytef z_Bytef
+# define alloc_func z_alloc_func
+# define charf z_charf
+# define free_func z_free_func
+# define gzFile z_gzFile
+# define gz_header z_gz_header
+# define gz_headerp z_gz_headerp
+# define in_func z_in_func
+# define intf z_intf
+# define out_func z_out_func
+# define uInt z_uInt
+# define uIntf z_uIntf
+# define uLong z_uLong
+# define uLongf z_uLongf
+# define voidp z_voidp
+# define voidpc z_voidpc
+# define voidpf z_voidpf
+
+/* all zlib structs in zlib.h and zconf.h */
+# define gz_header_s z_gz_header_s
+# define internal_state z_internal_state
+
+#endif
+
+#if defined(__MSDOS__) && !defined(MSDOS)
+# define MSDOS
+#endif
+#if (defined(OS_2) || defined(__OS2__)) && !defined(OS2)
+# define OS2
+#endif
+#if defined(_WINDOWS) && !defined(WINDOWS)
+# define WINDOWS
+#endif
+#if defined(_WIN32) || defined(_WIN32_WCE) || defined(__WIN32__)
+# ifndef WIN32
+# define WIN32
+# endif
+#endif
+#if (defined(MSDOS) || defined(OS2) || defined(WINDOWS)) && !defined(WIN32)
+# if !defined(__GNUC__) && !defined(__FLAT__) && !defined(__386__)
+# ifndef SYS16BIT
+# define SYS16BIT
+# endif
+# endif
+#endif
+
+/*
+ * Compile with -DMAXSEG_64K if the alloc function cannot allocate more
+ * than 64k bytes at a time (needed on systems with 16-bit int).
+ */
+#ifdef SYS16BIT
+# define MAXSEG_64K
+#endif
+#ifdef MSDOS
+# define UNALIGNED_OK
+#endif
+
+#ifdef __STDC_VERSION__
+# ifndef STDC
+# define STDC
+# endif
+# if __STDC_VERSION__ >= 199901L
+# ifndef STDC99
+# define STDC99
+# endif
+# endif
+#endif
+#if !defined(STDC) && (defined(__STDC__) || defined(__cplusplus))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(__GNUC__) || defined(__BORLANDC__))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(MSDOS) || defined(WINDOWS) || defined(WIN32))
+# define STDC
+#endif
+#if !defined(STDC) && (defined(OS2) || defined(__HOS_AIX__))
+# define STDC
+#endif
+
+#if defined(__OS400__) && !defined(STDC) /* iSeries (formerly AS/400). */
+# define STDC
+#endif
+
+#ifndef STDC
+# ifndef const /* cannot use !defined(STDC) && !defined(const) on Mac */
+# define const /* note: need a more gentle solution here */
+# endif
+#endif
+
+/* Some Mac compilers merge all .h files incorrectly: */
+#if defined(__MWERKS__)||defined(applec)||defined(THINK_C)||defined(__SC__)
+# define NO_DUMMY_DECL
+#endif
+
+/* Maximum value for memLevel in deflateInit2 */
+#ifndef MAX_MEM_LEVEL
+# ifdef MAXSEG_64K
+# define MAX_MEM_LEVEL 8
+# else
+# define MAX_MEM_LEVEL 9
+# endif
+#endif
+
+/* Maximum value for windowBits in deflateInit2 and inflateInit2.
+ * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files
+ * created by gzip. (Files created by minigzip can still be extracted by
+ * gzip.)
+ */
+#ifndef MAX_WBITS
+# define MAX_WBITS 15 /* 32K LZ77 window */
+#endif
+
+/* The memory requirements for deflate are (in bytes):
+ (1 << (windowBits+2)) + (1 << (memLevel+9))
+ that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values)
+ plus a few kilobytes for small objects. For example, if you want to reduce
+ the default memory requirements from 256K to 128K, compile with
+ make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7"
+ Of course this will generally degrade compression (there's no free lunch).
+
+ The memory requirements for inflate are (in bytes) 1 << windowBits
+ that is, 32K for windowBits=15 (default value) plus a few kilobytes
+ for small objects.
+*/
+
+ /* Type declarations */
+
+#ifndef OF /* function prototypes */
+# ifdef STDC
+# define OF(args) args
+# else
+# define OF(args) ()
+# endif
+#endif
+
+/* The following definitions for FAR are needed only for MSDOS mixed
+ * model programming (small or medium model with some far allocations).
+ * This was tested only with MSC; for other MSDOS compilers you may have
+ * to define NO_MEMCPY in zutil.h. If you don't need the mixed model,
+ * just define FAR to be empty.
+ */
+#ifdef SYS16BIT
+# if defined(M_I86SM) || defined(M_I86MM)
+ /* MSC small or medium model */
+# define SMALL_MEDIUM
+# ifdef _MSC_VER
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+# if (defined(__SMALL__) || defined(__MEDIUM__))
+ /* Turbo C small or medium model */
+# define SMALL_MEDIUM
+# ifdef __BORLANDC__
+# define FAR _far
+# else
+# define FAR far
+# endif
+# endif
+#endif
+
+#if defined(WINDOWS) || defined(WIN32)
+ /* If building or using zlib as a DLL, define ZLIB_DLL.
+ * This is not mandatory, but it offers a little performance increase.
+ */
+# ifdef ZLIB_DLL
+# if defined(WIN32) && (!defined(__BORLANDC__) || (__BORLANDC__ >= 0x500))
+# ifdef ZLIB_INTERNAL
+# define ZEXTERN extern __declspec(dllexport)
+# else
+# define ZEXTERN extern __declspec(dllimport)
+# endif
+# endif
+# endif /* ZLIB_DLL */
+ /* If building or using zlib with the WINAPI/WINAPIV calling convention,
+ * define ZLIB_WINAPI.
+ * Caution: the standard ZLIB1.DLL is NOT compiled using ZLIB_WINAPI.
+ */
+# ifdef ZLIB_WINAPI
+# ifdef FAR
+# undef FAR
+# endif
+# include <windows.h>
+ /* No need for _export, use ZLIB.DEF instead. */
+ /* For complete Windows compatibility, use WINAPI, not __stdcall. */
+# define ZEXPORT WINAPI
+# ifdef WIN32
+# define ZEXPORTVA WINAPIV
+# else
+# define ZEXPORTVA FAR CDECL
+# endif
+# endif
+#endif
+
+#if defined (__BEOS__)
+# ifdef ZLIB_DLL
+# ifdef ZLIB_INTERNAL
+# define ZEXPORT __declspec(dllexport)
+# define ZEXPORTVA __declspec(dllexport)
+# else
+# define ZEXPORT __declspec(dllimport)
+# define ZEXPORTVA __declspec(dllimport)
+# endif
+# endif
+#endif
+
+#ifndef ZEXTERN
+# define ZEXTERN extern
+#endif
+#ifndef ZEXPORT
+# define ZEXPORT
+#endif
+#ifndef ZEXPORTVA
+# define ZEXPORTVA
+#endif
+
+#ifndef FAR
+# define FAR
+#endif
+
+#if !defined(__MACTYPES__)
+typedef unsigned char Byte; /* 8 bits */
+#endif
+typedef unsigned int uInt; /* 16 bits or more */
+typedef unsigned long uLong; /* 32 bits or more */
+
+#ifdef SMALL_MEDIUM
+ /* Borland C/C++ and some old MSC versions ignore FAR inside typedef */
+# define Bytef Byte FAR
+#else
+ typedef Byte FAR Bytef;
+#endif
+typedef char FAR charf;
+typedef int FAR intf;
+typedef uInt FAR uIntf;
+typedef uLong FAR uLongf;
+
+#ifdef STDC
+ typedef void const *voidpc;
+ typedef void FAR *voidpf;
+ typedef void *voidp;
+#else
+ typedef Byte const *voidpc;
+ typedef Byte FAR *voidpf;
+ typedef Byte *voidp;
+#endif
+
+#ifdef HAVE_UNISTD_H /* may be set to #if 1 by ./configure */
+# define Z_HAVE_UNISTD_H
+#endif
+
+#ifdef STDC
+# include <sys/types.h> /* for off_t */
+#endif
+
+/* a little trick to accommodate both "#define _LARGEFILE64_SOURCE" and
+ * "#define _LARGEFILE64_SOURCE 1" as requesting 64-bit operations, (even
+ * though the former does not conform to the LFS document), but considering
+ * both "#undef _LARGEFILE64_SOURCE" and "#define _LARGEFILE64_SOURCE 0" as
+ * equivalently requesting no 64-bit operations
+ */
+#if -_LARGEFILE64_SOURCE - -1 == 1
+# undef _LARGEFILE64_SOURCE
+#endif
+
+#if defined(Z_HAVE_UNISTD_H) || defined(_LARGEFILE64_SOURCE)
+# include <unistd.h> /* for SEEK_* and off_t */
+# ifdef VMS
+# include <unixio.h> /* for off_t */
+# endif
+# ifndef z_off_t
+# define z_off_t off_t
+# endif
+#endif
+
+#ifndef SEEK_SET
+# define SEEK_SET 0 /* Seek from beginning of file. */
+# define SEEK_CUR 1 /* Seek from current position. */
+# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */
+#endif
+
+#ifndef z_off_t
+# define z_off_t long
+#endif
+
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+# define z_off64_t off64_t
+#else
+# define z_off64_t z_off_t
+#endif
+
+#if defined(__OS400__)
+# define NO_vsnprintf
+#endif
+
+#if defined(__MVS__)
+# define NO_vsnprintf
+#endif
+
+/* MVS linker does not support external names larger than 8 bytes */
+#if defined(__MVS__)
+ #pragma map(deflateInit_,"DEIN")
+ #pragma map(deflateInit2_,"DEIN2")
+ #pragma map(deflateEnd,"DEEND")
+ #pragma map(deflateBound,"DEBND")
+ #pragma map(inflateInit_,"ININ")
+ #pragma map(inflateInit2_,"ININ2")
+ #pragma map(inflateEnd,"INEND")
+ #pragma map(inflateSync,"INSY")
+ #pragma map(inflateSetDictionary,"INSEDI")
+ #pragma map(compressBound,"CMBND")
+ #pragma map(inflate_table,"INTABL")
+ #pragma map(inflate_fast,"INFA")
+ #pragma map(inflate_copyright,"INCOPY")
+#endif
+
+#endif /* ZCONF_H */
diff --git a/plugins/BasicHistory/zip/zip.c b/plugins/BasicHistory/zip/zip.c
new file mode 100644
index 0000000000..3c34fc8bd4
--- /dev/null
+++ b/plugins/BasicHistory/zip/zip.c
@@ -0,0 +1,2004 @@
+/* zip.c -- IO on .zip files using zlib
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+ Changes
+ Oct-2009 - Mathias Svensson - Remove old C style function prototypes
+ Oct-2009 - Mathias Svensson - Added Zip64 Support when creating new file archives
+ Oct-2009 - Mathias Svensson - Did some code cleanup and refactoring to get better overview of some functions.
+ Oct-2009 - Mathias Svensson - Added zipRemoveExtraInfoBlock to strip extra field data from its ZIP64 data
+ It is used when recreting zip archive with RAW when deleting items from a zip.
+ ZIP64 data is automaticly added to items that needs it, and existing ZIP64 data need to be removed.
+ Oct-2009 - Mathias Svensson - Added support for BZIP2 as compression mode (bzip2 lib is required)
+ Jan-2010 - back to unzip and minizip 1.0 name scheme, with compatibility layer
+
+*/
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "zlib.h"
+#include "zip.h"
+
+#ifdef STDC
+# include <stddef.h>
+# include <string.h>
+# include <stdlib.h>
+#endif
+#ifdef NO_ERRNO_H
+ extern int errno;
+#else
+# include <errno.h>
+#endif
+
+
+#ifndef local
+# define local static
+#endif
+/* compile with -Dlocal if your debugger can't find static symbols */
+
+#ifndef VERSIONMADEBY
+# define VERSIONMADEBY (0x0) /* platform depedent */
+#endif
+
+#ifndef Z_BUFSIZE
+#define Z_BUFSIZE (64*1024) //(16384)
+#endif
+
+#ifndef Z_MAXFILENAMEINZIP
+#define Z_MAXFILENAMEINZIP (256)
+#endif
+
+#ifndef ALLOC
+# define ALLOC(size) (malloc(size))
+#endif
+#ifndef TRYFREE
+# define TRYFREE(p) {if (p) free(p);}
+#endif
+
+/*
+#define SIZECENTRALDIRITEM (0x2e)
+#define SIZEZIPLOCALHEADER (0x1e)
+*/
+
+/* I've found an old Unix (a SunOS 4.1.3_U1) without all SEEK_* defined.... */
+
+
+// NOT sure that this work on ALL platform
+#define MAKEULONG64(a, b) ((ZPOS64_T)(((unsigned long)(a)) | ((ZPOS64_T)((unsigned long)(b))) << 32))
+
+#ifndef SEEK_CUR
+#define SEEK_CUR 1
+#endif
+
+#ifndef SEEK_END
+#define SEEK_END 2
+#endif
+
+#ifndef SEEK_SET
+#define SEEK_SET 0
+#endif
+
+#ifndef DEF_MEM_LEVEL
+#if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+#else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+#endif
+#endif
+const char zip_copyright[] =" zip 1.01 Copyright 1998-2004 Gilles Vollant - http://www.winimage.com/zLibDll";
+
+
+#define SIZEDATA_INDATABLOCK (4096-(4*4))
+
+#define LOCALHEADERMAGIC (0x04034b50)
+#define CENTRALHEADERMAGIC (0x02014b50)
+#define ENDHEADERMAGIC (0x06054b50)
+#define ZIP64ENDHEADERMAGIC (0x6064b50)
+#define ZIP64ENDLOCHEADERMAGIC (0x7064b50)
+
+#define FLAG_LOCALHEADER_OFFSET (0x06)
+#define CRC_LOCALHEADER_OFFSET (0x0e)
+
+#define SIZECENTRALHEADER (0x2e) /* 46 */
+
+typedef struct linkedlist_datablock_internal_s
+{
+ struct linkedlist_datablock_internal_s* next_datablock;
+ uLong avail_in_this_block;
+ uLong filled_in_this_block;
+ uLong unused; /* for future use and alignement */
+ unsigned char data[SIZEDATA_INDATABLOCK];
+} linkedlist_datablock_internal;
+
+typedef struct linkedlist_data_s
+{
+ linkedlist_datablock_internal* first_block;
+ linkedlist_datablock_internal* last_block;
+} linkedlist_data;
+
+
+typedef struct
+{
+ z_stream stream; /* zLib stream structure for inflate */
+#ifdef HAVE_BZIP2
+ bz_stream bstream; /* bzLib stream structure for bziped */
+#endif
+
+ int stream_initialised; /* 1 is stream is initialised */
+ uInt pos_in_buffered_data; /* last written byte in buffered_data */
+
+ ZPOS64_T pos_local_header; /* offset of the local header of the file
+ currenty writing */
+ char* central_header; /* central header data for the current file */
+ uLong size_centralExtra;
+ uLong size_centralheader; /* size of the central header for cur file */
+ uLong size_centralExtraFree; /* Extra bytes allocated to the centralheader but that are not used */
+ uLong flag; /* flag of the file currently writing */
+
+ int method; /* compression method of file currenty wr.*/
+ int raw; /* 1 for directly writing raw data */
+ Byte buffered_data[Z_BUFSIZE];/* buffer contain compressed data to be writ*/
+ uLong dosDate;
+ uLong crc32;
+ int encrypt;
+ int zip64; /* Add ZIP64 extened information in the extra field */
+ ZPOS64_T pos_zip64extrainfo;
+ ZPOS64_T totalCompressedData;
+ ZPOS64_T totalUncompressedData;
+#ifndef NOCRYPT
+ unsigned long keys[3]; /* keys defining the pseudo-random sequence */
+ const unsigned long* pcrc_32_tab;
+ int crypt_header_size;
+#endif
+} curfile64_info;
+
+typedef struct
+{
+ zlib_filefunc64_32_def z_filefunc;
+ voidpf filestream; /* io structore of the zipfile */
+ linkedlist_data central_dir;/* datablock with central dir in construction*/
+ int in_opened_file_inzip; /* 1 if a file in the zip is currently writ.*/
+ curfile64_info ci; /* info on the file curretly writing */
+
+ ZPOS64_T begin_pos; /* position of the beginning of the zipfile */
+ ZPOS64_T add_position_when_writting_offset;
+ ZPOS64_T number_entry;
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+ char *globalcomment;
+#endif
+
+} zip64_internal;
+
+
+#ifndef NOCRYPT
+#define INCLUDECRYPTINGCODE_IFCRYPTALLOWED
+#include "crypt.h"
+#endif
+
+local linkedlist_datablock_internal* allocate_new_datablock()
+{
+ linkedlist_datablock_internal* ldi;
+ ldi = (linkedlist_datablock_internal*)
+ ALLOC(sizeof(linkedlist_datablock_internal));
+ if (ldi!=NULL)
+ {
+ ldi->next_datablock = NULL ;
+ ldi->filled_in_this_block = 0 ;
+ ldi->avail_in_this_block = SIZEDATA_INDATABLOCK ;
+ }
+ return ldi;
+}
+
+local void free_datablock(linkedlist_datablock_internal* ldi)
+{
+ while (ldi!=NULL)
+ {
+ linkedlist_datablock_internal* ldinext = ldi->next_datablock;
+ TRYFREE(ldi);
+ ldi = ldinext;
+ }
+}
+
+local void init_linkedlist(linkedlist_data* ll)
+{
+ ll->first_block = ll->last_block = NULL;
+}
+
+local void free_linkedlist(linkedlist_data* ll)
+{
+ free_datablock(ll->first_block);
+ ll->first_block = ll->last_block = NULL;
+}
+
+
+local int add_data_in_datablock(linkedlist_data* ll, const void* buf, uLong len)
+{
+ linkedlist_datablock_internal* ldi;
+ const unsigned char* from_copy;
+
+ if (ll==NULL)
+ return ZIP_INTERNALERROR;
+
+ if (ll->last_block == NULL)
+ {
+ ll->first_block = ll->last_block = allocate_new_datablock();
+ if (ll->first_block == NULL)
+ return ZIP_INTERNALERROR;
+ }
+
+ ldi = ll->last_block;
+ from_copy = (unsigned char*)buf;
+
+ while (len>0)
+ {
+ uInt copy_this;
+ uInt i;
+ unsigned char* to_copy;
+
+ if (ldi->avail_in_this_block==0)
+ {
+ ldi->next_datablock = allocate_new_datablock();
+ if (ldi->next_datablock == NULL)
+ return ZIP_INTERNALERROR;
+ ldi = ldi->next_datablock ;
+ ll->last_block = ldi;
+ }
+
+ if (ldi->avail_in_this_block < len)
+ copy_this = (uInt)ldi->avail_in_this_block;
+ else
+ copy_this = (uInt)len;
+
+ to_copy = &(ldi->data[ldi->filled_in_this_block]);
+
+ for (i=0;i<copy_this;i++)
+ *(to_copy+i)=*(from_copy+i);
+
+ ldi->filled_in_this_block += copy_this;
+ ldi->avail_in_this_block -= copy_this;
+ from_copy += copy_this ;
+ len -= copy_this;
+ }
+ return ZIP_OK;
+}
+
+
+
+/****************************************************************************/
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+/* ===========================================================================
+ Inputs a long in LSB order to the given file
+ nbByte == 1, 2 ,4 or 8 (byte, short or long, ZPOS64_T)
+*/
+
+local int zip64local_putValue OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte));
+local int zip64local_putValue (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T x, int nbByte)
+{
+ unsigned char buf[8];
+ int n;
+ for (n = 0; n < nbByte; n++)
+ {
+ buf[n] = (unsigned char)(x & 0xff);
+ x >>= 8;
+ }
+ if (x != 0)
+ { /* data overflow - hack for ZIP64 (X Roche) */
+ for (n = 0; n < nbByte; n++)
+ {
+ buf[n] = 0xff;
+ }
+ }
+
+ if (ZWRITE64(*pzlib_filefunc_def,filestream,buf,nbByte)!=(uLong)nbByte)
+ return ZIP_ERRNO;
+ else
+ return ZIP_OK;
+}
+
+local void zip64local_putValue_inmemory OF((void* dest, ZPOS64_T x, int nbByte));
+local void zip64local_putValue_inmemory (void* dest, ZPOS64_T x, int nbByte)
+{
+ unsigned char* buf=(unsigned char*)dest;
+ int n;
+ for (n = 0; n < nbByte; n++) {
+ buf[n] = (unsigned char)(x & 0xff);
+ x >>= 8;
+ }
+
+ if (x != 0)
+ { /* data overflow - hack for ZIP64 */
+ for (n = 0; n < nbByte; n++)
+ {
+ buf[n] = 0xff;
+ }
+ }
+}
+
+/****************************************************************************/
+
+
+local uLong zip64local_TmzDateToDosDate(const tm_zip* ptm)
+{
+ uLong year = (uLong)ptm->tm_year;
+ if (year>=1980)
+ year-=1980;
+ else if (year>=80)
+ year-=80;
+ return
+ (uLong) (((ptm->tm_mday) + (32 * (ptm->tm_mon+1)) + (512 * year)) << 16) |
+ ((ptm->tm_sec/2) + (32* ptm->tm_min) + (2048 * (uLong)ptm->tm_hour));
+}
+
+
+/****************************************************************************/
+
+local int zip64local_getByte OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, int *pi));
+
+local int zip64local_getByte(const zlib_filefunc64_32_def* pzlib_filefunc_def,voidpf filestream,int* pi)
+{
+ unsigned char c;
+ int err = (int)ZREAD64(*pzlib_filefunc_def,filestream,&c,1);
+ if (err==1)
+ {
+ *pi = (int)c;
+ return ZIP_OK;
+ }
+ else
+ {
+ if (ZERROR64(*pzlib_filefunc_def,filestream))
+ return ZIP_ERRNO;
+ else
+ return ZIP_EOF;
+ }
+}
+
+
+/* ===========================================================================
+ Reads a long in LSB order from the given gz_stream. Sets
+*/
+local int zip64local_getShort OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX));
+
+local int zip64local_getShort (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)
+{
+ uLong x ;
+ int i = 0;
+ int err;
+
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<8;
+
+ if (err==ZIP_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int zip64local_getLong OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong *pX));
+
+local int zip64local_getLong (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, uLong* pX)
+{
+ uLong x ;
+ int i = 0;
+ int err;
+
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (uLong)i;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<8;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<16;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((uLong)i)<<24;
+
+ if (err==ZIP_OK)
+ *pX = x;
+ else
+ *pX = 0;
+ return err;
+}
+
+local int zip64local_getLong64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX));
+
+
+local int zip64local_getLong64 (const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream, ZPOS64_T *pX)
+{
+ ZPOS64_T x;
+ int i = 0;
+ int err;
+
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x = (ZPOS64_T)i;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<8;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<16;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<24;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<32;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<40;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<48;
+
+ if (err==ZIP_OK)
+ err = zip64local_getByte(pzlib_filefunc_def,filestream,&i);
+ x += ((ZPOS64_T)i)<<56;
+
+ if (err==ZIP_OK)
+ *pX = x;
+ else
+ *pX = 0;
+
+ return err;
+}
+
+#ifndef BUFREADCOMMENT
+#define BUFREADCOMMENT (0x400)
+#endif
+/*
+ Locate the Central directory of a zipfile (at the end, just before
+ the global comment)
+*/
+local ZPOS64_T zip64local_SearchCentralDir OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
+
+local ZPOS64_T zip64local_SearchCentralDir(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
+{
+ unsigned char* buf;
+ ZPOS64_T uSizeFile;
+ ZPOS64_T uBackRead;
+ ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+ ZPOS64_T uPosFound=0;
+
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+ return 0;
+
+
+ uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize;
+ ZPOS64_T uReadPos ;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ break;
+
+ if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;)
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) &&
+ ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+
+ if (uPosFound!=0)
+ break;
+ }
+ TRYFREE(buf);
+ return uPosFound;
+}
+
+/*
+Locate the End of Zip64 Central directory locator and from there find the CD of a zipfile (at the end, just before
+the global comment)
+*/
+local ZPOS64_T zip64local_SearchCentralDir64 OF((const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream));
+
+local ZPOS64_T zip64local_SearchCentralDir64(const zlib_filefunc64_32_def* pzlib_filefunc_def, voidpf filestream)
+{
+ unsigned char* buf;
+ ZPOS64_T uSizeFile;
+ ZPOS64_T uBackRead;
+ ZPOS64_T uMaxBack=0xffff; /* maximum size of global comment */
+ ZPOS64_T uPosFound=0;
+ uLong uL;
+ ZPOS64_T relativeOffset;
+
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,0,ZLIB_FILEFUNC_SEEK_END) != 0)
+ return 0;
+
+ uSizeFile = ZTELL64(*pzlib_filefunc_def,filestream);
+
+ if (uMaxBack>uSizeFile)
+ uMaxBack = uSizeFile;
+
+ buf = (unsigned char*)ALLOC(BUFREADCOMMENT+4);
+ if (buf==NULL)
+ return 0;
+
+ uBackRead = 4;
+ while (uBackRead<uMaxBack)
+ {
+ uLong uReadSize;
+ ZPOS64_T uReadPos;
+ int i;
+ if (uBackRead+BUFREADCOMMENT>uMaxBack)
+ uBackRead = uMaxBack;
+ else
+ uBackRead+=BUFREADCOMMENT;
+ uReadPos = uSizeFile-uBackRead ;
+
+ uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ?
+ (BUFREADCOMMENT+4) : (uLong)(uSizeFile-uReadPos);
+ if (ZSEEK64(*pzlib_filefunc_def,filestream,uReadPos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ break;
+
+ if (ZREAD64(*pzlib_filefunc_def,filestream,buf,uReadSize)!=uReadSize)
+ break;
+
+ for (i=(int)uReadSize-3; (i--)>0;)
+ {
+ // Signature "0x07064b50" Zip64 end of central directory locater
+ if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && ((*(buf+i+2))==0x06) && ((*(buf+i+3))==0x07))
+ {
+ uPosFound = uReadPos+i;
+ break;
+ }
+ }
+
+ if (uPosFound!=0)
+ break;
+ }
+
+ TRYFREE(buf);
+ if (uPosFound == 0)
+ return 0;
+
+ /* Zip64 end of central directory locator */
+ if (ZSEEK64(*pzlib_filefunc_def,filestream, uPosFound,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return 0;
+
+ /* the signature, already checked */
+ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
+ return 0;
+
+ /* number of the disk with the start of the zip64 end of central directory */
+ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
+ return 0;
+ if (uL != 0)
+ return 0;
+
+ /* relative offset of the zip64 end of central directory record */
+ if (zip64local_getLong64(pzlib_filefunc_def,filestream,&relativeOffset)!=ZIP_OK)
+ return 0;
+
+ /* total number of disks */
+ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
+ return 0;
+ if (uL != 1)
+ return 0;
+
+ /* Goto Zip64 end of central directory record */
+ if (ZSEEK64(*pzlib_filefunc_def,filestream, relativeOffset,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ return 0;
+
+ /* the signature */
+ if (zip64local_getLong(pzlib_filefunc_def,filestream,&uL)!=ZIP_OK)
+ return 0;
+
+ if (uL != 0x06064b50) // signature of 'Zip64 end of central directory'
+ return 0;
+
+ return relativeOffset;
+}
+
+int LoadCentralDirectoryRecord(zip64_internal* pziinit)
+{
+ int err=ZIP_OK;
+ ZPOS64_T byte_before_the_zipfile;/* byte before the zipfile, (>0 for sfx)*/
+
+ ZPOS64_T size_central_dir; /* size of the central directory */
+ ZPOS64_T offset_central_dir; /* offset of start of central directory */
+ ZPOS64_T central_pos;
+ uLong uL;
+
+ uLong number_disk; /* number of the current dist, used for
+ spaning ZIP, unsupported, always 0*/
+ uLong number_disk_with_CD; /* number the the disk with central dir, used
+ for spaning ZIP, unsupported, always 0*/
+ ZPOS64_T number_entry;
+ ZPOS64_T number_entry_CD; /* total number of entries in
+ the central dir
+ (same than number_entry on nospan) */
+ uLong VersionMadeBy;
+ uLong VersionNeeded;
+ uLong size_comment;
+
+ int hasZIP64Record = 0;
+
+ // check first if we find a ZIP64 record
+ central_pos = zip64local_SearchCentralDir64(&pziinit->z_filefunc,pziinit->filestream);
+ if(central_pos > 0)
+ {
+ hasZIP64Record = 1;
+ }
+ else if(central_pos == 0)
+ {
+ central_pos = zip64local_SearchCentralDir(&pziinit->z_filefunc,pziinit->filestream);
+ }
+
+/* disable to allow appending to empty ZIP archive
+ if (central_pos==0)
+ err=ZIP_ERRNO;
+*/
+
+ if(hasZIP64Record)
+ {
+ ZPOS64_T sizeEndOfCentralDirectory;
+ if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ err=ZIP_ERRNO;
+
+ /* the signature, already checked */
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* size of zip64 end of central directory record */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &sizeEndOfCentralDirectory)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* version made by */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionMadeBy)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* version needed to extract */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &VersionNeeded)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* number of this disk */
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* total number of entries in the central directory on this disk */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream, &number_entry)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* total number of entries in the central directory */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&number_entry_CD)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0))
+ err=ZIP_BADZIPFILE;
+
+ /* size of the central directory */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&size_central_dir)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* offset of start of central directory with respect to the
+ starting disk number */
+ if (zip64local_getLong64(&pziinit->z_filefunc, pziinit->filestream,&offset_central_dir)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ // TODO..
+ // read the comment from the standard central header.
+ size_comment = 0;
+ }
+ else
+ {
+ // Read End of central Directory info
+ if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, central_pos,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err=ZIP_ERRNO;
+
+ /* the signature, already checked */
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream,&uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* number of this disk */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* number of the disk with the start of the central directory */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream,&number_disk_with_CD)!=ZIP_OK)
+ err=ZIP_ERRNO;
+
+ /* total number of entries in the central dir on this disk */
+ number_entry = 0;
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ else
+ number_entry = uL;
+
+ /* total number of entries in the central dir */
+ number_entry_CD = 0;
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ else
+ number_entry_CD = uL;
+
+ if ((number_entry_CD!=number_entry) || (number_disk_with_CD!=0) || (number_disk!=0))
+ err=ZIP_BADZIPFILE;
+
+ /* size of the central directory */
+ size_central_dir = 0;
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ else
+ size_central_dir = uL;
+
+ /* offset of start of central directory with respect to the starting disk number */
+ offset_central_dir = 0;
+ if (zip64local_getLong(&pziinit->z_filefunc, pziinit->filestream, &uL)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ else
+ offset_central_dir = uL;
+
+
+ /* zipfile global comment length */
+ if (zip64local_getShort(&pziinit->z_filefunc, pziinit->filestream, &size_comment)!=ZIP_OK)
+ err=ZIP_ERRNO;
+ }
+
+ if ((central_pos<offset_central_dir+size_central_dir) &&
+ (err==ZIP_OK))
+ err=ZIP_BADZIPFILE;
+
+ if (err!=ZIP_OK)
+ {
+ ZCLOSE64(pziinit->z_filefunc, pziinit->filestream);
+ return ZIP_ERRNO;
+ }
+
+ if (size_comment>0)
+ {
+ pziinit->globalcomment = (char*)ALLOC(size_comment+1);
+ if (pziinit->globalcomment)
+ {
+ size_comment = ZREAD64(pziinit->z_filefunc, pziinit->filestream, pziinit->globalcomment,size_comment);
+ pziinit->globalcomment[size_comment]=0;
+ }
+ }
+
+ byte_before_the_zipfile = central_pos - (offset_central_dir+size_central_dir);
+ pziinit->add_position_when_writting_offset = byte_before_the_zipfile;
+
+ {
+ ZPOS64_T size_central_dir_to_read = size_central_dir;
+ size_t buf_size = SIZEDATA_INDATABLOCK;
+ void* buf_read = (void*)ALLOC(buf_size);
+ if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir + byte_before_the_zipfile, ZLIB_FILEFUNC_SEEK_SET) != 0)
+ err=ZIP_ERRNO;
+
+ while ((size_central_dir_to_read>0) && (err==ZIP_OK))
+ {
+ ZPOS64_T read_this = SIZEDATA_INDATABLOCK;
+ if (read_this > size_central_dir_to_read)
+ read_this = size_central_dir_to_read;
+
+ if (ZREAD64(pziinit->z_filefunc, pziinit->filestream,buf_read,(uLong)read_this) != read_this)
+ err=ZIP_ERRNO;
+
+ if (err==ZIP_OK)
+ err = add_data_in_datablock(&pziinit->central_dir,buf_read, (uLong)read_this);
+
+ size_central_dir_to_read-=read_this;
+ }
+ TRYFREE(buf_read);
+ }
+ pziinit->begin_pos = byte_before_the_zipfile;
+ pziinit->number_entry = number_entry_CD;
+
+ if (ZSEEK64(pziinit->z_filefunc, pziinit->filestream, offset_central_dir+byte_before_the_zipfile,ZLIB_FILEFUNC_SEEK_SET) != 0)
+ err=ZIP_ERRNO;
+
+ return err;
+}
+
+
+#endif /* !NO_ADDFILEINEXISTINGZIP*/
+
+
+/************************************************************/
+extern zipFile ZEXPORT zipOpen3 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_32_def* pzlib_filefunc64_32_def)
+{
+ zip64_internal ziinit;
+ zip64_internal* zi;
+ int err=ZIP_OK;
+
+ ziinit.z_filefunc.zseek32_file = NULL;
+ ziinit.z_filefunc.ztell32_file = NULL;
+ if (pzlib_filefunc64_32_def==NULL)
+ fill_fopen64_filefunc(&ziinit.z_filefunc.zfile_func64);
+ else
+ ziinit.z_filefunc = *pzlib_filefunc64_32_def;
+
+ ziinit.filestream = ZOPEN64(ziinit.z_filefunc,
+ pathname,
+ (append == APPEND_STATUS_CREATE) ?
+ (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_CREATE) :
+ (ZLIB_FILEFUNC_MODE_READ | ZLIB_FILEFUNC_MODE_WRITE | ZLIB_FILEFUNC_MODE_EXISTING));
+
+ if (ziinit.filestream == NULL)
+ return NULL;
+
+ if (append == APPEND_STATUS_CREATEAFTER)
+ ZSEEK64(ziinit.z_filefunc,ziinit.filestream,0,SEEK_END);
+
+ ziinit.begin_pos = ZTELL64(ziinit.z_filefunc,ziinit.filestream);
+ ziinit.in_opened_file_inzip = 0;
+ ziinit.ci.stream_initialised = 0;
+ ziinit.number_entry = 0;
+ ziinit.add_position_when_writting_offset = 0;
+ init_linkedlist(&(ziinit.central_dir));
+
+
+
+ zi = (zip64_internal*)ALLOC(sizeof(zip64_internal));
+ if (zi==NULL)
+ {
+ ZCLOSE64(ziinit.z_filefunc,ziinit.filestream);
+ return NULL;
+ }
+
+ /* now we add file in a zipfile */
+# ifndef NO_ADDFILEINEXISTINGZIP
+ ziinit.globalcomment = NULL;
+ if (append == APPEND_STATUS_ADDINZIP)
+ {
+ // Read and Cache Central Directory Records
+ err = LoadCentralDirectoryRecord(&ziinit);
+ }
+
+ if (globalcomment)
+ {
+ *globalcomment = ziinit.globalcomment;
+ }
+# endif /* !NO_ADDFILEINEXISTINGZIP*/
+
+ if (err != ZIP_OK)
+ {
+# ifndef NO_ADDFILEINEXISTINGZIP
+ TRYFREE(ziinit.globalcomment);
+# endif /* !NO_ADDFILEINEXISTINGZIP*/
+ TRYFREE(zi);
+ return NULL;
+ }
+ else
+ {
+ *zi = ziinit;
+ return (zipFile)zi;
+ }
+}
+
+extern zipFile ZEXPORT zipOpen2 (const char *pathname, int append, zipcharpc* globalcomment, zlib_filefunc_def* pzlib_filefunc32_def)
+{
+ if (pzlib_filefunc32_def != NULL)
+ {
+ zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+ fill_zlib_filefunc64_32_def_from_filefunc32(&zlib_filefunc64_32_def_fill,pzlib_filefunc32_def);
+ return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill);
+ }
+ else
+ return zipOpen3(pathname, append, globalcomment, NULL);
+}
+
+extern zipFile ZEXPORT zipOpen2_64 (const void *pathname, int append, zipcharpc* globalcomment, zlib_filefunc64_def* pzlib_filefunc_def)
+{
+ if (pzlib_filefunc_def != NULL)
+ {
+ zlib_filefunc64_32_def zlib_filefunc64_32_def_fill;
+ zlib_filefunc64_32_def_fill.zfile_func64 = *pzlib_filefunc_def;
+ zlib_filefunc64_32_def_fill.ztell32_file = NULL;
+ zlib_filefunc64_32_def_fill.zseek32_file = NULL;
+ return zipOpen3(pathname, append, globalcomment, &zlib_filefunc64_32_def_fill);
+ }
+ else
+ return zipOpen3(pathname, append, globalcomment, NULL);
+}
+
+
+
+extern zipFile ZEXPORT zipOpen (const char* pathname, int append)
+{
+ return zipOpen3((const void*)pathname,append,NULL,NULL);
+}
+
+extern zipFile ZEXPORT zipOpen64 (const void* pathname, int append)
+{
+ return zipOpen3(pathname,append,NULL,NULL);
+}
+
+int Write_LocalFileHeader(zip64_internal* zi, const char* filename, uInt size_extrafield_local, const void* extrafield_local)
+{
+ /* write the local header */
+ int err;
+ uInt size_filename = (uInt)strlen(filename);
+ uInt size_extrafield = size_extrafield_local;
+
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)LOCALHEADERMAGIC, 4);
+
+ if (err==ZIP_OK)
+ {
+ if(zi->ci.zip64)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);/* version needed to extract */
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)20,2);/* version needed to extract */
+ }
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.flag,2);
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.method,2);
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->ci.dosDate,4);
+
+ // CRC / Compressed size / Uncompressed size will be filled in later and rewritten later
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* crc 32, unknown */
+ if (err==ZIP_OK)
+ {
+ if(zi->ci.zip64)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* compressed size, unknown */
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* compressed size, unknown */
+ }
+ if (err==ZIP_OK)
+ {
+ if(zi->ci.zip64)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xFFFFFFFF,4); /* uncompressed size, unknown */
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4); /* uncompressed size, unknown */
+ }
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_filename,2);
+
+ if(zi->ci.zip64)
+ {
+ size_extrafield += 20;
+ }
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_extrafield,2);
+
+ if ((err==ZIP_OK) && (size_filename > 0))
+ {
+ if (ZWRITE64(zi->z_filefunc,zi->filestream,filename,size_filename)!=size_filename)
+ err = ZIP_ERRNO;
+ }
+
+ if ((err==ZIP_OK) && (size_extrafield_local > 0))
+ {
+ if (ZWRITE64(zi->z_filefunc, zi->filestream, extrafield_local, size_extrafield_local) != size_extrafield_local)
+ err = ZIP_ERRNO;
+ }
+
+
+ if ((err==ZIP_OK) && (zi->ci.zip64))
+ {
+ // write the Zip64 extended info
+ short HeaderID = 1;
+ short DataSize = 16;
+ ZPOS64_T CompressedSize = 0;
+ ZPOS64_T UncompressedSize = 0;
+
+ // Remember position of Zip64 extended info for the local file header. (needed when we update size after done with file)
+ zi->ci.pos_zip64extrainfo = ZTELL64(zi->z_filefunc,zi->filestream);
+
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)HeaderID,2);
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (short)DataSize,2);
+
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)UncompressedSize,8);
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, (ZPOS64_T)CompressedSize,8);
+ }
+
+ return err;
+}
+
+/*
+ NOTE.
+ When writing RAW the ZIP64 extended information in extrafield_local and extrafield_global needs to be stripped
+ before calling this function it can be done with zipRemoveExtraInfoBlock
+
+ It is not done here because then we need to realloc a new buffer since parameters are 'const' and I want to minimize
+ unnecessary allocations.
+ */
+extern int ZEXPORT zipOpenNewFileInZip4_64 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw,
+ int windowBits,int memLevel, int strategy,
+ const char* password, uLong crcForCrypting,
+ uLong versionMadeBy, uLong flagBase, int zip64)
+{
+ zip64_internal* zi;
+ uInt size_filename;
+ uInt size_comment;
+ uInt i;
+ int err = ZIP_OK;
+
+# ifdef NOCRYPT
+ if (password != NULL)
+ return ZIP_PARAMERROR;
+# endif
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+
+#ifdef HAVE_BZIP2
+ if ((method!=0) && (method!=Z_DEFLATED) && (method!=Z_BZIP2ED))
+ return ZIP_PARAMERROR;
+#else
+ if ((method!=0) && (method!=Z_DEFLATED))
+ return ZIP_PARAMERROR;
+#endif
+
+ zi = (zip64_internal*)file;
+
+ if (zi->in_opened_file_inzip == 1)
+ {
+ err = zipCloseFileInZip (file);
+ if (err != ZIP_OK)
+ return err;
+ }
+
+ if (filename==NULL)
+ filename="-";
+
+ if (comment==NULL)
+ size_comment = 0;
+ else
+ size_comment = (uInt)strlen(comment);
+
+ size_filename = (uInt)strlen(filename);
+
+ if (zipfi == NULL)
+ zi->ci.dosDate = 0;
+ else
+ {
+ if (zipfi->dosDate != 0)
+ zi->ci.dosDate = zipfi->dosDate;
+ else
+ zi->ci.dosDate = zip64local_TmzDateToDosDate(&zipfi->tmz_date);
+ }
+
+ zi->ci.flag = flagBase;
+ if ((level==8) || (level==9))
+ zi->ci.flag |= 2;
+ if ((level==2))
+ zi->ci.flag |= 4;
+ if ((level==1))
+ zi->ci.flag |= 6;
+ if (password != NULL)
+ zi->ci.flag |= 1;
+
+ zi->ci.crc32 = 0;
+ zi->ci.method = method;
+ zi->ci.encrypt = 0;
+ zi->ci.stream_initialised = 0;
+ zi->ci.pos_in_buffered_data = 0;
+ zi->ci.raw = raw;
+ zi->ci.pos_local_header = ZTELL64(zi->z_filefunc,zi->filestream);
+
+ zi->ci.size_centralheader = SIZECENTRALHEADER + size_filename + size_extrafield_global + size_comment;
+ zi->ci.size_centralExtraFree = 32; // Extra space we have reserved in case we need to add ZIP64 extra info data
+
+ zi->ci.central_header = (char*)ALLOC((uInt)zi->ci.size_centralheader + zi->ci.size_centralExtraFree);
+
+ zi->ci.size_centralExtra = size_extrafield_global;
+ zip64local_putValue_inmemory(zi->ci.central_header,(uLong)CENTRALHEADERMAGIC,4);
+ /* version info */
+ zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)versionMadeBy,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)20,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+8,(uLong)zi->ci.flag,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+10,(uLong)zi->ci.method,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+12,(uLong)zi->ci.dosDate,4);
+ zip64local_putValue_inmemory(zi->ci.central_header+16,(uLong)0,4); /*crc*/
+ zip64local_putValue_inmemory(zi->ci.central_header+20,(uLong)0,4); /*compr size*/
+ zip64local_putValue_inmemory(zi->ci.central_header+24,(uLong)0,4); /*uncompr size*/
+ zip64local_putValue_inmemory(zi->ci.central_header+28,(uLong)size_filename,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)size_extrafield_global,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+32,(uLong)size_comment,2);
+ zip64local_putValue_inmemory(zi->ci.central_header+34,(uLong)0,2); /*disk nm start*/
+
+ if (zipfi==NULL)
+ zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)0,2);
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)zipfi->internal_fa,2);
+
+ if (zipfi==NULL)
+ zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)0,4);
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+38,(uLong)zipfi->external_fa,4);
+
+ if(zi->ci.pos_local_header >= 0xffffffff)
+ zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)0xffffffff,4);
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+42,(uLong)zi->ci.pos_local_header - zi->add_position_when_writting_offset,4);
+
+ for (i=0;i<size_filename;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+i) = *(filename+i);
+
+ for (i=0;i<size_extrafield_global;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+i) =
+ *(((const char*)extrafield_global)+i);
+
+ for (i=0;i<size_comment;i++)
+ *(zi->ci.central_header+SIZECENTRALHEADER+size_filename+
+ size_extrafield_global+i) = *(comment+i);
+ if (zi->ci.central_header == NULL)
+ return ZIP_INTERNALERROR;
+
+ zi->ci.zip64 = zip64;
+ zi->ci.totalCompressedData = 0;
+ zi->ci.totalUncompressedData = 0;
+ zi->ci.pos_zip64extrainfo = 0;
+
+ err = Write_LocalFileHeader(zi, filename, size_extrafield_local, extrafield_local);
+
+#ifdef HAVE_BZIP2
+ zi->ci.bstream.avail_in = (uInt)0;
+ zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
+ zi->ci.bstream.total_in_hi32 = 0;
+ zi->ci.bstream.total_in_lo32 = 0;
+ zi->ci.bstream.total_out_hi32 = 0;
+ zi->ci.bstream.total_out_lo32 = 0;
+#endif
+
+ zi->ci.stream.avail_in = (uInt)0;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ zi->ci.stream.total_in = 0;
+ zi->ci.stream.total_out = 0;
+ zi->ci.stream.data_type = Z_BINARY;
+
+#ifdef HAVE_BZIP2
+ if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED || zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
+#else
+ if ((err==ZIP_OK) && (zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+#endif
+ {
+ if(zi->ci.method == Z_DEFLATED)
+ {
+ zi->ci.stream.zalloc = (alloc_func)0;
+ zi->ci.stream.zfree = (free_func)0;
+ zi->ci.stream.opaque = (voidpf)0;
+
+ if (windowBits>0)
+ windowBits = -windowBits;
+
+ err = deflateInit2(&zi->ci.stream, level, Z_DEFLATED, windowBits, memLevel, strategy);
+
+ if (err==Z_OK)
+ zi->ci.stream_initialised = Z_DEFLATED;
+ }
+ else if(zi->ci.method == Z_BZIP2ED)
+ {
+#ifdef HAVE_BZIP2
+ // Init BZip stuff here
+ zi->ci.bstream.bzalloc = 0;
+ zi->ci.bstream.bzfree = 0;
+ zi->ci.bstream.opaque = (voidpf)0;
+
+ err = BZ2_bzCompressInit(&zi->ci.bstream, level, 0,35);
+ if(err == BZ_OK)
+ zi->ci.stream_initialised = Z_BZIP2ED;
+#endif
+ }
+
+ }
+
+# ifndef NOCRYPT
+ zi->ci.crypt_header_size = 0;
+ if ((err==Z_OK) && (password != NULL))
+ {
+ unsigned char bufHead[RAND_HEAD_LEN];
+ unsigned int sizeHead;
+ zi->ci.encrypt = 1;
+ zi->ci.pcrc_32_tab = get_crc_table();
+ /*init_keys(password,zi->ci.keys,zi->ci.pcrc_32_tab);*/
+
+ sizeHead=crypthead(password,bufHead,RAND_HEAD_LEN,zi->ci.keys,zi->ci.pcrc_32_tab,crcForCrypting);
+ zi->ci.crypt_header_size = sizeHead;
+
+ if (ZWRITE64(zi->z_filefunc,zi->filestream,bufHead,sizeHead) != sizeHead)
+ err = ZIP_ERRNO;
+ }
+# endif
+
+ if (err==Z_OK)
+ zi->in_opened_file_inzip = 1;
+ return err;
+}
+
+extern int ZEXPORT zipOpenNewFileInZip4 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw,
+ int windowBits,int memLevel, int strategy,
+ const char* password, uLong crcForCrypting,
+ uLong versionMadeBy, uLong flagBase)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ windowBits, memLevel, strategy,
+ password, crcForCrypting, versionMadeBy, flagBase, 0);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip3 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw,
+ int windowBits,int memLevel, int strategy,
+ const char* password, uLong crcForCrypting)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ windowBits, memLevel, strategy,
+ password, crcForCrypting, VERSIONMADEBY, 0, 0);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip3_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw,
+ int windowBits,int memLevel, int strategy,
+ const char* password, uLong crcForCrypting, int zip64)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ windowBits, memLevel, strategy,
+ password, crcForCrypting, VERSIONMADEBY, 0, zip64);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip2(zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0, VERSIONMADEBY, 0, 0);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip2_64(zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void* extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int raw, int zip64)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, raw,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0, VERSIONMADEBY, 0, zip64);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip64 (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void*extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level, int zip64)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, 0,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0, VERSIONMADEBY, 0, zip64);
+}
+
+extern int ZEXPORT zipOpenNewFileInZip (zipFile file, const char* filename, const zip_fileinfo* zipfi,
+ const void* extrafield_local, uInt size_extrafield_local,
+ const void*extrafield_global, uInt size_extrafield_global,
+ const char* comment, int method, int level)
+{
+ return zipOpenNewFileInZip4_64 (file, filename, zipfi,
+ extrafield_local, size_extrafield_local,
+ extrafield_global, size_extrafield_global,
+ comment, method, level, 0,
+ -MAX_WBITS, DEF_MEM_LEVEL, Z_DEFAULT_STRATEGY,
+ NULL, 0, VERSIONMADEBY, 0, 0);
+}
+
+local int zip64FlushWriteBuffer(zip64_internal* zi)
+{
+ int err=ZIP_OK;
+
+ if (zi->ci.encrypt != 0)
+ {
+#ifndef NOCRYPT
+ uInt i;
+ int t;
+ for (i=0;i<zi->ci.pos_in_buffered_data;i++)
+ zi->ci.buffered_data[i] = zencode(zi->ci.keys, zi->ci.pcrc_32_tab, zi->ci.buffered_data[i],t);
+#endif
+ }
+
+ if (ZWRITE64(zi->z_filefunc,zi->filestream,zi->ci.buffered_data,zi->ci.pos_in_buffered_data) != zi->ci.pos_in_buffered_data)
+ err = ZIP_ERRNO;
+
+ zi->ci.totalCompressedData += zi->ci.pos_in_buffered_data;
+
+#ifdef HAVE_BZIP2
+ if(zi->ci.method == Z_BZIP2ED)
+ {
+ zi->ci.totalUncompressedData += zi->ci.bstream.total_in_lo32;
+ zi->ci.bstream.total_in_lo32 = 0;
+ zi->ci.bstream.total_in_hi32 = 0;
+ }
+ else
+#endif
+ {
+ zi->ci.totalUncompressedData += zi->ci.stream.total_in;
+ zi->ci.stream.total_in = 0;
+ }
+
+
+ zi->ci.pos_in_buffered_data = 0;
+
+ return err;
+}
+
+extern int ZEXPORT zipWriteInFileInZip (zipFile file,const void* buf,unsigned int len)
+{
+ zip64_internal* zi;
+ int err=ZIP_OK;
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+ zi = (zip64_internal*)file;
+
+ if (zi->in_opened_file_inzip == 0)
+ return ZIP_PARAMERROR;
+
+ zi->ci.crc32 = crc32(zi->ci.crc32,buf,(uInt)len);
+
+#ifdef HAVE_BZIP2
+ if(zi->ci.method == Z_BZIP2ED && (!zi->ci.raw))
+ {
+ zi->ci.bstream.next_in = (void*)buf;
+ zi->ci.bstream.avail_in = len;
+ err = BZ_RUN_OK;
+
+ while ((err==BZ_RUN_OK) && (zi->ci.bstream.avail_in>0))
+ {
+ if (zi->ci.bstream.avail_out == 0)
+ {
+ if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
+ }
+
+
+ if(err != BZ_RUN_OK)
+ break;
+
+ if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
+ {
+ uLong uTotalOutBefore_lo = zi->ci.bstream.total_out_lo32;
+// uLong uTotalOutBefore_hi = zi->ci.bstream.total_out_hi32;
+ err=BZ2_bzCompress(&zi->ci.bstream, BZ_RUN);
+
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore_lo) ;
+ }
+ }
+
+ if(err == BZ_RUN_OK)
+ err = ZIP_OK;
+ }
+ else
+#endif
+ {
+ zi->ci.stream.next_in = (Bytef*)buf;
+ zi->ci.stream.avail_in = len;
+
+ while ((err==ZIP_OK) && (zi->ci.stream.avail_in>0))
+ {
+ if (zi->ci.stream.avail_out == 0)
+ {
+ if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ }
+
+
+ if(err != ZIP_OK)
+ break;
+
+ if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+ {
+ uLong uTotalOutBefore = zi->ci.stream.total_out;
+ err=deflate(&zi->ci.stream, Z_NO_FLUSH);
+ if(uTotalOutBefore > zi->ci.stream.total_out)
+ {
+ int bBreak = 0;
+ bBreak++;
+ }
+
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
+ }
+ else
+ {
+ uInt copy_this,i;
+ if (zi->ci.stream.avail_in < zi->ci.stream.avail_out)
+ copy_this = zi->ci.stream.avail_in;
+ else
+ copy_this = zi->ci.stream.avail_out;
+
+ for (i = 0; i < copy_this; i++)
+ *(((char*)zi->ci.stream.next_out)+i) =
+ *(((const char*)zi->ci.stream.next_in)+i);
+ {
+ zi->ci.stream.avail_in -= copy_this;
+ zi->ci.stream.avail_out-= copy_this;
+ zi->ci.stream.next_in+= copy_this;
+ zi->ci.stream.next_out+= copy_this;
+ zi->ci.stream.total_in+= copy_this;
+ zi->ci.stream.total_out+= copy_this;
+ zi->ci.pos_in_buffered_data += copy_this;
+ }
+ }
+ }// while(...)
+ }
+
+ return err;
+}
+
+extern int ZEXPORT zipCloseFileInZipRaw (zipFile file, uLong uncompressed_size, uLong crc32)
+{
+ return zipCloseFileInZipRaw64 (file, uncompressed_size, crc32);
+}
+
+extern int ZEXPORT zipCloseFileInZipRaw64 (zipFile file, ZPOS64_T uncompressed_size, uLong crc32)
+{
+ zip64_internal* zi;
+ ZPOS64_T compressed_size;
+ uLong invalidValue = 0xffffffff;
+ short datasize = 0;
+ int err=ZIP_OK;
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+ zi = (zip64_internal*)file;
+
+ if (zi->in_opened_file_inzip == 0)
+ return ZIP_PARAMERROR;
+ zi->ci.stream.avail_in = 0;
+
+ if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+ {
+ while (err==ZIP_OK)
+ {
+ uLong uTotalOutBefore;
+ if (zi->ci.stream.avail_out == 0)
+ {
+ if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.stream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.stream.next_out = zi->ci.buffered_data;
+ }
+ uTotalOutBefore = zi->ci.stream.total_out;
+ err=deflate(&zi->ci.stream, Z_FINISH);
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.stream.total_out - uTotalOutBefore) ;
+ }
+ }
+ else if ((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
+ {
+#ifdef HAVE_BZIP2
+ err = BZ_FINISH_OK;
+ while (err==BZ_FINISH_OK)
+ {
+ uLong uTotalOutBefore;
+ if (zi->ci.bstream.avail_out == 0)
+ {
+ if (zip64FlushWriteBuffer(zi) == ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ zi->ci.bstream.avail_out = (uInt)Z_BUFSIZE;
+ zi->ci.bstream.next_out = (char*)zi->ci.buffered_data;
+ }
+ uTotalOutBefore = zi->ci.bstream.total_out_lo32;
+ err=BZ2_bzCompress(&zi->ci.bstream, BZ_FINISH);
+ if(err == BZ_STREAM_END)
+ err = Z_STREAM_END;
+
+ zi->ci.pos_in_buffered_data += (uInt)(zi->ci.bstream.total_out_lo32 - uTotalOutBefore);
+ }
+
+ if(err == BZ_FINISH_OK)
+ err = ZIP_OK;
+#endif
+ }
+
+ if (err==Z_STREAM_END)
+ err=ZIP_OK; /* this is normal */
+
+ if ((zi->ci.pos_in_buffered_data>0) && (err==ZIP_OK))
+ {
+ if (zip64FlushWriteBuffer(zi)==ZIP_ERRNO)
+ err = ZIP_ERRNO;
+ }
+
+ if ((zi->ci.method == Z_DEFLATED) && (!zi->ci.raw))
+ {
+ int tmp_err = deflateEnd(&zi->ci.stream);
+ if (err == ZIP_OK)
+ err = tmp_err;
+ zi->ci.stream_initialised = 0;
+ }
+#ifdef HAVE_BZIP2
+ else if((zi->ci.method == Z_BZIP2ED) && (!zi->ci.raw))
+ {
+ int tmperr = BZ2_bzCompressEnd(&zi->ci.bstream);
+ if (err==ZIP_OK)
+ err = tmperr;
+ zi->ci.stream_initialised = 0;
+ }
+#endif
+
+ if (!zi->ci.raw)
+ {
+ crc32 = (uLong)zi->ci.crc32;
+ uncompressed_size = zi->ci.totalUncompressedData;
+ }
+ compressed_size = zi->ci.totalCompressedData;
+
+# ifndef NOCRYPT
+ compressed_size += zi->ci.crypt_header_size;
+# endif
+
+ // update Current Item crc and sizes,
+ if(compressed_size >= 0xffffffff || uncompressed_size >= 0xffffffff || zi->ci.pos_local_header >= 0xffffffff)
+ {
+ /*version Made by*/
+ zip64local_putValue_inmemory(zi->ci.central_header+4,(uLong)45,2);
+ /*version needed*/
+ zip64local_putValue_inmemory(zi->ci.central_header+6,(uLong)45,2);
+
+ }
+
+ zip64local_putValue_inmemory(zi->ci.central_header+16,crc32,4); /*crc*/
+
+
+ if(compressed_size >= 0xffffffff)
+ zip64local_putValue_inmemory(zi->ci.central_header+20, invalidValue,4); /*compr size*/
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+20, compressed_size,4); /*compr size*/
+
+ /// set internal file attributes field
+ if (zi->ci.stream.data_type == Z_ASCII)
+ zip64local_putValue_inmemory(zi->ci.central_header+36,(uLong)Z_ASCII,2);
+
+ if(uncompressed_size >= 0xffffffff)
+ zip64local_putValue_inmemory(zi->ci.central_header+24, invalidValue,4); /*uncompr size*/
+ else
+ zip64local_putValue_inmemory(zi->ci.central_header+24, uncompressed_size,4); /*uncompr size*/
+
+ // Add ZIP64 extra info field for uncompressed size
+ if(uncompressed_size >= 0xffffffff)
+ datasize += 8;
+
+ // Add ZIP64 extra info field for compressed size
+ if(compressed_size >= 0xffffffff)
+ datasize += 8;
+
+ // Add ZIP64 extra info field for relative offset to local file header of current file
+ if(zi->ci.pos_local_header >= 0xffffffff)
+ datasize += 8;
+
+ if(datasize > 0)
+ {
+ char* p = NULL;
+
+ if((uLong)(datasize + 4) > zi->ci.size_centralExtraFree)
+ {
+ // we can not write more data to the buffer that we have room for.
+ return ZIP_BADZIPFILE;
+ }
+
+ p = zi->ci.central_header + zi->ci.size_centralheader;
+
+ // Add Extra Information Header for 'ZIP64 information'
+ zip64local_putValue_inmemory(p, 0x0001, 2); // HeaderID
+ p += 2;
+ zip64local_putValue_inmemory(p, datasize, 2); // DataSize
+ p += 2;
+
+ if(uncompressed_size >= 0xffffffff)
+ {
+ zip64local_putValue_inmemory(p, uncompressed_size, 8);
+ p += 8;
+ }
+
+ if(compressed_size >= 0xffffffff)
+ {
+ zip64local_putValue_inmemory(p, compressed_size, 8);
+ p += 8;
+ }
+
+ if(zi->ci.pos_local_header >= 0xffffffff)
+ {
+ zip64local_putValue_inmemory(p, zi->ci.pos_local_header, 8);
+ p += 8;
+ }
+
+ // Update how much extra free space we got in the memory buffer
+ // and increase the centralheader size so the new ZIP64 fields are included
+ // ( 4 below is the size of HeaderID and DataSize field )
+ zi->ci.size_centralExtraFree -= datasize + 4;
+ zi->ci.size_centralheader += datasize + 4;
+
+ // Update the extra info size field
+ zi->ci.size_centralExtra += datasize + 4;
+ zip64local_putValue_inmemory(zi->ci.central_header+30,(uLong)zi->ci.size_centralExtra,2);
+ }
+
+ if (err==ZIP_OK)
+ err = add_data_in_datablock(&zi->central_dir, zi->ci.central_header, (uLong)zi->ci.size_centralheader);
+
+ free(zi->ci.central_header);
+
+ if (err==ZIP_OK)
+ {
+ // Update the LocalFileHeader with the new values.
+
+ ZPOS64_T cur_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream);
+
+ if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_local_header + 14,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err = ZIP_ERRNO;
+
+ if (err==ZIP_OK)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,crc32,4); /* crc 32, unknown */
+
+ if(uncompressed_size >= 0xffffffff)
+ {
+ if(zi->ci.pos_zip64extrainfo > 0)
+ {
+ // Update the size in the ZIP64 extended field.
+ if (ZSEEK64(zi->z_filefunc,zi->filestream, zi->ci.pos_zip64extrainfo + 4,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err = ZIP_ERRNO;
+
+ if (err==ZIP_OK) /* compressed size, unknown */
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, uncompressed_size, 8);
+
+ if (err==ZIP_OK) /* uncompressed size, unknown */
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, compressed_size, 8);
+ }
+ }
+ else
+ {
+ if (err==ZIP_OK) /* compressed size, unknown */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,compressed_size,4);
+
+ if (err==ZIP_OK) /* uncompressed size, unknown */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,uncompressed_size,4);
+ }
+
+ if (ZSEEK64(zi->z_filefunc,zi->filestream, cur_pos_inzip,ZLIB_FILEFUNC_SEEK_SET)!=0)
+ err = ZIP_ERRNO;
+ }
+
+ zi->number_entry ++;
+ zi->in_opened_file_inzip = 0;
+
+ return err;
+}
+
+extern int ZEXPORT zipCloseFileInZip (zipFile file)
+{
+ return zipCloseFileInZipRaw (file,0,0);
+}
+
+int Write_Zip64EndOfCentralDirectoryLocator(zip64_internal* zi, ZPOS64_T zip64eocd_pos_inzip)
+{
+ int err = ZIP_OK;
+ ZPOS64_T pos = zip64eocd_pos_inzip - zi->add_position_when_writting_offset;
+
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDLOCHEADERMAGIC,4);
+
+ /*num disks*/
+ if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);
+
+ /*relative offset*/
+ if (err==ZIP_OK) /* Relative offset to the Zip64EndOfCentralDirectory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, pos,8);
+
+ /*total disks*/ /* Do not support spawning of disk so always say 1 here*/
+ if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)1,4);
+
+ return err;
+}
+
+int Write_Zip64EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip)
+{
+ int err = ZIP_OK;
+
+ uLong Zip64DataSize = 44;
+
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ZIP64ENDHEADERMAGIC,4);
+
+ if (err==ZIP_OK) /* size of this 'zip64 end of central directory' */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)Zip64DataSize,8); // why ZPOS64_T of this ?
+
+ if (err==ZIP_OK) /* version made by */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);
+
+ if (err==ZIP_OK) /* version needed */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)45,2);
+
+ if (err==ZIP_OK) /* number of this disk */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);
+
+ if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,4);
+
+ if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8);
+
+ if (err==ZIP_OK) /* total number of entries in the central dir */
+ err = zip64local_putValue(&zi->z_filefunc, zi->filestream, zi->number_entry, 8);
+
+ if (err==ZIP_OK) /* size of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(ZPOS64_T)size_centraldir,8);
+
+ if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */
+ {
+ ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (ZPOS64_T)pos,8);
+ }
+ return err;
+}
+int Write_EndOfCentralDirectoryRecord(zip64_internal* zi, uLong size_centraldir, ZPOS64_T centraldir_pos_inzip)
+{
+ int err = ZIP_OK;
+
+ /*signature*/
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)ENDHEADERMAGIC,4);
+
+ if (err==ZIP_OK) /* number of this disk */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
+
+ if (err==ZIP_OK) /* number of the disk with the start of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0,2);
+
+ if (err==ZIP_OK) /* total number of entries in the central dir on this disk */
+ {
+ {
+ if(zi->number_entry >= 0xFFFF)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
+ }
+ }
+
+ if (err==ZIP_OK) /* total number of entries in the central dir */
+ {
+ if(zi->number_entry >= 0xFFFF)
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)0xffff,2); // use value in ZIP64 record
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)zi->number_entry,2);
+ }
+
+ if (err==ZIP_OK) /* size of the central directory */
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_centraldir,4);
+
+ if (err==ZIP_OK) /* offset of start of central directory with respect to the starting disk number */
+ {
+ ZPOS64_T pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
+ if(pos >= 0xffffffff)
+ {
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)0xffffffff,4);
+ }
+ else
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream, (uLong)(centraldir_pos_inzip - zi->add_position_when_writting_offset),4);
+ }
+
+ return err;
+}
+
+int Write_GlobalComment(zip64_internal* zi, const char* global_comment)
+{
+ int err = ZIP_OK;
+ uInt size_global_comment = 0;
+
+ if(global_comment != NULL)
+ size_global_comment = (uInt)strlen(global_comment);
+
+ err = zip64local_putValue(&zi->z_filefunc,zi->filestream,(uLong)size_global_comment,2);
+
+ if (err == ZIP_OK && size_global_comment > 0)
+ {
+ if (ZWRITE64(zi->z_filefunc,zi->filestream, global_comment, size_global_comment) != size_global_comment)
+ err = ZIP_ERRNO;
+ }
+ return err;
+}
+
+extern int ZEXPORT zipClose (zipFile file, const char* global_comment)
+{
+ zip64_internal* zi;
+ int err = 0;
+ uLong size_centraldir = 0;
+ ZPOS64_T centraldir_pos_inzip;
+ ZPOS64_T pos;
+
+ if (file == NULL)
+ return ZIP_PARAMERROR;
+
+ zi = (zip64_internal*)file;
+
+ if (zi->in_opened_file_inzip == 1)
+ {
+ err = zipCloseFileInZip (file);
+ }
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+ if (global_comment==NULL)
+ global_comment = zi->globalcomment;
+#endif
+
+ centraldir_pos_inzip = ZTELL64(zi->z_filefunc,zi->filestream);
+
+ if (err==ZIP_OK)
+ {
+ linkedlist_datablock_internal* ldi = zi->central_dir.first_block;
+ while (ldi!=NULL)
+ {
+ if ((err==ZIP_OK) && (ldi->filled_in_this_block>0))
+ {
+ if (ZWRITE64(zi->z_filefunc,zi->filestream, ldi->data, ldi->filled_in_this_block) != ldi->filled_in_this_block)
+ err = ZIP_ERRNO;
+ }
+
+ size_centraldir += ldi->filled_in_this_block;
+ ldi = ldi->next_datablock;
+ }
+ }
+ free_linkedlist(&(zi->central_dir));
+
+ pos = centraldir_pos_inzip - zi->add_position_when_writting_offset;
+ if(pos >= 0xffffffff)
+ {
+ ZPOS64_T Zip64EOCDpos = ZTELL64(zi->z_filefunc,zi->filestream);
+ Write_Zip64EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip);
+
+ Write_Zip64EndOfCentralDirectoryLocator(zi, Zip64EOCDpos);
+ }
+
+ if (err==ZIP_OK)
+ err = Write_EndOfCentralDirectoryRecord(zi, size_centraldir, centraldir_pos_inzip);
+
+ if(err == ZIP_OK)
+ err = Write_GlobalComment(zi, global_comment);
+
+ if (ZCLOSE64(zi->z_filefunc,zi->filestream) != 0)
+ if (err == ZIP_OK)
+ err = ZIP_ERRNO;
+
+#ifndef NO_ADDFILEINEXISTINGZIP
+ TRYFREE(zi->globalcomment);
+#endif
+ TRYFREE(zi);
+
+ return err;
+}
+
+extern int ZEXPORT zipRemoveExtraInfoBlock (char* pData, int* dataLen, short sHeader)
+{
+ char* p = pData;
+ int size = 0;
+ char* pNewHeader;
+ char* pTmp;
+ short header;
+ short dataSize;
+
+ int retVal = ZIP_OK;
+
+ if(pData == NULL || *dataLen < 4)
+ return ZIP_PARAMERROR;
+
+ pNewHeader = (char*)ALLOC(*dataLen);
+ pTmp = pNewHeader;
+
+ while(p < (pData + *dataLen))
+ {
+ header = *(short*)p;
+ dataSize = *(((short*)p)+1);
+
+ if( header == sHeader ) // Header found.
+ {
+ p += dataSize + 4; // skip it. do not copy to temp buffer
+ }
+ else
+ {
+ // Extra Info block should not be removed, So copy it to the temp buffer.
+ memcpy(pTmp, p, dataSize + 4);
+ p += dataSize + 4;
+ size += dataSize + 4;
+ }
+
+ }
+
+ if(size < *dataLen)
+ {
+ // clean old extra info block.
+ memset(pData,0, *dataLen);
+
+ // copy the new extra info block over the old
+ if(size > 0)
+ memcpy(pData, pNewHeader, size);
+
+ // set the new extra info size
+ *dataLen = size;
+
+ retVal = ZIP_OK;
+ }
+ else
+ retVal = ZIP_ERRNO;
+
+ TRYFREE(pNewHeader);
+
+ return retVal;
+}
diff --git a/plugins/BasicHistory/zip/zip.h b/plugins/BasicHistory/zip/zip.h
new file mode 100644
index 0000000000..8aaebb6234
--- /dev/null
+++ b/plugins/BasicHistory/zip/zip.h
@@ -0,0 +1,362 @@
+/* zip.h -- IO on .zip files using zlib
+ Version 1.1, February 14h, 2010
+ part of the MiniZip project - ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Copyright (C) 1998-2010 Gilles Vollant (minizip) ( http://www.winimage.com/zLibDll/minizip.html )
+
+ Modifications for Zip64 support
+ Copyright (C) 2009-2010 Mathias Svensson ( http://result42.com )
+
+ For more info read MiniZip_info.txt
+
+ ---------------------------------------------------------------------------
+
+ Condition of use and distribution are the same than zlib :
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ ---------------------------------------------------------------------------
+
+ Changes
+
+ See header of zip.h
+
+*/
+
+#ifndef _zip12_H
+#define _zip12_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//#define HAVE_BZIP2
+
+#ifndef _ZLIB_H
+#include "zlib.h"
+#endif
+
+#ifndef _ZLIBIOAPI_H
+#include "ioapi.h"
+#endif
+
+#ifdef HAVE_BZIP2
+#include "bzlib.h"
+#endif
+
+#define Z_BZIP2ED 12
+
+#if defined(STRICTZIP) || defined(STRICTZIPUNZIP)
+/* like the STRICT of WIN32, we define a pointer that cannot be converted
+ from (void*) without cast */
+typedef struct TagzipFile__ { int unused; } zipFile__;
+typedef zipFile__ *zipFile;
+#else
+typedef voidp zipFile;
+#endif
+
+#define ZIP_OK (0)
+#define ZIP_EOF (0)
+#define ZIP_ERRNO (Z_ERRNO)
+#define ZIP_PARAMERROR (-102)
+#define ZIP_BADZIPFILE (-103)
+#define ZIP_INTERNALERROR (-104)
+
+#ifndef DEF_MEM_LEVEL
+# if MAX_MEM_LEVEL >= 8
+# define DEF_MEM_LEVEL 8
+# else
+# define DEF_MEM_LEVEL MAX_MEM_LEVEL
+# endif
+#endif
+/* default memLevel */
+
+/* tm_zip contain date/time info */
+typedef struct tm_zip_s
+{
+ uInt tm_sec; /* seconds after the minute - [0,59] */
+ uInt tm_min; /* minutes after the hour - [0,59] */
+ uInt tm_hour; /* hours since midnight - [0,23] */
+ uInt tm_mday; /* day of the month - [1,31] */
+ uInt tm_mon; /* months since January - [0,11] */
+ uInt tm_year; /* years - [1980..2044] */
+} tm_zip;
+
+typedef struct
+{
+ tm_zip tmz_date; /* date in understandable format */
+ uLong dosDate; /* if dos_date == 0, tmu_date is used */
+/* uLong flag; */ /* general purpose bit flag 2 bytes */
+
+ uLong internal_fa; /* internal file attributes 2 bytes */
+ uLong external_fa; /* external file attributes 4 bytes */
+} zip_fileinfo;
+
+typedef const char* zipcharpc;
+
+
+#define APPEND_STATUS_CREATE (0)
+#define APPEND_STATUS_CREATEAFTER (1)
+#define APPEND_STATUS_ADDINZIP (2)
+
+extern zipFile ZEXPORT zipOpen OF((const char *pathname, int append));
+extern zipFile ZEXPORT zipOpen64 OF((const void *pathname, int append));
+/*
+ Create a zipfile.
+ pathname contain on Windows XP a filename like "c:\\zlib\\zlib113.zip" or on
+ an Unix computer "zlib/zlib113.zip".
+ if the file pathname exist and append==APPEND_STATUS_CREATEAFTER, the zip
+ will be created at the end of the file.
+ (useful if the file contain a self extractor code)
+ if the file pathname exist and append==APPEND_STATUS_ADDINZIP, we will
+ add files in existing zip (be sure you don't add file that doesn't exist)
+ If the zipfile cannot be opened, the return value is NULL.
+ Else, the return value is a zipFile Handle, usable with other function
+ of this zip package.
+*/
+
+/* Note : there is no delete function into a zipfile.
+ If you want delete file into a zipfile, you must open a zipfile, and create another
+ Of couse, you can use RAW reading and writing to copy the file you did not want delte
+*/
+
+extern zipFile ZEXPORT zipOpen2 OF((const char *pathname,
+ int append,
+ zipcharpc* globalcomment,
+ zlib_filefunc_def* pzlib_filefunc_def));
+
+extern zipFile ZEXPORT zipOpen2_64 OF((const void *pathname,
+ int append,
+ zipcharpc* globalcomment,
+ zlib_filefunc64_def* pzlib_filefunc_def));
+
+extern int ZEXPORT zipOpenNewFileInZip OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level));
+
+extern int ZEXPORT zipOpenNewFileInZip64 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int zip64));
+
+/*
+ Open a file in the ZIP for writing.
+ filename : the filename in zip (if NULL, '-' without quote will be used
+ *zipfi contain supplemental information
+ if extrafield_local!=NULL and size_extrafield_local>0, extrafield_local
+ contains the extrafield data the the local header
+ if extrafield_global!=NULL and size_extrafield_global>0, extrafield_global
+ contains the extrafield data the the local header
+ if comment != NULL, comment contain the comment string
+ method contain the compression method (0 for store, Z_DEFLATED for deflate)
+ level contain the level of compression (can be Z_DEFAULT_COMPRESSION)
+ zip64 is set to 1 if a zip64 extended information block should be added to the local file header.
+ this MUST be '1' if the uncompressed size is >= 0xffffffff.
+
+*/
+
+
+extern int ZEXPORT zipOpenNewFileInZip2 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw));
+
+
+extern int ZEXPORT zipOpenNewFileInZip2_64 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int zip64));
+/*
+ Same than zipOpenNewFileInZip, except if raw=1, we write raw file
+ */
+
+extern int ZEXPORT zipOpenNewFileInZip3 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char* password,
+ uLong crcForCrypting));
+
+extern int ZEXPORT zipOpenNewFileInZip3_64 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char* password,
+ uLong crcForCrypting,
+ int zip64
+ ));
+
+/*
+ Same than zipOpenNewFileInZip2, except
+ windowBits,memLevel,,strategy : see parameter strategy in deflateInit2
+ password : crypting password (NULL for no crypting)
+ crcForCrypting : crc of file to compress (needed for crypting)
+ */
+
+extern int ZEXPORT zipOpenNewFileInZip4 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char* password,
+ uLong crcForCrypting,
+ uLong versionMadeBy,
+ uLong flagBase
+ ));
+
+
+extern int ZEXPORT zipOpenNewFileInZip4_64 OF((zipFile file,
+ const char* filename,
+ const zip_fileinfo* zipfi,
+ const void* extrafield_local,
+ uInt size_extrafield_local,
+ const void* extrafield_global,
+ uInt size_extrafield_global,
+ const char* comment,
+ int method,
+ int level,
+ int raw,
+ int windowBits,
+ int memLevel,
+ int strategy,
+ const char* password,
+ uLong crcForCrypting,
+ uLong versionMadeBy,
+ uLong flagBase,
+ int zip64
+ ));
+/*
+ Same than zipOpenNewFileInZip4, except
+ versionMadeBy : value for Version made by field
+ flag : value for flag field (compression level info will be added)
+ */
+
+
+extern int ZEXPORT zipWriteInFileInZip OF((zipFile file,
+ const void* buf,
+ unsigned len));
+/*
+ Write data in the zipfile
+*/
+
+extern int ZEXPORT zipCloseFileInZip OF((zipFile file));
+/*
+ Close the current file in the zipfile
+*/
+
+extern int ZEXPORT zipCloseFileInZipRaw OF((zipFile file,
+ uLong uncompressed_size,
+ uLong crc32));
+
+extern int ZEXPORT zipCloseFileInZipRaw64 OF((zipFile file,
+ ZPOS64_T uncompressed_size,
+ uLong crc32));
+
+/*
+ Close the current file in the zipfile, for file opened with
+ parameter raw=1 in zipOpenNewFileInZip2
+ uncompressed_size and crc32 are value for the uncompressed size
+*/
+
+extern int ZEXPORT zipClose OF((zipFile file,
+ const char* global_comment));
+/*
+ Close the zipfile
+*/
+
+
+extern int ZEXPORT zipRemoveExtraInfoBlock OF((char* pData, int* dataLen, short sHeader));
+/*
+ zipRemoveExtraInfoBlock - Added by Mathias Svensson
+
+ Remove extra information block from a extra information data for the local file header or central directory header
+
+ It is needed to remove ZIP64 extra information blocks when before data is written if using RAW mode.
+
+ 0x0001 is the signature header for the ZIP64 extra information blocks
+
+ usage.
+ Remove ZIP64 Extra information from a central director extra field data
+ zipRemoveExtraInfoBlock(pCenDirExtraFieldData, &nCenDirExtraFieldDataLen, 0x0001);
+
+ Remove ZIP64 Extra information from a Local File Header extra field data
+ zipRemoveExtraInfoBlock(pLocalHeaderExtraFieldData, &nLocalHeaderExtraFieldDataLen, 0x0001);
+*/
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _zip64_H */
diff --git a/plugins/BasicHistory/zip/zlib.h b/plugins/BasicHistory/zip/zlib.h
new file mode 100644
index 0000000000..bfbba83e8e
--- /dev/null
+++ b/plugins/BasicHistory/zip/zlib.h
@@ -0,0 +1,1613 @@
+/* zlib.h -- interface of the 'zlib' general purpose compression library
+ version 1.2.5, April 19th, 2010
+
+ Copyright (C) 1995-2010 Jean-loup Gailly and Mark Adler
+
+ This software is provided 'as-is', without any express or implied
+ warranty. In no event will the authors be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this software must not be misrepresented; you must not
+ claim that you wrote the original software. If you use this software
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original software.
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Jean-loup Gailly Mark Adler
+ jloup@gzip.org madler@alumni.caltech.edu
+
+
+ The data format used by the zlib library is described by RFCs (Request for
+ Comments) 1950 to 1952 in the files http://www.ietf.org/rfc/rfc1950.txt
+ (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format).
+*/
+
+#ifndef ZLIB_H
+#define ZLIB_H
+
+#include "zconf.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define ZLIB_VERSION "1.2.5"
+#define ZLIB_VERNUM 0x1250
+#define ZLIB_VER_MAJOR 1
+#define ZLIB_VER_MINOR 2
+#define ZLIB_VER_REVISION 5
+#define ZLIB_VER_SUBREVISION 0
+
+/*
+ The 'zlib' compression library provides in-memory compression and
+ decompression functions, including integrity checks of the uncompressed data.
+ This version of the library supports only one compression method (deflation)
+ but other algorithms will be added later and will have the same stream
+ interface.
+
+ Compression can be done in a single step if the buffers are large enough,
+ or can be done by repeated calls of the compression function. In the latter
+ case, the application must provide more input and/or consume the output
+ (providing more output space) before each call.
+
+ The compressed data format used by default by the in-memory functions is
+ the zlib format, which is a zlib wrapper documented in RFC 1950, wrapped
+ around a deflate stream, which is itself documented in RFC 1951.
+
+ The library also supports reading and writing files in gzip (.gz) format
+ with an interface similar to that of stdio using the functions that start
+ with "gz". The gzip format is different from the zlib format. gzip is a
+ gzip wrapper, documented in RFC 1952, wrapped around a deflate stream.
+
+ This library can optionally read and write gzip streams in memory as well.
+
+ The zlib format was designed to be compact and fast for use in memory
+ and on communications channels. The gzip format was designed for single-
+ file compression on file systems, has a larger header than zlib to maintain
+ directory information, and uses a different, slower check method than zlib.
+
+ The library does not install any signal handler. The decoder checks
+ the consistency of the compressed data, so the library should never crash
+ even in case of corrupted input.
+*/
+
+typedef voidpf (*alloc_func) OF((voidpf opaque, uInt items, uInt size));
+typedef void (*free_func) OF((voidpf opaque, voidpf address));
+
+struct internal_state;
+
+typedef struct z_stream_s {
+ Bytef *next_in; /* next input byte */
+ uInt avail_in; /* number of bytes available at next_in */
+ uLong total_in; /* total nb of input bytes read so far */
+
+ Bytef *next_out; /* next output byte should be put there */
+ uInt avail_out; /* remaining free space at next_out */
+ uLong total_out; /* total nb of bytes output so far */
+
+ char *msg; /* last error message, NULL if no error */
+ struct internal_state FAR *state; /* not visible by applications */
+
+ alloc_func zalloc; /* used to allocate the internal state */
+ free_func zfree; /* used to free the internal state */
+ voidpf opaque; /* private data object passed to zalloc and zfree */
+
+ int data_type; /* best guess about the data type: binary or text */
+ uLong adler; /* adler32 value of the uncompressed data */
+ uLong reserved; /* reserved for future use */
+} z_stream;
+
+typedef z_stream FAR *z_streamp;
+
+/*
+ gzip header information passed to and from zlib routines. See RFC 1952
+ for more details on the meanings of these fields.
+*/
+typedef struct gz_header_s {
+ int text; /* true if compressed data believed to be text */
+ uLong time; /* modification time */
+ int xflags; /* extra flags (not used when writing a gzip file) */
+ int os; /* operating system */
+ Bytef *extra; /* pointer to extra field or Z_NULL if none */
+ uInt extra_len; /* extra field length (valid if extra != Z_NULL) */
+ uInt extra_max; /* space at extra (only when reading header) */
+ Bytef *name; /* pointer to zero-terminated file name or Z_NULL */
+ uInt name_max; /* space at name (only when reading header) */
+ Bytef *comment; /* pointer to zero-terminated comment or Z_NULL */
+ uInt comm_max; /* space at comment (only when reading header) */
+ int hcrc; /* true if there was or will be a header crc */
+ int done; /* true when done reading gzip header (not used
+ when writing a gzip file) */
+} gz_header;
+
+typedef gz_header FAR *gz_headerp;
+
+/*
+ The application must update next_in and avail_in when avail_in has dropped
+ to zero. It must update next_out and avail_out when avail_out has dropped
+ to zero. The application must initialize zalloc, zfree and opaque before
+ calling the init function. All other fields are set by the compression
+ library and must not be updated by the application.
+
+ The opaque value provided by the application will be passed as the first
+ parameter for calls of zalloc and zfree. This can be useful for custom
+ memory management. The compression library attaches no meaning to the
+ opaque value.
+
+ zalloc must return Z_NULL if there is not enough memory for the object.
+ If zlib is used in a multi-threaded application, zalloc and zfree must be
+ thread safe.
+
+ On 16-bit systems, the functions zalloc and zfree must be able to allocate
+ exactly 65536 bytes, but will not be required to allocate more than this if
+ the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, pointers
+ returned by zalloc for objects of exactly 65536 bytes *must* have their
+ offset normalized to zero. The default allocation function provided by this
+ library ensures this (see zutil.c). To reduce memory requirements and avoid
+ any allocation of 64K objects, at the expense of compression ratio, compile
+ the library with -DMAX_WBITS=14 (see zconf.h).
+
+ The fields total_in and total_out can be used for statistics or progress
+ reports. After compression, total_in holds the total size of the
+ uncompressed data and may be saved for use in the decompressor (particularly
+ if the decompressor wants to decompress everything in a single step).
+*/
+
+ /* constants */
+
+#define Z_NO_FLUSH 0
+#define Z_PARTIAL_FLUSH 1
+#define Z_SYNC_FLUSH 2
+#define Z_FULL_FLUSH 3
+#define Z_FINISH 4
+#define Z_BLOCK 5
+#define Z_TREES 6
+/* Allowed flush values; see deflate() and inflate() below for details */
+
+#define Z_OK 0
+#define Z_STREAM_END 1
+#define Z_NEED_DICT 2
+#define Z_ERRNO (-1)
+#define Z_STREAM_ERROR (-2)
+#define Z_DATA_ERROR (-3)
+#define Z_MEM_ERROR (-4)
+#define Z_BUF_ERROR (-5)
+#define Z_VERSION_ERROR (-6)
+/* Return codes for the compression/decompression functions. Negative values
+ * are errors, positive values are used for special but normal events.
+ */
+
+#define Z_NO_COMPRESSION 0
+#define Z_BEST_SPEED 1
+#define Z_BEST_COMPRESSION 9
+#define Z_DEFAULT_COMPRESSION (-1)
+/* compression levels */
+
+#define Z_FILTERED 1
+#define Z_HUFFMAN_ONLY 2
+#define Z_RLE 3
+#define Z_FIXED 4
+#define Z_DEFAULT_STRATEGY 0
+/* compression strategy; see deflateInit2() below for details */
+
+#define Z_BINARY 0
+#define Z_TEXT 1
+#define Z_ASCII Z_TEXT /* for compatibility with 1.2.2 and earlier */
+#define Z_UNKNOWN 2
+/* Possible values of the data_type field (though see inflate()) */
+
+#define Z_DEFLATED 8
+/* The deflate compression method (the only one supported in this version) */
+
+#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */
+
+#define zlib_version zlibVersion()
+/* for compatibility with versions < 1.0.2 */
+
+
+ /* basic functions */
+
+ZEXTERN const char * ZEXPORT zlibVersion OF((void));
+/* The application can compare zlibVersion and ZLIB_VERSION for consistency.
+ If the first character differs, the library code actually used is not
+ compatible with the zlib.h header file used by the application. This check
+ is automatically made by deflateInit and inflateInit.
+ */
+
+/*
+ZEXTERN int ZEXPORT deflateInit OF((z_streamp strm, int level));
+
+ Initializes the internal stream state for compression. The fields
+ zalloc, zfree and opaque must be initialized before by the caller. If
+ zalloc and zfree are set to Z_NULL, deflateInit updates them to use default
+ allocation functions.
+
+ The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9:
+ 1 gives best speed, 9 gives best compression, 0 gives no compression at all
+ (the input data is simply copied a block at a time). Z_DEFAULT_COMPRESSION
+ requests a default compromise between speed and compression (currently
+ equivalent to level 6).
+
+ deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if level is not a valid compression level, or
+ Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible
+ with the version assumed by the caller (ZLIB_VERSION). msg is set to null
+ if there is no error message. deflateInit does not perform any compression:
+ this will be done by deflate().
+*/
+
+
+ZEXTERN int ZEXPORT deflate OF((z_streamp strm, int flush));
+/*
+ deflate compresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. deflate performs one or both of the
+ following actions:
+
+ - Compress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in and avail_in are updated and
+ processing will resume at this point for the next call of deflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. This action is forced if the parameter flush is non zero.
+ Forcing flush frequently degrades the compression ratio, so this parameter
+ should be set only when necessary (in interactive applications). Some
+ output may be provided even if flush is not set.
+
+ Before the call of deflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming more
+ output, and updating avail_in or avail_out accordingly; avail_out should
+ never be zero before the call. The application can consume the compressed
+ output when it wants, for example when the output buffer is full (avail_out
+ == 0), or after each call of deflate(). If deflate returns Z_OK and with
+ zero avail_out, it must be called again after making room in the output
+ buffer because there might be more output pending.
+
+ Normally the parameter flush is set to Z_NO_FLUSH, which allows deflate to
+ decide how much data to accumulate before producing output, in order to
+ maximize compression.
+
+ If the parameter flush is set to Z_SYNC_FLUSH, all pending output is
+ flushed to the output buffer and the output is aligned on a byte boundary, so
+ that the decompressor can get all input data available so far. (In
+ particular avail_in is zero after the call if enough output space has been
+ provided before the call.) Flushing may degrade compression for some
+ compression algorithms and so it should be used only when necessary. This
+ completes the current deflate block and follows it with an empty stored block
+ that is three bits plus filler bits to the next byte, followed by four bytes
+ (00 00 ff ff).
+
+ If flush is set to Z_PARTIAL_FLUSH, all pending output is flushed to the
+ output buffer, but the output is not aligned to a byte boundary. All of the
+ input data so far will be available to the decompressor, as for Z_SYNC_FLUSH.
+ This completes the current deflate block and follows it with an empty fixed
+ codes block that is 10 bits long. This assures that enough bytes are output
+ in order for the decompressor to finish the block before the empty fixed code
+ block.
+
+ If flush is set to Z_BLOCK, a deflate block is completed and emitted, as
+ for Z_SYNC_FLUSH, but the output is not aligned on a byte boundary, and up to
+ seven bits of the current block are held to be written as the next byte after
+ the next deflate block is completed. In this case, the decompressor may not
+ be provided enough bits at this point in order to complete decompression of
+ the data provided so far to the compressor. It may need to wait for the next
+ block to be emitted. This is for advanced applications that need to control
+ the emission of deflate blocks.
+
+ If flush is set to Z_FULL_FLUSH, all output is flushed as with
+ Z_SYNC_FLUSH, and the compression state is reset so that decompression can
+ restart from this point if previous compressed data has been damaged or if
+ random access is desired. Using Z_FULL_FLUSH too often can seriously degrade
+ compression.
+
+ If deflate returns with avail_out == 0, this function must be called again
+ with the same value of the flush parameter and more output space (updated
+ avail_out), until the flush is complete (deflate returns with non-zero
+ avail_out). In the case of a Z_FULL_FLUSH or Z_SYNC_FLUSH, make sure that
+ avail_out is greater than six to avoid repeated flush markers due to
+ avail_out == 0 on return.
+
+ If the parameter flush is set to Z_FINISH, pending input is processed,
+ pending output is flushed and deflate returns with Z_STREAM_END if there was
+ enough output space; if deflate returns with Z_OK, this function must be
+ called again with Z_FINISH and more output space (updated avail_out) but no
+ more input data, until it returns with Z_STREAM_END or an error. After
+ deflate has returned Z_STREAM_END, the only possible operations on the stream
+ are deflateReset or deflateEnd.
+
+ Z_FINISH can be used immediately after deflateInit if all the compression
+ is to be done in a single step. In this case, avail_out must be at least the
+ value returned by deflateBound (see below). If deflate does not return
+ Z_STREAM_END, then it must be called again as described above.
+
+ deflate() sets strm->adler to the adler32 checksum of all input read
+ so far (that is, total_in bytes).
+
+ deflate() may update strm->data_type if it can make a good guess about
+ the input data type (Z_BINARY or Z_TEXT). In doubt, the data is considered
+ binary. This field is only for information purposes and does not affect the
+ compression algorithm in any manner.
+
+ deflate() returns Z_OK if some progress has been made (more input
+ processed or more output produced), Z_STREAM_END if all input has been
+ consumed and all output has been produced (only when flush is set to
+ Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example
+ if next_in or next_out was Z_NULL), Z_BUF_ERROR if no progress is possible
+ (for example avail_in or avail_out was zero). Note that Z_BUF_ERROR is not
+ fatal, and deflate() can be called again with more input and more output
+ space to continue compressing.
+*/
+
+
+ZEXTERN int ZEXPORT deflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any pending
+ output.
+
+ deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the
+ stream state was inconsistent, Z_DATA_ERROR if the stream was freed
+ prematurely (some input or output was discarded). In the error case, msg
+ may be set but then points to a static string (which must not be
+ deallocated).
+*/
+
+
+/*
+ZEXTERN int ZEXPORT inflateInit OF((z_streamp strm));
+
+ Initializes the internal stream state for decompression. The fields
+ next_in, avail_in, zalloc, zfree and opaque must be initialized before by
+ the caller. If next_in is not Z_NULL and avail_in is large enough (the
+ exact value depends on the compression method), inflateInit determines the
+ compression method from the zlib header and allocates all data structures
+ accordingly; otherwise the allocation will be deferred to the first call of
+ inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to
+ use default allocation functions.
+
+ inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+ invalid, such as a null pointer to the structure. msg is set to null if
+ there is no error message. inflateInit does not perform any decompression
+ apart from possibly reading the zlib header if present: actual decompression
+ will be done by inflate(). (So next_in and avail_in may be modified, but
+ next_out and avail_out are unused and unchanged.) The current implementation
+ of inflateInit() does not process any header information -- that is deferred
+ until inflate() is called.
+*/
+
+
+ZEXTERN int ZEXPORT inflate OF((z_streamp strm, int flush));
+/*
+ inflate decompresses as much data as possible, and stops when the input
+ buffer becomes empty or the output buffer becomes full. It may introduce
+ some output latency (reading input without producing any output) except when
+ forced to flush.
+
+ The detailed semantics are as follows. inflate performs one or both of the
+ following actions:
+
+ - Decompress more input starting at next_in and update next_in and avail_in
+ accordingly. If not all input can be processed (because there is not
+ enough room in the output buffer), next_in is updated and processing will
+ resume at this point for the next call of inflate().
+
+ - Provide more output starting at next_out and update next_out and avail_out
+ accordingly. inflate() provides as much output as possible, until there is
+ no more input data or no more space in the output buffer (see below about
+ the flush parameter).
+
+ Before the call of inflate(), the application should ensure that at least
+ one of the actions is possible, by providing more input and/or consuming more
+ output, and updating the next_* and avail_* values accordingly. The
+ application can consume the uncompressed output when it wants, for example
+ when the output buffer is full (avail_out == 0), or after each call of
+ inflate(). If inflate returns Z_OK and with zero avail_out, it must be
+ called again after making room in the output buffer because there might be
+ more output pending.
+
+ The flush parameter of inflate() can be Z_NO_FLUSH, Z_SYNC_FLUSH, Z_FINISH,
+ Z_BLOCK, or Z_TREES. Z_SYNC_FLUSH requests that inflate() flush as much
+ output as possible to the output buffer. Z_BLOCK requests that inflate()
+ stop if and when it gets to the next deflate block boundary. When decoding
+ the zlib or gzip format, this will cause inflate() to return immediately
+ after the header and before the first block. When doing a raw inflate,
+ inflate() will go ahead and process the first block, and will return when it
+ gets to the end of that block, or when it runs out of data.
+
+ The Z_BLOCK option assists in appending to or combining deflate streams.
+ Also to assist in this, on return inflate() will set strm->data_type to the
+ number of unused bits in the last byte taken from strm->next_in, plus 64 if
+ inflate() is currently decoding the last block in the deflate stream, plus
+ 128 if inflate() returned immediately after decoding an end-of-block code or
+ decoding the complete header up to just before the first byte of the deflate
+ stream. The end-of-block will not be indicated until all of the uncompressed
+ data from that block has been written to strm->next_out. The number of
+ unused bits may in general be greater than seven, except when bit 7 of
+ data_type is set, in which case the number of unused bits will be less than
+ eight. data_type is set as noted here every time inflate() returns for all
+ flush options, and so can be used to determine the amount of currently
+ consumed input in bits.
+
+ The Z_TREES option behaves as Z_BLOCK does, but it also returns when the
+ end of each deflate block header is reached, before any actual data in that
+ block is decoded. This allows the caller to determine the length of the
+ deflate block header for later use in random access within a deflate block.
+ 256 is added to the value of strm->data_type when inflate() returns
+ immediately after reaching the end of the deflate block header.
+
+ inflate() should normally be called until it returns Z_STREAM_END or an
+ error. However if all decompression is to be performed in a single step (a
+ single call of inflate), the parameter flush should be set to Z_FINISH. In
+ this case all pending input is processed and all pending output is flushed;
+ avail_out must be large enough to hold all the uncompressed data. (The size
+ of the uncompressed data may have been saved by the compressor for this
+ purpose.) The next operation on this stream must be inflateEnd to deallocate
+ the decompression state. The use of Z_FINISH is never required, but can be
+ used to inform inflate that a faster approach may be used for the single
+ inflate() call.
+
+ In this implementation, inflate() always flushes as much output as
+ possible to the output buffer, and always uses the faster approach on the
+ first call. So the only effect of the flush parameter in this implementation
+ is on the return value of inflate(), as noted below, or when it returns early
+ because Z_BLOCK or Z_TREES is used.
+
+ If a preset dictionary is needed after this call (see inflateSetDictionary
+ below), inflate sets strm->adler to the adler32 checksum of the dictionary
+ chosen by the compressor and returns Z_NEED_DICT; otherwise it sets
+ strm->adler to the adler32 checksum of all output produced so far (that is,
+ total_out bytes) and returns Z_OK, Z_STREAM_END or an error code as described
+ below. At the end of the stream, inflate() checks that its computed adler32
+ checksum is equal to that saved by the compressor and returns Z_STREAM_END
+ only if the checksum is correct.
+
+ inflate() can decompress and check either zlib-wrapped or gzip-wrapped
+ deflate data. The header type is detected automatically, if requested when
+ initializing with inflateInit2(). Any information contained in the gzip
+ header is not retained, so applications that need that information should
+ instead use raw inflate, see inflateInit2() below, or inflateBack() and
+ perform their own processing of the gzip header and trailer.
+
+ inflate() returns Z_OK if some progress has been made (more input processed
+ or more output produced), Z_STREAM_END if the end of the compressed data has
+ been reached and all uncompressed output has been produced, Z_NEED_DICT if a
+ preset dictionary is needed at this point, Z_DATA_ERROR if the input data was
+ corrupted (input stream not conforming to the zlib format or incorrect check
+ value), Z_STREAM_ERROR if the stream structure was inconsistent (for example
+ next_in or next_out was Z_NULL), Z_MEM_ERROR if there was not enough memory,
+ Z_BUF_ERROR if no progress is possible or if there was not enough room in the
+ output buffer when Z_FINISH is used. Note that Z_BUF_ERROR is not fatal, and
+ inflate() can be called again with more input and more output space to
+ continue decompressing. If Z_DATA_ERROR is returned, the application may
+ then call inflateSync() to look for a good compression block if a partial
+ recovery of the data is desired.
+*/
+
+
+ZEXTERN int ZEXPORT inflateEnd OF((z_streamp strm));
+/*
+ All dynamically allocated data structures for this stream are freed.
+ This function discards any unprocessed input and does not flush any pending
+ output.
+
+ inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state
+ was inconsistent. In the error case, msg may be set but then points to a
+ static string (which must not be deallocated).
+*/
+
+
+ /* Advanced functions */
+
+/*
+ The following functions are needed only in some special applications.
+*/
+
+/*
+ZEXTERN int ZEXPORT deflateInit2 OF((z_streamp strm,
+ int level,
+ int method,
+ int windowBits,
+ int memLevel,
+ int strategy));
+
+ This is another version of deflateInit with more compression options. The
+ fields next_in, zalloc, zfree and opaque must be initialized before by the
+ caller.
+
+ The method parameter is the compression method. It must be Z_DEFLATED in
+ this version of the library.
+
+ The windowBits parameter is the base two logarithm of the window size
+ (the size of the history buffer). It should be in the range 8..15 for this
+ version of the library. Larger values of this parameter result in better
+ compression at the expense of memory usage. The default value is 15 if
+ deflateInit is used instead.
+
+ windowBits can also be -8..-15 for raw deflate. In this case, -windowBits
+ determines the window size. deflate() will then generate raw deflate data
+ with no zlib header or trailer, and will not compute an adler32 check value.
+
+ windowBits can also be greater than 15 for optional gzip encoding. Add
+ 16 to windowBits to write a simple gzip header and trailer around the
+ compressed data instead of a zlib wrapper. The gzip header will have no
+ file name, no extra data, no comment, no modification time (set to zero), no
+ header crc, and the operating system will be set to 255 (unknown). If a
+ gzip stream is being written, strm->adler is a crc32 instead of an adler32.
+
+ The memLevel parameter specifies how much memory should be allocated
+ for the internal compression state. memLevel=1 uses minimum memory but is
+ slow and reduces compression ratio; memLevel=9 uses maximum memory for
+ optimal speed. The default value is 8. See zconf.h for total memory usage
+ as a function of windowBits and memLevel.
+
+ The strategy parameter is used to tune the compression algorithm. Use the
+ value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a
+ filter (or predictor), Z_HUFFMAN_ONLY to force Huffman encoding only (no
+ string match), or Z_RLE to limit match distances to one (run-length
+ encoding). Filtered data consists mostly of small values with a somewhat
+ random distribution. In this case, the compression algorithm is tuned to
+ compress them better. The effect of Z_FILTERED is to force more Huffman
+ coding and less string matching; it is somewhat intermediate between
+ Z_DEFAULT_STRATEGY and Z_HUFFMAN_ONLY. Z_RLE is designed to be almost as
+ fast as Z_HUFFMAN_ONLY, but give better compression for PNG image data. The
+ strategy parameter only affects the compression ratio but not the
+ correctness of the compressed output even if it is not set appropriately.
+ Z_FIXED prevents the use of dynamic Huffman codes, allowing for a simpler
+ decoder for special applications.
+
+ deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_STREAM_ERROR if any parameter is invalid (such as an invalid
+ method), or Z_VERSION_ERROR if the zlib library version (zlib_version) is
+ incompatible with the version assumed by the caller (ZLIB_VERSION). msg is
+ set to null if there is no error message. deflateInit2 does not perform any
+ compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the compression dictionary from the given byte sequence
+ without producing any compressed output. This function must be called
+ immediately after deflateInit, deflateInit2 or deflateReset, before any call
+ of deflate. The compressor and decompressor must use exactly the same
+ dictionary (see inflateSetDictionary).
+
+ The dictionary should consist of strings (byte sequences) that are likely
+ to be encountered later in the data to be compressed, with the most commonly
+ used strings preferably put towards the end of the dictionary. Using a
+ dictionary is most useful when the data to be compressed is short and can be
+ predicted with good accuracy; the data can then be compressed better than
+ with the default empty dictionary.
+
+ Depending on the size of the compression data structures selected by
+ deflateInit or deflateInit2, a part of the dictionary may in effect be
+ discarded, for example if the dictionary is larger than the window size
+ provided in deflateInit or deflateInit2. Thus the strings most likely to be
+ useful should be put at the end of the dictionary, not at the front. In
+ addition, the current implementation of deflate will use at most the window
+ size minus 262 bytes of the provided dictionary.
+
+ Upon return of this function, strm->adler is set to the adler32 value
+ of the dictionary; the decompressor may later use this value to determine
+ which dictionary has been used by the compressor. (The adler32 value
+ applies to the whole dictionary even if only a subset of the dictionary is
+ actually used by the compressor.) If a raw deflate was requested, then the
+ adler32 value is not computed and strm->adler is not set.
+
+ deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a
+ parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
+ inconsistent (for example if deflate has already been called for this stream
+ or if the compression method is bsort). deflateSetDictionary does not
+ perform any compression: this will be done by deflate().
+*/
+
+ZEXTERN int ZEXPORT deflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when several compression strategies will be
+ tried, for example when there are several ways of pre-processing the input
+ data with a filter. The streams that will be discarded should then be freed
+ by calling deflateEnd. Note that deflateCopy duplicates the internal
+ compression state which can be quite large, so this strategy is slow and can
+ consume lots of memory.
+
+ deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being Z_NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT deflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to deflateEnd followed by deflateInit,
+ but does not free and reallocate all the internal compression state. The
+ stream will keep the same compression level and any other attributes that
+ may have been set by deflateInit2.
+
+ deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT deflateParams OF((z_streamp strm,
+ int level,
+ int strategy));
+/*
+ Dynamically update the compression level and compression strategy. The
+ interpretation of level and strategy is as in deflateInit2. This can be
+ used to switch between compression and straight copy of the input data, or
+ to switch to a different kind of input data requiring a different strategy.
+ If the compression level is changed, the input available so far is
+ compressed with the old level (and may be flushed); the new level will take
+ effect only at the next call of deflate().
+
+ Before the call of deflateParams, the stream state must be set as for
+ a call of deflate(), since the currently available input may have to be
+ compressed and flushed. In particular, strm->avail_out must be non-zero.
+
+ deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source
+ stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR if
+ strm->avail_out was zero.
+*/
+
+ZEXTERN int ZEXPORT deflateTune OF((z_streamp strm,
+ int good_length,
+ int max_lazy,
+ int nice_length,
+ int max_chain));
+/*
+ Fine tune deflate's internal compression parameters. This should only be
+ used by someone who understands the algorithm used by zlib's deflate for
+ searching for the best matching string, and even then only by the most
+ fanatic optimizer trying to squeeze out the last compressed bit for their
+ specific input data. Read the deflate.c source code for the meaning of the
+ max_lazy, good_length, nice_length, and max_chain parameters.
+
+ deflateTune() can be called after deflateInit() or deflateInit2(), and
+ returns Z_OK on success, or Z_STREAM_ERROR for an invalid deflate stream.
+ */
+
+ZEXTERN uLong ZEXPORT deflateBound OF((z_streamp strm,
+ uLong sourceLen));
+/*
+ deflateBound() returns an upper bound on the compressed size after
+ deflation of sourceLen bytes. It must be called after deflateInit() or
+ deflateInit2(), and after deflateSetHeader(), if used. This would be used
+ to allocate an output buffer for deflation in a single pass, and so would be
+ called before deflate().
+*/
+
+ZEXTERN int ZEXPORT deflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ deflatePrime() inserts bits in the deflate output stream. The intent
+ is that this function is used to start off the deflate output with the bits
+ leftover from a previous deflate stream when appending to it. As such, this
+ function can only be used for raw deflate, and must be used before the first
+ deflate() call after a deflateInit2() or deflateReset(). bits must be less
+ than or equal to 16, and that many of the least significant bits of value
+ will be inserted in the output.
+
+ deflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT deflateSetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ deflateSetHeader() provides gzip header information for when a gzip
+ stream is requested by deflateInit2(). deflateSetHeader() may be called
+ after deflateInit2() or deflateReset() and before the first call of
+ deflate(). The text, time, os, extra field, name, and comment information
+ in the provided gz_header structure are written to the gzip header (xflag is
+ ignored -- the extra flags are set according to the compression level). The
+ caller must assure that, if not Z_NULL, name and comment are terminated with
+ a zero byte, and that if extra is not Z_NULL, that extra_len bytes are
+ available there. If hcrc is true, a gzip header crc is included. Note that
+ the current versions of the command-line version of gzip (up through version
+ 1.3.x) do not support header crc's, and will report that it is a "multi-part
+ gzip file" and give up.
+
+ If deflateSetHeader is not used, the default gzip header has text false,
+ the time set to zero, and os set to 255, with no extra, name, or comment
+ fields. The gzip header is returned to the default state by deflateReset().
+
+ deflateSetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateInit2 OF((z_streamp strm,
+ int windowBits));
+
+ This is another version of inflateInit with an extra parameter. The
+ fields next_in, avail_in, zalloc, zfree and opaque must be initialized
+ before by the caller.
+
+ The windowBits parameter is the base two logarithm of the maximum window
+ size (the size of the history buffer). It should be in the range 8..15 for
+ this version of the library. The default value is 15 if inflateInit is used
+ instead. windowBits must be greater than or equal to the windowBits value
+ provided to deflateInit2() while compressing, or it must be equal to 15 if
+ deflateInit2() was not used. If a compressed stream with a larger window
+ size is given as input, inflate() will return with the error code
+ Z_DATA_ERROR instead of trying to allocate a larger window.
+
+ windowBits can also be zero to request that inflate use the window size in
+ the zlib header of the compressed stream.
+
+ windowBits can also be -8..-15 for raw inflate. In this case, -windowBits
+ determines the window size. inflate() will then process raw deflate data,
+ not looking for a zlib or gzip header, not generating a check value, and not
+ looking for any check values for comparison at the end of the stream. This
+ is for use with other formats that use the deflate compressed data format
+ such as zip. Those formats provide their own check values. If a custom
+ format is developed using the raw deflate format for compressed data, it is
+ recommended that a check value such as an adler32 or a crc32 be applied to
+ the uncompressed data as is done in the zlib, gzip, and zip formats. For
+ most applications, the zlib format should be used as is. Note that comments
+ above on the use in deflateInit2() applies to the magnitude of windowBits.
+
+ windowBits can also be greater than 15 for optional gzip decoding. Add
+ 32 to windowBits to enable zlib and gzip decoding with automatic header
+ detection, or add 16 to decode only the gzip format (the zlib format will
+ return a Z_DATA_ERROR). If a gzip stream is being decoded, strm->adler is a
+ crc32 instead of an adler32.
+
+ inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_VERSION_ERROR if the zlib library version is incompatible with the
+ version assumed by the caller, or Z_STREAM_ERROR if the parameters are
+ invalid, such as a null pointer to the structure. msg is set to null if
+ there is no error message. inflateInit2 does not perform any decompression
+ apart from possibly reading the zlib header if present: actual decompression
+ will be done by inflate(). (So next_in and avail_in may be modified, but
+ next_out and avail_out are unused and unchanged.) The current implementation
+ of inflateInit2() does not process any header information -- that is
+ deferred until inflate() is called.
+*/
+
+ZEXTERN int ZEXPORT inflateSetDictionary OF((z_streamp strm,
+ const Bytef *dictionary,
+ uInt dictLength));
+/*
+ Initializes the decompression dictionary from the given uncompressed byte
+ sequence. This function must be called immediately after a call of inflate,
+ if that call returned Z_NEED_DICT. The dictionary chosen by the compressor
+ can be determined from the adler32 value returned by that call of inflate.
+ The compressor and decompressor must use exactly the same dictionary (see
+ deflateSetDictionary). For raw inflate, this function can be called
+ immediately after inflateInit2() or inflateReset() and before any call of
+ inflate() to set the dictionary. The application must insure that the
+ dictionary that was used for compression is provided.
+
+ inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a
+ parameter is invalid (e.g. dictionary being Z_NULL) or the stream state is
+ inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the
+ expected one (incorrect adler32 value). inflateSetDictionary does not
+ perform any decompression: this will be done by subsequent calls of
+ inflate().
+*/
+
+ZEXTERN int ZEXPORT inflateSync OF((z_streamp strm));
+/*
+ Skips invalid compressed data until a full flush point (see above the
+ description of deflate with Z_FULL_FLUSH) can be found, or until all
+ available input is skipped. No output is provided.
+
+ inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR
+ if no more input was provided, Z_DATA_ERROR if no flush point has been
+ found, or Z_STREAM_ERROR if the stream structure was inconsistent. In the
+ success case, the application may save the current current value of total_in
+ which indicates where valid compressed data was found. In the error case,
+ the application may repeatedly call inflateSync, providing more input each
+ time, until success or end of the input data.
+*/
+
+ZEXTERN int ZEXPORT inflateCopy OF((z_streamp dest,
+ z_streamp source));
+/*
+ Sets the destination stream as a complete copy of the source stream.
+
+ This function can be useful when randomly accessing a large stream. The
+ first pass through the stream can periodically record the inflate state,
+ allowing restarting inflate at those points when randomly accessing the
+ stream.
+
+ inflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_STREAM_ERROR if the source stream state was inconsistent
+ (such as zalloc being Z_NULL). msg is left unchanged in both source and
+ destination.
+*/
+
+ZEXTERN int ZEXPORT inflateReset OF((z_streamp strm));
+/*
+ This function is equivalent to inflateEnd followed by inflateInit,
+ but does not free and reallocate all the internal decompression state. The
+ stream will keep attributes that may have been set by inflateInit2.
+
+ inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL).
+*/
+
+ZEXTERN int ZEXPORT inflateReset2 OF((z_streamp strm,
+ int windowBits));
+/*
+ This function is the same as inflateReset, but it also permits changing
+ the wrap and window size requests. The windowBits parameter is interpreted
+ the same as it is for inflateInit2.
+
+ inflateReset2 returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent (such as zalloc or state being Z_NULL), or if
+ the windowBits parameter is invalid.
+*/
+
+ZEXTERN int ZEXPORT inflatePrime OF((z_streamp strm,
+ int bits,
+ int value));
+/*
+ This function inserts bits in the inflate input stream. The intent is
+ that this function is used to start inflating at a bit position in the
+ middle of a byte. The provided bits will be used before any bytes are used
+ from next_in. This function should only be used with raw inflate, and
+ should be used before the first inflate() call after inflateInit2() or
+ inflateReset(). bits must be less than or equal to 16, and that many of the
+ least significant bits of value will be inserted in the input.
+
+ If bits is negative, then the input stream bit buffer is emptied. Then
+ inflatePrime() can be called again to put bits in the buffer. This is used
+ to clear out bits leftover after feeding inflate a block description prior
+ to feeding inflate codes.
+
+ inflatePrime returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+ZEXTERN long ZEXPORT inflateMark OF((z_streamp strm));
+/*
+ This function returns two values, one in the lower 16 bits of the return
+ value, and the other in the remaining upper bits, obtained by shifting the
+ return value down 16 bits. If the upper value is -1 and the lower value is
+ zero, then inflate() is currently decoding information outside of a block.
+ If the upper value is -1 and the lower value is non-zero, then inflate is in
+ the middle of a stored block, with the lower value equaling the number of
+ bytes from the input remaining to copy. If the upper value is not -1, then
+ it is the number of bits back from the current bit position in the input of
+ the code (literal or length/distance pair) currently being processed. In
+ that case the lower value is the number of bytes already emitted for that
+ code.
+
+ A code is being processed if inflate is waiting for more input to complete
+ decoding of the code, or if it has completed decoding but is waiting for
+ more output space to write the literal or match data.
+
+ inflateMark() is used to mark locations in the input data for random
+ access, which may be at bit positions, and to note those cases where the
+ output of a code may span boundaries of random access blocks. The current
+ location in the input stream can be determined from avail_in and data_type
+ as noted in the description for the Z_BLOCK flush parameter for inflate.
+
+ inflateMark returns the value noted above or -1 << 16 if the provided
+ source stream state was inconsistent.
+*/
+
+ZEXTERN int ZEXPORT inflateGetHeader OF((z_streamp strm,
+ gz_headerp head));
+/*
+ inflateGetHeader() requests that gzip header information be stored in the
+ provided gz_header structure. inflateGetHeader() may be called after
+ inflateInit2() or inflateReset(), and before the first call of inflate().
+ As inflate() processes the gzip stream, head->done is zero until the header
+ is completed, at which time head->done is set to one. If a zlib stream is
+ being decoded, then head->done is set to -1 to indicate that there will be
+ no gzip header information forthcoming. Note that Z_BLOCK or Z_TREES can be
+ used to force inflate() to return immediately after header processing is
+ complete and before any actual data is decompressed.
+
+ The text, time, xflags, and os fields are filled in with the gzip header
+ contents. hcrc is set to true if there is a header CRC. (The header CRC
+ was valid if done is set to one.) If extra is not Z_NULL, then extra_max
+ contains the maximum number of bytes to write to extra. Once done is true,
+ extra_len contains the actual extra field length, and extra contains the
+ extra field, or that field truncated if extra_max is less than extra_len.
+ If name is not Z_NULL, then up to name_max characters are written there,
+ terminated with a zero unless the length is greater than name_max. If
+ comment is not Z_NULL, then up to comm_max characters are written there,
+ terminated with a zero unless the length is greater than comm_max. When any
+ of extra, name, or comment are not Z_NULL and the respective field is not
+ present in the header, then that field is set to Z_NULL to signal its
+ absence. This allows the use of deflateSetHeader() with the returned
+ structure to duplicate the header. However if those fields are set to
+ allocated memory, then the application will need to save those pointers
+ elsewhere so that they can be eventually freed.
+
+ If inflateGetHeader is not used, then the header information is simply
+ discarded. The header is always checked for validity, including the header
+ CRC if present. inflateReset() will reset the process to discard the header
+ information. The application would need to call inflateGetHeader() again to
+ retrieve the header from the next gzip stream.
+
+ inflateGetHeader returns Z_OK if success, or Z_STREAM_ERROR if the source
+ stream state was inconsistent.
+*/
+
+/*
+ZEXTERN int ZEXPORT inflateBackInit OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window));
+
+ Initialize the internal stream state for decompression using inflateBack()
+ calls. The fields zalloc, zfree and opaque in strm must be initialized
+ before the call. If zalloc and zfree are Z_NULL, then the default library-
+ derived memory allocation routines are used. windowBits is the base two
+ logarithm of the window size, in the range 8..15. window is a caller
+ supplied buffer of that size. Except for special applications where it is
+ assured that deflate was used with small window sizes, windowBits must be 15
+ and a 32K byte window must be supplied to be able to decompress general
+ deflate streams.
+
+ See inflateBack() for the usage of these routines.
+
+ inflateBackInit will return Z_OK on success, Z_STREAM_ERROR if any of
+ the paramaters are invalid, Z_MEM_ERROR if the internal state could not be
+ allocated, or Z_VERSION_ERROR if the version of the library does not match
+ the version of the header file.
+*/
+
+typedef unsigned (*in_func) OF((void FAR *, unsigned char FAR * FAR *));
+typedef int (*out_func) OF((void FAR *, unsigned char FAR *, unsigned));
+
+ZEXTERN int ZEXPORT inflateBack OF((z_streamp strm,
+ in_func in, void FAR *in_desc,
+ out_func out, void FAR *out_desc));
+/*
+ inflateBack() does a raw inflate with a single call using a call-back
+ interface for input and output. This is more efficient than inflate() for
+ file i/o applications in that it avoids copying between the output and the
+ sliding window by simply making the window itself the output buffer. This
+ function trusts the application to not change the output buffer passed by
+ the output function, at least until inflateBack() returns.
+
+ inflateBackInit() must be called first to allocate the internal state
+ and to initialize the state with the user-provided window buffer.
+ inflateBack() may then be used multiple times to inflate a complete, raw
+ deflate stream with each call. inflateBackEnd() is then called to free the
+ allocated state.
+
+ A raw deflate stream is one with no zlib or gzip header or trailer.
+ This routine would normally be used in a utility that reads zip or gzip
+ files and writes out uncompressed files. The utility would decode the
+ header and process the trailer on its own, hence this routine expects only
+ the raw deflate stream to decompress. This is different from the normal
+ behavior of inflate(), which expects either a zlib or gzip header and
+ trailer around the deflate stream.
+
+ inflateBack() uses two subroutines supplied by the caller that are then
+ called by inflateBack() for input and output. inflateBack() calls those
+ routines until it reads a complete deflate stream and writes out all of the
+ uncompressed data, or until it encounters an error. The function's
+ parameters and return types are defined above in the in_func and out_func
+ typedefs. inflateBack() will call in(in_desc, &buf) which should return the
+ number of bytes of provided input, and a pointer to that input in buf. If
+ there is no input available, in() must return zero--buf is ignored in that
+ case--and inflateBack() will return a buffer error. inflateBack() will call
+ out(out_desc, buf, len) to write the uncompressed data buf[0..len-1]. out()
+ should return zero on success, or non-zero on failure. If out() returns
+ non-zero, inflateBack() will return with an error. Neither in() nor out()
+ are permitted to change the contents of the window provided to
+ inflateBackInit(), which is also the buffer that out() uses to write from.
+ The length written by out() will be at most the window size. Any non-zero
+ amount of input may be provided by in().
+
+ For convenience, inflateBack() can be provided input on the first call by
+ setting strm->next_in and strm->avail_in. If that input is exhausted, then
+ in() will be called. Therefore strm->next_in must be initialized before
+ calling inflateBack(). If strm->next_in is Z_NULL, then in() will be called
+ immediately for input. If strm->next_in is not Z_NULL, then strm->avail_in
+ must also be initialized, and then if strm->avail_in is not zero, input will
+ initially be taken from strm->next_in[0 .. strm->avail_in - 1].
+
+ The in_desc and out_desc parameters of inflateBack() is passed as the
+ first parameter of in() and out() respectively when they are called. These
+ descriptors can be optionally used to pass any information that the caller-
+ supplied in() and out() functions need to do their job.
+
+ On return, inflateBack() will set strm->next_in and strm->avail_in to
+ pass back any unused input that was provided by the last in() call. The
+ return values of inflateBack() can be Z_STREAM_END on success, Z_BUF_ERROR
+ if in() or out() returned an error, Z_DATA_ERROR if there was a format error
+ in the deflate stream (in which case strm->msg is set to indicate the nature
+ of the error), or Z_STREAM_ERROR if the stream was not properly initialized.
+ In the case of Z_BUF_ERROR, an input or output error can be distinguished
+ using strm->next_in which will be Z_NULL only if in() returned an error. If
+ strm->next_in is not Z_NULL, then the Z_BUF_ERROR was due to out() returning
+ non-zero. (in() will always be called before out(), so strm->next_in is
+ assured to be defined if out() returns non-zero.) Note that inflateBack()
+ cannot return Z_OK.
+*/
+
+ZEXTERN int ZEXPORT inflateBackEnd OF((z_streamp strm));
+/*
+ All memory allocated by inflateBackInit() is freed.
+
+ inflateBackEnd() returns Z_OK on success, or Z_STREAM_ERROR if the stream
+ state was inconsistent.
+*/
+
+ZEXTERN uLong ZEXPORT zlibCompileFlags OF((void));
+/* Return flags indicating compile-time options.
+
+ Type sizes, two bits each, 00 = 16 bits, 01 = 32, 10 = 64, 11 = other:
+ 1.0: size of uInt
+ 3.2: size of uLong
+ 5.4: size of voidpf (pointer)
+ 7.6: size of z_off_t
+
+ Compiler, assembler, and debug options:
+ 8: DEBUG
+ 9: ASMV or ASMINF -- use ASM code
+ 10: ZLIB_WINAPI -- exported functions use the WINAPI calling convention
+ 11: 0 (reserved)
+
+ One-time table building (smaller code, but not thread-safe if true):
+ 12: BUILDFIXED -- build static block decoding tables when needed
+ 13: DYNAMIC_CRC_TABLE -- build CRC calculation tables when needed
+ 14,15: 0 (reserved)
+
+ Library content (indicates missing functionality):
+ 16: NO_GZCOMPRESS -- gz* functions cannot compress (to avoid linking
+ deflate code when not needed)
+ 17: NO_GZIP -- deflate can't write gzip streams, and inflate can't detect
+ and decode gzip streams (to avoid linking crc code)
+ 18-19: 0 (reserved)
+
+ Operation variations (changes in library functionality):
+ 20: PKZIP_BUG_WORKAROUND -- slightly more permissive inflate
+ 21: FASTEST -- deflate algorithm with only one, lowest compression level
+ 22,23: 0 (reserved)
+
+ The sprintf variant used by gzprintf (zero is best):
+ 24: 0 = vs*, 1 = s* -- 1 means limited to 20 arguments after the format
+ 25: 0 = *nprintf, 1 = *printf -- 1 means gzprintf() not secure!
+ 26: 0 = returns value, 1 = void -- 1 means inferred string length returned
+
+ Remainder:
+ 27-31: 0 (reserved)
+ */
+
+
+ /* utility functions */
+
+/*
+ The following utility functions are implemented on top of the basic
+ stream-oriented functions. To simplify the interface, some default options
+ are assumed (compression level and memory usage, standard memory allocation
+ functions). The source code of these utility functions can be modified if
+ you need special options.
+*/
+
+ZEXTERN int ZEXPORT compress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Compresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total size
+ of the destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer.
+*/
+
+ZEXTERN int ZEXPORT compress2 OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen,
+ int level));
+/*
+ Compresses the source buffer into the destination buffer. The level
+ parameter has the same meaning as in deflateInit. sourceLen is the byte
+ length of the source buffer. Upon entry, destLen is the total size of the
+ destination buffer, which must be at least the value returned by
+ compressBound(sourceLen). Upon exit, destLen is the actual size of the
+ compressed buffer.
+
+ compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough
+ memory, Z_BUF_ERROR if there was not enough room in the output buffer,
+ Z_STREAM_ERROR if the level parameter is invalid.
+*/
+
+ZEXTERN uLong ZEXPORT compressBound OF((uLong sourceLen));
+/*
+ compressBound() returns an upper bound on the compressed size after
+ compress() or compress2() on sourceLen bytes. It would be used before a
+ compress() or compress2() call to allocate the destination buffer.
+*/
+
+ZEXTERN int ZEXPORT uncompress OF((Bytef *dest, uLongf *destLen,
+ const Bytef *source, uLong sourceLen));
+/*
+ Decompresses the source buffer into the destination buffer. sourceLen is
+ the byte length of the source buffer. Upon entry, destLen is the total size
+ of the destination buffer, which must be large enough to hold the entire
+ uncompressed data. (The size of the uncompressed data must have been saved
+ previously by the compressor and transmitted to the decompressor by some
+ mechanism outside the scope of this compression library.) Upon exit, destLen
+ is the actual size of the uncompressed buffer.
+
+ uncompress returns Z_OK if success, Z_MEM_ERROR if there was not
+ enough memory, Z_BUF_ERROR if there was not enough room in the output
+ buffer, or Z_DATA_ERROR if the input data was corrupted or incomplete.
+*/
+
+
+ /* gzip file access functions */
+
+/*
+ This library supports reading and writing files in gzip (.gz) format with
+ an interface similar to that of stdio, using the functions that start with
+ "gz". The gzip format is different from the zlib format. gzip is a gzip
+ wrapper, documented in RFC 1952, wrapped around a deflate stream.
+*/
+
+typedef voidp gzFile; /* opaque gzip file descriptor */
+
+/*
+ZEXTERN gzFile ZEXPORT gzopen OF((const char *path, const char *mode));
+
+ Opens a gzip (.gz) file for reading or writing. The mode parameter is as
+ in fopen ("rb" or "wb") but can also include a compression level ("wb9") or
+ a strategy: 'f' for filtered data as in "wb6f", 'h' for Huffman-only
+ compression as in "wb1h", 'R' for run-length encoding as in "wb1R", or 'F'
+ for fixed code compression as in "wb9F". (See the description of
+ deflateInit2 for more information about the strategy parameter.) Also "a"
+ can be used instead of "w" to request that the gzip stream that will be
+ written be appended to the file. "+" will result in an error, since reading
+ and writing to the same gzip file is not supported.
+
+ gzopen can be used to read a file which is not in gzip format; in this
+ case gzread will directly read from the file without decompression.
+
+ gzopen returns NULL if the file could not be opened, if there was
+ insufficient memory to allocate the gzFile state, or if an invalid mode was
+ specified (an 'r', 'w', or 'a' was not provided, or '+' was provided).
+ errno can be checked to determine if the reason gzopen failed was that the
+ file could not be opened.
+*/
+
+ZEXTERN gzFile ZEXPORT gzdopen OF((int fd, const char *mode));
+/*
+ gzdopen associates a gzFile with the file descriptor fd. File descriptors
+ are obtained from calls like open, dup, creat, pipe or fileno (if the file
+ has been previously opened with fopen). The mode parameter is as in gzopen.
+
+ The next call of gzclose on the returned gzFile will also close the file
+ descriptor fd, just like fclose(fdopen(fd, mode)) closes the file descriptor
+ fd. If you want to keep fd open, use fd = dup(fd_keep); gz = gzdopen(fd,
+ mode);. The duplicated descriptor should be saved to avoid a leak, since
+ gzdopen does not close fd if it fails.
+
+ gzdopen returns NULL if there was insufficient memory to allocate the
+ gzFile state, if an invalid mode was specified (an 'r', 'w', or 'a' was not
+ provided, or '+' was provided), or if fd is -1. The file descriptor is not
+ used until the next gz* read, write, seek, or close operation, so gzdopen
+ will not detect if fd is invalid (unless fd is -1).
+*/
+
+ZEXTERN int ZEXPORT gzbuffer OF((gzFile file, unsigned size));
+/*
+ Set the internal buffer size used by this library's functions. The
+ default buffer size is 8192 bytes. This function must be called after
+ gzopen() or gzdopen(), and before any other calls that read or write the
+ file. The buffer memory allocation is always deferred to the first read or
+ write. Two buffers are allocated, either both of the specified size when
+ writing, or one of the specified size and the other twice that size when
+ reading. A larger buffer size of, for example, 64K or 128K bytes will
+ noticeably increase the speed of decompression (reading).
+
+ The new buffer size also affects the maximum length for gzprintf().
+
+ gzbuffer() returns 0 on success, or -1 on failure, such as being called
+ too late.
+*/
+
+ZEXTERN int ZEXPORT gzsetparams OF((gzFile file, int level, int strategy));
+/*
+ Dynamically update the compression level or strategy. See the description
+ of deflateInit2 for the meaning of these parameters.
+
+ gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not
+ opened for writing.
+*/
+
+ZEXTERN int ZEXPORT gzread OF((gzFile file, voidp buf, unsigned len));
+/*
+ Reads the given number of uncompressed bytes from the compressed file. If
+ the input file was not in gzip format, gzread copies the given number of
+ bytes into the buffer.
+
+ After reaching the end of a gzip stream in the input, gzread will continue
+ to read, looking for another gzip stream, or failing that, reading the rest
+ of the input file directly without decompression. The entire input file
+ will be read if gzread is called until it returns less than the requested
+ len.
+
+ gzread returns the number of uncompressed bytes actually read, less than
+ len for end of file, or -1 for error.
+*/
+
+ZEXTERN int ZEXPORT gzwrite OF((gzFile file,
+ voidpc buf, unsigned len));
+/*
+ Writes the given number of uncompressed bytes into the compressed file.
+ gzwrite returns the number of uncompressed bytes written or 0 in case of
+ error.
+*/
+
+ZEXTERN int ZEXPORTVA gzprintf OF((gzFile file, const char *format, ...));
+/*
+ Converts, formats, and writes the arguments to the compressed file under
+ control of the format string, as in fprintf. gzprintf returns the number of
+ uncompressed bytes actually written, or 0 in case of error. The number of
+ uncompressed bytes written is limited to 8191, or one less than the buffer
+ size given to gzbuffer(). The caller should assure that this limit is not
+ exceeded. If it is exceeded, then gzprintf() will return an error (0) with
+ nothing written. In this case, there may also be a buffer overflow with
+ unpredictable consequences, which is possible only if zlib was compiled with
+ the insecure functions sprintf() or vsprintf() because the secure snprintf()
+ or vsnprintf() functions were not available. This can be determined using
+ zlibCompileFlags().
+*/
+
+ZEXTERN int ZEXPORT gzputs OF((gzFile file, const char *s));
+/*
+ Writes the given null-terminated string to the compressed file, excluding
+ the terminating null character.
+
+ gzputs returns the number of characters written, or -1 in case of error.
+*/
+
+ZEXTERN char * ZEXPORT gzgets OF((gzFile file, char *buf, int len));
+/*
+ Reads bytes from the compressed file until len-1 characters are read, or a
+ newline character is read and transferred to buf, or an end-of-file
+ condition is encountered. If any characters are read or if len == 1, the
+ string is terminated with a null character. If no characters are read due
+ to an end-of-file or len < 1, then the buffer is left untouched.
+
+ gzgets returns buf which is a null-terminated string, or it returns NULL
+ for end-of-file or in case of error. If there was an error, the contents at
+ buf are indeterminate.
+*/
+
+ZEXTERN int ZEXPORT gzputc OF((gzFile file, int c));
+/*
+ Writes c, converted to an unsigned char, into the compressed file. gzputc
+ returns the value that was written, or -1 in case of error.
+*/
+
+ZEXTERN int ZEXPORT gzgetc OF((gzFile file));
+/*
+ Reads one byte from the compressed file. gzgetc returns this byte or -1
+ in case of end of file or error.
+*/
+
+ZEXTERN int ZEXPORT gzungetc OF((int c, gzFile file));
+/*
+ Push one character back onto the stream to be read as the first character
+ on the next read. At least one character of push-back is allowed.
+ gzungetc() returns the character pushed, or -1 on failure. gzungetc() will
+ fail if c is -1, and may fail if a character has been pushed but not read
+ yet. If gzungetc is used immediately after gzopen or gzdopen, at least the
+ output buffer size of pushed characters is allowed. (See gzbuffer above.)
+ The pushed character will be discarded if the stream is repositioned with
+ gzseek() or gzrewind().
+*/
+
+ZEXTERN int ZEXPORT gzflush OF((gzFile file, int flush));
+/*
+ Flushes all pending output into the compressed file. The parameter flush
+ is as in the deflate() function. The return value is the zlib error number
+ (see function gzerror below). gzflush is only permitted when writing.
+
+ If the flush parameter is Z_FINISH, the remaining data is written and the
+ gzip stream is completed in the output. If gzwrite() is called again, a new
+ gzip stream will be started in the output. gzread() is able to read such
+ concatented gzip streams.
+
+ gzflush should be called only when strictly necessary because it will
+ degrade compression if called too often.
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile file,
+ z_off_t offset, int whence));
+
+ Sets the starting position for the next gzread or gzwrite on the given
+ compressed file. The offset represents a number of bytes in the
+ uncompressed data stream. The whence parameter is defined as in lseek(2);
+ the value SEEK_END is not supported.
+
+ If the file is opened for reading, this function is emulated but can be
+ extremely slow. If the file is opened for writing, only forward seeks are
+ supported; gzseek then compresses a sequence of zeroes up to the new
+ starting position.
+
+ gzseek returns the resulting offset location as measured in bytes from
+ the beginning of the uncompressed stream, or -1 in case of error, in
+ particular if the file is opened for writing and the new starting position
+ would be before the current position.
+*/
+
+ZEXTERN int ZEXPORT gzrewind OF((gzFile file));
+/*
+ Rewinds the given file. This function is supported only for reading.
+
+ gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gztell OF((gzFile file));
+
+ Returns the starting position for the next gzread or gzwrite on the given
+ compressed file. This position represents a number of bytes in the
+ uncompressed data stream, and is zero when starting, even if appending or
+ reading a gzip stream from the middle of a file using gzdopen().
+
+ gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR)
+*/
+
+/*
+ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile file));
+
+ Returns the current offset in the file being read or written. This offset
+ includes the count of bytes that precede the gzip stream, for example when
+ appending or when using gzdopen() for reading. When reading, the offset
+ does not include as yet unused buffered input. This information can be used
+ for a progress indicator. On error, gzoffset() returns -1.
+*/
+
+ZEXTERN int ZEXPORT gzeof OF((gzFile file));
+/*
+ Returns true (1) if the end-of-file indicator has been set while reading,
+ false (0) otherwise. Note that the end-of-file indicator is set only if the
+ read tried to go past the end of the input, but came up short. Therefore,
+ just like feof(), gzeof() may return false even if there is no more data to
+ read, in the event that the last read request was for the exact number of
+ bytes remaining in the input file. This will happen if the input file size
+ is an exact multiple of the buffer size.
+
+ If gzeof() returns true, then the read functions will return no more data,
+ unless the end-of-file indicator is reset by gzclearerr() and the input file
+ has grown since the previous end of file was detected.
+*/
+
+ZEXTERN int ZEXPORT gzdirect OF((gzFile file));
+/*
+ Returns true (1) if file is being copied directly while reading, or false
+ (0) if file is a gzip stream being decompressed. This state can change from
+ false to true while reading the input file if the end of a gzip stream is
+ reached, but is followed by data that is not another gzip stream.
+
+ If the input file is empty, gzdirect() will return true, since the input
+ does not contain a gzip stream.
+
+ If gzdirect() is used immediately after gzopen() or gzdopen() it will
+ cause buffers to be allocated to allow reading the file to determine if it
+ is a gzip file. Therefore if gzbuffer() is used, it should be called before
+ gzdirect().
+*/
+
+ZEXTERN int ZEXPORT gzclose OF((gzFile file));
+/*
+ Flushes all pending output if necessary, closes the compressed file and
+ deallocates the (de)compression state. Note that once file is closed, you
+ cannot call gzerror with file, since its structures have been deallocated.
+ gzclose must not be called more than once on the same file, just as free
+ must not be called more than once on the same allocation.
+
+ gzclose will return Z_STREAM_ERROR if file is not valid, Z_ERRNO on a
+ file operation error, or Z_OK on success.
+*/
+
+ZEXTERN int ZEXPORT gzclose_r OF((gzFile file));
+ZEXTERN int ZEXPORT gzclose_w OF((gzFile file));
+/*
+ Same as gzclose(), but gzclose_r() is only for use when reading, and
+ gzclose_w() is only for use when writing or appending. The advantage to
+ using these instead of gzclose() is that they avoid linking in zlib
+ compression or decompression code that is not used when only reading or only
+ writing respectively. If gzclose() is used, then both compression and
+ decompression code will be included the application when linking to a static
+ zlib library.
+*/
+
+ZEXTERN const char * ZEXPORT gzerror OF((gzFile file, int *errnum));
+/*
+ Returns the error message for the last error which occurred on the given
+ compressed file. errnum is set to zlib error number. If an error occurred
+ in the file system and not in the compression library, errnum is set to
+ Z_ERRNO and the application may consult errno to get the exact error code.
+
+ The application must not modify the returned string. Future calls to
+ this function may invalidate the previously returned string. If file is
+ closed, then the string previously returned by gzerror will no longer be
+ available.
+
+ gzerror() should be used to distinguish errors from end-of-file for those
+ functions above that do not distinguish those cases in their return values.
+*/
+
+ZEXTERN void ZEXPORT gzclearerr OF((gzFile file));
+/*
+ Clears the error and end-of-file flags for file. This is analogous to the
+ clearerr() function in stdio. This is useful for continuing to read a gzip
+ file that is being written concurrently.
+*/
+
+
+ /* checksum functions */
+
+/*
+ These functions are not related to compression but are exported
+ anyway because they might be useful in applications using the compression
+ library.
+*/
+
+ZEXTERN uLong ZEXPORT adler32 OF((uLong adler, const Bytef *buf, uInt len));
+/*
+ Update a running Adler-32 checksum with the bytes buf[0..len-1] and
+ return the updated checksum. If buf is Z_NULL, this function returns the
+ required initial value for the checksum.
+
+ An Adler-32 checksum is almost as reliable as a CRC32 but can be computed
+ much faster.
+
+ Usage example:
+
+ uLong adler = adler32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ adler = adler32(adler, buffer, length);
+ }
+ if (adler != original_adler) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT adler32_combine OF((uLong adler1, uLong adler2,
+ z_off_t len2));
+
+ Combine two Adler-32 checksums into one. For two sequences of bytes, seq1
+ and seq2 with lengths len1 and len2, Adler-32 checksums were calculated for
+ each, adler1 and adler2. adler32_combine() returns the Adler-32 checksum of
+ seq1 and seq2 concatenated, requiring only adler1, adler2, and len2.
+*/
+
+ZEXTERN uLong ZEXPORT crc32 OF((uLong crc, const Bytef *buf, uInt len));
+/*
+ Update a running CRC-32 with the bytes buf[0..len-1] and return the
+ updated CRC-32. If buf is Z_NULL, this function returns the required
+ initial value for the for the crc. Pre- and post-conditioning (one's
+ complement) is performed within this function so it shouldn't be done by the
+ application.
+
+ Usage example:
+
+ uLong crc = crc32(0L, Z_NULL, 0);
+
+ while (read_buffer(buffer, length) != EOF) {
+ crc = crc32(crc, buffer, length);
+ }
+ if (crc != original_crc) error();
+*/
+
+/*
+ZEXTERN uLong ZEXPORT crc32_combine OF((uLong crc1, uLong crc2, z_off_t len2));
+
+ Combine two CRC-32 check values into one. For two sequences of bytes,
+ seq1 and seq2 with lengths len1 and len2, CRC-32 check values were
+ calculated for each, crc1 and crc2. crc32_combine() returns the CRC-32
+ check value of seq1 and seq2 concatenated, requiring only crc1, crc2, and
+ len2.
+*/
+
+
+ /* various hacks, don't look :) */
+
+/* deflateInit and inflateInit are macros to allow checking the zlib version
+ * and the compiler's view of z_stream:
+ */
+ZEXTERN int ZEXPORT deflateInit_ OF((z_streamp strm, int level,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateInit_ OF((z_streamp strm,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT deflateInit2_ OF((z_streamp strm, int level, int method,
+ int windowBits, int memLevel,
+ int strategy, const char *version,
+ int stream_size));
+ZEXTERN int ZEXPORT inflateInit2_ OF((z_streamp strm, int windowBits,
+ const char *version, int stream_size));
+ZEXTERN int ZEXPORT inflateBackInit_ OF((z_streamp strm, int windowBits,
+ unsigned char FAR *window,
+ const char *version,
+ int stream_size));
+#define deflateInit(strm, level) \
+ deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit(strm) \
+ inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream))
+#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \
+ deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\
+ (strategy), ZLIB_VERSION, sizeof(z_stream))
+#define inflateInit2(strm, windowBits) \
+ inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream))
+#define inflateBackInit(strm, windowBits, window) \
+ inflateBackInit_((strm), (windowBits), (window), \
+ ZLIB_VERSION, sizeof(z_stream))
+
+/* provide 64-bit offset functions if _LARGEFILE64_SOURCE defined, and/or
+ * change the regular functions to 64 bits if _FILE_OFFSET_BITS is 64 (if
+ * both are true, the application gets the *64 functions, and the regular
+ * functions are changed to 64 bits) -- in case these are set on systems
+ * without large file support, _LFS64_LARGEFILE must also be true
+ */
+#if defined(_LARGEFILE64_SOURCE) && _LFS64_LARGEFILE-0
+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+ ZEXTERN z_off64_t ZEXPORT gzseek64 OF((gzFile, z_off64_t, int));
+ ZEXTERN z_off64_t ZEXPORT gztell64 OF((gzFile));
+ ZEXTERN z_off64_t ZEXPORT gzoffset64 OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off64_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off64_t));
+#endif
+
+#if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && _LFS64_LARGEFILE-0
+# define gzopen gzopen64
+# define gzseek gzseek64
+# define gztell gztell64
+# define gzoffset gzoffset64
+# define adler32_combine adler32_combine64
+# define crc32_combine crc32_combine64
+# ifdef _LARGEFILE64_SOURCE
+ ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const char *));
+ ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, int));
+ ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile));
+ ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, z_off_t));
+# endif
+#else
+ ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char *));
+ ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int));
+ ZEXTERN z_off_t ZEXPORT gztell OF((gzFile));
+ ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile));
+ ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, z_off_t));
+ ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, z_off_t));
+#endif
+
+/* hack for buggy compilers */
+#if !defined(ZUTIL_H) && !defined(NO_DUMMY_DECL)
+ struct internal_state {int dummy;};
+#endif
+
+/* undocumented functions */
+ZEXTERN const char * ZEXPORT zError OF((int));
+ZEXTERN int ZEXPORT inflateSyncPoint OF((z_streamp));
+ZEXTERN const uLongf * ZEXPORT get_crc_table OF((void));
+ZEXTERN int ZEXPORT inflateUndermine OF((z_streamp, int));
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* ZLIB_H */