/* * This code implements miscellaneous usefull functions * * (c) majvan 2002-2004 */ #include "m_yamn.h" #include "m_protoplugin.h" #include "m_messages.h" #include "m_synchro.h" #include "main.h" #include "yamn.h" #ifdef DEBUG_SYNCHRO #include #endif //- imported --------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- extern PYAMN_PROTOPLUGINQUEUE FirstProtoPlugin; extern YAMN_VARIABLES YAMNVar; extern char *ProtoName; extern HANDLE hTTButton; //TopToolBar button extern DWORD WriteAccountsToFile(); extern DWORD WINAPI SWMRGWaitToRead(PSWMRG,DWORD); extern void WINAPI SWMRGDoneReading(PSWMRG); extern DWORD WINAPI WaitToReadFcn(PSWMRG); extern void WINAPI ReadDoneFcn(PSWMRG); //From protoplugin.cpp extern struct CExportedFunctions ProtoPluginExportedFcn[1]; extern struct CExportedServices ProtoPluginExportedSvc[5]; //From filterplugin.cpp extern struct CExportedFunctions FilterPluginExportedFcn[1]; extern struct CExportedServices FilterPluginExportedSvc[2]; //From synchro.cpp extern struct CExportedFunctions SynchroExportedFcn[7]; //From account.cpp extern struct CExportedFunctions AccountExportedFcn[2]; extern struct CExportedServices AccountExportedSvc[9]; //From mails.cpp (MIME) extern struct CExportedFunctions MailExportedFcn[8]; extern struct CExportedServices MailExportedSvc[5]; //-------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- //MessageWndCS //We want to send messages to all windows in the queue //When we send messages, no other window can register itself to the queue for receiving messages LPCRITICAL_SECTION MessageWndCS; //Plugin registration CS //Used if we add (register) plugin to YAMN plugins and when we browse through registered plugins LPCRITICAL_SECTION PluginRegCS; //AccountWriterCS //We want to store number of writers of Accounts (number of Accounts used for writing) //If we want to read all accounts (for saving to file) immidiatelly, we have to wait until no account is changing (no thread writing to account) SCOUNTER *AccountWriterSO; //NoExitEV //Event that is signaled when there's a request to exit, so no new pop3 check should be performed HANDLE ExitEV; //WriteToFileEV //If this is signaled, write accounts to file is performed. Set this event if you want to actualize your accounts and messages HANDLE WriteToFileEV; //Returns pointer to YAMN exported function INT_PTR GetFcnPtrSvc(WPARAM wParam,LPARAM lParam); //Returns pointer to YAMN variables INT_PTR GetVariablesSvc(WPARAM wParam,LPARAM); // Thread running only to catch hotkeys DWORD WINAPI YAMNHotKeyThread(LPVOID Param); // Function every seconds decrements account counter of seconds and checks if they are 0 // If yes, creates a POP3 thread to check account void CALLBACK TimerProc(HWND,UINT,UINT,DWORD); // Function called to check all accounts immidialtelly // no params INT_PTR ForceCheckSvc(WPARAM,LPARAM); //thread is running all the time //waits for WriteToFileEV and then writes all accounts to file //DWORD WINAPI FileWritingThread(PVOID); // Function is called when Miranda notifies plugin that it is about to exit // Ensures succesfull end of POP3 checking, sets event that no next checking should be performed // If there's no writer to account (POP3 thread), saves the results to the file //not used now, perhaps in the future //int ExitProc(WPARAM wParam,LPARAM lParam); //-------------------------------------------------------------------------------------------------- //-------------------------------------------------------------------------------------------------- INT_PTR GetFcnPtrSvc(WPARAM wParam,LPARAM lParam) { register int i; for(i=0;iNext) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"TimerProc:AccountBrowserSO-read wait\n"); #endif if(WAIT_OBJECT_0!=SWMRGWaitToRead(ActualPlugin->Plugin->AccountBrowserSO,0)) //we want to access accounts immiadtelly { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"TimerProc:AccountBrowserSO-read enter failed\n"); #endif LeaveCriticalSection(PluginRegCS); return; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"TimerProc:AccountBrowserSO-read enter\n"); #endif for(ActualAccount=ActualPlugin->Plugin->FirstAccount;ActualAccount!=NULL;ActualAccount=ActualAccount->Next) { if(ActualAccount->Plugin==NULL || ActualAccount->Plugin->Fcn==NULL) //account not inited continue; #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read wait\n"); #endif if(WAIT_OBJECT_0!=SWMRGWaitToRead(ActualAccount->AccountAccessSO,0)) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read wait failed\n"); #endif continue; } #ifdef DEBUG_SYNCHRO switch(Status) { case ID_STATUS_OFFLINE: DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read enter status offline\n"); break; case ID_STATUS_ONLINE: DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read enter status online\n"); break; case ID_STATUS_AWAY: DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read enter status away\n"); break; case ID_STATUS_DND: DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read enter status dnd\n"); break; case ID_STATUS_NA: DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read enter status na\n"); break; case ID_STATUS_OCCUPIED: DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read enter status occupied\n"); break; case ID_STATUS_FREECHAT: DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read enter status freechat\n"); break; case ID_STATUS_INVISIBLE: DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read enter status invisible\n"); break; case ID_STATUS_ONTHEPHONE: DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read enter status onthephone\n"); break; case ID_STATUS_OUTTOLUNCH: DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read enter status outtolunch\n"); break; default: DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read enter status unknown\n"); break; } #endif BOOL isAccountCounting = 0; if( (ActualAccount->Flags & YAMN_ACC_ENA) && (((ActualAccount->StatusFlags & YAMN_ACC_ST0) && (Status<=ID_STATUS_OFFLINE)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST1) && (Status==ID_STATUS_ONLINE)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST2) && (Status==ID_STATUS_AWAY)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST3) && (Status==ID_STATUS_DND)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST4) && (Status==ID_STATUS_NA)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST5) && (Status==ID_STATUS_OCCUPIED)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST6) && (Status==ID_STATUS_FREECHAT)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST7) && (Status==ID_STATUS_INVISIBLE)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST8) && (Status==ID_STATUS_ONTHEPHONE)) || ((ActualAccount->StatusFlags & YAMN_ACC_ST9) && (Status==ID_STATUS_OUTTOLUNCH)))) { if((!ActualAccount->Interval && !ActualAccount->TimeLeft) || ActualAccount->Plugin->Fcn->TimeoutFcnPtr==NULL) { goto ChangeIsCountingStatusLabel; } if(ActualAccount->TimeLeft){ ActualAccount->TimeLeft--; isAccountCounting = TRUE; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"TimerProc:time left : %i\n",ActualAccount->TimeLeft); #endif WindowList_BroadcastAsync(YAMNVar.MessageWnds,WM_YAMN_CHANGETIME,(WPARAM)ActualAccount,(LPARAM)ActualAccount->TimeLeft); if(!ActualAccount->TimeLeft) { struct CheckParam ParamToPlugin={YAMN_CHECKVERSION,ThreadRunningEV,ActualAccount,YAMN_NORMALCHECK,(void *)0,NULL}; HANDLE NewThread; ActualAccount->TimeLeft=ActualAccount->Interval; if(NULL==(NewThread=CreateThread(NULL,0,(YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->TimeoutFcnPtr,&ParamToPlugin,0,&tid))) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read done\n"); #endif ReadDoneFcn(ActualAccount->AccountAccessSO); continue; } else { WaitForSingleObject(ThreadRunningEV,INFINITE); CloseHandle(NewThread); } } } ChangeIsCountingStatusLabel: #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"TimerProc:ActualAccountSO-read done\n"); #endif if (((ActualAccount->isCounting)!=0)!=isAccountCounting){ ActualAccount->isCounting=isAccountCounting; WORD cStatus = DBGetContactSettingWord(ActualAccount->hContact,ProtoName,"Status",0); switch (cStatus){ case ID_STATUS_ONLINE: case ID_STATUS_OFFLINE: DBWriteContactSettingWord(ActualAccount->hContact, ProtoName, "Status", isAccountCounting?ID_STATUS_ONLINE:ID_STATUS_OFFLINE); default: break; } } ReadDoneFcn(ActualAccount->AccountAccessSO); } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"TimerProc:AccountBrowserSO-read done\n"); #endif SWMRGDoneReading(ActualPlugin->Plugin->AccountBrowserSO); } LeaveCriticalSection(PluginRegCS); CloseHandle(ThreadRunningEV); return; } INT_PTR ForceCheckSvc(WPARAM,LPARAM) { PYAMN_PROTOPLUGINQUEUE ActualPlugin; HACCOUNT ActualAccount; HANDLE ThreadRunningEV; DWORD tid; //we use event to signal, that running thread has all needed stack parameters copied if(NULL==(ThreadRunningEV=CreateEvent(NULL,FALSE,FALSE,NULL))) return 0; //if we want to close miranda, we get event and do not run pop3 checking anymore if(WAIT_OBJECT_0==WaitForSingleObject(ExitEV,0)) return 0; EnterCriticalSection(PluginRegCS); for(ActualPlugin=FirstProtoPlugin;ActualPlugin!=NULL;ActualPlugin=ActualPlugin->Next) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"ForceCheck:AccountBrowserSO-read wait\n"); #endif SWMRGWaitToRead(ActualPlugin->Plugin->AccountBrowserSO,INFINITE); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"ForceCheck:AccountBrowserSO-read enter\n"); #endif for(ActualAccount=ActualPlugin->Plugin->FirstAccount;ActualAccount!=NULL;ActualAccount=ActualAccount->Next) { if(ActualAccount->Plugin->Fcn==NULL) //account not inited continue; #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"ForceCheck:ActualAccountSO-read wait\n"); #endif if(WAIT_OBJECT_0!=WaitToReadFcn(ActualAccount->AccountAccessSO)) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"ForceCheck:ActualAccountSO-read wait failed\n"); #endif continue; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"ForceCheck:ActualAccountSO-read enter\n"); #endif if((ActualAccount->Flags & YAMN_ACC_ENA) && (ActualAccount->StatusFlags & YAMN_ACC_FORCE)) //account cannot be forced to check { if(ActualAccount->Plugin->Fcn->ForceCheckFcnPtr==NULL) { ReadDoneFcn(ActualAccount->AccountAccessSO); continue; } struct CheckParam ParamToPlugin={YAMN_CHECKVERSION,ThreadRunningEV,ActualAccount,YAMN_FORCECHECK,(void *)0,NULL}; if(NULL==CreateThread(NULL,0,(YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->ForceCheckFcnPtr,&ParamToPlugin,0,&tid)) { ReadDoneFcn(ActualAccount->AccountAccessSO); continue; } else WaitForSingleObject(ThreadRunningEV,INFINITE); } ReadDoneFcn(ActualAccount->AccountAccessSO); } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"ForceCheck:AccountBrowserSO-read done\n"); #endif SWMRGDoneReading(ActualPlugin->Plugin->AccountBrowserSO); } LeaveCriticalSection(PluginRegCS); CloseHandle(ThreadRunningEV); CallService(MS_TTB_SETBUTTONSTATE,(WPARAM)hTTButton,(LPARAM)TTBST_RELEASED); return 1; } /* int ExitProc(WPARAM wParam,LPARAM lParam) { THIS WILL BE IMPLEMENTED LATER // First, no thread must add or delete accounts. This is achieved by entering browsing through accounts // If any thread want to delete or add, it waits for write-access to browse accounts (so it waits infinite time) #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"ExitProc:AccountBrowserSO-wait to obtain read access\n")); #endif if(WAIT_TIMEOUT==SWMRGWaitToRead(AccountBrowserSO,0)) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"ExitProc:AccountBrowserSO-read access obtain failed, I'll try later\n")); #endif return 1; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"ExitProc:AccountBrowserSO-read access obtained\n")); #endif #ifdef DEBUG_SYNCHRO TCHAR Debug[100]; _stprintf(Debug,_T("ExitProc:Writers: %d\n"),AccountWriterSO->GetNumber()); DEBUG_SYNCHRO2F(Debug); DebugLog(SynchroFile,"ExitProc:NoWriterEV-test\n")); #endif // next, threads must not write to any account. This works like hFinishEV event in AccountAccessSO and MessagesAccessSO. // When hFinishEV is set, any beginning with reading and writing to account (messages) is failed. // This is similar, but the difference is, that we can finish the whole work (we can decide: if ExitEV is set, should we // end immidialtelly or should we continue (to end operation successfully)? // E.g. I decided that once we started checking account, we get all new mails and then we can end. // The second and more significant difference is, that ExitEV is signal to all accounts and messages, not only to one account. SetEvent(ExitEV); if(WAIT_TIMEOUT==WaitForSingleObject(AccountWriterSO->Event,0)) { // There exists a thread writing to account, so we ca try later to write accounts to file, if no thread is writting #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"ExitProc:NoWriterEV-writer(s) exists, I'll try later\n")); #endif SWMRGDoneReading(AccountBrowserSO); return 1; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"ExitProc:NoWriterEV-no writer, going to save!\n")); #endif // Save to file WriteAccountsToFile(); SWMRGDoneReading(AccountBrowserSO); // Now, all is saved, we can safe exit from Miranda return 0; } */ /* DWORD WINAPI FileWritingThread(PVOID) { HACCOUNT ActualAccount=FirstAccount; while(1) { WaitForSingleObject(WriteToFileEV,INFINITE); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile,"FileWriting:WriteToFileEV-signaled\n")); #endif // now, write accounts and messages if it is possible. If it is not possible e.g. to read messages from one account, // function will wait until messages are not used and then writes messages WriteAccountsToFile(); } return 0; } */