summaryrefslogtreecommitdiff
path: root/plugins/StatusManager/src/aaa_main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/StatusManager/src/aaa_main.cpp')
-rw-r--r--plugins/StatusManager/src/aaa_main.cpp541
1 files changed, 541 insertions, 0 deletions
diff --git a/plugins/StatusManager/src/aaa_main.cpp b/plugins/StatusManager/src/aaa_main.cpp
new file mode 100644
index 0000000000..aa630ccb36
--- /dev/null
+++ b/plugins/StatusManager/src/aaa_main.cpp
@@ -0,0 +1,541 @@
+/*
+ AdvancedAutoAway Plugin for Miranda-IM (www.miranda-im.org)
+ Copyright 2003-2006 P. Boon
+
+ 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
+
+
+ Some code is copied from Miranda's AutoAway module
+*/
+
+#include "stdafx.h"
+
+#ifdef _DEBUG
+#define SECS_PER_MINUTE 20 /* speedup */
+#else
+#define SECS_PER_MINUTE 60 /* default I believe */
+#endif
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+CFakePlugin AAAPlugin(AAAMODULENAME);
+
+static HANDLE hEvents[3];
+
+static BOOL ignoreLockKeys = FALSE;
+static BOOL ignoreSysKeys = FALSE;
+static BOOL ignoreAltCombo = FALSE;
+static BOOL monitorMouse = TRUE;
+static BOOL monitorKeyboard = TRUE;
+static HWND confirmDialog;
+static int mouseStationaryTimer;
+HHOOK hMirandaMouseHook = nullptr;
+HHOOK hMirandaKeyBoardHook = nullptr;
+#pragma data_seg("Shared")
+DWORD lastInput = 0;
+POINT lastMousePos = { 0 };
+HHOOK hMouseHook = nullptr;
+HHOOK hKeyBoardHook = nullptr;
+#pragma data_seg()
+#pragma comment(linker, "/section:Shared,rws")
+DWORD lastMirandaInput = 0;
+static UINT_PTR hAutoAwayTimer;
+// prototypes
+extern DWORD StatusModeToProtoFlag(int status);
+
+int AutoAwayOptInitialise(WPARAM wParam, LPARAM lParam);
+
+static int ProcessProtoAck(WPARAM, LPARAM lParam)
+{
+ ACKDATA *ack = (ACKDATA*)lParam;
+ if (ack->type != ACKTYPE_STATUS || ack->result != ACKRESULT_SUCCESS)
+ return 0;
+
+ log_debug(0, "ProcessProtoAck: ack->szModule: %s", ack->szModule);
+ for (auto &it : protoList) {
+ log_debug(0, "chk: %s", it->m_szName);
+ if (!mir_strcmp(it->m_szName, ack->szModule)) {
+ log_debug(0, "ack->szModule: %s p.statusChanged: %d", ack->szModule, it->bStatusChanged);
+ if (!it->bStatusChanged)
+ it->bManualStatus = true;
+
+ it->bStatusChanged = false;
+ }
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Account control event
+
+static char* status2descr(int status)
+{
+ switch (status) {
+ case ACTIVE: return "ACTIVE";
+ case STATUS1_SET: return "STATUS1_SET";
+ case STATUS2_SET: return "STATUS2_SET";
+ case SET_ORGSTATUS: return "SET_ORGSTATUS";
+ case HIDDEN_ACTIVE: return "HIDDEN_ACTIVE";
+ }
+ return "ERROR";
+}
+
+static int changeState(SMProto &setting, int mode, STATES newState)
+{
+ if (setting.curState == newState)
+ return 0;
+
+ setting.oldState = setting.curState;
+ setting.curState = newState;
+
+ log_debug(0, "%s state change: %s -> %s", setting.m_szName, status2descr(setting.oldState), status2descr(setting.curState));
+
+ if (setting.curState != SET_ORGSTATUS && setting.curState != ACTIVE && setting.bStatusChanged) {
+ /* change the awaymessage */
+ if (setting.m_szMsg != nullptr) {
+ mir_free(setting.m_szMsg);
+ setting.m_szMsg = nullptr;
+ }
+
+ if (AAAPlugin.getByte(StatusModeToDbSetting(setting.aaaStatus, SETTING_MSGCUSTOM), FALSE))
+ setting.m_szMsg = AAAPlugin.getWStringA(StatusModeToDbSetting(setting.aaaStatus, SETTING_STATUSMSG));
+ }
+ else if (setting.m_szMsg != nullptr) {
+ mir_free(setting.m_szMsg);
+ setting.m_szMsg = nullptr;
+ }
+
+ if (setting.optionFlags & FLAG_ENTERIDLE) {
+ if (newState == ACTIVE) // we're returning back
+ Idle_Enter(-1);
+ else
+ Idle_Enter(mode);
+ }
+
+ return 0;
+}
+
+static int getIdleMode(int options)
+{
+ if ((options & FLAG_ONSAVER) && IsScreenSaverRunning())
+ return 1;
+
+ if ((options & FLAG_ONLOCK) && IsWorkstationLocked())
+ return 2;
+
+ if ((options & FLAG_ONTS) && IsTerminalDisconnected())
+ return 3;
+
+ if ((options & FLAG_FULLSCREEN) && IsFullScreen())
+ return 4;
+
+ return 0;
+}
+
+static VOID CALLBACK AutoAwayTimer(HWND, UINT, UINT_PTR, DWORD)
+{
+ int statusChanged = FALSE;
+ int confirm = FALSE;
+
+ for (auto &it : protoList) {
+ it->aaaStatus = ID_STATUS_DISABLED;
+
+ if (it->optionFlags & FLAG_MONITORMIRANDA)
+ mouseStationaryTimer = (GetTickCount() - lastMirandaInput) / 1000;
+ else {
+ LASTINPUTINFO ii = { sizeof(ii) };
+ GetLastInputInfo(&ii);
+ mouseStationaryTimer = (GetTickCount() - ii.dwTime) / 1000;
+ }
+
+ int sts1Time = it->awayTime * SECS_PER_MINUTE;
+ int sts2Time = it->naTime * SECS_PER_MINUTE;
+ int sts1setTime = it->sts1setTimer == 0 ? 0 : (GetTickCount() - it->sts1setTimer) / 1000;
+ int currentMode = Proto_GetStatus(it->m_szName);
+
+ int mode = getIdleMode(it->optionFlags);
+
+ /* check states */
+ if (it->curState == ACTIVE) {
+ if (((mouseStationaryTimer >= sts1Time && (it->optionFlags & FLAG_ONMOUSE)) || mode) && currentMode != it->lv1Status && it->statusFlags & StatusModeToProtoFlag(currentMode)) {
+ if (it->optionFlags & FLAG_ONMOUSE)
+ mode = 5;
+
+ /* from ACTIVE to STATUS1_SET */
+ it->m_lastStatus = it->originalStatusMode = Proto_GetStatus(it->m_szName);
+ it->aaaStatus = it->lv1Status;
+ it->sts1setTimer = GetTickCount();
+ sts1setTime = 0;
+ it->bStatusChanged = statusChanged = true;
+ changeState(*it, mode, STATUS1_SET);
+ }
+ else if (mouseStationaryTimer >= sts2Time && currentMode == it->lv1Status && currentMode != it->lv2Status && (it->optionFlags & FLAG_SETNA) && (it->statusFlags & StatusModeToProtoFlag(currentMode))) {
+ /* from ACTIVE to STATUS2_SET */
+ it->m_lastStatus = it->originalStatusMode = Proto_GetStatus(it->m_szName);
+ it->aaaStatus = it->lv2Status;
+ it->bStatusChanged = statusChanged = true;
+ changeState(*it, mode, STATUS2_SET);
+ }
+ }
+
+ if (it->curState == STATUS1_SET) {
+ if ((mouseStationaryTimer < sts1Time && !mode) && !(it->optionFlags & FLAG_RESET)) {
+ /* from STATUS1_SET to HIDDEN_ACTIVE */
+ changeState(*it, mode, HIDDEN_ACTIVE);
+ it->m_lastStatus = Proto_GetStatus(it->m_szName);
+ }
+ else if (((mouseStationaryTimer < sts1Time) && !mode) &&
+ ((it->optionFlags & FLAG_LV2ONINACTIVE) || (!(it->optionFlags & FLAG_SETNA))) &&
+ (it->optionFlags & FLAG_RESET)) {
+ /* from STATUS1_SET to SET_ORGSTATUS */
+ changeState(*it, mode, SET_ORGSTATUS);
+ }
+ else if ((it->optionFlags & FLAG_SETNA) && sts1setTime >= sts2Time) {
+ /* when set STATUS2, currentMode doesn't have to be in the selected status list (statusFlags) */
+ /* from STATUS1_SET to STATUS2_SET */
+ it->m_lastStatus = Proto_GetStatus(it->m_szName);
+ it->aaaStatus = it->lv2Status;
+ it->bStatusChanged = statusChanged = true;
+ changeState(*it, mode, STATUS2_SET);
+ }
+ }
+
+ if (it->curState == STATUS2_SET) {
+ if (mouseStationaryTimer < sts2Time && !mode && (it->optionFlags & FLAG_RESET)) {
+ /* from STATUS2_SET to SET_ORGSTATUS */
+ changeState(*it, mode, SET_ORGSTATUS);
+ }
+ else if (mouseStationaryTimer < sts2Time && !mode && !(it->optionFlags & FLAG_RESET)) {
+ /* from STATUS2_SET to HIDDEN_ACTIVE */
+ /* Remember: after status1 is set, and "only on inactive" is NOT set, it implies !reset. */
+ changeState(*it, mode, HIDDEN_ACTIVE);
+ it->m_lastStatus = Proto_GetStatus(it->m_szName);
+ }
+ }
+
+ if (it->curState == HIDDEN_ACTIVE) {
+ if (it->bManualStatus) {
+ /* HIDDEN_ACTIVE to ACTIVE */
+ // it->bStatusChanged = false;
+ changeState(*it, mode, ACTIVE);
+ it->sts1setTimer = 0;
+ it->bManualStatus = false;
+ }
+ else if ((it->optionFlags & FLAG_SETNA) && currentMode == it->lv1Status &&
+ currentMode != it->lv2Status && (it->statusFlags & StatusModeToProtoFlag(currentMode)) &&
+ (mouseStationaryTimer >= sts2Time || (sts1setTime >= sts2Time && !(it->optionFlags & FLAG_LV2ONINACTIVE)))) {
+ /* HIDDEN_ACTIVE to STATUS2_SET */
+ it->m_lastStatus = it->originalStatusMode = Proto_GetStatus(it->m_szName);
+ it->aaaStatus = it->lv2Status;
+ it->bStatusChanged = statusChanged = true;
+ changeState(*it, mode, STATUS2_SET);
+ }
+ }
+ if (it->curState == SET_ORGSTATUS) {
+ /* SET_ORGSTATUS to ACTIVE */
+ it->m_lastStatus = Proto_GetStatus(it->m_szName);
+ it->aaaStatus = it->originalStatusMode;
+ confirm = (it->optionFlags & FLAG_CONFIRM) ? TRUE : confirm;
+ it->bStatusChanged = statusChanged = true;
+ changeState(*it, mode, ACTIVE);
+ it->sts1setTimer = 0;
+ }
+ it->bManualStatus = false;
+ }
+
+ if (confirm || statusChanged) {
+ TProtoSettings ps(protoList); // make a copy of data not to pollute main array
+ for (auto &it : ps)
+ it->m_status = it->aaaStatus;
+
+ if (confirm)
+ confirmDialog = ShowConfirmDialogEx(&ps, AAAPlugin.getWord(SETTING_CONFIRMDELAY, 5));
+ else if (statusChanged)
+ SetStatusEx(ps);
+ }
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Windows hooks
+
+static LRESULT CALLBACK MirandaMouseHookFunction(int code, WPARAM wParam, LPARAM lParam)
+{
+ if (code >= 0) {
+ PMOUSEHOOKSTRUCT mouseInfo = (PMOUSEHOOKSTRUCT)lParam;
+ POINT pt = mouseInfo->pt;
+
+ /* TioDuke's KeyBoardNotifyExt: only update if a Miranda window is focused */
+ DWORD pid;
+ GetWindowThreadProcessId(GetForegroundWindow(), &pid);
+ if (pid != GetCurrentProcessId())
+ return CallNextHookEx(hMirandaMouseHook, code, wParam, lParam);
+
+ if (pt.x != lastMousePos.x || pt.y != lastMousePos.y) {
+ lastMousePos = pt;
+ lastMirandaInput = GetTickCount();
+ }
+ }
+
+ return CallNextHookEx(hMirandaMouseHook, code, wParam, lParam);
+}
+
+static LRESULT CALLBACK MirandaKeyBoardHookFunction(int code, WPARAM wParam, LPARAM lParam)
+{
+ if (code >= 0) {
+ if (ignoreAltCombo) {
+ if (((GetKeyState(VK_MENU) < 0) || (wParam == VK_MENU)) ||
+ ((GetKeyState(VK_TAB) < 0) || (wParam == VK_TAB)) ||
+ ((GetKeyState(VK_SHIFT) < 0) || (wParam == VK_SHIFT)) ||
+ ((GetKeyState(VK_CONTROL) < 0) || (wParam == VK_CONTROL)) ||
+ ((GetKeyState(VK_ESCAPE) < 0) || (wParam == VK_ESCAPE)) ||
+ ((GetKeyState(VK_LWIN) < 0) || (wParam == VK_LWIN)) ||
+ ((GetKeyState(VK_RWIN) < 0) || (wParam == VK_RWIN))) {
+ return CallNextHookEx(hMirandaKeyBoardHook, code, wParam, lParam);
+ }
+ }
+
+ switch (wParam) {
+ case VK_NUMLOCK:
+ case VK_CAPITAL:
+ case VK_SCROLL:
+ if (!ignoreLockKeys)
+ lastMirandaInput = GetTickCount();
+ break;
+
+ case VK_TAB:
+ case VK_SHIFT:
+ case VK_CONTROL:
+ case VK_MENU:
+ case VK_ESCAPE:
+ case VK_LWIN:
+ case VK_RWIN:
+ if (!ignoreSysKeys)
+ lastMirandaInput = GetTickCount();
+ break;
+
+ default:
+ lastMirandaInput = GetTickCount();
+ break;
+ }
+ }
+
+ return CallNextHookEx(hMirandaKeyBoardHook, code, wParam, lParam);
+}
+
+static LRESULT CALLBACK MouseHookFunction(int code, WPARAM wParam, LPARAM lParam)
+{
+ if (code >= 0) {
+ PMOUSEHOOKSTRUCT mouseInfo = (PMOUSEHOOKSTRUCT)lParam;
+ POINT pt = mouseInfo->pt;
+
+ /* TioDuke's KeyBoardNotifyExt: also grab clicks */
+ if ((wParam >= WM_NCLBUTTONDOWN && wParam <= WM_NCXBUTTONDBLCLK && wParam != 0x00AA) || (wParam >= WM_LBUTTONDOWN && wParam <= WM_XBUTTONDBLCLK))
+ lastInput = GetTickCount();
+
+ if (pt.x != lastMousePos.x || pt.y != lastMousePos.y) {
+ lastMousePos = pt;
+ lastInput = GetTickCount();
+ }
+ }
+
+ return CallNextHookEx(hMouseHook, code, wParam, lParam);
+}
+
+static LRESULT CALLBACK KeyBoardHookFunction(int code, WPARAM wParam, LPARAM lParam)
+{
+ if (code >= 0) {
+ if (ignoreAltCombo) {
+ if (((GetKeyState(VK_MENU) < 0) || (wParam == VK_MENU)) ||
+ ((GetKeyState(VK_TAB) < 0) || (wParam == VK_TAB)) ||
+ ((GetKeyState(VK_SHIFT) < 0) || (wParam == VK_SHIFT)) ||
+ ((GetKeyState(VK_CONTROL) < 0) || (wParam == VK_CONTROL)) ||
+ ((GetKeyState(VK_ESCAPE) < 0) || (wParam == VK_ESCAPE)) ||
+ ((GetKeyState(VK_LWIN) < 0) || (wParam == VK_LWIN)) ||
+ ((GetKeyState(VK_RWIN) < 0) || (wParam == VK_RWIN))) {
+ return CallNextHookEx(hKeyBoardHook, code, wParam, lParam);
+ }
+ }
+
+ switch (wParam) {
+ case VK_NUMLOCK:
+ case VK_CAPITAL:
+ case VK_SCROLL:
+ if (!ignoreLockKeys)
+ lastInput = GetTickCount();
+ break;
+
+ case VK_TAB:
+ case VK_SHIFT:
+ case VK_CONTROL:
+ case VK_MENU:
+ case VK_ESCAPE:
+ case VK_LWIN:
+ case VK_RWIN:
+ if (!ignoreSysKeys)
+ lastInput = GetTickCount();
+ break;
+
+ default:
+ lastInput = GetTickCount();
+ break;
+ }
+ }
+
+ return CallNextHookEx(hKeyBoardHook, code, wParam, lParam);
+}
+
+static int HookWindowsHooks(int hookMiranda, int hookAll)
+{
+ if (hookMiranda) {
+ if (monitorKeyboard && hMirandaKeyBoardHook == nullptr)
+ hMirandaKeyBoardHook = SetWindowsHookEx(WH_KEYBOARD, MirandaKeyBoardHookFunction, nullptr, GetCurrentThreadId());
+ if (monitorMouse && hMirandaMouseHook == nullptr)
+ hMirandaMouseHook = SetWindowsHookEx(WH_MOUSE, MirandaMouseHookFunction, nullptr, GetCurrentThreadId());
+ }
+ if (hookAll) {
+ if (monitorKeyboard && hKeyBoardHook == nullptr)
+ hKeyBoardHook = SetWindowsHookEx(WH_KEYBOARD, KeyBoardHookFunction, nullptr, GetCurrentThreadId());
+ if (monitorMouse && hMouseHook == nullptr)
+ hMouseHook = SetWindowsHookEx(WH_MOUSE, MouseHookFunction, nullptr, GetCurrentThreadId());
+ }
+
+ return 0;
+}
+
+static int UnhookWindowsHooks()
+{
+ UnhookWindowsHookEx(hMouseHook);
+ UnhookWindowsHookEx(hKeyBoardHook);
+ UnhookWindowsHookEx(hMirandaMouseHook);
+ UnhookWindowsHookEx(hMirandaKeyBoardHook);
+
+ hMouseHook = hKeyBoardHook = hMirandaMouseHook = hMirandaKeyBoardHook = nullptr;
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Load from DB
+
+int LoadAutoAwaySetting(SMProto &autoAwaySetting, char *protoName)
+{
+ char setting[128];
+ mir_snprintf(setting, "%s_OptionFlags", protoName);
+ autoAwaySetting.optionFlags = AAAPlugin.getWord(setting, FLAG_LV2ONINACTIVE | FLAG_RESET | FLAG_ENTERIDLE);
+ mir_snprintf(setting, "%s_AwayTime", protoName);
+ autoAwaySetting.awayTime = AAAPlugin.getWord(setting, SETTING_AWAYTIME_DEFAULT);
+ mir_snprintf(setting, "%s_NATime", protoName);
+ autoAwaySetting.naTime = AAAPlugin.getWord(setting, SETTING_NATIME_DEFAULT);
+ mir_snprintf(setting, "%s_StatusFlags", protoName);
+ autoAwaySetting.statusFlags = AAAPlugin.getWord(setting, StatusModeToProtoFlag(ID_STATUS_ONLINE) | StatusModeToProtoFlag(ID_STATUS_FREECHAT));
+
+ int flags;
+ if (g_bAAASettingSame)
+ flags = 0xFFFFFF;
+ else
+ flags = CallProtoService(protoName, PS_GETCAPS, PFLAGNUM_2, 0) & ~CallProtoService(protoName, PS_GETCAPS, (WPARAM)PFLAGNUM_5, 0);
+ mir_snprintf(setting, "%s_Lv1Status", protoName);
+ autoAwaySetting.lv1Status = AAAPlugin.getWord(setting, (flags & StatusModeToProtoFlag(ID_STATUS_AWAY)) ? ID_STATUS_AWAY : ID_STATUS_OFFLINE);
+ mir_snprintf(setting, "%s_Lv2Status", protoName);
+ autoAwaySetting.lv2Status = AAAPlugin.getWord(setting, (flags & StatusModeToProtoFlag(ID_STATUS_NA)) ? ID_STATUS_NA : ID_STATUS_OFFLINE);
+
+ return 0;
+}
+
+void AAAUnloadOptions()
+{
+ UnhookWindowsHooks();
+ if (hAutoAwayTimer != 0)
+ KillTimer(nullptr, hAutoAwayTimer);
+}
+
+void AAALoadOptions()
+{
+ // if bOverride is enabled, samesettings will be ignored (for options loading)
+ AAAUnloadOptions();
+
+ bool monitorMiranda = false, monitorAll = false;
+
+ ignoreLockKeys = AAAPlugin.getByte(SETTING_IGNLOCK, FALSE);
+ ignoreSysKeys = AAAPlugin.getByte(SETTING_IGNSYSKEYS, FALSE);
+ ignoreAltCombo = AAAPlugin.getByte(SETTING_IGNALTCOMBO, FALSE);
+ monitorMouse = AAAPlugin.getByte(SETTING_MONITORMOUSE, TRUE) != 0;
+ monitorKeyboard = AAAPlugin.getByte(SETTING_MONITORKEYBOARD, TRUE) != 0;
+ lastInput = lastMirandaInput = GetTickCount();
+
+ for (auto &it : protoList) {
+ char *protoName;
+ if (g_bAAASettingSame)
+ protoName = SETTING_ALL;
+ else
+ protoName = it->m_szName;
+ LoadAutoAwaySetting(*it, protoName);
+
+ if (it->optionFlags & FLAG_MONITORMIRANDA)
+ monitorMiranda = true;
+ else if (ignoreLockKeys || ignoreSysKeys || ignoreAltCombo || (monitorMouse != monitorKeyboard))
+ monitorAll = true;
+ }
+
+ HookWindowsHooks(monitorMiranda, monitorAll);
+ hAutoAwayTimer = SetTimer(nullptr, 0, AAAPlugin.getWord(SETTING_AWAYCHECKTIMEINSECS, 5) * 1000, AutoAwayTimer);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Inits & stuff
+
+static int AutoAwayShutdown(WPARAM, LPARAM)
+{
+ AAAUnloadOptions();
+ return 0;
+}
+
+static int AAAModuleLoaded(WPARAM, LPARAM)
+{
+ hEvents[0] = HookEvent(ME_OPT_INITIALISE, AutoAwayOptInitialise);
+ hEvents[1] = HookEvent(ME_SYSTEM_PRESHUTDOWN, AutoAwayShutdown);
+ hEvents[2] = HookEvent(ME_PROTO_ACK, ProcessProtoAck);
+
+ mouseStationaryTimer = 0;
+ lastInput = lastMirandaInput = GetTickCount();
+
+ AAALoadOptions();
+ return 0;
+}
+
+void AdvancedAutoAwayLoad()
+{
+ g_bAAASettingSame = AAAPlugin.getByte(SETTING_SAMESETTINGS);
+
+ if (g_bMirandaLoaded)
+ AAAModuleLoaded(0, 0);
+ else
+ HookEvent(ME_SYSTEM_MODULESLOADED, AAAModuleLoaded);
+}
+
+void AdvancedAutoAwayUnload()
+{
+ if (g_bMirandaLoaded)
+ AutoAwayShutdown(0, 0);
+
+ KillModuleOptions(&AAAPlugin);
+
+ for (auto &it : hEvents) {
+ UnhookEvent(it);
+ it = nullptr;
+ }
+
+ protoList.destroy();
+}