/*
Sessions Management plugin for Miranda IM
Copyright (C) 2007-2008 Danil Mozhar
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 3 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, see .
*/
#include "stdafx.h"
HGENMENU hmSaveCurrentSession;
OBJLIST g_arUserSessions(1, NumericKeySortT), g_arDateSessions(1, NumericKeySortT);
HANDLE hmTBButton[2], hiTBbutton[2], iTBbutton[2];
int g_lastUserId, g_lastDateId;
bool g_bExclHidden;
bool g_bWarnOnHidden;
bool g_bOtherWarnings;
bool g_bCrashRecovery;
bool g_bIncompletedSave;
HWND g_hDlg;
bool DONT = false;
bool g_bLastSessionPresent = false;
MCONTACT session_list[255] = { 0 };
MCONTACT session_list_recovered[255];
CMPlugin g_plugin;
int OptionsInit(WPARAM, LPARAM);
/////////////////////////////////////////////////////////////////////////////////////////
PLUGININFOEX pluginInfoEx =
{
sizeof(PLUGININFOEX),
__PLUGIN_NAME,
PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
__DESCRIPTION,
__AUTHOR,
__COPYRIGHT,
__AUTHORWEB,
UNICODE_AWARE,
// {60558872-2AAB-45AA-888D-097691C9B683}
{ 0x60558872, 0x2aab, 0x45aa, { 0x88, 0x8d, 0x9, 0x76, 0x91, 0xc9, 0xb6, 0x83 } }
};
CMPlugin::CMPlugin() :
PLUGIN(MODULENAME, pluginInfoEx),
g_lastUserId(MODULENAME, "LastUserId", 0),
g_lastDateId(MODULENAME, "LastDateId", 0),
bExclHidden(MODULENAME, "ExclHidden", false),
bWarnOnHidden(MODULENAME, "WarnOnHidden", false),
bOtherWarnings(MODULENAME, "OtherWarnings", true),
bCrashRecovery(MODULENAME, "CrashRecovery", false),
iTrackCount(MODULENAME, "TrackCount", 10),
iStartupDelay(MODULENAME, "StartupModeDelay", 1500)
{}
/////////////////////////////////////////////////////////////////////////////////////////
INT_PTR CloseCurrentSession(WPARAM, LPARAM)
{
while (session_list[0] != 0) {
if (auto *pDlg = Srmm_FindDialog(session_list[0]))
pDlg->CloseTab();
SleepEx(50, TRUE);
}
memset(session_list, 0, sizeof(session_list));
return 0;
}
int SessionPreShutdown(WPARAM, LPARAM)
{
DONT = 1;
if (g_hDlg) DestroyWindow(g_hDlg);
if (g_hSDlg) DestroyWindow(g_hSDlg);
g_plugin.setByte("lastSaveCompleted", 1);
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////
static void SaveDateSession()
{
if (session_list[0] != 0) {
int TimeSize = GetTimeFormat(LOCALE_USER_DEFAULT, 0/*TIME_NOSECONDS*/, nullptr, nullptr, nullptr, 0);
ptrW szTimeBuf((wchar_t*)mir_alloc((TimeSize + 1)*sizeof(wchar_t)));
GetTimeFormat(LOCALE_USER_DEFAULT, 0/*TIME_NOSECONDS*/, nullptr, nullptr, szTimeBuf, TimeSize);
int DateSize = GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, nullptr, nullptr, nullptr, 0);
ptrW szDateBuf((wchar_t*)mir_alloc((DateSize + 1)*sizeof(wchar_t)));
GetDateFormat(LOCALE_USER_DEFAULT, DATE_SHORTDATE, nullptr, nullptr, szDateBuf, DateSize);
g_plugin.g_lastDateId = g_plugin.g_lastDateId+1;
CSession data;
data.wszName.Format(L"%s - %s", szTimeBuf.get(), szDateBuf.get());
for (int i = 0; session_list[i]; i++)
data.contacts.push_back(session_list[i]);
char szSetting[256];
mir_snprintf(szSetting, "%s_%d", "SessionDate", int(g_plugin.g_lastDateId));
g_plugin.setUString(szSetting, data.toString().c_str());
while (g_arDateSessions.getCount() >= g_plugin.iTrackCount) {
mir_snprintf(szSetting, "%s_%d", "SessionDate", g_arDateSessions[0].id);
g_plugin.delSetting(szSetting);
g_arDateSessions.remove(int(0));
}
}
if (g_bCrashRecovery)
g_plugin.setByte("lastSaveCompleted", 1);
}
/////////////////////////////////////////////////////////////////////////////////////////
// Exit dialog
class CExitDlg : public CDlgBase
{
public:
CExitDlg() :
CDlgBase(g_plugin, IDD_EXDIALOG)
{}
bool OnInitDialog() override
{
LoadPosition(m_hwnd, "ExitDlg");
return true;
}
bool OnApply() override
{
SaveDateSession();
return true;
}
void OnDestroy() override
{
SavePosition(m_hwnd, "ExitDlg");
g_plugin.setByte("lastempty", 1);
PostQuitMessage(0);
}
};
int OkToExit(WPARAM, LPARAM)
{
int exitmode = g_plugin.getByte("ShutdownMode", 2);
DONT = 1;
if (exitmode == 2 && session_list[0] != 0) {
SaveDateSession();
g_plugin.setByte("lastempty", 0);
}
else if (exitmode == 1 && session_list[0] != 0) {
CExitDlg().DoModal();
}
else g_plugin.setByte("lastempty", 1);
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////
static void AddToCurSession(MCONTACT hContact)
{
if (CheckForDuplicate(session_list, hContact) == -1) {
for (int i = 0;; i++) {
if (session_list[i] == 0) {
session_list[i] = hContact;
break;
}
}
}
}
static void DelFromCurSession(MCONTACT hContact)
{
for (int i = 0; session_list[i] != 0; i++) {
if (session_list[i] == hContact) {
while (session_list[i + 1] != 0) {
session_list[i] = session_list[i + 1];
i++;
}
session_list[i] = 0;
}
}
}
static int OnSrmmWindowEvent(WPARAM uType, LPARAM lParam)
{
auto *pDlg = (CSrmmBaseDialog *)lParam;
if (uType == MSG_WINDOW_EVT_OPEN) {
AddToCurSession(pDlg->m_hContact);
if (g_bCrashRecovery)
g_plugin.setByte(pDlg->m_hContact, "wasInLastSession", 1);
}
else if (uType == MSG_WINDOW_EVT_CLOSE) {
if (!DONT)
DelFromCurSession(pDlg->m_hContact);
if (g_bCrashRecovery)
g_plugin.setByte(pDlg->m_hContact, "wasInLastSession", 0);
}
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////
INT_PTR BuildFavMenu(WPARAM, LPARAM)
{
POINT pt;
GetCursorPos(&pt);
HMENU hMenu = CreatePopupMenu();
for (auto &it: g_arUserSessions)
if (it->bIsFavorite)
AppendMenu(hMenu, MF_STRING, it->id + 1, it->wszName);
if (GetMenuItemCount(hMenu) == 0) {
DestroyMenu(hMenu);
return 2;
}
int res = TrackPopupMenu(hMenu, TPM_RETURNCMD | TPM_NONOTIFY, pt.x, pt.y, 0, GetActiveWindow(), nullptr);
if (res == 0)
return 1;
res--;
if (auto *pSession = g_arUserSessions.find((CSession*)&res))
LoadSession(pSession);
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////
// Toolbar initialization
static int CreateButtons(WPARAM, LPARAM)
{
TTBButton ttb = {};
ttb.dwFlags = TTBBF_SHOWTOOLTIP | TTBBF_VISIBLE;
ttb.pszService = MS_SESSIONS_OPENMANAGER;
ttb.pszTooltipUp = ttb.name = LPGEN("Open Sessions Manager");
ttb.hIconHandleUp = g_plugin.getIconHandle(IDI_SESSIONS_LOAD);
g_plugin.addTTB(&ttb);
ttb.pszService = MS_SESSIONS_SAVEUSERSESSION;
ttb.pszTooltipUp = ttb.name = LPGEN("Save Session");
ttb.hIconHandleUp = g_plugin.getIconHandle(IDD_SESSIONS_SAVE);
g_plugin.addTTB(&ttb);
ttb.pszService = MS_SESSIONS_RESTORELASTSESSION;
ttb.pszTooltipUp = ttb.name = LPGEN("Restore Last Session");
ttb.hIconHandleUp = g_plugin.getIconHandle(IDD_SESSIONS_LOADLAST);
g_plugin.addTTB(&ttb);
ttb.pszService = MS_SESSIONS_SHOWFAVORITESMENU;
ttb.pszTooltipUp = ttb.name = LPGEN("Show Favorite Sessions Menu");
ttb.hIconHandleUp = g_plugin.getIconHandle(IDD_SESSION_CHECKED);
g_plugin.addTTB(&ttb);
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////
static int OnModulesLoaded(WPARAM, LPARAM)
{
HookEvent(ME_MSG_WINDOWEVENT, OnSrmmWindowEvent);
HookEvent(ME_TTB_MODULELOADED, CreateButtons);
// Hotkeys
HOTKEYDESC hkd = {};
hkd.pszName = "OpenSessionsManager";
hkd.szSection.a = LPGEN("Sessions");
hkd.szDescription.a = LPGEN("Open Sessions Manager");
hkd.pszService = MS_SESSIONS_OPENMANAGER;
g_plugin.addHotkey(&hkd);
hkd.pszName = "RestoreLastSession";
hkd.szDescription.a = LPGEN("Restore last Session");
hkd.pszService = MS_SESSIONS_RESTORELASTSESSION;
g_plugin.addHotkey(&hkd);
hkd.pszName = "SaveSession";
hkd.szDescription.a = LPGEN("Save Session");
hkd.pszService = MS_SESSIONS_SAVEUSERSESSION;
g_plugin.addHotkey(&hkd);
hkd.pszName = "CloseSession";
hkd.szDescription.a = LPGEN("Close Session");
hkd.pszService = MS_SESSIONS_CLOSESESSION;
g_plugin.addHotkey(&hkd);
// Main menu
CMenuItem mi(&g_plugin);
mi.position = 1000000000;
mi.root = g_plugin.addRootMenu(MO_MAIN, LPGENW("Sessions Manager"), 1000000000);
Menu_ConfigureItem(mi.root, MCI_OPT_UID, "D77B9AB4-AF7E-43DB-A487-BD581704D635");
SET_UID(mi, 0xd35302fa, 0x8326, 0x4323, 0xa3, 0xe5, 0xb4, 0x41, 0xff, 0xfb, 0xaa, 0x2d);
mi.name.a = LPGEN("Save session...");
mi.hIcolibItem = g_plugin.getIconHandle(IDD_SESSIONS_SAVE);
mi.pszService = MS_SESSIONS_SAVEUSERSESSION;
hmSaveCurrentSession = Menu_AddMainMenuItem(&mi);
SET_UID(mi, 0x8de4d8b1, 0x9a62, 0x4f4e, 0xb0, 0x3d, 0x99, 0x7, 0x80, 0xe8, 0x93, 0xc2);
mi.name.a = LPGEN("Load session...");
mi.pszService = MS_SESSIONS_OPENMANAGER;
mi.hIcolibItem = g_plugin.getIconHandle(IDI_SESSIONS_LOAD);
Menu_AddMainMenuItem(&mi);
SET_UID(mi, 0x73ea91d6, 0xb7e5, 0x4f67, 0x96, 0x96, 0xa, 0x24, 0x21, 0x48, 0x6f, 0x15);
mi.name.a = LPGEN("Close session");
mi.pszService = MS_SESSIONS_CLOSESESSION;
mi.hIcolibItem = nullptr;
Menu_AddMainMenuItem(&mi);
SET_UID(mi, 0xe2c4e4ba, 0x5d08, 0x441b, 0xb5, 0x93, 0xc4, 0xe7, 0x9a, 0xfb, 0xa4, 0x6c);
mi.name.a = LPGEN("Load last session");
mi.pszService = MS_SESSIONS_RESTORELASTSESSION;
mi.hIcolibItem = g_plugin.getIconHandle(IDD_SESSIONS_LOADLAST);
mi.position = 10100000;
Menu_AddMainMenuItem(&mi);
return 0;
}
/////////////////////////////////////////////////////////////////////////////////////////
static IconItem iconList[] =
{
{ LPGEN("Sessions"), "Sessions", IDD_SESSION_CHECKED },
{ LPGEN("Favorite Session"), "SessionMarked", IDD_SESSION_CHECKED },
{ LPGEN("Not favorite Session"), "SessionUnMarked", IDD_SESSION_UNCHECKED },
{ LPGEN("Load Session"), "SessionsLoad", IDI_SESSIONS_LOAD },
{ LPGEN("Save Session"), "SessionsSave", IDD_SESSIONS_SAVE },
{ LPGEN("Load last Session"), "SessionsLoadLast", IDD_SESSIONS_LOADLAST }
};
int LoadSettings(const char *szSetting, void *)
{
if (!memcmp(szSetting, "SessionUser_", 12)) {
auto *pSession = new CSession();
pSession->id = atoi(szSetting + 12);
pSession->fromString(ptrA(db_get_utfa(0, MODULENAME, szSetting)));
g_arUserSessions.insert(pSession);
}
else if (!memcmp(szSetting, "SessionDate_", 12)) {
auto *pSession = new CSession();
pSession->id = atoi(szSetting + 12);
pSession->fromString(ptrA(db_get_utfa(0, MODULENAME, szSetting)));
g_arDateSessions.insert(pSession);
}
return 0;
}
int CMPlugin::Load()
{
// Icons
g_plugin.registerIcon(MODULENAME, iconList);
// Services
CreateServiceFunction(MS_SESSIONS_SHOWFAVORITESMENU, BuildFavMenu);
CreateServiceFunction(MS_SESSIONS_OPENMANAGER, OpenSessionsManagerWindow);
CreateServiceFunction(MS_SESSIONS_RESTORELASTSESSION, LoadLastSession);
CreateServiceFunction(MS_SESSIONS_SAVEUSERSESSION, SaveUserSessionHandles);
CreateServiceFunction(MS_SESSIONS_CLOSESESSION, CloseCurrentSession);
// Events
HookEvent(ME_SYSTEM_MODULESLOADED, OnModulesLoaded);
HookEvent(ME_SYSTEM_OKTOEXIT, OkToExit);
HookEvent(ME_SYSTEM_PRESHUTDOWN, SessionPreShutdown);
HookEvent(ME_OPT_INITIALISE, OptionsInit);
Miranda_WaitOnHandle(LaunchSessions);
// Settimgs
g_bExclHidden = g_plugin.getByte("ExclHidden", 0) != 0;
g_bWarnOnHidden = g_plugin.getByte("WarnOnHidden", 0) != 0;
g_bOtherWarnings = g_plugin.getByte("OtherWarnings", 1) != 0;
g_bCrashRecovery = g_plugin.getByte("CrashRecovery", 0) != 0;
// Crash recovery
if (g_bCrashRecovery)
g_bIncompletedSave = g_plugin.getByte("lastSaveCompleted", 0) == 0;
if (g_bIncompletedSave) {
int i = 0;
memset(session_list_recovered, 0, sizeof(session_list_recovered));
for (auto &hContact : Contacts())
if (g_plugin.getByte(hContact, "wasInLastSession"))
session_list_recovered[i++] = hContact;
}
if (!session_list_recovered[0])
g_bIncompletedSave = false;
g_plugin.setByte("lastSaveCompleted", 0);
if (!g_plugin.getByte("lastempty", 1) || g_bIncompletedSave)
g_bLastSessionPresent = true;
// Check for old settings
CheckImport();
// Load settings data
db_enum_settings(0, LoadSettings, MODULENAME);
return 0;
}