/*
Basic History plugin
Copyright (C) 2011-2012 Krzysztof Kral
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation version 2
of the License.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include "stdafx.h"
#include "version.h"
#include "HistoryWindow.h"
#include "resource.h"
#include "Options.h"
// {E25367A2-51AE-4044-BE28-131BC18B71A4}
#define MIID_BASICHISTORY { 0xe25367a2, 0x51ae, 0x4044, { 0xbe, 0x28, 0x13, 0x1b, 0xc1, 0x8b, 0x71, 0xa4 } }
#define MS_HISTORY_DELETEALLCONTACTHISTORY "BasicHistory/DeleteAllContactHistory"
#define MS_HISTORY_EXECUTE_TASK "BasicHistory/ExecuteTask"
HCURSOR hCurSplitNS, hCurSplitWE;
HANDLE g_hMainThread=NULL;
extern HINSTANCE hInst;
HANDLE hServiceShowContactHistory, hServiceDeleteAllContactHistory, hServiceExecuteTask;
HANDLE *hEventIcons = NULL;
int iconsNum;
HANDLE hPlusIcon, hMinusIcon, hFindNextIcon, hFindPrevIcon;
HANDLE hPlusExIcon, hMinusExIcon;
HANDLE hToolbarButton;
HGENMENU hContactMenu, hDeleteContactMenu;
HGENMENU hTaskMainMenu;
std::vector taskMenus;
bool g_SmileyAddAvail = false;
char* metaContactProto = NULL;
const IID IID_ITextDocument={0x8CC497C0, 0xA1DF, 0x11ce, {0x80, 0x98, 0x00, 0xAA, 0x00, 0x47, 0xBE, 0x5D}};
#define MODULE "BasicHistory"
PLUGININFOEX pluginInfo =
{
sizeof(PLUGININFOEX),
__PLUGIN_NAME,
PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
__AUTHOREMAIL,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
MIID_BASICHISTORY
};
TIME_API tmi = {0};
int hLangpack = 0;
extern "C" __declspec(dllexport) PLUGININFOEX* MirandaPluginInfoEx(DWORD mirandaVersion)
{
return &pluginInfo;
}
static const MUUID interfaces[] = {MIID_UIHISTORY, MIID_LAST};
extern "C" __declspec(dllexport) const MUUID* MirandaPluginInterfaces(void)
{
return interfaces;
}
void InitScheduler();
void DeinitScheduler();
int DoLastTask(WPARAM, LPARAM);
INT_PTR ExecuteTaskService(WPARAM wParam, LPARAM lParam);
int PrebuildContactMenu(WPARAM wParam, LPARAM lParam)
{
int count = EventList::GetContactMessageNumber((HANDLE)wParam);
bool isInList = HistoryWindow::IsInList(GetForegroundWindow());
CLISTMENUITEM mi = {0};
mi.cbSize = sizeof(mi);
mi.flags = CMIM_FLAGS;
if (!count) mi.flags |= CMIF_HIDDEN;
else mi.flags &= ~CMIF_HIDDEN;
CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hContactMenu, (LPARAM)&mi);
mi.flags = CMIM_FLAGS;
if (!count || !isInList) mi.flags |= CMIF_HIDDEN;
else mi.flags &= ~CMIF_HIDDEN;
CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hDeleteContactMenu, (LPARAM)&mi);
return 0;
}
int ToolbarModuleLoaded(WPARAM wParam,LPARAM lParam)
{
if(ServiceExists(MS_TTB_REMOVEBUTTON)) {
TTBButton tbb = {0};
tbb.cbSize = sizeof(tbb);
tbb.name = LPGEN("Open History");
tbb.pszService = MS_HISTORY_SHOWCONTACTHISTORY;
tbb.pszTooltipUp = LPGEN("Open History");
tbb.pszTooltipDn = LPGEN("Open History");
tbb.dwFlags = TTBBF_SHOWTOOLTIP;
tbb.hIconHandleUp = tbb.hIconHandleDn = LoadSkinnedIconHandle(SKINICON_OTHER_HISTORY);
hToolbarButton = TopToolbar_AddButton(&tbb);
}
return 0;
}
void InitMenuItems()
{
CLISTMENUITEM mi = { 0 };
mi.cbSize = sizeof(mi);
mi.position = 1000090000;
mi.flags = CMIF_ICONFROMICOLIB;
mi.icolibItem = LoadSkinnedIconHandle(SKINICON_OTHER_HISTORY);
mi.pszName = LPGEN("View &History");
mi.pszService = MS_HISTORY_SHOWCONTACTHISTORY;
hContactMenu = Menu_AddContactMenuItem(&mi);
mi.position = 500060000;
mi.pszService = MS_HISTORY_SHOWCONTACTHISTORY;
Menu_AddMainMenuItem(&mi);
mi.position = 1000090001;
mi.flags = CMIF_ICONFROMICOLIB;
mi.icolibItem = LoadSkinnedIconHandle(SKINICON_OTHER_DELETE);
mi.pszName = LPGEN("Delete All User History");
mi.pszService = MS_HISTORY_DELETEALLCONTACTHISTORY;
hDeleteContactMenu = Menu_AddContactMenuItem(&mi);
HookEvent(ME_CLIST_PREBUILDCONTACTMENU, PrebuildContactMenu);
}
void InitTaskMenuItems()
{
if(Options::instance->taskOptions.size() > 0)
{
CLISTMENUITEM mi = { 0 };
mi.cbSize = sizeof(mi);
if(hTaskMainMenu == NULL)
{
mi.position = 500060005;
mi.flags = CMIF_ROOTPOPUP | CMIF_ICONFROMICOLIB;
mi.icolibItem = LoadSkinnedIconHandle(SKINICON_OTHER_HISTORY);
mi.pszName = LPGEN("Execute history task");
hTaskMainMenu = Menu_AddMainMenuItem(&mi);
}
std::vector::iterator taskIt = Options::instance->taskOptions.begin();
std::vector::iterator it = taskMenus.begin();
for(; it != taskMenus.end() && taskIt != Options::instance->taskOptions.end(); ++it, ++taskIt)
{
memset(&mi, 0, sizeof(mi));
mi.cbSize = sizeof(mi);
mi.flags = CMIM_FLAGS | CMIM_NAME | CMIF_CHILDPOPUP | CMIF_ROOTHANDLE | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED;
mi.hParentMenu = hTaskMainMenu;
mi.ptszName = (TCHAR*)taskIt->taskName.c_str();
CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)(HGENMENU)*it, (LPARAM)&mi);
}
for(; it != taskMenus.end(); ++it)
{
memset(&mi, 0, sizeof(mi));
mi.cbSize = sizeof(mi);
mi.flags = CMIM_FLAGS | CMIF_CHILDPOPUP | CMIF_ROOTHANDLE | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED | CMIF_HIDDEN;
mi.hParentMenu = hTaskMainMenu;
CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)(HGENMENU)*it, (LPARAM)&mi);
}
int pos = (int)taskMenus.size();
for(; taskIt != Options::instance->taskOptions.end(); ++taskIt)
{
memset(&mi, 0, sizeof(mi));
mi.cbSize = sizeof(mi);
mi.flags = CMIF_CHILDPOPUP | CMIF_ROOTHANDLE | CMIF_TCHAR | CMIF_KEEPUNTRANSLATED;
mi.pszService = MS_HISTORY_EXECUTE_TASK;
mi.hParentMenu = hTaskMainMenu;
mi.popupPosition = pos++;
mi.ptszName = (TCHAR*)taskIt->taskName.c_str();
HGENMENU menu = Menu_AddMainMenuItem(&mi);
taskMenus.push_back(menu);
}
}
else if(hTaskMainMenu != NULL)
{
CLISTMENUITEM mi = { 0 };
mi.cbSize = sizeof(mi);
mi.flags = CMIM_FLAGS | CMIF_ROOTPOPUP | CMIF_HIDDEN;
CallService(MS_CLIST_MODIFYMENUITEM, (WPARAM)hTaskMainMenu, (LPARAM)&mi);
}
}
void InitIcolib()
{
TCHAR stzFile[MAX_PATH];
SKINICONDESC sid = {0};
sid.cbSize = sizeof(sid);
sid.cx = sid.cy = 16;
sid.ptszDefaultFile = stzFile;
sid.ptszSection = LPGENT("History");
sid.flags = SIDF_ALL_TCHAR;
GetModuleFileName(hInst, stzFile, MAX_PATH);
iconsNum = 3;
hEventIcons = new HANDLE[iconsNum];
sid.pszName = "BasicHistory_in";
sid.ptszDescription = LPGENT("Incoming message");
sid.iDefaultIndex = -IDI_INM;
hEventIcons[0] = Skin_AddIcon(&sid);
sid.pszName = "BasicHistory_out";
sid.ptszDescription = LPGENT("Outgoing message");
sid.iDefaultIndex = -IDI_OUTM;
hEventIcons[1] = Skin_AddIcon(&sid);
sid.pszName = "BasicHistory_status";
sid.ptszDescription = LPGENT("Statuschange");
sid.iDefaultIndex = -IDI_STATUS;
hEventIcons[2] = Skin_AddIcon(&sid);
sid.pszName = "BasicHistory_show";
sid.ptszDescription = LPGENT("Show Contacts");
sid.iDefaultIndex = -IDI_SHOW;
hPlusIcon = Skin_AddIcon(&sid);
sid.pszName = "BasicHistory_hide";
sid.ptszDescription = LPGENT("Hide Contacts");
sid.iDefaultIndex = -IDI_HIDE;
hMinusIcon = Skin_AddIcon(&sid);
sid.pszName = "BasicHistory_findnext";
sid.ptszDescription = LPGENT("Find Next");
sid.iDefaultIndex = -IDI_FINDNEXT;
hFindNextIcon = Skin_AddIcon(&sid);
sid.pszName = "BasicHistory_findprev";
sid.ptszDescription = LPGENT("Find Previous");
sid.iDefaultIndex = -IDI_FINDPREV;
hFindPrevIcon = Skin_AddIcon(&sid);
sid.pszName = "BasicHistory_plusex";
sid.ptszDescription = LPGENT("Plus in export");
sid.iDefaultIndex = -IDI_PLUSEX;
hPlusExIcon = Skin_AddIcon(&sid);
sid.pszName = "BasicHistory_minusex";
sid.ptszDescription = LPGENT("Minus in export");
sid.iDefaultIndex = -IDI_MINUSEX;
hMinusExIcon = Skin_AddIcon(&sid);
}
void InitUpdater()
{
if (ServiceExists(MS_UPDATE_REGISTER))
{
Update update = {0};
char szVersion[16];
update.cbSize = sizeof(Update);
update.szComponentName = pluginInfo.shortName;
update.pbVersion = (BYTE *)CreateVersionStringPluginEx(&pluginInfo, szVersion);
update.cpbVersion = (int)strlen((char *)update.pbVersion);
#ifdef _WIN64
update.szUpdateURL = "http://programista.free.of.pl/miranda/BasicHistory64.zip";
update.szVersionURL = "http://programista.free.of.pl/miranda/pluginversion.php?plugin=basichistory&x64=yes";
update.szBetaUpdateURL = "http://programista.free.of.pl/miranda/BasicHistoryBeta64.zip";
update.szBetaVersionURL = "http://programista.free.of.pl/miranda/pluginversion.php?plugin=basichistory&beta=yes&x64=yes";
update.szBetaChangelogURL = "http://programista.free.of.pl/miranda/BasicHistoryChangelog.txt";
#else
update.szUpdateURL = "http://programista.free.of.pl/miranda/BasicHistory.zip";
update.szVersionURL = "http://programista.free.of.pl/miranda/pluginversion.php?plugin=basichistory";
update.szBetaUpdateURL = "http://programista.free.of.pl/miranda/BasicHistoryBeta.zip";
update.szBetaVersionURL = "http://programista.free.of.pl/miranda/pluginversion.php?plugin=basichistory&beta=yes";
update.szBetaChangelogURL = "http://programista.free.of.pl/miranda/BasicHistoryChangelog.txt";
#endif
update.pbBetaVersionPrefix = update.pbVersionPrefix = (BYTE *)"Basic History ";
update.cpbBetaVersionPrefix = update.cpbVersionPrefix = (int)strlen((char *)update.pbVersionPrefix);
CallService(MS_UPDATE_REGISTER, 0, (WPARAM)&update);
}
}
INT_PTR ShowContactHistory(WPARAM wParam, LPARAM lParam)
{
HANDLE hContact = (HANDLE)wParam;
HistoryWindow::Open(hContact);
return 0;
}
int PreShutdownHistoryModule(WPARAM, LPARAM)
{
HistoryWindow::Deinit();
DeinitScheduler();
return 0;
}
int HistoryContactDelete(WPARAM wParam, LPARAM)
{
HistoryWindow::Close((HANDLE)wParam);
return 0;
}
int ModulesLoaded(WPARAM wParam, LPARAM lParam)
{
InitMenuItems();
InitUpdater();
TCHAR ftpExe[MAX_PATH];
if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILES, NULL, SHGFP_TYPE_CURRENT, ftpExe)))
{
_tcscat_s(ftpExe, _T("\\WinSCP\\WinSCP.exe"));
DWORD atr = GetFileAttributes(ftpExe);
if(atr == INVALID_FILE_ATTRIBUTES || atr & FILE_ATTRIBUTE_DIRECTORY)
{
#ifdef _WIN64
if(SUCCEEDED(SHGetFolderPath(NULL, CSIDL_PROGRAM_FILESX86, NULL, SHGFP_TYPE_CURRENT, ftpExe)))
{
_tcscat_s(ftpExe, _T("\\WinSCP\\WinSCP.exe"));
atr = GetFileAttributes(ftpExe);
if(!(atr == INVALID_FILE_ATTRIBUTES || atr & FILE_ATTRIBUTE_DIRECTORY))
{
Options::instance->ftpExePathDef = ftpExe;
}
}
#endif
}
else
Options::instance->ftpExePathDef = ftpExe;
}
TCHAR* log = _T("%miranda_logpath%\\BasicHistory\\ftplog.txt");
TCHAR* logAbsolute = Utils_ReplaceVarsT(log);
Options::instance->ftpLogPath = logAbsolute;
mir_free(logAbsolute);
Options::instance->Load();
InitTaskMenuItems();
HookEvent(ME_TTB_MODULELOADED,ToolbarModuleLoaded);
HookEvent(ME_SYSTEM_PRESHUTDOWN,PreShutdownHistoryModule);
HookEvent(ME_DB_CONTACT_DELETED,HistoryContactDelete);
HookEvent(ME_FONT_RELOAD, HistoryWindow::FontsChanged);
HookEvent(ME_SYSTEM_OKTOEXIT, DoLastTask);
if (ServiceExists(MS_SMILEYADD_REPLACESMILEYS))
g_SmileyAddAvail = true;
if (ServiceExists(MS_MC_GETPROTOCOLNAME))
metaContactProto = (char*)CallService(MS_MC_GETPROTOCOLNAME, 0, 0);
InitScheduler();
return 0;
}
extern "C" int __declspec(dllexport) Load(void)
{
hTaskMainMenu = NULL;
DuplicateHandle(GetCurrentProcess(),GetCurrentThread(),GetCurrentProcess(),&g_hMainThread,0,FALSE,DUPLICATE_SAME_ACCESS);
mir_getTMI(&tmi);
mir_getLP(&pluginInfo);
hCurSplitNS = LoadCursor(NULL, IDC_SIZENS);
hCurSplitWE = LoadCursor(NULL, IDC_SIZEWE);
hServiceShowContactHistory = CreateServiceFunction(MS_HISTORY_SHOWCONTACTHISTORY, ShowContactHistory);
hServiceDeleteAllContactHistory = CreateServiceFunction(MS_HISTORY_DELETEALLCONTACTHISTORY, HistoryWindow::DeleteAllUserHistory);
hServiceExecuteTask = CreateServiceFunction(MS_HISTORY_EXECUTE_TASK, ExecuteTaskService);
Options::instance = new Options();
HookEvent(ME_SYSTEM_MODULESLOADED, ModulesLoaded);
HookEvent(ME_OPT_INITIALISE, Options::InitOptions);
EventList::Init();
InitIcolib();
return 0;
}
extern "C" int __declspec(dllexport) Unload(void)
{
if (g_hMainThread)
CloseHandle(g_hMainThread);
g_hMainThread=NULL;
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;
}