summaryrefslogtreecommitdiff
path: root/plugins/StatusManager/src/KeepStatus
diff options
context:
space:
mode:
authoraunsane <aunsane@gmail.com>2017-01-06 16:19:32 +0300
committeraunsane <aunsane@gmail.com>2017-01-06 20:10:47 +0300
commitb7336b2fc97092442ce643532f67466868a87812 (patch)
tree718b87c37090fe8bf7ae88b9d5da9b3b957c3e3c /plugins/StatusManager/src/KeepStatus
parentac1d88965de3022be2f484c2f58185ae75b4fe00 (diff)
StatusManager: #662
- files splitted by folders - main.cpp cleanup - project cleanup
Diffstat (limited to 'plugins/StatusManager/src/KeepStatus')
-rw-r--r--plugins/StatusManager/src/KeepStatus/keepstatus.cpp1246
-rw-r--r--plugins/StatusManager/src/KeepStatus/keepstatus.h124
-rw-r--r--plugins/StatusManager/src/KeepStatus/ks_options.cpp589
3 files changed, 1959 insertions, 0 deletions
diff --git a/plugins/StatusManager/src/KeepStatus/keepstatus.cpp b/plugins/StatusManager/src/KeepStatus/keepstatus.cpp
new file mode 100644
index 0000000000..f975b64793
--- /dev/null
+++ b/plugins/StatusManager/src/KeepStatus/keepstatus.cpp
@@ -0,0 +1,1246 @@
+/*
+ KeepStatus 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
+ */
+
+#include "..\stdafx.h"
+
+struct TimerInfo {
+ int timer;
+ int timeout;
+ BOOL restart;
+ int result;
+ HANDLE hEvent;
+};
+
+HANDLE hMainThread = 0;
+unsigned long mainThreadId = 0;
+
+HANDLE hKSModuleLoadedHook = NULL,
+ hConnectionEvent = NULL,
+ hStopRecon = NULL,
+ hEnableProto = NULL,
+ hIsProtoEnabled = NULL,
+ hAnnounceStat = NULL;
+
+static mir_cs GenTimerCS, GenStatusCS, CheckContinueslyCS;
+
+static HANDLE hProtoAckHook = NULL;
+static HANDLE hStatusChangeHook = NULL;
+static HANDLE hCSStatusChangeHook = NULL;
+static HANDLE hCSStatusChangeExHook = NULL;
+
+static HWND hMessageWindow = NULL;
+
+static int CompareConnections(const TConnectionSettings *p1, const TConnectionSettings *p2)
+{
+ return mir_strcmp(p1->szName, p2->szName);
+}
+
+static OBJLIST<TConnectionSettings> connectionSettings(10, CompareConnections);
+
+static UINT_PTR checkConnectionTimerId = 0;
+static UINT_PTR afterCheckTimerId = 0;
+static UINT_PTR processAckTimerId = 0;
+static UINT_PTR checkContinTimerId = 0;
+static UINT_PTR checkConnectingTimerId = 0;
+static int retryCount = 0;
+static BOOL bLastPingResult = TRUE;
+// variables (options)
+static int maxRetries = 0;
+static int initDelay = 0;
+static int currentDelay = 0;
+static int maxDelay = 0;
+static int ackDelay = 500;
+static int increaseExponential = 0;
+static int showConnectionPopups = 0;
+// prototypes
+static int StartTimer(int timer, int timeout, BOOL restart);
+static int StopTimer(int timer);
+static void GetCurrentConnectionSettings();
+static int AssignStatus(TConnectionSettings* connSetting, int status, int lastStatus, wchar_t *szMsg);
+static int ProcessProtoAck(WPARAM wParam, LPARAM lParam);
+static VOID CALLBACK CheckConnectingTimer(HWND hwnd, UINT message, UINT_PTR idEvent, DWORD dwTime);
+static VOID CALLBACK CheckAckStatusTimer(HWND hwnd, UINT message, UINT_PTR idEvent, DWORD dwTime);
+static int StatusChange(WPARAM wParam, LPARAM lParam);
+static int CSStatusChange(WPARAM wParam, LPARAM lParam);
+static int CSStatusChangeEx(WPARAM wParam, LPARAM lParam);
+static VOID CALLBACK StatusChangeTimer(HWND hwnd, UINT message, UINT_PTR idEvent, DWORD dwTime);
+static VOID CALLBACK CheckConnectionTimer(HWND hwnd, UINT message, UINT_PTR idEvent, DWORD dwTime);
+static int StopChecking();
+static VOID CALLBACK AfterCheckTimer(HWND hwnd, UINT message, UINT_PTR idEvent, DWORD dwTime);
+static void ContinueslyCheckFunction(void *arg);
+static VOID CALLBACK CheckContinueslyTimer(HWND hwnd, UINT message, UINT_PTR idEvent, DWORD dwTime);
+INT_PTR IsProtocolEnabledService(WPARAM wParam, LPARAM lParam);
+
+static int ProcessPopup(int reason, LPARAM lParam);
+static INT_PTR ShowPopup(wchar_t *msg, HICON hIcon);
+LRESULT CALLBACK KSPopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+static DWORD CALLBACK MessageWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// options.c
+extern int KeepStatusOptionsInit(WPARAM wparam, LPARAM);
+
+TConnectionSettings::TConnectionSettings(PROTOACCOUNT *pa)
+{
+ cbSize = sizeof(PROTOCOLSETTINGEX);
+ szName = pa->szModuleName;
+ tszAccName = pa->tszAccountName;
+ szMsg = NULL;
+
+ int iStatus = CallProtoService(pa->szModuleName, PS_GETSTATUS, 0, 0);
+ AssignStatus(this, iStatus, iStatus, NULL);
+}
+
+TConnectionSettings::~TConnectionSettings()
+{
+ if (szMsg != NULL)
+ free(szMsg);
+}
+
+int KSLoadOptions()
+{
+ UnhookEvent(hProtoAckHook);
+ UnhookEvent(hStatusChangeHook);
+ UnhookEvent(hCSStatusChangeHook);
+ UnhookEvent(hCSStatusChangeExHook);
+ hProtoAckHook = hStatusChangeHook = hCSStatusChangeHook = hCSStatusChangeExHook = 0;
+
+ if (IsWindow(hMessageWindow))
+ DestroyWindow(hMessageWindow);
+ if (StartTimer(IDT_CHECKCONTIN, -1, FALSE)) {
+ WSACleanup();
+ }
+ StopTimer(IDT_CHECKCONN | IDT_PROCESSACK | IDT_AFTERCHECK | IDT_CHECKCONTIN | IDT_CHECKCONNECTING);
+
+ GetCurrentConnectionSettings();
+
+ if (db_get_b(NULL, KSMODULENAME, SETTING_CHECKCONNECTION, FALSE)) {
+ if (db_get_b(NULL, KSMODULENAME, SETTING_CONTCHECK, FALSE)) {
+ if (db_get_b(NULL, KSMODULENAME, SETTING_BYPING, FALSE)) {
+ WSADATA wsaData;
+ WSAStartup(MAKEWORD(2, 2), &wsaData);
+ }
+ StartTimer(IDT_CHECKCONTIN, 0, FALSE);
+ }
+ increaseExponential = db_get_b(NULL, KSMODULENAME, SETTING_INCREASEEXPONENTIAL, FALSE);
+ currentDelay = initDelay = 1000 * db_get_dw(NULL, KSMODULENAME, SETTING_INITDELAY, DEFAULT_INITDELAY);
+ maxDelay = 1000 * db_get_dw(NULL, KSMODULENAME, SETTING_MAXDELAY, DEFAULT_MAXDELAY);
+ maxRetries = db_get_b(NULL, KSMODULENAME, SETTING_MAXRETRIES, 0);
+ if (maxRetries == 0)
+ maxRetries = -1;
+ hProtoAckHook = HookEvent(ME_PROTO_ACK, ProcessProtoAck);
+ hStatusChangeHook = HookEvent(ME_CLIST_STATUSMODECHANGE, StatusChange);
+ if (ServiceExists(ME_CS_STATUSCHANGE))
+ hCSStatusChangeHook = HookEvent(ME_CS_STATUSCHANGE, CSStatusChange);
+ hCSStatusChangeExHook = HookEvent(ME_CS_STATUSCHANGEEX, CSStatusChangeEx);
+ if (db_get_b(NULL, KSMODULENAME, SETTING_CHECKAPMRESUME, 0)) {
+ if (!IsWindow(hMessageWindow)) {
+ hMessageWindow = CreateWindowEx(0, L"STATIC", NULL, 0, 0, 0, 0, 0, NULL, NULL, NULL, NULL);
+ SetWindowLongPtr(hMessageWindow, GWLP_WNDPROC, (LONG_PTR)MessageWndProc);
+ }
+ }
+ retryCount = 0;
+ }
+
+ return 0;
+}
+
+static void GetCurrentConnectionSettings()
+{
+ connectionSettings.destroy();
+
+ int count;
+ PROTOACCOUNT** protos;
+ Proto_EnumAccounts(&count, &protos);
+
+ for (int i = 0; i < count; i++)
+ if (IsSuitableProto(protos[i]))
+ connectionSettings.insert(new TConnectionSettings(protos[i]));
+}
+
+static PROTOCOLSETTINGEX** GetCurrentProtoSettingsCopy()
+{
+ mir_cslock lck(GenStatusCS);
+ PROTOCOLSETTINGEX **ps = (PROTOCOLSETTINGEX**)malloc(connectionSettings.getCount()*sizeof(PROTOCOLSETTINGEX *));
+ if (ps == NULL) {
+ return NULL;
+ }
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ ps[i] = (PROTOCOLSETTINGEX*)calloc(1, sizeof(PROTOCOLSETTINGEX));
+ if (ps[i] == NULL) {
+ free(ps);
+ return NULL;
+ }
+
+ TConnectionSettings& cs = connectionSettings[i];
+ ps[i]->cbSize = sizeof(PROTOCOLSETTINGEX);
+ ps[i]->lastStatus = cs.lastStatus;
+ ps[i]->status = cs.status;
+ ps[i]->szMsg = NULL;
+ ps[i]->szName = cs.szName;
+ ps[i]->tszAccName = cs.tszAccName;
+ }
+
+ return ps;
+}
+
+static void FreeProtoSettings(PROTOCOLSETTINGEX** ps)
+{
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ if (ps[i]->szMsg != NULL)
+ free(ps[i]->szMsg);
+ free(ps[i]);
+ }
+ free(ps);
+}
+
+static int AssignStatus(TConnectionSettings* cs, int status, int lastStatus, wchar_t *szMsg)
+{
+ if (status < MIN_STATUS || status > MAX_STATUS)
+ return -1;
+
+ mir_cslock lck(GenStatusCS);
+
+ char dbSetting[128];
+ mir_snprintf(dbSetting, "%s_enabled", cs->szName);
+ cs->lastStatus = lastStatus == 0 ? cs->status : lastStatus;
+ if (!db_get_b(NULL, KSMODULENAME, dbSetting, 1))
+ cs->status = ID_STATUS_DISABLED;
+ else if (status == ID_STATUS_LAST)
+ cs->status = cs->lastStatus;
+ else
+ cs->status = status;
+
+ log_infoA("KeepStatus: assigning status %d to %s", cs->status, cs->szName);
+
+ if (szMsg != NULL && mir_wstrcmp(szMsg, cs->szMsg)) {
+ if (cs->szMsg != NULL)
+ free(cs->szMsg);
+
+ cs->szMsg = wcsdup(szMsg);
+ }
+ else if (szMsg != cs->szMsg) {
+ if (cs->szMsg != NULL)
+ free(cs->szMsg);
+
+ cs->szMsg = NULL;
+ }
+ return 0;
+}
+
+static int GetStatus(const TConnectionSettings& cs)
+{
+ if (cs.status == ID_STATUS_CURRENT)
+ return CallProtoService(cs.szName, PS_GETSTATUS, 0, 0);
+
+ return cs.status;
+}
+
+static int SetCurrentStatus()
+{
+ PROTOCOLSETTINGEX **ps = GetCurrentProtoSettingsCopy();
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ int realStatus = CallProtoService(ps[i]->szName, PS_GETSTATUS, 0, 0);
+ if (ps[i]->status == ID_STATUS_DISABLED || ps[i]->status == realStatus) { // ignore this proto by removing it's name (not so nice)
+ ps[i]->szName = "";
+ }
+ else if ((ps[i]->status != ID_STATUS_DISABLED) && (ps[i]->status != realStatus) && (realStatus != ID_STATUS_OFFLINE) && (db_get_b(NULL, KSMODULENAME, SETTING_FIRSTOFFLINE, FALSE))) {
+ // force offline before reconnecting
+ log_infoA("KeepStatus: Setting %s offline before making a new connection attempt", ps[i]->szName);
+ CallProtoService(ps[i]->szName, PS_SETSTATUS, (WPARAM)ID_STATUS_OFFLINE, 0);
+ }
+ }
+ ProcessPopup(KS_CONN_STATE_RETRY, (LPARAM)ps);
+ INT_PTR ret = CallService(MS_CS_SETSTATUSEX, (WPARAM)&ps, 0);
+ FreeProtoSettings(ps);
+
+ return ret;
+}
+
+static int StatusChange(WPARAM wParam, LPARAM lParam)
+{
+ char* szProto = (char *)lParam;
+ if (szProto == NULL) { // global status change
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ TConnectionSettings& cs = connectionSettings[i];
+ if (GetStatus(cs) != ID_STATUS_DISABLED)
+ if (db_get_b(NULL, KSMODULENAME, SETTING_NOLOCKED, 0) ||
+ !db_get_b(NULL, cs.szName, "LockMainStatus", 0))
+ AssignStatus(&cs, wParam, 0, cs.szMsg);
+ }
+ }
+ else {
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ TConnectionSettings& cs = connectionSettings[i];
+ if (GetStatus(cs) != ID_STATUS_DISABLED && !mir_strcmp(cs.szName, szProto))
+ AssignStatus(&cs, wParam, 0, cs.szMsg);
+ }
+ }
+
+ return 0;
+}
+
+static int CSStatusChange(WPARAM wParam, LPARAM)
+{
+ // the status was changed by commonstatus (old)
+ if (wParam != 0) {
+ PROTOCOLSETTING** protoSettings = *(PROTOCOLSETTING***)wParam;
+
+ if (protoSettings == NULL)
+ return -1;
+
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ for (int j = 0; j < connectionSettings.getCount(); j++) {
+ if ((protoSettings[i]->szName == NULL) || (connectionSettings[j].szName == NULL))
+ continue;
+
+ if (!mir_strcmp(protoSettings[i]->szName, connectionSettings[j].szName))
+ if (GetStatus(connectionSettings[j]) != ID_STATUS_DISABLED)
+ AssignStatus(&connectionSettings[j], protoSettings[i]->status, protoSettings[i]->lastStatus, connectionSettings[j].szMsg);
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int CSStatusChangeEx(WPARAM wParam, LPARAM)
+{
+ // the status was changed by commonstatus (new)
+ if (wParam != 0) {
+ PROTOCOLSETTINGEX** protoSettings = *(PROTOCOLSETTINGEX***)wParam;
+
+ if (protoSettings == NULL)
+ return -1;
+
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ for (int j = 0; j < connectionSettings.getCount(); j++) {
+ if ((protoSettings[i]->szName == NULL) || (connectionSettings[j].szName == NULL))
+ continue;
+ if (!mir_strcmp(protoSettings[i]->szName, connectionSettings[j].szName)) {
+ if (GetStatus(connectionSettings[j]) != ID_STATUS_DISABLED)
+ AssignStatus(&connectionSettings[j], protoSettings[i]->status, protoSettings[i]->lastStatus, protoSettings[i]->szMsg);
+ }
+ }
+ }
+ }
+
+ return 0;
+}
+
+static int StartTimerFunction(int timer, int timeout, BOOL restart)
+{
+ int res = 0;
+
+ mir_cslock lck(GenTimerCS);
+ log_debugA("StartTimer: %d, %d, %d", timer, timeout, restart);
+ log_debugA("ack: %u, chk: %u, aft: %u, cnt: %u, con: %u", processAckTimerId, checkConnectionTimerId, afterCheckTimerId, checkContinTimerId, checkConnectingTimerId);
+ if (timer & IDT_PROCESSACK) {
+ res = (processAckTimerId == 0) ? 0 : 1;
+ if (((processAckTimerId == 0) && (checkConnectionTimerId == 0)) || (restart)) {
+ if (timeout != -1) {
+ if (restart)
+ KillTimer(NULL, processAckTimerId);
+ if (timeout == 0)
+ processAckTimerId = SetTimer(NULL, 0, ackDelay, CheckAckStatusTimer);
+ else
+ processAckTimerId = SetTimer(NULL, 0, timeout, CheckAckStatusTimer);
+ }
+ }
+ }
+
+ if (timer & IDT_CHECKCONN) {
+ res = (checkConnectionTimerId == 0 ? 0 : 1) || res;
+ if ((checkConnectionTimerId == 0) || (restart)) {
+ if (timeout != -1) {
+ if (restart)
+ KillTimer(NULL, checkConnectionTimerId);
+ if (timeout == 0)
+ checkConnectionTimerId = SetTimer(NULL, 0, initDelay, CheckConnectionTimer);
+ else
+ checkConnectionTimerId = SetTimer(NULL, 0, timeout, CheckConnectionTimer);
+ }
+ }
+ }
+
+ if (timer & IDT_AFTERCHECK) {
+ res = (afterCheckTimerId == 0 ? 0 : 1) || res;
+ if ((afterCheckTimerId == 0) || (restart)) {
+ if (timeout != -1) {
+ if (restart)
+ KillTimer(NULL, afterCheckTimerId);
+ if (timeout == 0)
+ afterCheckTimerId = SetTimer(NULL, 0, initDelay / 2, AfterCheckTimer);
+ else
+ afterCheckTimerId = SetTimer(NULL, 0, timeout, AfterCheckTimer);
+ }
+ }
+ }
+
+ if (timer & IDT_CHECKCONTIN) {
+ res = (checkContinTimerId == 0 ? 0 : 1) || res;
+ if ((checkContinTimerId == 0) || (restart)) {
+ if (timeout != -1) {
+ if (restart)
+ KillTimer(NULL, checkContinTimerId);
+ if (timeout == 0) {
+ checkContinTimerId = SetTimer(NULL, 0, 1000 * db_get_dw(NULL, KSMODULENAME, SETTING_CNTDELAY, CHECKCONTIN_DELAY), CheckContinueslyTimer);
+ }
+ else
+ checkContinTimerId = SetTimer(NULL, 0, timeout, CheckContinueslyTimer);
+ }
+ }
+ }
+
+ if (timer & IDT_CHECKCONNECTING) {
+ res = (checkConnectingTimerId == 0 ? 0 : 1) || res;
+ if ((checkConnectingTimerId == 0) || (restart)) {
+ if (timeout != -1) {
+ if (restart)
+ KillTimer(NULL, checkConnectingTimerId);
+ if (timeout == 0) {
+ timeout = initDelay / 2;
+ }
+ checkConnectingTimerId = SetTimer(NULL, 0, timeout, CheckConnectingTimer);
+ }
+ }
+ }
+
+ log_debugA("ack: %u, chk: %u, aft: %u, cnt: %u, con: %u", processAckTimerId, checkConnectionTimerId, afterCheckTimerId, checkContinTimerId, checkConnectingTimerId);
+ log_debugA("StartTimer done %d", res);
+
+ return res;
+}
+
+static VOID CALLBACK StartTimerApcProc(ULONG_PTR param)
+{
+ struct TimerInfo *ti = (struct TimerInfo *)param;
+ log_debugA("StartTimerApcProc %d %d %d", ti->timer, ti->timeout, ti->restart);
+ ti->result = StartTimerFunction(ti->timer, ti->timeout, ti->restart);
+ SetEvent(ti->hEvent);
+}
+
+static int StartTimer(int timer, int timeout, BOOL restart)
+{
+ if (GetCurrentThreadId() == mainThreadId)
+ return StartTimerFunction(timer, timeout, restart);
+
+ TimerInfo *ti = (TimerInfo*)calloc(1, sizeof(struct TimerInfo));
+ ti->timer = timer;
+ ti->timeout = timeout;
+ ti->restart = restart;
+ ti->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
+ QueueUserAPC(StartTimerApcProc, hMainThread, (ULONG_PTR)ti);
+ WaitForSingleObject(ti->hEvent, INFINITE);
+ CloseHandle(ti->hEvent);
+ int res = ti->result;
+ free(ti);
+ return res;
+}
+
+static int StopTimer(int timer)
+{
+ int res = 0;
+
+ mir_cslock lck(GenTimerCS);
+ log_debugA("StopTimer %d", timer);
+ log_debugA("ack: %u, chk: %u, aft: %u, cnt: %u, con: %u", processAckTimerId, checkConnectionTimerId, afterCheckTimerId, checkContinTimerId, checkConnectingTimerId);
+
+ if (timer & IDT_PROCESSACK) {
+ if (processAckTimerId == 0)
+ res = 0;
+ else {
+ KillTimer(NULL, processAckTimerId);
+ processAckTimerId = 0;
+ res = 1;
+ }
+ }
+
+ if (timer & IDT_CHECKCONN) {
+ if (checkConnectionTimerId == 0)
+ res = 0 || res;
+ else {
+ KillTimer(NULL, checkConnectionTimerId);
+ checkConnectionTimerId = 0;
+ res = 1;
+ }
+ }
+
+ if (timer & IDT_AFTERCHECK) {
+ if (afterCheckTimerId == 0)
+ res = 0 || res;
+ else {
+ KillTimer(NULL, afterCheckTimerId);
+ afterCheckTimerId = 0;
+ res = 1;
+ }
+ }
+
+ if (timer & IDT_CHECKCONTIN) {
+ if (checkContinTimerId == 0)
+ res = 0 || res;
+ else {
+ KillTimer(NULL, checkContinTimerId);
+ checkContinTimerId = 0;
+ res = 1;
+ }
+ }
+
+ if (timer & IDT_CHECKCONNECTING) {
+ if (checkConnectingTimerId == 0)
+ res = 0 || res;
+ else {
+ KillTimer(NULL, checkConnectingTimerId);
+ checkConnectingTimerId = 0;
+ res = 1;
+ }
+ }
+
+ log_debugA("ack: %u, chk: %u, aft: %u, cnt: %u, con: %u", processAckTimerId, checkConnectionTimerId, afterCheckTimerId, checkContinTimerId, checkConnectingTimerId);
+ log_debugA("StopTimer done %d", res);
+
+ return res;
+}
+
+static int ProcessProtoAck(WPARAM, LPARAM lParam)
+{
+ ACKDATA *ack = (ACKDATA*)lParam;
+
+ if (ack->type != ACKTYPE_STATUS && ack->type != ACKTYPE_LOGIN)
+ return 0;
+
+ char dbSetting[128];
+ mir_snprintf(dbSetting, "%s_enabled", ack->szModule);
+ if (!db_get_b(NULL, KSMODULENAME, dbSetting, 1))
+ return 0;
+
+ if (ack->type == ACKTYPE_STATUS && ack->result == ACKRESULT_SUCCESS) {
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ TConnectionSettings& cs = connectionSettings[i];
+ if (!mir_strcmp(cs.szName, ack->szModule))
+ cs.lastStatusAckTime = GetTickCount();
+ }
+ StartTimer(IDT_PROCESSACK, 0, FALSE);
+ return 0;
+ }
+
+ if (ack->type == ACKTYPE_LOGIN) {
+ if (ack->lParam == LOGINERR_OTHERLOCATION) {
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ TConnectionSettings& cs = connectionSettings[i];
+ if (!mir_strcmp(ack->szModule, cs.szName)) {
+ AssignStatus(&cs, ID_STATUS_OFFLINE, 0, NULL);
+ if (db_get_b(NULL, KSMODULENAME, SETTING_CNCOTHERLOC, 0)) {
+ StopTimer(IDT_PROCESSACK);
+ for (int j = 0; j < connectionSettings.getCount(); j++) {
+ AssignStatus(&connectionSettings[j], ID_STATUS_OFFLINE, 0, NULL);
+ }
+ }
+
+ NotifyEventHooks(hConnectionEvent, (WPARAM)KS_CONN_STATE_OTHERLOCATION, (LPARAM)cs.szName);
+ ProcessPopup(KS_CONN_STATE_OTHERLOCATION, (LPARAM)ack->szModule);
+ }
+ }
+ }
+ else if (ack->result == ACKRESULT_FAILED) {
+ // login failed
+ NotifyEventHooks(hConnectionEvent, (WPARAM)KS_CONN_STATE_LOGINERROR, (LPARAM)ack->szModule);
+ switch (db_get_b(NULL, KSMODULENAME, SETTING_LOGINERR, LOGINERR_NOTHING)) {
+ case LOGINERR_CANCEL:
+ {
+ log_infoA("KeepStatus: cancel on login error (%s)", ack->szModule);
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ TConnectionSettings& cs = connectionSettings[i];
+ if (!mir_strcmp(ack->szModule, cs.szName))
+ AssignStatus(&cs, ID_STATUS_OFFLINE, 0, NULL);
+ }
+ ProcessPopup(KS_CONN_STATE_LOGINERROR, (LPARAM)ack->szModule);
+ StopChecking();
+ }
+ break;
+
+ case LOGINERR_SETDELAY:
+ {
+ int newDelay = 1000 * db_get_dw(NULL, KSMODULENAME, SETTING_LOGINERR_DELAY, DEFAULT_MAXDELAY);
+ log_infoA("KeepStatus: set delay to %d on login error (%s)", newDelay / 1000, ack->szModule);
+ StartTimer(IDT_CHECKCONN, newDelay, TRUE);
+ }
+ ProcessPopup(KS_CONN_STATE_LOGINERROR, (LPARAM)ack->szModule);
+ break;
+
+ default:
+ case LOGINERR_NOTHING:
+ StartTimer(IDT_PROCESSACK, 0, FALSE);
+ break;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static VOID CALLBACK CheckConnectingTimer(HWND, UINT, UINT_PTR, DWORD)
+{
+ int maxConnectingTime;
+
+ StopTimer(IDT_CHECKCONNECTING);
+ //log_debugA("KeepStatus: CheckConnectingTimer");
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ TConnectionSettings& cs = connectionSettings[i];
+
+ int curStatus = GetStatus(cs);
+ if (IsStatusConnecting(curStatus)) { // connecting
+ maxConnectingTime = db_get_dw(NULL, KSMODULENAME, SETTING_MAXCONNECTINGTIME, 0);
+ if (maxConnectingTime > 0) {
+ if ((unsigned int)maxConnectingTime <= ((GetTickCount() - cs.lastStatusAckTime) / 1000)) {
+ // set offline
+ log_infoA("KeepStatus: %s is too long connecting; setting offline", cs.szName);
+ CallProtoService(cs.szName, PS_SETSTATUS, (WPARAM)ID_STATUS_OFFLINE, 0);
+ }
+ }
+ }
+ }
+}
+
+static VOID CALLBACK CheckAckStatusTimer(HWND, UINT, UINT_PTR, DWORD)
+{
+ int maxConnectingTime;
+ bool needChecking = false;
+
+ StopTimer(IDT_PROCESSACK);
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ TConnectionSettings& cs = connectionSettings[i];
+
+ int curStatus = GetStatus(cs);
+ int newStatus = CallProtoService(cs.szName, PS_GETSTATUS, 0, 0);
+ // ok, np
+ if (curStatus == ID_STATUS_CURRENT || curStatus == ID_STATUS_DISABLED || curStatus == newStatus || newStatus > MAX_STATUS)
+ continue;
+
+ if (IsStatusConnecting(newStatus)) { // connecting
+ maxConnectingTime = db_get_dw(NULL, KSMODULENAME, SETTING_MAXCONNECTINGTIME, 0);
+ if (maxConnectingTime > 0)
+ StartTimer(IDT_CHECKCONNECTING, (maxConnectingTime * 1000 - (GetTickCount() - cs.lastStatusAckTime)), FALSE);
+ }
+ // keepstatus' administration was wrong!
+ else if (newStatus != ID_STATUS_OFFLINE)
+ AssignStatus(&cs, newStatus, 0, NULL);
+
+ // connection lost
+ else if (newStatus == ID_STATUS_OFFLINE) {// start checking connection
+ if (!StartTimer(IDT_CHECKCONN, -1, FALSE)) { /* check if not already checking */
+ needChecking = true;
+ log_infoA("KeepStatus: connection lost! (%s)", cs.szName);
+ NotifyEventHooks(hConnectionEvent, (WPARAM)KS_CONN_STATE_LOST, (LPARAM)cs.szName);
+ ProcessPopup(KS_CONN_STATE_LOST, (LPARAM)cs.szName);
+ }
+ }
+ }
+
+ if (needChecking)
+ StartTimer(IDT_CHECKCONN, initDelay, FALSE);
+}
+
+static VOID CALLBACK CheckConnectionTimer(HWND, UINT, UINT_PTR, DWORD)
+{
+ int shouldBeStatus, realStatus;
+ HICON hIcon;
+
+ log_debugA("CheckConnectionTimer");
+ bool setStatus = false;
+ if (showConnectionPopups)
+ hIcon = Skin_LoadIcon(SKINICON_STATUS_OFFLINE);
+
+ for (int i = 0; i < connectionSettings.getCount() && !setStatus; i++) {
+ TConnectionSettings& cs = connectionSettings[i];
+ realStatus = CallProtoService(cs.szName, PS_GETSTATUS, 0, 0);
+ shouldBeStatus = GetStatus(cs);
+ if (shouldBeStatus == ID_STATUS_LAST)
+ shouldBeStatus = cs.lastStatus;
+ if (shouldBeStatus == ID_STATUS_DISABLED)
+ continue;
+ if ((shouldBeStatus != realStatus) && (realStatus == ID_STATUS_OFFLINE) || (realStatus < MIN_STATUS)) {
+ setStatus = true;
+ if (showConnectionPopups)
+ hIcon = Skin_LoadProtoIcon(cs.szName, ID_STATUS_OFFLINE);
+ }
+ }
+
+ // one of the status was wrong
+ if (setStatus && (maxRetries == -1 || retryCount < maxRetries)) {
+ if (increaseExponential)
+ currentDelay = min(2 * currentDelay, maxDelay);
+
+ if (((db_get_b(NULL, KSMODULENAME, SETTING_CHKINET, 0)) && (!InternetGetConnectedState(NULL, 0))) || ((db_get_b(NULL, KSMODULENAME, SETTING_BYPING, FALSE)) && (!bLastPingResult))) {
+ // no network
+ NotifyEventHooks(hConnectionEvent, (WPARAM)KS_CONN_STATE_RETRYNOCONN, (LPARAM)retryCount + 1);
+ ProcessPopup(KS_CONN_STATE_RETRYNOCONN, 0);
+ }
+ else {
+ NotifyEventHooks(hConnectionEvent, (WPARAM)KS_CONN_STATE_RETRY, (LPARAM)retryCount + 1);
+ /* set the status */
+ SetCurrentStatus();
+ }
+ retryCount += 1;
+ StartTimer(IDT_AFTERCHECK, min(currentDelay, AFTERCHECK_DELAY) / 2, FALSE);
+ StartTimer(IDT_CHECKCONN, currentDelay, TRUE); // restart this timer
+ }
+ else // all status set ok already, or stop checking
+ StopChecking();
+
+ log_debugA("CheckConnectionTimer done");
+}
+
+static int StopChecking()
+{
+ StopTimer(IDT_CHECKCONN | IDT_PROCESSACK | IDT_AFTERCHECK | IDT_CHECKCONNECTING);
+
+ BOOL isOk = TRUE;
+ for (int i = 0; i < connectionSettings.getCount() && isOk; i++) {
+ TConnectionSettings& cs = connectionSettings[i];
+ int curStatus = GetStatus(cs);
+ int newStatus = CallProtoService(cs.szName, PS_GETSTATUS, 0, 0);
+ if (newStatus != curStatus && curStatus != ID_STATUS_DISABLED) {
+ AssignStatus(&cs, newStatus, 0, NULL);
+ isOk = FALSE;
+ }
+ }
+
+ NotifyEventHooks(hConnectionEvent, (WPARAM)KS_CONN_STATE_STOPPEDCHECKING, (LPARAM)isOk);
+ ProcessPopup(KS_CONN_STATE_STOPPEDCHECKING, (LPARAM)isOk);
+ log_infoA("KeepStatus: stop checking (%s)", isOk ? "success" : "failure");
+ retryCount = 0;
+ currentDelay = initDelay;
+
+ return 0;
+}
+
+static VOID CALLBACK AfterCheckTimer(HWND, UINT, UINT_PTR, DWORD)
+{
+ // after each connection check, this function is called to see if connection was recovered
+ StopTimer(IDT_AFTERCHECK);
+
+ bool setStatus = false;
+
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ TConnectionSettings& cs = connectionSettings[i];
+ int realStatus = CallProtoService(cs.szName, PS_GETSTATUS, 0, 0);
+ int shouldBeStatus = GetStatus(cs);
+ if (shouldBeStatus == ID_STATUS_LAST) // this should never happen
+ shouldBeStatus = cs.lastStatus;
+ if (shouldBeStatus == ID_STATUS_DISABLED) // (on ignoring proto)
+ continue;
+ if ((shouldBeStatus != realStatus) && (realStatus == ID_STATUS_OFFLINE) || (realStatus < MIN_STATUS))
+ setStatus = true;
+ }
+
+ if (!setStatus || retryCount == maxRetries)
+ StopChecking();
+}
+
+static void CheckContinueslyFunction(void *)
+{
+ Thread_SetName("KeepStatus: CheckContinueslyFunction");
+
+ static int pingFailures = 0;
+
+ // one at the time is enough, do it the 'easy' way
+ mir_cslock lck(CheckContinueslyCS);
+
+ // do a ping, even if reconnecting
+ bool doPing = false;
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ TConnectionSettings& cs = connectionSettings[i];
+ int shouldBeStatus = GetStatus(cs);
+ if (shouldBeStatus == ID_STATUS_LAST)
+ shouldBeStatus = cs.lastStatus;
+
+ if (shouldBeStatus == ID_STATUS_DISABLED)
+ continue;
+
+ if (shouldBeStatus != ID_STATUS_OFFLINE) {
+ log_debugA("CheckContinueslyFunction: %s should be %d", cs.szName, shouldBeStatus);
+ doPing = true;
+ }
+ }
+
+ if (!doPing) {
+ log_debugA("CheckContinueslyFunction: All protocols should be offline, no need to check connection");
+ return;
+ }
+
+ BOOL ping = db_get_b(NULL, KSMODULENAME, SETTING_BYPING, FALSE);
+ if (ping) {
+ DBVARIANT dbv;
+ if (db_get(NULL, KSMODULENAME, SETTING_PINGHOST, &dbv))
+ ping = FALSE;
+ else {
+ char *start, *end;
+ char host[MAX_PATH];
+ DWORD *addr;
+ struct hostent *hostent;
+ char reply[sizeof(ICMP_ECHO_REPLY) + 8];
+
+ bLastPingResult = FALSE;
+ HANDLE hICMPFile = (HANDLE)IcmpCreateFile();
+ if (hICMPFile == INVALID_HANDLE_VALUE) {
+ bLastPingResult = TRUE;
+ log_infoA("KeepStatus: icmp.dll error (2)");
+ }
+ if (bLastPingResult == FALSE) {
+ start = dbv.pszVal;
+ while ((*start != '\0') && (!bLastPingResult)) {
+ end = start;
+ while ((*end != ' ') && (*end != '\0'))
+ end++;
+ memset(host, '\0', sizeof(host));
+ strncpy(host, start, end - start);
+ hostent = gethostbyname(host);
+ if (hostent != NULL) {
+ addr = (DWORD *)(*hostent->h_addr_list);
+ bLastPingResult = (IcmpSendEcho(hICMPFile, *addr, 0, 0, NULL, reply, sizeof(ICMP_ECHO_REPLY) + 8, 5000) != 0);
+
+ if (bLastPingResult)
+ pingFailures = 0;
+ else
+ pingFailures++;
+
+ log_debugA("CheckContinueslyFunction: pinging %s (result: %d/%d)", host, bLastPingResult, pingFailures);
+ }
+ else log_debugA("CheckContinueslyFunction: unable to resolve %s", host);
+
+ start = end;
+ while (*start == ' ')
+ start++;
+ }
+ }
+ IcmpCloseHandle(hICMPFile);
+ }
+ db_free(&dbv);
+ }
+
+ if (StartTimer(IDT_CHECKCONN, -1, FALSE)) {
+ return; // already connecting, leave
+ }
+
+ if (((!ping) && (!InternetGetConnectedState(NULL, 0))) || ((ping) && (!bLastPingResult) && (pingFailures >= db_get_w(NULL, KSMODULENAME, SETTING_PINGCOUNT, DEFAULT_PINGCOUNT)))) {
+ pingFailures = 0;
+
+ int count;
+ PROTOACCOUNT** protos;
+ Proto_EnumAccounts(&count, &protos);
+
+ for (int i = 0; i < count; i++) {
+ if (!IsSuitableProto(protos[i]))
+ continue;
+
+ if (IsStatusConnecting(CallProtoService(protos[i]->szModuleName, PS_GETSTATUS, 0, 0))) {
+ log_debugA("CheckContinueslyFunction: %s is connecting", protos[i]->szModuleName);
+ continue; // connecting, leave alone
+ }
+ if (IsProtocolEnabledService(0, (LPARAM)protos[i]->szModuleName)) {
+ log_debugA("CheckContinueslyFunction: forcing %s offline", protos[i]->szModuleName);
+ CallProtoService(protos[i]->szModuleName, PS_SETSTATUS, (WPARAM)ID_STATUS_OFFLINE, 0);
+ }
+ }
+ if (StartTimer(IDT_CHECKCONN | IDT_PROCESSACK, -1, FALSE)) {// are our 'set offlines' noticed?
+ log_debugA("CheckContinueslyFunction: currently checking");
+ return;
+ }
+ log_infoA("KeepStatus: connection lost! (continuesly check)");
+ NotifyEventHooks(hConnectionEvent, (WPARAM)KS_CONN_STATE_LOST, 0);
+ ProcessPopup(KS_CONN_STATE_LOST, 0);
+ maxRetries = db_get_b(NULL, KSMODULENAME, SETTING_MAXRETRIES, 0);
+ if (maxRetries == 0)
+ maxRetries = -1;
+ StartTimer(IDT_CHECKCONN, initDelay, FALSE);
+ }
+}
+
+static VOID CALLBACK CheckContinueslyTimer(HWND, UINT, UINT_PTR, DWORD)
+{
+ if (db_get_b(NULL, KSMODULENAME, SETTING_BYPING, FALSE))
+ mir_forkthread(CheckContinueslyFunction, NULL);
+ else
+ CheckContinueslyFunction(NULL);
+}
+
+// =============== popup ======================
+static wchar_t* GetHumanName(LPARAM lParam)
+{
+ PROTOACCOUNT *ProtoAccount = Proto_GetAccount((char*)lParam);
+ return (ProtoAccount != NULL) ? ProtoAccount->tszAccountName : TranslateT("Protocol");
+}
+
+static int ProcessPopup(int reason, LPARAM lParam)
+{
+ HICON hIcon = NULL;
+ wchar_t text[MAX_SECONDLINE];
+
+ if (!db_get_b(NULL, KSMODULENAME, SETTING_SHOWCONNECTIONPOPUPS, FALSE) || !ServiceExists(MS_POPUP_ADDPOPUPT))
+ return -1;
+
+ switch (reason) {
+ case KS_CONN_STATE_OTHERLOCATION: // lParam = 1 proto
+ if (!db_get_b(NULL, KSMODULENAME, SETTING_PUOTHER, TRUE))
+ return -1;
+
+ hIcon = Skin_LoadProtoIcon((char*)lParam, SKINICON_STATUS_OFFLINE);
+ mir_snwprintf(text, TranslateT("%s connected from another location"), GetHumanName(lParam));
+ break;
+
+ case KS_CONN_STATE_LOGINERROR: // lParam = 1 proto
+ if (!db_get_b(NULL, KSMODULENAME, SETTING_PUOTHER, TRUE))
+ return -1;
+
+ hIcon = Skin_LoadProtoIcon((char*)lParam, SKINICON_STATUS_OFFLINE);
+ if (db_get_b(NULL, KSMODULENAME, SETTING_LOGINERR, LOGINERR_NOTHING) == LOGINERR_CANCEL)
+ mir_snwprintf(text, TranslateT("%s login error, cancel reconnecting"), GetHumanName(lParam));
+ else if (db_get_b(NULL, KSMODULENAME, SETTING_LOGINERR, LOGINERR_NOTHING) == LOGINERR_SETDELAY)
+ mir_snwprintf(text, TranslateT("%s login error (next retry (%d) in %d s)"), GetHumanName(lParam), retryCount + 1, db_get_dw(NULL, KSMODULENAME, SETTING_LOGINERR_DELAY, DEFAULT_MAXDELAY));
+ else
+ return -1;
+ break;
+
+ case KS_CONN_STATE_LOST: // lParam = 1 proto, or NULL
+ if (!db_get_b(NULL, KSMODULENAME, SETTING_PUCONNLOST, TRUE))
+ return -1;
+
+ if (lParam) { // Указатель на имя модуля.
+ hIcon = Skin_LoadProtoIcon((char*)lParam, SKINICON_STATUS_OFFLINE);
+ mir_snwprintf(text, TranslateT("%s status error (next retry (%d) in %d s)"), GetHumanName(lParam), retryCount + 1, currentDelay / 1000);
+ }
+ else mir_snwprintf(text, TranslateT("Status error (next retry (%d) in %d s)"), retryCount + 1, currentDelay / 1000);
+ break;
+
+ case KS_CONN_STATE_RETRY: // lParam = PROTOCOLSETTINGEX**
+ if (!db_get_b(NULL, KSMODULENAME, SETTING_PUCONNRETRY, TRUE))
+ return -1;
+ if (lParam) {
+ PROTOCOLSETTINGEX **ps = (PROTOCOLSETTINGEX **)lParam;
+ wchar_t protoInfoLine[512], protoInfo[MAX_SECONDLINE];
+ memset(protoInfoLine, '\0', sizeof(protoInfoLine));
+ memset(protoInfo, '\0', sizeof(protoInfo));
+ mir_wstrcpy(protoInfo, L"\r\n");
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ if (mir_wstrlen(ps[i]->tszAccName) > 0 && mir_strlen(ps[i]->szName) > 0) {
+ if (db_get_b(NULL, KSMODULENAME, SETTING_PUSHOWEXTRA, TRUE)) {
+ mir_snwprintf(protoInfoLine, TranslateT("%s\t(will be set to %s)\r\n"), ps[i]->tszAccName, pcli->pfnGetStatusModeDescription(ps[i]->status, 0));
+ mir_wstrncat(protoInfo, protoInfoLine, _countof(protoInfo) - mir_wstrlen(protoInfo) - 1);
+ }
+ }
+ }
+ hIcon = Skin_LoadProtoIcon(ps[0]->szName, SKINICON_STATUS_OFFLINE);
+
+ rtrimw(protoInfo);
+ if (retryCount == (maxRetries - 1))
+ mir_snwprintf(text, TranslateT("Resetting status... (last try (%d))%s"), retryCount + 1, protoInfo);
+ else
+ mir_snwprintf(text, TranslateT("Resetting status... (next retry (%d) in %d s)%s"), retryCount + 2, currentDelay / 1000, protoInfo);
+ }
+ break;
+
+ case KS_CONN_STATE_RETRYNOCONN: // lParam = NULL
+ if (!db_get_b(NULL, KSMODULENAME, SETTING_PUOTHER, TRUE))
+ return -1;
+
+ if (retryCount == maxRetries - 1)
+ mir_snwprintf(text, TranslateT("No internet connection seems available... (last try (%d))"), retryCount + 1);
+ else
+ mir_snwprintf(text, TranslateT("No internet connection seems available... (next retry (%d) in %d s)"), retryCount + 2, currentDelay / 1000);
+ break;
+
+ case KS_CONN_STATE_STOPPEDCHECKING: // lParam == BOOL succes
+ if (!db_get_b(NULL, KSMODULENAME, SETTING_PURESULT, TRUE))
+ return -1;
+
+ if (lParam) {
+ hIcon = Skin_LoadIcon(SKINICON_STATUS_ONLINE);
+ mir_snwprintf(text, TranslateT("Status was set ok"));
+ }
+ else mir_snwprintf(text, TranslateT("Giving up"));
+ break;
+ }
+ if (hIcon == NULL)
+ hIcon = Skin_LoadIcon(SKINICON_STATUS_OFFLINE);
+
+ log_info(L"KeepStatus: %s", text);
+ return ShowPopup(text, hIcon);
+}
+
+static INT_PTR ShowPopup(wchar_t *msg, HICON hIcon)
+{
+ POPUPDATAT ppd = { 0 };
+ ppd.lchIcon = hIcon;
+ wcsncpy(ppd.lptzContactName, TranslateT("Keep status"), MAX_CONTACTNAME);
+ wcsncpy(ppd.lptzText, msg, MAX_SECONDLINE);
+ if (db_get_b(NULL, KSMODULENAME, SETTING_POPUP_USEWINCOLORS, 0)) {
+ ppd.colorBack = GetSysColor(COLOR_BTNFACE);
+ ppd.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ else if (!db_get_b(NULL, KSMODULENAME, SETTING_POPUP_USEDEFCOLORS, 0)) {
+ ppd.colorBack = db_get_dw(NULL, KSMODULENAME, SETTING_POPUP_BACKCOLOR, 0xAAAAAA);
+ ppd.colorText = db_get_dw(NULL, KSMODULENAME, SETTING_POPUP_TEXTCOLOR, 0x0000CC);
+ }
+ ppd.PluginWindowProc = KSPopupDlgProc;
+
+ switch (db_get_b(NULL, KSMODULENAME, SETTING_POPUP_DELAYTYPE, POPUP_DELAYFROMPU)) {
+ case POPUP_DELAYCUSTOM:
+ ppd.iSeconds = (int)db_get_dw(NULL, KSMODULENAME, SETTING_POPUP_TIMEOUT, 0);
+ if (ppd.iSeconds == 0)
+ ppd.iSeconds = currentDelay / 1000 - 1;
+ break;
+
+ case POPUP_DELAYPERMANENT:
+ ppd.iSeconds = -1;
+ break;
+
+ case POPUP_DELAYFROMPU:
+ default:
+ ppd.iSeconds = 0;
+ break;
+ }
+ return PUAddPopupT(&ppd);
+}
+
+LRESULT CALLBACK KSPopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
+{
+ switch (message) {
+ case WM_CONTEXTMENU: // right
+ case WM_COMMAND: // left
+ switch (db_get_b(NULL, KSMODULENAME,
+ (message == WM_COMMAND) ? SETTING_POPUP_LEFTCLICK : SETTING_POPUP_RIGHTCLICK,
+ POPUP_ACT_CLOSEPOPUP)) {
+ case POPUP_ACT_CANCEL:
+ // cancel timer
+ StopChecking();
+ PUDeletePopup(hWnd);
+ break;
+
+ case POPUP_ACT_CLOSEPOPUP:
+ // close the popup
+ PUDeletePopup(hWnd);
+ break;
+ }
+ break;
+ }
+
+ return DefWindowProc(hWnd, message, wParam, lParam);
+}
+
+// =============== services ===================
+INT_PTR StopReconnectingService(WPARAM, LPARAM)
+{
+ int ret = StartTimer(IDT_CHECKCONN | IDT_AFTERCHECK, -1, FALSE);
+ StopChecking();
+ return ret;
+}
+
+INT_PTR EnableProtocolService(WPARAM wParam, LPARAM lParam)
+{
+ char *szProto = (char *)lParam;
+ if (szProto == NULL)
+ return -1;
+
+ char dbSetting[128];
+ mir_snprintf(dbSetting, "%s_enabled", szProto);
+ if (!db_get_b(NULL, KSMODULENAME, dbSetting, 1)) // 'hard' disabled
+ return -1;
+
+ int ret = -2;
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ TConnectionSettings& cs = connectionSettings[i];
+ if (!mir_strcmp(szProto, cs.szName)) {
+ if (wParam) {
+ if (GetStatus(cs) == ID_STATUS_DISABLED)
+ AssignStatus(&cs, CallProtoService(cs.szName, PS_GETSTATUS, 0, 0), 0, NULL);
+ }
+ else AssignStatus(&cs, ID_STATUS_DISABLED, 0, NULL);
+
+ ret = 0;
+ break;
+ }
+ }
+ return ret;
+}
+
+INT_PTR IsProtocolEnabledService(WPARAM, LPARAM lParam)
+{
+ char *szProto = (char *)lParam;
+
+ char dbSetting[128];
+ mir_snprintf(dbSetting, "%s_enabled", szProto);
+ if (!db_get_b(NULL, KSMODULENAME, dbSetting, 1))
+ return FALSE;
+
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ TConnectionSettings& cs = connectionSettings[i];
+ if (!mir_strcmp(szProto, cs.szName))
+ return GetStatus(cs) != ID_STATUS_DISABLED;
+ }
+
+ return FALSE;
+}
+
+INT_PTR AnnounceStatusChangeService(WPARAM, LPARAM lParam)
+{
+ PROTOCOLSETTINGEX *newSituation = (PROTOCOLSETTINGEX *)lParam;
+ log_infoA("Another plugin announced a status change to %d for %s", newSituation->status, newSituation->szName == NULL ? "all" : newSituation->szName);
+
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ TConnectionSettings& cs = connectionSettings[i];
+ if (!mir_strcmp(cs.szName, newSituation->szName))
+ AssignStatus(&cs, newSituation->status, newSituation->lastStatus, newSituation->szMsg);
+ }
+
+ return 0;
+}
+
+// =============== window for suspend ===============
+
+static DWORD CALLBACK MessageWndProc(HWND, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static PROTOCOLSETTINGEX** ps = NULL;
+
+ switch (msg) {
+ case WM_POWERBROADCAST:
+ switch (wParam) {
+ case PBT_APMSUSPEND:
+ log_infoA("KeepStatus: suspend state detected: %08X %08X", wParam, lParam);
+ if (ps == NULL) {
+ ps = GetCurrentProtoSettingsCopy();
+ for (int i = 0; i < connectionSettings.getCount(); i++)
+ EnableProtocolService(0, (LPARAM)ps[i]->szName);
+
+ // set proto's offline, the clist will not try to reconnect in that case
+ CallService(MS_CLIST_SETSTATUSMODE, (WPARAM)ID_STATUS_OFFLINE, 0);
+ }
+ break;
+
+ //case PBT_APMRESUMEAUTOMATIC: ?
+ case PBT_APMRESUMESUSPEND:
+ case PBT_APMRESUMECRITICAL:
+ log_infoA("KeepStatus: resume from suspend state");
+ if (ps != NULL) {
+ for (int i = 0; i < connectionSettings.getCount(); i++)
+ AssignStatus(&connectionSettings[i], ps[i]->status, ps[i]->lastStatus, ps[i]->szMsg);
+ FreeProtoSettings(ps);
+ ps = NULL;
+ }
+ StartTimer(IDT_PROCESSACK, 0, FALSE);
+ break;
+ }
+ break;
+
+ case WM_DESTROY:
+ if (ps != NULL) {
+ FreeProtoSettings(ps);
+ ps = NULL;
+ }
+ break;
+ }
+
+ return TRUE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Account control event
+
+int OnKSAccChanged(WPARAM wParam, LPARAM lParam)
+{
+ PROTOACCOUNT *pa = (PROTOACCOUNT*)lParam;
+ switch (wParam) {
+ case PRAC_ADDED:
+ connectionSettings.insert(new TConnectionSettings(pa));
+ break;
+
+ case PRAC_REMOVED:
+ for (int i = 0; i < connectionSettings.getCount(); i++) {
+ if (!mir_strcmp(connectionSettings[i].szName, pa->szModuleName)) {
+ connectionSettings.remove(i);
+ break;
+ }
+ }
+ break;
+ }
+ return 0;
+}
+
+// =============== init stuff =================
+
+static int onShutdown(WPARAM, LPARAM)
+{
+ UnhookEvent(hStatusChangeHook);
+ UnhookEvent(hProtoAckHook);
+ UnhookEvent(hCSStatusChangeHook);
+ UnhookEvent(hCSStatusChangeExHook);
+
+ StopTimer(IDT_CHECKCONN | IDT_PROCESSACK | IDT_AFTERCHECK | IDT_CHECKCONTIN);
+ if (IsWindow(hMessageWindow))
+ DestroyWindow(hMessageWindow);
+
+ connectionSettings.destroy();
+
+ return 0;
+}
+
+int KSModuleLoaded(WPARAM, LPARAM)
+{
+ protoList = (OBJLIST<PROTOCOLSETTINGEX>*)&connectionSettings;
+
+ hMessageWindow = NULL;
+ KSLoadOptions();
+
+ HookEvent(ME_OPT_INITIALISE, KeepStatusOptionsInit);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, onShutdown);
+ HookEvent(ME_PROTO_ACCLISTCHANGED, OnKSAccChanged);
+ return 0;
+}
+
+void KeepStatusLoad()
+{
+ hKSModuleLoadedHook = HookEvent(ME_SYSTEM_MODULESLOADED, KSModuleLoaded);
+
+ CreateHookableEvent(ME_KS_CONNECTIONEVENT);
+
+ hStopRecon = CreateServiceFunction(MS_KS_STOPRECONNECTING, StopReconnectingService);
+ hEnableProto = CreateServiceFunction(MS_KS_ENABLEPROTOCOL, EnableProtocolService);
+ hIsProtoEnabled = CreateServiceFunction(MS_KS_ISPROTOCOLENABLED, IsProtocolEnabledService);
+ hAnnounceStat = CreateServiceFunction(MS_KS_ANNOUNCESTATUSCHANGE, AnnounceStatusChangeService);
+
+ DuplicateHandle(GetCurrentProcess(), GetCurrentThread(), GetCurrentProcess(), &hMainThread, THREAD_SET_CONTEXT, FALSE, 0);
+ mainThreadId = GetCurrentThreadId();
+}
+
+void KeepStatusUnload()
+{
+ if (hMainThread)
+ CloseHandle(hMainThread);
+
+ DestroyServiceFunction(hStopRecon);
+ DestroyServiceFunction(hEnableProto);
+ DestroyServiceFunction(hIsProtoEnabled);
+ DestroyServiceFunction(hAnnounceStat);
+
+ if (hMainThread)
+ CloseHandle(hMainThread);
+
+ DestroyHookableEvent(hConnectionEvent);
+
+ UnhookEvent(hKSModuleLoadedHook);
+}
diff --git a/plugins/StatusManager/src/KeepStatus/keepstatus.h b/plugins/StatusManager/src/KeepStatus/keepstatus.h
new file mode 100644
index 0000000000..18e13f242c
--- /dev/null
+++ b/plugins/StatusManager/src/KeepStatus/keepstatus.h
@@ -0,0 +1,124 @@
+/*
+ KeepStatus 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
+ */
+
+#ifndef __KEEPSTATUS_HEADER
+#define __KEEPSTATUS_HEADER
+
+
+#define KSMODULENAME "KeepStatus"
+#define SETTING_CHECKCONNECTION "CheckConnection"
+#define SETTING_MAXRETRIES "MaxRetries"
+#define SETTING_INCREASEEXPONENTIAL "IncreaseExponential"
+#define SETTING_INITDELAY "InitDelay"
+#define SETTING_MAXDELAY "MaxDelay"
+#define SETTING_SHOWCONNECTIONPOPUPS "ShowConnectionPopups"
+#define SETTING_CHKINET "CheckInet"
+#define SETTING_CNCOTHERLOC "CancelIfOtherLocation"
+#define SETTING_LOGINERR "OnLoginErr"
+#define SETTING_LOGINERR_DELAY "OnLoginErrDelay"
+#define SETTING_CONTCHECK "ContinueslyCheck"
+#define SETTING_BYPING "ByPingingHost"
+#define SETTING_PINGHOST "HostToPing"
+#define SETTING_CHECKAPMRESUME "CheckAPMResume"
+#define SETTING_FIRSTOFFLINE "FirstOffline"
+#define SETTING_NOLOCKED "NoLocked"
+#define SETTING_MAXCONNECTINGTIME "MaxConnectingTime"
+#define SETTING_PINGCOUNT "PingCount"
+#define DEFAULT_PINGCOUNT 1
+#define SETTING_CNTDELAY "CntDelay"
+#define STATUSCHANGEDELAY 500 // ms
+#define DEFAULT_MAXRETRIES 0
+#define DEFAULT_INITDELAY 10 // s
+#define DEFAULT_MAXDELAY 900 // s
+#define AFTERCHECK_DELAY 10000 //ms (divided by 2)
+#define CHECKCONTIN_DELAY 10 // s
+#define SETTING_POPUP_DELAYTYPE "PopupDelayType"
+#define SETTING_POPUP_USEWINCOLORS "PopupUseWinColors"
+#define SETTING_POPUP_USEDEFCOLORS "PopupUseDefColors"
+#define SETTING_POPUP_BACKCOLOR "PopupBackColor"
+#define SETTING_POPUP_TEXTCOLOR "PopupTextColor"
+#define SETTING_POPUP_TIMEOUT "PopupTimeout"
+#define SETTING_POPUP_LEFTCLICK "PopupLeftClickAction"
+#define SETTING_POPUP_RIGHTCLICK "PopupRightClickAction"
+#define SETTING_PUOTHER "PopupShowOther"
+#define SETTING_PUCONNLOST "PopupShowConnLost"
+#define SETTING_PUCONNRETRY "PopupShowConnRetry"
+#define SETTING_PURESULT "PopupShowResult"
+#define SETTING_PUSHOWEXTRA "PopupShowExtra"
+#define POPUP_ACT_NOTHING 0
+#define POPUP_ACT_CANCEL 1
+#define POPUP_ACT_CLOSEPOPUP 2
+#define POPUP_DELAYFROMPU 0
+#define POPUP_DELAYCUSTOM 1
+#define POPUP_DELAYPERMANENT 2
+#define LOGINERR_NOTHING 0
+#define LOGINERR_CANCEL 1
+#define LOGINERR_SETDELAY 2
+
+#define IDT_PROCESSACK 0x01
+#define IDT_CHECKCONN 0x02
+#define IDT_AFTERCHECK 0x04
+#define IDT_CHECKCONTIN 0x08
+#define IDT_CHECKCONNECTING 0x10
+
+#define KS_ISENABLED WM_APP + 10
+#define KS_ENABLEITEMS WM_APP + 11
+
+// action
+#define SETTING_ENABLECHECKING "EnableChecking"
+// trigger
+#define TRIGGERNAME "KeepStatus: Connection state change"
+#define TRIGGER_CONNLOST 0x01
+#define TRIGGER_LOGINERROR 0x02
+#define TRIGGER_OTHERLOC 0x04
+#define TRIGGER_CONNRETRY 0x08
+#define TRIGGER_CONNSUCCESS 0x10
+#define TRIGGER_CONNGIVEUP 0x20
+#define SETTING_TRIGGERON "TriggerOn"
+
+struct TConnectionSettings : public PROTOCOLSETTINGEX
+{
+ TConnectionSettings(PROTOACCOUNT *pa);
+ ~TConnectionSettings();
+
+ int lastStatusAckTime; // the time the last status ack was received
+};
+
+/* old; replaced by PROTOCOLSETTINGEX see m_statusplugins.h */
+typedef struct {
+ char *szName; // pointer to protocol modulename
+ WORD status; // the status
+ WORD lastStatus;// last status
+} PROTOCOLSETTING;
+
+/* old; replaced by ME_CS_STATUSCHANGE see m_statusplugins.h */
+// wParam = PROTOCOLSETTING**
+// lParam = 0
+#define ME_CS_STATUSCHANGE "CommonStatus/StatusChange"
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// keepstatus.cpp
+
+void KeepStatusLoad();
+void KeepStatusUnload();
+int KSLoadOptions();
+
+LRESULT CALLBACK KSPopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
+
+#endif //__KEEPSTATUS_HEADER
diff --git a/plugins/StatusManager/src/KeepStatus/ks_options.cpp b/plugins/StatusManager/src/KeepStatus/ks_options.cpp
new file mode 100644
index 0000000000..0f321dfd14
--- /dev/null
+++ b/plugins/StatusManager/src/KeepStatus/ks_options.cpp
@@ -0,0 +1,589 @@
+/*
+ KeepStatus 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
+ */
+
+#include "..\stdafx.h"
+
+// prototypes
+INT_PTR CALLBACK OptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+INT_PTR CALLBACK PopupOptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+static INT_PTR CALLBACK DlgProcKSBasicOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+ {
+ LVCOLUMN lvCol;
+ LVITEM lvItem;
+ DBVARIANT dbv;
+
+ SetDlgItemInt(hwndDlg, IDC_MAXRETRIES, db_get_b(NULL, KSMODULENAME, SETTING_MAXRETRIES, DEFAULT_MAXRETRIES), FALSE);
+ SetDlgItemInt(hwndDlg, IDC_INITDELAY, db_get_dw(NULL, KSMODULENAME, SETTING_INITDELAY, DEFAULT_INITDELAY), FALSE);
+ CheckDlgButton(hwndDlg, IDC_CHECKCONNECTION, db_get_b(NULL, KSMODULENAME, SETTING_CHECKCONNECTION, FALSE) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_SHOWCONNECTIONPOPUPS, (db_get_b(NULL, KSMODULENAME, SETTING_SHOWCONNECTIONPOPUPS, FALSE) && ServiceExists(MS_POPUP_SHOWMESSAGE)) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_CHKINET, db_get_b(NULL, KSMODULENAME, SETTING_CHKINET, FALSE) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_CONTCHECK, db_get_b(NULL, KSMODULENAME, SETTING_CONTCHECK, FALSE) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_BYPING, db_get_b(NULL, KSMODULENAME, SETTING_BYPING, FALSE) ? BST_CHECKED : BST_UNCHECKED);
+ if (!db_get_s(NULL, KSMODULENAME, SETTING_PINGHOST, &dbv)) {
+ SetDlgItemTextA(hwndDlg, IDC_PINGHOST, dbv.pszVal);
+ db_free(&dbv);
+ }
+ // proto list
+ HWND hList = GetDlgItem(hwndDlg, IDC_PROTOCOLLIST);
+ ListView_SetExtendedListViewStyleEx(hList, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES, LVS_EX_FULLROWSELECT | LVS_EX_CHECKBOXES);
+ memset(&lvCol, 0, sizeof(lvCol));
+ lvCol.mask = LVCF_WIDTH | LVCF_TEXT;
+ lvCol.pszText = TranslateT("Protocol");
+ lvCol.cx = 118;
+ ListView_InsertColumn(hList, 0, &lvCol);
+ // fill the list
+ memset(&lvItem, 0, sizeof(lvItem));
+ lvItem.mask = LVIF_TEXT | LVIF_PARAM;
+ lvItem.iItem = 0;
+ lvItem.iSubItem = 0;
+
+ int count;
+ PROTOACCOUNT** protos;
+ Proto_EnumAccounts(&count, &protos);
+
+ for (int i = 0; i < count; i++) {
+ if (!IsSuitableProto(protos[i]))
+ continue;
+
+ lvItem.pszText = protos[i]->tszAccountName;
+ lvItem.lParam = (LPARAM)protos[i]->szModuleName;
+ ListView_InsertItem(hList, &lvItem);
+
+ char dbSetting[128];
+ mir_snprintf(dbSetting, "%s_enabled", protos[i]->szModuleName);
+ ListView_SetCheckState(hList, lvItem.iItem, db_get_b(NULL, KSMODULENAME, dbSetting, TRUE));
+ lvItem.iItem++;
+ }
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MAXRETRIES), IsDlgButtonChecked(hwndDlg, IDC_CHECKCONNECTION));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWCONNECTIONPOPUPS), ServiceExists(MS_POPUP_SHOWMESSAGE) && IsDlgButtonChecked(hwndDlg, IDC_CHECKCONNECTION));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_INITDELAY), IsDlgButtonChecked(hwndDlg, IDC_CHECKCONNECTION));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PROTOCOLLIST), IsDlgButtonChecked(hwndDlg, IDC_CHECKCONNECTION));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHKINET), IsDlgButtonChecked(hwndDlg, IDC_CHECKCONNECTION));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CONTCHECK), IsDlgButtonChecked(hwndDlg, IDC_CHECKCONNECTION));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BYPING), (IsDlgButtonChecked(hwndDlg, IDC_CONTCHECK) && IsDlgButtonChecked(hwndDlg, IDC_CHECKCONNECTION)) ? TRUE : FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PINGHOST), (IsDlgButtonChecked(hwndDlg, IDC_CONTCHECK)) && (IsDlgButtonChecked(hwndDlg, IDC_BYPING) && IsDlgButtonChecked(hwndDlg, IDC_CHECKCONNECTION)) ? TRUE : FALSE);
+ }
+ break;
+
+ case WM_COMMAND:
+ if (((HIWORD(wParam) == EN_CHANGE) || (HIWORD(wParam) == BN_CLICKED)) && ((HWND)lParam == GetFocus()))
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ // something changed
+ switch (LOWORD(wParam)) {
+ case IDC_CHECKCONNECTION:
+ case IDC_CONTCHECK:
+ case IDC_BYPING:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MAXRETRIES), SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_SHOWCONNECTIONPOPUPS), ServiceExists(MS_POPUP_SHOWMESSAGE) && SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_INITDELAY), SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PROTOCOLLIST), SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHKINET), SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CONTCHECK), SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BYPING), (IsDlgButtonChecked(hwndDlg, IDC_CONTCHECK) && SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0)) ? TRUE : FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PINGHOST), (IsDlgButtonChecked(hwndDlg, IDC_CONTCHECK)) && (IsDlgButtonChecked(hwndDlg, IDC_BYPING) && SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0)) ? TRUE : FALSE);
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ if (((NMHDR*)lParam)->idFrom == IDC_PROTOCOLLIST) {
+ switch (((NMHDR*)lParam)->code) {
+ case LVN_ITEMCHANGED:
+ {
+ NMLISTVIEW *nmlv = (NMLISTVIEW *)lParam;
+ if (IsWindowVisible(GetDlgItem(hwndDlg, IDC_PROTOCOLLIST)) && ((nmlv->uNewState^nmlv->uOldState)&LVIS_STATEIMAGEMASK))
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ }
+ break;
+ }
+ }
+
+ if (((LPNMHDR)lParam)->code == PSN_APPLY) {
+ int i;
+ LVITEM lvItem;
+
+ db_set_b(NULL, KSMODULENAME, SETTING_MAXRETRIES, (BYTE)GetDlgItemInt(hwndDlg, IDC_MAXRETRIES, NULL, FALSE));
+ db_set_b(NULL, KSMODULENAME, SETTING_CHECKCONNECTION, (BYTE)SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ db_set_b(NULL, KSMODULENAME, SETTING_SHOWCONNECTIONPOPUPS, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_SHOWCONNECTIONPOPUPS));
+ db_set_dw(NULL, KSMODULENAME, SETTING_INITDELAY, (DWORD)GetDlgItemInt(hwndDlg, IDC_INITDELAY, NULL, FALSE));
+ db_set_b(NULL, KSMODULENAME, SETTING_CHKINET, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_CHKINET));
+ db_set_b(NULL, KSMODULENAME, SETTING_CONTCHECK, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_CONTCHECK));
+ db_set_b(NULL, KSMODULENAME, SETTING_BYPING, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_BYPING));
+ if (IsDlgButtonChecked(hwndDlg, IDC_BYPING)) {
+ char *host;
+
+ int len = SendDlgItemMessage(hwndDlg, IDC_PINGHOST, WM_GETTEXTLENGTH, 0, 0);
+ if (len > 0) {
+ host = (char*)malloc(len + 1);
+ if (host != NULL) {
+ memset(host, '\0', len + 1);
+ GetDlgItemTextA(hwndDlg, IDC_PINGHOST, host, len + 1);
+ db_set_s(NULL, KSMODULENAME, SETTING_PINGHOST, host);
+ }
+ }
+ }
+ HWND hList = GetDlgItem(hwndDlg, IDC_PROTOCOLLIST);
+ memset(&lvItem, 0, sizeof(lvItem));
+ lvItem.mask = LVIF_PARAM;
+ for (i = 0; i < ListView_GetItemCount(hList); i++) {
+ lvItem.iItem = i;
+ lvItem.iSubItem = 0;
+ ListView_GetItem(hList, &lvItem);
+
+ char dbSetting[128];
+ mir_snprintf(dbSetting, "%s_enabled", (char *)lvItem.lParam);
+ db_set_b(NULL, KSMODULENAME, dbSetting, (BYTE)ListView_GetCheckState(hList, lvItem.iItem));
+ }
+ }
+ break;
+ }
+
+ return 0;
+}
+
+static INT_PTR CALLBACK DlgProcKSAdvOpts(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG: {
+ TranslateDialogDefault(hwndDlg);
+ SetDlgItemInt(hwndDlg, IDC_MAXDELAY, db_get_dw(NULL, KSMODULENAME, SETTING_MAXDELAY, DEFAULT_MAXDELAY), FALSE);
+ SetDlgItemInt(hwndDlg, IDC_MAXCONNECTINGTIME, db_get_dw(NULL, KSMODULENAME, SETTING_MAXCONNECTINGTIME, 0), FALSE);
+ CheckDlgButton(hwndDlg, IDC_INCREASEEXPONENTIAL, db_get_b(NULL, KSMODULENAME, SETTING_INCREASEEXPONENTIAL, FALSE) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_CNCOTHERLOC, (db_get_b(NULL, KSMODULENAME, SETTING_CNCOTHERLOC, FALSE)) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_LOGINERR, db_get_b(NULL, KSMODULENAME, SETTING_LOGINERR, LOGINERR_NOTHING) == LOGINERR_NOTHING ? BST_UNCHECKED : BST_CHECKED);
+ CheckDlgButton(hwndDlg, IDC_CHECKAPMRESUME, (db_get_b(NULL, KSMODULENAME, SETTING_CHECKAPMRESUME, FALSE)) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_FIRSTOFFLINE, (db_get_b(NULL, KSMODULENAME, SETTING_FIRSTOFFLINE, FALSE)) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_NOLOCKED, (db_get_b(NULL, KSMODULENAME, SETTING_NOLOCKED, FALSE)) ? BST_CHECKED : BST_UNCHECKED);
+ SetDlgItemInt(hwndDlg, IDC_LOGINERR_DELAY, db_get_dw(NULL, KSMODULENAME, SETTING_LOGINERR_DELAY, DEFAULT_MAXDELAY), FALSE);
+ SetDlgItemInt(hwndDlg, IDC_PINGCOUNT, db_get_w(NULL, KSMODULENAME, SETTING_PINGCOUNT, DEFAULT_PINGCOUNT), FALSE);
+ SetDlgItemInt(hwndDlg, IDC_CNTDELAY, db_get_dw(NULL, KSMODULENAME, SETTING_CNTDELAY, CHECKCONTIN_DELAY), FALSE);
+ switch (db_get_b(NULL, KSMODULENAME, SETTING_LOGINERR, LOGINERR_CANCEL)) {
+ case LOGINERR_SETDELAY:
+ CheckRadioButton(hwndDlg, IDC_LOGINERR_CANCEL, IDC_LOGINERR_SETDELAY, IDC_LOGINERR_SETDELAY);
+ break;
+ default:
+ case LOGINERR_CANCEL:
+ CheckRadioButton(hwndDlg, IDC_LOGINERR_CANCEL, IDC_LOGINERR_SETDELAY, IDC_LOGINERR_CANCEL);
+ break;
+ }
+ SendMessage(hwndDlg, KS_ENABLEITEMS, 0, 0);
+ break;
+ }
+ case WM_COMMAND:
+ if (((HIWORD(wParam) == EN_CHANGE) || (HIWORD(wParam) == BN_CLICKED)) && ((HWND)lParam == GetFocus()))
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ // something changed
+ switch (LOWORD(wParam)) {
+ case IDC_INCREASEEXPONENTIAL:
+ case IDC_LOGINERR:
+ SendMessage(hwndDlg, KS_ENABLEITEMS, 0, 0);
+ break;
+
+ case IDC_LOGINERR_CANCEL:
+ case IDC_LOGINERR_SETDELAY:
+ CheckRadioButton(hwndDlg, IDC_LOGINERR_CANCEL, IDC_LOGINERR_SETDELAY, LOWORD(wParam));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LOGINERR_DELAY), IsDlgButtonChecked(hwndDlg, IDC_LOGINERR_SETDELAY) && IsDlgButtonChecked(hwndDlg, IDC_LOGINERR) && SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY) {
+ db_set_b(NULL, KSMODULENAME, SETTING_INCREASEEXPONENTIAL, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_INCREASEEXPONENTIAL));
+ db_set_dw(NULL, KSMODULENAME, SETTING_MAXDELAY, (DWORD)GetDlgItemInt(hwndDlg, IDC_MAXDELAY, NULL, FALSE));
+ db_set_dw(NULL, KSMODULENAME, SETTING_MAXCONNECTINGTIME, (DWORD)GetDlgItemInt(hwndDlg, IDC_MAXCONNECTINGTIME, NULL, FALSE));
+ db_set_b(NULL, KSMODULENAME, SETTING_FIRSTOFFLINE, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_FIRSTOFFLINE));
+ db_set_b(NULL, KSMODULENAME, SETTING_NOLOCKED, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_NOLOCKED));
+ db_set_b(NULL, KSMODULENAME, SETTING_CNCOTHERLOC, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_CNCOTHERLOC));
+ db_set_b(NULL, KSMODULENAME, SETTING_LOGINERR, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_LOGINERR));
+ if (IsDlgButtonChecked(hwndDlg, IDC_LOGINERR)) {
+ if (IsDlgButtonChecked(hwndDlg, IDC_LOGINERR_SETDELAY)) {
+ db_set_b(NULL, KSMODULENAME, SETTING_LOGINERR, LOGINERR_SETDELAY);
+ db_set_dw(NULL, KSMODULENAME, SETTING_LOGINERR_DELAY, GetDlgItemInt(hwndDlg, IDC_LOGINERR_DELAY, NULL, FALSE));
+ }
+ else db_set_b(NULL, KSMODULENAME, SETTING_LOGINERR, LOGINERR_CANCEL);
+ }
+ else db_set_b(NULL, KSMODULENAME, SETTING_LOGINERR, LOGINERR_NOTHING);
+
+ db_set_b(NULL, KSMODULENAME, SETTING_CHECKAPMRESUME, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_CHECKAPMRESUME));
+ db_set_w(NULL, KSMODULENAME, SETTING_PINGCOUNT, (WORD)GetDlgItemInt(hwndDlg, IDC_PINGCOUNT, NULL, FALSE));
+ db_set_dw(NULL, KSMODULENAME, SETTING_CNTDELAY, (DWORD)GetDlgItemInt(hwndDlg, IDC_CNTDELAY, NULL, FALSE) == 0 ? CHECKCONTIN_DELAY : GetDlgItemInt(hwndDlg, IDC_CNTDELAY, NULL, FALSE));
+ }
+ break;
+
+ case KS_ENABLEITEMS:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_INCREASEEXPONENTIAL), SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MAXCONNECTINGTIME), SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CNCOTHERLOC), SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LOGINERR), SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LOGINERR_SETDELAY), IsDlgButtonChecked(hwndDlg, IDC_LOGINERR) && SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LOGINERR_DELAY), IsDlgButtonChecked(hwndDlg, IDC_LOGINERR_SETDELAY) && IsDlgButtonChecked(hwndDlg, IDC_LOGINERR) && SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_LOGINERR_CANCEL), IsDlgButtonChecked(hwndDlg, IDC_LOGINERR) && SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_MAXDELAY), (IsDlgButtonChecked(hwndDlg, IDC_INCREASEEXPONENTIAL) && SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0)) ? TRUE : FALSE);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CHECKAPMRESUME), SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_FIRSTOFFLINE), SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_NOLOCKED), SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CHECKCONNECTION, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_PINGCOUNT), SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_BYPING, 0));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_CNTDELAY), SendMessage(GetParent(hwndDlg), KS_ISENABLED, (WPARAM)IDC_CONTCHECK, 0));
+ break;
+
+ case WM_SHOWWINDOW:
+ if (wParam)
+ SendMessage(hwndDlg, KS_ENABLEITEMS, 0, 0);
+
+ break;
+ }
+
+ return 0;
+}
+
+static INT_PTR CALLBACK DlgProcKsTabs(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static HWND hBasicTab;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ HWND hShow, hPage;
+ RECT rcTabs, rcOptions, rcPage;
+
+ TranslateDialogDefault(hwndDlg);
+
+ // set tabs
+ int tabCount = 0;
+ HWND hTab = GetDlgItem(hwndDlg, IDC_TABS);
+ GetWindowRect(hTab, &rcTabs);
+ GetWindowRect(hwndDlg, &rcOptions);
+
+ // basic tab
+ TCITEM tci;
+ memset(&tci, 0, sizeof(TCITEM));
+ tci.mask = TCIF_TEXT | TCIF_PARAM;
+ tci.pszText = TranslateT("Basic");
+ hShow = hBasicTab = hPage = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_OPT_KS_BASIC), hwndDlg, DlgProcKSBasicOpts, (LPARAM)GetParent(hwndDlg));
+ EnableThemeDialogTexture(hPage, ETDT_ENABLETAB);
+
+ tci.lParam = (LPARAM)hPage;
+ GetClientRect(hPage, &rcPage);
+ MoveWindow(hPage, (rcTabs.left - rcOptions.left) + ((rcTabs.right - rcTabs.left) - (rcPage.right - rcPage.left)) / 2, 10 + (rcTabs.top - rcOptions.top) + ((rcTabs.bottom - rcTabs.top) - (rcPage.bottom - rcPage.top)) / 2, rcPage.right - rcPage.left, rcPage.bottom - rcPage.top, TRUE);
+ ShowWindow(hPage, SW_HIDE);
+ TabCtrl_InsertItem(hTab, tabCount++, &tci);
+
+ // advanced tab
+ tci.mask = TCIF_TEXT | TCIF_PARAM;
+ tci.pszText = TranslateT("Advanced");
+ hPage = CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_OPT_KS_ADV), hwndDlg, DlgProcKSAdvOpts, (LPARAM)GetParent(hwndDlg));
+ EnableThemeDialogTexture(hPage, ETDT_ENABLETAB);
+
+ tci.lParam = (LPARAM)hPage;
+ GetClientRect(hPage, &rcPage);
+ MoveWindow(hPage, (rcTabs.left - rcOptions.left) + ((rcTabs.right - rcTabs.left) - (rcPage.right - rcPage.left)) / 2, 10 + (rcTabs.top - rcOptions.top) + ((rcTabs.bottom - rcTabs.top) - (rcPage.bottom - rcPage.top)) / 2, rcPage.right - rcPage.left, rcPage.bottom - rcPage.top, TRUE);
+ ShowWindow(hPage, SW_HIDE);
+ TabCtrl_InsertItem(hTab, tabCount++, &tci);
+ ShowWindow(hShow, SW_SHOW);
+ }
+ break;
+
+ case KS_ISENABLED:
+ SetWindowLongPtr(hwndDlg, DWLP_MSGRESULT, (LONG_PTR)IsDlgButtonChecked(hBasicTab, wParam));
+ return TRUE;
+
+ case PSM_CHANGED:
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case WM_NOTIFY:
+ if ((((NMHDR*)lParam)->idFrom == IDC_TABS)) {
+ if (((NMHDR*)lParam)->code == TCN_SELCHANGING) {
+ TCITEM tci;
+
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TABS), TabCtrl_GetCurSel(GetDlgItem(hwndDlg, IDC_TABS)), &tci);
+ ShowWindow((HWND)tci.lParam, SW_HIDE);
+ }
+ else if (((NMHDR*)lParam)->code == TCN_SELCHANGE) {
+ TCITEM tci;
+
+ tci.mask = TCIF_PARAM;
+ TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TABS), TabCtrl_GetCurSel(GetDlgItem(hwndDlg, IDC_TABS)), &tci);
+ ShowWindow((HWND)tci.lParam, SW_SHOW);
+ }
+ }
+ if (((LPNMHDR)lParam)->code == PSN_APPLY) {
+ TCITEM tci;
+ int i, count;
+
+ tci.mask = TCIF_PARAM;
+ count = TabCtrl_GetItemCount(GetDlgItem(hwndDlg, IDC_TABS));
+ for (i = 0; i < count; i++) {
+ TabCtrl_GetItem(GetDlgItem(hwndDlg, IDC_TABS), i, &tci);
+ SendMessage((HWND)tci.lParam, WM_NOTIFY, 0, lParam);
+ }
+ // let main reload options
+ KSLoadOptions();
+ }
+ break;
+ }
+
+ return FALSE;
+}
+
+INT_PTR CALLBACK PopupOptDlgProc(HWND hwndDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ static bool bFreeze = false;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ TranslateDialogDefault(hwndDlg);
+
+ bFreeze = true;
+
+ // left action
+ switch (db_get_b(NULL, KSMODULENAME, SETTING_POPUP_LEFTCLICK, POPUP_ACT_CANCEL)) {
+ case POPUP_ACT_CLOSEPOPUP:
+ CheckDlgButton(hwndDlg, IDC_LCLOSE, BST_CHECKED);
+ break;
+
+ case POPUP_ACT_CANCEL:
+ CheckDlgButton(hwndDlg, IDC_LCANCEL, BST_CHECKED);
+ break;
+
+ case POPUP_ACT_NOTHING:
+ default:
+ CheckDlgButton(hwndDlg, IDC_LNOTHING, BST_CHECKED);
+ break;
+ }
+ // right action
+ switch (db_get_b(NULL, KSMODULENAME, SETTING_POPUP_RIGHTCLICK, POPUP_ACT_CANCEL)) {
+ case POPUP_ACT_CLOSEPOPUP:
+ CheckDlgButton(hwndDlg, IDC_RCLOSE, BST_CHECKED);
+ break;
+
+ case POPUP_ACT_CANCEL:
+ CheckDlgButton(hwndDlg, IDC_RCANCEL, BST_CHECKED);
+ break;
+
+ case POPUP_ACT_NOTHING:
+ default:
+ CheckDlgButton(hwndDlg, IDC_RNOTHING, BST_CHECKED);
+ break;
+ }
+ // delay
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELAYCUSTOM), ServiceExists(MS_POPUP_ADDPOPUPT));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELAYFROMPU), ServiceExists(MS_POPUP_ADDPOPUPT));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELAYPERMANENT), ServiceExists(MS_POPUP_ADDPOPUPT));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELAY), ServiceExists(MS_POPUP_ADDPOPUPT));
+ switch (db_get_b(NULL, KSMODULENAME, SETTING_POPUP_DELAYTYPE, POPUP_DELAYFROMPU)) {
+ case POPUP_DELAYCUSTOM:
+ CheckDlgButton(hwndDlg, IDC_DELAYCUSTOM, BST_CHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELAY), ServiceExists(MS_POPUP_ADDPOPUPT));
+ break;
+
+ case POPUP_DELAYPERMANENT:
+ CheckDlgButton(hwndDlg, IDC_DELAYPERMANENT, BST_CHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELAY), FALSE);
+ break;
+
+ case POPUP_DELAYFROMPU:
+ default:
+ CheckDlgButton(hwndDlg, IDC_DELAYFROMPU, BST_CHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELAY), FALSE);
+ break;
+ }
+ // delay
+ SetDlgItemInt(hwndDlg, IDC_DELAY, db_get_dw(NULL, KSMODULENAME, SETTING_POPUP_TIMEOUT, 0), FALSE);
+ // back color
+ SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_SETCOLOUR, 0, db_get_dw(NULL, KSMODULENAME, SETTING_POPUP_BACKCOLOR, 0xAAAAAA));
+ // text
+ SendDlgItemMessage(hwndDlg, IDC_TEXTCOLOR, CPM_SETCOLOUR, 0, db_get_dw(NULL, KSMODULENAME, SETTING_POPUP_TEXTCOLOR, 0x0000CC));
+ // wincolors
+ CheckDlgButton(hwndDlg, IDC_WINCOLORS, db_get_b(NULL, KSMODULENAME, SETTING_POPUP_USEWINCOLORS, 0) ? BST_CHECKED : BST_UNCHECKED);
+ // defaultcolors
+ CheckDlgButton(hwndDlg, IDC_DEFAULTCOLORS, ((db_get_b(NULL, KSMODULENAME, SETTING_POPUP_USEDEFCOLORS, 0)) && (BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_WINCOLORS))) ? BST_CHECKED : BST_UNCHECKED);
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BGCOLOR), ((BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_WINCOLORS)) && (BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_DEFAULTCOLORS))));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TEXTCOLOR), ((BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_WINCOLORS)) && (BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_DEFAULTCOLORS))));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DEFAULTCOLORS), (BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_WINCOLORS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_WINCOLORS), (BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_DEFAULTCOLORS)));
+ // popup types
+ CheckDlgButton(hwndDlg, IDC_PUCONNLOST, db_get_b(NULL, KSMODULENAME, SETTING_PUCONNLOST, TRUE) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_PUOTHER, db_get_b(NULL, KSMODULENAME, SETTING_PUOTHER, TRUE) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_PUCONNRETRY, db_get_b(NULL, KSMODULENAME, SETTING_PUCONNRETRY, TRUE) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_PURESULT, db_get_b(NULL, KSMODULENAME, SETTING_PURESULT, TRUE) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hwndDlg, IDC_PUSHOWEXTRA, db_get_b(NULL, KSMODULENAME, SETTING_PUSHOWEXTRA, TRUE) ? BST_CHECKED : BST_UNCHECKED);
+ bFreeze = false;
+ break;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_WINCOLORS:
+ case IDC_DEFAULTCOLORS:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_BGCOLOR), ((BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_WINCOLORS)) && (BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_DEFAULTCOLORS))));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_TEXTCOLOR), ((BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_WINCOLORS)) && (BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_DEFAULTCOLORS))));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DEFAULTCOLORS), (BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_WINCOLORS)));
+ EnableWindow(GetDlgItem(hwndDlg, IDC_WINCOLORS), (BST_UNCHECKED == IsDlgButtonChecked(hwndDlg, IDC_DEFAULTCOLORS)));
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_DELAYFROMPU:
+ case IDC_DELAYPERMANENT:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELAY), FALSE);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_DELAYCUSTOM:
+ EnableWindow(GetDlgItem(hwndDlg, IDC_DELAY), TRUE);
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_BGCOLOR:
+ case IDC_TEXTCOLOR:
+ case IDC_DELAY:
+ case IDC_LNOTHING:
+ case IDC_LCLOSE:
+ case IDC_LCANCEL:
+ case IDC_RNOTHING:
+ case IDC_RCLOSE:
+ case IDC_RCANCEL:
+ case IDC_PUCONNLOST:
+ case IDC_PUOTHER:
+ case IDC_PUCONNRETRY:
+ case IDC_PURESULT:
+ case IDC_PUSHOWEXTRA:
+ if (!bFreeze)
+ SendMessage(GetParent(hwndDlg), PSM_CHANGED, 0, 0);
+ break;
+
+ case IDC_PREV:
+ {
+ POPUPDATAT ppd = { NULL };
+
+ ppd.lchContact = NULL;
+ ppd.lchIcon = Skin_LoadIcon(SKINICON_STATUS_OFFLINE);
+ wcsncpy(ppd.lptzContactName, TranslateT("Keep status"), MAX_CONTACTNAME);
+ wcsncpy(ppd.lptzText, TranslateT("You broke the Internet!"), MAX_SECONDLINE);
+ if (IsDlgButtonChecked(hwndDlg, IDC_WINCOLORS))
+ {
+ ppd.colorBack = GetSysColor(COLOR_BTNFACE);
+ ppd.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ else if (IsDlgButtonChecked(hwndDlg, IDC_DEFAULTCOLORS))
+ {
+ ppd.colorBack = NULL;
+ ppd.colorText = NULL;
+ }
+ else
+ {
+ ppd.colorBack = SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_GETCOLOUR, 0, 0);
+ ppd.colorText = SendDlgItemMessage(hwndDlg, IDC_TEXTCOLOR, CPM_GETCOLOUR, 0, 0);
+ }
+ ppd.PluginWindowProc = KSPopupDlgProc;
+ ppd.PluginData = NULL;
+ if (IsDlgButtonChecked(hwndDlg, IDC_DELAYFROMPU))
+ {
+ ppd.iSeconds = 0;
+ }
+ else if (IsDlgButtonChecked(hwndDlg, IDC_DELAYCUSTOM))
+ {
+ ppd.iSeconds = GetDlgItemInt(hwndDlg, IDC_DELAY, NULL, FALSE);
+ }
+ else if (IsDlgButtonChecked(hwndDlg, IDC_DELAYPERMANENT))
+ {
+ ppd.iSeconds = -1;
+ }
+ PUAddPopupT(&ppd);
+ }
+ break;
+ }
+ break;
+
+ case WM_NOTIFY:
+ if (((LPNMHDR)lParam)->code == PSN_APPLY) {
+ // left action
+ if (IsDlgButtonChecked(hwndDlg, IDC_LNOTHING))
+ db_set_b(NULL, KSMODULENAME, SETTING_POPUP_LEFTCLICK, POPUP_ACT_NOTHING);
+ else if (IsDlgButtonChecked(hwndDlg, IDC_LCLOSE))
+ db_set_b(NULL, KSMODULENAME, SETTING_POPUP_LEFTCLICK, POPUP_ACT_CLOSEPOPUP);
+ else if (IsDlgButtonChecked(hwndDlg, IDC_LCANCEL))
+ db_set_b(NULL, KSMODULENAME, SETTING_POPUP_LEFTCLICK, POPUP_ACT_CANCEL);
+ // right action
+ if (IsDlgButtonChecked(hwndDlg, IDC_RNOTHING))
+ db_set_b(NULL, KSMODULENAME, SETTING_POPUP_RIGHTCLICK, POPUP_ACT_NOTHING);
+ else if (IsDlgButtonChecked(hwndDlg, IDC_RCLOSE))
+ db_set_b(NULL, KSMODULENAME, SETTING_POPUP_RIGHTCLICK, POPUP_ACT_CLOSEPOPUP);
+ else if (IsDlgButtonChecked(hwndDlg, IDC_RCANCEL))
+ db_set_b(NULL, KSMODULENAME, SETTING_POPUP_RIGHTCLICK, POPUP_ACT_CANCEL);
+ // delay
+ if (IsDlgButtonChecked(hwndDlg, IDC_DELAYFROMPU))
+ db_set_b(NULL, KSMODULENAME, SETTING_POPUP_DELAYTYPE, POPUP_DELAYFROMPU);
+ else if (IsDlgButtonChecked(hwndDlg, IDC_DELAYCUSTOM))
+ db_set_b(NULL, KSMODULENAME, SETTING_POPUP_DELAYTYPE, POPUP_DELAYCUSTOM);
+ else if (IsDlgButtonChecked(hwndDlg, IDC_DELAYPERMANENT))
+ db_set_b(NULL, KSMODULENAME, SETTING_POPUP_DELAYTYPE, POPUP_DELAYPERMANENT);
+ // delay
+ db_set_dw(NULL, KSMODULENAME, SETTING_POPUP_TIMEOUT, GetDlgItemInt(hwndDlg, IDC_DELAY, NULL, FALSE));
+ // back color
+ db_set_dw(NULL, KSMODULENAME, SETTING_POPUP_BACKCOLOR, SendDlgItemMessage(hwndDlg, IDC_BGCOLOR, CPM_GETCOLOUR, 0, 0));
+ // text color
+ db_set_dw(NULL, KSMODULENAME, SETTING_POPUP_TEXTCOLOR, SendDlgItemMessage(hwndDlg, IDC_TEXTCOLOR, CPM_GETCOLOUR, 0, 0));
+ // use win
+ db_set_b(NULL, KSMODULENAME, SETTING_POPUP_USEWINCOLORS, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_WINCOLORS));
+ // use def
+ db_set_b(NULL, KSMODULENAME, SETTING_POPUP_USEDEFCOLORS, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_DEFAULTCOLORS));
+ // store types
+ db_set_b(NULL, KSMODULENAME, SETTING_PUCONNLOST, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_PUCONNLOST));
+ db_set_b(NULL, KSMODULENAME, SETTING_PUOTHER, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_PUOTHER));
+ db_set_b(NULL, KSMODULENAME, SETTING_PUCONNRETRY, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_PUCONNRETRY));
+ db_set_b(NULL, KSMODULENAME, SETTING_PURESULT, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_PURESULT));
+ db_set_b(NULL, KSMODULENAME, SETTING_PUSHOWEXTRA, (BYTE)IsDlgButtonChecked(hwndDlg, IDC_PUSHOWEXTRA));
+ }
+ break;
+ }
+
+ return 0;
+}
+
+int KeepStatusOptionsInit(WPARAM wparam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = { 0 };
+ odp.hInstance = hInst;
+ odp.szGroup.w = LPGENW("Status");
+ odp.szTitle.w = LPGENW("Keep status");
+ odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_OPT_TABS);
+ odp.pfnDlgProc = DlgProcKsTabs;
+ Options_AddPage(wparam, &odp);
+
+ if (ServiceExists(MS_POPUP_ADDPOPUPT)) {
+ memset(&odp, 0, sizeof(odp));
+ odp.position = 150000000;
+ odp.szGroup.w = LPGENW("Popups");
+ odp.hInstance = hInst;
+ odp.pszTemplate = MAKEINTRESOURCEA(IDD_PUOPT_KEEPSTATUS);
+ odp.szTitle.w = LPGENW("Keep status");
+ odp.pfnDlgProc = PopupOptDlgProc;
+ odp.flags = ODPF_BOLDGROUPS | ODPF_UNICODE;
+ Options_AddPage(wparam, &odp);
+ }
+ return 0;
+}