diff options
author | aunsane <aunsane@gmail.com> | 2017-01-06 16:19:32 +0300 |
---|---|---|
committer | aunsane <aunsane@gmail.com> | 2017-01-06 20:10:47 +0300 |
commit | b7336b2fc97092442ce643532f67466868a87812 (patch) | |
tree | 718b87c37090fe8bf7ae88b9d5da9b3b957c3e3c /plugins/StatusManager/src/KeepStatus | |
parent | ac1d88965de3022be2f484c2f58185ae75b4fe00 (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.cpp | 1246 | ||||
-rw-r--r-- | plugins/StatusManager/src/KeepStatus/keepstatus.h | 124 | ||||
-rw-r--r-- | plugins/StatusManager/src/KeepStatus/ks_options.cpp | 589 |
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; +} |