From e706438ffc7299f9c5e10d9f5962e3a23d0a752a Mon Sep 17 00:00:00 2001 From: Rozhuk Ivan Date: Wed, 26 Nov 2014 17:52:37 +0000 Subject: KeepStatus code cleanup git-svn-id: http://svn.miranda-ng.org/main/trunk@11101 1316c22d-e87f-b044-9b9b-93d7a3e3ba9c --- plugins/StatusPlugins/KeepStatus/keepstatus.cpp | 2452 +++++++++++------------ 1 file changed, 1226 insertions(+), 1226 deletions(-) (limited to 'plugins') diff --git a/plugins/StatusPlugins/KeepStatus/keepstatus.cpp b/plugins/StatusPlugins/KeepStatus/keepstatus.cpp index 25dd21b9ee..6b3876988b 100644 --- a/plugins/StatusPlugins/KeepStatus/keepstatus.cpp +++ b/plugins/StatusPlugins/KeepStatus/keepstatus.cpp @@ -1,1226 +1,1226 @@ -/* - 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 "../commonstatus.h" -#include "keepstatus.h" -#include "../resource.h" - -struct TimerInfo { - int timer; - int timeout; - BOOL restart; - int result; - HANDLE hEvent; -}; - -static CRITICAL_SECTION GenTimerCS, GenStatusCS, CheckContinueslyCS; - -static HANDLE hProtoAckHook = NULL; -static HANDLE hStatusChangeHook = NULL; -static HANDLE hCSStatusChangeHook = NULL; -static HANDLE hCSStatusChangeExHook = NULL; - -extern HANDLE hConnectionEvent; -extern PLUGININFOEX pluginInfoEx; - -static HWND hMessageWindow = NULL; - -static int CompareConnections( const TConnectionSettings *p1, const TConnectionSettings *p2 ) -{ - return lstrcmpA( p1->szName, p2->szName ); -} - -static OBJLIST 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); -int LoadMainOptions(); -static void GetCurrentConnectionSettings(); -static int AssignStatus(TConnectionSettings* connSetting, int status, int lastStatus, TCHAR *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(TCHAR *msg, HICON hIcon); -LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); -static DWORD CALLBACK MessageWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - -// options.c -extern int OptionsInit(WPARAM wparam,LPARAM); -extern int InitCommonStatus(); - -TConnectionSettings::TConnectionSettings( PROTOACCOUNT *pa ) -{ - cbSize = sizeof(PROTOCOLSETTINGEX); - szName = pa->szModuleName; - tszAccName = pa->tszAccountName; - szMsg = NULL; - - int status = CallProtoService( pa->szModuleName, PS_GETSTATUS, 0, 0); - AssignStatus( this, status, status, NULL); -} - -TConnectionSettings::~TConnectionSettings() -{ - if ( szMsg != NULL) - free( szMsg ); -} - -int LoadMainOptions() -{ - 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, MODULENAME, SETTING_CHECKCONNECTION, FALSE)) { - if ( db_get_b(NULL, MODULENAME, SETTING_CONTCHECK, FALSE)) { - if ( db_get_b(NULL, MODULENAME, SETTING_BYPING, FALSE)) { - WSADATA wsaData; - WSAStartup(MAKEWORD(2, 2), &wsaData); - } - StartTimer(IDT_CHECKCONTIN, 0, FALSE); - } - increaseExponential = db_get_b(NULL, MODULENAME, SETTING_INCREASEEXPONENTIAL, FALSE); - currentDelay = initDelay = 1000*db_get_dw(NULL, MODULENAME, SETTING_INITDELAY, DEFAULT_INITDELAY); - maxDelay = 1000*db_get_dw(NULL, MODULENAME, SETTING_MAXDELAY, DEFAULT_MAXDELAY); - maxRetries = db_get_b(NULL, MODULENAME, 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, MODULENAME, SETTING_CHECKAPMRESUME, 0)&&(CallService(MS_SYSTEM_GETVERSION,0,0) >= 0x00040000)) { - if (!IsWindow(hMessageWindow)) { - hMessageWindow = CreateWindowEx(0, _T("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; - ProtoEnumAccounts( &count, &protos ); - - for ( int i=0; i < count; i++ ) - if ( IsSuitableProto( protos[i] )) - connectionSettings.insert( new TConnectionSettings( protos[i] )); -} - -static PROTOCOLSETTINGEX** GetCurrentProtoSettingsCopy() -{ - EnterCriticalSection(&GenStatusCS); - PROTOCOLSETTINGEX **ps = ( PROTOCOLSETTINGEX** )malloc(connectionSettings.getCount()*sizeof(PROTOCOLSETTINGEX *)); - if (ps == NULL) { - LeaveCriticalSection(&GenStatusCS); - return NULL; - } - for(int i=0;icbSize = 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; - } - LeaveCriticalSection(&GenStatusCS); - - 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, TCHAR *szMsg) -{ - if ( status < MIN_STATUS || status > MAX_STATUS ) - return -1; - - EnterCriticalSection(&GenStatusCS); - - char dbSetting[128]; - mir_snprintf(dbSetting, sizeof(dbSetting), "%s_enabled", cs->szName); - cs->lastStatus = lastStatus == 0 ? cs->status : lastStatus; - if (!db_get_b(NULL, MODULENAME, 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 && lstrcmp(szMsg, cs->szMsg)) { - if ( cs->szMsg != NULL ) - free(cs->szMsg); - - cs->szMsg = _tcsdup(szMsg); - } - else if (szMsg != cs->szMsg) { - if (cs->szMsg != NULL) - free(cs->szMsg); - - cs->szMsg = NULL; - } - LeaveCriticalSection(&GenStatusCS); - 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, MODULENAME, 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;iszName == NULL) || (connectionSettings[j].szName == NULL)) - continue; - - if (!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;iszName == NULL) || (connectionSettings[j].szName == NULL)) - continue; - if (!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; - - EnterCriticalSection(&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, MODULENAME, 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); - LeaveCriticalSection(&GenTimerCS); - - 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; - - EnterCriticalSection(&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); - LeaveCriticalSection(&GenTimerCS); - - 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, sizeof(dbSetting), "%s_enabled", ack->szModule); - if (!db_get_b(NULL, MODULENAME, 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 (!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 (!strcmp(ack->szModule, cs.szName)) { - AssignStatus(&cs, ID_STATUS_OFFLINE, 0, NULL); - if (db_get_b(NULL, MODULENAME, 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, MODULENAME, 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 (!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 = newDelay = 1000*db_get_dw(NULL, MODULENAME, 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 hwnd,UINT message,UINT_PTR idEvent,DWORD dwTime) -{ - 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); - int newStatus = CallProtoService(cs.szName,PS_GETSTATUS, 0, 0); - if (curStatus < MAX_CONNECT_RETRIES) { // connecting - maxConnectingTime = db_get_dw(NULL, MODULENAME, 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 hwnd,UINT message,UINT_PTR idEvent,DWORD dwTime) -{ - 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 (newStatus < MAX_CONNECT_RETRIES) { // connecting - maxConnectingTime = db_get_dw(NULL, MODULENAME, 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 hwnd,UINT message,UINT_PTR idEvent,DWORD dwTime) -{ - int shouldBeStatus, realStatus; - HICON hIcon; - - log_debugA("CheckConnectionTimer"); - bool setStatus = false; - if (showConnectionPopups) - hIcon = LoadSkinnedIcon(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 = LoadSkinnedProtoIcon(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, MODULENAME, SETTING_CHKINET, 0)) && (!InternetGetConnectedState(NULL, 0))) || (( db_get_b(NULL, MODULENAME, 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 hwnd,UINT message,UINT_PTR idEvent,DWORD dwTime) -{ - // 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 *arg) -{ - static int pingFailures = 0; - - // one at the time is enough, do it the 'easy' way - EnterCriticalSection(&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"); - LeaveCriticalSection(&CheckContinueslyCS); - return; - } - - BOOL ping = db_get_b(NULL, MODULENAME, SETTING_BYPING, FALSE); - if (ping) { - DBVARIANT dbv; - if (db_get(NULL, MODULENAME, 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)) { - LeaveCriticalSection(&CheckContinueslyCS); - return; // already connecting, leave - } - - if ( ((!ping) && (!InternetGetConnectedState(NULL, 0))) || ( (ping) && (!bLastPingResult) && (pingFailures >= db_get_w(NULL, MODULENAME, SETTING_PINGCOUNT, DEFAULT_PINGCOUNT)))) { - pingFailures = 0; - - int count; - PROTOACCOUNT** protos; - ProtoEnumAccounts( &count, &protos ); - - for(int i=0; i < count; i++ ) { - if ( !IsSuitableProto( protos[i] )) - continue; - - if (CallProtoService(protos[i]->szModuleName, PS_GETSTATUS, 0, 0) < MAX_CONNECT_RETRIES) { - 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"); - LeaveCriticalSection(&CheckContinueslyCS); - 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, MODULENAME, SETTING_MAXRETRIES, 0); - if (maxRetries == 0) - maxRetries = -1; - StartTimer(IDT_CHECKCONN, initDelay, FALSE); - } - LeaveCriticalSection(&CheckContinueslyCS); -} - -static VOID CALLBACK CheckContinueslyTimer(HWND hwnd, UINT message, UINT_PTR idEvent, DWORD dwTime) -{ - if ( db_get_b(NULL, MODULENAME, SETTING_BYPING, FALSE)) - mir_forkthread(CheckContinueslyFunction, NULL); - else - CheckContinueslyFunction(NULL); -} - -// =============== popup ====================== -static TCHAR* GetHumanName(LPARAM lParam) -{ - PROTOACCOUNT *ProtoAccount = ProtoGetAccount((char*)lParam); - return (ProtoAccount != NULL) ? ProtoAccount->tszAccountName : TranslateT("Protocol"); -} - -static int ProcessPopup(int reason, LPARAM lParam) -{ - HICON hIcon = NULL; - TCHAR text[MAX_SECONDLINE]; - - if ( !db_get_b(NULL, MODULENAME, SETTING_SHOWCONNECTIONPOPUPS,FALSE) || !ServiceExists(MS_POPUP_ADDPOPUPT)) - return -1; - - switch(reason) { - case KS_CONN_STATE_OTHERLOCATION: // lParam = 1 proto - if (!db_get_b(NULL, MODULENAME, SETTING_PUOTHER, TRUE)) - return -1; - - hIcon = LoadSkinnedProtoIcon((char*)lParam, SKINICON_STATUS_OFFLINE); - mir_sntprintf(text, SIZEOF(text), TranslateT("%s connected from another location"), GetHumanName(lParam)); - break; - - case KS_CONN_STATE_LOGINERROR: // lParam = 1 proto - if (!db_get_b(NULL, MODULENAME, SETTING_PUOTHER, TRUE)) - return -1; - - hIcon = LoadSkinnedProtoIcon((char*)lParam, SKINICON_STATUS_OFFLINE); - if ( db_get_b(NULL, MODULENAME, SETTING_LOGINERR, LOGINERR_NOTHING) == LOGINERR_CANCEL) - mir_sntprintf(text, SIZEOF(text), TranslateT("%s login error, cancel reconnecting"), GetHumanName(lParam)); - else if ( db_get_b(NULL, MODULENAME, SETTING_LOGINERR, LOGINERR_NOTHING) == LOGINERR_SETDELAY) - mir_sntprintf(text, SIZEOF(text), TranslateT("%s login error (next retry (%d) in %d s)"), GetHumanName(lParam), retryCount+1, db_get_dw(NULL, MODULENAME, SETTING_LOGINERR_DELAY, DEFAULT_MAXDELAY)); - else - return -1; - break; - - case KS_CONN_STATE_LOST: // lParam = 1 proto, or NULL - if (!db_get_b(NULL, MODULENAME, SETTING_PUCONNLOST, TRUE)) - return -1; - - if (lParam) { // Указатель на имя модуля. - hIcon = LoadSkinnedProtoIcon((char*)lParam, SKINICON_STATUS_OFFLINE); - mir_sntprintf(text, SIZEOF(text), TranslateT("%s status error (next retry (%d) in %d s)"), GetHumanName(lParam), retryCount+1, currentDelay/1000); - } - else mir_sntprintf(text, SIZEOF(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, MODULENAME, SETTING_PUCONNRETRY, TRUE)) - return -1; - else { - TCHAR protoInfoLine[512], protoInfo[MAX_SECONDLINE]; - memset(protoInfoLine, '\0', sizeof(protoInfoLine)); - memset(protoInfo, '\0', sizeof(protoInfo)); - _tcscpy(protoInfo, _T("\r\n")); - PROTOCOLSETTINGEX **ps = (PROTOCOLSETTINGEX **)lParam; - for (int i = 0; i < connectionSettings.getCount(); i++) - if (_tcslen(ps[i]->tszAccName) > 0 && strlen(ps[i]->szName) > 0) - if ( db_get_b(NULL, MODULENAME, SETTING_PUSHOWEXTRA, TRUE)) { - mir_sntprintf(protoInfoLine, SIZEOF(protoInfoLine), TranslateT("%s\t(will be set to %s)\r\n"), ps[i]->tszAccName, pcli->pfnGetStatusModeDescription(ps[i]->status, GSMDF_TCHAR)); - _tcsncat(protoInfo, protoInfoLine, SIZEOF(protoInfo) - _tcslen(protoInfo)-1); - } - - if (_tcslen(protoInfo) > 0) { - // cut the last end of line (this may also be the first one ;)) - *(protoInfo + _tcslen(protoInfo) - 2) = '\0'; - } - if (ps) - hIcon = LoadSkinnedProtoIcon(ps[0]->szName, SKINICON_STATUS_OFFLINE); - - if (retryCount == maxRetries-1) - mir_sntprintf(text, SIZEOF(text), TranslateT("Resetting status... (last try (%d))%s"), retryCount+1, protoInfo); - else - mir_sntprintf(text, SIZEOF(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, MODULENAME, SETTING_PUOTHER, TRUE)) - return -1; - - if (retryCount == maxRetries-1) - mir_sntprintf(text, SIZEOF(text), TranslateT("No internet connection seems available... (last try (%d))"), retryCount+1); - else - mir_sntprintf(text, SIZEOF(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, MODULENAME, SETTING_PURESULT, TRUE)) - return -1; - - if (lParam) { - hIcon = LoadSkinnedIcon(SKINICON_STATUS_ONLINE); - mir_sntprintf(text, SIZEOF(text), TranslateT("Status was set ok")); - } - else mir_sntprintf(text, SIZEOF(text), TranslateT("Giving up")); - break; - } - if (hIcon == NULL) - hIcon = LoadSkinnedIcon(SKINICON_STATUS_OFFLINE); - - log_info(L"KeepStatus: %s", text); - return ShowPopup(text, hIcon); -} - -static INT_PTR ShowPopup(TCHAR *msg, HICON hIcon) -{ - POPUPDATAT ppd = { 0 }; - ppd.lchIcon = hIcon; - _tcsncpy(ppd.lptzContactName, TranslateT("KeepStatus"), MAX_CONTACTNAME); - _tcsncpy(ppd.lptzText, msg, MAX_SECONDLINE); - if (db_get_b(NULL, MODULENAME, SETTING_POPUP_USEWINCOLORS, 0)) { - ppd.colorBack = GetSysColor(COLOR_BTNFACE); - ppd.colorText = GetSysColor(COLOR_WINDOWTEXT); - } - else if (!db_get_b(NULL, MODULENAME, SETTING_POPUP_USEDEFCOLORS, 0)) { - ppd.colorBack = db_get_dw(NULL, MODULENAME, SETTING_POPUP_BACKCOLOR, 0xAAAAAA); - ppd.colorText = db_get_dw(NULL, MODULENAME, SETTING_POPUP_TEXTCOLOR, 0x0000CC); - } - ppd.PluginWindowProc = PopupDlgProc; - - switch (db_get_b(NULL, MODULENAME, SETTING_POPUP_DELAYTYPE, POPUP_DELAYFROMPU)) { - case POPUP_DELAYCUSTOM: - ppd.iSeconds = (int)db_get_dw(NULL, MODULENAME, 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 PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -{ - switch (message) { - case WM_CONTEXTMENU: // right - case WM_COMMAND: // left - switch (db_get_b(NULL, MODULENAME, - (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 wParam, LPARAM 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, sizeof(dbSetting), "%s_enabled", szProto); - if (!db_get_b(NULL, MODULENAME, dbSetting, 1)) // 'hard' disabled - return -1; - - int ret = -2; - for (int i = 0; i < connectionSettings.getCount(); i++) { - TConnectionSettings& cs = connectionSettings[i]; - if (!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 wParam, LPARAM lParam) -{ - int ret = -2; - char *szProto = (char *)lParam; - - char dbSetting[128]; - mir_snprintf(dbSetting, sizeof(dbSetting), "%s_enabled", szProto); - if (!db_get_b(NULL, MODULENAME, dbSetting, 1)) - return FALSE; - - for (int i = 0; i < connectionSettings.getCount(); i++) { - TConnectionSettings& cs = connectionSettings[i]; - if (!strcmp(szProto, cs.szName)) - return GetStatus(cs) != ID_STATUS_DISABLED; - } - - return FALSE; -} - -INT_PTR AnnounceStatusChangeService(WPARAM 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 ( !lstrcmpA( cs.szName, newSituation->szName )) - AssignStatus(&cs, newSituation->status, newSituation->lastStatus, newSituation->szMsg); - } - - return 0; -} - -// =============== window for suspend =============== - -static DWORD CALLBACK MessageWndProc(HWND 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 OnAccChanged(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 (!lstrcmpA(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(); - - DeleteCriticalSection(&GenTimerCS); - DeleteCriticalSection(&GenStatusCS); - DeleteCriticalSection(&CheckContinueslyCS); - return 0; -} - -int CSModuleLoaded(WPARAM, LPARAM) -{ - InitializeCriticalSection(&GenTimerCS); - InitializeCriticalSection(&GenStatusCS); - InitializeCriticalSection(&CheckContinueslyCS); - - protoList = (OBJLIST*)&connectionSettings; - - hMessageWindow = NULL; - LoadMainOptions(); - - HookEvent(ME_OPT_INITIALISE, OptionsInit); - HookEvent(ME_SYSTEM_PRESHUTDOWN, onShutdown); - HookEvent(ME_PROTO_ACCLISTCHANGED, OnAccChanged); - return 0; -} +/* + 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 "../commonstatus.h" +#include "keepstatus.h" +#include "../resource.h" + +struct TimerInfo { + int timer; + int timeout; + BOOL restart; + int result; + HANDLE hEvent; +}; + +static CRITICAL_SECTION GenTimerCS, GenStatusCS, CheckContinueslyCS; + +static HANDLE hProtoAckHook = NULL; +static HANDLE hStatusChangeHook = NULL; +static HANDLE hCSStatusChangeHook = NULL; +static HANDLE hCSStatusChangeExHook = NULL; + +extern HANDLE hConnectionEvent; +extern PLUGININFOEX pluginInfoEx; + +static HWND hMessageWindow = NULL; + +static int CompareConnections( const TConnectionSettings *p1, const TConnectionSettings *p2 ) +{ + return lstrcmpA( p1->szName, p2->szName ); +} + +static OBJLIST 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); +int LoadMainOptions(); +static void GetCurrentConnectionSettings(); +static int AssignStatus(TConnectionSettings* connSetting, int status, int lastStatus, TCHAR *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(TCHAR *msg, HICON hIcon); +LRESULT CALLBACK PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); +static DWORD CALLBACK MessageWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); + +// options.c +extern int OptionsInit(WPARAM wparam,LPARAM); +extern int InitCommonStatus(); + +TConnectionSettings::TConnectionSettings( PROTOACCOUNT *pa ) +{ + cbSize = sizeof(PROTOCOLSETTINGEX); + szName = pa->szModuleName; + tszAccName = pa->tszAccountName; + szMsg = NULL; + + int status = CallProtoService( pa->szModuleName, PS_GETSTATUS, 0, 0); + AssignStatus( this, status, status, NULL); +} + +TConnectionSettings::~TConnectionSettings() +{ + if ( szMsg != NULL) + free( szMsg ); +} + +int LoadMainOptions() +{ + 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, MODULENAME, SETTING_CHECKCONNECTION, FALSE)) { + if ( db_get_b(NULL, MODULENAME, SETTING_CONTCHECK, FALSE)) { + if ( db_get_b(NULL, MODULENAME, SETTING_BYPING, FALSE)) { + WSADATA wsaData; + WSAStartup(MAKEWORD(2, 2), &wsaData); + } + StartTimer(IDT_CHECKCONTIN, 0, FALSE); + } + increaseExponential = db_get_b(NULL, MODULENAME, SETTING_INCREASEEXPONENTIAL, FALSE); + currentDelay = initDelay = 1000*db_get_dw(NULL, MODULENAME, SETTING_INITDELAY, DEFAULT_INITDELAY); + maxDelay = 1000*db_get_dw(NULL, MODULENAME, SETTING_MAXDELAY, DEFAULT_MAXDELAY); + maxRetries = db_get_b(NULL, MODULENAME, 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, MODULENAME, SETTING_CHECKAPMRESUME, 0)&&(CallService(MS_SYSTEM_GETVERSION,0,0) >= 0x00040000)) { + if (!IsWindow(hMessageWindow)) { + hMessageWindow = CreateWindowEx(0, _T("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; + ProtoEnumAccounts( &count, &protos ); + + for ( int i=0; i < count; i++ ) + if ( IsSuitableProto( protos[i] )) + connectionSettings.insert( new TConnectionSettings( protos[i] )); +} + +static PROTOCOLSETTINGEX** GetCurrentProtoSettingsCopy() +{ + EnterCriticalSection(&GenStatusCS); + PROTOCOLSETTINGEX **ps = ( PROTOCOLSETTINGEX** )malloc(connectionSettings.getCount()*sizeof(PROTOCOLSETTINGEX *)); + if (ps == NULL) { + LeaveCriticalSection(&GenStatusCS); + return NULL; + } + for(int i=0;icbSize = 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; + } + LeaveCriticalSection(&GenStatusCS); + + 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, TCHAR *szMsg) +{ + if ( status < MIN_STATUS || status > MAX_STATUS ) + return -1; + + EnterCriticalSection(&GenStatusCS); + + char dbSetting[128]; + mir_snprintf(dbSetting, sizeof(dbSetting), "%s_enabled", cs->szName); + cs->lastStatus = lastStatus == 0 ? cs->status : lastStatus; + if (!db_get_b(NULL, MODULENAME, 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 && lstrcmp(szMsg, cs->szMsg)) { + if ( cs->szMsg != NULL ) + free(cs->szMsg); + + cs->szMsg = _tcsdup(szMsg); + } + else if (szMsg != cs->szMsg) { + if (cs->szMsg != NULL) + free(cs->szMsg); + + cs->szMsg = NULL; + } + LeaveCriticalSection(&GenStatusCS); + 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, MODULENAME, 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;iszName == NULL) || (connectionSettings[j].szName == NULL)) + continue; + + if (!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;iszName == NULL) || (connectionSettings[j].szName == NULL)) + continue; + if (!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; + + EnterCriticalSection(&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, MODULENAME, 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); + LeaveCriticalSection(&GenTimerCS); + + 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; + + EnterCriticalSection(&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); + LeaveCriticalSection(&GenTimerCS); + + 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, sizeof(dbSetting), "%s_enabled", ack->szModule); + if (!db_get_b(NULL, MODULENAME, 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 (!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 (!strcmp(ack->szModule, cs.szName)) { + AssignStatus(&cs, ID_STATUS_OFFLINE, 0, NULL); + if (db_get_b(NULL, MODULENAME, 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, MODULENAME, 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 (!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 = newDelay = 1000*db_get_dw(NULL, MODULENAME, 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 hwnd,UINT message,UINT_PTR idEvent,DWORD dwTime) +{ + 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); + int newStatus = CallProtoService(cs.szName,PS_GETSTATUS, 0, 0); + if (curStatus < MAX_CONNECT_RETRIES) { // connecting + maxConnectingTime = db_get_dw(NULL, MODULENAME, 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 hwnd,UINT message,UINT_PTR idEvent,DWORD dwTime) +{ + 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 (newStatus < MAX_CONNECT_RETRIES) { // connecting + maxConnectingTime = db_get_dw(NULL, MODULENAME, 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 hwnd,UINT message,UINT_PTR idEvent,DWORD dwTime) +{ + int shouldBeStatus, realStatus; + HICON hIcon; + + log_debugA("CheckConnectionTimer"); + bool setStatus = false; + if (showConnectionPopups) + hIcon = LoadSkinnedIcon(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 = LoadSkinnedProtoIcon(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, MODULENAME, SETTING_CHKINET, 0)) && (!InternetGetConnectedState(NULL, 0))) || (( db_get_b(NULL, MODULENAME, 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 hwnd,UINT message,UINT_PTR idEvent,DWORD dwTime) +{ + // 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 *arg) +{ + static int pingFailures = 0; + + // one at the time is enough, do it the 'easy' way + EnterCriticalSection(&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"); + LeaveCriticalSection(&CheckContinueslyCS); + return; + } + + BOOL ping = db_get_b(NULL, MODULENAME, SETTING_BYPING, FALSE); + if (ping) { + DBVARIANT dbv; + if (db_get(NULL, MODULENAME, 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)) { + LeaveCriticalSection(&CheckContinueslyCS); + return; // already connecting, leave + } + + if ( ((!ping) && (!InternetGetConnectedState(NULL, 0))) || ( (ping) && (!bLastPingResult) && (pingFailures >= db_get_w(NULL, MODULENAME, SETTING_PINGCOUNT, DEFAULT_PINGCOUNT)))) { + pingFailures = 0; + + int count; + PROTOACCOUNT** protos; + ProtoEnumAccounts( &count, &protos ); + + for(int i=0; i < count; i++ ) { + if ( !IsSuitableProto( protos[i] )) + continue; + + if (CallProtoService(protos[i]->szModuleName, PS_GETSTATUS, 0, 0) < MAX_CONNECT_RETRIES) { + 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"); + LeaveCriticalSection(&CheckContinueslyCS); + 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, MODULENAME, SETTING_MAXRETRIES, 0); + if (maxRetries == 0) + maxRetries = -1; + StartTimer(IDT_CHECKCONN, initDelay, FALSE); + } + LeaveCriticalSection(&CheckContinueslyCS); +} + +static VOID CALLBACK CheckContinueslyTimer(HWND hwnd, UINT message, UINT_PTR idEvent, DWORD dwTime) +{ + if ( db_get_b(NULL, MODULENAME, SETTING_BYPING, FALSE)) + mir_forkthread(CheckContinueslyFunction, NULL); + else + CheckContinueslyFunction(NULL); +} + +// =============== popup ====================== +static TCHAR* GetHumanName(LPARAM lParam) +{ + PROTOACCOUNT *ProtoAccount = ProtoGetAccount((char*)lParam); + return (ProtoAccount != NULL) ? ProtoAccount->tszAccountName : TranslateT("Protocol"); +} + +static int ProcessPopup(int reason, LPARAM lParam) +{ + HICON hIcon = NULL; + TCHAR text[MAX_SECONDLINE]; + + if ( !db_get_b(NULL, MODULENAME, SETTING_SHOWCONNECTIONPOPUPS,FALSE) || !ServiceExists(MS_POPUP_ADDPOPUPT)) + return -1; + + switch(reason) { + case KS_CONN_STATE_OTHERLOCATION: // lParam = 1 proto + if (!db_get_b(NULL, MODULENAME, SETTING_PUOTHER, TRUE)) + return -1; + + hIcon = LoadSkinnedProtoIcon((char*)lParam, SKINICON_STATUS_OFFLINE); + mir_sntprintf(text, SIZEOF(text), TranslateT("%s connected from another location"), GetHumanName(lParam)); + break; + + case KS_CONN_STATE_LOGINERROR: // lParam = 1 proto + if (!db_get_b(NULL, MODULENAME, SETTING_PUOTHER, TRUE)) + return -1; + + hIcon = LoadSkinnedProtoIcon((char*)lParam, SKINICON_STATUS_OFFLINE); + if ( db_get_b(NULL, MODULENAME, SETTING_LOGINERR, LOGINERR_NOTHING) == LOGINERR_CANCEL) + mir_sntprintf(text, SIZEOF(text), TranslateT("%s login error, cancel reconnecting"), GetHumanName(lParam)); + else if ( db_get_b(NULL, MODULENAME, SETTING_LOGINERR, LOGINERR_NOTHING) == LOGINERR_SETDELAY) + mir_sntprintf(text, SIZEOF(text), TranslateT("%s login error (next retry (%d) in %d s)"), GetHumanName(lParam), retryCount+1, db_get_dw(NULL, MODULENAME, SETTING_LOGINERR_DELAY, DEFAULT_MAXDELAY)); + else + return -1; + break; + + case KS_CONN_STATE_LOST: // lParam = 1 proto, or NULL + if (!db_get_b(NULL, MODULENAME, SETTING_PUCONNLOST, TRUE)) + return -1; + + if (lParam) { // Указатель на имя модуля. + hIcon = LoadSkinnedProtoIcon((char*)lParam, SKINICON_STATUS_OFFLINE); + mir_sntprintf(text, SIZEOF(text), TranslateT("%s status error (next retry (%d) in %d s)"), GetHumanName(lParam), retryCount+1, currentDelay/1000); + } + else mir_sntprintf(text, SIZEOF(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, MODULENAME, SETTING_PUCONNRETRY, TRUE)) + return -1; + if (lParam) { + int i; + PROTOCOLSETTINGEX **ps = (PROTOCOLSETTINGEX **)lParam; + TCHAR protoInfoLine[512], protoInfo[MAX_SECONDLINE]; + memset(protoInfoLine, '\0', sizeof(protoInfoLine)); + memset(protoInfo, '\0', sizeof(protoInfo)); + _tcscpy(protoInfo, _T("\r\n")); + for (i = 0; i < connectionSettings.getCount(); i++) { + if (_tcslen(ps[i]->tszAccName) > 0 && strlen(ps[i]->szName) > 0) { + if ( db_get_b(NULL, MODULENAME, SETTING_PUSHOWEXTRA, TRUE)) { + mir_sntprintf(protoInfoLine, SIZEOF(protoInfoLine), TranslateT("%s\t(will be set to %s)\r\n"), ps[i]->tszAccName, pcli->pfnGetStatusModeDescription(ps[i]->status, GSMDF_TCHAR)); + _tcsncat(protoInfo, protoInfoLine, SIZEOF(protoInfo) - _tcslen(protoInfo)-1); + } + } + } + i = _tcslen(protoInfo); + if (i > 0) /* cut the last end of line (this may also be the first one ;)) */ + protoInfo[i - 2] = '\0'; + hIcon = LoadSkinnedProtoIcon(ps[0]->szName, SKINICON_STATUS_OFFLINE); + + if (retryCount == (maxRetries - 1)) + mir_sntprintf(text, SIZEOF(text), TranslateT("Resetting status... (last try (%d))%s"), retryCount + 1, protoInfo); + else + mir_sntprintf(text, SIZEOF(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, MODULENAME, SETTING_PUOTHER, TRUE)) + return -1; + + if (retryCount == maxRetries-1) + mir_sntprintf(text, SIZEOF(text), TranslateT("No internet connection seems available... (last try (%d))"), retryCount + 1); + else + mir_sntprintf(text, SIZEOF(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, MODULENAME, SETTING_PURESULT, TRUE)) + return -1; + + if (lParam) { + hIcon = LoadSkinnedIcon(SKINICON_STATUS_ONLINE); + mir_sntprintf(text, SIZEOF(text), TranslateT("Status was set ok")); + } + else mir_sntprintf(text, SIZEOF(text), TranslateT("Giving up")); + break; + } + if (hIcon == NULL) + hIcon = LoadSkinnedIcon(SKINICON_STATUS_OFFLINE); + + log_info(L"KeepStatus: %s", text); + return ShowPopup(text, hIcon); +} + +static INT_PTR ShowPopup(TCHAR *msg, HICON hIcon) +{ + POPUPDATAT ppd = { 0 }; + ppd.lchIcon = hIcon; + _tcsncpy(ppd.lptzContactName, TranslateT("KeepStatus"), MAX_CONTACTNAME); + _tcsncpy(ppd.lptzText, msg, MAX_SECONDLINE); + if (db_get_b(NULL, MODULENAME, SETTING_POPUP_USEWINCOLORS, 0)) { + ppd.colorBack = GetSysColor(COLOR_BTNFACE); + ppd.colorText = GetSysColor(COLOR_WINDOWTEXT); + } + else if (!db_get_b(NULL, MODULENAME, SETTING_POPUP_USEDEFCOLORS, 0)) { + ppd.colorBack = db_get_dw(NULL, MODULENAME, SETTING_POPUP_BACKCOLOR, 0xAAAAAA); + ppd.colorText = db_get_dw(NULL, MODULENAME, SETTING_POPUP_TEXTCOLOR, 0x0000CC); + } + ppd.PluginWindowProc = PopupDlgProc; + + switch (db_get_b(NULL, MODULENAME, SETTING_POPUP_DELAYTYPE, POPUP_DELAYFROMPU)) { + case POPUP_DELAYCUSTOM: + ppd.iSeconds = (int)db_get_dw(NULL, MODULENAME, 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 PopupDlgProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) +{ + switch (message) { + case WM_CONTEXTMENU: // right + case WM_COMMAND: // left + switch (db_get_b(NULL, MODULENAME, + (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 wParam, LPARAM 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, sizeof(dbSetting), "%s_enabled", szProto); + if (!db_get_b(NULL, MODULENAME, dbSetting, 1)) // 'hard' disabled + return -1; + + int ret = -2; + for (int i = 0; i < connectionSettings.getCount(); i++) { + TConnectionSettings& cs = connectionSettings[i]; + if (!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 wParam, LPARAM lParam) +{ + int ret = -2; + char *szProto = (char *)lParam; + + char dbSetting[128]; + mir_snprintf(dbSetting, sizeof(dbSetting), "%s_enabled", szProto); + if (!db_get_b(NULL, MODULENAME, dbSetting, 1)) + return FALSE; + + for (int i = 0; i < connectionSettings.getCount(); i++) { + TConnectionSettings& cs = connectionSettings[i]; + if (!strcmp(szProto, cs.szName)) + return GetStatus(cs) != ID_STATUS_DISABLED; + } + + return FALSE; +} + +INT_PTR AnnounceStatusChangeService(WPARAM 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 ( !lstrcmpA( cs.szName, newSituation->szName )) + AssignStatus(&cs, newSituation->status, newSituation->lastStatus, newSituation->szMsg); + } + + return 0; +} + +// =============== window for suspend =============== + +static DWORD CALLBACK MessageWndProc(HWND 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 OnAccChanged(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 (!lstrcmpA(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(); + + DeleteCriticalSection(&GenTimerCS); + DeleteCriticalSection(&GenStatusCS); + DeleteCriticalSection(&CheckContinueslyCS); + return 0; +} + +int CSModuleLoaded(WPARAM, LPARAM) +{ + InitializeCriticalSection(&GenTimerCS); + InitializeCriticalSection(&GenStatusCS); + InitializeCriticalSection(&CheckContinueslyCS); + + protoList = (OBJLIST*)&connectionSettings; + + hMessageWindow = NULL; + LoadMainOptions(); + + HookEvent(ME_OPT_INITIALISE, OptionsInit); + HookEvent(ME_SYSTEM_PRESHUTDOWN, onShutdown); + HookEvent(ME_PROTO_ACCLISTCHANGED, OnAccChanged); + return 0; +} -- cgit v1.2.3