diff options
author | George Hazan <ghazan@miranda.im> | 2019-03-02 12:32:44 +0300 |
---|---|---|
committer | George Hazan <ghazan@miranda.im> | 2019-03-02 12:32:55 +0300 |
commit | 931a7dc1ac0dbc7e6c1083583ced915e572f5b47 (patch) | |
tree | 9fe9a6448d44030e26aa7107ce16044ed413e0d0 /protocols/YAMN/src/account.cpp | |
parent | dd7d9954042254e66e3bbbec7195c6be8b1a0663 (diff) |
all protocols (even virtual ones) moved to the Protocols folder
Diffstat (limited to 'protocols/YAMN/src/account.cpp')
-rw-r--r-- | protocols/YAMN/src/account.cpp | 1246 |
1 files changed, 1246 insertions, 0 deletions
diff --git a/protocols/YAMN/src/account.cpp b/protocols/YAMN/src/account.cpp new file mode 100644 index 0000000000..0755276f7b --- /dev/null +++ b/protocols/YAMN/src/account.cpp @@ -0,0 +1,1246 @@ +/* + * This code implements manipulation with accounts + * such as reading accounts from file, writing them to file, + * finding account by name etc. + * + * (c) majvan 2002-2004 + */ + +#include "stdafx.h" + +// Account status CS +// When we check some account, thread should change status of account to idle, connecting etc. +// So if we want to read status, we have to successfully write and then read. +static mir_cs csAccountStatusCS; + +// File Writing CS +// When 2 threads want to write to file... +static mir_cs csFileWritingCS; + +struct CExportedFunctions AccountExportedFcn[] = +{ + { YAMN_GETSTATUSID, (void *)GetStatusFcn }, + { YAMN_SETSTATUSID, (void *)SetStatusFcn }, +}; + +struct CExportedServices AccountExportedSvc[] = +{ + { MS_YAMN_CREATEPLUGINACCOUNT, CreatePluginAccountSvc }, + { MS_YAMN_DELETEPLUGINACCOUNT, DeletePluginAccountSvc }, + { MS_YAMN_FINDACCOUNTBYNAME, FindAccountByNameSvc }, + { MS_YAMN_GETNEXTFREEACCOUNT, GetNextFreeAccountSvc }, + { MS_YAMN_DELETEACCOUNT, DeletePluginAccountSvc }, + { MS_YAMN_READACCOUNTS, AddAccountsFromFileSvc }, + { MS_YAMN_WRITEACCOUNTS, WriteAccountsToFileSvc }, +}; + +//-------------------------------------------------------------------------------------------------- +//-------------------------------------------------------------------------------------------------- + +INT_PTR CreatePluginAccountSvc(WPARAM wParam, LPARAM lParam) +{ + HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; + DWORD AccountVersion = (DWORD)lParam; + + //test if we are going to initialize members of suitable structure (structures of plugin and YAMN must match) + if (AccountVersion != YAMN_ACCOUNTVERSION) + return NULL; + + if (Plugin != nullptr) + { + HACCOUNT NewAccount; + if (Plugin->Fcn->NewAccountFcnPtr != nullptr) + //Let plugin create its own structure, which can be derived from CAccount structure + NewAccount = Plugin->Fcn->NewAccountFcnPtr(Plugin, YAMN_ACCOUNTVERSION); + else + //We suggest plugin uses standard CAccount structure, so we create it + NewAccount = new struct CAccount; + + //If not created successfully + if (NewAccount == nullptr) + return NULL; + + NewAccount->Plugin = Plugin; + //Init every members of structure, used by YAMN + InitAccount(NewAccount); + + return (INT_PTR)NewAccount; + } + return NULL; +} + +INT_PTR DeletePluginAccountSvc(WPARAM wParam, LPARAM) +{ + HACCOUNT OldAccount = (HACCOUNT)wParam; + + if (OldAccount->Plugin->Fcn != nullptr) + { + //Deinit every members and allocated fields of structure used by YAMN + DeInitAccount(OldAccount); + if (OldAccount->Plugin->Fcn->DeleteAccountFcnPtr != nullptr) + { + //Let plugin delete its own CAccount derived structure + OldAccount->Plugin->Fcn->DeleteAccountFcnPtr(OldAccount); + } + else + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeletePluginAccountSvc:delete OldAccount\n"); +#endif + delete OldAccount; //consider account as standard YAMN HACCOUNT and use its own destructor + } + return 1; + } + delete OldAccount; //consider account as standard YAMN HACCOUNT, not initialized before and use its own destructor + return 1; +} + +int InitAccount(HACCOUNT Which) +{ + //initialize synchronizing objects + Which->AccountAccessSO = new SWMRG; + SWMRGInitialize(Which->AccountAccessSO, nullptr); + Which->MessagesAccessSO = new SWMRG; + SWMRGInitialize(Which->MessagesAccessSO, nullptr); + Which->UsingThreads = new SCOUNTER; + SWMRGInitialize(Which->MessagesAccessSO, nullptr); + + //zero memory, where timestamps are stored + memset(&Which->LastChecked, 0, sizeof(Which->LastChecked)); + memset(&Which->LastSChecked, 0, sizeof(Which->LastSChecked)); + memset(&Which->LastSynchronised, 0, sizeof(Which->LastSynchronised)); + memset(&Which->LastMail, 0, sizeof(Which->LastMail)); + + Which->Name = nullptr; + Which->Mails = nullptr; + Which->Interval = 0; + Which->Flags = 0; + Which->StatusFlags = 0; + Which->Next = nullptr; + + Which->Server = new struct CServer; + Which->AbleToWork = TRUE; + + return 1; +} + +void DeInitAccount(HACCOUNT Which) +{ + //delete YAMN allocated fields + if (Which->Name != nullptr) + delete[] Which->Name; + if (Which->Server != nullptr) { + if (Which->Server->Name != nullptr) + delete[] Which->Server->Name; + if (Which->Server->Login != nullptr) + delete[] Which->Server->Login; + if (Which->Server->Passwd != nullptr) + delete[] Which->Server->Passwd; + delete[] Which->Server; + } + + SWMRGDelete(Which->AccountAccessSO); + delete Which->AccountAccessSO; + SWMRGDelete(Which->MessagesAccessSO); + delete Which->MessagesAccessSO; + delete Which->UsingThreads; + DeleteMessagesToEndFcn(Which, (HYAMNMAIL)Which->Mails); +} + +void StopSignalFcn(HACCOUNT Which) +//set event that we are going to delete account +{ +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"\tStopSignalFcn:stop account: %x\n",Which); +#endif + Which->AbleToWork = FALSE; + //do not use synchronizing objects anymore + //any access to these objects then ends with WAIT_FAILED + SetEvent(Which->AccountAccessSO->hFinishEV); + SetEvent(Which->MessagesAccessSO->hFinishEV); +} + +void CodeDecodeString(char *Dest, BOOL Encrypt) +{ + wchar_t Code = STARTCODEPSW; + + if (Dest == nullptr) + return; + + for (; *Dest != (wchar_t)0; Dest++) + { + if (Encrypt) + *Dest = *Dest + Code; + else + *Dest = *Dest - Code; + Code += (wchar_t)ADDCODEPSW; + } +} + +static DWORD PostFileToMemory(HANDLE File, char **MemFile, char **End) +{ + DWORD FileSize, ReadBytes; + if (!(FileSize = GetFileSize(File, nullptr))) { + CloseHandle(File); + return EACC_FILESIZE; + } + + //allocate space in memory, where we copy the whole file + if (nullptr == (*MemFile = new char[FileSize])) + { + CloseHandle(File); + return EACC_ALLOC; + } + + //copy file to memory + if (!ReadFile(File, (LPVOID)*MemFile, FileSize, &ReadBytes, nullptr)) + { + CloseHandle(File); + delete[] * MemFile; + return EACC_SYSTEM; + } + CloseHandle(File); + *End = *MemFile + FileSize; + return 0; +} + +DWORD FileToMemory(wchar_t *FileName, char **MemFile, char **End) +{ + HANDLE hFile = CreateFile(FileName, GENERIC_READ, FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile == INVALID_HANDLE_VALUE) + return EACC_SYSTEM; + + return PostFileToMemory(hFile, MemFile, End); +} + +#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES) +DWORD ReadStringFromMemory(char **Parser,wchar_t *End,char **StoreTo,wchar_t *DebugString) +{ + //This is the debug version of ReadStringFromMemory function. This version shows MessageBox where + //read string is displayed + wchar_t *Dest,*Finder; + DWORD Size; + wchar_t Debug[65536]; + + Finder=*Parser; + while((*Finder != (wchar_t)0) && (Finder<=End)) Finder++; + mir_snwprintf(Debug, L"%s: %s,length is %d, remaining %d chars", DebugString, *Parser, Finder-*Parser, End-Finder); + MessageBox(NULL,Debug,L"debug",MB_OK); + if (Finder>=End) + return EACC_FILECOMPATIBILITY; + if (Size=Finder-*Parser) + { + if (NULL==(Dest=*StoreTo=new wchar_t[Size+1])) + return EACC_ALLOC; + for (;*Parser<=Finder;(*Parser)++,Dest++) + *Dest=**Parser; + } + else + { + *StoreTo=NULL; + (*Parser)++; + } + return 0; +} +#endif + +DWORD ReadStringFromMemory(char **Parser, char *End, char **StoreTo) +{ + char *Dest, *Finder; + DWORD Size; + + Finder = *Parser; + while ((*Finder != (wchar_t)0) && (Finder <= End)) Finder++; + if (Finder >= End) + return EACC_FILECOMPATIBILITY; + if (Size = Finder - *Parser) + { + if (nullptr == (Dest = *StoreTo = new char[Size + 1])) + return EACC_ALLOC; + for (; *Parser <= Finder; (*Parser)++, Dest++) + *Dest = **Parser; + } + else + { + *StoreTo = nullptr; + (*Parser)++; + } + return 0; +} + +#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES) +DWORD ReadStringFromMemoryW(WCHAR **Parser,wchar_t *End,WCHAR **StoreTo,WCHAR *DebugString) +{ + //This is the debug version of ReadStringFromMemoryW function. This version shows MessageBox where + //read string is displayed + WCHAR *Dest,*Finder; + DWORD Size; + WCHAR Debug[65536]; + + Finder=*Parser; + while((*Finder != (WCHAR)0) && (Finder<=(WCHAR *)End)) Finder++; + mir_snwprintf(Debug, L"%s: %s,length is %d, remaining %d chars", DebugString, *Parser, Finder-*Parser, (WCHAR *)End-Finder); + MessageBoxW(NULL,Debug,L"debug",MB_OK); + if (Finder>=(WCHAR *)End) + return EACC_FILECOMPATIBILITY; + if (Size=Finder-*Parser) + { + if (NULL==(Dest=*StoreTo=new WCHAR[Size+1])) + return EACC_ALLOC; + for (;*Parser<=Finder;(*Parser)++,Dest++) + *Dest=**Parser; + } + else + { + *StoreTo=NULL; + (*Parser)++; + } + return 0; +} +#endif //if defined(DEBUG...) + +DWORD ReadStringFromMemoryW(WCHAR **Parser, WCHAR *End, WCHAR **StoreTo) +{ + WCHAR *Dest, *Finder; + DWORD Size; + + Finder = *Parser; + while ((*Finder != (WCHAR)0) && (Finder <= (WCHAR *)End)) Finder++; + if (Finder >= (WCHAR *)End) + return EACC_FILECOMPATIBILITY; + if (Size = Finder - *Parser) + { + if (nullptr == (Dest = *StoreTo = new WCHAR[Size + 1])) + return EACC_ALLOC; + for (; *Parser <= Finder; (*Parser)++, Dest++) + *Dest = **Parser; + } + else + { + *StoreTo = nullptr; + (*Parser)++; + } + return 0; +} + +static DWORD ReadNotificationFromMemory(char **Parser, char *End, YAMN_NOTIFICATION *Which) +{ + DWORD Stat; +#ifdef DEBUG_FILEREAD + wchar_t Debug[65536]; +#endif + + Which->Flags = *(DWORD *)(*Parser); + (*Parser) += sizeof(DWORD); + if (*Parser >= End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + mir_snwprintf(Debug, L"NFlags: %04x, remaining %d chars", Which->Flags, End-*Parser); + MessageBox(NULL,Debug,L"debug",MB_OK); +#endif + + Which->PopupB = *(COLORREF *)(*Parser); + (*Parser) += sizeof(COLORREF); + if (*Parser >= End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + mir_snwprintf(Debug, L"PopupB: %04x, remaining %d chars", Which->PopupB, End-*Parser); + MessageBox(NULL,Debug,L"debug",MB_OK); +#endif + Which->PopupT = *(COLORREF *)(*Parser); + (*Parser) += sizeof(COLORREF); + if (*Parser >= End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + mir_snwprintf(Debug, L"PopupT: %04x, remaining %d chars", Which->PopupT, End-*Parser); + MessageBox(NULL,Debug,L"debug",MB_OK); +#endif + Which->PopupTime = *(DWORD *)(*Parser); + (*Parser) += sizeof(DWORD); + if (*Parser >= End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + mir_snwprintf(Debug, L"PopupTime: %04x, remaining %d chars", Which->PopupTime, End-*Parser); + MessageBox(NULL,Debug,L"debug",MB_OK); +#endif + +#ifdef DEBUG_FILEREAD + if (Stat=ReadStringFromMemoryW((WCHAR **)Parser,(WCHAR*)End,&Which->App,L"App")) +#else + if (Stat = ReadStringFromMemoryW((WCHAR **)Parser, (WCHAR*)End, &Which->App)) +#endif + return Stat; +#ifdef DEBUG_FILEREAD + if (Stat=ReadStringFromMemoryW((WCHAR **)Parser,(WCHAR*)End,&Which->AppParam,L"AppParam")) +#else + if (Stat = ReadStringFromMemoryW((WCHAR **)Parser, (WCHAR*)End, &Which->AppParam)) +#endif + return Stat; + return 0; +} + +DWORD ReadMessagesFromMemory(HACCOUNT Which, char **Parser, char *End) +{ + char *Finder; + DWORD Size, Stat; + HYAMNMAIL ActualMail = nullptr; + struct CMimeItem *items; + char *ReadString; + +#ifdef DEBUG_FILEREAD + MessageBox(NULL,L"going to read messages, if any...",L"debug",MB_OK); +#endif + do + { + Finder = *Parser; + while ((*Finder != (wchar_t)0) && (Finder <= End)) Finder++; + if (Finder >= End) + return EACC_FILECOMPATIBILITY; + if (Size = Finder - *Parser) + { + if (Which->Mails == nullptr) //First message in queue + { + if (nullptr == (Which->Mails = ActualMail = CreateAccountMail(Which))) + return EACC_ALLOC; + } + else + { + if (nullptr == (ActualMail->Next = CreateAccountMail(Which))) { + return EACC_ALLOC; + } + ActualMail = ActualMail->Next; + } + items = nullptr; +#ifdef DEBUG_FILEREADMESSAGES + if (Stat=ReadStringFromMemory(Parser,End,&ActualMail->ID,L"ID")) +#else + if (Stat = ReadStringFromMemory(Parser, End, &ActualMail->ID)) +#endif + return Stat; + // ActualMail->MailData=new MAILDATA; !!! mem leake !!! this is alloc by CreateAccountMail, no need for doubble alloc !!!! + + ActualMail->MailData->Size = *(DWORD *)(*Parser); + (*Parser) += sizeof(DWORD); + if (*Parser >= End) + return EACC_FILECOMPATIBILITY; + ActualMail->Flags = *(DWORD *)(*Parser); + (*Parser) += sizeof(DWORD); + if (*Parser >= End) + return EACC_FILECOMPATIBILITY; + ActualMail->Number = *(DWORD *)(*Parser); + (*Parser) += sizeof(DWORD); + if (*Parser >= End) + return EACC_FILECOMPATIBILITY; + + if ((nullptr != Which->Plugin->MailFcn) && (nullptr != Which->Plugin->MailFcn->ReadMailOptsFcnPtr)) + Which->Plugin->MailFcn->ReadMailOptsFcnPtr(ActualMail, Parser, End); //read plugin mail settings from file + + do + { +#if defined(DEBUG_FILEREADMESSAGES) || defined(DEBUG_FILEREAD) + if (Stat=ReadStringFromMemory(Parser,End,&ReadString,L"Name")) +#else + if (Stat = ReadStringFromMemory(Parser, End, &ReadString)) +#endif + return Stat; + if (ReadString == nullptr) + break; + +#ifdef DEBUG_DECODE + DebugLog(DecodeFile,"<read name>%s</read name>",ReadString); +#endif + + if (items == nullptr) + items = ActualMail->MailData->TranslatedHeader = new struct CMimeItem; + else + { + items->Next = new struct CMimeItem; + items = items->Next; + } + if (items == nullptr) + return EACC_ALLOC; + items->name = ReadString; + +#ifdef DEBUG_FILEREADMESSAGES + if (Stat=ReadStringFromMemory(Parser,End,&ReadString,L"Value")) +#else + if (Stat = ReadStringFromMemory(Parser, End, &ReadString)) +#endif + return Stat; + items->value = ReadString; +#ifdef DEBUG_DECODE + DebugLog(DecodeFile,"<read value>%s</read value>\n",ReadString); +#endif + } while (1); + } + else + break; //no next messages, new account! + + } while (1); + (*Parser)++; + return 0; +} + +DWORD ReadAccountFromMemory(HACCOUNT Which, char **Parser, char *End) +{ + DWORD Stat; +#ifdef DEBUG_FILEREAD + wchar_t Debug[65536]; +#endif + //Read name of account + +#ifdef DEBUG_FILEREAD + if (Stat=ReadStringFromMemory(Parser,End,&Which->Name,L"Name")) +#else + if (Stat = ReadStringFromMemory(Parser, End, &Which->Name)) +#endif + return Stat; + if (Which->Name == nullptr) + return EACC_FILECOMPATIBILITY; + + //Read server parameters +#ifdef DEBUG_FILEREAD + if (Stat=ReadStringFromMemory(Parser,End,&Which->Server->Name,L"Server")) +#else + if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Name)) +#endif + return Stat; + Which->Server->Port = *(WORD *)(*Parser); + (*Parser) += sizeof(WORD); + if (*Parser >= End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + mir_snwprintf(Debug, L"Port: %d, remaining %d chars", Which->Server->Port, End-*Parser); + MessageBox(NULL,Debug,L"debug",MB_OK); +#endif +#ifdef DEBUG_FILEREAD + if (Stat=ReadStringFromMemory(Parser,End,&Which->Server->Login,L"Login")) +#else + if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Login)) +#endif + return Stat; +#ifdef DEBUG_FILEREAD + if (Stat=ReadStringFromMemory(Parser,End,&Which->Server->Passwd,L"Password")) +#else + if (Stat = ReadStringFromMemory(Parser, End, &Which->Server->Passwd)) +#endif + return Stat; + CodeDecodeString(Which->Server->Passwd, FALSE); + + //Read account flags + Which->Flags = *(DWORD *)(*Parser); + (*Parser) += sizeof(DWORD); + if (*Parser >= End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + mir_snwprintf(Debug, L"Flags: %04x, remaining %d chars", Which->Flags, End-*Parser); + MessageBox(NULL,Debug,L"debug",MB_OK); +#endif + Which->StatusFlags = *(DWORD *)(*Parser); + (*Parser) += sizeof(DWORD); +#ifdef DEBUG_FILEREAD + mir_snwprintf(Debug, L"STFlags: %04x, remaining %d chars", Which->StatusFlags, End-*Parser); + MessageBox(NULL,Debug,L"debug",MB_OK); +#endif + Which->PluginFlags = *(DWORD *)(*Parser); + (*Parser) += sizeof(DWORD); +#ifdef DEBUG_FILEREAD + mir_snwprintf(Debug, L"PFlags: %04x, remaining %d chars", Which->PluginFlags, End-*Parser); + MessageBox(NULL,Debug,L"debug",MB_OK); +#endif + + //Read account miscellaneous parameters + Which->Interval = *(WORD *)(*Parser); + Which->TimeLeft = Which->Interval; //check on loading + (*Parser) += sizeof(WORD); + if (*Parser >= End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + mir_snwprintf(Debug, L"Interval: %d, remaining %d chars", Which->Interval, End-*Parser); + MessageBox(NULL,Debug,L"debug",MB_OK); +#endif + + //Read notification parameters + if (Stat = ReadNotificationFromMemory(Parser, End, &Which->NewMailN)) + return Stat; + if (Stat = ReadNotificationFromMemory(Parser, End, &Which->NoNewMailN)) + return Stat; + if (Stat = ReadNotificationFromMemory(Parser, End, &Which->BadConnectN)) + return Stat; + + //Let plugin read its own data stored in file + if (Which->Plugin->Fcn != nullptr && Which->Plugin->Fcn->ReadPluginOptsFcnPtr != nullptr) + if (Stat = Which->Plugin->Fcn->ReadPluginOptsFcnPtr(Which, Parser, End)) + return Stat; + //Read mails +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"ReadAccountFromMemory:ActualAccountMsgsSO-write wait\n"); +#endif + WaitToWriteFcn(Which->MessagesAccessSO); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"ReadAccountFromMemory:ActualAccountMsgsSO-write enter\n"); +#endif + if (Stat = ReadMessagesFromMemory(Which, Parser, End)) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"ReadAccountFromMemory:ActualAccountMsgsSO-write done\n"); +#endif + WriteDoneFcn(Which->MessagesAccessSO); + return Stat; + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"ReadAccountFromMemory:ActualAccountMsgsSO-write done\n"); +#endif + WriteDoneFcn(Which->MessagesAccessSO); + + //Read timestamps + Which->LastChecked = *(SYSTEMTIME *)(*Parser); + (*Parser) += sizeof(SYSTEMTIME); + if (*Parser >= End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + mir_snwprintf(Debug, L"LastChecked: %04x, remaining %d chars", Which->LastChecked, End-*Parser); + MessageBox(NULL,Debug,L"debug",MB_OK); +#endif + Which->LastSChecked = *(SYSTEMTIME *)(*Parser); + (*Parser) += sizeof(SYSTEMTIME); + if (*Parser >= End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + mir_snwprintf(Debug, L"LastSChecked: %04x, remaining %d chars", Which->LastSChecked, End-*Parser); + MessageBox(NULL,Debug,L"debug",MB_OK); +#endif + Which->LastSynchronised = *(SYSTEMTIME *)(*Parser); + (*Parser) += sizeof(SYSTEMTIME); + if (*Parser >= End) + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + mir_snwprintf(Debug, L"LastSynchronised: %04x, remaining %d chars", Which->LastSynchronised, End-*Parser); + MessageBox(NULL,Debug,L"debug",MB_OK); +#endif + Which->LastMail = *(SYSTEMTIME *)(*Parser); + (*Parser) += sizeof(SYSTEMTIME); + if (*Parser > End) //WARNING! There's only > at the end of testing + return EACC_FILECOMPATIBILITY; +#ifdef DEBUG_FILEREAD + mir_snwprintf(Debug, L"LastMail: %04x, remaining %d chars", Which->LastMail, End-*Parser); + MessageBox(NULL,Debug,L"debug",MB_OK); +#endif + if (*Parser == End) + return EACC_ENDOFFILE; + return 0; + +} + +static INT_PTR PerformAccountReading(HYAMNPROTOPLUGIN Plugin, char *MemFile, char *End) +{ + //Retrieve info for account from memory + char *Parser; + DWORD Ver, Stat; + + HACCOUNT ActualAccount, FirstAllocatedAccount; + + Ver = *(DWORD *)MemFile; + if (Ver > YAMN_ACCOUNTFILEVERSION) + { + delete[] MemFile; + return EACC_FILEVERSION; + } + Parser = MemFile + sizeof(Ver); + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write wait\n"); +#endif + SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write enter\n"); +#endif + if (nullptr == (ActualAccount = (HACCOUNT)CallService(MS_YAMN_GETNEXTFREEACCOUNT, (WPARAM)Plugin, (LPARAM)YAMN_ACCOUNTVERSION))) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + delete[] MemFile; + return EACC_ALLOC; + } + FirstAllocatedAccount = ActualAccount; + + do + { + HACCOUNT Temp; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:ActualAccountSO-write wait\n"); +#endif + WaitToWriteFcn(ActualAccount->AccountAccessSO); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:ActualAccountSO-write enter\n"); +#endif + Stat = ReadAccountFromMemory(ActualAccount, &Parser, End); + + if (ActualAccount->StatusFlags & (YAMN_ACC_STARTA | YAMN_ACC_STARTS)) + ActualAccount->TimeLeft = 1; //check on loading + + if (Stat && (Stat != EACC_ENDOFFILE)) + { + for (ActualAccount = FirstAllocatedAccount; ActualAccount != nullptr; ActualAccount = Temp) + { + Temp = ActualAccount->Next; + delete ActualAccount; + } + delete[] MemFile; + if (Plugin->FirstAccount == FirstAllocatedAccount) + Plugin->FirstAccount = nullptr; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:ActualAccountSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + return (INT_PTR)Stat; + } + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:ActualAccountSO-write done\n"); +#endif + WriteDoneFcn(ActualAccount->AccountAccessSO); + + if ((Stat != EACC_ENDOFFILE) && (nullptr == (ActualAccount = (HACCOUNT)CallService(MS_YAMN_GETNEXTFREEACCOUNT, (WPARAM)Plugin, (LPARAM)YAMN_ACCOUNTVERSION)))) + { + for (ActualAccount = FirstAllocatedAccount; ActualAccount != nullptr; ActualAccount = Temp) + { + Temp = ActualAccount->Next; + delete ActualAccount; + } + delete[] MemFile; + if (Plugin->FirstAccount == FirstAllocatedAccount) + Plugin->FirstAccount = nullptr; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + return EACC_ALLOC; + } + } while (Stat != EACC_ENDOFFILE); + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"AddAccountsFromFile:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + delete[] MemFile; + + return 0; +} + +// Add accounts from file to memory +INT_PTR AddAccountsFromFileSvc(WPARAM wParam, LPARAM lParam) +{ + char *MemFile, *End; + DWORD Stat = FileToMemory((wchar_t*)lParam, &MemFile, &End); + if (Stat != NO_ERROR) + return (INT_PTR)Stat; + + return PerformAccountReading((HYAMNPROTOPLUGIN)wParam, MemFile, End); +} + +DWORD WriteStringToFile(HANDLE File, char *Source) +{ + DWORD Length, WrittenBytes; + char null = 0; + + if ((Source == nullptr) || !(Length = (DWORD)mir_strlen(Source))) { + if (!WriteFile(File, &null, 1, &WrittenBytes, nullptr)) { + CloseHandle(File); + return EACC_SYSTEM; + } + } + else if (!WriteFile(File, Source, (Length + 1), &WrittenBytes, nullptr)) { + CloseHandle(File); + return EACC_SYSTEM; + } + return 0; +} + +DWORD WriteStringToFileW(HANDLE File, WCHAR *Source) +{ + DWORD Length, WrittenBytes; + WCHAR null = (WCHAR)0; + + if ((Source == nullptr) || !(Length = (DWORD)mir_wstrlen(Source))) + { + if (!WriteFile(File, &null, sizeof(WCHAR), &WrittenBytes, nullptr)) + { + CloseHandle(File); + return EACC_SYSTEM; + } + } + else if (!WriteFile(File, Source, (Length + 1)*sizeof(WCHAR), &WrittenBytes, nullptr)) + return EACC_SYSTEM; + return 0; +} + +DWORD WriteMessagesToFile(HANDLE File, HACCOUNT Which) +{ + DWORD WrittenBytes, Stat; + HYAMNMAIL ActualMail = (HYAMNMAIL)Which->Mails; + struct CMimeItem *items; + + while (ActualMail != nullptr) + { + if (Stat = WriteStringToFile(File, ActualMail->ID)) + return Stat; + if (!WriteFile(File, (char *)&ActualMail->MailData->Size, sizeof(ActualMail->MailData->Size), &WrittenBytes, nullptr) || + !WriteFile(File, (char *)&ActualMail->Flags, sizeof(ActualMail->Flags), &WrittenBytes, nullptr) || + !WriteFile(File, (char *)&ActualMail->Number, sizeof(ActualMail->Number), &WrittenBytes, nullptr)) + return EACC_SYSTEM; + if ((nullptr != Which->Plugin->MailFcn) && (nullptr != Which->Plugin->MailFcn->WriteMailOptsFcnPtr)) + Which->Plugin->MailFcn->WriteMailOptsFcnPtr(File, ActualMail); //write plugin mail options to file + for (items = ActualMail->MailData->TranslatedHeader; items != nullptr; items = items->Next) + { + if (Stat = WriteStringToFile(File, items->name)) + return Stat; + if (Stat = WriteStringToFile(File, items->value)) + return Stat; + } + if (Stat = WriteStringToFile(File, "")) + return Stat; + ActualMail = ActualMail->Next; + } + if (Stat = WriteStringToFile(File, "")) + return Stat; + return 0; +} + +static INT_PTR PerformAccountWriting(HYAMNPROTOPLUGIN Plugin, HANDLE File) +{ + DWORD WrittenBytes, Stat; + HACCOUNT ActualAccount; + DWORD Ver = YAMN_ACCOUNTFILEVERSION; + BOOL Writed = FALSE; + DWORD ReturnValue = 0, EnterCode; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:AccountBrowserSO-read wait\n"); +#endif + SWMRGWaitToRead(Plugin->AccountBrowserSO, INFINITE); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:AccountBrowserSO-read enter\n"); +#endif + try + { + for (ActualAccount = Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = ActualAccount->Next) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountSO-read wait\n"); +#endif + EnterCode = WaitToReadFcn(ActualAccount->AccountAccessSO); + if (EnterCode == WAIT_FINISH) //account is about to delete + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountSO-read wait failed\n"); +#endif + ActualAccount = ActualAccount->Next; + continue; + } + if (EnterCode == WAIT_FAILED) //account is deleted + break; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountSO-read enter\n"); +#endif + if ((ActualAccount->Name == nullptr) || (*ActualAccount->Name == (wchar_t)0)) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountSO-read done\n"); +#endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + continue; + } + + if (!Writed && !WriteFile(File, &Ver, sizeof(Ver), &WrittenBytes, nullptr)) + throw (DWORD)EACC_SYSTEM; + Writed = TRUE; + + if (Stat = WriteStringToFile(File, ActualAccount->Name)) + throw (DWORD)Stat; + + if (Stat = WriteStringToFile(File, ActualAccount->Server->Name)) + throw (DWORD)Stat; + + if (!WriteFile(File, (char *)&ActualAccount->Server->Port, 2, &WrittenBytes, nullptr)) + throw (DWORD)EACC_SYSTEM; + + if ((Stat = WriteStringToFile(File, ActualAccount->Server->Login))) + throw (DWORD)Stat; + + CodeDecodeString(ActualAccount->Server->Passwd, TRUE); + + if (Stat = WriteStringToFile(File, ActualAccount->Server->Passwd)) + { + CodeDecodeString(ActualAccount->Server->Passwd, FALSE); + throw (DWORD)Stat; + } + CodeDecodeString(ActualAccount->Server->Passwd, FALSE); + + if ((!WriteFile(File, (char *)&ActualAccount->Flags, sizeof(DWORD), &WrittenBytes, nullptr) || + (!WriteFile(File, (char *)&ActualAccount->StatusFlags, sizeof(DWORD), &WrittenBytes, nullptr)) || + (!WriteFile(File, (char *)&ActualAccount->PluginFlags, sizeof(DWORD), &WrittenBytes, nullptr)))) + throw (DWORD)EACC_SYSTEM; + + if (!WriteFile(File, (char *)&ActualAccount->Interval, sizeof(WORD), &WrittenBytes, nullptr)) + throw (DWORD)EACC_SYSTEM; + + if ((!WriteFile(File, (char *)&ActualAccount->NewMailN.Flags, sizeof(DWORD), &WrittenBytes, nullptr)) || + (!WriteFile(File, (char *)&ActualAccount->NewMailN.PopupB, sizeof(COLORREF), &WrittenBytes, nullptr)) || + (!WriteFile(File, (char *)&ActualAccount->NewMailN.PopupT, sizeof(COLORREF), &WrittenBytes, nullptr)) || + (!WriteFile(File, (char *)&ActualAccount->NewMailN.PopupTime, sizeof(DWORD), &WrittenBytes, nullptr))) + throw (DWORD)EACC_SYSTEM; + + if ((Stat = WriteStringToFileW(File, ActualAccount->NewMailN.App)) || + (Stat = WriteStringToFileW(File, ActualAccount->NewMailN.AppParam))) + throw (DWORD)Stat; + + if ((!WriteFile(File, (char *)&ActualAccount->NoNewMailN.Flags, sizeof(DWORD), &WrittenBytes, nullptr)) || + (!WriteFile(File, (char *)&ActualAccount->NoNewMailN.PopupB, sizeof(COLORREF), &WrittenBytes, nullptr)) || + (!WriteFile(File, (char *)&ActualAccount->NoNewMailN.PopupT, sizeof(COLORREF), &WrittenBytes, nullptr)) || + (!WriteFile(File, (char *)&ActualAccount->NoNewMailN.PopupTime, sizeof(DWORD), &WrittenBytes, nullptr))) + throw (DWORD)EACC_SYSTEM; + + if ((Stat = WriteStringToFileW(File, ActualAccount->NoNewMailN.App)) || + (Stat = WriteStringToFileW(File, ActualAccount->NoNewMailN.AppParam))) + throw (DWORD)Stat; + + if ((!WriteFile(File, (char *)&ActualAccount->BadConnectN.Flags, sizeof(DWORD), &WrittenBytes, nullptr)) || + (!WriteFile(File, (char *)&ActualAccount->BadConnectN.PopupB, sizeof(COLORREF), &WrittenBytes, nullptr)) || + (!WriteFile(File, (char *)&ActualAccount->BadConnectN.PopupT, sizeof(COLORREF), &WrittenBytes, nullptr)) || + (!WriteFile(File, (char *)&ActualAccount->BadConnectN.PopupTime, sizeof(DWORD), &WrittenBytes, nullptr))) + throw (DWORD)EACC_SYSTEM; + + if ((Stat = WriteStringToFileW(File, ActualAccount->BadConnectN.App)) || + (Stat = WriteStringToFileW(File, ActualAccount->BadConnectN.AppParam))) + throw (DWORD)Stat; + + //Let plugin write its own values into file + if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->WritePluginOptsFcnPtr != nullptr) + if (Stat = ActualAccount->Plugin->Fcn->WritePluginOptsFcnPtr(File, ActualAccount)) + throw (DWORD)Stat; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountMsgsSO-read wait\n"); +#endif + WaitToReadFcn(ActualAccount->MessagesAccessSO); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountMsgsSO-read enter\n"); +#endif + if (Stat = WriteMessagesToFile(File, ActualAccount)) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountMsgsSO-read done\n"); +#endif + ReadDoneFcn(ActualAccount->MessagesAccessSO); + throw (DWORD)Stat; + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountMsgsSO-read done\n"); +#endif + ReadDoneFcn(ActualAccount->MessagesAccessSO); + + if ((!WriteFile(File, (char *)&ActualAccount->LastChecked, sizeof(SYSTEMTIME), &WrittenBytes, nullptr)) || + (!WriteFile(File, (char *)&ActualAccount->LastSChecked, sizeof(SYSTEMTIME), &WrittenBytes, nullptr)) || + (!WriteFile(File, (char *)&ActualAccount->LastSynchronised, sizeof(SYSTEMTIME), &WrittenBytes, nullptr)) || + (!WriteFile(File, (char *)&ActualAccount->LastMail, sizeof(SYSTEMTIME), &WrittenBytes, nullptr))) + throw (DWORD)Stat; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountSO-read done\n"); +#endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + } + } + catch (DWORD ErrorCode) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:ActualAccountSO-read done\n"); +#endif + ReadDoneFcn(ActualAccount->AccountAccessSO); + ReturnValue = ErrorCode; + } +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WriteAccountsToFile:AccountBrowserSO-read done\n"); +#endif + SWMRGDoneReading(Plugin->AccountBrowserSO); + CloseHandle(File); + return 0; +} + +// Writes accounts to file +INT_PTR WriteAccountsToFileSvc(WPARAM wParam, LPARAM lParam) +{ + HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; + + mir_cslock lck(csFileWritingCS); + HANDLE hFile = CreateFile((wchar_t*)lParam, GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr); + if (hFile == INVALID_HANDLE_VALUE) + return EACC_SYSTEM; + + return PerformAccountWriting(Plugin, hFile); +} + +INT_PTR FindAccountByNameSvc(WPARAM wParam, LPARAM lParam) +{ + HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; + char *SearchedAccount = (char *)lParam; + HACCOUNT Finder; + +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"FindAccountByName:AccountBrowserSO-read wait\n"); +#endif + SWMRGWaitToRead(Plugin->AccountBrowserSO, INFINITE); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"FindAccountByName:AccountBrowserSO-read enter\n"); +#endif + for (Finder = Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) + if ((Finder->Name != nullptr) && (0 == mir_strcmp(SearchedAccount, Finder->Name))) + break; +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"FindAccountByName:AccountBrowserSO-read done\n"); +#endif + SWMRGDoneReading(Plugin->AccountBrowserSO); + return (INT_PTR)Finder; +} + +INT_PTR GetNextFreeAccountSvc(WPARAM wParam, LPARAM lParam) +{ + HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; + HACCOUNT Finder; + + if (Plugin->FirstAccount == nullptr) + { + Plugin->FirstAccount = (HACCOUNT)CallService(MS_YAMN_CREATEPLUGINACCOUNT, wParam, lParam); + return (INT_PTR)Plugin->FirstAccount; + } + for (Finder = Plugin->FirstAccount; Finder->Next != nullptr; Finder = Finder->Next); + Finder->Next = (HACCOUNT)CallService(MS_YAMN_CREATEPLUGINACCOUNT, wParam, lParam); + return (INT_PTR)Finder->Next; +} + +/* +int FindPluginAccount(WPARAM wParam,LPARAM lParam) +{ +HYAMNPROTOPLUGIN Plugin=(HYAMNPROTOPLUGIN)wParam; +HACCOUNT Finder=(HACCOUNT)lParam; + +if (Finder=NULL) Finder=Plugin->FirstAccount; + +// for (;Finder != NULL && Finder->PluginID != Plugin->PluginInfo->PluginID;Finder=(HACCOUNT)Finder->Next); +return (int)Finder; +} +*/ +INT_PTR DeleteAccountSvc(WPARAM wParam, LPARAM lParam) +{ + //Deleting account works on these steps: + //1. set signal that account should stop activity (set event) + // setting this event we achieve, that any access to account is failed, + // so threads do not start any work with accounts (better saying threads of plugins should not start) + //2. wait to get write access to chained list of accounts + //3. we can write to chained list, so we change chain not to show to actual account + // now, any thread browsing list of accounts does not browse through actual account + // actual account seems to be hidden (it exists, but it is not in accounts chained list (chained list=queue)) + //Now, we should delete account from memory, BUT!!! + // Any thread can still be waked up and start asking account synchronizing object + // If account is deleted, asking about access to read account can throw memory exception (reading for + // a synchronizing object from memory, that was deleted) + //So, we cannot now delete account. We have to wait until we are sure no thread will be using account anymore + // (or to the end of Miranda, but problem is in allocated memory- it is allocated and Miranda is SMALLER, faster, easier, isn't it?) + // This deleting is achieved in 2 ways: + // We have event in UsingThreads synchronization objects. This event signals that no thread will use actual account + // 1. Any thread using account first increment UsingThread, so we know that account is used + // 2. If thread is about to close, it should decrement UsingThread + // 3. If thread creates another thread, that will use account, caller has to wait until the new thread does not + // increment UsingThreads (imagine that caller ends before the new thread set it: if no other thread is using + // account, account is automaticaly (decreasing UsingThreads) signaled as "not used" and we delete it. But then + // new thread is going to read account...). + //4. wait until UsingThread Event is signaled + //5. delete account from memory + + HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; + HACCOUNT Which = (HACCOUNT)lParam; + HACCOUNT Finder; + + //1. set stop signal + StopSignalFcn(Which); + WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_STOPACCOUNT, (WPARAM)Which, 0); + if (Plugin->Fcn->StopAccountFcnPtr != nullptr) + Plugin->Fcn->StopAccountFcnPtr(Which); + + //2. wait to get write access +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write wait\n"); +#endif + SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write enter\n"); +#endif + + //3. remove from queue (chained list) + if (Plugin->FirstAccount == nullptr) + { +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + return 0; + } + if (Plugin->FirstAccount == Which) + { + Finder = Plugin->FirstAccount->Next; + Plugin->FirstAccount = Finder; + } + else + { + for (Finder = Plugin->FirstAccount; Which != Finder->Next; Finder = Finder->Next); + Finder->Next = Finder->Next->Next; + } + //leave write access +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteAccount:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + + //4. wait while event "UsingThread" is not signaled + // And what to do, if this event will be signaled in 1 hour? (Although it's paranoia, because we have sent "delete signal", so + // other threads do not start any new work with actual account) We will wait in blocked state? + // No, of course not. We will create new thread, that will wait and additionally remove our thread in background. + //5. So, the last point (deleting from memory) is performed in new DeleteAccountInBackground thread + + if ((Plugin->Fcn != nullptr) && (Plugin->Fcn->WriteAccountsFcnPtr != nullptr)) + Plugin->Fcn->WriteAccountsFcnPtr(); + CloseHandle(mir_forkthread(DeleteAccountInBackground, (void*)Which)); + + //Now, plugin can consider account as deleted, but plugin really can achieve deleting this account from memory when using + //event UsingThreads. + return 1; +} + +void __cdecl DeleteAccountInBackground(void *Value) +{ + HACCOUNT Which = (HACCOUNT)Value; + WaitForSingleObject(Which->UsingThreads->Event, INFINITE); + CallService(MS_YAMN_DELETEPLUGINACCOUNT, (WPARAM)Which, 0); +} + +int StopAccounts(HYAMNPROTOPLUGIN Plugin) +{ + HACCOUNT Finder; + + //1. wait to get write access +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"StopAccounts:AccountBrowserSO-write wait\n"); +#endif + SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"StopAccounts:AccountBrowserSO-write enter\n"); +#endif + for (Finder = Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) + { + //2. set stop signal + StopSignalFcn(Finder); + WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_STOPACCOUNT, (WPARAM)Finder, 0); + if (Plugin->Fcn->StopAccountFcnPtr != nullptr) + Plugin->Fcn->StopAccountFcnPtr(Finder); + } + + //leave write access +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"StopAccounts:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + + //Now, account is stopped. It can be removed from memory... + return 1; +} + +int WaitForAllAccounts(HYAMNPROTOPLUGIN Plugin, BOOL GetAccountBrowserAccess) +{ + HACCOUNT Finder; + + if (GetAccountBrowserAccess) + { + //1. wait to get write access +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WaitForAllAccounts:AccountBrowserSO-write wait\n"); +#endif + SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WaitForAllAccounts:AccountBrowserSO-write enter\n"); +#endif + } + for (Finder = Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) + { + //2. wait for signal that account is not in use +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WaitForAllAccounts:waiting for UsingThreadEV %x (account %x)\n",Finder->UsingThreads,Finder); +#endif + WaitForSingleObject(Finder->UsingThreads->Event, INFINITE); + SetEvent(Finder->UsingThreads->Event); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WaitForAllAccounts:UsingThreadEV signaled\n"); +#endif + } + if (GetAccountBrowserAccess) + { + //leave write access +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"WaitForAllAccounts:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + } + + return 1; +} + +int DeleteAccounts(HYAMNPROTOPLUGIN Plugin) +{ + HACCOUNT Finder; + + //1. wait to get write access +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteAccounts:AccountBrowserSO-write wait\n"); +#endif + SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteAccounts:AccountBrowserSO-write enter\n"); +#endif + + WaitForAllAccounts(Plugin, FALSE); + + for (Finder = Plugin->FirstAccount; Finder != nullptr;) + { + HACCOUNT Next = Finder->Next; + DeletePluginAccountSvc((WPARAM)Finder, 0); + Finder = Next; + } + + //leave write access +#ifdef DEBUG_SYNCHRO + DebugLog(SynchroFile,"DeleteAccounts:AccountBrowserSO-write done\n"); +#endif + SWMRGDoneWriting(Plugin->AccountBrowserSO); + return 1; +} + +void WINAPI GetStatusFcn(HACCOUNT Which, wchar_t *Value) +{ + if (Which == nullptr) + return; + + mir_cslock lck(csAccountStatusCS); + mir_wstrcpy(Value, Which->Status); +} + +void WINAPI SetStatusFcn(HACCOUNT Which, wchar_t *Value) +{ + if (Which != nullptr) { + mir_cslock lck(csAccountStatusCS); + mir_wstrcpy(Which->Status, Value); + } + + WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_CHANGESTATUS, (WPARAM)Which, 0); +} |