diff options
author | dartraiden <wowemuh@gmail.com> | 2023-01-14 01:30:59 +0300 |
---|---|---|
committer | dartraiden <wowemuh@gmail.com> | 2023-01-14 01:30:59 +0300 |
commit | de40f3be3f08487937525c2ef096dad665dda61d (patch) | |
tree | eb1205f8dca7c30b561a2776f9527072bd92eaf1 /protocols/YAMN/src | |
parent | dd743899a769120ba2321230afddd6e4f1271872 (diff) |
Convert sources to CR+LF
Diffstat (limited to 'protocols/YAMN/src')
22 files changed, 10480 insertions, 10480 deletions
diff --git a/protocols/YAMN/src/account.cpp b/protocols/YAMN/src/account.cpp index 91b57ad544..46b7782ab0 100644 --- a/protocols/YAMN/src/account.cpp +++ b/protocols/YAMN/src/account.cpp @@ -1,1051 +1,1051 @@ -/* - * 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; - uint32_t AccountVersion = (uint32_t)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) { - CAccount *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) -{ - CAccount *OldAccount = (CAccount *)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 { - delete OldAccount; //consider account as standard YAMN CAccount *and use its own destructor - } - return 1; - } - delete OldAccount; //consider account as standard YAMN CAccount *, not initialized before and use its own destructor - return 1; -} - -int InitAccount(CAccount *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 = YAMN_ACC_ST1 + YAMN_ACC_ST7; - Which->Next = nullptr; - - Which->Server = new struct CServer; - Which->AbleToWork = TRUE; - - return 1; -} - -void DeInitAccount(CAccount *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(CAccount *Which) -//set event that we are going to delete account -{ - 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 uint32_t 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; -} - -uint32_t 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) -uint32_t 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; - uint32_t 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 - -uint32_t ReadStringFromMemory(char **Parser, char *End, char **StoreTo) -{ - char *Dest, *Finder; - uint32_t 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) -uint32_t ReadStringFromMemoryW(wchar_t **Parser, wchar_t *End, wchar_t **StoreTo, wchar_t *DebugString) -{ - //This is the debug version of ReadStringFromMemoryW function. This version shows MessageBox where - //read string is displayed - wchar_t *Dest, *Finder; - uint32_t Size; - wchar_t Debug[65536]; - - Finder = *Parser; - while ((*Finder != (wchar_t)0) && (Finder <= (wchar_t *)End)) Finder++; - mir_snwprintf(Debug, L"%s: %s,length is %d, remaining %d chars", DebugString, *Parser, Finder - *Parser, (wchar_t *)End - Finder); - MessageBoxW(NULL, Debug, L"debug", MB_OK); - if (Finder >= (wchar_t *)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 //if defined(DEBUG...) - -uint32_t ReadStringFromMemoryW(wchar_t **Parser, wchar_t *End, wchar_t **StoreTo) -{ - wchar_t *Dest, *Finder; - uint32_t Size; - - Finder = *Parser; - while ((*Finder != (wchar_t)0) && (Finder <= (wchar_t *)End)) Finder++; - if (Finder >= (wchar_t *)End) - return EACC_FILECOMPATIBILITY; - if (Size = Finder - *Parser) { - if (nullptr == (Dest = *StoreTo = new wchar_t[Size + 1])) - return EACC_ALLOC; - for (; *Parser <= Finder; (*Parser)++, Dest++) - *Dest = **Parser; - } - else { - *StoreTo = nullptr; - (*Parser)++; - } - return 0; -} - -static uint32_t ReadNotificationFromMemory(char **Parser, char *End, YAMN_NOTIFICATION *Which) -{ - uint32_t Stat; - #ifdef DEBUG_FILEREAD - wchar_t Debug[65536]; - #endif - - Which->Flags = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - 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 = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - 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_t **)Parser, (wchar_t *)End, &Which->App, L"App")) - #else - if (Stat = ReadStringFromMemoryW((wchar_t **)Parser, (wchar_t *)End, &Which->App)) - #endif - return Stat; - #ifdef DEBUG_FILEREAD - if (Stat = ReadStringFromMemoryW((wchar_t **)Parser, (wchar_t *)End, &Which->AppParam, L"AppParam")) - #else - if (Stat = ReadStringFromMemoryW((wchar_t **)Parser, (wchar_t *)End, &Which->AppParam)) - #endif - return Stat; - return 0; -} - -uint32_t ReadMessagesFromMemory(CAccount *Which, char **Parser, char *End) -{ - char *Finder; - uint32_t 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 = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - ActualMail->Flags = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - ActualMail->Number = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - 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; -} - -uint32_t ReadAccountFromMemory(CAccount *Which, char **Parser, char *End) -{ - uint32_t 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 = *(uint16_t *)(*Parser); - (*Parser) += sizeof(uint16_t); - 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 = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - 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 = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - #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 = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - #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 = *(uint16_t *)(*Parser); - Which->TimeLeft = Which->Interval; //check on loading - (*Parser) += sizeof(uint16_t); - 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 - WaitToWriteFcn(Which->MessagesAccessSO); - - if (Stat = ReadMessagesFromMemory(Which, Parser, End)) { - WriteDoneFcn(Which->MessagesAccessSO); - return Stat; - } - - WriteDoneFcn(Which->MessagesAccessSO); - - // Read timestamps - Which->LastChecked = *(SYSTEMTIME *)(*Parser); - (*Parser) += sizeof(SYSTEMTIME); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - - Which->LastSChecked = *(SYSTEMTIME *)(*Parser); - (*Parser) += sizeof(SYSTEMTIME); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - - Which->LastSynchronised = *(SYSTEMTIME *)(*Parser); - (*Parser) += sizeof(SYSTEMTIME); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - - Which->LastMail = *(SYSTEMTIME *)(*Parser); - (*Parser) += sizeof(SYSTEMTIME); - if (*Parser > End) //WARNING! There's only > at the end of testing - return EACC_FILECOMPATIBILITY; - - 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; - uint32_t Ver, Stat; - - CAccount *ActualAccount, *FirstAllocatedAccount; - - Ver = *(uint32_t *)MemFile; - if (Ver > YAMN_ACCOUNTFILEVERSION) { - delete[] MemFile; - return EACC_FILEVERSION; - } - Parser = MemFile + sizeof(Ver); - - SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); - - if (nullptr == (ActualAccount = (CAccount *)CallService(MS_YAMN_GETNEXTFREEACCOUNT, (WPARAM)Plugin, (LPARAM)YAMN_ACCOUNTVERSION))) { - SWMRGDoneWriting(Plugin->AccountBrowserSO); - delete[] MemFile; - return EACC_ALLOC; - } - - FirstAllocatedAccount = ActualAccount; - - do { - CAccount *Temp; - - WaitToWriteFcn(ActualAccount->AccountAccessSO); - 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; - - SWMRGDoneWriting(Plugin->AccountBrowserSO); - return (INT_PTR)Stat; - } - - WriteDoneFcn(ActualAccount->AccountAccessSO); - - if ((Stat != EACC_ENDOFFILE) && (nullptr == (ActualAccount = (CAccount *)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; - - SWMRGDoneWriting(Plugin->AccountBrowserSO); - return EACC_ALLOC; - } - } while (Stat != EACC_ENDOFFILE); - - SWMRGDoneWriting(Plugin->AccountBrowserSO); - delete[] MemFile; - return 0; -} - -// Add accounts from file to memory -INT_PTR AddAccountsFromFileSvc(WPARAM wParam, LPARAM lParam) -{ - char *MemFile, *End; - uint32_t Stat = FileToMemory((wchar_t *)lParam, &MemFile, &End); - if (Stat != NO_ERROR) - return (INT_PTR)Stat; - - return PerformAccountReading((HYAMNPROTOPLUGIN)wParam, MemFile, End); -} - -uint32_t WriteStringToFile(HANDLE File, char *Source) -{ - DWORD Length, WrittenBytes; - char null = 0; - - if ((Source == nullptr) || !(Length = (uint32_t)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; -} - -uint32_t WriteStringToFileW(HANDLE File, wchar_t *Source) -{ - DWORD Length, WrittenBytes; - wchar_t null = (wchar_t)0; - - if ((Source == nullptr) || !(Length = (uint32_t)mir_wstrlen(Source))) { - if (!WriteFile(File, &null, sizeof(wchar_t), &WrittenBytes, nullptr)) { - CloseHandle(File); - return EACC_SYSTEM; - } - } - else if (!WriteFile(File, Source, (Length + 1) * sizeof(wchar_t), &WrittenBytes, nullptr)) - return EACC_SYSTEM; - return 0; -} - -DWORD WriteMessagesToFile(HANDLE File, CAccount *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; - CAccount *ActualAccount; - uint32_t Ver = YAMN_ACCOUNTFILEVERSION; - BOOL Writed = FALSE; - uint32_t ReturnValue = 0, EnterCode; - - SWMRGWaitToRead(Plugin->AccountBrowserSO, INFINITE); - - try { - for (ActualAccount = Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = ActualAccount->Next) { - EnterCode = WaitToReadFcn(ActualAccount->AccountAccessSO); - if (EnterCode == WAIT_FINISH) //account is about to delete - { - ActualAccount = ActualAccount->Next; - continue; - } - if (EnterCode == WAIT_FAILED) //account is deleted - break; - - if ((ActualAccount->Name == nullptr) || (*ActualAccount->Name == (wchar_t)0)) { - ReadDoneFcn(ActualAccount->AccountAccessSO); - continue; - } - - if (!Writed && !WriteFile(File, &Ver, sizeof(Ver), &WrittenBytes, nullptr)) - throw (uint32_t)EACC_SYSTEM; - - Writed = TRUE; - - if (Stat = WriteStringToFile(File, ActualAccount->Name)) - throw (uint32_t)Stat; - - if (Stat = WriteStringToFile(File, ActualAccount->Server->Name)) - throw (uint32_t)Stat; - - if (!WriteFile(File, (char *)&ActualAccount->Server->Port, 2, &WrittenBytes, nullptr)) - throw (uint32_t)EACC_SYSTEM; - - if ((Stat = WriteStringToFile(File, ActualAccount->Server->Login))) - throw (uint32_t)Stat; - - CodeDecodeString(ActualAccount->Server->Passwd, TRUE); - - if (Stat = WriteStringToFile(File, ActualAccount->Server->Passwd)) { - CodeDecodeString(ActualAccount->Server->Passwd, FALSE); - throw (uint32_t)Stat; - } - CodeDecodeString(ActualAccount->Server->Passwd, FALSE); - - if ((!WriteFile(File, (char *)&ActualAccount->Flags, sizeof(uint32_t), &WrittenBytes, nullptr) || - (!WriteFile(File, (char *)&ActualAccount->StatusFlags, sizeof(uint32_t), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&ActualAccount->PluginFlags, sizeof(uint32_t), &WrittenBytes, nullptr)))) - throw (uint32_t)EACC_SYSTEM; - - if (!WriteFile(File, (char *)&ActualAccount->Interval, sizeof(uint16_t), &WrittenBytes, nullptr)) - throw (uint32_t)EACC_SYSTEM; - - if ((!WriteFile(File, (char *)&ActualAccount->NewMailN.Flags, sizeof(uint32_t), &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(uint32_t), &WrittenBytes, nullptr))) - throw (uint32_t)EACC_SYSTEM; - - if ((Stat = WriteStringToFileW(File, ActualAccount->NewMailN.App)) || - (Stat = WriteStringToFileW(File, ActualAccount->NewMailN.AppParam))) - throw (uint32_t)Stat; - - if ((!WriteFile(File, (char *)&ActualAccount->NoNewMailN.Flags, sizeof(uint32_t), &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(uint32_t), &WrittenBytes, nullptr))) - throw (uint32_t)EACC_SYSTEM; - - if ((Stat = WriteStringToFileW(File, ActualAccount->NoNewMailN.App)) || - (Stat = WriteStringToFileW(File, ActualAccount->NoNewMailN.AppParam))) - throw (uint32_t)Stat; - - if ((!WriteFile(File, (char *)&ActualAccount->BadConnectN.Flags, sizeof(uint32_t), &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(uint32_t), &WrittenBytes, nullptr))) - throw (uint32_t)EACC_SYSTEM; - - if ((Stat = WriteStringToFileW(File, ActualAccount->BadConnectN.App)) || - (Stat = WriteStringToFileW(File, ActualAccount->BadConnectN.AppParam))) - throw (uint32_t)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 (uint32_t)Stat; - - WaitToReadFcn(ActualAccount->MessagesAccessSO); - - if (Stat = WriteMessagesToFile(File, ActualAccount)) { - - ReadDoneFcn(ActualAccount->MessagesAccessSO); - throw (uint32_t)Stat; - } - - 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 (uint32_t)Stat; - - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - } - catch (uint32_t ErrorCode) { - ReadDoneFcn(ActualAccount->AccountAccessSO); - ReturnValue = ErrorCode; - } - - 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; - CAccount *Finder; - - SWMRGWaitToRead(Plugin->AccountBrowserSO, INFINITE); - - for (Finder = Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) - if ((Finder->Name != nullptr) && (0 == mir_strcmp(SearchedAccount, Finder->Name))) - break; - - SWMRGDoneReading(Plugin->AccountBrowserSO); - return (INT_PTR)Finder; -} - -INT_PTR GetNextFreeAccountSvc(WPARAM wParam, LPARAM lParam) -{ - HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; - CAccount *Finder; - - if (Plugin->FirstAccount == nullptr) { - Plugin->FirstAccount = (CAccount *)CallService(MS_YAMN_CREATEPLUGINACCOUNT, wParam, lParam); - return (INT_PTR)Plugin->FirstAccount; - } - for (Finder = Plugin->FirstAccount; Finder->Next != nullptr; Finder = Finder->Next); - Finder->Next = (CAccount *)CallService(MS_YAMN_CREATEPLUGINACCOUNT, wParam, lParam); - return (INT_PTR)Finder->Next; -} - -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; - CAccount *Which = (CAccount *)lParam; - CAccount *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 - SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); - - //3. remove from queue (chained list) - if (Plugin->FirstAccount == nullptr) { - 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 - 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) -{ - CAccount *Which = (CAccount *)Value; - WaitForSingleObject(Which->UsingThreads->Event, INFINITE); - CallService(MS_YAMN_DELETEPLUGINACCOUNT, (WPARAM)Which, 0); -} - -int StopAccounts(HYAMNPROTOPLUGIN Plugin) -{ - CAccount *Finder; - - //1. wait to get write access - SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); - - 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 - SWMRGDoneWriting(Plugin->AccountBrowserSO); - - //Now, account is stopped. It can be removed from memory... - return 1; -} - -int WaitForAllAccounts(HYAMNPROTOPLUGIN Plugin, BOOL GetAccountBrowserAccess) -{ - if (GetAccountBrowserAccess) { - //1. wait to get write access - SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); - } - for (CAccount *Finder = Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) { - //2. wait for signal that account is not in use - WaitForSingleObject(Finder->UsingThreads->Event, INFINITE); - SetEvent(Finder->UsingThreads->Event); - } - if (GetAccountBrowserAccess) { - //leave write access - SWMRGDoneWriting(Plugin->AccountBrowserSO); - } - - return 1; -} - -int DeleteAccounts(HYAMNPROTOPLUGIN Plugin) -{ - //1. wait to get write access - SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE); - - WaitForAllAccounts(Plugin, FALSE); - - for (CAccount *Finder = Plugin->FirstAccount; Finder != nullptr;) { - CAccount *Next = Finder->Next; - DeletePluginAccountSvc((WPARAM)Finder, 0); - Finder = Next; - } - - //leave write access - SWMRGDoneWriting(Plugin->AccountBrowserSO); - return 1; -} - -void WINAPI GetStatusFcn(CAccount *Which, wchar_t *Value) -{ - if (Which == nullptr) - return; - - mir_cslock lck(csAccountStatusCS); - mir_wstrcpy(Value, Which->Status); -} - -void WINAPI SetStatusFcn(CAccount *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); -} +/*
+ * 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;
+ uint32_t AccountVersion = (uint32_t)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) {
+ CAccount *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)
+{
+ CAccount *OldAccount = (CAccount *)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 {
+ delete OldAccount; //consider account as standard YAMN CAccount *and use its own destructor
+ }
+ return 1;
+ }
+ delete OldAccount; //consider account as standard YAMN CAccount *, not initialized before and use its own destructor
+ return 1;
+}
+
+int InitAccount(CAccount *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 = YAMN_ACC_ST1 + YAMN_ACC_ST7;
+ Which->Next = nullptr;
+
+ Which->Server = new struct CServer;
+ Which->AbleToWork = TRUE;
+
+ return 1;
+}
+
+void DeInitAccount(CAccount *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(CAccount *Which)
+//set event that we are going to delete account
+{
+ 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 uint32_t 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;
+}
+
+uint32_t 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)
+uint32_t 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;
+ uint32_t 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
+
+uint32_t ReadStringFromMemory(char **Parser, char *End, char **StoreTo)
+{
+ char *Dest, *Finder;
+ uint32_t 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)
+uint32_t ReadStringFromMemoryW(wchar_t **Parser, wchar_t *End, wchar_t **StoreTo, wchar_t *DebugString)
+{
+ //This is the debug version of ReadStringFromMemoryW function. This version shows MessageBox where
+ //read string is displayed
+ wchar_t *Dest, *Finder;
+ uint32_t Size;
+ wchar_t Debug[65536];
+
+ Finder = *Parser;
+ while ((*Finder != (wchar_t)0) && (Finder <= (wchar_t *)End)) Finder++;
+ mir_snwprintf(Debug, L"%s: %s,length is %d, remaining %d chars", DebugString, *Parser, Finder - *Parser, (wchar_t *)End - Finder);
+ MessageBoxW(NULL, Debug, L"debug", MB_OK);
+ if (Finder >= (wchar_t *)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 //if defined(DEBUG...)
+
+uint32_t ReadStringFromMemoryW(wchar_t **Parser, wchar_t *End, wchar_t **StoreTo)
+{
+ wchar_t *Dest, *Finder;
+ uint32_t Size;
+
+ Finder = *Parser;
+ while ((*Finder != (wchar_t)0) && (Finder <= (wchar_t *)End)) Finder++;
+ if (Finder >= (wchar_t *)End)
+ return EACC_FILECOMPATIBILITY;
+ if (Size = Finder - *Parser) {
+ if (nullptr == (Dest = *StoreTo = new wchar_t[Size + 1]))
+ return EACC_ALLOC;
+ for (; *Parser <= Finder; (*Parser)++, Dest++)
+ *Dest = **Parser;
+ }
+ else {
+ *StoreTo = nullptr;
+ (*Parser)++;
+ }
+ return 0;
+}
+
+static uint32_t ReadNotificationFromMemory(char **Parser, char *End, YAMN_NOTIFICATION *Which)
+{
+ uint32_t Stat;
+ #ifdef DEBUG_FILEREAD
+ wchar_t Debug[65536];
+ #endif
+
+ Which->Flags = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ 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 = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ 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_t **)Parser, (wchar_t *)End, &Which->App, L"App"))
+ #else
+ if (Stat = ReadStringFromMemoryW((wchar_t **)Parser, (wchar_t *)End, &Which->App))
+ #endif
+ return Stat;
+ #ifdef DEBUG_FILEREAD
+ if (Stat = ReadStringFromMemoryW((wchar_t **)Parser, (wchar_t *)End, &Which->AppParam, L"AppParam"))
+ #else
+ if (Stat = ReadStringFromMemoryW((wchar_t **)Parser, (wchar_t *)End, &Which->AppParam))
+ #endif
+ return Stat;
+ return 0;
+}
+
+uint32_t ReadMessagesFromMemory(CAccount *Which, char **Parser, char *End)
+{
+ char *Finder;
+ uint32_t 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 = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ ActualMail->Flags = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ ActualMail->Number = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ 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;
+}
+
+uint32_t ReadAccountFromMemory(CAccount *Which, char **Parser, char *End)
+{
+ uint32_t 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 = *(uint16_t *)(*Parser);
+ (*Parser) += sizeof(uint16_t);
+ 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 = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ 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 = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ #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 = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ #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 = *(uint16_t *)(*Parser);
+ Which->TimeLeft = Which->Interval; //check on loading
+ (*Parser) += sizeof(uint16_t);
+ 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
+ WaitToWriteFcn(Which->MessagesAccessSO);
+
+ if (Stat = ReadMessagesFromMemory(Which, Parser, End)) {
+ WriteDoneFcn(Which->MessagesAccessSO);
+ return Stat;
+ }
+
+ WriteDoneFcn(Which->MessagesAccessSO);
+
+ // Read timestamps
+ Which->LastChecked = *(SYSTEMTIME *)(*Parser);
+ (*Parser) += sizeof(SYSTEMTIME);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+
+ Which->LastSChecked = *(SYSTEMTIME *)(*Parser);
+ (*Parser) += sizeof(SYSTEMTIME);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+
+ Which->LastSynchronised = *(SYSTEMTIME *)(*Parser);
+ (*Parser) += sizeof(SYSTEMTIME);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+
+ Which->LastMail = *(SYSTEMTIME *)(*Parser);
+ (*Parser) += sizeof(SYSTEMTIME);
+ if (*Parser > End) //WARNING! There's only > at the end of testing
+ return EACC_FILECOMPATIBILITY;
+
+ 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;
+ uint32_t Ver, Stat;
+
+ CAccount *ActualAccount, *FirstAllocatedAccount;
+
+ Ver = *(uint32_t *)MemFile;
+ if (Ver > YAMN_ACCOUNTFILEVERSION) {
+ delete[] MemFile;
+ return EACC_FILEVERSION;
+ }
+ Parser = MemFile + sizeof(Ver);
+
+ SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE);
+
+ if (nullptr == (ActualAccount = (CAccount *)CallService(MS_YAMN_GETNEXTFREEACCOUNT, (WPARAM)Plugin, (LPARAM)YAMN_ACCOUNTVERSION))) {
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+ delete[] MemFile;
+ return EACC_ALLOC;
+ }
+
+ FirstAllocatedAccount = ActualAccount;
+
+ do {
+ CAccount *Temp;
+
+ WaitToWriteFcn(ActualAccount->AccountAccessSO);
+ 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;
+
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+ return (INT_PTR)Stat;
+ }
+
+ WriteDoneFcn(ActualAccount->AccountAccessSO);
+
+ if ((Stat != EACC_ENDOFFILE) && (nullptr == (ActualAccount = (CAccount *)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;
+
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+ return EACC_ALLOC;
+ }
+ } while (Stat != EACC_ENDOFFILE);
+
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+ delete[] MemFile;
+ return 0;
+}
+
+// Add accounts from file to memory
+INT_PTR AddAccountsFromFileSvc(WPARAM wParam, LPARAM lParam)
+{
+ char *MemFile, *End;
+ uint32_t Stat = FileToMemory((wchar_t *)lParam, &MemFile, &End);
+ if (Stat != NO_ERROR)
+ return (INT_PTR)Stat;
+
+ return PerformAccountReading((HYAMNPROTOPLUGIN)wParam, MemFile, End);
+}
+
+uint32_t WriteStringToFile(HANDLE File, char *Source)
+{
+ DWORD Length, WrittenBytes;
+ char null = 0;
+
+ if ((Source == nullptr) || !(Length = (uint32_t)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;
+}
+
+uint32_t WriteStringToFileW(HANDLE File, wchar_t *Source)
+{
+ DWORD Length, WrittenBytes;
+ wchar_t null = (wchar_t)0;
+
+ if ((Source == nullptr) || !(Length = (uint32_t)mir_wstrlen(Source))) {
+ if (!WriteFile(File, &null, sizeof(wchar_t), &WrittenBytes, nullptr)) {
+ CloseHandle(File);
+ return EACC_SYSTEM;
+ }
+ }
+ else if (!WriteFile(File, Source, (Length + 1) * sizeof(wchar_t), &WrittenBytes, nullptr))
+ return EACC_SYSTEM;
+ return 0;
+}
+
+DWORD WriteMessagesToFile(HANDLE File, CAccount *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;
+ CAccount *ActualAccount;
+ uint32_t Ver = YAMN_ACCOUNTFILEVERSION;
+ BOOL Writed = FALSE;
+ uint32_t ReturnValue = 0, EnterCode;
+
+ SWMRGWaitToRead(Plugin->AccountBrowserSO, INFINITE);
+
+ try {
+ for (ActualAccount = Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = ActualAccount->Next) {
+ EnterCode = WaitToReadFcn(ActualAccount->AccountAccessSO);
+ if (EnterCode == WAIT_FINISH) //account is about to delete
+ {
+ ActualAccount = ActualAccount->Next;
+ continue;
+ }
+ if (EnterCode == WAIT_FAILED) //account is deleted
+ break;
+
+ if ((ActualAccount->Name == nullptr) || (*ActualAccount->Name == (wchar_t)0)) {
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ continue;
+ }
+
+ if (!Writed && !WriteFile(File, &Ver, sizeof(Ver), &WrittenBytes, nullptr))
+ throw (uint32_t)EACC_SYSTEM;
+
+ Writed = TRUE;
+
+ if (Stat = WriteStringToFile(File, ActualAccount->Name))
+ throw (uint32_t)Stat;
+
+ if (Stat = WriteStringToFile(File, ActualAccount->Server->Name))
+ throw (uint32_t)Stat;
+
+ if (!WriteFile(File, (char *)&ActualAccount->Server->Port, 2, &WrittenBytes, nullptr))
+ throw (uint32_t)EACC_SYSTEM;
+
+ if ((Stat = WriteStringToFile(File, ActualAccount->Server->Login)))
+ throw (uint32_t)Stat;
+
+ CodeDecodeString(ActualAccount->Server->Passwd, TRUE);
+
+ if (Stat = WriteStringToFile(File, ActualAccount->Server->Passwd)) {
+ CodeDecodeString(ActualAccount->Server->Passwd, FALSE);
+ throw (uint32_t)Stat;
+ }
+ CodeDecodeString(ActualAccount->Server->Passwd, FALSE);
+
+ if ((!WriteFile(File, (char *)&ActualAccount->Flags, sizeof(uint32_t), &WrittenBytes, nullptr) ||
+ (!WriteFile(File, (char *)&ActualAccount->StatusFlags, sizeof(uint32_t), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&ActualAccount->PluginFlags, sizeof(uint32_t), &WrittenBytes, nullptr))))
+ throw (uint32_t)EACC_SYSTEM;
+
+ if (!WriteFile(File, (char *)&ActualAccount->Interval, sizeof(uint16_t), &WrittenBytes, nullptr))
+ throw (uint32_t)EACC_SYSTEM;
+
+ if ((!WriteFile(File, (char *)&ActualAccount->NewMailN.Flags, sizeof(uint32_t), &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(uint32_t), &WrittenBytes, nullptr)))
+ throw (uint32_t)EACC_SYSTEM;
+
+ if ((Stat = WriteStringToFileW(File, ActualAccount->NewMailN.App)) ||
+ (Stat = WriteStringToFileW(File, ActualAccount->NewMailN.AppParam)))
+ throw (uint32_t)Stat;
+
+ if ((!WriteFile(File, (char *)&ActualAccount->NoNewMailN.Flags, sizeof(uint32_t), &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(uint32_t), &WrittenBytes, nullptr)))
+ throw (uint32_t)EACC_SYSTEM;
+
+ if ((Stat = WriteStringToFileW(File, ActualAccount->NoNewMailN.App)) ||
+ (Stat = WriteStringToFileW(File, ActualAccount->NoNewMailN.AppParam)))
+ throw (uint32_t)Stat;
+
+ if ((!WriteFile(File, (char *)&ActualAccount->BadConnectN.Flags, sizeof(uint32_t), &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(uint32_t), &WrittenBytes, nullptr)))
+ throw (uint32_t)EACC_SYSTEM;
+
+ if ((Stat = WriteStringToFileW(File, ActualAccount->BadConnectN.App)) ||
+ (Stat = WriteStringToFileW(File, ActualAccount->BadConnectN.AppParam)))
+ throw (uint32_t)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 (uint32_t)Stat;
+
+ WaitToReadFcn(ActualAccount->MessagesAccessSO);
+
+ if (Stat = WriteMessagesToFile(File, ActualAccount)) {
+
+ ReadDoneFcn(ActualAccount->MessagesAccessSO);
+ throw (uint32_t)Stat;
+ }
+
+ 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 (uint32_t)Stat;
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ }
+ catch (uint32_t ErrorCode) {
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ ReturnValue = ErrorCode;
+ }
+
+ 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;
+ CAccount *Finder;
+
+ SWMRGWaitToRead(Plugin->AccountBrowserSO, INFINITE);
+
+ for (Finder = Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next)
+ if ((Finder->Name != nullptr) && (0 == mir_strcmp(SearchedAccount, Finder->Name)))
+ break;
+
+ SWMRGDoneReading(Plugin->AccountBrowserSO);
+ return (INT_PTR)Finder;
+}
+
+INT_PTR GetNextFreeAccountSvc(WPARAM wParam, LPARAM lParam)
+{
+ HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam;
+ CAccount *Finder;
+
+ if (Plugin->FirstAccount == nullptr) {
+ Plugin->FirstAccount = (CAccount *)CallService(MS_YAMN_CREATEPLUGINACCOUNT, wParam, lParam);
+ return (INT_PTR)Plugin->FirstAccount;
+ }
+ for (Finder = Plugin->FirstAccount; Finder->Next != nullptr; Finder = Finder->Next);
+ Finder->Next = (CAccount *)CallService(MS_YAMN_CREATEPLUGINACCOUNT, wParam, lParam);
+ return (INT_PTR)Finder->Next;
+}
+
+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;
+ CAccount *Which = (CAccount *)lParam;
+ CAccount *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
+ SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE);
+
+ //3. remove from queue (chained list)
+ if (Plugin->FirstAccount == nullptr) {
+ 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
+ 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)
+{
+ CAccount *Which = (CAccount *)Value;
+ WaitForSingleObject(Which->UsingThreads->Event, INFINITE);
+ CallService(MS_YAMN_DELETEPLUGINACCOUNT, (WPARAM)Which, 0);
+}
+
+int StopAccounts(HYAMNPROTOPLUGIN Plugin)
+{
+ CAccount *Finder;
+
+ //1. wait to get write access
+ SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE);
+
+ 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
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+
+ //Now, account is stopped. It can be removed from memory...
+ return 1;
+}
+
+int WaitForAllAccounts(HYAMNPROTOPLUGIN Plugin, BOOL GetAccountBrowserAccess)
+{
+ if (GetAccountBrowserAccess) {
+ //1. wait to get write access
+ SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE);
+ }
+ for (CAccount *Finder = Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) {
+ //2. wait for signal that account is not in use
+ WaitForSingleObject(Finder->UsingThreads->Event, INFINITE);
+ SetEvent(Finder->UsingThreads->Event);
+ }
+ if (GetAccountBrowserAccess) {
+ //leave write access
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+ }
+
+ return 1;
+}
+
+int DeleteAccounts(HYAMNPROTOPLUGIN Plugin)
+{
+ //1. wait to get write access
+ SWMRGWaitToWrite(Plugin->AccountBrowserSO, INFINITE);
+
+ WaitForAllAccounts(Plugin, FALSE);
+
+ for (CAccount *Finder = Plugin->FirstAccount; Finder != nullptr;) {
+ CAccount *Next = Finder->Next;
+ DeletePluginAccountSvc((WPARAM)Finder, 0);
+ Finder = Next;
+ }
+
+ //leave write access
+ SWMRGDoneWriting(Plugin->AccountBrowserSO);
+ return 1;
+}
+
+void WINAPI GetStatusFcn(CAccount *Which, wchar_t *Value)
+{
+ if (Which == nullptr)
+ return;
+
+ mir_cslock lck(csAccountStatusCS);
+ mir_wstrcpy(Value, Which->Status);
+}
+
+void WINAPI SetStatusFcn(CAccount *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);
+}
diff --git a/protocols/YAMN/src/browser/badconnect.cpp b/protocols/YAMN/src/browser/badconnect.cpp index 5f9118eb18..d871fa2eea 100644 --- a/protocols/YAMN/src/browser/badconnect.cpp +++ b/protocols/YAMN/src/browser/badconnect.cpp @@ -1,251 +1,251 @@ -/* - * This code implements window handling (connection error) - * - * (c) majvan 2002,2004 - */ - -#include "../stdafx.h" - -#define BADCONNECTTITLE LPGEN("%s - connection error") -#define BADCONNECTMSG LPGEN("An error occurred. Error code: %d")//is in use? - -//-------------------------------------------------------------------------------------------------- - -LRESULT CALLBACK BadConnectPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_COMMAND: - // if clicked and it's new mail popup window - if ((HIWORD(wParam) == STN_CLICKED) && (PUGetPluginData(hWnd))) { - PROCESS_INFORMATION pi; - STARTUPINFOW si; - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - CAccount *ActualAccount = (CAccount *)PUGetPluginData(hWnd); - - if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { - if (ActualAccount->BadConnectN.App != nullptr) { - wchar_t *Command; - if (ActualAccount->BadConnectN.AppParam != nullptr) - Command = new wchar_t[mir_wstrlen(ActualAccount->BadConnectN.App) + mir_wstrlen(ActualAccount->BadConnectN.AppParam) + 6]; - else - Command = new wchar_t[mir_wstrlen(ActualAccount->BadConnectN.App) + 6]; - - if (Command != nullptr) { - mir_wstrcpy(Command, L"\""); - mir_wstrcat(Command, ActualAccount->BadConnectN.App); - mir_wstrcat(Command, L"\" "); - if (ActualAccount->BadConnectN.AppParam != nullptr) - mir_wstrcat(Command, ActualAccount->BadConnectN.AppParam); - CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi); - delete[] Command; - } - } - - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - - PUDeletePopup(hWnd); - } - break; - - case UM_FREEPLUGINDATA: - //Here we'd free our own data, if we had it. - return FALSE; - - case UM_INITPOPUP: - //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups. - break; - case WM_CONTEXTMENU: - PUDeletePopup(hWnd); - break; - } - return DefWindowProc(hWnd, msg, wParam, lParam); -} - -INT_PTR CALLBACK DlgProcYAMNBadConnection(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_INITDIALOG: - { - BOOL ShowPopup, ShowMsg, ShowIco; - CAccount *ActualAccount; - uint32_t ErrorCode; - char *TitleStrA; - char *Message1A = nullptr; - wchar_t *Message1W = nullptr; - POPUPDATAW BadConnectPopup = {}; - - ActualAccount = ((struct BadConnectionParam *)lParam)->account; - ErrorCode = ((struct BadConnectionParam *)lParam)->errcode; - - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) - return FALSE; - - int size = (int)(mir_strlen(ActualAccount->Name) + mir_strlen(Translate(BADCONNECTTITLE))); - TitleStrA = new char[size]; - mir_snprintf(TitleStrA, size, Translate(BADCONNECTTITLE), ActualAccount->Name); - - ShowPopup = ActualAccount->BadConnectN.Flags & YAMN_ACC_POP; - ShowMsg = ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG; - ShowIco = ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO; - - if (ShowPopup) { - BadConnectPopup.lchIcon = g_plugin.getIcon(IDI_BADCONNECT); - BadConnectPopup.colorBack = ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC ? ActualAccount->BadConnectN.PopupB : GetSysColor(COLOR_BTNFACE); - BadConnectPopup.colorText = ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC ? ActualAccount->BadConnectN.PopupT : GetSysColor(COLOR_WINDOWTEXT); - BadConnectPopup.iSeconds = ActualAccount->BadConnectN.PopupTime; - - BadConnectPopup.PluginWindowProc = BadConnectPopupProc; - BadConnectPopup.PluginData = ActualAccount; - mir_wstrncpy(BadConnectPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(BadConnectPopup.lpwzContactName)); - } - - if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr != nullptr) { - Message1W = ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr(ErrorCode); - SetDlgItemText(hDlg, IDC_STATICMSG, Message1W); - wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE); - if (ShowPopup) - PUAddPopupW(&BadConnectPopup); - } - else if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->GetErrorStringAFcnPtr != nullptr) { - Message1W = ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr(ErrorCode); - SetDlgItemText(hDlg, IDC_STATICMSG, Message1W); - wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE); - if (ShowPopup) - PUAddPopupW(&BadConnectPopup); - } - else { - Message1W = TranslateT("Unknown error"); - SetDlgItemText(hDlg, IDC_STATICMSG, Message1W); - wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE); - if (ShowPopup) - PUAddPopupW(&BadConnectPopup); - } - - if (!ShowMsg && !ShowIco) - DestroyWindow(hDlg); - - ReadDoneFcn(ActualAccount->AccountAccessSO); - - SetWindowTextA(hDlg, TitleStrA); - delete[] TitleStrA; - if (Message1A != nullptr) - delete[] Message1A; - if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr != nullptr && Message1A != nullptr) - ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr(Message1A); - if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr != nullptr && Message1W != nullptr) - ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr(Message1W); - return 0; - } - case WM_DESTROY: - { - NOTIFYICONDATA nid; - - memset(&nid, 0, sizeof(NOTIFYICONDATA)); - nid.cbSize = sizeof(NOTIFYICONDATA); - nid.hWnd = hDlg; - nid.uID = 0; - Shell_NotifyIcon(NIM_DELETE, &nid); - PostQuitMessage(0); - break; - } - case WM_YAMN_NOTIFYICON: - switch (lParam) { - case WM_LBUTTONDBLCLK: - ShowWindow(hDlg, SW_SHOWNORMAL); - SetForegroundWindow(hDlg); - break; - } - return 0; - case WM_CHAR: - switch ((wchar_t)wParam) { - case 27: - case 13: - DestroyWindow(hDlg); - break; - } - break; - case WM_SYSCOMMAND: - switch (wParam) { - case SC_CLOSE: - DestroyWindow(hDlg); - } - break; - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDC_BTNOK: - DestroyWindow(hDlg); - } - break; - } - return 0; -} - -void __cdecl BadConnection(void *Param) -{ - MSG msg; - HWND hBadConnect; - CAccount *ActualAccount; - - struct BadConnectionParam MyParam = *(struct BadConnectionParam *)Param; - ActualAccount = MyParam.account; - - SCIncFcn(ActualAccount->UsingThreads); - - // we will not use params in stack anymore - SetEvent(MyParam.ThreadRunningEV); - - __try { - hBadConnect = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_DLGBADCONNECT), nullptr, DlgProcYAMNBadConnection, (LPARAM)&MyParam); - Window_SetIcon_IcoLib(hBadConnect, g_plugin.getIconHandle(IDI_BADCONNECT)); - - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) - __leave; - - if (ActualAccount->BadConnectN.Flags & YAMN_ACC_SND) - Skin_PlaySound(YAMN_CONNECTFAILSOUND); - - if (ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG) - ShowWindow(hBadConnect, SW_SHOWNORMAL); - - if (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) { - NOTIFYICONDATA nid = {}; - nid.cbSize = sizeof(nid); - nid.hWnd = hBadConnect; - nid.hIcon = g_plugin.getIcon(IDI_BADCONNECT); - nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; - nid.uCallbackMessage = WM_YAMN_NOTIFYICON; - mir_snwprintf(nid.szTip, L"%S%s", ActualAccount->Name, TranslateT(" - connection error")); - Shell_NotifyIcon(NIM_ADD, &nid); - } - - ReadDoneFcn(ActualAccount->AccountAccessSO); - - UpdateWindow(hBadConnect); - while (GetMessage(&msg, nullptr, 0, 0)) { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - - // now, write to file. Why? Because we want to write when was new mail last checked - if ((ActualAccount->Plugin->Fcn != nullptr) && (ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr != nullptr) && ActualAccount->AbleToWork) - ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr(); - } - __finally { - SCDecFcn(ActualAccount->UsingThreads); - } -} - -int RunBadConnection(CAccount *acc, UINT_PTR iErrorCode, void *pUserInfo) -{ - BadConnectionParam param = {CreateEvent(nullptr, FALSE, FALSE, nullptr), acc, iErrorCode, pUserInfo}; - - HANDLE NewThread = mir_forkthread(BadConnection, ¶m); - if (nullptr == NewThread) - return 0; - - WaitForSingleObject(param.ThreadRunningEV, INFINITE); - CloseHandle(param.ThreadRunningEV); - return 1; -} +/*
+ * This code implements window handling (connection error)
+ *
+ * (c) majvan 2002,2004
+ */
+
+#include "../stdafx.h"
+
+#define BADCONNECTTITLE LPGEN("%s - connection error")
+#define BADCONNECTMSG LPGEN("An error occurred. Error code: %d")//is in use?
+
+//--------------------------------------------------------------------------------------------------
+
+LRESULT CALLBACK BadConnectPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_COMMAND:
+ // if clicked and it's new mail popup window
+ if ((HIWORD(wParam) == STN_CLICKED) && (PUGetPluginData(hWnd))) {
+ PROCESS_INFORMATION pi;
+ STARTUPINFOW si;
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+ CAccount *ActualAccount = (CAccount *)PUGetPluginData(hWnd);
+
+ if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ if (ActualAccount->BadConnectN.App != nullptr) {
+ wchar_t *Command;
+ if (ActualAccount->BadConnectN.AppParam != nullptr)
+ Command = new wchar_t[mir_wstrlen(ActualAccount->BadConnectN.App) + mir_wstrlen(ActualAccount->BadConnectN.AppParam) + 6];
+ else
+ Command = new wchar_t[mir_wstrlen(ActualAccount->BadConnectN.App) + 6];
+
+ if (Command != nullptr) {
+ mir_wstrcpy(Command, L"\"");
+ mir_wstrcat(Command, ActualAccount->BadConnectN.App);
+ mir_wstrcat(Command, L"\" ");
+ if (ActualAccount->BadConnectN.AppParam != nullptr)
+ mir_wstrcat(Command, ActualAccount->BadConnectN.AppParam);
+ CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi);
+ delete[] Command;
+ }
+ }
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+
+ PUDeletePopup(hWnd);
+ }
+ break;
+
+ case UM_FREEPLUGINDATA:
+ //Here we'd free our own data, if we had it.
+ return FALSE;
+
+ case UM_INITPOPUP:
+ //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups.
+ break;
+ case WM_CONTEXTMENU:
+ PUDeletePopup(hWnd);
+ break;
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+INT_PTR CALLBACK DlgProcYAMNBadConnection(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ BOOL ShowPopup, ShowMsg, ShowIco;
+ CAccount *ActualAccount;
+ uint32_t ErrorCode;
+ char *TitleStrA;
+ char *Message1A = nullptr;
+ wchar_t *Message1W = nullptr;
+ POPUPDATAW BadConnectPopup = {};
+
+ ActualAccount = ((struct BadConnectionParam *)lParam)->account;
+ ErrorCode = ((struct BadConnectionParam *)lParam)->errcode;
+
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO))
+ return FALSE;
+
+ int size = (int)(mir_strlen(ActualAccount->Name) + mir_strlen(Translate(BADCONNECTTITLE)));
+ TitleStrA = new char[size];
+ mir_snprintf(TitleStrA, size, Translate(BADCONNECTTITLE), ActualAccount->Name);
+
+ ShowPopup = ActualAccount->BadConnectN.Flags & YAMN_ACC_POP;
+ ShowMsg = ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG;
+ ShowIco = ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO;
+
+ if (ShowPopup) {
+ BadConnectPopup.lchIcon = g_plugin.getIcon(IDI_BADCONNECT);
+ BadConnectPopup.colorBack = ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC ? ActualAccount->BadConnectN.PopupB : GetSysColor(COLOR_BTNFACE);
+ BadConnectPopup.colorText = ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC ? ActualAccount->BadConnectN.PopupT : GetSysColor(COLOR_WINDOWTEXT);
+ BadConnectPopup.iSeconds = ActualAccount->BadConnectN.PopupTime;
+
+ BadConnectPopup.PluginWindowProc = BadConnectPopupProc;
+ BadConnectPopup.PluginData = ActualAccount;
+ mir_wstrncpy(BadConnectPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(BadConnectPopup.lpwzContactName));
+ }
+
+ if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr != nullptr) {
+ Message1W = ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr(ErrorCode);
+ SetDlgItemText(hDlg, IDC_STATICMSG, Message1W);
+ wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE);
+ if (ShowPopup)
+ PUAddPopupW(&BadConnectPopup);
+ }
+ else if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->GetErrorStringAFcnPtr != nullptr) {
+ Message1W = ActualAccount->Plugin->Fcn->GetErrorStringWFcnPtr(ErrorCode);
+ SetDlgItemText(hDlg, IDC_STATICMSG, Message1W);
+ wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE);
+ if (ShowPopup)
+ PUAddPopupW(&BadConnectPopup);
+ }
+ else {
+ Message1W = TranslateT("Unknown error");
+ SetDlgItemText(hDlg, IDC_STATICMSG, Message1W);
+ wcsncpy_s(BadConnectPopup.lpwzText, Message1W, _TRUNCATE);
+ if (ShowPopup)
+ PUAddPopupW(&BadConnectPopup);
+ }
+
+ if (!ShowMsg && !ShowIco)
+ DestroyWindow(hDlg);
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ SetWindowTextA(hDlg, TitleStrA);
+ delete[] TitleStrA;
+ if (Message1A != nullptr)
+ delete[] Message1A;
+ if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr != nullptr && Message1A != nullptr)
+ ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr(Message1A);
+ if (ActualAccount->Plugin->Fcn != nullptr && ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr != nullptr && Message1W != nullptr)
+ ActualAccount->Plugin->Fcn->DeleteErrorStringFcnPtr(Message1W);
+ return 0;
+ }
+ case WM_DESTROY:
+ {
+ NOTIFYICONDATA nid;
+
+ memset(&nid, 0, sizeof(NOTIFYICONDATA));
+ nid.cbSize = sizeof(NOTIFYICONDATA);
+ nid.hWnd = hDlg;
+ nid.uID = 0;
+ Shell_NotifyIcon(NIM_DELETE, &nid);
+ PostQuitMessage(0);
+ break;
+ }
+ case WM_YAMN_NOTIFYICON:
+ switch (lParam) {
+ case WM_LBUTTONDBLCLK:
+ ShowWindow(hDlg, SW_SHOWNORMAL);
+ SetForegroundWindow(hDlg);
+ break;
+ }
+ return 0;
+ case WM_CHAR:
+ switch ((wchar_t)wParam) {
+ case 27:
+ case 13:
+ DestroyWindow(hDlg);
+ break;
+ }
+ break;
+ case WM_SYSCOMMAND:
+ switch (wParam) {
+ case SC_CLOSE:
+ DestroyWindow(hDlg);
+ }
+ break;
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDC_BTNOK:
+ DestroyWindow(hDlg);
+ }
+ break;
+ }
+ return 0;
+}
+
+void __cdecl BadConnection(void *Param)
+{
+ MSG msg;
+ HWND hBadConnect;
+ CAccount *ActualAccount;
+
+ struct BadConnectionParam MyParam = *(struct BadConnectionParam *)Param;
+ ActualAccount = MyParam.account;
+
+ SCIncFcn(ActualAccount->UsingThreads);
+
+ // we will not use params in stack anymore
+ SetEvent(MyParam.ThreadRunningEV);
+
+ __try {
+ hBadConnect = CreateDialogParam(g_plugin.getInst(), MAKEINTRESOURCE(IDD_DLGBADCONNECT), nullptr, DlgProcYAMNBadConnection, (LPARAM)&MyParam);
+ Window_SetIcon_IcoLib(hBadConnect, g_plugin.getIconHandle(IDI_BADCONNECT));
+
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO))
+ __leave;
+
+ if (ActualAccount->BadConnectN.Flags & YAMN_ACC_SND)
+ Skin_PlaySound(YAMN_CONNECTFAILSOUND);
+
+ if (ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG)
+ ShowWindow(hBadConnect, SW_SHOWNORMAL);
+
+ if (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) {
+ NOTIFYICONDATA nid = {};
+ nid.cbSize = sizeof(nid);
+ nid.hWnd = hBadConnect;
+ nid.hIcon = g_plugin.getIcon(IDI_BADCONNECT);
+ nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
+ nid.uCallbackMessage = WM_YAMN_NOTIFYICON;
+ mir_snwprintf(nid.szTip, L"%S%s", ActualAccount->Name, TranslateT(" - connection error"));
+ Shell_NotifyIcon(NIM_ADD, &nid);
+ }
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ UpdateWindow(hBadConnect);
+ while (GetMessage(&msg, nullptr, 0, 0)) {
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+
+ // now, write to file. Why? Because we want to write when was new mail last checked
+ if ((ActualAccount->Plugin->Fcn != nullptr) && (ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr != nullptr) && ActualAccount->AbleToWork)
+ ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr();
+ }
+ __finally {
+ SCDecFcn(ActualAccount->UsingThreads);
+ }
+}
+
+int RunBadConnection(CAccount *acc, UINT_PTR iErrorCode, void *pUserInfo)
+{
+ BadConnectionParam param = {CreateEvent(nullptr, FALSE, FALSE, nullptr), acc, iErrorCode, pUserInfo};
+
+ HANDLE NewThread = mir_forkthread(BadConnection, ¶m);
+ if (nullptr == NewThread)
+ return 0;
+
+ WaitForSingleObject(param.ThreadRunningEV, INFINITE);
+ CloseHandle(param.ThreadRunningEV);
+ return 1;
+}
diff --git a/protocols/YAMN/src/browser/browser.h b/protocols/YAMN/src/browser/browser.h index 6707d50621..0cb3f1a248 100644 --- a/protocols/YAMN/src/browser/browser.h +++ b/protocols/YAMN/src/browser/browser.h @@ -1,38 +1,38 @@ -#ifndef __MAILBROWSER_H -#define __MAILBROWSER_H - -typedef struct MailBrowserWinParam -{ -#define YAMN_MAILBROWSERVERSION 1 - HANDLE ThreadRunningEV; - CAccount *account; - uint32_t nflags; //flags YAMN_ACC_??? when new mails - uint32_t nnflags; //flags YAMN_ACC_??? when no new mails - void *Param; -} YAMN_MAILBROWSERPARAM,*PYAMN_MAILBROWSERPARAM; - -typedef struct MailShowMsgWinParam -{ - HANDLE ThreadRunningEV; - CAccount *account; - HYAMNMAIL mail; -} YAMN_MAILSHOWPARAM, *PYAMN_MAILSHOWPARAM; - -typedef struct NoNewMailParam -{ -#define YAMN_NONEWMAILVERSION 1 - HANDLE ThreadRunningEV; - CAccount *account; - uint32_t flags; - void *Param; -} YAMN_NONEWMAILPARAM,*PYAMN_NONEWMAILPARAM; - -struct BadConnectionParam -{ - HANDLE ThreadRunningEV; - CAccount *account; - UINT_PTR errcode; - void *Param; -}; - -#endif +#ifndef __MAILBROWSER_H
+#define __MAILBROWSER_H
+
+typedef struct MailBrowserWinParam
+{
+#define YAMN_MAILBROWSERVERSION 1
+ HANDLE ThreadRunningEV;
+ CAccount *account;
+ uint32_t nflags; //flags YAMN_ACC_??? when new mails
+ uint32_t nnflags; //flags YAMN_ACC_??? when no new mails
+ void *Param;
+} YAMN_MAILBROWSERPARAM,*PYAMN_MAILBROWSERPARAM;
+
+typedef struct MailShowMsgWinParam
+{
+ HANDLE ThreadRunningEV;
+ CAccount *account;
+ HYAMNMAIL mail;
+} YAMN_MAILSHOWPARAM, *PYAMN_MAILSHOWPARAM;
+
+typedef struct NoNewMailParam
+{
+#define YAMN_NONEWMAILVERSION 1
+ HANDLE ThreadRunningEV;
+ CAccount *account;
+ uint32_t flags;
+ void *Param;
+} YAMN_NONEWMAILPARAM,*PYAMN_NONEWMAILPARAM;
+
+struct BadConnectionParam
+{
+ HANDLE ThreadRunningEV;
+ CAccount *account;
+ UINT_PTR errcode;
+ void *Param;
+};
+
+#endif
diff --git a/protocols/YAMN/src/browser/mailbrowser.cpp b/protocols/YAMN/src/browser/mailbrowser.cpp index 1d62ad00dc..7b1b68e35a 100644 --- a/protocols/YAMN/src/browser/mailbrowser.cpp +++ b/protocols/YAMN/src/browser/mailbrowser.cpp @@ -1,2247 +1,2247 @@ -/* - * This code implements window handling (new mail) - * - * (c) majvan 2002-2004 - */ - /* There can be problems when compiling this file, because in this file - * we are using both unicode and no-unicode functions and compiler does not - * like it in one file - * When you got errors, try to comment the #define <stdio.h> and compile, then - * put it back to uncommented and compile again :) - */ - -#include "../stdafx.h" - -#define TIMER_FLASHING 0x09061979 -#define MAILBROWSER_MINXSIZE 200 //min size of mail browser window -#define MAILBROWSER_MINYSIZE 130 - -#define MAILBROWSERTITLE LPGEN("%s - %d new mail messages, %d total") - -void __cdecl ShowEmailThread(void *Param); - -//-------------------------------------------------------------------------------------------------- -char *s_MonthNames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; -bool bDate = false, bSub = false, bSize = false, bFrom = false; -int PosX = 0, PosY = 0, SizeX = 460, SizeY = 100; -int HeadSizeX = 0x2b2, HeadSizeY = 0x0b5, HeadPosX = 100, HeadPosY = 100; -int HeadSplitPos = 250; // per-mils of the size -static int FromWidth = 250, SubjectWidth = 280, SizeWidth = 50, SizeDate = 205; -unsigned char optDateTime = (SHOWDATELONG | SHOWDATENOTODAY); - -struct CMailNumbersSub -{ - int Total; //any mail - int New; //uses YAMN_MSG_NEW flag - int UnSeen; //uses YAMN_MSG_UNSEEN flag - // int Browser; //uses YAMN_MSG_BROWSER flag - int BrowserUC; //uses YAMN_MSG_BROWSER flag and YAMN_MSG_UNSEEN flag - int Display; //uses YAMN_MSG_DISPLAY flag - int DisplayTC; //uses YAMN_MSG_DISPLAY flag and YAMN_MSG_DISPLAYC flag - int DisplayUC; //uses YAMN_MSG_DISPLAY flag and YAMN_MSG_DISPLAYC flag and YAMN_MSG_UNSEEN flag - int Popup; //uses YAMN_MSG_POPUP flag - int PopupTC; //uses YAMN_MSG_POPUPC flag - int PopupNC; //uses YAMN_MSG_POPUPC flag and YAMN_MSG_NEW flag - int PopupRun; //uses YAMN_MSG_POPUP flag and YAMN_MSG_NEW flag - int PopupSL2NC; //uses YAMN_MSG_SPAML2 flag and YAMN_MSG_NEW flag - int PopupSL3NC; //uses YAMN_MSG_SPAML3 flag and YAMN_MSG_NEW flag - // int SysTray; //uses YAMN_MSG_SYSTRAY flag - int SysTrayUC; //uses YAMN_MSG_SYSTRAY flag and YAMN_MSG_UNSEEN flag - // int Sound; //uses YAMN_MSG_SOUND flag - int SoundNC; //uses YAMN_MSG_SOUND flag and YAMN_MSG_NEW flag - // int App; //uses YAMN_MSG_APP flag - int AppNC; //uses YAMN_MSG_APP flag and YAMN_MSG_NEW flag - int EventNC; //uses YAMN_MSG_NEVENT flag and YAMN_MSG_NEW flag -}; - -struct CMailNumbers -{ - struct CMailNumbersSub Real; - struct CMailNumbersSub Virtual; -}; - -struct CMailWinUserInfo -{ - CAccount *Account; - int TrayIconState; - BOOL UpdateMailsMessagesAccess; - BOOL Seen; - BOOL RunFirstTime; -}; - -struct CChangeContent -{ - uint32_t nflags; - uint32_t nnflags; -}; - -struct CUpdateMails -{ - struct CChangeContent *Flags; - BOOL Waiting; - HANDLE Copied; -}; - -struct CSortList -{ - HWND hDlg; - int iSubItem; -}; - -// Retrieves CAccount *, whose mails are displayed in ListMails -// hLM- handle of dialog window -// returns handle of account -inline CAccount *GetWindowAccount(HWND hDialog); - -// Looks to mail flags and increment mail counter (e.g. if mail is new, increments the new mail counter -// msgq- mail, which increments the counters -// MN- counnters structure -void IncrementMailCounters(HYAMNMAIL msgq, struct CMailNumbers *MN); - -enum -{ - UPDATE_FAIL = 0, //function failed - UPDATE_NONE, //none update has been performed - UPDATE_OK, //some changes occured, update performed -}; - -// Just looks for mail changes in account and update the mail browser window -// hDlg- dialog handle -// ActualAccount- account handle -// nflags- flags what to do when new mail arrives -// nnflags- flags what to do when no new mail arrives -// returns one of UPDATE_XXX value(not implemented yet) -int UpdateMails(HWND hDlg, CAccount *ActualAccount, uint32_t nflags, uint32_t nnflags); - -// When new mail occurs, shows window, plays sound, runs application... -// hDlg- dialog handle. Dialog of mailbrowser is already created and actions are performed over this window -// ActualAccount- handle of account, whose mails are to be notified -// MN- statistics of mails in account -// nflags- what to do or not to do (e.g. to show mailbrowser window or prohibit to show) -// nflags- flags what to do when new mail arrives -// nnflags- flags what to do when no new mail arrives -void DoMailActions(HWND hDlg, CAccount *ActualAccount, struct CMailNumbers *MN, uint32_t nflags, uint32_t nnflags); - -// Looks for items in mailbrowser and if they were deleted, delete them from browser window -// hListView- handle of listview window -// ActualAccount- handle of account, whose mails are show -// MailNumbers- pointer to structure, in which function stores numbers of mails with some property -// returns one of UPDATE_XXX value (not implemented yet) -int ChangeExistingMailStatus(HWND hListView, CAccount *ActualAccount); - -// Adds new mails to ListView and if any new, shows multi popup (every new message is new popup window created by popup plugin) -// hListView- handle of listview window -// ActualAccount- handle of account, whose mails are show -// NewMailPopup- pointer to prepared structure for popup plugin, can be NULL if no popup show -// MailNumbers- pointer to structure, in which function stores numbers of mails with some property -// nflags- flags what to do when new mail arrives -// returns one of UPDATE_XXX value (not implemented yet) -int AddNewMailsToListView(HWND hListView, CAccount *ActualAccount, uint32_t nflags); - -// Window callback procedure for popup window (created by popup plugin) -LRESULT CALLBACK NewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - -// Window callback procedure for popup window (created by popup plugin) -LRESULT CALLBACK NoNewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); - -// Dialog callback procedure for mail browser -INT_PTR CALLBACK DlgProcYAMNMailBrowser(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam); - -// MailBrowser thread function creates window if needed, tray icon and plays sound -void __cdecl MailBrowser(void *Param); - -LRESULT CALLBACK ListViewSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam); - -// Runs mail browser in new thread -INT_PTR RunMailBrowserSvc(WPARAM, LPARAM); - -#define YAMN_BROWSER_SHOWPOPUP 0x01 - -// list view items' order criteria -#define LVORDER_NOORDER -1 -#define LVORDER_STRING 0 -#define LVORDER_NUMERIC 1 -#define LVORDER_DATETIME 2 - -// list view order direction -#define LVORDER_ASCENDING 1 -#define LVORDER_NONE 0 -#define LVORDER_DESCENDING -1 - -// list view sort type -#define LVSORTPRIORITY_NONE -1 - -// List view column info. -typedef struct _SAMPLELISTVIEWCOLUMN -{ - UINT uCXCol; // index - int nSortType; // sorting type (STRING = 0, NUMERIC, DATE, DATETIME) - int nSortOrder; // sorting order (ASCENDING = -1, NONE, DESCENDING) - int nPriority; // sort priority (-1 for none, 0, 1, ..., nColumns - 1 maximum) - wchar_t lpszName[128]; // column name -} SAMPLELISTVIEWCOLUMN; - -// Compare priority -typedef struct _LVCOMPAREINFO -{ - int iIdx; // Index - int iPriority; // Priority -} LVCOMPAREINFO, *LPLVCOMPAREINFO; - -//-------------------------------------------------------------------------------------------------- - -LPARAM readItemLParam(HWND hwnd, uint32_t iItem) -{ - LVITEM item; - item.mask = LVIF_PARAM; - item.iItem = iItem; - item.iSubItem = 0; - SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM)&item); - return item.lParam; -} - -inline CAccount *GetWindowAccount(HWND hDlg) -{ - struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER); - - return (mwui == nullptr) ? nullptr : mwui->Account; -} - -void IncrementMailCounters(HYAMNMAIL msgq, struct CMailNumbers *MN) -{ - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.Total++; - else - MN->Real.Total++; - - if (msgq->Flags & YAMN_MSG_NEW) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.New++; - else - MN->Real.New++; - if (msgq->Flags & YAMN_MSG_UNSEEN) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.UnSeen++; - else - MN->Real.UnSeen++; - if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_BROWSER)) == (YAMN_MSG_UNSEEN | YAMN_MSG_BROWSER)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.BrowserUC++; - else - MN->Real.BrowserUC++; - if (msgq->Flags & YAMN_MSG_DISPLAY) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.Display++; - else - MN->Real.Display++; - if ((msgq->Flags & (YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) == (YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.DisplayTC++; - else - MN->Real.DisplayTC++; - if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) == (YAMN_MSG_UNSEEN | YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.DisplayUC++; - else - MN->Real.DisplayUC++; - if (msgq->Flags & YAMN_MSG_POPUP) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.Popup++; - else - MN->Real.Popup++; - if ((msgq->Flags & YAMN_MSG_POPUPC) == YAMN_MSG_POPUPC) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.PopupTC++; - else - MN->Real.PopupTC++; - if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_POPUPC)) == (YAMN_MSG_NEW | YAMN_MSG_POPUPC)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.PopupNC++; - else - MN->Real.PopupNC++; - if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_POPUP)) == (YAMN_MSG_NEW | YAMN_MSG_POPUP)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.PopupRun++; - else - MN->Real.PopupRun++; - if ((msgq->Flags & YAMN_MSG_NEW) && YAMN_MSG_SPAML(msgq->Flags, YAMN_MSG_SPAML2)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.PopupSL2NC++; - else - MN->Real.PopupSL2NC++; - if ((msgq->Flags & YAMN_MSG_NEW) && YAMN_MSG_SPAML(msgq->Flags, YAMN_MSG_SPAML3)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.PopupSL3NC++; - else - MN->Real.PopupSL3NC++; - /* if (msgq->MailData->Flags & YAMN_MSG_SYSTRAY) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.SysTray++; - else - MN->Real.SysTray++; - */ if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_SYSTRAY)) == (YAMN_MSG_UNSEEN | YAMN_MSG_SYSTRAY)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.SysTrayUC++; - else - MN->Real.SysTrayUC++; - /* if (msgq->MailData->Flags & YAMN_MSG_SOUND) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.Sound++; - else - MN->Real.Sound++; - */ if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_SOUND)) == (YAMN_MSG_NEW | YAMN_MSG_SOUND)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.SoundNC++; - else - MN->Real.SoundNC++; - /* if (msgq->MailData->Flags & YAMN_MSG_APP) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.App++; - else - MN->Real.App++; - */ if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_APP)) == (YAMN_MSG_NEW | YAMN_MSG_APP)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.AppNC++; - else - MN->Real.AppNC++; - if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_NEVENT)) == (YAMN_MSG_NEW | YAMN_MSG_NEVENT)) - if (msgq->Flags & YAMN_MSG_VIRTUAL) - MN->Virtual.EventNC++; - else - MN->Real.EventNC++; -} - -int UpdateMails(HWND hDlg, CAccount *ActualAccount, uint32_t nflags, uint32_t nnflags) -{ - struct CMailNumbers MN; - - BOOL Loaded; - BOOL RunMailBrowser, RunPopups; - - struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER); - //now we ensure read access for account and write access for its mails - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) { - PostMessage(hDlg, WM_DESTROY, 0, 0); - return UPDATE_FAIL; - } - - if (WAIT_OBJECT_0 != WaitToWriteFcn(ActualAccount->MessagesAccessSO)) { - ReadDoneFcn(ActualAccount->AccountAccessSO); - PostMessage(hDlg, WM_DESTROY, 0, 0); - return UPDATE_FAIL; - } - - memset(&MN, 0, sizeof(MN)); - - for (HYAMNMAIL msgq = (HYAMNMAIL)ActualAccount->Mails; msgq != nullptr; msgq = msgq->Next) { - if (!LoadedMailData(msgq)) //check if mail is already in memory - { - Loaded = false; - if (nullptr == LoadMailData(msgq)) //if we could not load mail to memory, consider this mail deleted and do not display it - continue; - } - else - Loaded = true; - - IncrementMailCounters(msgq, &MN); - - if (!Loaded) - UnloadMailData(msgq); //do not keep data for mail in memory - } - - if (mwui != nullptr) - mwui->UpdateMailsMessagesAccess = TRUE; - - //Now we are going to check if extracting data from mail headers are needed. - //If popups will be displayed or mailbrowser window - if ((((mwui != nullptr) && !(mwui->RunFirstTime)) && - ( - ((nnflags & YAMN_ACC_MSGP) && !(MN.Real.BrowserUC + MN.Virtual.BrowserUC)) || - ((nflags & YAMN_ACC_MSGP) && (MN.Real.BrowserUC + MN.Virtual.BrowserUC)) - ) - ) || //if mail window was displayed before and flag YAMN_ACC_MSGP is set - ((nnflags & YAMN_ACC_MSG) && !(MN.Real.BrowserUC + MN.Virtual.BrowserUC)) || //if needed to run mailbrowser when no unseen and no unseen mail found - ((nflags & YAMN_ACC_MSG) && (MN.Real.BrowserUC + MN.Virtual.BrowserUC)) || //if unseen mails found, we sure run mailbrowser - ((nflags & YAMN_ACC_ICO) && (MN.Real.SysTrayUC + MN.Virtual.SysTrayUC)) - ) //if needed to run systray - RunMailBrowser = TRUE; - else - RunMailBrowser = FALSE; - - // if some popups with mails are needed to show - if ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (MN.Real.PopupNC + MN.Virtual.PopupNC)) - RunPopups = TRUE; - else RunPopups = FALSE; - - if (RunMailBrowser) - ChangeExistingMailStatus(GetDlgItem(hDlg, IDC_LISTMAILS), ActualAccount); - if (RunMailBrowser || RunPopups) - AddNewMailsToListView(hDlg == nullptr ? nullptr : GetDlgItem(hDlg, IDC_LISTMAILS), ActualAccount, nflags); - - if (RunMailBrowser) { - size_t len = mir_strlen(ActualAccount->Name) + mir_strlen(Translate(MAILBROWSERTITLE)) + 10; //+10 chars for numbers - char *TitleStrA = new char[len]; - wchar_t *TitleStrW = new wchar_t[len]; - - mir_snprintf(TitleStrA, len, Translate(MAILBROWSERTITLE), ActualAccount->Name, MN.Real.DisplayUC + MN.Virtual.DisplayUC, MN.Real.Display + MN.Virtual.Display); - MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, TitleStrA, -1, TitleStrW, (int)mir_strlen(TitleStrA) + 1); - SetWindowTextW(hDlg, TitleStrW); - delete[] TitleStrA; - delete[] TitleStrW; - } - - DoMailActions(hDlg, ActualAccount, &MN, nflags, nnflags); - - SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_NEW, 0, YAMN_MSG_NEW, YAMN_FLAG_REMOVE); //rempve the new flag - if (!RunMailBrowser) - SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_UNSEEN, YAMN_MSG_STAYUNSEEN, YAMN_MSG_UNSEEN, YAMN_FLAG_REMOVE); //remove the unseen flag when it was not displayed and it has not "stay unseen" flag set - - if (mwui != nullptr) { - mwui->UpdateMailsMessagesAccess = FALSE; - mwui->RunFirstTime = FALSE; - } - - WriteDoneFcn(ActualAccount->MessagesAccessSO); - ReadDoneFcn(ActualAccount->AccountAccessSO); - - if (RunMailBrowser) - UpdateWindow(GetDlgItem(hDlg, IDC_LISTMAILS)); - else if (hDlg != nullptr) - DestroyWindow(hDlg); - - return 1; -} - -int ChangeExistingMailStatus(HWND hListView, CAccount *ActualAccount) -{ - LVITEM item; - HYAMNMAIL mail, msgq; - - int in = ListView_GetItemCount(hListView); - item.mask = LVIF_PARAM; - - for (int i = 0; i < in; i++) { - item.iItem = i; - item.iSubItem = 0; - if (TRUE == ListView_GetItem(hListView, &item)) - mail = (HYAMNMAIL)item.lParam; - else - continue; - for (msgq = (HYAMNMAIL)ActualAccount->Mails; (msgq != nullptr) && (msgq != mail); msgq = msgq->Next); //found the same mail in account queue - if (msgq == nullptr) //if mail was not found - if (TRUE == ListView_DeleteItem(hListView, i)) { - in--; i--; - continue; - } - } - - return TRUE; -} - -void MimeDateToLocalizedDateTime(char *datein, wchar_t *dateout, int lendateout); -int AddNewMailsToListView(HWND hListView, CAccount *ActualAccount, uint32_t nflags) -{ - wchar_t *FromStr; - wchar_t SizeStr[20]; - wchar_t LocalDateStr[128]; - - LVITEMW item; - LVFINDINFO fi; - - int foundi = 0, lfoundi = 0; - struct CHeader UnicodeHeader; - BOOL Loaded, Extracted, FromStrNew = FALSE; - - memset(&item, 0, sizeof(item)); - memset(&UnicodeHeader, 0, sizeof(UnicodeHeader)); - - if (hListView != nullptr) { - item.mask = LVIF_TEXT | LVIF_PARAM; - item.iItem = 0; - memset(&fi, 0, sizeof(fi)); - fi.flags = LVFI_PARAM; //let's go search item by lParam number - lfoundi = 0; - } - - POPUPDATAW NewMailPopup = {}; - NewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount; - NewMailPopup.lchIcon = g_plugin.getIcon(IDI_NEWMAIL); - if (nflags & YAMN_ACC_POPC) { - NewMailPopup.colorBack = ActualAccount->NewMailN.PopupB; - NewMailPopup.colorText = ActualAccount->NewMailN.PopupT; - } - else { - NewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE); - NewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT); - } - NewMailPopup.iSeconds = ActualAccount->NewMailN.PopupTime; - - NewMailPopup.PluginWindowProc = NewMailPopupProc; - NewMailPopup.PluginData = nullptr; //it's new mail popup - - for (HYAMNMAIL msgq = (HYAMNMAIL)ActualAccount->Mails; msgq != nullptr; msgq = msgq->Next, lfoundi++) { - // now we hide mail pointer to item's lParam member. We can later use it to retrieve mail datas - - Extracted = FALSE; FromStr = nullptr; FromStrNew = FALSE; - - if (hListView != nullptr) { - fi.lParam = (LPARAM)msgq; - if (-1 != (foundi = ListView_FindItem(hListView, -1, &fi))) { // if mail is already in window - lfoundi = foundi; - continue; // do not insert any item - } - - item.iItem = lfoundi; // insert after last found item - item.lParam = (LPARAM)msgq; - } - - if (!LoadedMailData(msgq)) { // check if mail is already in memory - Loaded = false; - if (nullptr == LoadMailData(msgq)) //if we could not load mail to memory, consider this mail deleted and do not display it - continue; - } - else Loaded = true; - - if (((hListView != nullptr) && (msgq->Flags & YAMN_MSG_DISPLAY)) || - ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (msgq->Flags & YAMN_MSG_POPUP) && (msgq->Flags & YAMN_MSG_NEW))) { - - if (!Extracted) ExtractHeader(msgq->MailData->TranslatedHeader, msgq->MailData->CP, &UnicodeHeader); - Extracted = TRUE; - - if ((UnicodeHeader.From != nullptr) && (UnicodeHeader.FromNick != nullptr)) { - size_t size = mir_wstrlen(UnicodeHeader.From) + mir_wstrlen(UnicodeHeader.FromNick) + 4; - FromStr = new wchar_t[size]; - mir_snwprintf(FromStr, size, L"%s <%s>", UnicodeHeader.FromNick, UnicodeHeader.From); - FromStrNew = TRUE; - } - else if (UnicodeHeader.From != nullptr) - FromStr = UnicodeHeader.From; - else if (UnicodeHeader.FromNick != nullptr) - FromStr = UnicodeHeader.FromNick; - else if (UnicodeHeader.ReturnPath != nullptr) - FromStr = UnicodeHeader.ReturnPath; - - if (nullptr == FromStr) { - FromStr = L""; - FromStrNew = FALSE; - } - } - - if ((hListView != nullptr) && (msgq->Flags & YAMN_MSG_DISPLAY)) { - item.iSubItem = 0; - item.pszText = FromStr; - item.iItem = SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&item); - - item.iSubItem = 1; - item.pszText = (nullptr != UnicodeHeader.Subject ? UnicodeHeader.Subject : (wchar_t *)L""); - SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item); - - item.iSubItem = 2; - mir_snwprintf(SizeStr, L"%d kB", msgq->MailData->Size / 1024); - item.pszText = SizeStr; - SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item); - - item.iSubItem = 3; - item.pszText = L""; - - for (CMimeItem *heads = msgq->MailData->TranslatedHeader; heads != nullptr; heads = heads->Next) { - if (!_stricmp(heads->name, "Date")) { - MimeDateToLocalizedDateTime(heads->value, LocalDateStr, 128); - item.pszText = LocalDateStr; - break; - } - } - SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item); - } - - if ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (msgq->Flags & YAMN_MSG_POPUP) && (msgq->Flags & YAMN_MSG_NEW)) { - mir_wstrncpy(NewMailPopup.lpwzContactName, FromStr, _countof(NewMailPopup.lpwzContactName)); - mir_wstrncpy(NewMailPopup.lpwzText, UnicodeHeader.Subject, _countof(NewMailPopup.lpwzText)); - - PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)malloc(sizeof(YAMN_MAILSHOWPARAM)); - if (MailParam) { - MailParam->account = ActualAccount; - MailParam->mail = msgq; - MailParam->ThreadRunningEV = nullptr; - NewMailPopup.PluginData = MailParam; - PUAddPopupW(&NewMailPopup); - } - } - - if ((msgq->Flags & YAMN_MSG_UNSEEN) && (ActualAccount->NewMailN.Flags & YAMN_ACC_KBN)) - CallService(MS_KBDNOTIFY_EVENTSOPENED, 1, NULL); - - if (FromStrNew) - delete[] FromStr; - - if (Extracted) { - DeleteHeaderContent(&UnicodeHeader); - memset(&UnicodeHeader, 0, sizeof(UnicodeHeader)); - } - - if (!Loaded) { - SaveMailData(msgq); - UnloadMailData(msgq); //do not keep data for mail in memory - } - } - - return TRUE; -} - -void DoMailActions(HWND hDlg, CAccount *ActualAccount, struct CMailNumbers *MN, uint32_t nflags, uint32_t nnflags) -{ - NOTIFYICONDATA nid = {}; - nid.cbSize = sizeof(nid); - nid.hWnd = hDlg; - - if (MN->Real.EventNC + MN->Virtual.EventNC) - NotifyEventHooks(hNewMailHook, 0, 0); - - if ((nflags & YAMN_ACC_KBN) && (MN->Real.PopupRun + MN->Virtual.PopupRun)) - CallService(MS_KBDNOTIFY_STARTBLINK, (WPARAM)MN->Real.PopupNC + MN->Virtual.PopupNC, NULL); - - if ((nflags & YAMN_ACC_CONT) && (MN->Real.PopupRun + MN->Virtual.PopupRun)) { - wchar_t tszMsg[250]; - mir_snwprintf(tszMsg, TranslateT("%s : %d new mail message(s), %d total"), _A2T(ActualAccount->Name).get(), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC); - - if (!(nflags & YAMN_ACC_CONTNOEVENT)) { - CLISTEVENT evt = {}; - evt.flags = CLEF_UNICODE; - evt.hContact = ActualAccount->hContact; - evt.hIcon = g_plugin.getIcon(IDI_NEWMAIL); - evt.hDbEvent = ActualAccount->hContact; - evt.lParam = ActualAccount->hContact; - evt.pszService = MS_YAMN_CLISTDBLCLICK; - evt.szTooltip.w = tszMsg; - g_clistApi.pfnAddEvent(&evt); - } - db_set_ws(ActualAccount->hContact, "CList", "StatusMsg", tszMsg); - - if (nflags & YAMN_ACC_CONTNICK) - g_plugin.setWString(ActualAccount->hContact, "Nick", tszMsg); - } - - if ((nflags & YAMN_ACC_POP) && - !(ActualAccount->Flags & YAMN_ACC_POPN) && - (MN->Real.PopupRun + MN->Virtual.PopupRun)) { - POPUPDATAW NewMailPopup; - - NewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount; - NewMailPopup.lchIcon = g_plugin.getIcon(IDI_NEWMAIL); - if (nflags & YAMN_ACC_POPC) { - NewMailPopup.colorBack = ActualAccount->NewMailN.PopupB; - NewMailPopup.colorText = ActualAccount->NewMailN.PopupT; - } - else { - NewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE); - NewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT); - } - NewMailPopup.iSeconds = ActualAccount->NewMailN.PopupTime; - - NewMailPopup.PluginWindowProc = NewMailPopupProc; - NewMailPopup.PluginData = (void *)nullptr; //multiple popups - - mir_wstrncpy(NewMailPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(NewMailPopup.lpwzContactName)); - mir_snwprintf(NewMailPopup.lpwzText, TranslateT("%d new mail message(s), %d total"), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC); - PUAddPopupW(&NewMailPopup); - } - - // destroy tray icon if no new mail - if ((MN->Real.SysTrayUC + MN->Virtual.SysTrayUC == 0) && (hDlg != nullptr)) - Shell_NotifyIcon(NIM_DELETE, &nid); - - // and remove the event - if ((nflags & YAMN_ACC_CONT) && (!(nflags & YAMN_ACC_CONTNOEVENT)) && (MN->Real.UnSeen + MN->Virtual.UnSeen == 0)) - g_clistApi.pfnRemoveEvent(ActualAccount->hContact, ActualAccount->hContact); - - if ((MN->Real.BrowserUC + MN->Virtual.BrowserUC == 0) && (hDlg != nullptr)) { - if (!IsWindowVisible(hDlg) && !(nflags & YAMN_ACC_MSG)) - PostMessage(hDlg, WM_DESTROY, 0, 0); //destroy window if no new mail and window is not visible - if (nnflags & YAMN_ACC_MSG) //if no new mail and msg should be executed - { - SetForegroundWindow(hDlg); - ShowWindow(hDlg, SW_SHOWNORMAL); - } - } - else - if (hDlg != nullptr) //else insert icon and set window if new mails - { - SendDlgItemMessageW(hDlg, IDC_LISTMAILS, LVM_SCROLL, 0, (LPARAM)0x7ffffff); - - if ((nflags & YAMN_ACC_ICO) && (MN->Real.SysTrayUC + MN->Virtual.SysTrayUC)) { - nid.hIcon = g_plugin.getIcon(IDI_NEWMAIL); - nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP; - nid.uCallbackMessage = WM_YAMN_NOTIFYICON; - mir_snwprintf(nid.szTip, L"%S %s", ActualAccount->Name, TranslateT("- new mail message(s)")); - Shell_NotifyIcon(NIM_ADD, &nid); - SetTimer(hDlg, TIMER_FLASHING, 500, nullptr); - } - if (nflags & YAMN_ACC_MSG) //if no new mail and msg should be executed - ShowWindow(hDlg, SW_SHOWNORMAL); - } - - if (MN->Real.AppNC + MN->Virtual.AppNC != 0) { - if (nflags & YAMN_ACC_APP) { - PROCESS_INFORMATION pi; - STARTUPINFOW si; - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - - if (ActualAccount->NewMailN.App != nullptr) { - wchar_t *Command; - if (ActualAccount->NewMailN.AppParam != nullptr) - Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6]; - else - Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + 6]; - - if (Command != nullptr) { - mir_wstrcpy(Command, L"\""); - mir_wstrcat(Command, ActualAccount->NewMailN.App); - mir_wstrcat(Command, L"\" "); - if (ActualAccount->NewMailN.AppParam != nullptr) - mir_wstrcat(Command, ActualAccount->NewMailN.AppParam); - CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi); - delete[] Command; - } - } - } - } - - if (MN->Real.SoundNC + MN->Virtual.SoundNC != 0) - if (nflags & YAMN_ACC_SND) - Skin_PlaySound(YAMN_NEWMAILSOUND); - - if ((nnflags & YAMN_ACC_POP) && (MN->Real.PopupRun + MN->Virtual.PopupRun == 0)) { - POPUPDATAW NoNewMailPopup = {}; - - NoNewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount; - NoNewMailPopup.lchIcon = g_plugin.getIcon(IDI_LAUNCHAPP); - if (nflags & YAMN_ACC_POPC) { - NoNewMailPopup.colorBack = ActualAccount->NoNewMailN.PopupB; - NoNewMailPopup.colorText = ActualAccount->NoNewMailN.PopupT; - } - else { - NoNewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE); - NoNewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT); - } - NoNewMailPopup.iSeconds = ActualAccount->NoNewMailN.PopupTime; - - NoNewMailPopup.PluginWindowProc = NoNewMailPopupProc; - NoNewMailPopup.PluginData = nullptr; //it's not new mail popup - - mir_wstrncpy(NoNewMailPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(NoNewMailPopup.lpwzContactName)); - if (MN->Real.PopupSL2NC + MN->Virtual.PopupSL2NC) - mir_snwprintf(NoNewMailPopup.lpwzText, TranslateT("No new mail message, %d spam(s)"), MN->Real.PopupSL2NC + MN->Virtual.PopupSL2NC); - else - mir_wstrncpy(NoNewMailPopup.lpwzText, TranslateT("No new mail message"), _countof(NoNewMailPopup.lpwzText)); - PUAddPopupW(&NoNewMailPopup); - } - - if ((nflags & YAMN_ACC_CONT) && (MN->Real.PopupRun + MN->Virtual.PopupRun == 0)) { - if (ActualAccount->hContact != NULL) { - if (MN->Real.PopupTC + MN->Virtual.PopupTC) { - char tmp[255]; - mir_snprintf(tmp, Translate("%d new mail message(s), %d total"), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC); - db_set_s(ActualAccount->hContact, "CList", "StatusMsg", tmp); - } - else db_set_s(ActualAccount->hContact, "CList", "StatusMsg", Translate("No new mail message")); - - if (nflags & YAMN_ACC_CONTNICK) - g_plugin.setString(ActualAccount->hContact, "Nick", ActualAccount->Name); - } - } - return; -} - -LRESULT CALLBACK NewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - INT_PTR PluginParam = 0; - switch (msg) { - case WM_COMMAND: - // if clicked and it's new mail popup window - if ((HIWORD(wParam) == STN_CLICKED) && (-1 != (PluginParam = (INT_PTR)PUGetPluginData(hWnd)))) { - MCONTACT hContact = 0; - CAccount *Account; - if (PluginParam) { - PYAMN_MAILSHOWPARAM MailParam = new YAMN_MAILSHOWPARAM; - memcpy(MailParam, (PINT_PTR)PluginParam, sizeof(YAMN_MAILSHOWPARAM)); - hContact = MailParam->account->hContact; - Account = MailParam->account; - mir_forkthread(ShowEmailThread, MailParam); - } - else { - DBVARIANT dbv; - - hContact = PUGetContact(hWnd); - - if (!g_plugin.getString(hContact, "Id", &dbv)) { - Account = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); - db_free(&dbv); - } - else Account = (CAccount *)hContact; //???? - - if (WAIT_OBJECT_0 == WaitToReadFcn(Account->AccountAccessSO)) { - switch (msg) { - case WM_COMMAND: - { - YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, Account, - (Account->NewMailN.Flags & ~YAMN_ACC_POP) | YAMN_ACC_MSGP | YAMN_ACC_MSG, - (Account->NoNewMailN.Flags & ~YAMN_ACC_POP) | YAMN_ACC_MSGP | YAMN_ACC_MSG}; - - RunMailBrowserSvc((WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION); - } - break; - } - ReadDoneFcn(Account->AccountAccessSO); - } - } - if ((Account->NewMailN.Flags & YAMN_ACC_CONT) && !(Account->NewMailN.Flags & YAMN_ACC_CONTNOEVENT)) - g_clistApi.pfnRemoveEvent(hContact, hContact); - } - __fallthrough; - - case WM_CONTEXTMENU: - PUDeletePopup(hWnd); - break; - case UM_FREEPLUGINDATA: - { - PYAMN_MAILSHOWPARAM mpd = (PYAMN_MAILSHOWPARAM)PUGetPluginData(hWnd); - if ((mpd) && (INT_PTR)mpd != -1)free(mpd); - return FALSE; - } - case UM_INITPOPUP: - //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups. - WindowList_Add(YAMNVar.MessageWnds, hWnd); - break; - case UM_DESTROYPOPUP: - WindowList_Remove(YAMNVar.MessageWnds, hWnd); - break; - case WM_YAMN_STOPACCOUNT: - { - CAccount *ActualAccount; - DBVARIANT dbv; - - MCONTACT hContact = PUGetContact(hWnd); - - if (!g_plugin.getString(hContact, "Id", &dbv)) { - ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); - db_free(&dbv); - } - else - ActualAccount = (CAccount *)hContact; - - if ((CAccount *)wParam != ActualAccount) - break; - DestroyWindow(hWnd); - return 0; - } - case WM_NOTIFY: - default: - break; - } - return DefWindowProc(hWnd, msg, wParam, lParam); -} - -LRESULT CALLBACK NoNewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_COMMAND: - if ((HIWORD(wParam) == STN_CLICKED) && (msg == WM_COMMAND)) { - CAccount *ActualAccount; - DBVARIANT dbv; - - MCONTACT hContact = PUGetContact(hWnd); - - if (!g_plugin.getString(hContact, "Id", &dbv)) { - ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); - db_free(&dbv); - } - else - ActualAccount = (CAccount *)hContact; - - if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { - switch (msg) { - case WM_COMMAND: - { - YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, ActualAccount->NewMailN.Flags, ActualAccount->NoNewMailN.Flags, nullptr}; - - Param.nnflags = Param.nnflags | YAMN_ACC_MSG; //show mails in account even no new mail in account - Param.nnflags = Param.nnflags & ~YAMN_ACC_POP; - - Param.nflags = Param.nflags | YAMN_ACC_MSG; //show mails in account even no new mail in account - Param.nflags = Param.nflags & ~YAMN_ACC_POP; - - RunMailBrowserSvc((WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION); - } - break; - } - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - PUDeletePopup(hWnd); - } - break; - - case WM_CONTEXTMENU: - PUDeletePopup(hWnd); - break; - - case UM_FREEPLUGINDATA: - //Here we'd free our own data, if we had it. - return FALSE; - case UM_INITPOPUP: - //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups. - WindowList_Add(YAMNVar.MessageWnds, hWnd); - break; - case UM_DESTROYPOPUP: - WindowList_Remove(YAMNVar.MessageWnds, hWnd); - break; - case WM_YAMN_STOPACCOUNT: - { - CAccount *ActualAccount; - DBVARIANT dbv; - - MCONTACT hContact = PUGetContact(hWnd); - - if (!g_plugin.getString(hContact, "Id", &dbv)) { - ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); - db_free(&dbv); - } - else - ActualAccount = (CAccount *)hContact; - - if ((CAccount *)wParam != ActualAccount) - break; - - DestroyWindow(hWnd); - return 0; - } - } - return DefWindowProc(hWnd, msg, wParam, lParam); -} - -#ifdef __GNUC__ -//number of 100 ns periods between FILETIME 0 (1601/01/01 00:00:00.0000000) and TIMESTAMP 0 (1970/01/01 00:00:00) -#define NUM100NANOSEC 116444736000000000ULL -//The biggest time Get[Date|Time]Format can handle (Fri, 31 Dec 30827 23:59:59.9999999) -#define MAXFILETIME 0x7FFF35F4F06C7FFFULL -#else -#define NUM100NANOSEC 116444736000000000 -#define MAXFILETIME 0x7FFF35F4F06C7FFF -#endif - -ULONGLONG MimeDateToFileTime(char *datein) -{ - char *day = nullptr, *month = nullptr, *year = nullptr, *time = nullptr, *shift = nullptr; - SYSTEMTIME st; - ULONGLONG res = 0; - int wShiftSeconds = TimeZone_ToLocal(0); - GetLocalTime(&st); - //datein = "Xxx, 1 Jan 2060 5:29:1 +0530 XXX"; - //datein = "Xxx, 1 Jan 2060 05:29:10 "; - //datein = " ManySpaces 1.5 Jan 2060 05::"; - //datein = "Xxx, 35 February 20 :29:10 "; - //datein = "01.12.2007 (22:38:17)"; // - if (datein) { - char tmp[64]; - while (datein[0] == ' ') datein++; // eat leading spaces - strncpy(tmp, datein, 63); tmp[63] = 0; - if (atoi(tmp)) { // Parseable integer on DayOfWeek field? Buggy mime date. - day = tmp; - } - else { - int i = 0; - while (tmp[i] == ' ')i++; if (day = strchr(&tmp[i], ' ')) { day[0] = 0; day++; } - } - if (day) { while (day[0] == ' ') day++; if (month = strchr(day, ' ')) { month[0] = 0; month++; } } - if (month) { while (month[0] == ' ')month++; if (year = strchr(month, ' ')) { year[0] = 0; year++; } } - if (year) { while (year[0] == ' ') year++; if (time = strchr(year, ' ')) { time[0] = 0; time++; } } - if (time) { while (time[0] == ' ') time++; if (shift = strchr(time, ' ')) { shift[0] = 0; shift++; shift[5] = 0; } } - - if (year) { - st.wYear = atoi(year); - if (mir_strlen(year) < 4) if (st.wYear < 70)st.wYear += 2000; else st.wYear += 1900; - }; - if (month) for (int i = 0; i < 12; i++) if (strncmp(month, s_MonthNames[i], 3) == 0) { st.wMonth = i + 1; break; } - if (day) st.wDay = atoi(day); - if (time) { - char *h, *m, *s; - h = time; - if (m = strchr(h, ':')) { - m[0] = 0; m++; - if (s = strchr(m, ':')) { s[0] = 0; s++; } - } - else s = nullptr; - st.wHour = atoi(h); - st.wMinute = m ? atoi(m) : 0; - st.wSecond = s ? atoi(s) : 0; - } - else { st.wHour = st.wMinute = st.wSecond = 0; } - - if (shift) { - if (mir_strlen(shift) < 4) { - //has only hour - wShiftSeconds = (atoi(shift)) * 3600; - } - else { - char *smin = shift + mir_strlen(shift) - 2; - int ismin = atoi(smin); - smin[0] = 0; - int ishour = atoi(shift); - wShiftSeconds = (ishour * 60 + (ishour < 0 ? -1 : 1) * ismin) * 60; - } - } - } // if (datein) - FILETIME ft; - if (SystemTimeToFileTime(&st, &ft)) { - res = ((ULONGLONG)ft.dwHighDateTime << 32) | ((ULONGLONG)ft.dwLowDateTime); - LONGLONG w100nano = Int32x32To64((uint32_t)wShiftSeconds, 10000000); - res -= w100nano; - } - else { - res = 0; - } - return res; -} - -void FileTimeToLocalizedDateTime(LONGLONG filetime, wchar_t *dateout, int lendateout) -{ - int localeID = Langpack_GetDefaultLocale(); - //int localeID = MAKELCID(LANG_URDU, SORT_DEFAULT); - if (localeID == CALLSERVICE_NOTFOUND) localeID = LOCALE_USER_DEFAULT; - if (filetime > MAXFILETIME) filetime = MAXFILETIME; - else if (filetime <= 0) { - wcsncpy(dateout, TranslateT("Invalid"), lendateout); - return; - } - SYSTEMTIME st; - uint16_t wTodayYear = 0, wTodayMonth = 0, wTodayDay = 0; - FILETIME ft; - BOOL willShowDate = !(optDateTime & SHOWDATENOTODAY); - if (!willShowDate) { - GetLocalTime(&st); - wTodayYear = st.wYear; - wTodayMonth = st.wMonth; - wTodayDay = st.wDay; - } - ft.dwLowDateTime = (uint32_t)filetime; - ft.dwHighDateTime = (uint32_t)(filetime >> 32); - FILETIME localft; - if (!FileTimeToLocalFileTime(&ft, &localft)) { - // this should never happen - wcsncpy(dateout, L"Incorrect FileTime", lendateout); - } - else { - if (!FileTimeToSystemTime(&localft, &st)) { - // this should never happen - wcsncpy(dateout, L"Incorrect LocalFileTime", lendateout); - } - else { - dateout[lendateout - 1] = 0; - int templen = 0; - if (!willShowDate) willShowDate = (wTodayYear != st.wYear) || (wTodayMonth != st.wMonth) || (wTodayDay != st.wDay); - if (willShowDate) { - templen = GetDateFormatW(localeID, (optDateTime & SHOWDATELONG) ? DATE_LONGDATE : DATE_SHORTDATE, &st, nullptr, dateout, lendateout - 2); - dateout[templen - 1] = ' '; - } - if (templen < (lendateout - 1)) { - GetTimeFormatW(localeID, (optDateTime & SHOWDATENOSECONDS) ? TIME_NOSECONDS : 0, &st, nullptr, &dateout[templen], lendateout - templen - 1); - } - } - } -} - -void MimeDateToLocalizedDateTime(char *datein, wchar_t *dateout, int lendateout) -{ - ULONGLONG ft = MimeDateToFileTime(datein); - FileTimeToLocalizedDateTime(ft, dateout, lendateout); -} - -int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort) -{ - if (lParam1 == NULL || lParam2 == NULL) - return 0; - - int nResult = 0; - char *str1; - char *str2; - HYAMNMAIL email1 = (HYAMNMAIL)lParam1; - HYAMNMAIL email2 = (HYAMNMAIL)lParam2; - struct CShortHeader Header1; - struct CShortHeader Header2; - memset(&Header1, 0, sizeof(Header1)); - memset(&Header2, 0, sizeof(Header2)); - - try { - ExtractShortHeader(email1->MailData->TranslatedHeader, &Header1); - ExtractShortHeader(email2->MailData->TranslatedHeader, &Header2); - - switch ((int)lParamSort) { - case 0: //From - if (Header1.FromNick == nullptr) - str1 = Header1.From; - else str1 = Header1.FromNick; - - if (Header2.FromNick == nullptr) - str2 = Header2.From; - else str2 = Header2.FromNick; - - nResult = mir_strcmp(str1, str2); - - if (bFrom) nResult = -nResult; - break; - case 1: //Subject - if (Header1.Subject == nullptr) - str1 = " "; - else str1 = Header1.Subject; - - if (Header2.Subject == nullptr) - str2 = " "; - else str2 = Header2.Subject; - - nResult = mir_strcmp(str1, str2); - - if (bSub) nResult = -nResult; - break; - case 2: //Size - if (email1->MailData->Size == email2->MailData->Size) nResult = 0; - if (email1->MailData->Size > email2->MailData->Size) nResult = 1; - if (email1->MailData->Size < email2->MailData->Size) nResult = -1; - - if (bSize) nResult = -nResult; - break; - - case 3: //Date - { - ULONGLONG ts1 = 0, ts2 = 0; - ts1 = MimeDateToFileTime(Header1.Date); - ts2 = MimeDateToFileTime(Header2.Date); - if (ts1 > ts2) nResult = 1; - else if (ts1 < ts2) nResult = -1; - else nResult = 0; - } - if (bDate) nResult = -nResult; - break; - - default: - if (Header1.Subject == nullptr) str1 = " "; - else str1 = Header1.Subject; - - if (Header2.Subject == nullptr) str2 = " "; - else str2 = Header2.Subject; - - nResult = mir_strcmp(str1, str2); - break; - } - //MessageBox(NULL,str1,str2,0); - } - catch (...) { - } - - //free mem - DeleteShortHeaderContent(&Header1); - DeleteShortHeaderContent(&Header2); - return nResult; - -} - -HCURSOR hCurSplitNS, hCurSplitWE; -#define DM_SPLITTERMOVED (WM_USER+15) - -static LRESULT CALLBACK SplitterSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_NCHITTEST: - return HTCLIENT; - - case WM_SETCURSOR: - SetCursor(hCurSplitNS); - return TRUE; - - case WM_LBUTTONDOWN: - SetCapture(hwnd); - return 0; - - case WM_MOUSEMOVE: - if (GetCapture() == hwnd) { - RECT rc; - GetClientRect(hwnd, &rc); - SendMessage(GetParent(hwnd), DM_SPLITTERMOVED, (short)HIWORD(GetMessagePos()) + rc.bottom / 2, (LPARAM)hwnd); - } - return 0; - - case WM_LBUTTONUP: - ReleaseCapture(); - return 0; - } - return mir_callNextSubclass(hwnd, SplitterSubclassProc, msg, wParam, lParam); -} - -void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode); -int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out); - -INT_PTR CALLBACK DlgProcYAMNShowMessage(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - switch (msg) { - case WM_INITDIALOG: - { - PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)lParam; - wchar_t *iHeaderW = nullptr; - wchar_t *iValueW = nullptr; - int StrLen; - HWND hListView = GetDlgItem(hDlg, IDC_LISTHEADERS); - mir_subclassWindow(GetDlgItem(hDlg, IDC_SPLITTER), SplitterSubclassProc); - SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)MailParam); - Window_SetIcon_IcoLib(hDlg, g_plugin.getIconHandle(IDI_NEWMAIL)); - - ListView_SetUnicodeFormat(hListView, TRUE); - ListView_SetExtendedListViewStyle(hListView, LVS_EX_FULLROWSELECT); - - StrLen = MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Header"), -1, nullptr, 0); - iHeaderW = new wchar_t[StrLen + 1]; - MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Header"), -1, iHeaderW, StrLen); - - StrLen = MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Value"), -1, nullptr, 0); - iValueW = new wchar_t[StrLen + 1]; - MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Value"), -1, iValueW, StrLen); - - LVCOLUMN lvc0 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, 130, iHeaderW, 0, 0}; - LVCOLUMN lvc1 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, 400, iValueW, 0, 0}; - SendMessage(hListView, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc0); - SendMessage(hListView, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc1); - if (nullptr != iHeaderW) - delete[] iHeaderW; - if (nullptr != iValueW) - delete[] iValueW; - - SendMessage(hDlg, WM_YAMN_CHANGECONTENT, 0, (LPARAM)MailParam); - MoveWindow(hDlg, HeadPosX, HeadPosY, HeadSizeX, HeadSizeY, 0); - ShowWindow(hDlg, SW_SHOWNORMAL); - } - break; - - case WM_YAMN_CHANGECONTENT: - { - PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM) - (lParam ? lParam : GetWindowLongPtr(hDlg, DWLP_USER)); - HWND hListView = GetDlgItem(hDlg, IDC_LISTHEADERS); - HWND hEdit = GetDlgItem(hDlg, IDC_EDITBODY); - //do not redraw - SendMessage(hListView, WM_SETREDRAW, 0, 0); - ListView_DeleteAllItems(hListView); - struct CMimeItem *Header; - LVITEMW item; - item.mask = LVIF_TEXT | LVIF_PARAM; - wchar_t *From = nullptr, *Subj = nullptr; - char *contentType = nullptr, *transEncoding = nullptr, *body = nullptr; //should not be delete[]-ed - for (Header = MailParam->mail->MailData->TranslatedHeader; Header != nullptr; Header = Header->Next) { - wchar_t *str1 = nullptr; - wchar_t *str2 = nullptr; - wchar_t str_nul[2] = {0}; - if (!body) if (!_stricmp(Header->name, "Body")) { body = Header->value; continue; } - if (!contentType) if (!_stricmp(Header->name, "Content-Type")) contentType = Header->value; - if (!transEncoding) if (!_stricmp(Header->name, "Content-Transfer-Encoding")) transEncoding = Header->value; - //ConvertCodedStringToUnicode(Header->name,&str1,MailParam->mail->MailData->CP,1); - { - int streamsize = MultiByteToWideChar(20127, 0, Header->name, -1, nullptr, 0); - str1 = (wchar_t *)malloc(sizeof(wchar_t) * (streamsize + 1)); - MultiByteToWideChar(20127, 0, Header->name, -1, str1, streamsize);//US-ASCII - } - ConvertCodedStringToUnicode(Header->value, &str2, MailParam->mail->MailData->CP, 1); - if (!str2) { str2 = (wchar_t *)str_nul; }// the header value may be NULL - if (!From) if (!_stricmp(Header->name, "From")) { - From = new wchar_t[mir_wstrlen(str2) + 1]; - mir_wstrcpy(From, str2); - } - if (!Subj) if (!_stricmp(Header->name, "Subject")) { - Subj = new wchar_t[mir_wstrlen(str2) + 1]; - mir_wstrcpy(Subj, str2); - } - //if (!hasBody) if (!mir_strcmp(Header->name,"Body")) hasBody = true; - int count = 0; wchar_t **split = nullptr; - int ofs = 0; - while (str2[ofs]) { - if ((str2[ofs] == 0x266A) || (str2[ofs] == 0x25D9) || (str2[ofs] == 0x25CB) || - (str2[ofs] == 0x09) || (str2[ofs] == 0x0A) || (str2[ofs] == 0x0D))count++; - ofs++; - } - split = new wchar_t *[count + 1]; - count = 0; ofs = 0; - split[0] = str2; - while (str2[ofs]) { - if ((str2[ofs] == 0x266A) || (str2[ofs] == 0x25D9) || (str2[ofs] == 0x25CB) || - (str2[ofs] == 0x09) || (str2[ofs] == 0x0A) || (str2[ofs] == 0x0D)) { - if (str2[ofs - 1]) { - count++; - } - split[count] = (wchar_t *)(str2 + ofs + 1); - str2[ofs] = 0; - } - ofs++; - }; - - if (!_stricmp(Header->name, "From") || !_stricmp(Header->name, "To") || !_stricmp(Header->name, "Date") || !_stricmp(Header->name, "Subject")) - item.iItem = 0; - else - item.iItem = 999; - for (int i = 0; i <= count; i++) { - item.iSubItem = 0; - if (i == 0) - item.pszText = str1; - else { - item.iItem++; - item.pszText = nullptr; - } - item.iItem = SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&item); - item.iSubItem = 1; - item.pszText = str2 ? split[i] : nullptr; - SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item); - } - delete[] split; - - if (str1) - free(str1); - if (str2 != (wchar_t *)str_nul) - free(str2); - } - if (body) { - wchar_t *bodyDecoded = nullptr; - char *localBody = nullptr; - if (contentType) { - if (!_strnicmp(contentType, "text", 4)) { - if (transEncoding) { - if (!_stricmp(transEncoding, "base64")) { - int size = (int)mir_strlen(body) * 3 / 4 + 5; - localBody = new char[size + 1]; - DecodeBase64(body, localBody, size); - } - else if (!_stricmp(transEncoding, "quoted-printable")) { - int size = (int)mir_strlen(body) + 2; - localBody = new char[size + 1]; - DecodeQuotedPrintable(body, localBody, size, FALSE); - } - } - } - else if (!_strnicmp(contentType, "multipart/", 10)) { - char *bondary = nullptr; - if (nullptr != (bondary = ExtractFromContentType(contentType, "boundary="))) { - bodyDecoded = ParseMultipartBody(body, bondary); - delete[] bondary; - } - } - } - if (!bodyDecoded)ConvertStringToUnicode(localBody ? localBody : body, MailParam->mail->MailData->CP, &bodyDecoded); - SetWindowTextW(hEdit, bodyDecoded); - delete[] bodyDecoded; - if (localBody) delete[] localBody; - SetFocus(hEdit); - } - if (!(MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED)) { - MailParam->mail->Flags |= YAMN_MSG_BODYREQUESTED; - CallService(MS_YAMN_ACCOUNTCHECK, (WPARAM)MailParam->account, 0); - } - else { - if (MailParam->mail->Flags & YAMN_MSG_UNSEEN) { - MailParam->mail->Flags &= ~YAMN_MSG_UNSEEN; //mark the message as seen - HWND hMailBrowser = WindowList_Find(YAMNVar.NewMailAccountWnd, (UINT_PTR)MailParam->account); - if (hMailBrowser) { - struct CChangeContent Params = {MailParam->account->NewMailN.Flags | YAMN_ACC_MSGP, MailParam->account->NoNewMailN.Flags | YAMN_ACC_MSGP}; - SendMessage(hMailBrowser, WM_YAMN_CHANGECONTENT, (WPARAM)MailParam->account, (LPARAM)&Params); - } - else UpdateMails(nullptr, MailParam->account, MailParam->account->NewMailN.Flags, MailParam->account->NoNewMailN.Flags); - } - } - ShowWindow(GetDlgItem(hDlg, IDC_SPLITTER), (MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED) ? SW_SHOW : SW_HIDE); - ShowWindow(hEdit, (MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED) ? SW_SHOW : SW_HIDE); - wchar_t *title = nullptr; - size_t size = (From ? mir_wstrlen(From) : 0) + (Subj ? mir_wstrlen(Subj) : 0) + 4; - title = new wchar_t[size]; - if (From && Subj) - mir_snwprintf(title, size, L"%s (%s)", Subj, From); - else if (From) - wcsncpy_s(title, size, From, _TRUNCATE); - else if (Subj) - wcsncpy_s(title, size, Subj, _TRUNCATE); - else - wcsncpy_s(title, size, L"none", _TRUNCATE); - if (Subj) delete[] Subj; - if (From) delete[] From; - SetWindowTextW(hDlg, title); - delete[] title; - // turn on redrawing - SendMessage(hListView, WM_SETREDRAW, 1, 0); - SendMessage(hDlg, WM_SIZE, 0, HeadSizeY << 16 | HeadSizeX); - } break; - - case WM_YAMN_STOPACCOUNT: - { - PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM) - (lParam ? lParam : GetWindowLongPtr(hDlg, DWLP_USER)); - - if (nullptr == MailParam) - break; - if ((CAccount *)wParam != MailParam->account) - break; - - DestroyWindow(hDlg); - } - return 1; - - case WM_CTLCOLORSTATIC: - // here should be check if this is our edittext control. - // but we have only one static control (for now); - SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW)); - SetTextColor((HDC)wParam, GetSysColor(COLOR_WINDOWTEXT)); - return (INT_PTR)GetSysColorBrush(COLOR_WINDOW); - - case WM_DESTROY: - Window_FreeIcon_IcoLib(hDlg); - { - RECT coord; - if (GetWindowRect(hDlg, &coord)) { - HeadPosX = coord.left; - HeadSizeX = coord.right - coord.left; - HeadPosY = coord.top; - HeadSizeY = coord.bottom - coord.top; - } - - PostQuitMessage(1); - } - break; - - case WM_SYSCOMMAND: - switch (wParam) { - case SC_CLOSE: - DestroyWindow(hDlg); - break; - } - break; - - case WM_MOVE: - HeadPosX = LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left; - HeadPosY = HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top; - return 0; - - case DM_SPLITTERMOVED: - if ((HWND)lParam == GetDlgItem(hDlg, IDC_SPLITTER)) { - POINT pt; - pt.x = 0; - pt.y = wParam; - ScreenToClient(hDlg, &pt); - HeadSplitPos = (pt.y * 1000) / HeadSizeY;//+rc.bottom-rc.top; - if (HeadSplitPos >= 1000) HeadSplitPos = 999; - else if (HeadSplitPos <= 0) HeadSplitPos = 1; - else SendMessage(hDlg, WM_SIZE, 0, HeadSizeY << 16 | HeadSizeX); - } - return 0; - - case WM_SIZE: - if (wParam == SIZE_RESTORED) { - HWND hList = GetDlgItem(hDlg, IDC_LISTHEADERS); - HWND hEdit = GetDlgItem(hDlg, IDC_EDITBODY); - BOOL isBodyShown = ((PYAMN_MAILSHOWPARAM)(GetWindowLongPtr(hDlg, DWLP_USER)))->mail->Flags & YAMN_MSG_BODYRECEIVED; - HeadSizeX = LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left; - HeadSizeY = HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top; - int localSplitPos = (HeadSplitPos * HeadSizeY) / 1000; - int localSizeX; - RECT coord; - MoveWindow(GetDlgItem(hDlg, IDC_SPLITTER), 5, localSplitPos, HeadSizeX - 10, 2, TRUE); - MoveWindow(hEdit, 5, localSplitPos + 6, HeadSizeX - 10, HeadSizeY - localSplitPos - 11, TRUE); //where to put text window while resizing - MoveWindow(hList, 5, 5, HeadSizeX - 10, (isBodyShown ? localSplitPos : HeadSizeY) - 10, TRUE); //where to put headers list window while resizing - //if (changeX) { - if (GetClientRect(hList, &coord)) { - localSizeX = coord.right - coord.left; - } - else localSizeX = HeadSizeX; - LONG iNameWidth = ListView_GetColumnWidth(hList, 0); - ListView_SetColumnWidth(hList, 1, (localSizeX <= iNameWidth) ? 0 : (localSizeX - iNameWidth)); - //} - } - return 0; - - case WM_CONTEXTMENU: - if (GetWindowLongPtr((HWND)wParam, GWLP_ID) == IDC_LISTHEADERS) { - //MessageBox(0,"LISTHEADERS","Debug",0); - HWND hList = GetDlgItem(hDlg, IDC_LISTHEADERS); - POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; - if (pt.x == -1) pt.x = 0; - if (pt.y == -1) pt.y = 0; - if (int numRows = ListView_GetItemCount(hList)) { - HMENU hMenu = CreatePopupMenu(); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)1, TranslateT("Copy Selected")); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)2, TranslateT("Copy All")); - AppendMenu(hMenu, MF_SEPARATOR, 0, nullptr); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel")); - int nReturnCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hDlg, nullptr); - DestroyMenu(hMenu); - if (nReturnCmd > 0) { - int courRow = 0; - size_t sizeNeeded = 0; - wchar_t headname[64] = {0}, headvalue[256] = {0}; - for (courRow = 0; courRow < numRows; courRow++) { - if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue; - ListView_GetItemText(hList, courRow, 0, headname, _countof(headname)); - ListView_GetItemText(hList, courRow, 1, headvalue, _countof(headvalue)); - size_t headnamelen = mir_wstrlen(headname); - if (headnamelen) sizeNeeded += 1 + headnamelen; - sizeNeeded += 3 + mir_wstrlen(headvalue); - } - if (sizeNeeded && OpenClipboard(hDlg)) { - EmptyClipboard(); - HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, (sizeNeeded + 1) * sizeof(wchar_t)); - wchar_t *buff = (wchar_t *)GlobalLock(hData); - int courPos = 0; - for (courRow = 0; courRow < numRows; courRow++) { - if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue; - ListView_GetItemText(hList, courRow, 0, headname, _countof(headname)); - ListView_GetItemText(hList, courRow, 1, headvalue, _countof(headvalue)); - if (mir_wstrlen(headname)) courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"%s:\t%s\r\n", headname, headvalue); - else courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"\t%s\r\n", headvalue); - } - GlobalUnlock(hData); - - SetClipboardData(CF_UNICODETEXT, hData); - - CloseClipboard(); - } - } - } - } - break; // just in case - } - return 0; -} - -void __cdecl ShowEmailThread(void *Param) -{ - struct MailShowMsgWinParam MyParam = *(struct MailShowMsgWinParam *)Param; - - SCIncFcn(MyParam.account->UsingThreads); - - if (MyParam.mail->MsgWindow) { - //if (!BringWindowToTop(MyParam.mail->MsgWindow)) { - if (!SetForegroundWindow(MyParam.mail->MsgWindow)) { - SendMessage(MyParam.mail->MsgWindow, WM_DESTROY, 0, 0); - MyParam.mail->MsgWindow = nullptr; - goto CREADTEVIEWMESSAGEWINDOW; - } - - if (IsIconic(MyParam.mail->MsgWindow)) - OpenIcon(MyParam.mail->MsgWindow); - } - else { -CREADTEVIEWMESSAGEWINDOW: - MyParam.mail->MsgWindow = CreateDialogParamW(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_DLGSHOWMESSAGE), nullptr, DlgProcYAMNShowMessage, (LPARAM)&MyParam); - WindowList_Add(YAMNVar.MessageWnds, MyParam.mail->MsgWindow); - MSG msg; - while (GetMessage(&msg, nullptr, 0, 0)) { - if (MyParam.mail->MsgWindow == nullptr || !IsDialogMessage(MyParam.mail->MsgWindow, &msg)) { /* Wine fix. */ - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - WindowList_Remove(YAMNVar.MessageWnds, MyParam.mail->MsgWindow); - MyParam.mail->MsgWindow = nullptr; - } - - SCDecFcn(MyParam.account->UsingThreads); - delete (struct MailShowMsgWinParam *)Param; -} - -INT_PTR CALLBACK DlgProcYAMNMailBrowser(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - CAccount *ActualAccount; - int Items; - - switch (msg) { - case WM_INITDIALOG: - { - struct MailBrowserWinParam *MyParam = (struct MailBrowserWinParam *)lParam; - - ListView_SetUnicodeFormat(GetDlgItem(hDlg, IDC_LISTMAILS), TRUE); - ListView_SetExtendedListViewStyle(GetDlgItem(hDlg, IDC_LISTMAILS), LVS_EX_FULLROWSELECT); - - ActualAccount = MyParam->account; - struct CMailWinUserInfo *mwui = new struct CMailWinUserInfo; - mwui->Account = ActualAccount; - mwui->TrayIconState = 0; - mwui->UpdateMailsMessagesAccess = FALSE; - mwui->Seen = FALSE; - mwui->RunFirstTime = TRUE; - - SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)mwui); - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) { - DestroyWindow(hDlg); - return FALSE; - } - - SetDlgItemText(hDlg, IDC_BTNAPP, TranslateT("Run application")); - SetDlgItemText(hDlg, IDC_BTNDEL, TranslateT("Delete selected")); - SetDlgItemText(hDlg, IDC_BTNCHECKALL, TranslateT("Select All")); - SetDlgItemText(hDlg, IDC_BTNOK, TranslateT("OK")); - - LVCOLUMN lvc0 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, FromWidth, TranslateT("From"), 0, 0}; - LVCOLUMN lvc1 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SubjectWidth, TranslateT("Subject"), 0, 0}; - LVCOLUMN lvc2 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SizeWidth, TranslateT("Size"), 0, 0}; - LVCOLUMN lvc3 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SizeDate, TranslateT("Date"), 0, 0}; - SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc0); - SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc1); - SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, (WPARAM)2, (LPARAM)&lvc2); - SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, (WPARAM)3, (LPARAM)&lvc3); - - if ((ActualAccount->NewMailN.App != nullptr) && (mir_wstrlen(ActualAccount->NewMailN.App))) - EnableWindow(GetDlgItem(hDlg, IDC_BTNAPP), TRUE); - else - EnableWindow(GetDlgItem(hDlg, IDC_BTNAPP), FALSE); - - ReadDoneFcn(ActualAccount->AccountAccessSO); - - WindowList_Add(YAMNVar.MessageWnds, hDlg); - WindowList_Add(YAMNVar.NewMailAccountWnd, hDlg, (UINT_PTR)ActualAccount); - - { - wchar_t accstatus[512]; - GetStatusFcn(ActualAccount, accstatus); - SetDlgItemText(hDlg, IDC_STSTATUS, accstatus); - } - SetTimer(hDlg, TIMER_FLASHING, 500, nullptr); - - if (ActualAccount->hContact != NULL) - g_clistApi.pfnRemoveEvent(ActualAccount->hContact, (LPARAM)"yamn new mail message"); - - mir_subclassWindow(GetDlgItem(hDlg, IDC_LISTMAILS), ListViewSubclassProc); - } - break; - - case WM_DESTROY: - { - RECT coord; - LVCOLUMN ColInfo; - HYAMNMAIL Parser; - - Window_FreeIcon_IcoLib(hDlg); - - struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER); - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - break; - ColInfo.mask = LVCF_WIDTH; - if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 0, &ColInfo)) - FromWidth = ColInfo.cx; - if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 1, &ColInfo)) - SubjectWidth = ColInfo.cx; - if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 2, &ColInfo)) - SizeWidth = ColInfo.cx; - if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 3, &ColInfo)) - SizeDate = ColInfo.cx; - - if (!YAMNVar.Shutdown && GetWindowRect(hDlg, &coord)) //the YAMNVar.Shutdown testing is because M<iranda strange functionality at shutdown phase, when call to DBWriteContactSetting freezes calling thread - { - PosX = coord.left; - SizeX = coord.right - coord.left; - PosY = coord.top; - SizeY = coord.bottom - coord.top; - g_plugin.setDword(YAMN_DBPOSX, PosX); - g_plugin.setDword(YAMN_DBPOSY, PosY); - g_plugin.setDword(YAMN_DBSIZEX, SizeX); - g_plugin.setDword(YAMN_DBSIZEY, SizeY); - } - KillTimer(hDlg, TIMER_FLASHING); - - WindowList_Remove(YAMNVar.NewMailAccountWnd, hDlg); - WindowList_Remove(YAMNVar.MessageWnds, hDlg); - - if (WAIT_OBJECT_0 != WaitToWriteFcn(ActualAccount->MessagesAccessSO)) - break; - - //delete mails from queue, which are deleted from server (spam level 3 mails e.g.) - for (Parser = (HYAMNMAIL)ActualAccount->Mails; Parser != nullptr; Parser = Parser->Next) { - if ((Parser->Flags & YAMN_MSG_DELETED) && YAMN_MSG_SPAML(Parser->Flags, YAMN_MSG_SPAML3) && mwui->Seen) //if spaml3 was already deleted and user knows about it - { - DeleteMessageFromQueueFcn((HYAMNMAIL *)&ActualAccount->Mails, Parser, 1); - CallService(MS_YAMN_DELETEACCOUNTMAIL, (WPARAM)ActualAccount->Plugin, (LPARAM)Parser); - } - } - - //mark mails as read (remove "new" and "unseen" flags) - if (mwui->Seen) - SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_DISPLAY, 0, YAMN_MSG_NEW | YAMN_MSG_UNSEEN, 0); - - WriteDoneFcn(ActualAccount->MessagesAccessSO); - - NOTIFYICONDATA nid; - memset(&nid, 0, sizeof(NOTIFYICONDATA)); - - delete mwui; - SetWindowLongPtr(hDlg, DWLP_USER, NULL); - - nid.cbSize = sizeof(NOTIFYICONDATA); - nid.hWnd = hDlg; - nid.uID = 0; - Shell_NotifyIcon(NIM_DELETE, &nid); - PostQuitMessage(0); - } - break; - - case WM_SHOWWINDOW: - { - struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER); - - if (mwui == nullptr) - return 0; - mwui->Seen = TRUE; - } - - case WM_YAMN_CHANGESTATUS: - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - break; - - if ((CAccount *)wParam != ActualAccount) - break; - - wchar_t accstatus[512]; - GetStatusFcn(ActualAccount, accstatus); - SetDlgItemText(hDlg, IDC_STSTATUS, accstatus); - return 1; - - case WM_YAMN_CHANGECONTENT: - { - struct CUpdateMails UpdateParams; - BOOL ThisThreadWindow = (GetCurrentThreadId() == GetWindowThreadProcessId(hDlg, nullptr)); - - if (nullptr == (UpdateParams.Copied = CreateEvent(nullptr, FALSE, FALSE, nullptr))) { - DestroyWindow(hDlg); - return 0; - } - UpdateParams.Flags = (struct CChangeContent *)lParam; - UpdateParams.Waiting = !ThisThreadWindow; - - if (ThisThreadWindow) { - if (!UpdateMails(hDlg, (CAccount *)wParam, UpdateParams.Flags->nflags, UpdateParams.Flags->nnflags)) - DestroyWindow(hDlg); - } - else if (PostMessage(hDlg, WM_YAMN_UPDATEMAILS, wParam, (LPARAM)&UpdateParams)) //this ensures UpdateMails will execute the thread who created the browser window - { - if (!ThisThreadWindow) - WaitForSingleObject(UpdateParams.Copied, INFINITE); - } - - CloseHandle(UpdateParams.Copied); - } - return 1; - case WM_YAMN_UPDATEMAILS: - { - struct CUpdateMails *um = (struct CUpdateMails *)lParam; - uint32_t nflags, nnflags; - - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - return 0; - if ((CAccount *)wParam != ActualAccount) - return 0; - - nflags = um->Flags->nflags; - nnflags = um->Flags->nnflags; - - if (um->Waiting) - SetEvent(um->Copied); - - if (!UpdateMails(hDlg, ActualAccount, nflags, nnflags)) - DestroyWindow(hDlg); - } - return 1; - case WM_YAMN_STOPACCOUNT: - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - break; - if ((CAccount *)wParam != ActualAccount) - break; - PostQuitMessage(0); - return 1; - - case WM_YAMN_NOTIFYICON: - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - break; - - switch (lParam) { - case WM_LBUTTONDBLCLK: - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) { - return 0; - } - - if (ActualAccount->AbilityFlags & YAMN_ACC_BROWSE) { - ShowWindow(hDlg, SW_SHOWNORMAL); - SetForegroundWindow(hDlg); - } - else DestroyWindow(hDlg); - - ReadDoneFcn(ActualAccount->AccountAccessSO); - break; - } - break; - - case WM_YAMN_SHOWSELECTED: - { - int iSelect = SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_GETNEXTITEM, -1, MAKELPARAM((UINT)LVNI_FOCUSED, 0)); // return item selected - if (iSelect != -1) { - LV_ITEMW item; - - item.iItem = iSelect; - item.iSubItem = 0; - item.mask = LVIF_PARAM | LVIF_STATE; - item.stateMask = 0xFFFFFFFF; - ListView_GetItem(GetDlgItem(hDlg, IDC_LISTMAILS), &item); - HYAMNMAIL ActualMail = (HYAMNMAIL)item.lParam; - if (nullptr != ActualMail) { - PYAMN_MAILSHOWPARAM MailParam = new YAMN_MAILSHOWPARAM; - MailParam->account = GetWindowAccount(hDlg); - MailParam->mail = ActualMail; - mir_forkthread(ShowEmailThread, MailParam); - } - } - } - break; - - case WM_SYSCOMMAND: - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - break; - switch (wParam) { - case SC_CLOSE: - DestroyWindow(hDlg); - break; - } - break; - - case WM_COMMAND: - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - break; - - switch (LOWORD(wParam)) { - case IDC_BTNCHECKALL: - ListView_SetItemState(GetDlgItem(hDlg, IDC_LISTMAILS), -1, 0, LVIS_SELECTED); // deselect all items - ListView_SetItemState(GetDlgItem(hDlg, IDC_LISTMAILS), -1, LVIS_SELECTED, LVIS_SELECTED); - Items = ListView_GetItemCount(GetDlgItem(hDlg, IDC_LISTMAILS)); - ListView_RedrawItems(GetDlgItem(hDlg, IDC_LISTMAILS), 0, Items); - UpdateWindow(GetDlgItem(hDlg, IDC_LISTMAILS)); - SetFocus(GetDlgItem(hDlg, IDC_LISTMAILS)); - break; - - case IDC_BTNOK: - DestroyWindow(hDlg); - break; - - case IDC_BTNAPP: - { - PROCESS_INFORMATION pi; - STARTUPINFOW si; - - memset(&si, 0, sizeof(si)); - si.cb = sizeof(si); - - if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { - if (ActualAccount->NewMailN.App != nullptr) { - wchar_t *Command; - if (ActualAccount->NewMailN.AppParam != nullptr) - Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6]; - else - Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + 6]; - - if (Command != nullptr) { - mir_wstrcpy(Command, L"\""); - mir_wstrcat(Command, ActualAccount->NewMailN.App); - mir_wstrcat(Command, L"\" "); - if (ActualAccount->NewMailN.AppParam != nullptr) - mir_wstrcat(Command, ActualAccount->NewMailN.AppParam); - CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi); - delete[] Command; - } - } - - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - - if (!(GetKeyState(VK_SHIFT) & 0x8000) && !(GetKeyState(VK_CONTROL) & 0x8000)) - DestroyWindow(hDlg); - } - break; - - case IDC_BTNDEL: - { - HYAMNMAIL ActualMail; - uint32_t Total = 0; - - // we use event to signal, that running thread has all needed stack parameters copied - HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (ThreadRunningEV == nullptr) - break; - - Items = ListView_GetItemCount(GetDlgItem(hDlg, IDC_LISTMAILS)); - - LVITEM item; - item.stateMask = 0xFFFFFFFF; - - if (WAIT_OBJECT_0 == WaitToWriteFcn(ActualAccount->MessagesAccessSO)) { - for (int i = 0; i < Items; i++) { - item.iItem = i; - item.iSubItem = 0; - item.mask = LVIF_PARAM | LVIF_STATE; - item.stateMask = 0xFFFFFFFF; - ListView_GetItem(GetDlgItem(hDlg, IDC_LISTMAILS), &item); - ActualMail = (HYAMNMAIL)item.lParam; - if (nullptr == ActualMail) - break; - if (item.state & LVIS_SELECTED) { - ActualMail->Flags |= YAMN_MSG_USERDELETE; //set to mail we are going to delete it - Total++; - } - } - - // Enable write-access to mails - WriteDoneFcn(ActualAccount->MessagesAccessSO); - - if (Total) { - wchar_t DeleteMsg[1024]; - - mir_snwprintf(DeleteMsg, TranslateT("Do you really want to delete %d selected mails?"), Total); - if (IDOK == MessageBox(hDlg, DeleteMsg, TranslateT("Delete confirmation"), MB_OKCANCEL | MB_ICONWARNING)) { - struct DeleteParam ParamToDeleteMails = {YAMN_DELETEVERSION, ThreadRunningEV, ActualAccount, nullptr}; - - // Find if there's mail marked to delete, which was deleted before - if (WAIT_OBJECT_0 == WaitToWriteFcn(ActualAccount->MessagesAccessSO)) { - for (ActualMail = (HYAMNMAIL)ActualAccount->Mails; ActualMail != nullptr; ActualMail = ActualMail->Next) { - if ((ActualMail->Flags & YAMN_MSG_DELETED) && ((ActualMail->Flags & YAMN_MSG_USERDELETE))) //if selected mail was already deleted - { - DeleteMessageFromQueueFcn((HYAMNMAIL *)&ActualAccount->Mails, ActualMail, 1); - CallService(MS_YAMN_DELETEACCOUNTMAIL, (WPARAM)ActualAccount->Plugin, (LPARAM)ActualMail); //delete it from memory - continue; - } - } - // Set flag to marked mails that they can be deleted - SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_DISPLAY | YAMN_MSG_USERDELETE, 0, YAMN_MSG_DELETEOK, 1); - // Create new thread which deletes marked mails. - HANDLE NewThread = mir_forkthread(ActualAccount->Plugin->Fcn->DeleteMailsFcnPtr, &ParamToDeleteMails); - if (NewThread != nullptr) - WaitForSingleObject(ThreadRunningEV, INFINITE); - - // Enable write-access to mails - WriteDoneFcn(ActualAccount->MessagesAccessSO); - } - } - else //else mark messages that they are not to be deleted - SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_DISPLAY | YAMN_MSG_USERDELETE, 0, YAMN_MSG_USERDELETE, 0); - } - } - CloseHandle(ThreadRunningEV); - if (g_plugin.getByte(YAMN_CLOSEDELETE, 0)) - DestroyWindow(hDlg); - } - break; - } - break; - - case WM_SIZE: - if (wParam == SIZE_RESTORED) { - LONG x = LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left; - LONG y = HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top; - MoveWindow(GetDlgItem(hDlg, IDC_BTNDEL), 5, y - 5 - 25, (x - 20) / 3, 25, TRUE); //where to put DELETE button while resizing - MoveWindow(GetDlgItem(hDlg, IDC_BTNCHECKALL), 10 + (x - 20) / 3, y - 5 - 25, (x - 20) / 6, 25, TRUE); //where to put CHECK ALL button while resizing - MoveWindow(GetDlgItem(hDlg, IDC_BTNAPP), 15 + (x - 20) / 3 + (x - 20) / 6, y - 5 - 25, (x - 20) / 3, 25, TRUE); //where to put RUN APP button while resizing - MoveWindow(GetDlgItem(hDlg, IDC_BTNOK), 20 + 2 * (x - 20) / 3 + (x - 20) / 6, y - 5 - 25, (x - 20) / 6, 25, TRUE); //where to put OK button while resizing - MoveWindow(GetDlgItem(hDlg, IDC_LISTMAILS), 5, 5, x - 10, y - 55, TRUE); //where to put list mail window while resizing - MoveWindow(GetDlgItem(hDlg, IDC_STSTATUS), 5, y - 5 - 45, x - 10, 15, TRUE); //where to put account status text while resizing - } - return 0; - - case WM_GETMINMAXINFO: - ((LPMINMAXINFO)lParam)->ptMinTrackSize.x = MAILBROWSER_MINXSIZE; - ((LPMINMAXINFO)lParam)->ptMinTrackSize.y = MAILBROWSER_MINYSIZE; - return 0; - - case WM_TIMER: - { - NOTIFYICONDATA nid; - struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER); - - memset(&nid, 0, sizeof(nid)); - nid.cbSize = sizeof(NOTIFYICONDATA); - nid.hWnd = hDlg; - nid.uID = 0; - nid.uFlags = NIF_ICON; - if (mwui->TrayIconState == 0) - nid.hIcon = g_plugin.getIcon(IDI_CHECKMAIL); - else - nid.hIcon = g_plugin.getIcon(IDI_NEWMAIL); - Shell_NotifyIcon(NIM_MODIFY, &nid); - mwui->TrayIconState = !mwui->TrayIconState; - // UpdateWindow(hDlg); - } - break; - - case WM_NOTIFY: - switch (((LPNMHDR)lParam)->idFrom) { - case IDC_LISTMAILS: - switch (((LPNMHDR)lParam)->code) { - case NM_DBLCLK: - SendMessage(hDlg, WM_YAMN_SHOWSELECTED, 0, 0); - break; - - case LVN_COLUMNCLICK: - if (nullptr != (ActualAccount = GetWindowAccount(hDlg))) { - NM_LISTVIEW *pNMListView = (NM_LISTVIEW *)lParam; - if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { - switch ((int)pNMListView->iSubItem) { - case 0: - bFrom = !bFrom; - break; - case 1: - bSub = !bSub; - break; - case 2: - bSize = !bSize; - break; - case 3: - bDate = !bDate; - break; - default: - break; - } - ListView_SortItems(pNMListView->hdr.hwndFrom, ListViewCompareProc, pNMListView->iSubItem); - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - } - break; - - case NM_CUSTOMDRAW: - { - LPNMLVCUSTOMDRAW cd = (LPNMLVCUSTOMDRAW)lParam; - LONG_PTR PaintCode; - - if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) - break; - - switch (cd->nmcd.dwDrawStage) { - case CDDS_PREPAINT: - PaintCode = CDRF_NOTIFYITEMDRAW; - break; - case CDDS_ITEMPREPAINT: - PaintCode = CDRF_NOTIFYSUBITEMDRAW; - break; - case CDDS_ITEMPREPAINT | CDDS_SUBITEM: - { - BOOL umma; - { - struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER); - umma = mwui->UpdateMailsMessagesAccess; - } - HYAMNMAIL ActualMail = (HYAMNMAIL)cd->nmcd.lItemlParam; - if (!ActualMail) - ActualMail = (HYAMNMAIL)readItemLParam(cd->nmcd.hdr.hwndFrom, cd->nmcd.dwItemSpec); - - if (!umma) - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->MessagesAccessSO)) - return 0; - - switch (ActualMail->Flags & YAMN_MSG_SPAMMASK) { - case YAMN_MSG_SPAML1: - case YAMN_MSG_SPAML2: - cd->clrText = RGB(150, 150, 150); - break; - case YAMN_MSG_SPAML3: - cd->clrText = RGB(200, 200, 200); - cd->clrTextBk = RGB(160, 160, 160); - break; - case 0: - if (cd->nmcd.dwItemSpec & 1) - cd->clrTextBk = RGB(230, 230, 230); - break; - default: - break; - } - if (ActualMail->Flags & YAMN_MSG_UNSEEN) - cd->clrTextBk = RGB(220, 235, 250); - PaintCode = CDRF_DODEFAULT; - - if (!umma) - ReadDoneFcn(ActualAccount->MessagesAccessSO); - break; - } - default: - PaintCode = 0; - } - SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PaintCode); - return 1; - } - } - } - break; - - case WM_CONTEXTMENU: - if (GetWindowLongPtr((HWND)wParam, GWLP_ID) == IDC_LISTMAILS) { - //MessageBox(0,"LISTHEADERS","Debug",0); - HWND hList = GetDlgItem(hDlg, IDC_LISTMAILS); - POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)}; - if (pt.x == -1) pt.x = 0; - if (pt.y == -1) pt.y = 0; - if (int numRows = ListView_GetItemCount(hList)) { - HMENU hMenu = CreatePopupMenu(); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)1, TranslateT("Copy Selected")); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)2, TranslateT("Copy All")); - AppendMenu(hMenu, MF_SEPARATOR, 0, nullptr); - AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel")); - int nReturnCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hDlg, nullptr); - DestroyMenu(hMenu); - if (nReturnCmd > 0) { - int courRow = 0; - size_t sizeNeeded = 0; - wchar_t from[128] = {0}, subject[256] = {0}, size[16] = {0}, date[64] = {0}; - for (courRow = 0; courRow < numRows; courRow++) { - if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue; - ListView_GetItemText(hList, courRow, 0, from, _countof(from)); - ListView_GetItemText(hList, courRow, 1, subject, _countof(subject)); - ListView_GetItemText(hList, courRow, 2, size, _countof(size)); - ListView_GetItemText(hList, courRow, 3, date, _countof(date)); - sizeNeeded += 5 + mir_wstrlen(from) + mir_wstrlen(subject) + mir_wstrlen(size) + mir_wstrlen(date); - } - if (sizeNeeded && OpenClipboard(hDlg)) { - EmptyClipboard(); - HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, (sizeNeeded + 1) * sizeof(wchar_t)); - wchar_t *buff = (wchar_t *)GlobalLock(hData); - int courPos = 0; - for (courRow = 0; courRow < numRows; courRow++) { - if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue; - ListView_GetItemText(hList, courRow, 0, from, _countof(from)); - ListView_GetItemText(hList, courRow, 1, subject, _countof(subject)); - ListView_GetItemText(hList, courRow, 2, size, _countof(size)); - ListView_GetItemText(hList, courRow, 3, date, _countof(date)); - courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"%s\t%s\t%s\t%s\r\n", from, subject, size, date); - } - GlobalUnlock(hData); - - SetClipboardData(CF_UNICODETEXT, hData); - - CloseClipboard(); - } - } - } - } - break; // just in case - } - return 0; -} - -LRESULT CALLBACK ListViewSubclassProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - HWND hwndParent = GetParent(hDlg); - - switch (msg) { - case WM_GETDLGCODE: - { - LPMSG lpmsg = (LPMSG)lParam; - if (lpmsg != nullptr) { - if (lpmsg->message == WM_KEYDOWN - && lpmsg->wParam == VK_RETURN) - return DLGC_WANTALLKEYS; - } - } - break; - - case WM_KEYDOWN: - { - BOOL isCtrl = GetKeyState(VK_CONTROL) & 0x8000; - BOOL isShift = GetKeyState(VK_SHIFT) & 0x8000; - BOOL isAlt = GetKeyState(VK_MENU) & 0x8000; - - switch (wParam) { - case 'A': // ctrl-a - if (!isAlt && !isShift && isCtrl) SendMessage(hwndParent, WM_COMMAND, IDC_BTNCHECKALL, 0); - break; - case VK_RETURN: - case VK_SPACE: - if (!isAlt && !isShift && !isCtrl) SendMessage(hwndParent, WM_YAMN_SHOWSELECTED, 0, 0); - break; - case VK_DELETE: - SendMessage(hwndParent, WM_COMMAND, IDC_BTNDEL, 0); - break; - } - } - break; - } - return mir_callNextSubclass(hDlg, ListViewSubclassProc, msg, wParam, lParam); -} - -void __cdecl MailBrowser(void *Param) -{ - MSG msg; - - HWND hMailBrowser; - BOOL WndFound = FALSE; - - struct MailBrowserWinParam MyParam = *(struct MailBrowserWinParam *)Param; - CAccount *ActualAccount = MyParam.account; - SCIncFcn(ActualAccount->UsingThreads); - - // we will not use params in stack anymore - SetEvent(MyParam.ThreadRunningEV); - - __try { - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) - return; - - if (!(ActualAccount->AbilityFlags & YAMN_ACC_BROWSE)) { - MyParam.nflags = MyParam.nflags & ~YAMN_ACC_MSG; - MyParam.nnflags = MyParam.nnflags & ~YAMN_ACC_MSG; - } - - if (!(ActualAccount->AbilityFlags & YAMN_ACC_POPUP)) - MyParam.nflags = MyParam.nflags & ~YAMN_ACC_POP; - - ReadDoneFcn(ActualAccount->AccountAccessSO); - - if (nullptr != (hMailBrowser = WindowList_Find(YAMNVar.NewMailAccountWnd, (UINT_PTR)ActualAccount))) - WndFound = TRUE; - - if ((hMailBrowser == nullptr) && ((MyParam.nflags & YAMN_ACC_MSG) || (MyParam.nflags & YAMN_ACC_ICO) || (MyParam.nnflags & YAMN_ACC_MSG))) { - hMailBrowser = CreateDialogParamW(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_DLGVIEWMESSAGES), nullptr, DlgProcYAMNMailBrowser, (LPARAM)&MyParam); - Window_SetIcon_IcoLib(hMailBrowser, g_plugin.getIconHandle(IDI_NEWMAIL)); - MoveWindow(hMailBrowser, PosX, PosY, SizeX, SizeY, TRUE); - } - - if (hMailBrowser != nullptr) { - struct CChangeContent Params = {MyParam.nflags, MyParam.nnflags}; //if this thread created window, just post message to update mails - - SendMessage(hMailBrowser, WM_YAMN_CHANGECONTENT, (WPARAM)ActualAccount, (LPARAM)&Params); //we ensure this will do the thread who created the browser window - } - else - UpdateMails(nullptr, ActualAccount, MyParam.nflags, MyParam.nnflags); //update mails without displaying or refreshing any window - - if ((hMailBrowser != nullptr) && !WndFound) { //we process message loop only for thread that created window - while (GetMessage(&msg, nullptr, 0, 0)) { - if (hMailBrowser == nullptr || !IsDialogMessage(hMailBrowser, &msg)) { /* Wine fix. */ - TranslateMessage(&msg); - DispatchMessage(&msg); - } - } - } - - if ((!WndFound) && (ActualAccount->Plugin->Fcn != nullptr) && (ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr != nullptr) && ActualAccount->AbleToWork) - ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr(); - } - __finally { - SCDecFcn(ActualAccount->UsingThreads); - } -} - -INT_PTR RunMailBrowserSvc(WPARAM wParam, LPARAM lParam) -{ - PYAMN_MAILBROWSERPARAM Param = (PYAMN_MAILBROWSERPARAM)wParam; - - if ((uint32_t)lParam != YAMN_MAILBROWSERVERSION) - return 0; - - //an event for successfull copy parameters to which point a pointer in stack for new thread - HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr); - Param->ThreadRunningEV = ThreadRunningEV; - - HANDLE NewThread = mir_forkthread(MailBrowser, Param); - if (NewThread != nullptr) - WaitForSingleObject(ThreadRunningEV, INFINITE); - - CloseHandle(ThreadRunningEV); - return 1; -} +/*
+ * This code implements window handling (new mail)
+ *
+ * (c) majvan 2002-2004
+ */
+ /* There can be problems when compiling this file, because in this file
+ * we are using both unicode and no-unicode functions and compiler does not
+ * like it in one file
+ * When you got errors, try to comment the #define <stdio.h> and compile, then
+ * put it back to uncommented and compile again :)
+ */
+
+#include "../stdafx.h"
+
+#define TIMER_FLASHING 0x09061979
+#define MAILBROWSER_MINXSIZE 200 //min size of mail browser window
+#define MAILBROWSER_MINYSIZE 130
+
+#define MAILBROWSERTITLE LPGEN("%s - %d new mail messages, %d total")
+
+void __cdecl ShowEmailThread(void *Param);
+
+//--------------------------------------------------------------------------------------------------
+char *s_MonthNames[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"};
+bool bDate = false, bSub = false, bSize = false, bFrom = false;
+int PosX = 0, PosY = 0, SizeX = 460, SizeY = 100;
+int HeadSizeX = 0x2b2, HeadSizeY = 0x0b5, HeadPosX = 100, HeadPosY = 100;
+int HeadSplitPos = 250; // per-mils of the size
+static int FromWidth = 250, SubjectWidth = 280, SizeWidth = 50, SizeDate = 205;
+unsigned char optDateTime = (SHOWDATELONG | SHOWDATENOTODAY);
+
+struct CMailNumbersSub
+{
+ int Total; //any mail
+ int New; //uses YAMN_MSG_NEW flag
+ int UnSeen; //uses YAMN_MSG_UNSEEN flag
+ // int Browser; //uses YAMN_MSG_BROWSER flag
+ int BrowserUC; //uses YAMN_MSG_BROWSER flag and YAMN_MSG_UNSEEN flag
+ int Display; //uses YAMN_MSG_DISPLAY flag
+ int DisplayTC; //uses YAMN_MSG_DISPLAY flag and YAMN_MSG_DISPLAYC flag
+ int DisplayUC; //uses YAMN_MSG_DISPLAY flag and YAMN_MSG_DISPLAYC flag and YAMN_MSG_UNSEEN flag
+ int Popup; //uses YAMN_MSG_POPUP flag
+ int PopupTC; //uses YAMN_MSG_POPUPC flag
+ int PopupNC; //uses YAMN_MSG_POPUPC flag and YAMN_MSG_NEW flag
+ int PopupRun; //uses YAMN_MSG_POPUP flag and YAMN_MSG_NEW flag
+ int PopupSL2NC; //uses YAMN_MSG_SPAML2 flag and YAMN_MSG_NEW flag
+ int PopupSL3NC; //uses YAMN_MSG_SPAML3 flag and YAMN_MSG_NEW flag
+ // int SysTray; //uses YAMN_MSG_SYSTRAY flag
+ int SysTrayUC; //uses YAMN_MSG_SYSTRAY flag and YAMN_MSG_UNSEEN flag
+ // int Sound; //uses YAMN_MSG_SOUND flag
+ int SoundNC; //uses YAMN_MSG_SOUND flag and YAMN_MSG_NEW flag
+ // int App; //uses YAMN_MSG_APP flag
+ int AppNC; //uses YAMN_MSG_APP flag and YAMN_MSG_NEW flag
+ int EventNC; //uses YAMN_MSG_NEVENT flag and YAMN_MSG_NEW flag
+};
+
+struct CMailNumbers
+{
+ struct CMailNumbersSub Real;
+ struct CMailNumbersSub Virtual;
+};
+
+struct CMailWinUserInfo
+{
+ CAccount *Account;
+ int TrayIconState;
+ BOOL UpdateMailsMessagesAccess;
+ BOOL Seen;
+ BOOL RunFirstTime;
+};
+
+struct CChangeContent
+{
+ uint32_t nflags;
+ uint32_t nnflags;
+};
+
+struct CUpdateMails
+{
+ struct CChangeContent *Flags;
+ BOOL Waiting;
+ HANDLE Copied;
+};
+
+struct CSortList
+{
+ HWND hDlg;
+ int iSubItem;
+};
+
+// Retrieves CAccount *, whose mails are displayed in ListMails
+// hLM- handle of dialog window
+// returns handle of account
+inline CAccount *GetWindowAccount(HWND hDialog);
+
+// Looks to mail flags and increment mail counter (e.g. if mail is new, increments the new mail counter
+// msgq- mail, which increments the counters
+// MN- counnters structure
+void IncrementMailCounters(HYAMNMAIL msgq, struct CMailNumbers *MN);
+
+enum
+{
+ UPDATE_FAIL = 0, //function failed
+ UPDATE_NONE, //none update has been performed
+ UPDATE_OK, //some changes occured, update performed
+};
+
+// Just looks for mail changes in account and update the mail browser window
+// hDlg- dialog handle
+// ActualAccount- account handle
+// nflags- flags what to do when new mail arrives
+// nnflags- flags what to do when no new mail arrives
+// returns one of UPDATE_XXX value(not implemented yet)
+int UpdateMails(HWND hDlg, CAccount *ActualAccount, uint32_t nflags, uint32_t nnflags);
+
+// When new mail occurs, shows window, plays sound, runs application...
+// hDlg- dialog handle. Dialog of mailbrowser is already created and actions are performed over this window
+// ActualAccount- handle of account, whose mails are to be notified
+// MN- statistics of mails in account
+// nflags- what to do or not to do (e.g. to show mailbrowser window or prohibit to show)
+// nflags- flags what to do when new mail arrives
+// nnflags- flags what to do when no new mail arrives
+void DoMailActions(HWND hDlg, CAccount *ActualAccount, struct CMailNumbers *MN, uint32_t nflags, uint32_t nnflags);
+
+// Looks for items in mailbrowser and if they were deleted, delete them from browser window
+// hListView- handle of listview window
+// ActualAccount- handle of account, whose mails are show
+// MailNumbers- pointer to structure, in which function stores numbers of mails with some property
+// returns one of UPDATE_XXX value (not implemented yet)
+int ChangeExistingMailStatus(HWND hListView, CAccount *ActualAccount);
+
+// Adds new mails to ListView and if any new, shows multi popup (every new message is new popup window created by popup plugin)
+// hListView- handle of listview window
+// ActualAccount- handle of account, whose mails are show
+// NewMailPopup- pointer to prepared structure for popup plugin, can be NULL if no popup show
+// MailNumbers- pointer to structure, in which function stores numbers of mails with some property
+// nflags- flags what to do when new mail arrives
+// returns one of UPDATE_XXX value (not implemented yet)
+int AddNewMailsToListView(HWND hListView, CAccount *ActualAccount, uint32_t nflags);
+
+// Window callback procedure for popup window (created by popup plugin)
+LRESULT CALLBACK NewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// Window callback procedure for popup window (created by popup plugin)
+LRESULT CALLBACK NoNewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// Dialog callback procedure for mail browser
+INT_PTR CALLBACK DlgProcYAMNMailBrowser(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// MailBrowser thread function creates window if needed, tray icon and plays sound
+void __cdecl MailBrowser(void *Param);
+
+LRESULT CALLBACK ListViewSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
+
+// Runs mail browser in new thread
+INT_PTR RunMailBrowserSvc(WPARAM, LPARAM);
+
+#define YAMN_BROWSER_SHOWPOPUP 0x01
+
+// list view items' order criteria
+#define LVORDER_NOORDER -1
+#define LVORDER_STRING 0
+#define LVORDER_NUMERIC 1
+#define LVORDER_DATETIME 2
+
+// list view order direction
+#define LVORDER_ASCENDING 1
+#define LVORDER_NONE 0
+#define LVORDER_DESCENDING -1
+
+// list view sort type
+#define LVSORTPRIORITY_NONE -1
+
+// List view column info.
+typedef struct _SAMPLELISTVIEWCOLUMN
+{
+ UINT uCXCol; // index
+ int nSortType; // sorting type (STRING = 0, NUMERIC, DATE, DATETIME)
+ int nSortOrder; // sorting order (ASCENDING = -1, NONE, DESCENDING)
+ int nPriority; // sort priority (-1 for none, 0, 1, ..., nColumns - 1 maximum)
+ wchar_t lpszName[128]; // column name
+} SAMPLELISTVIEWCOLUMN;
+
+// Compare priority
+typedef struct _LVCOMPAREINFO
+{
+ int iIdx; // Index
+ int iPriority; // Priority
+} LVCOMPAREINFO, *LPLVCOMPAREINFO;
+
+//--------------------------------------------------------------------------------------------------
+
+LPARAM readItemLParam(HWND hwnd, uint32_t iItem)
+{
+ LVITEM item;
+ item.mask = LVIF_PARAM;
+ item.iItem = iItem;
+ item.iSubItem = 0;
+ SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM)&item);
+ return item.lParam;
+}
+
+inline CAccount *GetWindowAccount(HWND hDlg)
+{
+ struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+
+ return (mwui == nullptr) ? nullptr : mwui->Account;
+}
+
+void IncrementMailCounters(HYAMNMAIL msgq, struct CMailNumbers *MN)
+{
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.Total++;
+ else
+ MN->Real.Total++;
+
+ if (msgq->Flags & YAMN_MSG_NEW)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.New++;
+ else
+ MN->Real.New++;
+ if (msgq->Flags & YAMN_MSG_UNSEEN)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.UnSeen++;
+ else
+ MN->Real.UnSeen++;
+ if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_BROWSER)) == (YAMN_MSG_UNSEEN | YAMN_MSG_BROWSER))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.BrowserUC++;
+ else
+ MN->Real.BrowserUC++;
+ if (msgq->Flags & YAMN_MSG_DISPLAY)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.Display++;
+ else
+ MN->Real.Display++;
+ if ((msgq->Flags & (YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) == (YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.DisplayTC++;
+ else
+ MN->Real.DisplayTC++;
+ if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY)) == (YAMN_MSG_UNSEEN | YAMN_MSG_DISPLAYC | YAMN_MSG_DISPLAY))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.DisplayUC++;
+ else
+ MN->Real.DisplayUC++;
+ if (msgq->Flags & YAMN_MSG_POPUP)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.Popup++;
+ else
+ MN->Real.Popup++;
+ if ((msgq->Flags & YAMN_MSG_POPUPC) == YAMN_MSG_POPUPC)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.PopupTC++;
+ else
+ MN->Real.PopupTC++;
+ if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_POPUPC)) == (YAMN_MSG_NEW | YAMN_MSG_POPUPC))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.PopupNC++;
+ else
+ MN->Real.PopupNC++;
+ if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_POPUP)) == (YAMN_MSG_NEW | YAMN_MSG_POPUP))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.PopupRun++;
+ else
+ MN->Real.PopupRun++;
+ if ((msgq->Flags & YAMN_MSG_NEW) && YAMN_MSG_SPAML(msgq->Flags, YAMN_MSG_SPAML2))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.PopupSL2NC++;
+ else
+ MN->Real.PopupSL2NC++;
+ if ((msgq->Flags & YAMN_MSG_NEW) && YAMN_MSG_SPAML(msgq->Flags, YAMN_MSG_SPAML3))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.PopupSL3NC++;
+ else
+ MN->Real.PopupSL3NC++;
+ /* if (msgq->MailData->Flags & YAMN_MSG_SYSTRAY)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.SysTray++;
+ else
+ MN->Real.SysTray++;
+ */ if ((msgq->Flags & (YAMN_MSG_UNSEEN | YAMN_MSG_SYSTRAY)) == (YAMN_MSG_UNSEEN | YAMN_MSG_SYSTRAY))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.SysTrayUC++;
+ else
+ MN->Real.SysTrayUC++;
+ /* if (msgq->MailData->Flags & YAMN_MSG_SOUND)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.Sound++;
+ else
+ MN->Real.Sound++;
+ */ if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_SOUND)) == (YAMN_MSG_NEW | YAMN_MSG_SOUND))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.SoundNC++;
+ else
+ MN->Real.SoundNC++;
+ /* if (msgq->MailData->Flags & YAMN_MSG_APP)
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.App++;
+ else
+ MN->Real.App++;
+ */ if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_APP)) == (YAMN_MSG_NEW | YAMN_MSG_APP))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.AppNC++;
+ else
+ MN->Real.AppNC++;
+ if ((msgq->Flags & (YAMN_MSG_NEW | YAMN_MSG_NEVENT)) == (YAMN_MSG_NEW | YAMN_MSG_NEVENT))
+ if (msgq->Flags & YAMN_MSG_VIRTUAL)
+ MN->Virtual.EventNC++;
+ else
+ MN->Real.EventNC++;
+}
+
+int UpdateMails(HWND hDlg, CAccount *ActualAccount, uint32_t nflags, uint32_t nnflags)
+{
+ struct CMailNumbers MN;
+
+ BOOL Loaded;
+ BOOL RunMailBrowser, RunPopups;
+
+ struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+ //now we ensure read access for account and write access for its mails
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ PostMessage(hDlg, WM_DESTROY, 0, 0);
+ return UPDATE_FAIL;
+ }
+
+ if (WAIT_OBJECT_0 != WaitToWriteFcn(ActualAccount->MessagesAccessSO)) {
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ PostMessage(hDlg, WM_DESTROY, 0, 0);
+ return UPDATE_FAIL;
+ }
+
+ memset(&MN, 0, sizeof(MN));
+
+ for (HYAMNMAIL msgq = (HYAMNMAIL)ActualAccount->Mails; msgq != nullptr; msgq = msgq->Next) {
+ if (!LoadedMailData(msgq)) //check if mail is already in memory
+ {
+ Loaded = false;
+ if (nullptr == LoadMailData(msgq)) //if we could not load mail to memory, consider this mail deleted and do not display it
+ continue;
+ }
+ else
+ Loaded = true;
+
+ IncrementMailCounters(msgq, &MN);
+
+ if (!Loaded)
+ UnloadMailData(msgq); //do not keep data for mail in memory
+ }
+
+ if (mwui != nullptr)
+ mwui->UpdateMailsMessagesAccess = TRUE;
+
+ //Now we are going to check if extracting data from mail headers are needed.
+ //If popups will be displayed or mailbrowser window
+ if ((((mwui != nullptr) && !(mwui->RunFirstTime)) &&
+ (
+ ((nnflags & YAMN_ACC_MSGP) && !(MN.Real.BrowserUC + MN.Virtual.BrowserUC)) ||
+ ((nflags & YAMN_ACC_MSGP) && (MN.Real.BrowserUC + MN.Virtual.BrowserUC))
+ )
+ ) || //if mail window was displayed before and flag YAMN_ACC_MSGP is set
+ ((nnflags & YAMN_ACC_MSG) && !(MN.Real.BrowserUC + MN.Virtual.BrowserUC)) || //if needed to run mailbrowser when no unseen and no unseen mail found
+ ((nflags & YAMN_ACC_MSG) && (MN.Real.BrowserUC + MN.Virtual.BrowserUC)) || //if unseen mails found, we sure run mailbrowser
+ ((nflags & YAMN_ACC_ICO) && (MN.Real.SysTrayUC + MN.Virtual.SysTrayUC))
+ ) //if needed to run systray
+ RunMailBrowser = TRUE;
+ else
+ RunMailBrowser = FALSE;
+
+ // if some popups with mails are needed to show
+ if ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (MN.Real.PopupNC + MN.Virtual.PopupNC))
+ RunPopups = TRUE;
+ else RunPopups = FALSE;
+
+ if (RunMailBrowser)
+ ChangeExistingMailStatus(GetDlgItem(hDlg, IDC_LISTMAILS), ActualAccount);
+ if (RunMailBrowser || RunPopups)
+ AddNewMailsToListView(hDlg == nullptr ? nullptr : GetDlgItem(hDlg, IDC_LISTMAILS), ActualAccount, nflags);
+
+ if (RunMailBrowser) {
+ size_t len = mir_strlen(ActualAccount->Name) + mir_strlen(Translate(MAILBROWSERTITLE)) + 10; //+10 chars for numbers
+ char *TitleStrA = new char[len];
+ wchar_t *TitleStrW = new wchar_t[len];
+
+ mir_snprintf(TitleStrA, len, Translate(MAILBROWSERTITLE), ActualAccount->Name, MN.Real.DisplayUC + MN.Virtual.DisplayUC, MN.Real.Display + MN.Virtual.Display);
+ MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, TitleStrA, -1, TitleStrW, (int)mir_strlen(TitleStrA) + 1);
+ SetWindowTextW(hDlg, TitleStrW);
+ delete[] TitleStrA;
+ delete[] TitleStrW;
+ }
+
+ DoMailActions(hDlg, ActualAccount, &MN, nflags, nnflags);
+
+ SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_NEW, 0, YAMN_MSG_NEW, YAMN_FLAG_REMOVE); //rempve the new flag
+ if (!RunMailBrowser)
+ SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_UNSEEN, YAMN_MSG_STAYUNSEEN, YAMN_MSG_UNSEEN, YAMN_FLAG_REMOVE); //remove the unseen flag when it was not displayed and it has not "stay unseen" flag set
+
+ if (mwui != nullptr) {
+ mwui->UpdateMailsMessagesAccess = FALSE;
+ mwui->RunFirstTime = FALSE;
+ }
+
+ WriteDoneFcn(ActualAccount->MessagesAccessSO);
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ if (RunMailBrowser)
+ UpdateWindow(GetDlgItem(hDlg, IDC_LISTMAILS));
+ else if (hDlg != nullptr)
+ DestroyWindow(hDlg);
+
+ return 1;
+}
+
+int ChangeExistingMailStatus(HWND hListView, CAccount *ActualAccount)
+{
+ LVITEM item;
+ HYAMNMAIL mail, msgq;
+
+ int in = ListView_GetItemCount(hListView);
+ item.mask = LVIF_PARAM;
+
+ for (int i = 0; i < in; i++) {
+ item.iItem = i;
+ item.iSubItem = 0;
+ if (TRUE == ListView_GetItem(hListView, &item))
+ mail = (HYAMNMAIL)item.lParam;
+ else
+ continue;
+ for (msgq = (HYAMNMAIL)ActualAccount->Mails; (msgq != nullptr) && (msgq != mail); msgq = msgq->Next); //found the same mail in account queue
+ if (msgq == nullptr) //if mail was not found
+ if (TRUE == ListView_DeleteItem(hListView, i)) {
+ in--; i--;
+ continue;
+ }
+ }
+
+ return TRUE;
+}
+
+void MimeDateToLocalizedDateTime(char *datein, wchar_t *dateout, int lendateout);
+int AddNewMailsToListView(HWND hListView, CAccount *ActualAccount, uint32_t nflags)
+{
+ wchar_t *FromStr;
+ wchar_t SizeStr[20];
+ wchar_t LocalDateStr[128];
+
+ LVITEMW item;
+ LVFINDINFO fi;
+
+ int foundi = 0, lfoundi = 0;
+ struct CHeader UnicodeHeader;
+ BOOL Loaded, Extracted, FromStrNew = FALSE;
+
+ memset(&item, 0, sizeof(item));
+ memset(&UnicodeHeader, 0, sizeof(UnicodeHeader));
+
+ if (hListView != nullptr) {
+ item.mask = LVIF_TEXT | LVIF_PARAM;
+ item.iItem = 0;
+ memset(&fi, 0, sizeof(fi));
+ fi.flags = LVFI_PARAM; //let's go search item by lParam number
+ lfoundi = 0;
+ }
+
+ POPUPDATAW NewMailPopup = {};
+ NewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount;
+ NewMailPopup.lchIcon = g_plugin.getIcon(IDI_NEWMAIL);
+ if (nflags & YAMN_ACC_POPC) {
+ NewMailPopup.colorBack = ActualAccount->NewMailN.PopupB;
+ NewMailPopup.colorText = ActualAccount->NewMailN.PopupT;
+ }
+ else {
+ NewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE);
+ NewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ NewMailPopup.iSeconds = ActualAccount->NewMailN.PopupTime;
+
+ NewMailPopup.PluginWindowProc = NewMailPopupProc;
+ NewMailPopup.PluginData = nullptr; //it's new mail popup
+
+ for (HYAMNMAIL msgq = (HYAMNMAIL)ActualAccount->Mails; msgq != nullptr; msgq = msgq->Next, lfoundi++) {
+ // now we hide mail pointer to item's lParam member. We can later use it to retrieve mail datas
+
+ Extracted = FALSE; FromStr = nullptr; FromStrNew = FALSE;
+
+ if (hListView != nullptr) {
+ fi.lParam = (LPARAM)msgq;
+ if (-1 != (foundi = ListView_FindItem(hListView, -1, &fi))) { // if mail is already in window
+ lfoundi = foundi;
+ continue; // do not insert any item
+ }
+
+ item.iItem = lfoundi; // insert after last found item
+ item.lParam = (LPARAM)msgq;
+ }
+
+ if (!LoadedMailData(msgq)) { // check if mail is already in memory
+ Loaded = false;
+ if (nullptr == LoadMailData(msgq)) //if we could not load mail to memory, consider this mail deleted and do not display it
+ continue;
+ }
+ else Loaded = true;
+
+ if (((hListView != nullptr) && (msgq->Flags & YAMN_MSG_DISPLAY)) ||
+ ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (msgq->Flags & YAMN_MSG_POPUP) && (msgq->Flags & YAMN_MSG_NEW))) {
+
+ if (!Extracted) ExtractHeader(msgq->MailData->TranslatedHeader, msgq->MailData->CP, &UnicodeHeader);
+ Extracted = TRUE;
+
+ if ((UnicodeHeader.From != nullptr) && (UnicodeHeader.FromNick != nullptr)) {
+ size_t size = mir_wstrlen(UnicodeHeader.From) + mir_wstrlen(UnicodeHeader.FromNick) + 4;
+ FromStr = new wchar_t[size];
+ mir_snwprintf(FromStr, size, L"%s <%s>", UnicodeHeader.FromNick, UnicodeHeader.From);
+ FromStrNew = TRUE;
+ }
+ else if (UnicodeHeader.From != nullptr)
+ FromStr = UnicodeHeader.From;
+ else if (UnicodeHeader.FromNick != nullptr)
+ FromStr = UnicodeHeader.FromNick;
+ else if (UnicodeHeader.ReturnPath != nullptr)
+ FromStr = UnicodeHeader.ReturnPath;
+
+ if (nullptr == FromStr) {
+ FromStr = L"";
+ FromStrNew = FALSE;
+ }
+ }
+
+ if ((hListView != nullptr) && (msgq->Flags & YAMN_MSG_DISPLAY)) {
+ item.iSubItem = 0;
+ item.pszText = FromStr;
+ item.iItem = SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&item);
+
+ item.iSubItem = 1;
+ item.pszText = (nullptr != UnicodeHeader.Subject ? UnicodeHeader.Subject : (wchar_t *)L"");
+ SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item);
+
+ item.iSubItem = 2;
+ mir_snwprintf(SizeStr, L"%d kB", msgq->MailData->Size / 1024);
+ item.pszText = SizeStr;
+ SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item);
+
+ item.iSubItem = 3;
+ item.pszText = L"";
+
+ for (CMimeItem *heads = msgq->MailData->TranslatedHeader; heads != nullptr; heads = heads->Next) {
+ if (!_stricmp(heads->name, "Date")) {
+ MimeDateToLocalizedDateTime(heads->value, LocalDateStr, 128);
+ item.pszText = LocalDateStr;
+ break;
+ }
+ }
+ SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item);
+ }
+
+ if ((nflags & YAMN_ACC_POP) && (ActualAccount->Flags & YAMN_ACC_POPN) && (msgq->Flags & YAMN_MSG_POPUP) && (msgq->Flags & YAMN_MSG_NEW)) {
+ mir_wstrncpy(NewMailPopup.lpwzContactName, FromStr, _countof(NewMailPopup.lpwzContactName));
+ mir_wstrncpy(NewMailPopup.lpwzText, UnicodeHeader.Subject, _countof(NewMailPopup.lpwzText));
+
+ PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)malloc(sizeof(YAMN_MAILSHOWPARAM));
+ if (MailParam) {
+ MailParam->account = ActualAccount;
+ MailParam->mail = msgq;
+ MailParam->ThreadRunningEV = nullptr;
+ NewMailPopup.PluginData = MailParam;
+ PUAddPopupW(&NewMailPopup);
+ }
+ }
+
+ if ((msgq->Flags & YAMN_MSG_UNSEEN) && (ActualAccount->NewMailN.Flags & YAMN_ACC_KBN))
+ CallService(MS_KBDNOTIFY_EVENTSOPENED, 1, NULL);
+
+ if (FromStrNew)
+ delete[] FromStr;
+
+ if (Extracted) {
+ DeleteHeaderContent(&UnicodeHeader);
+ memset(&UnicodeHeader, 0, sizeof(UnicodeHeader));
+ }
+
+ if (!Loaded) {
+ SaveMailData(msgq);
+ UnloadMailData(msgq); //do not keep data for mail in memory
+ }
+ }
+
+ return TRUE;
+}
+
+void DoMailActions(HWND hDlg, CAccount *ActualAccount, struct CMailNumbers *MN, uint32_t nflags, uint32_t nnflags)
+{
+ NOTIFYICONDATA nid = {};
+ nid.cbSize = sizeof(nid);
+ nid.hWnd = hDlg;
+
+ if (MN->Real.EventNC + MN->Virtual.EventNC)
+ NotifyEventHooks(hNewMailHook, 0, 0);
+
+ if ((nflags & YAMN_ACC_KBN) && (MN->Real.PopupRun + MN->Virtual.PopupRun))
+ CallService(MS_KBDNOTIFY_STARTBLINK, (WPARAM)MN->Real.PopupNC + MN->Virtual.PopupNC, NULL);
+
+ if ((nflags & YAMN_ACC_CONT) && (MN->Real.PopupRun + MN->Virtual.PopupRun)) {
+ wchar_t tszMsg[250];
+ mir_snwprintf(tszMsg, TranslateT("%s : %d new mail message(s), %d total"), _A2T(ActualAccount->Name).get(), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC);
+
+ if (!(nflags & YAMN_ACC_CONTNOEVENT)) {
+ CLISTEVENT evt = {};
+ evt.flags = CLEF_UNICODE;
+ evt.hContact = ActualAccount->hContact;
+ evt.hIcon = g_plugin.getIcon(IDI_NEWMAIL);
+ evt.hDbEvent = ActualAccount->hContact;
+ evt.lParam = ActualAccount->hContact;
+ evt.pszService = MS_YAMN_CLISTDBLCLICK;
+ evt.szTooltip.w = tszMsg;
+ g_clistApi.pfnAddEvent(&evt);
+ }
+ db_set_ws(ActualAccount->hContact, "CList", "StatusMsg", tszMsg);
+
+ if (nflags & YAMN_ACC_CONTNICK)
+ g_plugin.setWString(ActualAccount->hContact, "Nick", tszMsg);
+ }
+
+ if ((nflags & YAMN_ACC_POP) &&
+ !(ActualAccount->Flags & YAMN_ACC_POPN) &&
+ (MN->Real.PopupRun + MN->Virtual.PopupRun)) {
+ POPUPDATAW NewMailPopup;
+
+ NewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount;
+ NewMailPopup.lchIcon = g_plugin.getIcon(IDI_NEWMAIL);
+ if (nflags & YAMN_ACC_POPC) {
+ NewMailPopup.colorBack = ActualAccount->NewMailN.PopupB;
+ NewMailPopup.colorText = ActualAccount->NewMailN.PopupT;
+ }
+ else {
+ NewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE);
+ NewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ NewMailPopup.iSeconds = ActualAccount->NewMailN.PopupTime;
+
+ NewMailPopup.PluginWindowProc = NewMailPopupProc;
+ NewMailPopup.PluginData = (void *)nullptr; //multiple popups
+
+ mir_wstrncpy(NewMailPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(NewMailPopup.lpwzContactName));
+ mir_snwprintf(NewMailPopup.lpwzText, TranslateT("%d new mail message(s), %d total"), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC);
+ PUAddPopupW(&NewMailPopup);
+ }
+
+ // destroy tray icon if no new mail
+ if ((MN->Real.SysTrayUC + MN->Virtual.SysTrayUC == 0) && (hDlg != nullptr))
+ Shell_NotifyIcon(NIM_DELETE, &nid);
+
+ // and remove the event
+ if ((nflags & YAMN_ACC_CONT) && (!(nflags & YAMN_ACC_CONTNOEVENT)) && (MN->Real.UnSeen + MN->Virtual.UnSeen == 0))
+ g_clistApi.pfnRemoveEvent(ActualAccount->hContact, ActualAccount->hContact);
+
+ if ((MN->Real.BrowserUC + MN->Virtual.BrowserUC == 0) && (hDlg != nullptr)) {
+ if (!IsWindowVisible(hDlg) && !(nflags & YAMN_ACC_MSG))
+ PostMessage(hDlg, WM_DESTROY, 0, 0); //destroy window if no new mail and window is not visible
+ if (nnflags & YAMN_ACC_MSG) //if no new mail and msg should be executed
+ {
+ SetForegroundWindow(hDlg);
+ ShowWindow(hDlg, SW_SHOWNORMAL);
+ }
+ }
+ else
+ if (hDlg != nullptr) //else insert icon and set window if new mails
+ {
+ SendDlgItemMessageW(hDlg, IDC_LISTMAILS, LVM_SCROLL, 0, (LPARAM)0x7ffffff);
+
+ if ((nflags & YAMN_ACC_ICO) && (MN->Real.SysTrayUC + MN->Virtual.SysTrayUC)) {
+ nid.hIcon = g_plugin.getIcon(IDI_NEWMAIL);
+ nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP;
+ nid.uCallbackMessage = WM_YAMN_NOTIFYICON;
+ mir_snwprintf(nid.szTip, L"%S %s", ActualAccount->Name, TranslateT("- new mail message(s)"));
+ Shell_NotifyIcon(NIM_ADD, &nid);
+ SetTimer(hDlg, TIMER_FLASHING, 500, nullptr);
+ }
+ if (nflags & YAMN_ACC_MSG) //if no new mail and msg should be executed
+ ShowWindow(hDlg, SW_SHOWNORMAL);
+ }
+
+ if (MN->Real.AppNC + MN->Virtual.AppNC != 0) {
+ if (nflags & YAMN_ACC_APP) {
+ PROCESS_INFORMATION pi;
+ STARTUPINFOW si;
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+
+ if (ActualAccount->NewMailN.App != nullptr) {
+ wchar_t *Command;
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6];
+ else
+ Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + 6];
+
+ if (Command != nullptr) {
+ mir_wstrcpy(Command, L"\"");
+ mir_wstrcat(Command, ActualAccount->NewMailN.App);
+ mir_wstrcat(Command, L"\" ");
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ mir_wstrcat(Command, ActualAccount->NewMailN.AppParam);
+ CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi);
+ delete[] Command;
+ }
+ }
+ }
+ }
+
+ if (MN->Real.SoundNC + MN->Virtual.SoundNC != 0)
+ if (nflags & YAMN_ACC_SND)
+ Skin_PlaySound(YAMN_NEWMAILSOUND);
+
+ if ((nnflags & YAMN_ACC_POP) && (MN->Real.PopupRun + MN->Virtual.PopupRun == 0)) {
+ POPUPDATAW NoNewMailPopup = {};
+
+ NoNewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount;
+ NoNewMailPopup.lchIcon = g_plugin.getIcon(IDI_LAUNCHAPP);
+ if (nflags & YAMN_ACC_POPC) {
+ NoNewMailPopup.colorBack = ActualAccount->NoNewMailN.PopupB;
+ NoNewMailPopup.colorText = ActualAccount->NoNewMailN.PopupT;
+ }
+ else {
+ NoNewMailPopup.colorBack = GetSysColor(COLOR_BTNFACE);
+ NoNewMailPopup.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ NoNewMailPopup.iSeconds = ActualAccount->NoNewMailN.PopupTime;
+
+ NoNewMailPopup.PluginWindowProc = NoNewMailPopupProc;
+ NoNewMailPopup.PluginData = nullptr; //it's not new mail popup
+
+ mir_wstrncpy(NoNewMailPopup.lpwzContactName, _A2T(ActualAccount->Name), _countof(NoNewMailPopup.lpwzContactName));
+ if (MN->Real.PopupSL2NC + MN->Virtual.PopupSL2NC)
+ mir_snwprintf(NoNewMailPopup.lpwzText, TranslateT("No new mail message, %d spam(s)"), MN->Real.PopupSL2NC + MN->Virtual.PopupSL2NC);
+ else
+ mir_wstrncpy(NoNewMailPopup.lpwzText, TranslateT("No new mail message"), _countof(NoNewMailPopup.lpwzText));
+ PUAddPopupW(&NoNewMailPopup);
+ }
+
+ if ((nflags & YAMN_ACC_CONT) && (MN->Real.PopupRun + MN->Virtual.PopupRun == 0)) {
+ if (ActualAccount->hContact != NULL) {
+ if (MN->Real.PopupTC + MN->Virtual.PopupTC) {
+ char tmp[255];
+ mir_snprintf(tmp, Translate("%d new mail message(s), %d total"), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC);
+ db_set_s(ActualAccount->hContact, "CList", "StatusMsg", tmp);
+ }
+ else db_set_s(ActualAccount->hContact, "CList", "StatusMsg", Translate("No new mail message"));
+
+ if (nflags & YAMN_ACC_CONTNICK)
+ g_plugin.setString(ActualAccount->hContact, "Nick", ActualAccount->Name);
+ }
+ }
+ return;
+}
+
+LRESULT CALLBACK NewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ INT_PTR PluginParam = 0;
+ switch (msg) {
+ case WM_COMMAND:
+ // if clicked and it's new mail popup window
+ if ((HIWORD(wParam) == STN_CLICKED) && (-1 != (PluginParam = (INT_PTR)PUGetPluginData(hWnd)))) {
+ MCONTACT hContact = 0;
+ CAccount *Account;
+ if (PluginParam) {
+ PYAMN_MAILSHOWPARAM MailParam = new YAMN_MAILSHOWPARAM;
+ memcpy(MailParam, (PINT_PTR)PluginParam, sizeof(YAMN_MAILSHOWPARAM));
+ hContact = MailParam->account->hContact;
+ Account = MailParam->account;
+ mir_forkthread(ShowEmailThread, MailParam);
+ }
+ else {
+ DBVARIANT dbv;
+
+ hContact = PUGetContact(hWnd);
+
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ Account = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ db_free(&dbv);
+ }
+ else Account = (CAccount *)hContact; //????
+
+ if (WAIT_OBJECT_0 == WaitToReadFcn(Account->AccountAccessSO)) {
+ switch (msg) {
+ case WM_COMMAND:
+ {
+ YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, Account,
+ (Account->NewMailN.Flags & ~YAMN_ACC_POP) | YAMN_ACC_MSGP | YAMN_ACC_MSG,
+ (Account->NoNewMailN.Flags & ~YAMN_ACC_POP) | YAMN_ACC_MSGP | YAMN_ACC_MSG};
+
+ RunMailBrowserSvc((WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION);
+ }
+ break;
+ }
+ ReadDoneFcn(Account->AccountAccessSO);
+ }
+ }
+ if ((Account->NewMailN.Flags & YAMN_ACC_CONT) && !(Account->NewMailN.Flags & YAMN_ACC_CONTNOEVENT))
+ g_clistApi.pfnRemoveEvent(hContact, hContact);
+ }
+ __fallthrough;
+
+ case WM_CONTEXTMENU:
+ PUDeletePopup(hWnd);
+ break;
+ case UM_FREEPLUGINDATA:
+ {
+ PYAMN_MAILSHOWPARAM mpd = (PYAMN_MAILSHOWPARAM)PUGetPluginData(hWnd);
+ if ((mpd) && (INT_PTR)mpd != -1)free(mpd);
+ return FALSE;
+ }
+ case UM_INITPOPUP:
+ //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups.
+ WindowList_Add(YAMNVar.MessageWnds, hWnd);
+ break;
+ case UM_DESTROYPOPUP:
+ WindowList_Remove(YAMNVar.MessageWnds, hWnd);
+ break;
+ case WM_YAMN_STOPACCOUNT:
+ {
+ CAccount *ActualAccount;
+ DBVARIANT dbv;
+
+ MCONTACT hContact = PUGetContact(hWnd);
+
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ db_free(&dbv);
+ }
+ else
+ ActualAccount = (CAccount *)hContact;
+
+ if ((CAccount *)wParam != ActualAccount)
+ break;
+ DestroyWindow(hWnd);
+ return 0;
+ }
+ case WM_NOTIFY:
+ default:
+ break;
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+LRESULT CALLBACK NoNewMailPopupProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_COMMAND:
+ if ((HIWORD(wParam) == STN_CLICKED) && (msg == WM_COMMAND)) {
+ CAccount *ActualAccount;
+ DBVARIANT dbv;
+
+ MCONTACT hContact = PUGetContact(hWnd);
+
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ db_free(&dbv);
+ }
+ else
+ ActualAccount = (CAccount *)hContact;
+
+ if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ switch (msg) {
+ case WM_COMMAND:
+ {
+ YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, ActualAccount->NewMailN.Flags, ActualAccount->NoNewMailN.Flags, nullptr};
+
+ Param.nnflags = Param.nnflags | YAMN_ACC_MSG; //show mails in account even no new mail in account
+ Param.nnflags = Param.nnflags & ~YAMN_ACC_POP;
+
+ Param.nflags = Param.nflags | YAMN_ACC_MSG; //show mails in account even no new mail in account
+ Param.nflags = Param.nflags & ~YAMN_ACC_POP;
+
+ RunMailBrowserSvc((WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION);
+ }
+ break;
+ }
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ PUDeletePopup(hWnd);
+ }
+ break;
+
+ case WM_CONTEXTMENU:
+ PUDeletePopup(hWnd);
+ break;
+
+ case UM_FREEPLUGINDATA:
+ //Here we'd free our own data, if we had it.
+ return FALSE;
+ case UM_INITPOPUP:
+ //This is the equivalent to WM_INITDIALOG you'd get if you were the maker of dialog popups.
+ WindowList_Add(YAMNVar.MessageWnds, hWnd);
+ break;
+ case UM_DESTROYPOPUP:
+ WindowList_Remove(YAMNVar.MessageWnds, hWnd);
+ break;
+ case WM_YAMN_STOPACCOUNT:
+ {
+ CAccount *ActualAccount;
+ DBVARIANT dbv;
+
+ MCONTACT hContact = PUGetContact(hWnd);
+
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ db_free(&dbv);
+ }
+ else
+ ActualAccount = (CAccount *)hContact;
+
+ if ((CAccount *)wParam != ActualAccount)
+ break;
+
+ DestroyWindow(hWnd);
+ return 0;
+ }
+ }
+ return DefWindowProc(hWnd, msg, wParam, lParam);
+}
+
+#ifdef __GNUC__
+//number of 100 ns periods between FILETIME 0 (1601/01/01 00:00:00.0000000) and TIMESTAMP 0 (1970/01/01 00:00:00)
+#define NUM100NANOSEC 116444736000000000ULL
+//The biggest time Get[Date|Time]Format can handle (Fri, 31 Dec 30827 23:59:59.9999999)
+#define MAXFILETIME 0x7FFF35F4F06C7FFFULL
+#else
+#define NUM100NANOSEC 116444736000000000
+#define MAXFILETIME 0x7FFF35F4F06C7FFF
+#endif
+
+ULONGLONG MimeDateToFileTime(char *datein)
+{
+ char *day = nullptr, *month = nullptr, *year = nullptr, *time = nullptr, *shift = nullptr;
+ SYSTEMTIME st;
+ ULONGLONG res = 0;
+ int wShiftSeconds = TimeZone_ToLocal(0);
+ GetLocalTime(&st);
+ //datein = "Xxx, 1 Jan 2060 5:29:1 +0530 XXX";
+ //datein = "Xxx, 1 Jan 2060 05:29:10 ";
+ //datein = " ManySpaces 1.5 Jan 2060 05::";
+ //datein = "Xxx, 35 February 20 :29:10 ";
+ //datein = "01.12.2007 (22:38:17)"; //
+ if (datein) {
+ char tmp[64];
+ while (datein[0] == ' ') datein++; // eat leading spaces
+ strncpy(tmp, datein, 63); tmp[63] = 0;
+ if (atoi(tmp)) { // Parseable integer on DayOfWeek field? Buggy mime date.
+ day = tmp;
+ }
+ else {
+ int i = 0;
+ while (tmp[i] == ' ')i++; if (day = strchr(&tmp[i], ' ')) { day[0] = 0; day++; }
+ }
+ if (day) { while (day[0] == ' ') day++; if (month = strchr(day, ' ')) { month[0] = 0; month++; } }
+ if (month) { while (month[0] == ' ')month++; if (year = strchr(month, ' ')) { year[0] = 0; year++; } }
+ if (year) { while (year[0] == ' ') year++; if (time = strchr(year, ' ')) { time[0] = 0; time++; } }
+ if (time) { while (time[0] == ' ') time++; if (shift = strchr(time, ' ')) { shift[0] = 0; shift++; shift[5] = 0; } }
+
+ if (year) {
+ st.wYear = atoi(year);
+ if (mir_strlen(year) < 4) if (st.wYear < 70)st.wYear += 2000; else st.wYear += 1900;
+ };
+ if (month) for (int i = 0; i < 12; i++) if (strncmp(month, s_MonthNames[i], 3) == 0) { st.wMonth = i + 1; break; }
+ if (day) st.wDay = atoi(day);
+ if (time) {
+ char *h, *m, *s;
+ h = time;
+ if (m = strchr(h, ':')) {
+ m[0] = 0; m++;
+ if (s = strchr(m, ':')) { s[0] = 0; s++; }
+ }
+ else s = nullptr;
+ st.wHour = atoi(h);
+ st.wMinute = m ? atoi(m) : 0;
+ st.wSecond = s ? atoi(s) : 0;
+ }
+ else { st.wHour = st.wMinute = st.wSecond = 0; }
+
+ if (shift) {
+ if (mir_strlen(shift) < 4) {
+ //has only hour
+ wShiftSeconds = (atoi(shift)) * 3600;
+ }
+ else {
+ char *smin = shift + mir_strlen(shift) - 2;
+ int ismin = atoi(smin);
+ smin[0] = 0;
+ int ishour = atoi(shift);
+ wShiftSeconds = (ishour * 60 + (ishour < 0 ? -1 : 1) * ismin) * 60;
+ }
+ }
+ } // if (datein)
+ FILETIME ft;
+ if (SystemTimeToFileTime(&st, &ft)) {
+ res = ((ULONGLONG)ft.dwHighDateTime << 32) | ((ULONGLONG)ft.dwLowDateTime);
+ LONGLONG w100nano = Int32x32To64((uint32_t)wShiftSeconds, 10000000);
+ res -= w100nano;
+ }
+ else {
+ res = 0;
+ }
+ return res;
+}
+
+void FileTimeToLocalizedDateTime(LONGLONG filetime, wchar_t *dateout, int lendateout)
+{
+ int localeID = Langpack_GetDefaultLocale();
+ //int localeID = MAKELCID(LANG_URDU, SORT_DEFAULT);
+ if (localeID == CALLSERVICE_NOTFOUND) localeID = LOCALE_USER_DEFAULT;
+ if (filetime > MAXFILETIME) filetime = MAXFILETIME;
+ else if (filetime <= 0) {
+ wcsncpy(dateout, TranslateT("Invalid"), lendateout);
+ return;
+ }
+ SYSTEMTIME st;
+ uint16_t wTodayYear = 0, wTodayMonth = 0, wTodayDay = 0;
+ FILETIME ft;
+ BOOL willShowDate = !(optDateTime & SHOWDATENOTODAY);
+ if (!willShowDate) {
+ GetLocalTime(&st);
+ wTodayYear = st.wYear;
+ wTodayMonth = st.wMonth;
+ wTodayDay = st.wDay;
+ }
+ ft.dwLowDateTime = (uint32_t)filetime;
+ ft.dwHighDateTime = (uint32_t)(filetime >> 32);
+ FILETIME localft;
+ if (!FileTimeToLocalFileTime(&ft, &localft)) {
+ // this should never happen
+ wcsncpy(dateout, L"Incorrect FileTime", lendateout);
+ }
+ else {
+ if (!FileTimeToSystemTime(&localft, &st)) {
+ // this should never happen
+ wcsncpy(dateout, L"Incorrect LocalFileTime", lendateout);
+ }
+ else {
+ dateout[lendateout - 1] = 0;
+ int templen = 0;
+ if (!willShowDate) willShowDate = (wTodayYear != st.wYear) || (wTodayMonth != st.wMonth) || (wTodayDay != st.wDay);
+ if (willShowDate) {
+ templen = GetDateFormatW(localeID, (optDateTime & SHOWDATELONG) ? DATE_LONGDATE : DATE_SHORTDATE, &st, nullptr, dateout, lendateout - 2);
+ dateout[templen - 1] = ' ';
+ }
+ if (templen < (lendateout - 1)) {
+ GetTimeFormatW(localeID, (optDateTime & SHOWDATENOSECONDS) ? TIME_NOSECONDS : 0, &st, nullptr, &dateout[templen], lendateout - templen - 1);
+ }
+ }
+ }
+}
+
+void MimeDateToLocalizedDateTime(char *datein, wchar_t *dateout, int lendateout)
+{
+ ULONGLONG ft = MimeDateToFileTime(datein);
+ FileTimeToLocalizedDateTime(ft, dateout, lendateout);
+}
+
+int CALLBACK ListViewCompareProc(LPARAM lParam1, LPARAM lParam2, LPARAM lParamSort)
+{
+ if (lParam1 == NULL || lParam2 == NULL)
+ return 0;
+
+ int nResult = 0;
+ char *str1;
+ char *str2;
+ HYAMNMAIL email1 = (HYAMNMAIL)lParam1;
+ HYAMNMAIL email2 = (HYAMNMAIL)lParam2;
+ struct CShortHeader Header1;
+ struct CShortHeader Header2;
+ memset(&Header1, 0, sizeof(Header1));
+ memset(&Header2, 0, sizeof(Header2));
+
+ try {
+ ExtractShortHeader(email1->MailData->TranslatedHeader, &Header1);
+ ExtractShortHeader(email2->MailData->TranslatedHeader, &Header2);
+
+ switch ((int)lParamSort) {
+ case 0: //From
+ if (Header1.FromNick == nullptr)
+ str1 = Header1.From;
+ else str1 = Header1.FromNick;
+
+ if (Header2.FromNick == nullptr)
+ str2 = Header2.From;
+ else str2 = Header2.FromNick;
+
+ nResult = mir_strcmp(str1, str2);
+
+ if (bFrom) nResult = -nResult;
+ break;
+ case 1: //Subject
+ if (Header1.Subject == nullptr)
+ str1 = " ";
+ else str1 = Header1.Subject;
+
+ if (Header2.Subject == nullptr)
+ str2 = " ";
+ else str2 = Header2.Subject;
+
+ nResult = mir_strcmp(str1, str2);
+
+ if (bSub) nResult = -nResult;
+ break;
+ case 2: //Size
+ if (email1->MailData->Size == email2->MailData->Size) nResult = 0;
+ if (email1->MailData->Size > email2->MailData->Size) nResult = 1;
+ if (email1->MailData->Size < email2->MailData->Size) nResult = -1;
+
+ if (bSize) nResult = -nResult;
+ break;
+
+ case 3: //Date
+ {
+ ULONGLONG ts1 = 0, ts2 = 0;
+ ts1 = MimeDateToFileTime(Header1.Date);
+ ts2 = MimeDateToFileTime(Header2.Date);
+ if (ts1 > ts2) nResult = 1;
+ else if (ts1 < ts2) nResult = -1;
+ else nResult = 0;
+ }
+ if (bDate) nResult = -nResult;
+ break;
+
+ default:
+ if (Header1.Subject == nullptr) str1 = " ";
+ else str1 = Header1.Subject;
+
+ if (Header2.Subject == nullptr) str2 = " ";
+ else str2 = Header2.Subject;
+
+ nResult = mir_strcmp(str1, str2);
+ break;
+ }
+ //MessageBox(NULL,str1,str2,0);
+ }
+ catch (...) {
+ }
+
+ //free mem
+ DeleteShortHeaderContent(&Header1);
+ DeleteShortHeaderContent(&Header2);
+ return nResult;
+
+}
+
+HCURSOR hCurSplitNS, hCurSplitWE;
+#define DM_SPLITTERMOVED (WM_USER+15)
+
+static LRESULT CALLBACK SplitterSubclassProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_NCHITTEST:
+ return HTCLIENT;
+
+ case WM_SETCURSOR:
+ SetCursor(hCurSplitNS);
+ return TRUE;
+
+ case WM_LBUTTONDOWN:
+ SetCapture(hwnd);
+ return 0;
+
+ case WM_MOUSEMOVE:
+ if (GetCapture() == hwnd) {
+ RECT rc;
+ GetClientRect(hwnd, &rc);
+ SendMessage(GetParent(hwnd), DM_SPLITTERMOVED, (short)HIWORD(GetMessagePos()) + rc.bottom / 2, (LPARAM)hwnd);
+ }
+ return 0;
+
+ case WM_LBUTTONUP:
+ ReleaseCapture();
+ return 0;
+ }
+ return mir_callNextSubclass(hwnd, SplitterSubclassProc, msg, wParam, lParam);
+}
+
+void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode);
+int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out);
+
+INT_PTR CALLBACK DlgProcYAMNShowMessage(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)lParam;
+ wchar_t *iHeaderW = nullptr;
+ wchar_t *iValueW = nullptr;
+ int StrLen;
+ HWND hListView = GetDlgItem(hDlg, IDC_LISTHEADERS);
+ mir_subclassWindow(GetDlgItem(hDlg, IDC_SPLITTER), SplitterSubclassProc);
+ SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)MailParam);
+ Window_SetIcon_IcoLib(hDlg, g_plugin.getIconHandle(IDI_NEWMAIL));
+
+ ListView_SetUnicodeFormat(hListView, TRUE);
+ ListView_SetExtendedListViewStyle(hListView, LVS_EX_FULLROWSELECT);
+
+ StrLen = MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Header"), -1, nullptr, 0);
+ iHeaderW = new wchar_t[StrLen + 1];
+ MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Header"), -1, iHeaderW, StrLen);
+
+ StrLen = MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Value"), -1, nullptr, 0);
+ iValueW = new wchar_t[StrLen + 1];
+ MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Value"), -1, iValueW, StrLen);
+
+ LVCOLUMN lvc0 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, 130, iHeaderW, 0, 0};
+ LVCOLUMN lvc1 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, 400, iValueW, 0, 0};
+ SendMessage(hListView, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc0);
+ SendMessage(hListView, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc1);
+ if (nullptr != iHeaderW)
+ delete[] iHeaderW;
+ if (nullptr != iValueW)
+ delete[] iValueW;
+
+ SendMessage(hDlg, WM_YAMN_CHANGECONTENT, 0, (LPARAM)MailParam);
+ MoveWindow(hDlg, HeadPosX, HeadPosY, HeadSizeX, HeadSizeY, 0);
+ ShowWindow(hDlg, SW_SHOWNORMAL);
+ }
+ break;
+
+ case WM_YAMN_CHANGECONTENT:
+ {
+ PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)
+ (lParam ? lParam : GetWindowLongPtr(hDlg, DWLP_USER));
+ HWND hListView = GetDlgItem(hDlg, IDC_LISTHEADERS);
+ HWND hEdit = GetDlgItem(hDlg, IDC_EDITBODY);
+ //do not redraw
+ SendMessage(hListView, WM_SETREDRAW, 0, 0);
+ ListView_DeleteAllItems(hListView);
+ struct CMimeItem *Header;
+ LVITEMW item;
+ item.mask = LVIF_TEXT | LVIF_PARAM;
+ wchar_t *From = nullptr, *Subj = nullptr;
+ char *contentType = nullptr, *transEncoding = nullptr, *body = nullptr; //should not be delete[]-ed
+ for (Header = MailParam->mail->MailData->TranslatedHeader; Header != nullptr; Header = Header->Next) {
+ wchar_t *str1 = nullptr;
+ wchar_t *str2 = nullptr;
+ wchar_t str_nul[2] = {0};
+ if (!body) if (!_stricmp(Header->name, "Body")) { body = Header->value; continue; }
+ if (!contentType) if (!_stricmp(Header->name, "Content-Type")) contentType = Header->value;
+ if (!transEncoding) if (!_stricmp(Header->name, "Content-Transfer-Encoding")) transEncoding = Header->value;
+ //ConvertCodedStringToUnicode(Header->name,&str1,MailParam->mail->MailData->CP,1);
+ {
+ int streamsize = MultiByteToWideChar(20127, 0, Header->name, -1, nullptr, 0);
+ str1 = (wchar_t *)malloc(sizeof(wchar_t) * (streamsize + 1));
+ MultiByteToWideChar(20127, 0, Header->name, -1, str1, streamsize);//US-ASCII
+ }
+ ConvertCodedStringToUnicode(Header->value, &str2, MailParam->mail->MailData->CP, 1);
+ if (!str2) { str2 = (wchar_t *)str_nul; }// the header value may be NULL
+ if (!From) if (!_stricmp(Header->name, "From")) {
+ From = new wchar_t[mir_wstrlen(str2) + 1];
+ mir_wstrcpy(From, str2);
+ }
+ if (!Subj) if (!_stricmp(Header->name, "Subject")) {
+ Subj = new wchar_t[mir_wstrlen(str2) + 1];
+ mir_wstrcpy(Subj, str2);
+ }
+ //if (!hasBody) if (!mir_strcmp(Header->name,"Body")) hasBody = true;
+ int count = 0; wchar_t **split = nullptr;
+ int ofs = 0;
+ while (str2[ofs]) {
+ if ((str2[ofs] == 0x266A) || (str2[ofs] == 0x25D9) || (str2[ofs] == 0x25CB) ||
+ (str2[ofs] == 0x09) || (str2[ofs] == 0x0A) || (str2[ofs] == 0x0D))count++;
+ ofs++;
+ }
+ split = new wchar_t *[count + 1];
+ count = 0; ofs = 0;
+ split[0] = str2;
+ while (str2[ofs]) {
+ if ((str2[ofs] == 0x266A) || (str2[ofs] == 0x25D9) || (str2[ofs] == 0x25CB) ||
+ (str2[ofs] == 0x09) || (str2[ofs] == 0x0A) || (str2[ofs] == 0x0D)) {
+ if (str2[ofs - 1]) {
+ count++;
+ }
+ split[count] = (wchar_t *)(str2 + ofs + 1);
+ str2[ofs] = 0;
+ }
+ ofs++;
+ };
+
+ if (!_stricmp(Header->name, "From") || !_stricmp(Header->name, "To") || !_stricmp(Header->name, "Date") || !_stricmp(Header->name, "Subject"))
+ item.iItem = 0;
+ else
+ item.iItem = 999;
+ for (int i = 0; i <= count; i++) {
+ item.iSubItem = 0;
+ if (i == 0)
+ item.pszText = str1;
+ else {
+ item.iItem++;
+ item.pszText = nullptr;
+ }
+ item.iItem = SendMessage(hListView, LVM_INSERTITEM, 0, (LPARAM)&item);
+ item.iSubItem = 1;
+ item.pszText = str2 ? split[i] : nullptr;
+ SendMessage(hListView, LVM_SETITEMTEXT, (WPARAM)item.iItem, (LPARAM)&item);
+ }
+ delete[] split;
+
+ if (str1)
+ free(str1);
+ if (str2 != (wchar_t *)str_nul)
+ free(str2);
+ }
+ if (body) {
+ wchar_t *bodyDecoded = nullptr;
+ char *localBody = nullptr;
+ if (contentType) {
+ if (!_strnicmp(contentType, "text", 4)) {
+ if (transEncoding) {
+ if (!_stricmp(transEncoding, "base64")) {
+ int size = (int)mir_strlen(body) * 3 / 4 + 5;
+ localBody = new char[size + 1];
+ DecodeBase64(body, localBody, size);
+ }
+ else if (!_stricmp(transEncoding, "quoted-printable")) {
+ int size = (int)mir_strlen(body) + 2;
+ localBody = new char[size + 1];
+ DecodeQuotedPrintable(body, localBody, size, FALSE);
+ }
+ }
+ }
+ else if (!_strnicmp(contentType, "multipart/", 10)) {
+ char *bondary = nullptr;
+ if (nullptr != (bondary = ExtractFromContentType(contentType, "boundary="))) {
+ bodyDecoded = ParseMultipartBody(body, bondary);
+ delete[] bondary;
+ }
+ }
+ }
+ if (!bodyDecoded)ConvertStringToUnicode(localBody ? localBody : body, MailParam->mail->MailData->CP, &bodyDecoded);
+ SetWindowTextW(hEdit, bodyDecoded);
+ delete[] bodyDecoded;
+ if (localBody) delete[] localBody;
+ SetFocus(hEdit);
+ }
+ if (!(MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED)) {
+ MailParam->mail->Flags |= YAMN_MSG_BODYREQUESTED;
+ CallService(MS_YAMN_ACCOUNTCHECK, (WPARAM)MailParam->account, 0);
+ }
+ else {
+ if (MailParam->mail->Flags & YAMN_MSG_UNSEEN) {
+ MailParam->mail->Flags &= ~YAMN_MSG_UNSEEN; //mark the message as seen
+ HWND hMailBrowser = WindowList_Find(YAMNVar.NewMailAccountWnd, (UINT_PTR)MailParam->account);
+ if (hMailBrowser) {
+ struct CChangeContent Params = {MailParam->account->NewMailN.Flags | YAMN_ACC_MSGP, MailParam->account->NoNewMailN.Flags | YAMN_ACC_MSGP};
+ SendMessage(hMailBrowser, WM_YAMN_CHANGECONTENT, (WPARAM)MailParam->account, (LPARAM)&Params);
+ }
+ else UpdateMails(nullptr, MailParam->account, MailParam->account->NewMailN.Flags, MailParam->account->NoNewMailN.Flags);
+ }
+ }
+ ShowWindow(GetDlgItem(hDlg, IDC_SPLITTER), (MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED) ? SW_SHOW : SW_HIDE);
+ ShowWindow(hEdit, (MailParam->mail->Flags & YAMN_MSG_BODYRECEIVED) ? SW_SHOW : SW_HIDE);
+ wchar_t *title = nullptr;
+ size_t size = (From ? mir_wstrlen(From) : 0) + (Subj ? mir_wstrlen(Subj) : 0) + 4;
+ title = new wchar_t[size];
+ if (From && Subj)
+ mir_snwprintf(title, size, L"%s (%s)", Subj, From);
+ else if (From)
+ wcsncpy_s(title, size, From, _TRUNCATE);
+ else if (Subj)
+ wcsncpy_s(title, size, Subj, _TRUNCATE);
+ else
+ wcsncpy_s(title, size, L"none", _TRUNCATE);
+ if (Subj) delete[] Subj;
+ if (From) delete[] From;
+ SetWindowTextW(hDlg, title);
+ delete[] title;
+ // turn on redrawing
+ SendMessage(hListView, WM_SETREDRAW, 1, 0);
+ SendMessage(hDlg, WM_SIZE, 0, HeadSizeY << 16 | HeadSizeX);
+ } break;
+
+ case WM_YAMN_STOPACCOUNT:
+ {
+ PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)
+ (lParam ? lParam : GetWindowLongPtr(hDlg, DWLP_USER));
+
+ if (nullptr == MailParam)
+ break;
+ if ((CAccount *)wParam != MailParam->account)
+ break;
+
+ DestroyWindow(hDlg);
+ }
+ return 1;
+
+ case WM_CTLCOLORSTATIC:
+ // here should be check if this is our edittext control.
+ // but we have only one static control (for now);
+ SetBkColor((HDC)wParam, GetSysColor(COLOR_WINDOW));
+ SetTextColor((HDC)wParam, GetSysColor(COLOR_WINDOWTEXT));
+ return (INT_PTR)GetSysColorBrush(COLOR_WINDOW);
+
+ case WM_DESTROY:
+ Window_FreeIcon_IcoLib(hDlg);
+ {
+ RECT coord;
+ if (GetWindowRect(hDlg, &coord)) {
+ HeadPosX = coord.left;
+ HeadSizeX = coord.right - coord.left;
+ HeadPosY = coord.top;
+ HeadSizeY = coord.bottom - coord.top;
+ }
+
+ PostQuitMessage(1);
+ }
+ break;
+
+ case WM_SYSCOMMAND:
+ switch (wParam) {
+ case SC_CLOSE:
+ DestroyWindow(hDlg);
+ break;
+ }
+ break;
+
+ case WM_MOVE:
+ HeadPosX = LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left;
+ HeadPosY = HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top;
+ return 0;
+
+ case DM_SPLITTERMOVED:
+ if ((HWND)lParam == GetDlgItem(hDlg, IDC_SPLITTER)) {
+ POINT pt;
+ pt.x = 0;
+ pt.y = wParam;
+ ScreenToClient(hDlg, &pt);
+ HeadSplitPos = (pt.y * 1000) / HeadSizeY;//+rc.bottom-rc.top;
+ if (HeadSplitPos >= 1000) HeadSplitPos = 999;
+ else if (HeadSplitPos <= 0) HeadSplitPos = 1;
+ else SendMessage(hDlg, WM_SIZE, 0, HeadSizeY << 16 | HeadSizeX);
+ }
+ return 0;
+
+ case WM_SIZE:
+ if (wParam == SIZE_RESTORED) {
+ HWND hList = GetDlgItem(hDlg, IDC_LISTHEADERS);
+ HWND hEdit = GetDlgItem(hDlg, IDC_EDITBODY);
+ BOOL isBodyShown = ((PYAMN_MAILSHOWPARAM)(GetWindowLongPtr(hDlg, DWLP_USER)))->mail->Flags & YAMN_MSG_BODYRECEIVED;
+ HeadSizeX = LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left;
+ HeadSizeY = HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top;
+ int localSplitPos = (HeadSplitPos * HeadSizeY) / 1000;
+ int localSizeX;
+ RECT coord;
+ MoveWindow(GetDlgItem(hDlg, IDC_SPLITTER), 5, localSplitPos, HeadSizeX - 10, 2, TRUE);
+ MoveWindow(hEdit, 5, localSplitPos + 6, HeadSizeX - 10, HeadSizeY - localSplitPos - 11, TRUE); //where to put text window while resizing
+ MoveWindow(hList, 5, 5, HeadSizeX - 10, (isBodyShown ? localSplitPos : HeadSizeY) - 10, TRUE); //where to put headers list window while resizing
+ //if (changeX) {
+ if (GetClientRect(hList, &coord)) {
+ localSizeX = coord.right - coord.left;
+ }
+ else localSizeX = HeadSizeX;
+ LONG iNameWidth = ListView_GetColumnWidth(hList, 0);
+ ListView_SetColumnWidth(hList, 1, (localSizeX <= iNameWidth) ? 0 : (localSizeX - iNameWidth));
+ //}
+ }
+ return 0;
+
+ case WM_CONTEXTMENU:
+ if (GetWindowLongPtr((HWND)wParam, GWLP_ID) == IDC_LISTHEADERS) {
+ //MessageBox(0,"LISTHEADERS","Debug",0);
+ HWND hList = GetDlgItem(hDlg, IDC_LISTHEADERS);
+ POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+ if (pt.x == -1) pt.x = 0;
+ if (pt.y == -1) pt.y = 0;
+ if (int numRows = ListView_GetItemCount(hList)) {
+ HMENU hMenu = CreatePopupMenu();
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)1, TranslateT("Copy Selected"));
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)2, TranslateT("Copy All"));
+ AppendMenu(hMenu, MF_SEPARATOR, 0, nullptr);
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel"));
+ int nReturnCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hDlg, nullptr);
+ DestroyMenu(hMenu);
+ if (nReturnCmd > 0) {
+ int courRow = 0;
+ size_t sizeNeeded = 0;
+ wchar_t headname[64] = {0}, headvalue[256] = {0};
+ for (courRow = 0; courRow < numRows; courRow++) {
+ if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue;
+ ListView_GetItemText(hList, courRow, 0, headname, _countof(headname));
+ ListView_GetItemText(hList, courRow, 1, headvalue, _countof(headvalue));
+ size_t headnamelen = mir_wstrlen(headname);
+ if (headnamelen) sizeNeeded += 1 + headnamelen;
+ sizeNeeded += 3 + mir_wstrlen(headvalue);
+ }
+ if (sizeNeeded && OpenClipboard(hDlg)) {
+ EmptyClipboard();
+ HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, (sizeNeeded + 1) * sizeof(wchar_t));
+ wchar_t *buff = (wchar_t *)GlobalLock(hData);
+ int courPos = 0;
+ for (courRow = 0; courRow < numRows; courRow++) {
+ if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue;
+ ListView_GetItemText(hList, courRow, 0, headname, _countof(headname));
+ ListView_GetItemText(hList, courRow, 1, headvalue, _countof(headvalue));
+ if (mir_wstrlen(headname)) courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"%s:\t%s\r\n", headname, headvalue);
+ else courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"\t%s\r\n", headvalue);
+ }
+ GlobalUnlock(hData);
+
+ SetClipboardData(CF_UNICODETEXT, hData);
+
+ CloseClipboard();
+ }
+ }
+ }
+ }
+ break; // just in case
+ }
+ return 0;
+}
+
+void __cdecl ShowEmailThread(void *Param)
+{
+ struct MailShowMsgWinParam MyParam = *(struct MailShowMsgWinParam *)Param;
+
+ SCIncFcn(MyParam.account->UsingThreads);
+
+ if (MyParam.mail->MsgWindow) {
+ //if (!BringWindowToTop(MyParam.mail->MsgWindow)) {
+ if (!SetForegroundWindow(MyParam.mail->MsgWindow)) {
+ SendMessage(MyParam.mail->MsgWindow, WM_DESTROY, 0, 0);
+ MyParam.mail->MsgWindow = nullptr;
+ goto CREADTEVIEWMESSAGEWINDOW;
+ }
+
+ if (IsIconic(MyParam.mail->MsgWindow))
+ OpenIcon(MyParam.mail->MsgWindow);
+ }
+ else {
+CREADTEVIEWMESSAGEWINDOW:
+ MyParam.mail->MsgWindow = CreateDialogParamW(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_DLGSHOWMESSAGE), nullptr, DlgProcYAMNShowMessage, (LPARAM)&MyParam);
+ WindowList_Add(YAMNVar.MessageWnds, MyParam.mail->MsgWindow);
+ MSG msg;
+ while (GetMessage(&msg, nullptr, 0, 0)) {
+ if (MyParam.mail->MsgWindow == nullptr || !IsDialogMessage(MyParam.mail->MsgWindow, &msg)) { /* Wine fix. */
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ WindowList_Remove(YAMNVar.MessageWnds, MyParam.mail->MsgWindow);
+ MyParam.mail->MsgWindow = nullptr;
+ }
+
+ SCDecFcn(MyParam.account->UsingThreads);
+ delete (struct MailShowMsgWinParam *)Param;
+}
+
+INT_PTR CALLBACK DlgProcYAMNMailBrowser(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ CAccount *ActualAccount;
+ int Items;
+
+ switch (msg) {
+ case WM_INITDIALOG:
+ {
+ struct MailBrowserWinParam *MyParam = (struct MailBrowserWinParam *)lParam;
+
+ ListView_SetUnicodeFormat(GetDlgItem(hDlg, IDC_LISTMAILS), TRUE);
+ ListView_SetExtendedListViewStyle(GetDlgItem(hDlg, IDC_LISTMAILS), LVS_EX_FULLROWSELECT);
+
+ ActualAccount = MyParam->account;
+ struct CMailWinUserInfo *mwui = new struct CMailWinUserInfo;
+ mwui->Account = ActualAccount;
+ mwui->TrayIconState = 0;
+ mwui->UpdateMailsMessagesAccess = FALSE;
+ mwui->Seen = FALSE;
+ mwui->RunFirstTime = TRUE;
+
+ SetWindowLongPtr(hDlg, DWLP_USER, (LONG_PTR)mwui);
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ DestroyWindow(hDlg);
+ return FALSE;
+ }
+
+ SetDlgItemText(hDlg, IDC_BTNAPP, TranslateT("Run application"));
+ SetDlgItemText(hDlg, IDC_BTNDEL, TranslateT("Delete selected"));
+ SetDlgItemText(hDlg, IDC_BTNCHECKALL, TranslateT("Select All"));
+ SetDlgItemText(hDlg, IDC_BTNOK, TranslateT("OK"));
+
+ LVCOLUMN lvc0 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, FromWidth, TranslateT("From"), 0, 0};
+ LVCOLUMN lvc1 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SubjectWidth, TranslateT("Subject"), 0, 0};
+ LVCOLUMN lvc2 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SizeWidth, TranslateT("Size"), 0, 0};
+ LVCOLUMN lvc3 = {LVCF_FMT | LVCF_TEXT | LVCF_WIDTH, LVCFMT_LEFT, SizeDate, TranslateT("Date"), 0, 0};
+ SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, 0, (LPARAM)&lvc0);
+ SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, 1, (LPARAM)&lvc1);
+ SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, (WPARAM)2, (LPARAM)&lvc2);
+ SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_INSERTCOLUMN, (WPARAM)3, (LPARAM)&lvc3);
+
+ if ((ActualAccount->NewMailN.App != nullptr) && (mir_wstrlen(ActualAccount->NewMailN.App)))
+ EnableWindow(GetDlgItem(hDlg, IDC_BTNAPP), TRUE);
+ else
+ EnableWindow(GetDlgItem(hDlg, IDC_BTNAPP), FALSE);
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ WindowList_Add(YAMNVar.MessageWnds, hDlg);
+ WindowList_Add(YAMNVar.NewMailAccountWnd, hDlg, (UINT_PTR)ActualAccount);
+
+ {
+ wchar_t accstatus[512];
+ GetStatusFcn(ActualAccount, accstatus);
+ SetDlgItemText(hDlg, IDC_STSTATUS, accstatus);
+ }
+ SetTimer(hDlg, TIMER_FLASHING, 500, nullptr);
+
+ if (ActualAccount->hContact != NULL)
+ g_clistApi.pfnRemoveEvent(ActualAccount->hContact, (LPARAM)"yamn new mail message");
+
+ mir_subclassWindow(GetDlgItem(hDlg, IDC_LISTMAILS), ListViewSubclassProc);
+ }
+ break;
+
+ case WM_DESTROY:
+ {
+ RECT coord;
+ LVCOLUMN ColInfo;
+ HYAMNMAIL Parser;
+
+ Window_FreeIcon_IcoLib(hDlg);
+
+ struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+ ColInfo.mask = LVCF_WIDTH;
+ if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 0, &ColInfo))
+ FromWidth = ColInfo.cx;
+ if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 1, &ColInfo))
+ SubjectWidth = ColInfo.cx;
+ if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 2, &ColInfo))
+ SizeWidth = ColInfo.cx;
+ if (ListView_GetColumn(GetDlgItem(hDlg, IDC_LISTMAILS), 3, &ColInfo))
+ SizeDate = ColInfo.cx;
+
+ if (!YAMNVar.Shutdown && GetWindowRect(hDlg, &coord)) //the YAMNVar.Shutdown testing is because M<iranda strange functionality at shutdown phase, when call to DBWriteContactSetting freezes calling thread
+ {
+ PosX = coord.left;
+ SizeX = coord.right - coord.left;
+ PosY = coord.top;
+ SizeY = coord.bottom - coord.top;
+ g_plugin.setDword(YAMN_DBPOSX, PosX);
+ g_plugin.setDword(YAMN_DBPOSY, PosY);
+ g_plugin.setDword(YAMN_DBSIZEX, SizeX);
+ g_plugin.setDword(YAMN_DBSIZEY, SizeY);
+ }
+ KillTimer(hDlg, TIMER_FLASHING);
+
+ WindowList_Remove(YAMNVar.NewMailAccountWnd, hDlg);
+ WindowList_Remove(YAMNVar.MessageWnds, hDlg);
+
+ if (WAIT_OBJECT_0 != WaitToWriteFcn(ActualAccount->MessagesAccessSO))
+ break;
+
+ //delete mails from queue, which are deleted from server (spam level 3 mails e.g.)
+ for (Parser = (HYAMNMAIL)ActualAccount->Mails; Parser != nullptr; Parser = Parser->Next) {
+ if ((Parser->Flags & YAMN_MSG_DELETED) && YAMN_MSG_SPAML(Parser->Flags, YAMN_MSG_SPAML3) && mwui->Seen) //if spaml3 was already deleted and user knows about it
+ {
+ DeleteMessageFromQueueFcn((HYAMNMAIL *)&ActualAccount->Mails, Parser, 1);
+ CallService(MS_YAMN_DELETEACCOUNTMAIL, (WPARAM)ActualAccount->Plugin, (LPARAM)Parser);
+ }
+ }
+
+ //mark mails as read (remove "new" and "unseen" flags)
+ if (mwui->Seen)
+ SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_DISPLAY, 0, YAMN_MSG_NEW | YAMN_MSG_UNSEEN, 0);
+
+ WriteDoneFcn(ActualAccount->MessagesAccessSO);
+
+ NOTIFYICONDATA nid;
+ memset(&nid, 0, sizeof(NOTIFYICONDATA));
+
+ delete mwui;
+ SetWindowLongPtr(hDlg, DWLP_USER, NULL);
+
+ nid.cbSize = sizeof(NOTIFYICONDATA);
+ nid.hWnd = hDlg;
+ nid.uID = 0;
+ Shell_NotifyIcon(NIM_DELETE, &nid);
+ PostQuitMessage(0);
+ }
+ break;
+
+ case WM_SHOWWINDOW:
+ {
+ struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+
+ if (mwui == nullptr)
+ return 0;
+ mwui->Seen = TRUE;
+ }
+
+ case WM_YAMN_CHANGESTATUS:
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+
+ if ((CAccount *)wParam != ActualAccount)
+ break;
+
+ wchar_t accstatus[512];
+ GetStatusFcn(ActualAccount, accstatus);
+ SetDlgItemText(hDlg, IDC_STSTATUS, accstatus);
+ return 1;
+
+ case WM_YAMN_CHANGECONTENT:
+ {
+ struct CUpdateMails UpdateParams;
+ BOOL ThisThreadWindow = (GetCurrentThreadId() == GetWindowThreadProcessId(hDlg, nullptr));
+
+ if (nullptr == (UpdateParams.Copied = CreateEvent(nullptr, FALSE, FALSE, nullptr))) {
+ DestroyWindow(hDlg);
+ return 0;
+ }
+ UpdateParams.Flags = (struct CChangeContent *)lParam;
+ UpdateParams.Waiting = !ThisThreadWindow;
+
+ if (ThisThreadWindow) {
+ if (!UpdateMails(hDlg, (CAccount *)wParam, UpdateParams.Flags->nflags, UpdateParams.Flags->nnflags))
+ DestroyWindow(hDlg);
+ }
+ else if (PostMessage(hDlg, WM_YAMN_UPDATEMAILS, wParam, (LPARAM)&UpdateParams)) //this ensures UpdateMails will execute the thread who created the browser window
+ {
+ if (!ThisThreadWindow)
+ WaitForSingleObject(UpdateParams.Copied, INFINITE);
+ }
+
+ CloseHandle(UpdateParams.Copied);
+ }
+ return 1;
+ case WM_YAMN_UPDATEMAILS:
+ {
+ struct CUpdateMails *um = (struct CUpdateMails *)lParam;
+ uint32_t nflags, nnflags;
+
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ return 0;
+ if ((CAccount *)wParam != ActualAccount)
+ return 0;
+
+ nflags = um->Flags->nflags;
+ nnflags = um->Flags->nnflags;
+
+ if (um->Waiting)
+ SetEvent(um->Copied);
+
+ if (!UpdateMails(hDlg, ActualAccount, nflags, nnflags))
+ DestroyWindow(hDlg);
+ }
+ return 1;
+ case WM_YAMN_STOPACCOUNT:
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+ if ((CAccount *)wParam != ActualAccount)
+ break;
+ PostQuitMessage(0);
+ return 1;
+
+ case WM_YAMN_NOTIFYICON:
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+
+ switch (lParam) {
+ case WM_LBUTTONDBLCLK:
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ return 0;
+ }
+
+ if (ActualAccount->AbilityFlags & YAMN_ACC_BROWSE) {
+ ShowWindow(hDlg, SW_SHOWNORMAL);
+ SetForegroundWindow(hDlg);
+ }
+ else DestroyWindow(hDlg);
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ break;
+ }
+ break;
+
+ case WM_YAMN_SHOWSELECTED:
+ {
+ int iSelect = SendDlgItemMessage(hDlg, IDC_LISTMAILS, LVM_GETNEXTITEM, -1, MAKELPARAM((UINT)LVNI_FOCUSED, 0)); // return item selected
+ if (iSelect != -1) {
+ LV_ITEMW item;
+
+ item.iItem = iSelect;
+ item.iSubItem = 0;
+ item.mask = LVIF_PARAM | LVIF_STATE;
+ item.stateMask = 0xFFFFFFFF;
+ ListView_GetItem(GetDlgItem(hDlg, IDC_LISTMAILS), &item);
+ HYAMNMAIL ActualMail = (HYAMNMAIL)item.lParam;
+ if (nullptr != ActualMail) {
+ PYAMN_MAILSHOWPARAM MailParam = new YAMN_MAILSHOWPARAM;
+ MailParam->account = GetWindowAccount(hDlg);
+ MailParam->mail = ActualMail;
+ mir_forkthread(ShowEmailThread, MailParam);
+ }
+ }
+ }
+ break;
+
+ case WM_SYSCOMMAND:
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+ switch (wParam) {
+ case SC_CLOSE:
+ DestroyWindow(hDlg);
+ break;
+ }
+ break;
+
+ case WM_COMMAND:
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+
+ switch (LOWORD(wParam)) {
+ case IDC_BTNCHECKALL:
+ ListView_SetItemState(GetDlgItem(hDlg, IDC_LISTMAILS), -1, 0, LVIS_SELECTED); // deselect all items
+ ListView_SetItemState(GetDlgItem(hDlg, IDC_LISTMAILS), -1, LVIS_SELECTED, LVIS_SELECTED);
+ Items = ListView_GetItemCount(GetDlgItem(hDlg, IDC_LISTMAILS));
+ ListView_RedrawItems(GetDlgItem(hDlg, IDC_LISTMAILS), 0, Items);
+ UpdateWindow(GetDlgItem(hDlg, IDC_LISTMAILS));
+ SetFocus(GetDlgItem(hDlg, IDC_LISTMAILS));
+ break;
+
+ case IDC_BTNOK:
+ DestroyWindow(hDlg);
+ break;
+
+ case IDC_BTNAPP:
+ {
+ PROCESS_INFORMATION pi;
+ STARTUPINFOW si;
+
+ memset(&si, 0, sizeof(si));
+ si.cb = sizeof(si);
+
+ if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ if (ActualAccount->NewMailN.App != nullptr) {
+ wchar_t *Command;
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6];
+ else
+ Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + 6];
+
+ if (Command != nullptr) {
+ mir_wstrcpy(Command, L"\"");
+ mir_wstrcat(Command, ActualAccount->NewMailN.App);
+ mir_wstrcat(Command, L"\" ");
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ mir_wstrcat(Command, ActualAccount->NewMailN.AppParam);
+ CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi);
+ delete[] Command;
+ }
+ }
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+
+ if (!(GetKeyState(VK_SHIFT) & 0x8000) && !(GetKeyState(VK_CONTROL) & 0x8000))
+ DestroyWindow(hDlg);
+ }
+ break;
+
+ case IDC_BTNDEL:
+ {
+ HYAMNMAIL ActualMail;
+ uint32_t Total = 0;
+
+ // we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (ThreadRunningEV == nullptr)
+ break;
+
+ Items = ListView_GetItemCount(GetDlgItem(hDlg, IDC_LISTMAILS));
+
+ LVITEM item;
+ item.stateMask = 0xFFFFFFFF;
+
+ if (WAIT_OBJECT_0 == WaitToWriteFcn(ActualAccount->MessagesAccessSO)) {
+ for (int i = 0; i < Items; i++) {
+ item.iItem = i;
+ item.iSubItem = 0;
+ item.mask = LVIF_PARAM | LVIF_STATE;
+ item.stateMask = 0xFFFFFFFF;
+ ListView_GetItem(GetDlgItem(hDlg, IDC_LISTMAILS), &item);
+ ActualMail = (HYAMNMAIL)item.lParam;
+ if (nullptr == ActualMail)
+ break;
+ if (item.state & LVIS_SELECTED) {
+ ActualMail->Flags |= YAMN_MSG_USERDELETE; //set to mail we are going to delete it
+ Total++;
+ }
+ }
+
+ // Enable write-access to mails
+ WriteDoneFcn(ActualAccount->MessagesAccessSO);
+
+ if (Total) {
+ wchar_t DeleteMsg[1024];
+
+ mir_snwprintf(DeleteMsg, TranslateT("Do you really want to delete %d selected mails?"), Total);
+ if (IDOK == MessageBox(hDlg, DeleteMsg, TranslateT("Delete confirmation"), MB_OKCANCEL | MB_ICONWARNING)) {
+ struct DeleteParam ParamToDeleteMails = {YAMN_DELETEVERSION, ThreadRunningEV, ActualAccount, nullptr};
+
+ // Find if there's mail marked to delete, which was deleted before
+ if (WAIT_OBJECT_0 == WaitToWriteFcn(ActualAccount->MessagesAccessSO)) {
+ for (ActualMail = (HYAMNMAIL)ActualAccount->Mails; ActualMail != nullptr; ActualMail = ActualMail->Next) {
+ if ((ActualMail->Flags & YAMN_MSG_DELETED) && ((ActualMail->Flags & YAMN_MSG_USERDELETE))) //if selected mail was already deleted
+ {
+ DeleteMessageFromQueueFcn((HYAMNMAIL *)&ActualAccount->Mails, ActualMail, 1);
+ CallService(MS_YAMN_DELETEACCOUNTMAIL, (WPARAM)ActualAccount->Plugin, (LPARAM)ActualMail); //delete it from memory
+ continue;
+ }
+ }
+ // Set flag to marked mails that they can be deleted
+ SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_DISPLAY | YAMN_MSG_USERDELETE, 0, YAMN_MSG_DELETEOK, 1);
+ // Create new thread which deletes marked mails.
+ HANDLE NewThread = mir_forkthread(ActualAccount->Plugin->Fcn->DeleteMailsFcnPtr, &ParamToDeleteMails);
+ if (NewThread != nullptr)
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+
+ // Enable write-access to mails
+ WriteDoneFcn(ActualAccount->MessagesAccessSO);
+ }
+ }
+ else //else mark messages that they are not to be deleted
+ SetRemoveFlagsInQueueFcn((HYAMNMAIL)ActualAccount->Mails, YAMN_MSG_DISPLAY | YAMN_MSG_USERDELETE, 0, YAMN_MSG_USERDELETE, 0);
+ }
+ }
+ CloseHandle(ThreadRunningEV);
+ if (g_plugin.getByte(YAMN_CLOSEDELETE, 0))
+ DestroyWindow(hDlg);
+ }
+ break;
+ }
+ break;
+
+ case WM_SIZE:
+ if (wParam == SIZE_RESTORED) {
+ LONG x = LOWORD(lParam); //((LPRECT)lParam)->right-((LPRECT)lParam)->left;
+ LONG y = HIWORD(lParam); //((LPRECT)lParam)->bottom-((LPRECT)lParam)->top;
+ MoveWindow(GetDlgItem(hDlg, IDC_BTNDEL), 5, y - 5 - 25, (x - 20) / 3, 25, TRUE); //where to put DELETE button while resizing
+ MoveWindow(GetDlgItem(hDlg, IDC_BTNCHECKALL), 10 + (x - 20) / 3, y - 5 - 25, (x - 20) / 6, 25, TRUE); //where to put CHECK ALL button while resizing
+ MoveWindow(GetDlgItem(hDlg, IDC_BTNAPP), 15 + (x - 20) / 3 + (x - 20) / 6, y - 5 - 25, (x - 20) / 3, 25, TRUE); //where to put RUN APP button while resizing
+ MoveWindow(GetDlgItem(hDlg, IDC_BTNOK), 20 + 2 * (x - 20) / 3 + (x - 20) / 6, y - 5 - 25, (x - 20) / 6, 25, TRUE); //where to put OK button while resizing
+ MoveWindow(GetDlgItem(hDlg, IDC_LISTMAILS), 5, 5, x - 10, y - 55, TRUE); //where to put list mail window while resizing
+ MoveWindow(GetDlgItem(hDlg, IDC_STSTATUS), 5, y - 5 - 45, x - 10, 15, TRUE); //where to put account status text while resizing
+ }
+ return 0;
+
+ case WM_GETMINMAXINFO:
+ ((LPMINMAXINFO)lParam)->ptMinTrackSize.x = MAILBROWSER_MINXSIZE;
+ ((LPMINMAXINFO)lParam)->ptMinTrackSize.y = MAILBROWSER_MINYSIZE;
+ return 0;
+
+ case WM_TIMER:
+ {
+ NOTIFYICONDATA nid;
+ struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+
+ memset(&nid, 0, sizeof(nid));
+ nid.cbSize = sizeof(NOTIFYICONDATA);
+ nid.hWnd = hDlg;
+ nid.uID = 0;
+ nid.uFlags = NIF_ICON;
+ if (mwui->TrayIconState == 0)
+ nid.hIcon = g_plugin.getIcon(IDI_CHECKMAIL);
+ else
+ nid.hIcon = g_plugin.getIcon(IDI_NEWMAIL);
+ Shell_NotifyIcon(NIM_MODIFY, &nid);
+ mwui->TrayIconState = !mwui->TrayIconState;
+ // UpdateWindow(hDlg);
+ }
+ break;
+
+ case WM_NOTIFY:
+ switch (((LPNMHDR)lParam)->idFrom) {
+ case IDC_LISTMAILS:
+ switch (((LPNMHDR)lParam)->code) {
+ case NM_DBLCLK:
+ SendMessage(hDlg, WM_YAMN_SHOWSELECTED, 0, 0);
+ break;
+
+ case LVN_COLUMNCLICK:
+ if (nullptr != (ActualAccount = GetWindowAccount(hDlg))) {
+ NM_LISTVIEW *pNMListView = (NM_LISTVIEW *)lParam;
+ if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ switch ((int)pNMListView->iSubItem) {
+ case 0:
+ bFrom = !bFrom;
+ break;
+ case 1:
+ bSub = !bSub;
+ break;
+ case 2:
+ bSize = !bSize;
+ break;
+ case 3:
+ bDate = !bDate;
+ break;
+ default:
+ break;
+ }
+ ListView_SortItems(pNMListView->hdr.hwndFrom, ListViewCompareProc, pNMListView->iSubItem);
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ }
+ break;
+
+ case NM_CUSTOMDRAW:
+ {
+ LPNMLVCUSTOMDRAW cd = (LPNMLVCUSTOMDRAW)lParam;
+ LONG_PTR PaintCode;
+
+ if (nullptr == (ActualAccount = GetWindowAccount(hDlg)))
+ break;
+
+ switch (cd->nmcd.dwDrawStage) {
+ case CDDS_PREPAINT:
+ PaintCode = CDRF_NOTIFYITEMDRAW;
+ break;
+ case CDDS_ITEMPREPAINT:
+ PaintCode = CDRF_NOTIFYSUBITEMDRAW;
+ break;
+ case CDDS_ITEMPREPAINT | CDDS_SUBITEM:
+ {
+ BOOL umma;
+ {
+ struct CMailWinUserInfo *mwui = (struct CMailWinUserInfo *)GetWindowLongPtr(hDlg, DWLP_USER);
+ umma = mwui->UpdateMailsMessagesAccess;
+ }
+ HYAMNMAIL ActualMail = (HYAMNMAIL)cd->nmcd.lItemlParam;
+ if (!ActualMail)
+ ActualMail = (HYAMNMAIL)readItemLParam(cd->nmcd.hdr.hwndFrom, cd->nmcd.dwItemSpec);
+
+ if (!umma)
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->MessagesAccessSO))
+ return 0;
+
+ switch (ActualMail->Flags & YAMN_MSG_SPAMMASK) {
+ case YAMN_MSG_SPAML1:
+ case YAMN_MSG_SPAML2:
+ cd->clrText = RGB(150, 150, 150);
+ break;
+ case YAMN_MSG_SPAML3:
+ cd->clrText = RGB(200, 200, 200);
+ cd->clrTextBk = RGB(160, 160, 160);
+ break;
+ case 0:
+ if (cd->nmcd.dwItemSpec & 1)
+ cd->clrTextBk = RGB(230, 230, 230);
+ break;
+ default:
+ break;
+ }
+ if (ActualMail->Flags & YAMN_MSG_UNSEEN)
+ cd->clrTextBk = RGB(220, 235, 250);
+ PaintCode = CDRF_DODEFAULT;
+
+ if (!umma)
+ ReadDoneFcn(ActualAccount->MessagesAccessSO);
+ break;
+ }
+ default:
+ PaintCode = 0;
+ }
+ SetWindowLongPtr(hDlg, DWLP_MSGRESULT, PaintCode);
+ return 1;
+ }
+ }
+ }
+ break;
+
+ case WM_CONTEXTMENU:
+ if (GetWindowLongPtr((HWND)wParam, GWLP_ID) == IDC_LISTMAILS) {
+ //MessageBox(0,"LISTHEADERS","Debug",0);
+ HWND hList = GetDlgItem(hDlg, IDC_LISTMAILS);
+ POINT pt = {GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
+ if (pt.x == -1) pt.x = 0;
+ if (pt.y == -1) pt.y = 0;
+ if (int numRows = ListView_GetItemCount(hList)) {
+ HMENU hMenu = CreatePopupMenu();
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)1, TranslateT("Copy Selected"));
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)2, TranslateT("Copy All"));
+ AppendMenu(hMenu, MF_SEPARATOR, 0, nullptr);
+ AppendMenu(hMenu, MF_STRING, (UINT_PTR)0, TranslateT("Cancel"));
+ int nReturnCmd = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, 0, hDlg, nullptr);
+ DestroyMenu(hMenu);
+ if (nReturnCmd > 0) {
+ int courRow = 0;
+ size_t sizeNeeded = 0;
+ wchar_t from[128] = {0}, subject[256] = {0}, size[16] = {0}, date[64] = {0};
+ for (courRow = 0; courRow < numRows; courRow++) {
+ if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue;
+ ListView_GetItemText(hList, courRow, 0, from, _countof(from));
+ ListView_GetItemText(hList, courRow, 1, subject, _countof(subject));
+ ListView_GetItemText(hList, courRow, 2, size, _countof(size));
+ ListView_GetItemText(hList, courRow, 3, date, _countof(date));
+ sizeNeeded += 5 + mir_wstrlen(from) + mir_wstrlen(subject) + mir_wstrlen(size) + mir_wstrlen(date);
+ }
+ if (sizeNeeded && OpenClipboard(hDlg)) {
+ EmptyClipboard();
+ HGLOBAL hData = GlobalAlloc(GMEM_MOVEABLE, (sizeNeeded + 1) * sizeof(wchar_t));
+ wchar_t *buff = (wchar_t *)GlobalLock(hData);
+ int courPos = 0;
+ for (courRow = 0; courRow < numRows; courRow++) {
+ if ((nReturnCmd == 1) && (ListView_GetItemState(hList, courRow, LVIS_SELECTED) == 0)) continue;
+ ListView_GetItemText(hList, courRow, 0, from, _countof(from));
+ ListView_GetItemText(hList, courRow, 1, subject, _countof(subject));
+ ListView_GetItemText(hList, courRow, 2, size, _countof(size));
+ ListView_GetItemText(hList, courRow, 3, date, _countof(date));
+ courPos += mir_snwprintf(&buff[courPos], sizeNeeded + 1, L"%s\t%s\t%s\t%s\r\n", from, subject, size, date);
+ }
+ GlobalUnlock(hData);
+
+ SetClipboardData(CF_UNICODETEXT, hData);
+
+ CloseClipboard();
+ }
+ }
+ }
+ }
+ break; // just in case
+ }
+ return 0;
+}
+
+LRESULT CALLBACK ListViewSubclassProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
+{
+ HWND hwndParent = GetParent(hDlg);
+
+ switch (msg) {
+ case WM_GETDLGCODE:
+ {
+ LPMSG lpmsg = (LPMSG)lParam;
+ if (lpmsg != nullptr) {
+ if (lpmsg->message == WM_KEYDOWN
+ && lpmsg->wParam == VK_RETURN)
+ return DLGC_WANTALLKEYS;
+ }
+ }
+ break;
+
+ case WM_KEYDOWN:
+ {
+ BOOL isCtrl = GetKeyState(VK_CONTROL) & 0x8000;
+ BOOL isShift = GetKeyState(VK_SHIFT) & 0x8000;
+ BOOL isAlt = GetKeyState(VK_MENU) & 0x8000;
+
+ switch (wParam) {
+ case 'A': // ctrl-a
+ if (!isAlt && !isShift && isCtrl) SendMessage(hwndParent, WM_COMMAND, IDC_BTNCHECKALL, 0);
+ break;
+ case VK_RETURN:
+ case VK_SPACE:
+ if (!isAlt && !isShift && !isCtrl) SendMessage(hwndParent, WM_YAMN_SHOWSELECTED, 0, 0);
+ break;
+ case VK_DELETE:
+ SendMessage(hwndParent, WM_COMMAND, IDC_BTNDEL, 0);
+ break;
+ }
+ }
+ break;
+ }
+ return mir_callNextSubclass(hDlg, ListViewSubclassProc, msg, wParam, lParam);
+}
+
+void __cdecl MailBrowser(void *Param)
+{
+ MSG msg;
+
+ HWND hMailBrowser;
+ BOOL WndFound = FALSE;
+
+ struct MailBrowserWinParam MyParam = *(struct MailBrowserWinParam *)Param;
+ CAccount *ActualAccount = MyParam.account;
+ SCIncFcn(ActualAccount->UsingThreads);
+
+ // we will not use params in stack anymore
+ SetEvent(MyParam.ThreadRunningEV);
+
+ __try {
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO))
+ return;
+
+ if (!(ActualAccount->AbilityFlags & YAMN_ACC_BROWSE)) {
+ MyParam.nflags = MyParam.nflags & ~YAMN_ACC_MSG;
+ MyParam.nnflags = MyParam.nnflags & ~YAMN_ACC_MSG;
+ }
+
+ if (!(ActualAccount->AbilityFlags & YAMN_ACC_POPUP))
+ MyParam.nflags = MyParam.nflags & ~YAMN_ACC_POP;
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ if (nullptr != (hMailBrowser = WindowList_Find(YAMNVar.NewMailAccountWnd, (UINT_PTR)ActualAccount)))
+ WndFound = TRUE;
+
+ if ((hMailBrowser == nullptr) && ((MyParam.nflags & YAMN_ACC_MSG) || (MyParam.nflags & YAMN_ACC_ICO) || (MyParam.nnflags & YAMN_ACC_MSG))) {
+ hMailBrowser = CreateDialogParamW(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_DLGVIEWMESSAGES), nullptr, DlgProcYAMNMailBrowser, (LPARAM)&MyParam);
+ Window_SetIcon_IcoLib(hMailBrowser, g_plugin.getIconHandle(IDI_NEWMAIL));
+ MoveWindow(hMailBrowser, PosX, PosY, SizeX, SizeY, TRUE);
+ }
+
+ if (hMailBrowser != nullptr) {
+ struct CChangeContent Params = {MyParam.nflags, MyParam.nnflags}; //if this thread created window, just post message to update mails
+
+ SendMessage(hMailBrowser, WM_YAMN_CHANGECONTENT, (WPARAM)ActualAccount, (LPARAM)&Params); //we ensure this will do the thread who created the browser window
+ }
+ else
+ UpdateMails(nullptr, ActualAccount, MyParam.nflags, MyParam.nnflags); //update mails without displaying or refreshing any window
+
+ if ((hMailBrowser != nullptr) && !WndFound) { //we process message loop only for thread that created window
+ while (GetMessage(&msg, nullptr, 0, 0)) {
+ if (hMailBrowser == nullptr || !IsDialogMessage(hMailBrowser, &msg)) { /* Wine fix. */
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ }
+ }
+
+ if ((!WndFound) && (ActualAccount->Plugin->Fcn != nullptr) && (ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr != nullptr) && ActualAccount->AbleToWork)
+ ActualAccount->Plugin->Fcn->WriteAccountsFcnPtr();
+ }
+ __finally {
+ SCDecFcn(ActualAccount->UsingThreads);
+ }
+}
+
+INT_PTR RunMailBrowserSvc(WPARAM wParam, LPARAM lParam)
+{
+ PYAMN_MAILBROWSERPARAM Param = (PYAMN_MAILBROWSERPARAM)wParam;
+
+ if ((uint32_t)lParam != YAMN_MAILBROWSERVERSION)
+ return 0;
+
+ //an event for successfull copy parameters to which point a pointer in stack for new thread
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ Param->ThreadRunningEV = ThreadRunningEV;
+
+ HANDLE NewThread = mir_forkthread(MailBrowser, Param);
+ if (NewThread != nullptr)
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+
+ CloseHandle(ThreadRunningEV);
+ return 1;
+}
diff --git a/protocols/YAMN/src/debug.cpp b/protocols/YAMN/src/debug.cpp index 1fc41adc19..65322366ab 100644 --- a/protocols/YAMN/src/debug.cpp +++ b/protocols/YAMN/src/debug.cpp @@ -1,111 +1,111 @@ -/* - * YAMN plugin main file - * Miranda homepage: http://miranda-icq.sourceforge.net/ - * - * Debug functions used in DEBUG release (you need to global #define DEBUG to get debug version) - * - * (c) majvan 2002-2004 - */ - -#include "stdafx.h" - -#ifdef _DEBUG - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -wchar_t DebugUserDirectory[MAX_PATH] = L"."; -CRITICAL_SECTION FileAccessCS; - -#ifdef DEBUG_COMM -wchar_t DebugCommFileName2[]=L"%s\\yamn-debug.comm.log"; -HANDLE CommFile; -#endif - -#ifdef DEBUG_DECODE -wchar_t DebugDecodeFileName2[]=L"%s\\yamn-debug.decode.log"; -HANDLE DecodeFile; -#endif - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -void InitDebug() -{ -#if defined (DEBUG_COMM) || defined (DEBUG_DECODE) - wchar_t DebugFileName[MAX_PATH]; -#endif - InitializeCriticalSection(&FileAccessCS); - -#ifdef DEBUG_COMM - mir_snwprintf(DebugFileName, DebugCommFileName2, DebugUserDirectory); - - CommFile=CreateFile(DebugFileName,GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,CREATE_ALWAYS,0,NULL); - DebugLog(CommFile,"Communication debug file created by %s\n",YAMN_VER); -#endif - -#ifdef DEBUG_DECODE - mir_snwprintf(DebugFileName, DebugDecodeFileName2, DebugUserDirectory); - - DecodeFile=CreateFile(DebugFileName,GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,CREATE_ALWAYS,0,NULL); - DebugLog(DecodeFile,"Decoding kernel debug file created by %s\n",YAMN_VER); -#endif -} - -void UnInitDebug() -{ - DeleteCriticalSection(&FileAccessCS); -#ifdef DEBUG_COMM - DebugLog(CommFile,"File is being closed normally."); - CloseHandle(CommFile); -#endif -#ifdef DEBUG_DECODE - DebugLog(DecodeFile,"File is being closed normally."); - CloseHandle(DecodeFile); -#endif -} - - -void DebugLog(HANDLE File,const char *fmt,...) -{ - char *str; - char tids[32]; - va_list vararg; - int strsize; - DWORD Written; - - va_start(vararg,fmt); - str=(char *)malloc(strsize=65536); - mir_snprintf(tids, "[%x]",GetCurrentThreadId()); - while(mir_vsnprintf(str, strsize, fmt, vararg)==-1) - str=(char *)realloc(str,strsize+=65536); - va_end(vararg); - EnterCriticalSection(&FileAccessCS); - WriteFile(File,tids,(uint32_t)mir_strlen(tids),&Written,nullptr); - WriteFile(File,str,(uint32_t)mir_strlen(str),&Written,nullptr); - LeaveCriticalSection(&FileAccessCS); - free(str); -} - -void DebugLogW(HANDLE File,const wchar_t *fmt,...) -{ - wchar_t *str; - char tids[32]; - va_list vararg; - int strsize; - DWORD Written; - - va_start(vararg,fmt); - str=(wchar_t *)malloc((strsize=65536)*sizeof(wchar_t)); - mir_snprintf(tids, "[%x]",GetCurrentThreadId()); - while(mir_vsnwprintf(str, strsize, fmt, vararg)==-1) - str=(wchar_t *)realloc(str,(strsize+=65536)*sizeof(wchar_t)); - va_end(vararg); - EnterCriticalSection(&FileAccessCS); - WriteFile(File,tids,(uint32_t)mir_strlen(tids),&Written,nullptr); - WriteFile(File,str,(uint32_t)mir_wstrlen(str)*sizeof(wchar_t),&Written,nullptr); - LeaveCriticalSection(&FileAccessCS); - free(str); -} - +/*
+ * YAMN plugin main file
+ * Miranda homepage: http://miranda-icq.sourceforge.net/
+ *
+ * Debug functions used in DEBUG release (you need to global #define DEBUG to get debug version)
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+#ifdef _DEBUG
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+wchar_t DebugUserDirectory[MAX_PATH] = L".";
+CRITICAL_SECTION FileAccessCS;
+
+#ifdef DEBUG_COMM
+wchar_t DebugCommFileName2[]=L"%s\\yamn-debug.comm.log";
+HANDLE CommFile;
+#endif
+
+#ifdef DEBUG_DECODE
+wchar_t DebugDecodeFileName2[]=L"%s\\yamn-debug.decode.log";
+HANDLE DecodeFile;
+#endif
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+void InitDebug()
+{
+#if defined (DEBUG_COMM) || defined (DEBUG_DECODE)
+ wchar_t DebugFileName[MAX_PATH];
+#endif
+ InitializeCriticalSection(&FileAccessCS);
+
+#ifdef DEBUG_COMM
+ mir_snwprintf(DebugFileName, DebugCommFileName2, DebugUserDirectory);
+
+ CommFile=CreateFile(DebugFileName,GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,CREATE_ALWAYS,0,NULL);
+ DebugLog(CommFile,"Communication debug file created by %s\n",YAMN_VER);
+#endif
+
+#ifdef DEBUG_DECODE
+ mir_snwprintf(DebugFileName, DebugDecodeFileName2, DebugUserDirectory);
+
+ DecodeFile=CreateFile(DebugFileName,GENERIC_WRITE,FILE_SHARE_WRITE|FILE_SHARE_READ,NULL,CREATE_ALWAYS,0,NULL);
+ DebugLog(DecodeFile,"Decoding kernel debug file created by %s\n",YAMN_VER);
+#endif
+}
+
+void UnInitDebug()
+{
+ DeleteCriticalSection(&FileAccessCS);
+#ifdef DEBUG_COMM
+ DebugLog(CommFile,"File is being closed normally.");
+ CloseHandle(CommFile);
+#endif
+#ifdef DEBUG_DECODE
+ DebugLog(DecodeFile,"File is being closed normally.");
+ CloseHandle(DecodeFile);
+#endif
+}
+
+
+void DebugLog(HANDLE File,const char *fmt,...)
+{
+ char *str;
+ char tids[32];
+ va_list vararg;
+ int strsize;
+ DWORD Written;
+
+ va_start(vararg,fmt);
+ str=(char *)malloc(strsize=65536);
+ mir_snprintf(tids, "[%x]",GetCurrentThreadId());
+ while(mir_vsnprintf(str, strsize, fmt, vararg)==-1)
+ str=(char *)realloc(str,strsize+=65536);
+ va_end(vararg);
+ EnterCriticalSection(&FileAccessCS);
+ WriteFile(File,tids,(uint32_t)mir_strlen(tids),&Written,nullptr);
+ WriteFile(File,str,(uint32_t)mir_strlen(str),&Written,nullptr);
+ LeaveCriticalSection(&FileAccessCS);
+ free(str);
+}
+
+void DebugLogW(HANDLE File,const wchar_t *fmt,...)
+{
+ wchar_t *str;
+ char tids[32];
+ va_list vararg;
+ int strsize;
+ DWORD Written;
+
+ va_start(vararg,fmt);
+ str=(wchar_t *)malloc((strsize=65536)*sizeof(wchar_t));
+ mir_snprintf(tids, "[%x]",GetCurrentThreadId());
+ while(mir_vsnwprintf(str, strsize, fmt, vararg)==-1)
+ str=(wchar_t *)realloc(str,(strsize+=65536)*sizeof(wchar_t));
+ va_end(vararg);
+ EnterCriticalSection(&FileAccessCS);
+ WriteFile(File,tids,(uint32_t)mir_strlen(tids),&Written,nullptr);
+ WriteFile(File,str,(uint32_t)mir_wstrlen(str)*sizeof(wchar_t),&Written,nullptr);
+ LeaveCriticalSection(&FileAccessCS);
+ free(str);
+}
+
#endif //ifdef DEBUG
\ No newline at end of file diff --git a/protocols/YAMN/src/debug.h b/protocols/YAMN/src/debug.h index a13ac952b0..e2e8e3e506 100644 --- a/protocols/YAMN/src/debug.h +++ b/protocols/YAMN/src/debug.h @@ -1,50 +1,50 @@ -#ifndef __DEBUG_H -#define __DEBUG_H - -#ifdef _DEBUG - -//#define DEBUG_COMM //debug communiation to a file -//#define DEBUG_DECODE //debug header decoding to a file -//#define DEBUG_DECODECODEPAGE //add info about codepage used in conversion -//#define DEBUG_DECODEBASE64 //add info about base64 result -//#define DEBUG_DECODEQUOTED //add info about quoted printable result -//#define DEBUG_FILEREAD //debug file reading to message boxes -//#define DEBUG_FILEREADMESSAGES //debug file reading messages to message boxes - -void DebugLog(HANDLE,const char *fmt,...); -void DebugLogW(HANDLE File,const wchar_t *fmt,...); - -#ifdef DEBUG_SYNCHRO -// Used for synchronization debug -extern HANDLE SynchroFile; -#endif - -#ifdef DEBUG_COMM -// Used for communication debug -extern HANDLE CommFile; -#endif - -#ifdef DEBUG_DECODE -// Used for decoding debug -extern HANDLE DecodeFile; -#endif - -#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES) -uint32_t ReadStringFromMemory(char **Parser,char *End,char **StoreTo,char *DebugString); - -uint32_t ReadStringFromMemoryW(char **Parser,wchar_t *End,char **StoreTo,wchar_t *DebugString); - -#else -uint32_t ReadStringFromMemory(char **Parser,char *End,char **StoreTo); - -uint32_t ReadStringFromMemoryW(wchar_t **Parser,wchar_t *End,wchar_t **StoreTo); - -#endif - -//#ifdef DEBUG_ACCOUNTS -//int GetAccounts(); -//void WriteAccounts(); -//#endif - -#endif //YAMN_DEBUG -#endif //_DEBUG_H +#ifndef __DEBUG_H
+#define __DEBUG_H
+
+#ifdef _DEBUG
+
+//#define DEBUG_COMM //debug communiation to a file
+//#define DEBUG_DECODE //debug header decoding to a file
+//#define DEBUG_DECODECODEPAGE //add info about codepage used in conversion
+//#define DEBUG_DECODEBASE64 //add info about base64 result
+//#define DEBUG_DECODEQUOTED //add info about quoted printable result
+//#define DEBUG_FILEREAD //debug file reading to message boxes
+//#define DEBUG_FILEREADMESSAGES //debug file reading messages to message boxes
+
+void DebugLog(HANDLE,const char *fmt,...);
+void DebugLogW(HANDLE File,const wchar_t *fmt,...);
+
+#ifdef DEBUG_SYNCHRO
+// Used for synchronization debug
+extern HANDLE SynchroFile;
+#endif
+
+#ifdef DEBUG_COMM
+// Used for communication debug
+extern HANDLE CommFile;
+#endif
+
+#ifdef DEBUG_DECODE
+// Used for decoding debug
+extern HANDLE DecodeFile;
+#endif
+
+#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES)
+uint32_t ReadStringFromMemory(char **Parser,char *End,char **StoreTo,char *DebugString);
+
+uint32_t ReadStringFromMemoryW(char **Parser,wchar_t *End,char **StoreTo,wchar_t *DebugString);
+
+#else
+uint32_t ReadStringFromMemory(char **Parser,char *End,char **StoreTo);
+
+uint32_t ReadStringFromMemoryW(wchar_t **Parser,wchar_t *End,wchar_t **StoreTo);
+
+#endif
+
+//#ifdef DEBUG_ACCOUNTS
+//int GetAccounts();
+//void WriteAccounts();
+//#endif
+
+#endif //YAMN_DEBUG
+#endif //_DEBUG_H
diff --git a/protocols/YAMN/src/filterplugin.cpp b/protocols/YAMN/src/filterplugin.cpp index 1d55f3a9c1..451ea155aa 100644 --- a/protocols/YAMN/src/filterplugin.cpp +++ b/protocols/YAMN/src/filterplugin.cpp @@ -1,169 +1,169 @@ -/* - * YAMN plugin export functions for filtering - * - * (c) majvan 2002-2004 - */ - -#include "stdafx.h" - - //-------------------------------------------------------------------------------------------------- - //-------------------------------------------------------------------------------------------------- - -PYAMN_FILTERPLUGINQUEUE FirstFilterPlugin = nullptr; - -INT_PTR RegisterFilterPluginSvc(WPARAM, LPARAM); - -//Removes plugin from queue and deletes its structures -INT_PTR UnregisterFilterPlugin(HYAMNFILTERPLUGIN Plugin); - -INT_PTR UnregisterFilterPluginSvc(WPARAM wParam, LPARAM lParam); - -//Removes all filter plugins -INT_PTR UnregisterFilterPlugins(); - -INT_PTR FilterMailSvc(WPARAM, LPARAM); - -//Sets imported functions for an plugin and therefore it starts plugin to be registered and running -// Plugin- plugin, which wants to set its functions -// Importance- importance of plugin (see m_filterplugin.h) -// YAMNFilterFcn- pointer to imported functions -// YAMNfilterFcnVer- version of YAMN_FILTERIMPORTFCN, use YAMN_FILTERIMPORTFCNVERSION -// returns nonzero if success -int WINAPI SetFilterPluginFcnImportFcn(HYAMNFILTERPLUGIN Plugin, uint32_t Importance, PYAMN_FILTERIMPORTFCN YAMNFilterFcn, uint32_t YAMNFilterFcnVer); - -struct CExportedFunctions FilterPluginExportedFcn[] = -{ - {YAMN_SETFILTERPLUGINFCNIMPORTID, (void *)SetFilterPluginFcnImportFcn}, -}; - -struct CExportedServices FilterPluginExportedSvc[] = -{ - {MS_YAMN_REGISTERFILTERPLUGIN, RegisterFilterPluginSvc}, - {MS_YAMN_UNREGISTERFILTERPLUGIN, UnregisterFilterPluginSvc}, -}; - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -INT_PTR RegisterFilterPluginSvc(WPARAM wParam, LPARAM lParam) -{ - PYAMN_FILTERREGISTRATION Registration = (PYAMN_FILTERREGISTRATION)wParam; - HYAMNFILTERPLUGIN Plugin; - - if (lParam != YAMN_FILTERREGISTRATIONVERSION) - return 0; - if ((Registration->Name == nullptr) || (Registration->Ver == nullptr)) - return NULL; - if (nullptr == (Plugin = new YAMN_FILTERPLUGIN)) - return NULL; - - Plugin->PluginInfo = Registration; - Plugin->FilterFcn = nullptr; - return (INT_PTR)Plugin; -} - -INT_PTR UnregisterFilterPlugin(HYAMNFILTERPLUGIN Plugin) -{ - PYAMN_FILTERPLUGINQUEUE Parser, Found; - - if (FirstFilterPlugin->Plugin == Plugin) { - Found = FirstFilterPlugin; - FirstFilterPlugin = FirstFilterPlugin->Next; - } - else { - for (Parser = FirstFilterPlugin; (Parser->Next != nullptr) && (Plugin != Parser->Next->Plugin); Parser = Parser->Next); - if (Parser->Next != nullptr) { - Found = Parser->Next; - Parser->Next = Parser->Next->Next; - } - else - Found = nullptr; - } - if (Found != nullptr) { - if (Plugin->FilterFcn->UnLoadFcn != nullptr) - Plugin->FilterFcn->UnLoadFcn((void *)nullptr); - - delete Found->Plugin; - delete Found; - return 1; - } - - return 0; -} - -INT_PTR UnregisterFilterPluginSvc(WPARAM wParam, LPARAM) -{ - HYAMNFILTERPLUGIN Plugin = (HYAMNFILTERPLUGIN)wParam; - - mir_cslock lck(PluginRegCS); - UnregisterFilterPlugin(Plugin); - return 1; -} - -INT_PTR UnregisterFilterPlugins() -{ - mir_cslock lck(PluginRegCS); - - // We remove protocols from the protocol list - while (FirstFilterPlugin != nullptr) - UnregisterFilterPlugin(FirstFilterPlugin->Plugin); - return 1; -} - -int WINAPI SetFilterPluginFcnImportFcn(HYAMNFILTERPLUGIN Plugin, uint32_t Importance, PYAMN_FILTERIMPORTFCN YAMNFilterFcn, uint32_t YAMNFilterFcnVer) -{ - PYAMN_FILTERPLUGINQUEUE Parser, Previous; - - if (YAMNFilterFcnVer != YAMN_FILTERIMPORTFCNVERSION) - return 0; - if (YAMNFilterFcn == nullptr) - return 0; - - Plugin->Importance = Importance; - Plugin->FilterFcn = YAMNFilterFcn; - - mir_cslock lck(PluginRegCS); - - // We add protocol to the protocol list - for (Previous = nullptr, Parser = FirstFilterPlugin; Parser != nullptr && Parser->Next != nullptr && Parser->Plugin->Importance <= Importance; Previous = Parser, Parser = Parser->Next); - - if (Previous == nullptr) { //insert to the beginnig of queue - FirstFilterPlugin = new YAMN_FILTERPLUGINQUEUE; - FirstFilterPlugin->Plugin = Plugin; - FirstFilterPlugin->Next = Parser; - } - else { - Previous->Next = new YAMN_FILTERPLUGINQUEUE; - Previous = Previous->Next; //leave previous, go to actual plugin - Previous->Plugin = Plugin; - Previous->Next = Parser; //and in actual plugin set, that next plugin is the one we insert in front of - } - return 1; -} - -INT_PTR FilterMailSvc(WPARAM wParam, LPARAM lParam) -{ - CAccount *Account = (CAccount *)wParam; - HYAMNMAIL Mail = (HYAMNMAIL)lParam; - PYAMN_FILTERPLUGINQUEUE ActualPlugin; - - mir_cslock lck(PluginRegCS); - WaitToWriteFcn(Account->MessagesAccessSO); - - for (ActualPlugin = FirstFilterPlugin; ActualPlugin != nullptr; ActualPlugin = ActualPlugin->Next) - if (ActualPlugin->Plugin->FilterFcn->FilterMailFcnPtr != nullptr) - ActualPlugin->Plugin->FilterFcn->FilterMailFcnPtr(Account, YAMN_ACCOUNTVERSION, Mail, YAMN_MAILVERSION); - - Mail->Flags |= YAMN_MSG_FILTERED; - - //Set mail flags according to spamlevel settings - if ((Mail->Flags & YAMN_MSG_SPAMMASK) > YAMN_MSG_SPAML1) - Mail->Flags = Mail->Flags & ~(YAMN_MSG_BROWSER | YAMN_MSG_POPUP | YAMN_MSG_SYSTRAY | YAMN_MSG_SOUND | YAMN_MSG_APP | YAMN_MSG_NEVENT); - if (YAMN_MSG_SPAML(Mail->Flags, YAMN_MSG_SPAML3) || YAMN_MSG_SPAML(Mail->Flags, YAMN_MSG_SPAML4)) - Mail->Flags = Mail->Flags | (YAMN_MSG_AUTODELETE | YAMN_MSG_DELETEOK); //set message to delete - if (YAMN_MSG_SPAML(Mail->Flags, YAMN_MSG_SPAML3)) - Mail->Flags = Mail->Flags & ~(YAMN_MSG_MEMDELETE); //set message not to delete it immidiatelly from memory - - WriteDoneFcn(Account->MessagesAccessSO); - return 1; -} +/*
+ * YAMN plugin export functions for filtering
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+ //--------------------------------------------------------------------------------------------------
+
+PYAMN_FILTERPLUGINQUEUE FirstFilterPlugin = nullptr;
+
+INT_PTR RegisterFilterPluginSvc(WPARAM, LPARAM);
+
+//Removes plugin from queue and deletes its structures
+INT_PTR UnregisterFilterPlugin(HYAMNFILTERPLUGIN Plugin);
+
+INT_PTR UnregisterFilterPluginSvc(WPARAM wParam, LPARAM lParam);
+
+//Removes all filter plugins
+INT_PTR UnregisterFilterPlugins();
+
+INT_PTR FilterMailSvc(WPARAM, LPARAM);
+
+//Sets imported functions for an plugin and therefore it starts plugin to be registered and running
+// Plugin- plugin, which wants to set its functions
+// Importance- importance of plugin (see m_filterplugin.h)
+// YAMNFilterFcn- pointer to imported functions
+// YAMNfilterFcnVer- version of YAMN_FILTERIMPORTFCN, use YAMN_FILTERIMPORTFCNVERSION
+// returns nonzero if success
+int WINAPI SetFilterPluginFcnImportFcn(HYAMNFILTERPLUGIN Plugin, uint32_t Importance, PYAMN_FILTERIMPORTFCN YAMNFilterFcn, uint32_t YAMNFilterFcnVer);
+
+struct CExportedFunctions FilterPluginExportedFcn[] =
+{
+ {YAMN_SETFILTERPLUGINFCNIMPORTID, (void *)SetFilterPluginFcnImportFcn},
+};
+
+struct CExportedServices FilterPluginExportedSvc[] =
+{
+ {MS_YAMN_REGISTERFILTERPLUGIN, RegisterFilterPluginSvc},
+ {MS_YAMN_UNREGISTERFILTERPLUGIN, UnregisterFilterPluginSvc},
+};
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+INT_PTR RegisterFilterPluginSvc(WPARAM wParam, LPARAM lParam)
+{
+ PYAMN_FILTERREGISTRATION Registration = (PYAMN_FILTERREGISTRATION)wParam;
+ HYAMNFILTERPLUGIN Plugin;
+
+ if (lParam != YAMN_FILTERREGISTRATIONVERSION)
+ return 0;
+ if ((Registration->Name == nullptr) || (Registration->Ver == nullptr))
+ return NULL;
+ if (nullptr == (Plugin = new YAMN_FILTERPLUGIN))
+ return NULL;
+
+ Plugin->PluginInfo = Registration;
+ Plugin->FilterFcn = nullptr;
+ return (INT_PTR)Plugin;
+}
+
+INT_PTR UnregisterFilterPlugin(HYAMNFILTERPLUGIN Plugin)
+{
+ PYAMN_FILTERPLUGINQUEUE Parser, Found;
+
+ if (FirstFilterPlugin->Plugin == Plugin) {
+ Found = FirstFilterPlugin;
+ FirstFilterPlugin = FirstFilterPlugin->Next;
+ }
+ else {
+ for (Parser = FirstFilterPlugin; (Parser->Next != nullptr) && (Plugin != Parser->Next->Plugin); Parser = Parser->Next);
+ if (Parser->Next != nullptr) {
+ Found = Parser->Next;
+ Parser->Next = Parser->Next->Next;
+ }
+ else
+ Found = nullptr;
+ }
+ if (Found != nullptr) {
+ if (Plugin->FilterFcn->UnLoadFcn != nullptr)
+ Plugin->FilterFcn->UnLoadFcn((void *)nullptr);
+
+ delete Found->Plugin;
+ delete Found;
+ return 1;
+ }
+
+ return 0;
+}
+
+INT_PTR UnregisterFilterPluginSvc(WPARAM wParam, LPARAM)
+{
+ HYAMNFILTERPLUGIN Plugin = (HYAMNFILTERPLUGIN)wParam;
+
+ mir_cslock lck(PluginRegCS);
+ UnregisterFilterPlugin(Plugin);
+ return 1;
+}
+
+INT_PTR UnregisterFilterPlugins()
+{
+ mir_cslock lck(PluginRegCS);
+
+ // We remove protocols from the protocol list
+ while (FirstFilterPlugin != nullptr)
+ UnregisterFilterPlugin(FirstFilterPlugin->Plugin);
+ return 1;
+}
+
+int WINAPI SetFilterPluginFcnImportFcn(HYAMNFILTERPLUGIN Plugin, uint32_t Importance, PYAMN_FILTERIMPORTFCN YAMNFilterFcn, uint32_t YAMNFilterFcnVer)
+{
+ PYAMN_FILTERPLUGINQUEUE Parser, Previous;
+
+ if (YAMNFilterFcnVer != YAMN_FILTERIMPORTFCNVERSION)
+ return 0;
+ if (YAMNFilterFcn == nullptr)
+ return 0;
+
+ Plugin->Importance = Importance;
+ Plugin->FilterFcn = YAMNFilterFcn;
+
+ mir_cslock lck(PluginRegCS);
+
+ // We add protocol to the protocol list
+ for (Previous = nullptr, Parser = FirstFilterPlugin; Parser != nullptr && Parser->Next != nullptr && Parser->Plugin->Importance <= Importance; Previous = Parser, Parser = Parser->Next);
+
+ if (Previous == nullptr) { //insert to the beginnig of queue
+ FirstFilterPlugin = new YAMN_FILTERPLUGINQUEUE;
+ FirstFilterPlugin->Plugin = Plugin;
+ FirstFilterPlugin->Next = Parser;
+ }
+ else {
+ Previous->Next = new YAMN_FILTERPLUGINQUEUE;
+ Previous = Previous->Next; //leave previous, go to actual plugin
+ Previous->Plugin = Plugin;
+ Previous->Next = Parser; //and in actual plugin set, that next plugin is the one we insert in front of
+ }
+ return 1;
+}
+
+INT_PTR FilterMailSvc(WPARAM wParam, LPARAM lParam)
+{
+ CAccount *Account = (CAccount *)wParam;
+ HYAMNMAIL Mail = (HYAMNMAIL)lParam;
+ PYAMN_FILTERPLUGINQUEUE ActualPlugin;
+
+ mir_cslock lck(PluginRegCS);
+ WaitToWriteFcn(Account->MessagesAccessSO);
+
+ for (ActualPlugin = FirstFilterPlugin; ActualPlugin != nullptr; ActualPlugin = ActualPlugin->Next)
+ if (ActualPlugin->Plugin->FilterFcn->FilterMailFcnPtr != nullptr)
+ ActualPlugin->Plugin->FilterFcn->FilterMailFcnPtr(Account, YAMN_ACCOUNTVERSION, Mail, YAMN_MAILVERSION);
+
+ Mail->Flags |= YAMN_MSG_FILTERED;
+
+ //Set mail flags according to spamlevel settings
+ if ((Mail->Flags & YAMN_MSG_SPAMMASK) > YAMN_MSG_SPAML1)
+ Mail->Flags = Mail->Flags & ~(YAMN_MSG_BROWSER | YAMN_MSG_POPUP | YAMN_MSG_SYSTRAY | YAMN_MSG_SOUND | YAMN_MSG_APP | YAMN_MSG_NEVENT);
+ if (YAMN_MSG_SPAML(Mail->Flags, YAMN_MSG_SPAML3) || YAMN_MSG_SPAML(Mail->Flags, YAMN_MSG_SPAML4))
+ Mail->Flags = Mail->Flags | (YAMN_MSG_AUTODELETE | YAMN_MSG_DELETEOK); //set message to delete
+ if (YAMN_MSG_SPAML(Mail->Flags, YAMN_MSG_SPAML3))
+ Mail->Flags = Mail->Flags & ~(YAMN_MSG_MEMDELETE); //set message not to delete it immidiatelly from memory
+
+ WriteDoneFcn(Account->MessagesAccessSO);
+ return 1;
+}
diff --git a/protocols/YAMN/src/mails/decode.cpp b/protocols/YAMN/src/mails/decode.cpp index 414edfce60..7306376c2e 100644 --- a/protocols/YAMN/src/mails/decode.cpp +++ b/protocols/YAMN/src/mails/decode.cpp @@ -1,534 +1,534 @@ -/* - * This code implements decoding encoded MIME header in style - * =?iso-8859-2?Q? "User using email in central Europe characters such as =E9" ?= - * - * (c) majvan 2002-2004 - */ -#include "../stdafx.h" -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -struct _tcptable CodePageNamesAll[]= -{ - { "ANSI", "",TRUE,CP_ACP}, - { "WINDOWS-1", "250",0,1250}, - { "WINDOWS-1", "251",0,1251}, - { "WINDOWS-1", "252",0,1252}, - { "WINDOWS-1", "253",0,1253}, - { "WINDOWS-1", "254",0,1254}, - { "WINDOWS-1", "255",0,1255}, - { "WINDOWS-1", "256",0,1256}, - { "WINDOWS-1", "257",0,1257}, - { "WINDOWS-1", "258",0,1258}, - { "CP1", "250",0,1250}, - { "CP1", "251",0,1251}, - { "CP1", "252",0,1252}, - { "CP1", "253",0,1253}, - { "CP1", "254",0,1254}, - { "CP1", "255",0,1255}, - { "CP1", "256",0,1256}, - { "CP1", "257",0,1257}, - { "CP1", "258",0,1258}, - { "ANSI-1", "250",0,1250}, - { "ANSI-1", "251",0,1251}, - { "ANSI-1", "252",0,1252}, - { "ANSI-1", "253",0,1253}, - { "ANSI-1", "254",0,1254}, - { "ANSI-1", "255",0,1255}, - { "ANSI-1", "256",0,1256}, - { "ANSI-1", "257",0,1257}, - { "ANSI-1", "258",0,1258}, - { "KOI8", "-R",0,20866}, - { "KOI8", "",0,20866}, - { "KOI8", "-U",0,21866}, - { "KOI8", "-RU",0,21866}, - { "US-", "ASCII",0,20127}, - { "CP", "367",0,20127}, - { "ASCII", "",0,20127}, - { "ASCII", "7",0,20127}, - { "ISO-8859", "-1",0,28591}, - { "ISO-8859", "-2",0,28592}, - { "ISO-8859", "-3",0,28593}, - { "ISO-8859", "-4",0,28594}, - { "ISO-8859", "-5",0,28595}, - { "ISO-8859", "-6",0,28596}, - { "ISO-8859", "-7",0,28597}, - { "ISO-8859", "-8",0,28598}, - { "ISO-8859", "-9",0,28599}, - { "ISO-8859", "-15",0,28605}, - { "ISO_8859", "-1",0,28591}, - { "ISO_8859", "-2",0,28592}, - { "ISO_8859", "-3",0,28593}, - { "ISO_8859", "-4",0,28594}, - { "ISO_8859", "-5",0,28595}, - { "ISO_8859", "-6",0,28596}, - { "ISO_8859", "-7",0,28597}, - { "ISO_8859", "-8",0,28598}, - { "ISO_8859", "-9",0,28599}, - { "ISO_8859", "-15",0,28605}, - { "ISO-", "10646-USC2",0,1200}, - { "ISO-2022", "/2-JP",0,50220}, - { "ISO-2022", "-JP",0,50221}, - { "ISO-2022", "/JIS-JP",0,50222}, - { "ISO-2022", "-KR",0,50225}, - { "ISO-2022", "-CH(SP)",0,50227}, - { "ISO-2022", "-CH(TR)",0,50229}, - { "UTF-", "7",0,65000}, - { "UTF-", "8",0,65001}, - { "ARAB-", "TRANSPARENT",0,710}, - { "ASMO-", "TRANSPARENT",0,720}, - { "ASMO-", "449",0,709}, - { "ASMO-", "708",0,708}, - { "BIG5", "",0,950}, - { "EUC-", "CH(SP)",0,51936}, - { "EUC-", "CH(TR)",0,51950}, - { "EUC-", "JP",0,51932}, - { "EUC-", "KR",0,51949}, - { "GB-", "2312",0,20936}, - { "GB", "2312",0,20936}, - { "HZGB-", "2312",0,52936}, - { "IBM-", "037",0,37}, - { "IBM-", "290",0,290}, - { "IBM-", "437",0,437}, - { "IBM-", "500",0,500}, - { "IBM-", "775",0,775}, - { "IBM-", "850",0,850}, - { "IBM-", "852",0,852}, - { "IBM-", "855",0,855}, - { "IBM-", "857",0,857}, - { "IBM-", "860",0,860}, - { "IBM-", "861",0,861}, - { "IBM-", "862",0,862}, - { "IBM-", "863",0,863}, - { "IBM-", "864",0,864}, - { "IBM-", "865",0,865}, - { "IBM-", "866",0,866}, - { "IBM-", "869",0,869}, - { "IBM-", "870",0,870}, - { "IBM-", "875",0,875}, - { "IBM-", "1026",0,1026}, - { "IBM-", "273",0,20273}, - { "IBM-", "277",0,20277}, - { "IBM-", "278",0,20278}, - { "IBM-", "280",0,20280}, - { "IBM-", "284",0,20284}, - { "IBM-", "285",0,20285}, - { "IBM-", "290",0,20290}, - { "IBM-", "297",0,20297}, - { "IBM-", "420",0,20420}, - { "IBM-", "423",0,20423}, - { "IBM-", "871",0,20871}, - { "IBM-", "880",0,20880}, - { "IBM-", "905",0,20905}, - { "IBM-", "THAI",0,20838}, - { "ISCII-", "DEVANAGARI",0,57002}, - { "ISCII-", "BENGALI",0,57003}, - { "ISCII-", "TAMIL",0,57004}, - { "ISCII-", "TELUGU",0,57005}, - { "ISCII-", "ASSAMESE",0,57006}, - { "ISCII-", "ORIYA",0,57007}, - { "ISCII-", "KANNADA",0,57008}, - { "ISCII-", "MALAYALAM",0,57009}, - { "ISCII-", "GUJARATI",0,57010}, - { "ISCII-", "PUNJABI",0,57011}, - { "KOR-", "JOHAB",0,1361}, - { "KSC-", "5601",0,1361}, - { "MAC-", "ROMAN",0,10000}, - { "MAC-", "JP",0,10001}, - { "MAC-", "CH(SP)(BIG5)",0,10002}, - { "MAC-", "KR",0,10003}, - { "MAC-", "AR",0,10004}, - { "MAC-", "HW",0,10005}, - { "MAC-", "GR",0,10006}, - { "MAC-", "CY",0,10007}, - { "MAC-", "CH(SP)(GB2312)",0,10008}, - { "MAC-", "ROMANIA",0,10010}, - { "MAC-", "UA",0,10017}, - { "MAC-", "TH",0,10021}, - { "MAC-", "LAT2",0,10029}, - { "MAC-", "ICE",0,10079}, - { "MAC-", "TR",0,10081}, - { "MAC-", "CR",0,10082} -}; - -int CPLENALL = _countof(CodePageNamesAll); -struct _tcptable *CodePageNamesSupp; -int CPLENSUPP = 1; - -//Gets codepage ID from string representing charset such as "iso-8859-1" -// input- the string -// size- max length of input string -int GetCharsetFromString(char *input, size_t size); - -//HexValue to DecValue ('a' to 10) -// HexValue- hexa value ('a') -// DecValue- poiner where to store dec value -// returns 0 if not success -int FromHexa(char HexValue, char *DecValue); - -//Decodes a char from Base64 -// Base64Value- input char in Base64 -// DecValue- pointer where to store the result -// returns 0 if not success -int FromBase64(char Base64Value, char *DecValue); - -//Decodes string in quoted printable -// Src- input string -// Dst- where to store output string -// DstLen- how max long should be output string -// isQ- if is "Q-encoding" modification. should be TRUE in headers -// always returns 1 -int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ); - -//Decodes string in base64 -// Src- input string -// Dst- where to store output string -// DstLen- how max long should be output string -// returns 0 if string was not properly decoded -int DecodeBase64(char *Src, char *Dst, int DstLen); - -//Converts string to unicode from string with specified codepage -// stream- input string -// cp- codepage of input string -// out- pointer to new allocated memory that contains unicode string -int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out); - -//Converts string from MIME header to unicode -// stream- input string -// cp- codepage of input string -// storeto- pointer to memory that contains unicode string -// mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' from start and end of string) -void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode); - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -int GetCharsetFromString(char *input, size_t size) -//"ISO-8859-1" to ID from table -{ - char *pin = input; - char *pout, *parser; - - if ((size < 1) || (parser = pout = new char[size + 1]) == nullptr) - return -1; - while ((*pin != 0) && (pin - input < (INT_PTR)size)) { - if ((*pin >= 'a') && (*pin <= 'z')) - *parser++ = *(pin++) - ('a' - 'A'); // make it capital - //else if (*pin=='\"') // this is already done in ExtractFromContentType - // *pin++; //skip the quotes if any - else - *parser++ = *pin++; - } - - *parser = 0; - - #ifdef DEBUG_DECODECODEPAGE - DebugLog(DecodeFile, "<CodePage>%s</CodePage>", pout); - #endif - for (int i = 0; i < CPLENALL; i++) { - size_t len = mir_strlen(CodePageNamesAll[i].NameBase); - if (0 == strncmp(pout, CodePageNamesAll[i].NameBase, len)) { - if (0 == mir_strcmp(pout + len, CodePageNamesAll[i].NameSub)) { - delete[] pout; - return CodePageNamesAll[i].CP; - } - } - } - delete[] pout; - return -1; //not found -} - -int FromHexa(char HexValue, char *DecValue) -{ - if (HexValue >= '0' && HexValue <= '9') { - *DecValue = HexValue - '0'; - return 1; - } - if (HexValue >= 'A' && HexValue <= 'F') { - *DecValue = HexValue - 'A' + 10; - return 1; - } - if (HexValue >= 'a' && HexValue <= 'f') { - *DecValue = HexValue - 'a' + 10; - return 1; - } - return 0; -} - -int FromBase64(char Base64Value, char *DecValue) -{ - if (Base64Value >= 'A' && Base64Value <= 'Z') { - *DecValue = Base64Value - 'A'; - return 1; - } - if (Base64Value >= 'a' && Base64Value <= 'z') { - *DecValue = Base64Value - 'a' + 26; - return 1; - } - if (Base64Value >= '0' && Base64Value <= '9') { - *DecValue = Base64Value - '0' + 52; - return 1; - } - if (Base64Value == '+') { - *DecValue = Base64Value - '+' + 62; - return 1; - } - if (Base64Value == '/') { - *DecValue = Base64Value - '/' + 63; - return 1; - } - if (Base64Value == '=') { - *DecValue = 0; - return 1; - } - return 0; -} - -int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ) -{ - #ifdef DEBUG_DECODEQUOTED - char *DstTemp = Dst; - DebugLog(DecodeFile, "<Decode Quoted><Input>%s</Input>", Src); - #endif - for (int Counter = 0; (*Src != 0) && DstLen && (Counter++ < DstLen); Src++, Dst++) - if (*Src == '=') { - if (!isQ) { - if (Src[1] == 0x0D) { - Src++; Src++; - if (Src[0] == 0x0A) Src++; - goto CopyCharQuotedPrintable; - } - if (Src[1] == 0x0A) { - Src++; Src++; - goto CopyCharQuotedPrintable; - } - } - char First, Second; - if (!FromHexa(*(++Src), &First)) { - *Dst++ = '='; Src--; - continue; - } - if (!FromHexa(*(++Src), &Second)) { - *Dst++ = '='; Src--; Src--; - continue; - } - *Dst = (char)(First) << 4; - *Dst += Second; - } - else if (isQ && *Src == '_') - *Dst = ' '; - else - CopyCharQuotedPrintable: // Yeah. Bad programming stile. - *Dst = *Src; - *Dst = 0; - #ifdef DEBUG_DECODEQUOTED - DebugLog(DecodeFile, "<Output>%s</Output></Decode Quoted>", DstTemp); - #endif - return 1; -} - -int DecodeBase64(char *Src, char *Dst, int DstLen) -{ - int Result = 0; - char Locator = 0, MiniResult[4]; - char *End = Dst + DstLen; - - MiniResult[0] = MiniResult[1] = MiniResult[2] = MiniResult[3] = 0; - - #ifdef DEBUG_DECODEBASE64 - char *DstTemp = Dst; - DebugLog(DecodeFile, "<Decode Base64><Input>\n%s\n</Input>\n", Src); - #endif - while (*Src != 0 && DstLen && Dst != End) { - if ((*Src == 0x0D) || (*Src == 0x0A)) { - Src++; - continue; - } - if ((!(Result = FromBase64(*Src, MiniResult + Locator)) && (*Src == 0)) || Locator++ == 3) //end_of_str || end_of_4_bytes - { - Locator = 0; //next write to the first byte - *Dst++ = (char)((MiniResult[0] << 2) | (MiniResult[1] >> 4)); - if (Dst == End) goto end; //DstLen exceeded? - *Dst++ = (char)((MiniResult[1] << 4) | (MiniResult[2] >> 2)); - if (Dst == End) goto end; //someones don't like goto, but not me - *Dst++ = (char)((MiniResult[2] << 6) | MiniResult[3]); - if (!Result && (*Src == 0)) goto end; //end of string? - MiniResult[0] = MiniResult[1] = MiniResult[2] = MiniResult[3] = 0; //zero 4byte buffer for next loop - } - if (!Result) return 0; //unrecognised character occured - Src++; - } -end: - *Dst = 0; - #ifdef DEBUG_DECODEBASE64 - DebugLog(DecodeFile, "<Output>\n%s\n</Output></Decode Base64>", DstTemp); - #endif - return 1; -} - - - -int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out) -{ - CPINFO CPInfo; - wchar_t *temp, *src = *out, *dest; - size_t outlen; - int streamlen, Index; - - //codepages, which require to have set 0 in dwFlags parameter when calling MultiByteToWideChar - uint32_t CodePagesZeroFlags[] = {50220, 50221, 50222, 50225, 50227, 50229, 52936, 54936, 57002, 57003, 57004, 57005, 57006, 57007, 57008, 57009, 57010, 57011, 65000, 65001}; - - if ((cp != CP_ACP) && (cp != CP_OEMCP) && (cp != CP_MACCP) && (cp != CP_THREAD_ACP) && (cp != CP_SYMBOL) && (cp != CP_UTF7) && (cp != CP_UTF8) && !GetCPInfo(cp, &CPInfo)) - cp = CP_ACP; - #ifdef DEBUG_DECODECODEPAGE - DebugLog(DecodeFile, "<CodePage #>%d</CodePage #>", cp); - #endif - - for (Index = 0; Index < sizeof(CodePagesZeroFlags) / sizeof(CodePagesZeroFlags[0]); Index++) - if (CodePagesZeroFlags[Index] == cp) { - Index = -1; - break; - } - if (Index == -1) - streamlen = MultiByteToWideChar(cp, 0, stream, -1, nullptr, 0); - else - streamlen = MultiByteToWideChar(cp, MB_USEGLYPHCHARS, stream, -1, nullptr, 0); - - if (*out != nullptr) - outlen = mir_wstrlen(*out); - else - outlen = 0; - temp = new wchar_t[streamlen + outlen + 1]; - - if (*out != nullptr) { - for (dest = temp; *src != (wchar_t)0; src++, dest++) //copy old string from *out to temp - *dest = *src; - // *dest++=L' '; //add space? - delete[] * out; - } - else - dest = temp; - *out = temp; - - if (Index == -1) { - if (!MultiByteToWideChar(cp, 0, stream, -1, dest, streamlen)) - return 0; - } - else { - if (!MultiByteToWideChar(cp, MB_USEGLYPHCHARS, stream, -1, dest, streamlen)) - return 0; - } - return 1; -} - -void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode) -{ - char *start = stream, *finder, *finderend; - char Encoding = 0; - - if (stream == nullptr) - return; - - while (WS(start)) start++; - wchar_t *tempstore = nullptr; - if (!ConvertStringToUnicode(stream, cp, &tempstore))return; - - size_t tempstoreLength = mir_wstrlen(tempstore); - - size_t outind = 0; - while (*start != 0) { - if (CODES(start)) { - finder = start + 2; finderend = finder; - while (!CODED(finderend) && !EOS(finderend)) finderend++; - start = finderend; - if (CODED(finderend)) { - Encoding = *(finderend + 1); - switch (Encoding) { - case 'b': - case 'B': - case 'q': - case 'Q': - break; - default: - goto NotEncoded; - } - if (-1 == (cp = (uint32_t)GetCharsetFromString(finder, finderend - finder))) - cp = CP_ACP; - if (Encoding != 0) { - int size = 0, codeend; - char *pcodeend = nullptr; - - finder = finderend + 2; - if (CODED(finder)) - finder++; - while (WS(finder)) finder++; - finderend = finder; - while (!CODEE(finderend) && !EOS(finderend)) finderend++; - if (codeend = CODEE(finderend)) - pcodeend = finderend; - while (WS(finderend - 1)) finderend--; - if ((mode == MIME_MAIL) && (((*finder == '"') && (*(finderend - 1) == '"')))) { - finder++; - finderend--; - } - char *oneWordEncoded = new char[finderend - finder + 1]; - strncpy(oneWordEncoded, finder, finderend - finder); - oneWordEncoded[finderend - finder] = 0; - switch (Encoding) { - case 'b': - case 'B': - size = (finderend - finder) * 3 / 4 + 3 + 1 + 1; - break; - case 'q': - case 'Q': - size = finderend - finder + 1 + 1; - break; - } - - char *DecodedResult = new char[size + 1]; - switch (Encoding) { - case 'q': - case 'Q': - DecodeQuotedPrintable(oneWordEncoded, DecodedResult, size, TRUE); - break; - case 'b': - case 'B': - DecodeBase64(oneWordEncoded, DecodedResult, size); - break; - } - delete[] oneWordEncoded; - if (codeend) - finderend = pcodeend + 2; - if (WS(finderend)) //if string continues and there's some whitespace, add space to string that is to be converted - { - size_t len = mir_strlen(DecodedResult); - DecodedResult[len] = ' '; - DecodedResult[len + 1] = 0; - finderend++; - } - wchar_t *oneWord = nullptr; - if (ConvertStringToUnicode(DecodedResult, cp, &oneWord)) { - size_t len = mir_wstrlen(oneWord); - memcpy(&tempstore[outind], oneWord, len * sizeof(wchar_t)); - outind += len; - } - delete oneWord; - oneWord = nullptr; - delete[] DecodedResult; - start = finderend; - } - else if (!EOS(start)) start++; - } - else if (!EOS(start)) start++; - } - else { -NotEncoded: - tempstore[outind] = tempstore[start - stream]; - outind++; - if (outind > tempstoreLength) break; - start++; - } - } - tempstore[outind] = 0; - *storeto = tempstore; -} +/*
+ * This code implements decoding encoded MIME header in style
+ * =?iso-8859-2?Q? "User using email in central Europe characters such as =E9" ?=
+ *
+ * (c) majvan 2002-2004
+ */
+#include "../stdafx.h"
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+struct _tcptable CodePageNamesAll[]=
+{
+ { "ANSI", "",TRUE,CP_ACP},
+ { "WINDOWS-1", "250",0,1250},
+ { "WINDOWS-1", "251",0,1251},
+ { "WINDOWS-1", "252",0,1252},
+ { "WINDOWS-1", "253",0,1253},
+ { "WINDOWS-1", "254",0,1254},
+ { "WINDOWS-1", "255",0,1255},
+ { "WINDOWS-1", "256",0,1256},
+ { "WINDOWS-1", "257",0,1257},
+ { "WINDOWS-1", "258",0,1258},
+ { "CP1", "250",0,1250},
+ { "CP1", "251",0,1251},
+ { "CP1", "252",0,1252},
+ { "CP1", "253",0,1253},
+ { "CP1", "254",0,1254},
+ { "CP1", "255",0,1255},
+ { "CP1", "256",0,1256},
+ { "CP1", "257",0,1257},
+ { "CP1", "258",0,1258},
+ { "ANSI-1", "250",0,1250},
+ { "ANSI-1", "251",0,1251},
+ { "ANSI-1", "252",0,1252},
+ { "ANSI-1", "253",0,1253},
+ { "ANSI-1", "254",0,1254},
+ { "ANSI-1", "255",0,1255},
+ { "ANSI-1", "256",0,1256},
+ { "ANSI-1", "257",0,1257},
+ { "ANSI-1", "258",0,1258},
+ { "KOI8", "-R",0,20866},
+ { "KOI8", "",0,20866},
+ { "KOI8", "-U",0,21866},
+ { "KOI8", "-RU",0,21866},
+ { "US-", "ASCII",0,20127},
+ { "CP", "367",0,20127},
+ { "ASCII", "",0,20127},
+ { "ASCII", "7",0,20127},
+ { "ISO-8859", "-1",0,28591},
+ { "ISO-8859", "-2",0,28592},
+ { "ISO-8859", "-3",0,28593},
+ { "ISO-8859", "-4",0,28594},
+ { "ISO-8859", "-5",0,28595},
+ { "ISO-8859", "-6",0,28596},
+ { "ISO-8859", "-7",0,28597},
+ { "ISO-8859", "-8",0,28598},
+ { "ISO-8859", "-9",0,28599},
+ { "ISO-8859", "-15",0,28605},
+ { "ISO_8859", "-1",0,28591},
+ { "ISO_8859", "-2",0,28592},
+ { "ISO_8859", "-3",0,28593},
+ { "ISO_8859", "-4",0,28594},
+ { "ISO_8859", "-5",0,28595},
+ { "ISO_8859", "-6",0,28596},
+ { "ISO_8859", "-7",0,28597},
+ { "ISO_8859", "-8",0,28598},
+ { "ISO_8859", "-9",0,28599},
+ { "ISO_8859", "-15",0,28605},
+ { "ISO-", "10646-USC2",0,1200},
+ { "ISO-2022", "/2-JP",0,50220},
+ { "ISO-2022", "-JP",0,50221},
+ { "ISO-2022", "/JIS-JP",0,50222},
+ { "ISO-2022", "-KR",0,50225},
+ { "ISO-2022", "-CH(SP)",0,50227},
+ { "ISO-2022", "-CH(TR)",0,50229},
+ { "UTF-", "7",0,65000},
+ { "UTF-", "8",0,65001},
+ { "ARAB-", "TRANSPARENT",0,710},
+ { "ASMO-", "TRANSPARENT",0,720},
+ { "ASMO-", "449",0,709},
+ { "ASMO-", "708",0,708},
+ { "BIG5", "",0,950},
+ { "EUC-", "CH(SP)",0,51936},
+ { "EUC-", "CH(TR)",0,51950},
+ { "EUC-", "JP",0,51932},
+ { "EUC-", "KR",0,51949},
+ { "GB-", "2312",0,20936},
+ { "GB", "2312",0,20936},
+ { "HZGB-", "2312",0,52936},
+ { "IBM-", "037",0,37},
+ { "IBM-", "290",0,290},
+ { "IBM-", "437",0,437},
+ { "IBM-", "500",0,500},
+ { "IBM-", "775",0,775},
+ { "IBM-", "850",0,850},
+ { "IBM-", "852",0,852},
+ { "IBM-", "855",0,855},
+ { "IBM-", "857",0,857},
+ { "IBM-", "860",0,860},
+ { "IBM-", "861",0,861},
+ { "IBM-", "862",0,862},
+ { "IBM-", "863",0,863},
+ { "IBM-", "864",0,864},
+ { "IBM-", "865",0,865},
+ { "IBM-", "866",0,866},
+ { "IBM-", "869",0,869},
+ { "IBM-", "870",0,870},
+ { "IBM-", "875",0,875},
+ { "IBM-", "1026",0,1026},
+ { "IBM-", "273",0,20273},
+ { "IBM-", "277",0,20277},
+ { "IBM-", "278",0,20278},
+ { "IBM-", "280",0,20280},
+ { "IBM-", "284",0,20284},
+ { "IBM-", "285",0,20285},
+ { "IBM-", "290",0,20290},
+ { "IBM-", "297",0,20297},
+ { "IBM-", "420",0,20420},
+ { "IBM-", "423",0,20423},
+ { "IBM-", "871",0,20871},
+ { "IBM-", "880",0,20880},
+ { "IBM-", "905",0,20905},
+ { "IBM-", "THAI",0,20838},
+ { "ISCII-", "DEVANAGARI",0,57002},
+ { "ISCII-", "BENGALI",0,57003},
+ { "ISCII-", "TAMIL",0,57004},
+ { "ISCII-", "TELUGU",0,57005},
+ { "ISCII-", "ASSAMESE",0,57006},
+ { "ISCII-", "ORIYA",0,57007},
+ { "ISCII-", "KANNADA",0,57008},
+ { "ISCII-", "MALAYALAM",0,57009},
+ { "ISCII-", "GUJARATI",0,57010},
+ { "ISCII-", "PUNJABI",0,57011},
+ { "KOR-", "JOHAB",0,1361},
+ { "KSC-", "5601",0,1361},
+ { "MAC-", "ROMAN",0,10000},
+ { "MAC-", "JP",0,10001},
+ { "MAC-", "CH(SP)(BIG5)",0,10002},
+ { "MAC-", "KR",0,10003},
+ { "MAC-", "AR",0,10004},
+ { "MAC-", "HW",0,10005},
+ { "MAC-", "GR",0,10006},
+ { "MAC-", "CY",0,10007},
+ { "MAC-", "CH(SP)(GB2312)",0,10008},
+ { "MAC-", "ROMANIA",0,10010},
+ { "MAC-", "UA",0,10017},
+ { "MAC-", "TH",0,10021},
+ { "MAC-", "LAT2",0,10029},
+ { "MAC-", "ICE",0,10079},
+ { "MAC-", "TR",0,10081},
+ { "MAC-", "CR",0,10082}
+};
+
+int CPLENALL = _countof(CodePageNamesAll);
+struct _tcptable *CodePageNamesSupp;
+int CPLENSUPP = 1;
+
+//Gets codepage ID from string representing charset such as "iso-8859-1"
+// input- the string
+// size- max length of input string
+int GetCharsetFromString(char *input, size_t size);
+
+//HexValue to DecValue ('a' to 10)
+// HexValue- hexa value ('a')
+// DecValue- poiner where to store dec value
+// returns 0 if not success
+int FromHexa(char HexValue, char *DecValue);
+
+//Decodes a char from Base64
+// Base64Value- input char in Base64
+// DecValue- pointer where to store the result
+// returns 0 if not success
+int FromBase64(char Base64Value, char *DecValue);
+
+//Decodes string in quoted printable
+// Src- input string
+// Dst- where to store output string
+// DstLen- how max long should be output string
+// isQ- if is "Q-encoding" modification. should be TRUE in headers
+// always returns 1
+int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ);
+
+//Decodes string in base64
+// Src- input string
+// Dst- where to store output string
+// DstLen- how max long should be output string
+// returns 0 if string was not properly decoded
+int DecodeBase64(char *Src, char *Dst, int DstLen);
+
+//Converts string to unicode from string with specified codepage
+// stream- input string
+// cp- codepage of input string
+// out- pointer to new allocated memory that contains unicode string
+int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out);
+
+//Converts string from MIME header to unicode
+// stream- input string
+// cp- codepage of input string
+// storeto- pointer to memory that contains unicode string
+// mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' from start and end of string)
+void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode);
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+int GetCharsetFromString(char *input, size_t size)
+//"ISO-8859-1" to ID from table
+{
+ char *pin = input;
+ char *pout, *parser;
+
+ if ((size < 1) || (parser = pout = new char[size + 1]) == nullptr)
+ return -1;
+ while ((*pin != 0) && (pin - input < (INT_PTR)size)) {
+ if ((*pin >= 'a') && (*pin <= 'z'))
+ *parser++ = *(pin++) - ('a' - 'A'); // make it capital
+ //else if (*pin=='\"') // this is already done in ExtractFromContentType
+ // *pin++; //skip the quotes if any
+ else
+ *parser++ = *pin++;
+ }
+
+ *parser = 0;
+
+ #ifdef DEBUG_DECODECODEPAGE
+ DebugLog(DecodeFile, "<CodePage>%s</CodePage>", pout);
+ #endif
+ for (int i = 0; i < CPLENALL; i++) {
+ size_t len = mir_strlen(CodePageNamesAll[i].NameBase);
+ if (0 == strncmp(pout, CodePageNamesAll[i].NameBase, len)) {
+ if (0 == mir_strcmp(pout + len, CodePageNamesAll[i].NameSub)) {
+ delete[] pout;
+ return CodePageNamesAll[i].CP;
+ }
+ }
+ }
+ delete[] pout;
+ return -1; //not found
+}
+
+int FromHexa(char HexValue, char *DecValue)
+{
+ if (HexValue >= '0' && HexValue <= '9') {
+ *DecValue = HexValue - '0';
+ return 1;
+ }
+ if (HexValue >= 'A' && HexValue <= 'F') {
+ *DecValue = HexValue - 'A' + 10;
+ return 1;
+ }
+ if (HexValue >= 'a' && HexValue <= 'f') {
+ *DecValue = HexValue - 'a' + 10;
+ return 1;
+ }
+ return 0;
+}
+
+int FromBase64(char Base64Value, char *DecValue)
+{
+ if (Base64Value >= 'A' && Base64Value <= 'Z') {
+ *DecValue = Base64Value - 'A';
+ return 1;
+ }
+ if (Base64Value >= 'a' && Base64Value <= 'z') {
+ *DecValue = Base64Value - 'a' + 26;
+ return 1;
+ }
+ if (Base64Value >= '0' && Base64Value <= '9') {
+ *DecValue = Base64Value - '0' + 52;
+ return 1;
+ }
+ if (Base64Value == '+') {
+ *DecValue = Base64Value - '+' + 62;
+ return 1;
+ }
+ if (Base64Value == '/') {
+ *DecValue = Base64Value - '/' + 63;
+ return 1;
+ }
+ if (Base64Value == '=') {
+ *DecValue = 0;
+ return 1;
+ }
+ return 0;
+}
+
+int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ)
+{
+ #ifdef DEBUG_DECODEQUOTED
+ char *DstTemp = Dst;
+ DebugLog(DecodeFile, "<Decode Quoted><Input>%s</Input>", Src);
+ #endif
+ for (int Counter = 0; (*Src != 0) && DstLen && (Counter++ < DstLen); Src++, Dst++)
+ if (*Src == '=') {
+ if (!isQ) {
+ if (Src[1] == 0x0D) {
+ Src++; Src++;
+ if (Src[0] == 0x0A) Src++;
+ goto CopyCharQuotedPrintable;
+ }
+ if (Src[1] == 0x0A) {
+ Src++; Src++;
+ goto CopyCharQuotedPrintable;
+ }
+ }
+ char First, Second;
+ if (!FromHexa(*(++Src), &First)) {
+ *Dst++ = '='; Src--;
+ continue;
+ }
+ if (!FromHexa(*(++Src), &Second)) {
+ *Dst++ = '='; Src--; Src--;
+ continue;
+ }
+ *Dst = (char)(First) << 4;
+ *Dst += Second;
+ }
+ else if (isQ && *Src == '_')
+ *Dst = ' ';
+ else
+ CopyCharQuotedPrintable: // Yeah. Bad programming stile.
+ *Dst = *Src;
+ *Dst = 0;
+ #ifdef DEBUG_DECODEQUOTED
+ DebugLog(DecodeFile, "<Output>%s</Output></Decode Quoted>", DstTemp);
+ #endif
+ return 1;
+}
+
+int DecodeBase64(char *Src, char *Dst, int DstLen)
+{
+ int Result = 0;
+ char Locator = 0, MiniResult[4];
+ char *End = Dst + DstLen;
+
+ MiniResult[0] = MiniResult[1] = MiniResult[2] = MiniResult[3] = 0;
+
+ #ifdef DEBUG_DECODEBASE64
+ char *DstTemp = Dst;
+ DebugLog(DecodeFile, "<Decode Base64><Input>\n%s\n</Input>\n", Src);
+ #endif
+ while (*Src != 0 && DstLen && Dst != End) {
+ if ((*Src == 0x0D) || (*Src == 0x0A)) {
+ Src++;
+ continue;
+ }
+ if ((!(Result = FromBase64(*Src, MiniResult + Locator)) && (*Src == 0)) || Locator++ == 3) //end_of_str || end_of_4_bytes
+ {
+ Locator = 0; //next write to the first byte
+ *Dst++ = (char)((MiniResult[0] << 2) | (MiniResult[1] >> 4));
+ if (Dst == End) goto end; //DstLen exceeded?
+ *Dst++ = (char)((MiniResult[1] << 4) | (MiniResult[2] >> 2));
+ if (Dst == End) goto end; //someones don't like goto, but not me
+ *Dst++ = (char)((MiniResult[2] << 6) | MiniResult[3]);
+ if (!Result && (*Src == 0)) goto end; //end of string?
+ MiniResult[0] = MiniResult[1] = MiniResult[2] = MiniResult[3] = 0; //zero 4byte buffer for next loop
+ }
+ if (!Result) return 0; //unrecognised character occured
+ Src++;
+ }
+end:
+ *Dst = 0;
+ #ifdef DEBUG_DECODEBASE64
+ DebugLog(DecodeFile, "<Output>\n%s\n</Output></Decode Base64>", DstTemp);
+ #endif
+ return 1;
+}
+
+
+
+int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out)
+{
+ CPINFO CPInfo;
+ wchar_t *temp, *src = *out, *dest;
+ size_t outlen;
+ int streamlen, Index;
+
+ //codepages, which require to have set 0 in dwFlags parameter when calling MultiByteToWideChar
+ uint32_t CodePagesZeroFlags[] = {50220, 50221, 50222, 50225, 50227, 50229, 52936, 54936, 57002, 57003, 57004, 57005, 57006, 57007, 57008, 57009, 57010, 57011, 65000, 65001};
+
+ if ((cp != CP_ACP) && (cp != CP_OEMCP) && (cp != CP_MACCP) && (cp != CP_THREAD_ACP) && (cp != CP_SYMBOL) && (cp != CP_UTF7) && (cp != CP_UTF8) && !GetCPInfo(cp, &CPInfo))
+ cp = CP_ACP;
+ #ifdef DEBUG_DECODECODEPAGE
+ DebugLog(DecodeFile, "<CodePage #>%d</CodePage #>", cp);
+ #endif
+
+ for (Index = 0; Index < sizeof(CodePagesZeroFlags) / sizeof(CodePagesZeroFlags[0]); Index++)
+ if (CodePagesZeroFlags[Index] == cp) {
+ Index = -1;
+ break;
+ }
+ if (Index == -1)
+ streamlen = MultiByteToWideChar(cp, 0, stream, -1, nullptr, 0);
+ else
+ streamlen = MultiByteToWideChar(cp, MB_USEGLYPHCHARS, stream, -1, nullptr, 0);
+
+ if (*out != nullptr)
+ outlen = mir_wstrlen(*out);
+ else
+ outlen = 0;
+ temp = new wchar_t[streamlen + outlen + 1];
+
+ if (*out != nullptr) {
+ for (dest = temp; *src != (wchar_t)0; src++, dest++) //copy old string from *out to temp
+ *dest = *src;
+ // *dest++=L' '; //add space?
+ delete[] * out;
+ }
+ else
+ dest = temp;
+ *out = temp;
+
+ if (Index == -1) {
+ if (!MultiByteToWideChar(cp, 0, stream, -1, dest, streamlen))
+ return 0;
+ }
+ else {
+ if (!MultiByteToWideChar(cp, MB_USEGLYPHCHARS, stream, -1, dest, streamlen))
+ return 0;
+ }
+ return 1;
+}
+
+void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode)
+{
+ char *start = stream, *finder, *finderend;
+ char Encoding = 0;
+
+ if (stream == nullptr)
+ return;
+
+ while (WS(start)) start++;
+ wchar_t *tempstore = nullptr;
+ if (!ConvertStringToUnicode(stream, cp, &tempstore))return;
+
+ size_t tempstoreLength = mir_wstrlen(tempstore);
+
+ size_t outind = 0;
+ while (*start != 0) {
+ if (CODES(start)) {
+ finder = start + 2; finderend = finder;
+ while (!CODED(finderend) && !EOS(finderend)) finderend++;
+ start = finderend;
+ if (CODED(finderend)) {
+ Encoding = *(finderend + 1);
+ switch (Encoding) {
+ case 'b':
+ case 'B':
+ case 'q':
+ case 'Q':
+ break;
+ default:
+ goto NotEncoded;
+ }
+ if (-1 == (cp = (uint32_t)GetCharsetFromString(finder, finderend - finder)))
+ cp = CP_ACP;
+ if (Encoding != 0) {
+ int size = 0, codeend;
+ char *pcodeend = nullptr;
+
+ finder = finderend + 2;
+ if (CODED(finder))
+ finder++;
+ while (WS(finder)) finder++;
+ finderend = finder;
+ while (!CODEE(finderend) && !EOS(finderend)) finderend++;
+ if (codeend = CODEE(finderend))
+ pcodeend = finderend;
+ while (WS(finderend - 1)) finderend--;
+ if ((mode == MIME_MAIL) && (((*finder == '"') && (*(finderend - 1) == '"')))) {
+ finder++;
+ finderend--;
+ }
+ char *oneWordEncoded = new char[finderend - finder + 1];
+ strncpy(oneWordEncoded, finder, finderend - finder);
+ oneWordEncoded[finderend - finder] = 0;
+ switch (Encoding) {
+ case 'b':
+ case 'B':
+ size = (finderend - finder) * 3 / 4 + 3 + 1 + 1;
+ break;
+ case 'q':
+ case 'Q':
+ size = finderend - finder + 1 + 1;
+ break;
+ }
+
+ char *DecodedResult = new char[size + 1];
+ switch (Encoding) {
+ case 'q':
+ case 'Q':
+ DecodeQuotedPrintable(oneWordEncoded, DecodedResult, size, TRUE);
+ break;
+ case 'b':
+ case 'B':
+ DecodeBase64(oneWordEncoded, DecodedResult, size);
+ break;
+ }
+ delete[] oneWordEncoded;
+ if (codeend)
+ finderend = pcodeend + 2;
+ if (WS(finderend)) //if string continues and there's some whitespace, add space to string that is to be converted
+ {
+ size_t len = mir_strlen(DecodedResult);
+ DecodedResult[len] = ' ';
+ DecodedResult[len + 1] = 0;
+ finderend++;
+ }
+ wchar_t *oneWord = nullptr;
+ if (ConvertStringToUnicode(DecodedResult, cp, &oneWord)) {
+ size_t len = mir_wstrlen(oneWord);
+ memcpy(&tempstore[outind], oneWord, len * sizeof(wchar_t));
+ outind += len;
+ }
+ delete oneWord;
+ oneWord = nullptr;
+ delete[] DecodedResult;
+ start = finderend;
+ }
+ else if (!EOS(start)) start++;
+ }
+ else if (!EOS(start)) start++;
+ }
+ else {
+NotEncoded:
+ tempstore[outind] = tempstore[start - stream];
+ outind++;
+ if (outind > tempstoreLength) break;
+ start++;
+ }
+ }
+ tempstore[outind] = 0;
+ *storeto = tempstore;
+}
diff --git a/protocols/YAMN/src/mails/mails.cpp b/protocols/YAMN/src/mails/mails.cpp index 168c6c9397..1385cb649d 100644 --- a/protocols/YAMN/src/mails/mails.cpp +++ b/protocols/YAMN/src/mails/mails.cpp @@ -1,473 +1,473 @@ -/* - * This code implements retrieving info from MIME header - * - * (c) majvan 2002-2004 - */ - -#include "../stdafx.h" - - //-------------------------------------------------------------------------------------------------- - //-------------------------------------------------------------------------------------------------- - - // SMALL INTRO - // Mails are queued in a queue (chained list). Pointer to first mail is pointed from Account structure - // member called Mails. - // Mail queue is ended with NULL- pointered mail (NULL handle) - - //Creates new mail for plugin (calling plugin's constructor, when plugin imported to YAMN) -INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam); - -//Deletes mail for plugin (calling plugin's destructor, when plugin imported to YAMN) -INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam); - -//Loads mail data from standard storage to memory -INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam); - -//Deletes mail data from memory -INT_PTR UnloadMailDataSvc(WPARAM wParam, LPARAM); - -//Saves mail data from memory to standard storage -INT_PTR SaveMailDataSvc(WPARAM wParam, LPARAM lParam); - -//Appends second MIME mail queue to the first one -//Only finds the end of first queue and its Next memember repoints to second one -void WINAPI AppendQueueFcn(HYAMNMAIL first, HYAMNMAIL second); - -//Synchronizes two accounts -//Function finds, if there were some mails deleted from mailbox and deletes (depends on RemovedOld param) them from OldQueue -//Next finds, if there are new mails. Mails that are still on mailbox are deleted (depends on RemovedNew param) from NewQueue -//After this, OldQueue is pointer to mails that are on mailbox, but not new mails -//and NewQueue contains new mails in account -//New accounts can be then appended to account mails queue, but they have set the New flag -// -//Two mails equals if they have the same ID -// -// hPlugin- handle of plugin going to delete mails -// OldQueue- queue of mails that we found on mailbox last time, after function finishes queue contains all mails except new ones -// RemovedOld- queue of mails where to store removed mails from OldQueue, if NULL deletes mails from OldQueue -// NewQueue- queue of mails that we found on mailbox (all mails), after function finishes queue contains only new mails -// RemovedNew- queue of mails where to store removed mails from NewQueue, if NULL deletes mails from NewQueue -//So function works like: -//1. delete (or move to RemovedOld queue if RemovedOld is not NULL) all mails from OldQueue not found in NewQueue -//2. delete (or move to RemovedNew queue if RemovedNew is not NULL) all mails from NewQueue found in OldQueue -void WINAPI SynchroMessagesFcn(CAccount *Account, HYAMNMAIL *OldQueue, HYAMNMAIL *RemovedOld, HYAMNMAIL *NewQueue, HYAMNMAIL *RemovedNew); - -//Deletes messages from mail From to the end -// Account- account who owns mails -// From- first mail in queue, which is going to delete -void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From); - -//Removes message from queue, does not delete from memory -// From- queue pointer -// Which- mail to delete -// mode- nonzero if you want to decrement numbers in messages that are bigger than the one in Which mail, 0 if not -void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode); - -//Finds message in queue that has the same ID number -// From- message queue -// ID- pointer to ID -// returns pointer to found message, NULL if not found -HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From, char *ID); - -//Translate header from text to queue of CMimeItem structures -//This means that new queue will contain all info about headers -// stream- pointer to text containing header (can be ended with zero) -// len- length of stream -// head- function fills this pointer to first header item in queue -void WINAPI TranslateHeaderFcn(char *stream, int len, struct CMimeItem **head); - -//Creates new mail queue, copying only these mails, that have set flag for deleting -// From- message queue, whose mail with given flag are duplicated -// returns new mail queue (or NULL when no mail with flag is in From queue) -//Function does not copy the whole mails, it copies only ID string. And ID is copied as string, so -//you can use this fcn only if you have your ID as pointer to char string ended with zero character -HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From); - -//Sets/removes flags from specific mails -// From- pointer to first message -// FlagsSet- mail must have set these flags... -// FlagsNotSet- ...and must not have set these flags... -// FlagsToSetRemove- ...to set/remove these flags (see mode) -// mode- nonzero to set, else remove -void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSetRemove, int mode); - -struct CExportedFunctions MailExportedFcn[] = -{ - {YAMN_SYNCHROMIMEMSGSID, (void *)SynchroMessagesFcn}, - {YAMN_TRANSLATEHEADERID, (void *)TranslateHeaderFcn}, - {YAMN_APPENDQUEUEID, (void *)AppendQueueFcn}, - {YAMN_DELETEMIMEQUEUEID, (void *)DeleteMessagesToEndFcn}, - {YAMN_DELETEMIMEMESSAGEID, (void *)DeleteMessageFromQueueFcn}, - {YAMN_FINDMIMEMESSAGEID, (void *)FindMessageByIDFcn}, - {YAMN_CREATENEWDELETEQUEUEID, (void *)CreateNewDeleteQueueFcn}, - {YAMN_SETREMOVEQUEUEFLAGSID, (void *)SetRemoveFlagsInQueueFcn}, -}; - -struct CExportedServices MailExportedSvc[] = -{ - {MS_YAMN_CREATEACCOUNTMAIL, CreateAccountMailSvc}, - {MS_YAMN_DELETEACCOUNTMAIL, DeleteAccountMailSvc}, - {MS_YAMN_LOADMAILDATA, LoadMailDataSvc}, - {MS_YAMN_UNLOADMAILDATA, UnloadMailDataSvc}, - {MS_YAMN_SAVEMAILDATA, SaveMailDataSvc}, -}; - - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam) -{ - CAccount *Account = (CAccount *)wParam; - uint32_t MailVersion = (uint32_t)lParam; - HYAMNMAIL NewMail; - - //test if we are going to initialize members of suitable structure (structures of plugin and YAMN must match) - if (MailVersion != YAMN_MAILVERSION) - return NULL; - - if (Account->Plugin != nullptr) { - if (Account->Plugin->MailFcn->NewMailFcnPtr != nullptr) { - //Let plugin create its own structure, which can be derived from CAccount structure - if (nullptr == (NewMail = Account->Plugin->MailFcn->NewMailFcnPtr(Account, YAMN_MAILVERSION))) - return NULL; - } - else { - //We suggest plugin uses standard CAccount structure, so we create it - if (nullptr == (NewMail = new YAMNMAIL)) - //If not created successfully - return NULL; - NewMail->MailData = nullptr; - } - //Init every members of structure, used by YAMN - return (INT_PTR)NewMail; - } - return NULL; -} - -INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam) -{ - HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; - HYAMNMAIL OldMail = (HYAMNMAIL)lParam; - struct CMimeItem *TH; - - if (Plugin->MailFcn != nullptr) { - if (Plugin->MailFcn->DeleteMailFcnPtr != nullptr) { - //Let plugin delete its own CMimeMsgQueue derived structure - Plugin->MailFcn->DeleteMailFcnPtr(OldMail); - return 1; - } - } - if (OldMail->MailData != nullptr) { - if (OldMail->MailData->Body != nullptr) - delete[] OldMail->MailData->Body; - if ((TH = OldMail->MailData->TranslatedHeader) != nullptr) - for (; OldMail->MailData->TranslatedHeader != nullptr;) { - TH = TH->Next; - if (OldMail->MailData->TranslatedHeader->name != nullptr) - delete[] OldMail->MailData->TranslatedHeader->name; - if (OldMail->MailData->TranslatedHeader->value != nullptr) - delete[] OldMail->MailData->TranslatedHeader->value; - delete OldMail->MailData->TranslatedHeader; - OldMail->MailData->TranslatedHeader = TH; - } - delete OldMail->MailData; - } - if (OldMail->ID != nullptr) - delete[] OldMail->ID; - - delete OldMail; //consider mail as standard HYAMNMAIL, not initialized before and use its own destructor - return 1; -} - - -void WINAPI AppendQueueFcn(HYAMNMAIL first, HYAMNMAIL second) -{ - HYAMNMAIL Finder = first; - while (Finder->Next != nullptr) Finder = Finder->Next; - Finder->Next = second; -} - -INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam) -{ - HYAMNMAIL Mail = (HYAMNMAIL)wParam; - uint32_t MailVersion = (uint32_t)lParam; - - if (MailVersion != YAMN_MAILDATAVERSION) - return NULL; - - // now we have all data to memory persisting, so no loading is needed - return (INT_PTR)Mail->MailData; -} - -INT_PTR UnloadMailDataSvc(WPARAM, LPARAM) -{ - return 1; -} - -INT_PTR SaveMailDataSvc(WPARAM, LPARAM lParam) -{ - uint32_t MailVersion = (uint32_t)lParam; - - if (MailVersion != YAMN_MAILDATAVERSION) - return (INT_PTR)-1; - - // now we have all data to memory persisting, so no saving is needed - return (INT_PTR)0; -} - -void WINAPI SynchroMessagesFcn(CAccount *Account, HYAMNMAIL *OldQueue, HYAMNMAIL *RemovedOld, HYAMNMAIL *NewQueue, HYAMNMAIL *RemovedNew) -//deletes messages from new queue, if they are old -//it also deletes messages from old queue, if they are not in mailbox anymore -//"YAMN_MSG_DELETED" messages in old queue remain in old queue (are never removed, although they are not in new queue) -//"YAMN_MSG_DELETED" messages in new queue remain in new queue (are never removed, although they can be in old queue) -{ - HYAMNMAIL Finder, FinderPrev; - HYAMNMAIL Parser, ParserPrev; - HYAMNMAIL RemovedOldParser = nullptr; - HYAMNMAIL RemovedNewParser = nullptr; - if (RemovedOld != nullptr) *RemovedOld = nullptr; - if (RemovedNew != nullptr) *RemovedNew = nullptr; - - for (FinderPrev = nullptr, Finder = *OldQueue; Finder != nullptr;) { - if (Finder->Flags & YAMN_MSG_DELETED) //if old queue contains deleted mail - { - FinderPrev = Finder; - Finder = Finder->Next; //get next message in old queue for testing - continue; - } - for (ParserPrev = nullptr, Parser = *NewQueue; Parser != nullptr; ParserPrev = Parser, Parser = Parser->Next) { - if (Parser->Flags & YAMN_MSG_DELETED) - continue; - - if (Parser->ID == nullptr) //simply ignore the message, that has not filled its ID - continue; - - if (0 == mir_strcmp(Parser->ID, Finder->ID)) //search for equal message in new queue - break; - } - if (Parser != nullptr) //found equal message in new queue - { - if (Parser == *NewQueue) - *NewQueue = (*NewQueue)->Next; - else - ParserPrev->Next = Parser->Next; - Finder->Number = Parser->Number; //rewrite the number of current message in old queue - - if (RemovedNew == nullptr) //delete from new queue - DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Parser); - else //or move to RemovedNew - { - if (RemovedNewParser == nullptr) //if it is first mail removed from NewQueue - *RemovedNew = Parser; //set RemovedNew queue to point to first message in removed queue - else - RemovedNewParser->Next = Parser; //else don't forget to show to next message in RemovedNew queue - RemovedNewParser = Parser; //follow RemovedNew queue - RemovedNewParser->Next = nullptr; - } - FinderPrev = Finder; - Finder = Finder->Next; //get next message in old queue for testing - } - else //a message was already deleted from mailbox - { - if (Finder == *OldQueue) //if we are at the first item in OldQueue - { - *OldQueue = (*OldQueue)->Next; //set OldQueue to next item - if (RemovedOld == nullptr) //delete from old queue - DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Finder); - else //or move to RemovedOld - { - if (RemovedOldParser == nullptr) //if it is first mail removed from OldQueue - *RemovedOld = Finder; //set RemovedOld queue to point to first message in removed queue - else - RemovedOldParser->Next = Finder; //else don't forget to show to next message in RemovedNew queue - RemovedOldParser = Finder; //follow RemovedOld queue - RemovedOldParser->Next = nullptr; - } - Finder = *OldQueue; - } - else { - FinderPrev->Next = Finder->Next; - if (RemovedOld == nullptr) //delete from old queue - DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Finder); - else //or move to RemovedOld - { - if (RemovedOldParser == nullptr) //if it is first mail removed from OldQueue - *RemovedOld = Finder; //set RemovedOld queue to point to first message in removed queue - else - RemovedOldParser->Next = Finder; //else don't forget to show to next message in RemovedNew queue - RemovedOldParser = Finder; //follow RemovedOld queue - RemovedOldParser->Next = nullptr; - } - Finder = FinderPrev->Next; - } - } - } -} - -void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From) -{ - HYAMNMAIL Temp; - while (From != nullptr) { - Temp = From; - From = From->Next; - DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Temp); - } -} - -void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode = 0) -{ - uint32_t Number = Which->Number; - HYAMNMAIL Parser; - - if (*From == Which) { - Parser = Which->Next; - *From = Parser; - } - else { - for (Parser = *From; Which != Parser->Next; Parser = Parser->Next) - if (mode && (Parser->Number > Number)) Parser->Number--; - if (mode && (Parser->Number > Number)) Parser->Number--; - Parser->Next = Parser->Next->Next; - Parser = Which->Next; - } - if (mode) - for (; Parser != nullptr; Parser = Parser->Next) - if (Parser->Number > Number) Parser->Number--; -} - -void DeleteMessagesFromQueue(HYAMNMAIL *From, HYAMNMAIL Which, int mode = 0) -{ - HYAMNMAIL Parser; - - for (Parser = Which; Parser != nullptr; Parser = Parser->Next) - DeleteMessageFromQueueFcn(From, Parser, mode); -} - -HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From, char *ID) -{ - HYAMNMAIL Browser; - - for (Browser = From; Browser != nullptr; Browser = Browser->Next) - if (0 == mir_strcmp(Browser->ID, ID)) - break; - return Browser; -} - -void WINAPI TranslateHeaderFcn(char *stream, int len, struct CMimeItem **head) -{ - try { - char *finder = stream; - char *prev1, *prev2, *prev3; - struct CMimeItem *Item = nullptr; - - while (finder <= (stream + len)) { - while (ENDLINEWS(finder)) finder++; - - //at the start of line - if (DOTLINE(finder + 1)) //at the end of stream - break; - - prev1 = finder; - - while (*finder != ':' && !EOS(finder)) finder++; - if (!EOS(finder)) - prev2 = finder++; - else - break; - - while (WS(finder) && !EOS(finder)) finder++; - if (!EOS(finder)) - prev3 = finder; - else - break; - - do { - if (ENDLINEWS(finder)) finder += 2; //after endline information continues - while (!ENDLINE(finder) && !EOS(finder)) finder++; - } while (ENDLINEWS(finder)); - - if (Item != nullptr) { - if (nullptr == (Item->Next = new struct CMimeItem)) - break; - Item = Item->Next; - } - else { - Item = new CMimeItem; - *head = Item; - } - - Item->Next = nullptr; - Item->name = new char[prev2 - prev1 + 1]; - mir_strncpy(Item->name, prev1, prev2 - prev1 + 1); - Item->value = new char[finder - prev3 + 1]; - mir_strncpy(Item->value, prev3, finder - prev3 + 1); - - if (EOS(finder)) - break; - finder++; - if (ENDLINE(finder)) { - finder++; - if (ENDLINE(finder)) { - // end of headers. message body begins - finder++; - if (ENDLINE(finder))finder++; - prev1 = finder; - while (!DOTLINE(finder + 1))finder++; - if (ENDLINE(finder))finder--; - prev2 = finder; - if (prev2 > prev1) { // yes, we have body - if (nullptr == (Item->Next = new struct CMimeItem)) break; // Cant create new item?! - Item = Item->Next; - Item->Next = nullptr;//just in case; - Item->name = new char[5]; strncpy(Item->name, "Body", 5); - Item->value = new char[prev2 - prev1]; - mir_strncpy(Item->value, prev1, prev2 - prev1 - 1); - } - break; // there is nothing else - } - } - } - } - catch (...) { - MessageBoxA(nullptr, "Translate header error", "", 0); - } -} - -HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From) -{ - HYAMNMAIL FirstMail, Browser = nullptr; - - for (FirstMail = nullptr; From != nullptr; From = From->Next) { - if ((From->Flags & (YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE)) && !(From->Flags & YAMN_MSG_DELETED)) { - if (FirstMail == nullptr) { - FirstMail = Browser = new YAMNMAIL; - if (FirstMail == nullptr) - break; - } - else { - Browser->Next = new YAMNMAIL; - Browser = Browser->Next; - } - Browser->ID = new char[mir_strlen(From->ID) + 1]; - mir_strcpy(Browser->ID, From->ID); - Browser->Number = From->Number; - Browser->Flags = From->Flags; - } - } - return FirstMail; -} - -void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSetRemove, int mode) -{ - HYAMNMAIL msgq; - - for (msgq = (HYAMNMAIL)From; msgq != nullptr; msgq = msgq->Next) { - if ((FlagsSet == (msgq->Flags & FlagsSet)) && (0 == (msgq->Flags & FlagsNotSet))) { - if (mode) - msgq->Flags = msgq->Flags | FlagsToSetRemove; - else - msgq->Flags = msgq->Flags & ~FlagsToSetRemove; - } - } -} +/*
+ * This code implements retrieving info from MIME header
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "../stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+ //--------------------------------------------------------------------------------------------------
+
+ // SMALL INTRO
+ // Mails are queued in a queue (chained list). Pointer to first mail is pointed from Account structure
+ // member called Mails.
+ // Mail queue is ended with NULL- pointered mail (NULL handle)
+
+ //Creates new mail for plugin (calling plugin's constructor, when plugin imported to YAMN)
+INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam);
+
+//Deletes mail for plugin (calling plugin's destructor, when plugin imported to YAMN)
+INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam);
+
+//Loads mail data from standard storage to memory
+INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam);
+
+//Deletes mail data from memory
+INT_PTR UnloadMailDataSvc(WPARAM wParam, LPARAM);
+
+//Saves mail data from memory to standard storage
+INT_PTR SaveMailDataSvc(WPARAM wParam, LPARAM lParam);
+
+//Appends second MIME mail queue to the first one
+//Only finds the end of first queue and its Next memember repoints to second one
+void WINAPI AppendQueueFcn(HYAMNMAIL first, HYAMNMAIL second);
+
+//Synchronizes two accounts
+//Function finds, if there were some mails deleted from mailbox and deletes (depends on RemovedOld param) them from OldQueue
+//Next finds, if there are new mails. Mails that are still on mailbox are deleted (depends on RemovedNew param) from NewQueue
+//After this, OldQueue is pointer to mails that are on mailbox, but not new mails
+//and NewQueue contains new mails in account
+//New accounts can be then appended to account mails queue, but they have set the New flag
+//
+//Two mails equals if they have the same ID
+//
+// hPlugin- handle of plugin going to delete mails
+// OldQueue- queue of mails that we found on mailbox last time, after function finishes queue contains all mails except new ones
+// RemovedOld- queue of mails where to store removed mails from OldQueue, if NULL deletes mails from OldQueue
+// NewQueue- queue of mails that we found on mailbox (all mails), after function finishes queue contains only new mails
+// RemovedNew- queue of mails where to store removed mails from NewQueue, if NULL deletes mails from NewQueue
+//So function works like:
+//1. delete (or move to RemovedOld queue if RemovedOld is not NULL) all mails from OldQueue not found in NewQueue
+//2. delete (or move to RemovedNew queue if RemovedNew is not NULL) all mails from NewQueue found in OldQueue
+void WINAPI SynchroMessagesFcn(CAccount *Account, HYAMNMAIL *OldQueue, HYAMNMAIL *RemovedOld, HYAMNMAIL *NewQueue, HYAMNMAIL *RemovedNew);
+
+//Deletes messages from mail From to the end
+// Account- account who owns mails
+// From- first mail in queue, which is going to delete
+void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From);
+
+//Removes message from queue, does not delete from memory
+// From- queue pointer
+// Which- mail to delete
+// mode- nonzero if you want to decrement numbers in messages that are bigger than the one in Which mail, 0 if not
+void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode);
+
+//Finds message in queue that has the same ID number
+// From- message queue
+// ID- pointer to ID
+// returns pointer to found message, NULL if not found
+HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From, char *ID);
+
+//Translate header from text to queue of CMimeItem structures
+//This means that new queue will contain all info about headers
+// stream- pointer to text containing header (can be ended with zero)
+// len- length of stream
+// head- function fills this pointer to first header item in queue
+void WINAPI TranslateHeaderFcn(char *stream, int len, struct CMimeItem **head);
+
+//Creates new mail queue, copying only these mails, that have set flag for deleting
+// From- message queue, whose mail with given flag are duplicated
+// returns new mail queue (or NULL when no mail with flag is in From queue)
+//Function does not copy the whole mails, it copies only ID string. And ID is copied as string, so
+//you can use this fcn only if you have your ID as pointer to char string ended with zero character
+HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From);
+
+//Sets/removes flags from specific mails
+// From- pointer to first message
+// FlagsSet- mail must have set these flags...
+// FlagsNotSet- ...and must not have set these flags...
+// FlagsToSetRemove- ...to set/remove these flags (see mode)
+// mode- nonzero to set, else remove
+void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSetRemove, int mode);
+
+struct CExportedFunctions MailExportedFcn[] =
+{
+ {YAMN_SYNCHROMIMEMSGSID, (void *)SynchroMessagesFcn},
+ {YAMN_TRANSLATEHEADERID, (void *)TranslateHeaderFcn},
+ {YAMN_APPENDQUEUEID, (void *)AppendQueueFcn},
+ {YAMN_DELETEMIMEQUEUEID, (void *)DeleteMessagesToEndFcn},
+ {YAMN_DELETEMIMEMESSAGEID, (void *)DeleteMessageFromQueueFcn},
+ {YAMN_FINDMIMEMESSAGEID, (void *)FindMessageByIDFcn},
+ {YAMN_CREATENEWDELETEQUEUEID, (void *)CreateNewDeleteQueueFcn},
+ {YAMN_SETREMOVEQUEUEFLAGSID, (void *)SetRemoveFlagsInQueueFcn},
+};
+
+struct CExportedServices MailExportedSvc[] =
+{
+ {MS_YAMN_CREATEACCOUNTMAIL, CreateAccountMailSvc},
+ {MS_YAMN_DELETEACCOUNTMAIL, DeleteAccountMailSvc},
+ {MS_YAMN_LOADMAILDATA, LoadMailDataSvc},
+ {MS_YAMN_UNLOADMAILDATA, UnloadMailDataSvc},
+ {MS_YAMN_SAVEMAILDATA, SaveMailDataSvc},
+};
+
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam)
+{
+ CAccount *Account = (CAccount *)wParam;
+ uint32_t MailVersion = (uint32_t)lParam;
+ HYAMNMAIL NewMail;
+
+ //test if we are going to initialize members of suitable structure (structures of plugin and YAMN must match)
+ if (MailVersion != YAMN_MAILVERSION)
+ return NULL;
+
+ if (Account->Plugin != nullptr) {
+ if (Account->Plugin->MailFcn->NewMailFcnPtr != nullptr) {
+ //Let plugin create its own structure, which can be derived from CAccount structure
+ if (nullptr == (NewMail = Account->Plugin->MailFcn->NewMailFcnPtr(Account, YAMN_MAILVERSION)))
+ return NULL;
+ }
+ else {
+ //We suggest plugin uses standard CAccount structure, so we create it
+ if (nullptr == (NewMail = new YAMNMAIL))
+ //If not created successfully
+ return NULL;
+ NewMail->MailData = nullptr;
+ }
+ //Init every members of structure, used by YAMN
+ return (INT_PTR)NewMail;
+ }
+ return NULL;
+}
+
+INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam)
+{
+ HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam;
+ HYAMNMAIL OldMail = (HYAMNMAIL)lParam;
+ struct CMimeItem *TH;
+
+ if (Plugin->MailFcn != nullptr) {
+ if (Plugin->MailFcn->DeleteMailFcnPtr != nullptr) {
+ //Let plugin delete its own CMimeMsgQueue derived structure
+ Plugin->MailFcn->DeleteMailFcnPtr(OldMail);
+ return 1;
+ }
+ }
+ if (OldMail->MailData != nullptr) {
+ if (OldMail->MailData->Body != nullptr)
+ delete[] OldMail->MailData->Body;
+ if ((TH = OldMail->MailData->TranslatedHeader) != nullptr)
+ for (; OldMail->MailData->TranslatedHeader != nullptr;) {
+ TH = TH->Next;
+ if (OldMail->MailData->TranslatedHeader->name != nullptr)
+ delete[] OldMail->MailData->TranslatedHeader->name;
+ if (OldMail->MailData->TranslatedHeader->value != nullptr)
+ delete[] OldMail->MailData->TranslatedHeader->value;
+ delete OldMail->MailData->TranslatedHeader;
+ OldMail->MailData->TranslatedHeader = TH;
+ }
+ delete OldMail->MailData;
+ }
+ if (OldMail->ID != nullptr)
+ delete[] OldMail->ID;
+
+ delete OldMail; //consider mail as standard HYAMNMAIL, not initialized before and use its own destructor
+ return 1;
+}
+
+
+void WINAPI AppendQueueFcn(HYAMNMAIL first, HYAMNMAIL second)
+{
+ HYAMNMAIL Finder = first;
+ while (Finder->Next != nullptr) Finder = Finder->Next;
+ Finder->Next = second;
+}
+
+INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam)
+{
+ HYAMNMAIL Mail = (HYAMNMAIL)wParam;
+ uint32_t MailVersion = (uint32_t)lParam;
+
+ if (MailVersion != YAMN_MAILDATAVERSION)
+ return NULL;
+
+ // now we have all data to memory persisting, so no loading is needed
+ return (INT_PTR)Mail->MailData;
+}
+
+INT_PTR UnloadMailDataSvc(WPARAM, LPARAM)
+{
+ return 1;
+}
+
+INT_PTR SaveMailDataSvc(WPARAM, LPARAM lParam)
+{
+ uint32_t MailVersion = (uint32_t)lParam;
+
+ if (MailVersion != YAMN_MAILDATAVERSION)
+ return (INT_PTR)-1;
+
+ // now we have all data to memory persisting, so no saving is needed
+ return (INT_PTR)0;
+}
+
+void WINAPI SynchroMessagesFcn(CAccount *Account, HYAMNMAIL *OldQueue, HYAMNMAIL *RemovedOld, HYAMNMAIL *NewQueue, HYAMNMAIL *RemovedNew)
+//deletes messages from new queue, if they are old
+//it also deletes messages from old queue, if they are not in mailbox anymore
+//"YAMN_MSG_DELETED" messages in old queue remain in old queue (are never removed, although they are not in new queue)
+//"YAMN_MSG_DELETED" messages in new queue remain in new queue (are never removed, although they can be in old queue)
+{
+ HYAMNMAIL Finder, FinderPrev;
+ HYAMNMAIL Parser, ParserPrev;
+ HYAMNMAIL RemovedOldParser = nullptr;
+ HYAMNMAIL RemovedNewParser = nullptr;
+ if (RemovedOld != nullptr) *RemovedOld = nullptr;
+ if (RemovedNew != nullptr) *RemovedNew = nullptr;
+
+ for (FinderPrev = nullptr, Finder = *OldQueue; Finder != nullptr;) {
+ if (Finder->Flags & YAMN_MSG_DELETED) //if old queue contains deleted mail
+ {
+ FinderPrev = Finder;
+ Finder = Finder->Next; //get next message in old queue for testing
+ continue;
+ }
+ for (ParserPrev = nullptr, Parser = *NewQueue; Parser != nullptr; ParserPrev = Parser, Parser = Parser->Next) {
+ if (Parser->Flags & YAMN_MSG_DELETED)
+ continue;
+
+ if (Parser->ID == nullptr) //simply ignore the message, that has not filled its ID
+ continue;
+
+ if (0 == mir_strcmp(Parser->ID, Finder->ID)) //search for equal message in new queue
+ break;
+ }
+ if (Parser != nullptr) //found equal message in new queue
+ {
+ if (Parser == *NewQueue)
+ *NewQueue = (*NewQueue)->Next;
+ else
+ ParserPrev->Next = Parser->Next;
+ Finder->Number = Parser->Number; //rewrite the number of current message in old queue
+
+ if (RemovedNew == nullptr) //delete from new queue
+ DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Parser);
+ else //or move to RemovedNew
+ {
+ if (RemovedNewParser == nullptr) //if it is first mail removed from NewQueue
+ *RemovedNew = Parser; //set RemovedNew queue to point to first message in removed queue
+ else
+ RemovedNewParser->Next = Parser; //else don't forget to show to next message in RemovedNew queue
+ RemovedNewParser = Parser; //follow RemovedNew queue
+ RemovedNewParser->Next = nullptr;
+ }
+ FinderPrev = Finder;
+ Finder = Finder->Next; //get next message in old queue for testing
+ }
+ else //a message was already deleted from mailbox
+ {
+ if (Finder == *OldQueue) //if we are at the first item in OldQueue
+ {
+ *OldQueue = (*OldQueue)->Next; //set OldQueue to next item
+ if (RemovedOld == nullptr) //delete from old queue
+ DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Finder);
+ else //or move to RemovedOld
+ {
+ if (RemovedOldParser == nullptr) //if it is first mail removed from OldQueue
+ *RemovedOld = Finder; //set RemovedOld queue to point to first message in removed queue
+ else
+ RemovedOldParser->Next = Finder; //else don't forget to show to next message in RemovedNew queue
+ RemovedOldParser = Finder; //follow RemovedOld queue
+ RemovedOldParser->Next = nullptr;
+ }
+ Finder = *OldQueue;
+ }
+ else {
+ FinderPrev->Next = Finder->Next;
+ if (RemovedOld == nullptr) //delete from old queue
+ DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Finder);
+ else //or move to RemovedOld
+ {
+ if (RemovedOldParser == nullptr) //if it is first mail removed from OldQueue
+ *RemovedOld = Finder; //set RemovedOld queue to point to first message in removed queue
+ else
+ RemovedOldParser->Next = Finder; //else don't forget to show to next message in RemovedNew queue
+ RemovedOldParser = Finder; //follow RemovedOld queue
+ RemovedOldParser->Next = nullptr;
+ }
+ Finder = FinderPrev->Next;
+ }
+ }
+ }
+}
+
+void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From)
+{
+ HYAMNMAIL Temp;
+ while (From != nullptr) {
+ Temp = From;
+ From = From->Next;
+ DeleteAccountMailSvc((WPARAM)Account->Plugin, (LPARAM)Temp);
+ }
+}
+
+void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode = 0)
+{
+ uint32_t Number = Which->Number;
+ HYAMNMAIL Parser;
+
+ if (*From == Which) {
+ Parser = Which->Next;
+ *From = Parser;
+ }
+ else {
+ for (Parser = *From; Which != Parser->Next; Parser = Parser->Next)
+ if (mode && (Parser->Number > Number)) Parser->Number--;
+ if (mode && (Parser->Number > Number)) Parser->Number--;
+ Parser->Next = Parser->Next->Next;
+ Parser = Which->Next;
+ }
+ if (mode)
+ for (; Parser != nullptr; Parser = Parser->Next)
+ if (Parser->Number > Number) Parser->Number--;
+}
+
+void DeleteMessagesFromQueue(HYAMNMAIL *From, HYAMNMAIL Which, int mode = 0)
+{
+ HYAMNMAIL Parser;
+
+ for (Parser = Which; Parser != nullptr; Parser = Parser->Next)
+ DeleteMessageFromQueueFcn(From, Parser, mode);
+}
+
+HYAMNMAIL WINAPI FindMessageByIDFcn(HYAMNMAIL From, char *ID)
+{
+ HYAMNMAIL Browser;
+
+ for (Browser = From; Browser != nullptr; Browser = Browser->Next)
+ if (0 == mir_strcmp(Browser->ID, ID))
+ break;
+ return Browser;
+}
+
+void WINAPI TranslateHeaderFcn(char *stream, int len, struct CMimeItem **head)
+{
+ try {
+ char *finder = stream;
+ char *prev1, *prev2, *prev3;
+ struct CMimeItem *Item = nullptr;
+
+ while (finder <= (stream + len)) {
+ while (ENDLINEWS(finder)) finder++;
+
+ //at the start of line
+ if (DOTLINE(finder + 1)) //at the end of stream
+ break;
+
+ prev1 = finder;
+
+ while (*finder != ':' && !EOS(finder)) finder++;
+ if (!EOS(finder))
+ prev2 = finder++;
+ else
+ break;
+
+ while (WS(finder) && !EOS(finder)) finder++;
+ if (!EOS(finder))
+ prev3 = finder;
+ else
+ break;
+
+ do {
+ if (ENDLINEWS(finder)) finder += 2; //after endline information continues
+ while (!ENDLINE(finder) && !EOS(finder)) finder++;
+ } while (ENDLINEWS(finder));
+
+ if (Item != nullptr) {
+ if (nullptr == (Item->Next = new struct CMimeItem))
+ break;
+ Item = Item->Next;
+ }
+ else {
+ Item = new CMimeItem;
+ *head = Item;
+ }
+
+ Item->Next = nullptr;
+ Item->name = new char[prev2 - prev1 + 1];
+ mir_strncpy(Item->name, prev1, prev2 - prev1 + 1);
+ Item->value = new char[finder - prev3 + 1];
+ mir_strncpy(Item->value, prev3, finder - prev3 + 1);
+
+ if (EOS(finder))
+ break;
+ finder++;
+ if (ENDLINE(finder)) {
+ finder++;
+ if (ENDLINE(finder)) {
+ // end of headers. message body begins
+ finder++;
+ if (ENDLINE(finder))finder++;
+ prev1 = finder;
+ while (!DOTLINE(finder + 1))finder++;
+ if (ENDLINE(finder))finder--;
+ prev2 = finder;
+ if (prev2 > prev1) { // yes, we have body
+ if (nullptr == (Item->Next = new struct CMimeItem)) break; // Cant create new item?!
+ Item = Item->Next;
+ Item->Next = nullptr;//just in case;
+ Item->name = new char[5]; strncpy(Item->name, "Body", 5);
+ Item->value = new char[prev2 - prev1];
+ mir_strncpy(Item->value, prev1, prev2 - prev1 - 1);
+ }
+ break; // there is nothing else
+ }
+ }
+ }
+ }
+ catch (...) {
+ MessageBoxA(nullptr, "Translate header error", "", 0);
+ }
+}
+
+HYAMNMAIL WINAPI CreateNewDeleteQueueFcn(HYAMNMAIL From)
+{
+ HYAMNMAIL FirstMail, Browser = nullptr;
+
+ for (FirstMail = nullptr; From != nullptr; From = From->Next) {
+ if ((From->Flags & (YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE)) && !(From->Flags & YAMN_MSG_DELETED)) {
+ if (FirstMail == nullptr) {
+ FirstMail = Browser = new YAMNMAIL;
+ if (FirstMail == nullptr)
+ break;
+ }
+ else {
+ Browser->Next = new YAMNMAIL;
+ Browser = Browser->Next;
+ }
+ Browser->ID = new char[mir_strlen(From->ID) + 1];
+ mir_strcpy(Browser->ID, From->ID);
+ Browser->Number = From->Number;
+ Browser->Flags = From->Flags;
+ }
+ }
+ return FirstMail;
+}
+
+void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSetRemove, int mode)
+{
+ HYAMNMAIL msgq;
+
+ for (msgq = (HYAMNMAIL)From; msgq != nullptr; msgq = msgq->Next) {
+ if ((FlagsSet == (msgq->Flags & FlagsSet)) && (0 == (msgq->Flags & FlagsNotSet))) {
+ if (mode)
+ msgq->Flags = msgq->Flags | FlagsToSetRemove;
+ else
+ msgq->Flags = msgq->Flags & ~FlagsToSetRemove;
+ }
+ }
+}
diff --git a/protocols/YAMN/src/mails/mime.cpp b/protocols/YAMN/src/mails/mime.cpp index 69099af808..2a2e7b4665 100644 --- a/protocols/YAMN/src/mails/mime.cpp +++ b/protocols/YAMN/src/mails/mime.cpp @@ -1,695 +1,695 @@ -/* - * This code implements retrieving info from MIME header - * - * (c) majvan 2002-2004 - */ - -#include "../stdafx.h" - - //-------------------------------------------------------------------------------------------------- - - //Copies one string to another - // srcstart- source string - // srcend- address to the end of source string - // dest- pointer that stores new allocated string that contains copy of source string - // mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' characters (or '<' and '>') if they are at start and end of source string -void CopyToHeader(char *srcstart, char *srcend, char **dest, int mode); - -//Extracts email address (finds nick name and mail and then stores them to strings) -// finder- source string -// storeto- pointer that receives address of mail string -// storetonick- pointer that receives address of nickname -void ExtractAddressFromLine(char *finder, char **storeto, char **storetonick); - -//Extracts simple text from string -// finder- source string -// storeto- pointer that receives address of string -void ExtractStringFromLine(char *finder, char **storeto); - -//Extracts some item from content-type string -//Example: ContentType string: "TEXT/PLAIN; charset=US-ASCII", item:"charset=", returns: "US-ASCII" -// ContetType- content-type string -// value- string item -// returns extracted string (or NULL when not found) -char *ExtractFromContentType(char *ContentType, char *value); - -//Extracts info from header text into header members -//Note that this function as well as struct CShortHeadwer can be always changed, because there are many items to extract -//(e.g. the X-Priority and Importance and so on) -// items- translated header (see TranslateHeaderFcn) -// head- header to be filled with values extracted from items -void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head); - -//Extracts header to mail using ExtractShortHeader fcn. -// items- translated header (see TranslateHeaderFcn) -// CP- codepage used when no default found -// head- header to be filled with values extracted from items, in unicode (wide char) -void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head); - -//Deletes items in CShortHeader structure -// head- structure whose items are deleted -void DeleteShortHeaderContent(struct CShortHeader *head); - -//Deletes list of YAMN_MIMENAMES structures -// Names- pointer to first item of list -void DeleteNames(CMimeNames *Names); - -//Deletes list of YAMN_MIMESHORTNAMES structures -// Names- pointer to first item of list -void DeleteShortNames(CShortNames *Names); - -//Makes a string lowercase -// string- string to be lowercased -void inline ToLower(char *string); - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -void CopyToHeader(char *srcstart, char *srcend, char **dest, int mode) -{ - char *dst; - - if (dest == nullptr) - return; - if (srcstart >= srcend) - return; - - if ((mode == MIME_MAIL) && (((*srcstart == '"') && (*(srcend - 1) == '"')) || ((*srcstart == '<') && (*(srcend - 1) == '>')))) { - srcstart++; - srcend--; - } - - if (srcstart >= srcend) - return; - - if (nullptr != *dest) - delete[] * dest; - if (nullptr == (*dest = new char[srcend - srcstart + 1])) - return; - - dst = *dest; - - for (; srcstart < srcend; dst++, srcstart++) { - if (ENDLINE(srcstart)) { - while (ENDLINE(srcstart) || WS(srcstart)) srcstart++; - *dst = ' '; - srcstart--; //because at the end of "for loop" we increment srcstart - } - else - *dst = *srcstart; - } - *dst = 0; -} - -void ExtractAddressFromLine(char *finder, char **storeto, char **storetonick) -{ - if (finder == nullptr) { - *storeto = *storetonick = nullptr; - return; - } - while (WS(finder)) finder++; - if ((*finder) != '<') { - char *finderend = finder + 1; - do { - if (ENDLINEWS(finderend)) //after endline information continues - finderend += 2; - while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string - } while (ENDLINEWS(finderend)); - finderend--; - while (WS(finderend) || ENDLINE(finderend)) finderend--; //find the end of text, no whitespace - if (*finderend != '>') //not '>' at the end of line - CopyToHeader(finder, finderend + 1, storeto, MIME_MAIL); - else //at the end of line, there's '>' - { - char *finder2 = finderend; - while ((*finder2 != '<') && (finder2 > finder)) finder2--; //go to matching '<' or to the start - CopyToHeader(finder2, finderend + 1, storeto, MIME_MAIL); - if (*finder2 == '<') //if we found '<', the rest copy as from nick - { - finder2--; - while (WS(finder2) || ENDLINE(finder2)) finder2--; //parse whitespace - CopyToHeader(finder, finder2 + 1, storetonick, MIME_MAIL); //and store nickname - } - } - } - else { - char *finderend = finder + 1; - do { - if (ENDLINEWS(finderend)) //after endline information continues - finderend += 2; - while (!ENDLINE(finderend) && (*finderend != '>') && !EOS(finderend)) finderend++; //seek to the matching < or to the end of line or to the end of string - } while (ENDLINEWS(finderend)); - CopyToHeader(finder, finderend + 1, storeto, MIME_MAIL); //go to first '>' or to the end and copy - finder = finderend + 1; - while (WS(finder)) finder++; //parse whitespace - if (!ENDLINE(finder) && !EOS(finder)) //if there are chars yet, it's nick - { - finderend = finder + 1; - while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string - finderend--; - while (WS(finderend)) finderend--; //find the end of line, no whitespace - CopyToHeader(finder, finderend + 1, storetonick, MIME_MAIL); - } - } -} - -void ExtractStringFromLine(char *finder, char **storeto) -{ - if (finder == nullptr) { - *storeto = nullptr; - return; - } - while (WS(finder)) finder++; - char *finderend = finder; - - do { - if (ENDLINEWS(finderend)) finderend++; //after endline information continues - while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; - } while (ENDLINEWS(finderend)); - finderend--; - while (WS(finderend)) finderend--; //find the end of line, no whitespace - CopyToHeader(finder, finderend + 1, storeto, MIME_PLAIN); -} - -char *ExtractFromContentType(char *ContentType, char *value) -{ - char *lowered = _strdup(ContentType); - ToLower(lowered); - char *finder = strstr(lowered, value); - if (finder == nullptr) { - free(lowered); - return nullptr; - } - finder = finder - lowered + ContentType; - free(lowered); - - char *temp, *copier; - char *CopiedString; - - temp = finder - 1; - while ((temp > ContentType) && WS(temp)) temp--; //now we have to find, if the word "Charset=" is located after ';' like "; Charset=" - if (*temp != ';' && !ENDLINE(temp) && temp != ContentType) - return nullptr; - finder = finder + mir_strlen(value); //jump over value string - - while (WS(finder)) finder++; //jump over whitespaces - temp = finder; - while (*temp != 0 && *temp != ';') temp++; //jump to the end of setting (to the next ;) - temp--; - while (WS(temp)) temp--; //remove whitespaces from the end - if (*finder == '\"') { //remove heading and tailing quotes - finder++; - if (*temp == '\"') temp--; - } - if (nullptr == (CopiedString = new char[++temp - finder + 1])) - return nullptr; - for (copier = CopiedString; finder != temp; *copier++ = *finder++); //copy string - *copier = 0; //and end it with zero character - - return CopiedString; -} - -void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head) -{ - for (; items != nullptr; items = items->Next) { - //at the start of line - //MessageBox(NULL,items->value,items->name,0); - if (0 == _strnicmp(items->name, "From", 4)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting from>"); - #endif - ExtractAddressFromLine(items->value, &head->From, &head->FromNick); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Return-Path", 11)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting return-path>"); - #endif - ExtractAddressFromLine(items->value, &head->ReturnPath, &head->ReturnPathNick); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Subject", 7)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting subject>"); - #endif - ExtractStringFromLine(items->value, &head->Subject); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Body", 4)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting body>"); - #endif - ExtractStringFromLine(items->value, &head->Body); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Date", 4)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting date>"); - #endif - ExtractStringFromLine(items->value, &head->Date); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - } - else if (0 == _strnicmp(items->name, "Content-Type", 12)) { - if (items->value == nullptr) - continue; - - char *ContentType = nullptr, *CharSetStr; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting Content-Type>"); - #endif - ExtractStringFromLine(items->value, &ContentType); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - ToLower(ContentType); - if (nullptr != (CharSetStr = ExtractFromContentType(ContentType, "charset="))) { - head->CP = GetCharsetFromString(CharSetStr, mir_strlen(CharSetStr)); - delete[] CharSetStr; - } - delete[] ContentType; - } - else if (0 == _strnicmp(items->name, "Importance", 10)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting importance>"); - #endif - if (head->Priority != -1) { - if (0 == strncmp(items->value, "low", 3)) - head->Priority = 5; - else if (0 == strncmp(items->value, "normal", 6)) - head->Priority = 3; - else if (0 == strncmp(items->value, "high", 4)) - head->Priority = 1; - } - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - } - else if (0 == _strnicmp(items->name, "X-Priority", 10)) { - if (items->value == nullptr) - continue; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<X-Priority>"); - #endif - if ((*items->value >= '1') && (*items->value <= '5')) - head->Priority = *items->value - '0'; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting>\n"); - #endif - } - - } -} - -void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head) -{ - struct CShortHeader ShortHeader; - - memset(&ShortHeader, 0, sizeof(struct CShortHeader)); - ShortHeader.Priority = ShortHeader.CP = -1; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting header>\n"); - #endif - ExtractShortHeader(items, &ShortHeader); - - head->Priority = ShortHeader.Priority == -1 ? 3 : ShortHeader.Priority; - CP = ShortHeader.CP == -1 ? CP : ShortHeader.CP; - #ifdef DEBUG_DECODE - if (NULL != ShortHeader.From) - DebugLog(DecodeFile, "<Decoded from>%s</Decoded)\n", ShortHeader.From); - if (NULL != ShortHeader.FromNick) - DebugLog(DecodeFile, "<Decoded from-nick>%s</Decoded)\n", ShortHeader.FromNick); - if (NULL != ShortHeader.ReturnPath) - DebugLog(DecodeFile, "<Decoded return-path>%s</Decoded)\n", ShortHeader.ReturnPath); - if (NULL != ShortHeader.ReturnPathNick) - DebugLog(DecodeFile, "<Decoded return-path nick>%s</Decoded)\n", ShortHeader.ReturnPathNick); - if (NULL != ShortHeader.Subject) - DebugLog(DecodeFile, "<Decoded subject>%s</Decoded)\n", ShortHeader.Subject); - if (NULL != ShortHeader.Date) - DebugLog(DecodeFile, "<Decoded date>%s</Decoded)\n", ShortHeader.Date); - DebugLog(DecodeFile, "</Extracting header>\n"); - DebugLog(DecodeFile, "<Convert>\n"); - #endif - - ConvertCodedStringToUnicode(ShortHeader.From, &head->From, CP, MIME_PLAIN); - - #ifdef DEBUG_DECODE - if (NULL != head->From) - DebugLogW(DecodeFile, L"<Converted from>%s</Converted>\n", head->From); - #endif - ConvertCodedStringToUnicode(ShortHeader.FromNick, &head->FromNick, CP, MIME_MAIL); - #ifdef DEBUG_DECODE - if (NULL != head->FromNick) - DebugLogW(DecodeFile, L"<Converted from-nick>%s</Converted>\n", head->FromNick); - #endif - ConvertCodedStringToUnicode(ShortHeader.ReturnPath, &head->ReturnPath, CP, MIME_PLAIN); - #ifdef DEBUG_DECODE - if (NULL != head->ReturnPath) - DebugLogW(DecodeFile, L"<Converted return-path>%s</Converted>\n", head->ReturnPath); - #endif - ConvertCodedStringToUnicode(ShortHeader.ReturnPathNick, &head->ReturnPathNick, CP, MIME_MAIL); - #ifdef DEBUG_DECODE - if (NULL != head->ReturnPathNick) - DebugLogW(DecodeFile, L"<Converted return-path nick>%s</Converted>\n", head->ReturnPathNick); - #endif - ConvertCodedStringToUnicode(ShortHeader.Subject, &head->Subject, CP, MIME_PLAIN); - #ifdef DEBUG_DECODE - if (NULL != head->Subject) - DebugLogW(DecodeFile, L"<Converted subject>%s</Converted>\n", head->Subject); - #endif - ConvertCodedStringToUnicode(ShortHeader.Date, &head->Date, CP, MIME_PLAIN); - #ifdef DEBUG_DECODE - if (NULL != head->Date) - DebugLogW(DecodeFile, L"<Converted date>%s</Converted>\n", head->Date); - #endif - - ConvertCodedStringToUnicode(ShortHeader.Body, &head->Body, CP, MIME_PLAIN); - #ifdef DEBUG_DECODE - if (NULL != head->Body) - DebugLogW(DecodeFile, L"<Converted Body>%s</Converted>\n", head->Body); - #endif - - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Convert>\n"); - #endif - - DeleteShortHeaderContent(&ShortHeader); - - // head->From=L"Frommmm"; - // head->Subject=L"Subject"; - return; -} - -void DeleteShortHeaderContent(struct CShortHeader *head) -{ - if (head->From != nullptr) delete[] head->From; - if (head->FromNick != nullptr) delete[] head->FromNick; - if (head->ReturnPath != nullptr) delete[] head->ReturnPath; - if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick; - if (head->Subject != nullptr) delete[] head->Subject; - if (head->Date != nullptr) delete[] head->Date; - if (head->To != nullptr) DeleteShortNames(head->To); - if (head->Cc != nullptr) DeleteShortNames(head->Cc); - if (head->Bcc != nullptr) DeleteShortNames(head->Bcc); - if (head->Body != nullptr) delete[] head->Body; -} - -void DeleteHeaderContent(struct CHeader *head) -{ - if (head->From != nullptr) delete[] head->From; - if (head->FromNick != nullptr) delete[] head->FromNick; - if (head->ReturnPath != nullptr) delete[] head->ReturnPath; - if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick; - if (head->Subject != nullptr) delete[] head->Subject; - if (head->Date != nullptr) delete[] head->Date; - if (head->Body != nullptr) delete[] head->Body; - if (head->To != nullptr) DeleteNames(head->To); - if (head->Cc != nullptr) DeleteNames(head->Cc); - if (head->Bcc != nullptr) DeleteNames(head->Bcc); -} - -void DeleteNames(CMimeNames *Names) -{ - CMimeNames *Parser = Names; - for (; Parser != nullptr; Parser = Parser->Next) { - if (Parser->Value != nullptr) - delete[] Parser->Value; - if (Parser->ValueNick != nullptr) - delete[] Parser->ValueNick; - - CMimeNames *Old = Parser; - Parser = Parser->Next; - delete Old; - } -} - -void DeleteShortNames(CShortNames *Names) -{ - CShortNames *Parser = Names; - for (; Parser != nullptr; Parser = Parser->Next) { - if (Parser->Value != nullptr) - delete[] Parser->Value; - if (Parser->ValueNick != nullptr) - delete[] Parser->ValueNick; - - CShortNames *Old = Parser; - Parser = Parser->Next; - delete Old; - } -} - - -void inline ToLower(char *string) -{ - for (; *string != 0; string++) - if (*string >= 'A' && *string <= 'Z') *string = *string - 'A' + 'a'; -} - -#define TE_UNKNOWN -#define TE_QUOTEDPRINTABLE 1 -#define TE_BASE64 2 -struct APartDataType -{ - char *Src;//Input - char *ContType; - int CodePage; - char *TransEnc; - uint8_t TransEncType; //TE_something - char *body; - int bodyLen; - wchar_t *wBody; -}; - - -void ParseAPart(APartDataType *data) -{ - size_t len = mir_strlen(data->Src); - try { - char *finder = data->Src; - char *prev1, *prev2, *prev3; - - while (finder <= (data->Src + len)) { - while (ENDLINEWS(finder)) finder++; - - //at the start of line - if (finder > data->Src) { - if (*(finder - 2) == '\r' || *(finder - 2) == '\n') - *(finder - 2) = 0; - if (*(finder - 1) == '\r' || *(finder - 1) == '\n') - *(finder - 1) = 0; - } - prev1 = finder; - - while (*finder != ':' && !EOS(finder) && !ENDLINE(finder)) finder++; - if (ENDLINE(finder) || EOS(finder)) { - // no ":" in the line? here the body begins; - data->body = prev1; - break; - } - prev2 = finder++; - - while (WS(finder) && !EOS(finder)) finder++; - if (!EOS(finder)) - prev3 = finder; - else - break; - - do { - if (ENDLINEWS(finder)) finder += 2; //after endline information continues - while (!ENDLINE(finder) && !EOS(finder)) finder++; - } while (ENDLINEWS(finder)); - - if (!_strnicmp(prev1, "Content-type", prev2 - prev1)) { - data->ContType = prev3; - } - else if (!_strnicmp(prev1, "Content-Transfer-Encoding", prev2 - prev1)) { - data->TransEnc = prev3; - } - - if (EOS(finder)) - break; - finder++; - if (ENDLINE(finder)) { - finder++; - if (ENDLINE(finder)) { - // end of headers. message body begins - if (finder > data->Src) { - if (*(finder - 2) == '\r' || *(finder - 2) == '\n') - *(finder - 2) = 0; - if (*(finder - 1) == '\r' || *(finder - 1) == '\n') - *(finder - 1) = 0; - } - finder++; - if (ENDLINE(finder))finder++; - prev1 = finder; - while (!EOS(finder + 1))finder++; - if (ENDLINE(finder))finder--; - prev2 = finder; - if (prev2 > prev1) { // yes, we have body - data->body = prev1; - } - break; // there is nothing else - } - } - } - } - catch (...) { - MessageBox(nullptr, TranslateT("Translate header error"), L"", 0); - } - if (data->body) data->bodyLen = (int)mir_strlen(data->body); -} - -//from decode.cpp -int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ); -int DecodeBase64(char *Src, char *Dst, int DstLen); -int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out); - -wchar_t *ParseMultipartBody(char *src, char *bond) -{ - char *srcback = _strdup(src); - size_t sizebond = mir_strlen(bond); - int numparts = 1; - int i; - char *courbond = srcback; - wchar_t *dest; - for (; (courbond = strstr(courbond, bond)); numparts++, courbond += sizebond); - APartDataType *partData = new APartDataType[numparts]; - memset(partData, 0, sizeof(APartDataType) * numparts); - partData[0].Src = courbond = srcback; - for (i = 1; (courbond = strstr(courbond, bond)); i++, courbond += sizebond) { - *(courbond - 2) = 0; - partData[i].Src = courbond + sizebond; - while (ENDLINE(partData[i].Src)) partData[i].Src++; - } - size_t resultSize = 0; - for (i = 0; i < numparts; i++) { - ParseAPart(&partData[i]); - if (partData[i].body) { - if (partData[i].TransEnc) { - if (!_stricmp(partData[i].TransEnc, "base64")) partData[i].TransEncType = TE_BASE64; - else if (!_stricmp(partData[i].TransEnc, "quoted-printable"))partData[i].TransEncType = TE_QUOTEDPRINTABLE; - } - if (partData[i].ContType) { - char *CharSetStr; - if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "charset="))) { - partData[i].CodePage = GetCharsetFromString(CharSetStr, mir_strlen(CharSetStr)); - delete[] CharSetStr; - } - } - if (partData[i].ContType && !_strnicmp(partData[i].ContType, "text", 4)) { - char *localBody = nullptr; - switch (partData[i].TransEncType) { - case TE_BASE64: - { - int size = partData[i].bodyLen * 3 / 4 + 5; - localBody = new char[size + 1]; - DecodeBase64(partData[i].body, localBody, size); - }break; - case TE_QUOTEDPRINTABLE: - { - int size = partData[i].bodyLen + 2; - localBody = new char[size + 1]; - DecodeQuotedPrintable(partData[i].body, localBody, size, FALSE); - }break; - } - ConvertStringToUnicode(localBody ? localBody : partData[i].body, partData[i].CodePage, &partData[i].wBody); - if (localBody) delete[] localBody; - } - else if (partData[i].ContType && !_strnicmp(partData[i].ContType, "multipart/", 10)) { - //Multipart in mulitipart recursive? should be SPAM. Ah well - char *bondary = nullptr; - if (nullptr != (bondary = ExtractFromContentType(partData[i].ContType, "boundary="))) { - partData[i].wBody = ParseMultipartBody(partData[i].body, bondary); - delete[] bondary; - } - else goto FailBackRaw; //multipart with no boundary? badly formatted messages. - } - else { -FailBackRaw: - ConvertStringToUnicode(partData[i].body, partData[i].CodePage, &partData[i].wBody); - } - resultSize += mir_wstrlen(partData[i].wBody); - }// if (partData[i].body) - resultSize += 100 + 4 + 3; //cr+nl+100+ 3*bullet - } - dest = new wchar_t[resultSize + 1]; - size_t destpos = 0; - for (i = 0; i < numparts; i++) { - if (i) { // part before first boudary should not have headers - char infoline[1024]; size_t linesize = 0; - mir_snprintf(infoline, "%s %d", Translate("Part"), i); - linesize = mir_strlen(infoline); - if (partData[i].TransEnc) { - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].TransEnc); - linesize = mir_strlen(infoline); - } - if (partData[i].ContType) { - char *CharSetStr = strchr(partData[i].ContType, ';'); - if (CharSetStr) { - CharSetStr[0] = 0; - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].ContType); - linesize = mir_strlen(infoline); - partData[i].ContType = CharSetStr + 1; - if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "charset="))) { - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", CharSetStr); - linesize = mir_strlen(infoline); - delete[] CharSetStr; - } - if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "name="))) { - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; \"%s\"", CharSetStr); - linesize = mir_strlen(infoline); - delete[] CharSetStr; - } - } - else { - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].ContType); - linesize = mir_strlen(infoline); - } - } - mir_snprintf(infoline + linesize, _countof(infoline) - linesize, ".\r\n"); - { - wchar_t *temp = nullptr; - dest[destpos] = dest[destpos + 1] = dest[destpos + 2] = 0x2022; // bullet; - destpos += 3; - ConvertStringToUnicode(infoline, CP_ACP, &temp); - size_t wsize = mir_wstrlen(temp); - mir_wstrcpy(&dest[destpos], temp); - destpos += wsize; - delete[] temp; - } - } // if (i) - - if (partData[i].wBody) { - size_t wsize = mir_wstrlen(partData[i].wBody); - mir_wstrcpy(&dest[destpos], partData[i].wBody); - destpos += wsize; - delete[] partData[i].wBody; - } - } - - free(srcback); - delete[] partData; - dest[resultSize] = 0;//just in case - return dest; -} +/*
+ * This code implements retrieving info from MIME header
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "../stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+
+ //Copies one string to another
+ // srcstart- source string
+ // srcend- address to the end of source string
+ // dest- pointer that stores new allocated string that contains copy of source string
+ // mode- MIME_PLAIN or MIME_MAIL (MIME_MAIL deletes '"' characters (or '<' and '>') if they are at start and end of source string
+void CopyToHeader(char *srcstart, char *srcend, char **dest, int mode);
+
+//Extracts email address (finds nick name and mail and then stores them to strings)
+// finder- source string
+// storeto- pointer that receives address of mail string
+// storetonick- pointer that receives address of nickname
+void ExtractAddressFromLine(char *finder, char **storeto, char **storetonick);
+
+//Extracts simple text from string
+// finder- source string
+// storeto- pointer that receives address of string
+void ExtractStringFromLine(char *finder, char **storeto);
+
+//Extracts some item from content-type string
+//Example: ContentType string: "TEXT/PLAIN; charset=US-ASCII", item:"charset=", returns: "US-ASCII"
+// ContetType- content-type string
+// value- string item
+// returns extracted string (or NULL when not found)
+char *ExtractFromContentType(char *ContentType, char *value);
+
+//Extracts info from header text into header members
+//Note that this function as well as struct CShortHeadwer can be always changed, because there are many items to extract
+//(e.g. the X-Priority and Importance and so on)
+// items- translated header (see TranslateHeaderFcn)
+// head- header to be filled with values extracted from items
+void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head);
+
+//Extracts header to mail using ExtractShortHeader fcn.
+// items- translated header (see TranslateHeaderFcn)
+// CP- codepage used when no default found
+// head- header to be filled with values extracted from items, in unicode (wide char)
+void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head);
+
+//Deletes items in CShortHeader structure
+// head- structure whose items are deleted
+void DeleteShortHeaderContent(struct CShortHeader *head);
+
+//Deletes list of YAMN_MIMENAMES structures
+// Names- pointer to first item of list
+void DeleteNames(CMimeNames *Names);
+
+//Deletes list of YAMN_MIMESHORTNAMES structures
+// Names- pointer to first item of list
+void DeleteShortNames(CShortNames *Names);
+
+//Makes a string lowercase
+// string- string to be lowercased
+void inline ToLower(char *string);
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+void CopyToHeader(char *srcstart, char *srcend, char **dest, int mode)
+{
+ char *dst;
+
+ if (dest == nullptr)
+ return;
+ if (srcstart >= srcend)
+ return;
+
+ if ((mode == MIME_MAIL) && (((*srcstart == '"') && (*(srcend - 1) == '"')) || ((*srcstart == '<') && (*(srcend - 1) == '>')))) {
+ srcstart++;
+ srcend--;
+ }
+
+ if (srcstart >= srcend)
+ return;
+
+ if (nullptr != *dest)
+ delete[] * dest;
+ if (nullptr == (*dest = new char[srcend - srcstart + 1]))
+ return;
+
+ dst = *dest;
+
+ for (; srcstart < srcend; dst++, srcstart++) {
+ if (ENDLINE(srcstart)) {
+ while (ENDLINE(srcstart) || WS(srcstart)) srcstart++;
+ *dst = ' ';
+ srcstart--; //because at the end of "for loop" we increment srcstart
+ }
+ else
+ *dst = *srcstart;
+ }
+ *dst = 0;
+}
+
+void ExtractAddressFromLine(char *finder, char **storeto, char **storetonick)
+{
+ if (finder == nullptr) {
+ *storeto = *storetonick = nullptr;
+ return;
+ }
+ while (WS(finder)) finder++;
+ if ((*finder) != '<') {
+ char *finderend = finder + 1;
+ do {
+ if (ENDLINEWS(finderend)) //after endline information continues
+ finderend += 2;
+ while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string
+ } while (ENDLINEWS(finderend));
+ finderend--;
+ while (WS(finderend) || ENDLINE(finderend)) finderend--; //find the end of text, no whitespace
+ if (*finderend != '>') //not '>' at the end of line
+ CopyToHeader(finder, finderend + 1, storeto, MIME_MAIL);
+ else //at the end of line, there's '>'
+ {
+ char *finder2 = finderend;
+ while ((*finder2 != '<') && (finder2 > finder)) finder2--; //go to matching '<' or to the start
+ CopyToHeader(finder2, finderend + 1, storeto, MIME_MAIL);
+ if (*finder2 == '<') //if we found '<', the rest copy as from nick
+ {
+ finder2--;
+ while (WS(finder2) || ENDLINE(finder2)) finder2--; //parse whitespace
+ CopyToHeader(finder, finder2 + 1, storetonick, MIME_MAIL); //and store nickname
+ }
+ }
+ }
+ else {
+ char *finderend = finder + 1;
+ do {
+ if (ENDLINEWS(finderend)) //after endline information continues
+ finderend += 2;
+ while (!ENDLINE(finderend) && (*finderend != '>') && !EOS(finderend)) finderend++; //seek to the matching < or to the end of line or to the end of string
+ } while (ENDLINEWS(finderend));
+ CopyToHeader(finder, finderend + 1, storeto, MIME_MAIL); //go to first '>' or to the end and copy
+ finder = finderend + 1;
+ while (WS(finder)) finder++; //parse whitespace
+ if (!ENDLINE(finder) && !EOS(finder)) //if there are chars yet, it's nick
+ {
+ finderend = finder + 1;
+ while (!ENDLINE(finderend) && !EOS(finderend)) finderend++; //seek to the end of line or to the end of string
+ finderend--;
+ while (WS(finderend)) finderend--; //find the end of line, no whitespace
+ CopyToHeader(finder, finderend + 1, storetonick, MIME_MAIL);
+ }
+ }
+}
+
+void ExtractStringFromLine(char *finder, char **storeto)
+{
+ if (finder == nullptr) {
+ *storeto = nullptr;
+ return;
+ }
+ while (WS(finder)) finder++;
+ char *finderend = finder;
+
+ do {
+ if (ENDLINEWS(finderend)) finderend++; //after endline information continues
+ while (!ENDLINE(finderend) && !EOS(finderend)) finderend++;
+ } while (ENDLINEWS(finderend));
+ finderend--;
+ while (WS(finderend)) finderend--; //find the end of line, no whitespace
+ CopyToHeader(finder, finderend + 1, storeto, MIME_PLAIN);
+}
+
+char *ExtractFromContentType(char *ContentType, char *value)
+{
+ char *lowered = _strdup(ContentType);
+ ToLower(lowered);
+ char *finder = strstr(lowered, value);
+ if (finder == nullptr) {
+ free(lowered);
+ return nullptr;
+ }
+ finder = finder - lowered + ContentType;
+ free(lowered);
+
+ char *temp, *copier;
+ char *CopiedString;
+
+ temp = finder - 1;
+ while ((temp > ContentType) && WS(temp)) temp--; //now we have to find, if the word "Charset=" is located after ';' like "; Charset="
+ if (*temp != ';' && !ENDLINE(temp) && temp != ContentType)
+ return nullptr;
+ finder = finder + mir_strlen(value); //jump over value string
+
+ while (WS(finder)) finder++; //jump over whitespaces
+ temp = finder;
+ while (*temp != 0 && *temp != ';') temp++; //jump to the end of setting (to the next ;)
+ temp--;
+ while (WS(temp)) temp--; //remove whitespaces from the end
+ if (*finder == '\"') { //remove heading and tailing quotes
+ finder++;
+ if (*temp == '\"') temp--;
+ }
+ if (nullptr == (CopiedString = new char[++temp - finder + 1]))
+ return nullptr;
+ for (copier = CopiedString; finder != temp; *copier++ = *finder++); //copy string
+ *copier = 0; //and end it with zero character
+
+ return CopiedString;
+}
+
+void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head)
+{
+ for (; items != nullptr; items = items->Next) {
+ //at the start of line
+ //MessageBox(NULL,items->value,items->name,0);
+ if (0 == _strnicmp(items->name, "From", 4)) {
+ if (items->value == nullptr)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting from>");
+ #endif
+ ExtractAddressFromLine(items->value, &head->From, &head->FromNick);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ }
+ else if (0 == _strnicmp(items->name, "Return-Path", 11)) {
+ if (items->value == nullptr)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting return-path>");
+ #endif
+ ExtractAddressFromLine(items->value, &head->ReturnPath, &head->ReturnPathNick);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ }
+ else if (0 == _strnicmp(items->name, "Subject", 7)) {
+ if (items->value == nullptr)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting subject>");
+ #endif
+ ExtractStringFromLine(items->value, &head->Subject);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ }
+ else if (0 == _strnicmp(items->name, "Body", 4)) {
+ if (items->value == nullptr)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting body>");
+ #endif
+ ExtractStringFromLine(items->value, &head->Body);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ }
+ else if (0 == _strnicmp(items->name, "Date", 4)) {
+ if (items->value == nullptr)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting date>");
+ #endif
+ ExtractStringFromLine(items->value, &head->Date);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ }
+ else if (0 == _strnicmp(items->name, "Content-Type", 12)) {
+ if (items->value == nullptr)
+ continue;
+
+ char *ContentType = nullptr, *CharSetStr;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting Content-Type>");
+ #endif
+ ExtractStringFromLine(items->value, &ContentType);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ ToLower(ContentType);
+ if (nullptr != (CharSetStr = ExtractFromContentType(ContentType, "charset="))) {
+ head->CP = GetCharsetFromString(CharSetStr, mir_strlen(CharSetStr));
+ delete[] CharSetStr;
+ }
+ delete[] ContentType;
+ }
+ else if (0 == _strnicmp(items->name, "Importance", 10)) {
+ if (items->value == nullptr)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting importance>");
+ #endif
+ if (head->Priority != -1) {
+ if (0 == strncmp(items->value, "low", 3))
+ head->Priority = 5;
+ else if (0 == strncmp(items->value, "normal", 6))
+ head->Priority = 3;
+ else if (0 == strncmp(items->value, "high", 4))
+ head->Priority = 1;
+ }
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ }
+ else if (0 == _strnicmp(items->name, "X-Priority", 10)) {
+ if (items->value == nullptr)
+ continue;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<X-Priority>");
+ #endif
+ if ((*items->value >= '1') && (*items->value <= '5'))
+ head->Priority = *items->value - '0';
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting>\n");
+ #endif
+ }
+
+ }
+}
+
+void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head)
+{
+ struct CShortHeader ShortHeader;
+
+ memset(&ShortHeader, 0, sizeof(struct CShortHeader));
+ ShortHeader.Priority = ShortHeader.CP = -1;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting header>\n");
+ #endif
+ ExtractShortHeader(items, &ShortHeader);
+
+ head->Priority = ShortHeader.Priority == -1 ? 3 : ShortHeader.Priority;
+ CP = ShortHeader.CP == -1 ? CP : ShortHeader.CP;
+ #ifdef DEBUG_DECODE
+ if (NULL != ShortHeader.From)
+ DebugLog(DecodeFile, "<Decoded from>%s</Decoded)\n", ShortHeader.From);
+ if (NULL != ShortHeader.FromNick)
+ DebugLog(DecodeFile, "<Decoded from-nick>%s</Decoded)\n", ShortHeader.FromNick);
+ if (NULL != ShortHeader.ReturnPath)
+ DebugLog(DecodeFile, "<Decoded return-path>%s</Decoded)\n", ShortHeader.ReturnPath);
+ if (NULL != ShortHeader.ReturnPathNick)
+ DebugLog(DecodeFile, "<Decoded return-path nick>%s</Decoded)\n", ShortHeader.ReturnPathNick);
+ if (NULL != ShortHeader.Subject)
+ DebugLog(DecodeFile, "<Decoded subject>%s</Decoded)\n", ShortHeader.Subject);
+ if (NULL != ShortHeader.Date)
+ DebugLog(DecodeFile, "<Decoded date>%s</Decoded)\n", ShortHeader.Date);
+ DebugLog(DecodeFile, "</Extracting header>\n");
+ DebugLog(DecodeFile, "<Convert>\n");
+ #endif
+
+ ConvertCodedStringToUnicode(ShortHeader.From, &head->From, CP, MIME_PLAIN);
+
+ #ifdef DEBUG_DECODE
+ if (NULL != head->From)
+ DebugLogW(DecodeFile, L"<Converted from>%s</Converted>\n", head->From);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.FromNick, &head->FromNick, CP, MIME_MAIL);
+ #ifdef DEBUG_DECODE
+ if (NULL != head->FromNick)
+ DebugLogW(DecodeFile, L"<Converted from-nick>%s</Converted>\n", head->FromNick);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.ReturnPath, &head->ReturnPath, CP, MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL != head->ReturnPath)
+ DebugLogW(DecodeFile, L"<Converted return-path>%s</Converted>\n", head->ReturnPath);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.ReturnPathNick, &head->ReturnPathNick, CP, MIME_MAIL);
+ #ifdef DEBUG_DECODE
+ if (NULL != head->ReturnPathNick)
+ DebugLogW(DecodeFile, L"<Converted return-path nick>%s</Converted>\n", head->ReturnPathNick);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.Subject, &head->Subject, CP, MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL != head->Subject)
+ DebugLogW(DecodeFile, L"<Converted subject>%s</Converted>\n", head->Subject);
+ #endif
+ ConvertCodedStringToUnicode(ShortHeader.Date, &head->Date, CP, MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL != head->Date)
+ DebugLogW(DecodeFile, L"<Converted date>%s</Converted>\n", head->Date);
+ #endif
+
+ ConvertCodedStringToUnicode(ShortHeader.Body, &head->Body, CP, MIME_PLAIN);
+ #ifdef DEBUG_DECODE
+ if (NULL != head->Body)
+ DebugLogW(DecodeFile, L"<Converted Body>%s</Converted>\n", head->Body);
+ #endif
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Convert>\n");
+ #endif
+
+ DeleteShortHeaderContent(&ShortHeader);
+
+ // head->From=L"Frommmm";
+ // head->Subject=L"Subject";
+ return;
+}
+
+void DeleteShortHeaderContent(struct CShortHeader *head)
+{
+ if (head->From != nullptr) delete[] head->From;
+ if (head->FromNick != nullptr) delete[] head->FromNick;
+ if (head->ReturnPath != nullptr) delete[] head->ReturnPath;
+ if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick;
+ if (head->Subject != nullptr) delete[] head->Subject;
+ if (head->Date != nullptr) delete[] head->Date;
+ if (head->To != nullptr) DeleteShortNames(head->To);
+ if (head->Cc != nullptr) DeleteShortNames(head->Cc);
+ if (head->Bcc != nullptr) DeleteShortNames(head->Bcc);
+ if (head->Body != nullptr) delete[] head->Body;
+}
+
+void DeleteHeaderContent(struct CHeader *head)
+{
+ if (head->From != nullptr) delete[] head->From;
+ if (head->FromNick != nullptr) delete[] head->FromNick;
+ if (head->ReturnPath != nullptr) delete[] head->ReturnPath;
+ if (head->ReturnPathNick != nullptr) delete[] head->ReturnPathNick;
+ if (head->Subject != nullptr) delete[] head->Subject;
+ if (head->Date != nullptr) delete[] head->Date;
+ if (head->Body != nullptr) delete[] head->Body;
+ if (head->To != nullptr) DeleteNames(head->To);
+ if (head->Cc != nullptr) DeleteNames(head->Cc);
+ if (head->Bcc != nullptr) DeleteNames(head->Bcc);
+}
+
+void DeleteNames(CMimeNames *Names)
+{
+ CMimeNames *Parser = Names;
+ for (; Parser != nullptr; Parser = Parser->Next) {
+ if (Parser->Value != nullptr)
+ delete[] Parser->Value;
+ if (Parser->ValueNick != nullptr)
+ delete[] Parser->ValueNick;
+
+ CMimeNames *Old = Parser;
+ Parser = Parser->Next;
+ delete Old;
+ }
+}
+
+void DeleteShortNames(CShortNames *Names)
+{
+ CShortNames *Parser = Names;
+ for (; Parser != nullptr; Parser = Parser->Next) {
+ if (Parser->Value != nullptr)
+ delete[] Parser->Value;
+ if (Parser->ValueNick != nullptr)
+ delete[] Parser->ValueNick;
+
+ CShortNames *Old = Parser;
+ Parser = Parser->Next;
+ delete Old;
+ }
+}
+
+
+void inline ToLower(char *string)
+{
+ for (; *string != 0; string++)
+ if (*string >= 'A' && *string <= 'Z') *string = *string - 'A' + 'a';
+}
+
+#define TE_UNKNOWN
+#define TE_QUOTEDPRINTABLE 1
+#define TE_BASE64 2
+struct APartDataType
+{
+ char *Src;//Input
+ char *ContType;
+ int CodePage;
+ char *TransEnc;
+ uint8_t TransEncType; //TE_something
+ char *body;
+ int bodyLen;
+ wchar_t *wBody;
+};
+
+
+void ParseAPart(APartDataType *data)
+{
+ size_t len = mir_strlen(data->Src);
+ try {
+ char *finder = data->Src;
+ char *prev1, *prev2, *prev3;
+
+ while (finder <= (data->Src + len)) {
+ while (ENDLINEWS(finder)) finder++;
+
+ //at the start of line
+ if (finder > data->Src) {
+ if (*(finder - 2) == '\r' || *(finder - 2) == '\n')
+ *(finder - 2) = 0;
+ if (*(finder - 1) == '\r' || *(finder - 1) == '\n')
+ *(finder - 1) = 0;
+ }
+ prev1 = finder;
+
+ while (*finder != ':' && !EOS(finder) && !ENDLINE(finder)) finder++;
+ if (ENDLINE(finder) || EOS(finder)) {
+ // no ":" in the line? here the body begins;
+ data->body = prev1;
+ break;
+ }
+ prev2 = finder++;
+
+ while (WS(finder) && !EOS(finder)) finder++;
+ if (!EOS(finder))
+ prev3 = finder;
+ else
+ break;
+
+ do {
+ if (ENDLINEWS(finder)) finder += 2; //after endline information continues
+ while (!ENDLINE(finder) && !EOS(finder)) finder++;
+ } while (ENDLINEWS(finder));
+
+ if (!_strnicmp(prev1, "Content-type", prev2 - prev1)) {
+ data->ContType = prev3;
+ }
+ else if (!_strnicmp(prev1, "Content-Transfer-Encoding", prev2 - prev1)) {
+ data->TransEnc = prev3;
+ }
+
+ if (EOS(finder))
+ break;
+ finder++;
+ if (ENDLINE(finder)) {
+ finder++;
+ if (ENDLINE(finder)) {
+ // end of headers. message body begins
+ if (finder > data->Src) {
+ if (*(finder - 2) == '\r' || *(finder - 2) == '\n')
+ *(finder - 2) = 0;
+ if (*(finder - 1) == '\r' || *(finder - 1) == '\n')
+ *(finder - 1) = 0;
+ }
+ finder++;
+ if (ENDLINE(finder))finder++;
+ prev1 = finder;
+ while (!EOS(finder + 1))finder++;
+ if (ENDLINE(finder))finder--;
+ prev2 = finder;
+ if (prev2 > prev1) { // yes, we have body
+ data->body = prev1;
+ }
+ break; // there is nothing else
+ }
+ }
+ }
+ }
+ catch (...) {
+ MessageBox(nullptr, TranslateT("Translate header error"), L"", 0);
+ }
+ if (data->body) data->bodyLen = (int)mir_strlen(data->body);
+}
+
+//from decode.cpp
+int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ);
+int DecodeBase64(char *Src, char *Dst, int DstLen);
+int ConvertStringToUnicode(char *stream, unsigned int cp, wchar_t **out);
+
+wchar_t *ParseMultipartBody(char *src, char *bond)
+{
+ char *srcback = _strdup(src);
+ size_t sizebond = mir_strlen(bond);
+ int numparts = 1;
+ int i;
+ char *courbond = srcback;
+ wchar_t *dest;
+ for (; (courbond = strstr(courbond, bond)); numparts++, courbond += sizebond);
+ APartDataType *partData = new APartDataType[numparts];
+ memset(partData, 0, sizeof(APartDataType) * numparts);
+ partData[0].Src = courbond = srcback;
+ for (i = 1; (courbond = strstr(courbond, bond)); i++, courbond += sizebond) {
+ *(courbond - 2) = 0;
+ partData[i].Src = courbond + sizebond;
+ while (ENDLINE(partData[i].Src)) partData[i].Src++;
+ }
+ size_t resultSize = 0;
+ for (i = 0; i < numparts; i++) {
+ ParseAPart(&partData[i]);
+ if (partData[i].body) {
+ if (partData[i].TransEnc) {
+ if (!_stricmp(partData[i].TransEnc, "base64")) partData[i].TransEncType = TE_BASE64;
+ else if (!_stricmp(partData[i].TransEnc, "quoted-printable"))partData[i].TransEncType = TE_QUOTEDPRINTABLE;
+ }
+ if (partData[i].ContType) {
+ char *CharSetStr;
+ if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "charset="))) {
+ partData[i].CodePage = GetCharsetFromString(CharSetStr, mir_strlen(CharSetStr));
+ delete[] CharSetStr;
+ }
+ }
+ if (partData[i].ContType && !_strnicmp(partData[i].ContType, "text", 4)) {
+ char *localBody = nullptr;
+ switch (partData[i].TransEncType) {
+ case TE_BASE64:
+ {
+ int size = partData[i].bodyLen * 3 / 4 + 5;
+ localBody = new char[size + 1];
+ DecodeBase64(partData[i].body, localBody, size);
+ }break;
+ case TE_QUOTEDPRINTABLE:
+ {
+ int size = partData[i].bodyLen + 2;
+ localBody = new char[size + 1];
+ DecodeQuotedPrintable(partData[i].body, localBody, size, FALSE);
+ }break;
+ }
+ ConvertStringToUnicode(localBody ? localBody : partData[i].body, partData[i].CodePage, &partData[i].wBody);
+ if (localBody) delete[] localBody;
+ }
+ else if (partData[i].ContType && !_strnicmp(partData[i].ContType, "multipart/", 10)) {
+ //Multipart in mulitipart recursive? should be SPAM. Ah well
+ char *bondary = nullptr;
+ if (nullptr != (bondary = ExtractFromContentType(partData[i].ContType, "boundary="))) {
+ partData[i].wBody = ParseMultipartBody(partData[i].body, bondary);
+ delete[] bondary;
+ }
+ else goto FailBackRaw; //multipart with no boundary? badly formatted messages.
+ }
+ else {
+FailBackRaw:
+ ConvertStringToUnicode(partData[i].body, partData[i].CodePage, &partData[i].wBody);
+ }
+ resultSize += mir_wstrlen(partData[i].wBody);
+ }// if (partData[i].body)
+ resultSize += 100 + 4 + 3; //cr+nl+100+ 3*bullet
+ }
+ dest = new wchar_t[resultSize + 1];
+ size_t destpos = 0;
+ for (i = 0; i < numparts; i++) {
+ if (i) { // part before first boudary should not have headers
+ char infoline[1024]; size_t linesize = 0;
+ mir_snprintf(infoline, "%s %d", Translate("Part"), i);
+ linesize = mir_strlen(infoline);
+ if (partData[i].TransEnc) {
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].TransEnc);
+ linesize = mir_strlen(infoline);
+ }
+ if (partData[i].ContType) {
+ char *CharSetStr = strchr(partData[i].ContType, ';');
+ if (CharSetStr) {
+ CharSetStr[0] = 0;
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].ContType);
+ linesize = mir_strlen(infoline);
+ partData[i].ContType = CharSetStr + 1;
+ if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "charset="))) {
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", CharSetStr);
+ linesize = mir_strlen(infoline);
+ delete[] CharSetStr;
+ }
+ if (nullptr != (CharSetStr = ExtractFromContentType(partData[i].ContType, "name="))) {
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; \"%s\"", CharSetStr);
+ linesize = mir_strlen(infoline);
+ delete[] CharSetStr;
+ }
+ }
+ else {
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, "; %s", partData[i].ContType);
+ linesize = mir_strlen(infoline);
+ }
+ }
+ mir_snprintf(infoline + linesize, _countof(infoline) - linesize, ".\r\n");
+ {
+ wchar_t *temp = nullptr;
+ dest[destpos] = dest[destpos + 1] = dest[destpos + 2] = 0x2022; // bullet;
+ destpos += 3;
+ ConvertStringToUnicode(infoline, CP_ACP, &temp);
+ size_t wsize = mir_wstrlen(temp);
+ mir_wstrcpy(&dest[destpos], temp);
+ destpos += wsize;
+ delete[] temp;
+ }
+ } // if (i)
+
+ if (partData[i].wBody) {
+ size_t wsize = mir_wstrlen(partData[i].wBody);
+ mir_wstrcpy(&dest[destpos], partData[i].wBody);
+ destpos += wsize;
+ delete[] partData[i].wBody;
+ }
+ }
+
+ free(srcback);
+ delete[] partData;
+ dest[resultSize] = 0;//just in case
+ return dest;
+}
diff --git a/protocols/YAMN/src/main.cpp b/protocols/YAMN/src/main.cpp index 72b831f765..c4979af1fb 100644 --- a/protocols/YAMN/src/main.cpp +++ b/protocols/YAMN/src/main.cpp @@ -1,324 +1,324 @@ -/* - * YAMN plugin main file - * Miranda homepage: http://miranda-icq.sourceforge.net/ - * YAMN homepage: http://www.majvan.host.sk/Projekty/YAMN - * - * initializes all variables for further work - * - * (c) majvan 2002-2004 - */ - -#include "stdafx.h" - - //-------------------------------------------------------------------------------------------------- - -wchar_t ProfileName[MAX_PATH]; -wchar_t UserDirectory[MAX_PATH]; - -wchar_t szMirandaDir[MAX_PATH]; -wchar_t szProfileDir[MAX_PATH]; - -BOOL UninstallPlugins; - -HANDLE hAccountFolder; - -HINSTANCE *hDllPlugins; -static int iDllPlugins = 0; - -YAMN_VARIABLES YAMNVar; - -CMPlugin g_plugin; - -HANDLE hNewMailHook; -HANDLE NoWriterEV; -HANDLE hTTButton; - -UINT SecTimer; - -#define FIXED_TAB_SIZE 100 // default value for fixed width tabs - -static void GetProfileDirectory(wchar_t *szPath, int cbPath) -//This is copied from Miranda's sources. In 0.2.1.0 it is needed, in newer vesions of Miranda use MS_DB_GETPROFILEPATH service -{ - wchar_t tszOldPath[MAX_PATH]; - Profile_GetPathW(_countof(tszOldPath), tszOldPath); - mir_wstrcat(tszOldPath, L"\\*.book"); - - VARSW ptszNewPath(L"%miranda_userdata%"); - - SHFILEOPSTRUCT file_op = { - nullptr, - FO_MOVE, - tszOldPath, - ptszNewPath, - FOF_NOERRORUI | FOF_NOCONFIRMATION | FOF_SILENT, - false, - nullptr, - L""}; - SHFileOperation(&file_op); - - wcsncpy(szPath, ptszNewPath, cbPath); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST}; - -///////////////////////////////////////////////////////////////////////////////////////// - -PLUGININFOEX pluginInfoEx = { - sizeof(PLUGININFOEX), - __PLUGIN_NAME, - PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM), - __DESCRIPTION, - __AUTHOR, - __COPYRIGHT, - __AUTHORWEB, - UNICODE_AWARE, - // {B047A7E5-027A-4CFC-8B18-EDA8345D2790} - {0xb047a7e5, 0x27a, 0x4cfc, {0x8b, 0x18, 0xed, 0xa8, 0x34, 0x5d, 0x27, 0x90}} -}; - -CMPlugin::CMPlugin() : - PLUGIN<CMPlugin>(YAMN_DBMODULE, pluginInfoEx) -{ - RegisterProtocol(PROTOTYPE_VIRTUAL); - SetUniqueId("Id"); -} - -///////////////////////////////////////////////////////////////////////////////////////// -// The callback function - -BOOL CALLBACK EnumSystemCodePagesProc(LPTSTR cpStr) -{ - // Convert code page string to number - UINT cp = _wtoi(cpStr); - if (!IsValidCodePage(cp)) - return TRUE; - - // Get Code Page name - CPINFOEX info; - if (GetCPInfoEx(cp, 0, &info)) { - for (int i = 1; i < CPLENALL; i++) if (CodePageNamesAll[i].CP == cp) { - CodePageNamesAll[i].isValid = TRUE; - CPLENSUPP++; - break; - } - } - return TRUE; -} - -int SystemModulesLoaded(WPARAM, LPARAM) -{ - //Insert "Check mail (YAMN)" item to Miranda's menu - CMenuItem mi(&g_plugin); - - SET_UID(mi, 0xa01ff3d9, 0x53cb, 0x4406, 0x85, 0xd9, 0xf1, 0x90, 0x3a, 0x94, 0xed, 0xf4); - mi.position = 0xb0000000; - mi.hIcolibItem = g_plugin.getIconHandle(IDI_CHECKMAIL); - mi.name.a = LPGEN("Check &mail (All Account)"); - mi.pszService = MS_YAMN_FORCECHECK; - Menu_AddMainMenuItem(&mi); - - SET_UID(mi, 0xfe22191f, 0x40c8, 0x479f, 0x93, 0x5d, 0xa5, 0x17, 0x1f, 0x57, 0x2f, 0xcb); - mi.name.a = LPGEN("Check &mail (This Account)"); - mi.pszService = MS_YAMN_CLISTCONTEXT; - Menu_AddContactMenuItem(&mi, YAMN_DBMODULE); - - SET_UID(mi, 0x147c7800, 0x12d0, 0x4209, 0xab, 0xcc, 0xfa, 0x64, 0xc6, 0xb0, 0xa6, 0xeb); - mi.hIcolibItem = g_plugin.getIconHandle(IDI_LAUNCHAPP); - mi.name.a = LPGEN("Launch application"); - mi.pszService = MS_YAMN_CLISTCONTEXTAPP; - Menu_AddContactMenuItem(&mi, YAMN_DBMODULE); - - if (hAccountFolder = FoldersRegisterCustomPathW(LPGEN("YAMN"), LPGEN("YAMN Account Folder"), UserDirectory)) - FoldersGetCustomPathW(hAccountFolder, UserDirectory, MAX_PATH, UserDirectory); - - RegisterPOP3Plugin(0, 0); - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static IconItem iconList[] = -{ - {LPGEN("Check mail"), "YAMN_Check", IDI_CHECKMAIL}, - {LPGEN("Launch application"), "YAMN_Launch", IDI_LAUNCHAPP}, - {LPGEN("New Mail"), "YAMN_NewMail", IDI_NEWMAIL}, - {LPGEN("Connect Fail"), "YAMN_ConnectFail", IDI_BADCONNECT}, -}; - -void LoadIcons() -{ - g_plugin.registerIcon("YAMN", iconList); -} - -static void LoadPlugins() -{ - wchar_t szSearchPath[MAX_PATH]; - mir_snwprintf(szSearchPath, L"%s\\Plugins\\YAMN\\*.dll", szMirandaDir); - - hDllPlugins = nullptr; - - WIN32_FIND_DATA fd; - HANDLE hFind = FindFirstFile(szSearchPath, &fd); - if (hFind != INVALID_HANDLE_VALUE) { - do { - //rewritten from Miranda sources... Needed because Win32 API has a bug in FindFirstFile, search is done for *.dlllllll... too - wchar_t *dot = wcsrchr(fd.cFileName, '.'); - if (dot == nullptr) - continue; - - // we have a dot - int len = (int)mir_wstrlen(fd.cFileName); // find the length of the string - wchar_t *end = fd.cFileName + len; // get a pointer to the NULL - int safe = (end - dot) - 1; // figure out how many chars after the dot are "safe", not including NULL - - if ((safe != 3) || (mir_wstrcmpi(dot + 1, L"dll") != 0)) //not bound, however the "dll" string should mean only 3 chars are compared - continue; - - wchar_t szPluginPath[MAX_PATH]; - mir_snwprintf(szPluginPath, L"%s\\Plugins\\YAMN\\%s", szMirandaDir, fd.cFileName); - HINSTANCE hDll = LoadLibrary(szPluginPath); - if (hDll == nullptr) - continue; - - LOADFILTERFCN LoadFilter = (LOADFILTERFCN)GetProcAddress(hDll, "LoadFilter"); - if (nullptr == LoadFilter) { - FreeLibrary(hDll); - hDll = nullptr; - continue; - } - - if (!LoadFilter(GetFcnPtrSvc)) { - FreeLibrary(hDll); - hDll = nullptr; - } - - if (hDll != nullptr) { - hDllPlugins = (HINSTANCE *)realloc(hDllPlugins, (iDllPlugins + 1) * sizeof(HINSTANCE)); - hDllPlugins[iDllPlugins++] = hDll; - } - } while (FindNextFile(hFind, &fd)); - - FindClose(hFind); - } -} - -int CMPlugin::Load() -{ - // we get the Miranda Root Path - PathToAbsoluteW(L".", szMirandaDir); - - // retrieve the current profile name - Profile_GetNameW(_countof(ProfileName), ProfileName); - wchar_t *fc = wcsrchr(ProfileName, '.'); - if (fc != nullptr) *fc = 0; - - // we get the user path where our yamn-account.book.ini is stored from mirandaboot.ini file - GetProfileDirectory(UserDirectory, _countof(UserDirectory)); - - // Enumerate all the code pages available for the System Locale - EnumSystemCodePages(EnumSystemCodePagesProc, CP_INSTALLED); - CodePageNamesSupp = new _tcptable[CPLENSUPP]; - for (int i = 0, k = 0; i < CPLENALL; i++) - if (CodePageNamesAll[i].isValid) { - CodePageNamesSupp[k] = CodePageNamesAll[i]; - k++; - } - - if (nullptr == (NoWriterEV = CreateEvent(nullptr, TRUE, TRUE, nullptr))) - return 1; - if (nullptr == (WriteToFileEV = CreateEvent(nullptr, FALSE, FALSE, nullptr))) - return 1; - if (nullptr == (ExitEV = CreateEvent(nullptr, TRUE, FALSE, nullptr))) - return 1; - - PosX = g_plugin.getDword(YAMN_DBPOSX, 0); - PosY = g_plugin.getDword(YAMN_DBPOSY, 0); - SizeX = g_plugin.getDword(YAMN_DBSIZEX, 800); - SizeY = g_plugin.getDword(YAMN_DBSIZEY, 200); - - HeadPosX = g_plugin.getDword(YAMN_DBMSGPOSX, 0); - HeadPosY = g_plugin.getDword(YAMN_DBMSGPOSY, 0); - HeadSizeX = g_plugin.getDword(YAMN_DBMSGSIZEX, 690); - HeadSizeY = g_plugin.getDword(YAMN_DBMSGSIZEY, 300); - HeadSplitPos = g_plugin.getWord(YAMN_DBMSGPOSSPLIT, 250); - - optDateTime = g_plugin.getByte(YAMN_DBTIMEOPTIONS, optDateTime); - - // Create new window queues for broadcast messages - YAMNVar.MessageWnds = WindowList_Create(); - YAMNVar.NewMailAccountWnd = WindowList_Create(); - YAMNVar.Shutdown = FALSE; - - hCurSplitNS = LoadCursor(nullptr, IDC_SIZENS); - hCurSplitWE = LoadCursor(nullptr, IDC_SIZEWE); - - #ifdef _DEBUG - InitDebug(); - #endif - - CreateServiceFunctions(); - - g_plugin.addSound(YAMN_NEWMAILSOUND, L"YAMN", YAMN_NEWMAILSNDDESC); - g_plugin.addSound(YAMN_CONNECTFAILSOUND, L"YAMN", YAMN_CONNECTFAILSNDDESC); - - HookEvents(); - - LoadIcons(); - LoadPlugins(); - - HOTKEYDESC hkd = {}; - hkd.pszName = "YAMN_hotkey"; - hkd.pszService = MS_YAMN_FORCECHECK; - hkd.szSection.a = YAMN_DBMODULE; - hkd.szDescription.a = LPGEN("Check mail"); - hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, VK_F11); - g_plugin.addHotkey(&hkd); - - //Create thread that will be executed every second - if (!(SecTimer = SetTimer(nullptr, 0, 1000, TimerProc))) - return 1; - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -static void UnloadPlugins() -{ - if (hDllPlugins == nullptr) - return; - - for (int i = iDllPlugins - 1; i >= 0; i--) { - if (FreeLibrary(hDllPlugins[i])) { - hDllPlugins[i] = nullptr; //for safety - iDllPlugins--; - } - } - free((void *)hDllPlugins); - hDllPlugins = nullptr; -} - -int CMPlugin::Unload() -{ - #ifdef _DEBUG - UnInitDebug(); - #endif - - WindowList_Destroy(YAMNVar.MessageWnds); - WindowList_Destroy(YAMNVar.NewMailAccountWnd); - - DestroyCursor(hCurSplitNS); - DestroyCursor(hCurSplitWE); - - CloseHandle(NoWriterEV); - CloseHandle(WriteToFileEV); - CloseHandle(ExitEV); - - UnloadPlugins(); - - delete[] CodePageNamesSupp; - return 0; -} +/*
+ * YAMN plugin main file
+ * Miranda homepage: http://miranda-icq.sourceforge.net/
+ * YAMN homepage: http://www.majvan.host.sk/Projekty/YAMN
+ *
+ * initializes all variables for further work
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+
+wchar_t ProfileName[MAX_PATH];
+wchar_t UserDirectory[MAX_PATH];
+
+wchar_t szMirandaDir[MAX_PATH];
+wchar_t szProfileDir[MAX_PATH];
+
+BOOL UninstallPlugins;
+
+HANDLE hAccountFolder;
+
+HINSTANCE *hDllPlugins;
+static int iDllPlugins = 0;
+
+YAMN_VARIABLES YAMNVar;
+
+CMPlugin g_plugin;
+
+HANDLE hNewMailHook;
+HANDLE NoWriterEV;
+HANDLE hTTButton;
+
+UINT SecTimer;
+
+#define FIXED_TAB_SIZE 100 // default value for fixed width tabs
+
+static void GetProfileDirectory(wchar_t *szPath, int cbPath)
+//This is copied from Miranda's sources. In 0.2.1.0 it is needed, in newer vesions of Miranda use MS_DB_GETPROFILEPATH service
+{
+ wchar_t tszOldPath[MAX_PATH];
+ Profile_GetPathW(_countof(tszOldPath), tszOldPath);
+ mir_wstrcat(tszOldPath, L"\\*.book");
+
+ VARSW ptszNewPath(L"%miranda_userdata%");
+
+ SHFILEOPSTRUCT file_op = {
+ nullptr,
+ FO_MOVE,
+ tszOldPath,
+ ptszNewPath,
+ FOF_NOERRORUI | FOF_NOCONFIRMATION | FOF_SILENT,
+ false,
+ nullptr,
+ L""};
+ SHFileOperation(&file_op);
+
+ wcsncpy(szPath, ptszNewPath, cbPath);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+extern "C" __declspec(dllexport) const MUUID MirandaInterfaces[] = {MIID_PROTOCOL, MIID_LAST};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+PLUGININFOEX pluginInfoEx = {
+ sizeof(PLUGININFOEX),
+ __PLUGIN_NAME,
+ PLUGIN_MAKE_VERSION(__MAJOR_VERSION, __MINOR_VERSION, __RELEASE_NUM, __BUILD_NUM),
+ __DESCRIPTION,
+ __AUTHOR,
+ __COPYRIGHT,
+ __AUTHORWEB,
+ UNICODE_AWARE,
+ // {B047A7E5-027A-4CFC-8B18-EDA8345D2790}
+ {0xb047a7e5, 0x27a, 0x4cfc, {0x8b, 0x18, 0xed, 0xa8, 0x34, 0x5d, 0x27, 0x90}}
+};
+
+CMPlugin::CMPlugin() :
+ PLUGIN<CMPlugin>(YAMN_DBMODULE, pluginInfoEx)
+{
+ RegisterProtocol(PROTOTYPE_VIRTUAL);
+ SetUniqueId("Id");
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// The callback function
+
+BOOL CALLBACK EnumSystemCodePagesProc(LPTSTR cpStr)
+{
+ // Convert code page string to number
+ UINT cp = _wtoi(cpStr);
+ if (!IsValidCodePage(cp))
+ return TRUE;
+
+ // Get Code Page name
+ CPINFOEX info;
+ if (GetCPInfoEx(cp, 0, &info)) {
+ for (int i = 1; i < CPLENALL; i++) if (CodePageNamesAll[i].CP == cp) {
+ CodePageNamesAll[i].isValid = TRUE;
+ CPLENSUPP++;
+ break;
+ }
+ }
+ return TRUE;
+}
+
+int SystemModulesLoaded(WPARAM, LPARAM)
+{
+ //Insert "Check mail (YAMN)" item to Miranda's menu
+ CMenuItem mi(&g_plugin);
+
+ SET_UID(mi, 0xa01ff3d9, 0x53cb, 0x4406, 0x85, 0xd9, 0xf1, 0x90, 0x3a, 0x94, 0xed, 0xf4);
+ mi.position = 0xb0000000;
+ mi.hIcolibItem = g_plugin.getIconHandle(IDI_CHECKMAIL);
+ mi.name.a = LPGEN("Check &mail (All Account)");
+ mi.pszService = MS_YAMN_FORCECHECK;
+ Menu_AddMainMenuItem(&mi);
+
+ SET_UID(mi, 0xfe22191f, 0x40c8, 0x479f, 0x93, 0x5d, 0xa5, 0x17, 0x1f, 0x57, 0x2f, 0xcb);
+ mi.name.a = LPGEN("Check &mail (This Account)");
+ mi.pszService = MS_YAMN_CLISTCONTEXT;
+ Menu_AddContactMenuItem(&mi, YAMN_DBMODULE);
+
+ SET_UID(mi, 0x147c7800, 0x12d0, 0x4209, 0xab, 0xcc, 0xfa, 0x64, 0xc6, 0xb0, 0xa6, 0xeb);
+ mi.hIcolibItem = g_plugin.getIconHandle(IDI_LAUNCHAPP);
+ mi.name.a = LPGEN("Launch application");
+ mi.pszService = MS_YAMN_CLISTCONTEXTAPP;
+ Menu_AddContactMenuItem(&mi, YAMN_DBMODULE);
+
+ if (hAccountFolder = FoldersRegisterCustomPathW(LPGEN("YAMN"), LPGEN("YAMN Account Folder"), UserDirectory))
+ FoldersGetCustomPathW(hAccountFolder, UserDirectory, MAX_PATH, UserDirectory);
+
+ RegisterPOP3Plugin(0, 0);
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static IconItem iconList[] =
+{
+ {LPGEN("Check mail"), "YAMN_Check", IDI_CHECKMAIL},
+ {LPGEN("Launch application"), "YAMN_Launch", IDI_LAUNCHAPP},
+ {LPGEN("New Mail"), "YAMN_NewMail", IDI_NEWMAIL},
+ {LPGEN("Connect Fail"), "YAMN_ConnectFail", IDI_BADCONNECT},
+};
+
+void LoadIcons()
+{
+ g_plugin.registerIcon("YAMN", iconList);
+}
+
+static void LoadPlugins()
+{
+ wchar_t szSearchPath[MAX_PATH];
+ mir_snwprintf(szSearchPath, L"%s\\Plugins\\YAMN\\*.dll", szMirandaDir);
+
+ hDllPlugins = nullptr;
+
+ WIN32_FIND_DATA fd;
+ HANDLE hFind = FindFirstFile(szSearchPath, &fd);
+ if (hFind != INVALID_HANDLE_VALUE) {
+ do {
+ //rewritten from Miranda sources... Needed because Win32 API has a bug in FindFirstFile, search is done for *.dlllllll... too
+ wchar_t *dot = wcsrchr(fd.cFileName, '.');
+ if (dot == nullptr)
+ continue;
+
+ // we have a dot
+ int len = (int)mir_wstrlen(fd.cFileName); // find the length of the string
+ wchar_t *end = fd.cFileName + len; // get a pointer to the NULL
+ int safe = (end - dot) - 1; // figure out how many chars after the dot are "safe", not including NULL
+
+ if ((safe != 3) || (mir_wstrcmpi(dot + 1, L"dll") != 0)) //not bound, however the "dll" string should mean only 3 chars are compared
+ continue;
+
+ wchar_t szPluginPath[MAX_PATH];
+ mir_snwprintf(szPluginPath, L"%s\\Plugins\\YAMN\\%s", szMirandaDir, fd.cFileName);
+ HINSTANCE hDll = LoadLibrary(szPluginPath);
+ if (hDll == nullptr)
+ continue;
+
+ LOADFILTERFCN LoadFilter = (LOADFILTERFCN)GetProcAddress(hDll, "LoadFilter");
+ if (nullptr == LoadFilter) {
+ FreeLibrary(hDll);
+ hDll = nullptr;
+ continue;
+ }
+
+ if (!LoadFilter(GetFcnPtrSvc)) {
+ FreeLibrary(hDll);
+ hDll = nullptr;
+ }
+
+ if (hDll != nullptr) {
+ hDllPlugins = (HINSTANCE *)realloc(hDllPlugins, (iDllPlugins + 1) * sizeof(HINSTANCE));
+ hDllPlugins[iDllPlugins++] = hDll;
+ }
+ } while (FindNextFile(hFind, &fd));
+
+ FindClose(hFind);
+ }
+}
+
+int CMPlugin::Load()
+{
+ // we get the Miranda Root Path
+ PathToAbsoluteW(L".", szMirandaDir);
+
+ // retrieve the current profile name
+ Profile_GetNameW(_countof(ProfileName), ProfileName);
+ wchar_t *fc = wcsrchr(ProfileName, '.');
+ if (fc != nullptr) *fc = 0;
+
+ // we get the user path where our yamn-account.book.ini is stored from mirandaboot.ini file
+ GetProfileDirectory(UserDirectory, _countof(UserDirectory));
+
+ // Enumerate all the code pages available for the System Locale
+ EnumSystemCodePages(EnumSystemCodePagesProc, CP_INSTALLED);
+ CodePageNamesSupp = new _tcptable[CPLENSUPP];
+ for (int i = 0, k = 0; i < CPLENALL; i++)
+ if (CodePageNamesAll[i].isValid) {
+ CodePageNamesSupp[k] = CodePageNamesAll[i];
+ k++;
+ }
+
+ if (nullptr == (NoWriterEV = CreateEvent(nullptr, TRUE, TRUE, nullptr)))
+ return 1;
+ if (nullptr == (WriteToFileEV = CreateEvent(nullptr, FALSE, FALSE, nullptr)))
+ return 1;
+ if (nullptr == (ExitEV = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
+ return 1;
+
+ PosX = g_plugin.getDword(YAMN_DBPOSX, 0);
+ PosY = g_plugin.getDword(YAMN_DBPOSY, 0);
+ SizeX = g_plugin.getDword(YAMN_DBSIZEX, 800);
+ SizeY = g_plugin.getDword(YAMN_DBSIZEY, 200);
+
+ HeadPosX = g_plugin.getDword(YAMN_DBMSGPOSX, 0);
+ HeadPosY = g_plugin.getDword(YAMN_DBMSGPOSY, 0);
+ HeadSizeX = g_plugin.getDword(YAMN_DBMSGSIZEX, 690);
+ HeadSizeY = g_plugin.getDword(YAMN_DBMSGSIZEY, 300);
+ HeadSplitPos = g_plugin.getWord(YAMN_DBMSGPOSSPLIT, 250);
+
+ optDateTime = g_plugin.getByte(YAMN_DBTIMEOPTIONS, optDateTime);
+
+ // Create new window queues for broadcast messages
+ YAMNVar.MessageWnds = WindowList_Create();
+ YAMNVar.NewMailAccountWnd = WindowList_Create();
+ YAMNVar.Shutdown = FALSE;
+
+ hCurSplitNS = LoadCursor(nullptr, IDC_SIZENS);
+ hCurSplitWE = LoadCursor(nullptr, IDC_SIZEWE);
+
+ #ifdef _DEBUG
+ InitDebug();
+ #endif
+
+ CreateServiceFunctions();
+
+ g_plugin.addSound(YAMN_NEWMAILSOUND, L"YAMN", YAMN_NEWMAILSNDDESC);
+ g_plugin.addSound(YAMN_CONNECTFAILSOUND, L"YAMN", YAMN_CONNECTFAILSNDDESC);
+
+ HookEvents();
+
+ LoadIcons();
+ LoadPlugins();
+
+ HOTKEYDESC hkd = {};
+ hkd.pszName = "YAMN_hotkey";
+ hkd.pszService = MS_YAMN_FORCECHECK;
+ hkd.szSection.a = YAMN_DBMODULE;
+ hkd.szDescription.a = LPGEN("Check mail");
+ hkd.DefHotKey = HOTKEYCODE(HOTKEYF_CONTROL, VK_F11);
+ g_plugin.addHotkey(&hkd);
+
+ //Create thread that will be executed every second
+ if (!(SecTimer = SetTimer(nullptr, 0, 1000, TimerProc)))
+ return 1;
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+static void UnloadPlugins()
+{
+ if (hDllPlugins == nullptr)
+ return;
+
+ for (int i = iDllPlugins - 1; i >= 0; i--) {
+ if (FreeLibrary(hDllPlugins[i])) {
+ hDllPlugins[i] = nullptr; //for safety
+ iDllPlugins--;
+ }
+ }
+ free((void *)hDllPlugins);
+ hDllPlugins = nullptr;
+}
+
+int CMPlugin::Unload()
+{
+ #ifdef _DEBUG
+ UnInitDebug();
+ #endif
+
+ WindowList_Destroy(YAMNVar.MessageWnds);
+ WindowList_Destroy(YAMNVar.NewMailAccountWnd);
+
+ DestroyCursor(hCurSplitNS);
+ DestroyCursor(hCurSplitWE);
+
+ CloseHandle(NoWriterEV);
+ CloseHandle(WriteToFileEV);
+ CloseHandle(ExitEV);
+
+ UnloadPlugins();
+
+ delete[] CodePageNamesSupp;
+ return 0;
+}
diff --git a/protocols/YAMN/src/main.h b/protocols/YAMN/src/main.h index cdcf5c285c..971ba43c9f 100644 --- a/protocols/YAMN/src/main.h +++ b/protocols/YAMN/src/main.h @@ -1,37 +1,37 @@ -#ifndef __MAIN_H -#define __MAIN_H - -#define YAMN_NEWMAILSNDDESC LPGENW("New mail message") -#define YAMN_CONNECTFAILSNDDESC LPGENW("Connect failed") -#define YAMN_CONNECTFAILSOUND "YAMN/Sound/ConnectFail" -#define YAMN_NEWMAILSOUND "YAMN/Sound/NewMail" - -#define YAMN_DBMODULE "YAMN" -#define YAMN_DBPOSX "MailBrowserWinX" -#define YAMN_DBPOSY "MailBrowserWinY" -#define YAMN_DBSIZEX "MailBrowserWinW" -#define YAMN_DBSIZEY "MailBrowserWinH" -#define YAMN_DBMSGPOSX "MailMessageWinX" -#define YAMN_DBMSGPOSY "MailMessageWinY" -#define YAMN_DBMSGSIZEX "MailMessageWinW" -#define YAMN_DBMSGSIZEY "MailMessageWinH" -#define YAMN_DBMSGPOSSPLIT "MailMessageSplitY" -#define YAMN_TTBFCHECK "ForceCheckTTB" -#define YAMN_CLOSEDELETE "CloseOnDelete" -#define YAMN_DBTIMEOPTIONS "MailBrowserTimeOpts" - -#define YAMN_DEFAULTHK MAKEWORD(VK_F11,MOD_CONTROL) - -#define SHOWDATELONG 0x01 -#define SHOWDATENOTODAY 0x02 -#define SHOWDATENOSECONDS 0x04 - -extern unsigned char optDateTime; - -// Loading Icon and checking for icolib -void LoadIcons(); - -typedef INT_PTR (*LOADFILTERFCN)(MIRANDASERVICE GetYAMNFcn); - -#endif - +#ifndef __MAIN_H
+#define __MAIN_H
+
+#define YAMN_NEWMAILSNDDESC LPGENW("New mail message")
+#define YAMN_CONNECTFAILSNDDESC LPGENW("Connect failed")
+#define YAMN_CONNECTFAILSOUND "YAMN/Sound/ConnectFail"
+#define YAMN_NEWMAILSOUND "YAMN/Sound/NewMail"
+
+#define YAMN_DBMODULE "YAMN"
+#define YAMN_DBPOSX "MailBrowserWinX"
+#define YAMN_DBPOSY "MailBrowserWinY"
+#define YAMN_DBSIZEX "MailBrowserWinW"
+#define YAMN_DBSIZEY "MailBrowserWinH"
+#define YAMN_DBMSGPOSX "MailMessageWinX"
+#define YAMN_DBMSGPOSY "MailMessageWinY"
+#define YAMN_DBMSGSIZEX "MailMessageWinW"
+#define YAMN_DBMSGSIZEY "MailMessageWinH"
+#define YAMN_DBMSGPOSSPLIT "MailMessageSplitY"
+#define YAMN_TTBFCHECK "ForceCheckTTB"
+#define YAMN_CLOSEDELETE "CloseOnDelete"
+#define YAMN_DBTIMEOPTIONS "MailBrowserTimeOpts"
+
+#define YAMN_DEFAULTHK MAKEWORD(VK_F11,MOD_CONTROL)
+
+#define SHOWDATELONG 0x01
+#define SHOWDATENOTODAY 0x02
+#define SHOWDATENOSECONDS 0x04
+
+extern unsigned char optDateTime;
+
+// Loading Icon and checking for icolib
+void LoadIcons();
+
+typedef INT_PTR (*LOADFILTERFCN)(MIRANDASERVICE GetYAMNFcn);
+
+#endif
+
diff --git a/protocols/YAMN/src/proto/netlib.cpp b/protocols/YAMN/src/proto/netlib.cpp index cf477e8219..726860e459 100644 --- a/protocols/YAMN/src/proto/netlib.cpp +++ b/protocols/YAMN/src/proto/netlib.cpp @@ -1,232 +1,232 @@ -/* - * This code implements communication based on Miranda netlib library - * - * (c) majvan 2002-2004 - */ - -#include "../stdafx.h" - - //-------------------------------------------------------------------------------------------------- - -BOOL SSLLoaded = FALSE; -HNETLIBUSER hNetlibUser = nullptr; - -void __stdcall SSL_DebugLog(const char *fmt, ...) -{ - char str[4096]; - va_list vararg; - - va_start(vararg, fmt); - int tBytes = mir_vsnprintf(str, _countof(str), fmt, vararg); - if (tBytes == 0) - return; - - if (tBytes > 0) - str[tBytes] = 0; - else - str[sizeof(str) - 1] = 0; - - Netlib_Log(hNetlibUser, str); - va_end(vararg); -} - -HANDLE RegisterNLClient(char *name) -{ - #ifdef DEBUG_COMM - DebugLog(CommFile, "<Register PROXY support>"); - #endif - - NETLIBUSER nlu = {}; - nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS; - nlu.szDescriptiveName.a = name; - nlu.szSettingsModule = (char *)name; - hNetlibUser = Netlib_RegisterUser(&nlu); - - #ifdef DEBUG_COMM - if (NULL == hNetlibUser) - DebugLog(CommFile, "<error></Register PROXY support>\n"); - else - DebugLog(CommFile, "</Register PROXY support>\n"); - #endif - return hNetlibUser; -} - -//Move connection to SSL -void CNLClient::SSLify() throw(DWORD) -{ - #ifdef DEBUG_COMM - SSL_DebugLog("Staring SSL..."); - #endif - int socket = Netlib_GetSocket(hConnection); - if (socket != INVALID_SOCKET) { - #ifdef DEBUG_COMM - SSL_DebugLog("Staring netlib core SSL"); - #endif - if (Netlib_StartSsl(hConnection, nullptr)) { - #ifdef DEBUG_COMM - SSL_DebugLog("Netlib core SSL started"); - #endif - isTLSed = true; - SSLLoaded = TRUE; - return; - } - } - - //ssl could not be created - throw NetworkError = (uint32_t)ESSL_CREATESSL; -} - -//Connects to the server through the sock -//if not success, exception is throwed -void CNLClient::Connect(const char *servername, const int port) throw(DWORD) -{ - NetworkError = SystemError = 0; - isTLSed = false; - - #ifdef DEBUG_COMM - DebugLog(CommFile, "<connect>\n"); - #endif - try { - if (nullptr == (hConnection = Netlib_OpenConnection(hNetlibUser, servername, port))) { - SystemError = WSAGetLastError(); - throw NetworkError = (uint32_t)ENL_CONNECT; - } - #ifdef DEBUG_COMM - DebugLog(CommFile, "</connect>\n"); - #endif - return; - } - catch (...) { - #ifdef DEBUG_COMM - DebugLog(CommFile, "<error></connect>\n"); - #endif - throw; - } -} - -//Performs a simple query -// query- command to send -int CNLClient::LocalNetlib_Send(HNETLIBCONN hConn, const char *buf, int len, int flags) -{ - return Netlib_Send(hConn, buf, len, flags); -} - -void CNLClient::Send(const char *query) throw(DWORD) -{ - unsigned int Sent; - - if (nullptr == query) - return; - if (hConnection == nullptr) - return; - #ifdef DEBUG_COMM - DebugLog(CommFile, "<send>%s", query); - #endif - try { - if ((SOCKET_ERROR == (Sent = LocalNetlib_Send(hConnection, query, (int)mir_strlen(query), MSG_DUMPASTEXT))) || Sent != (unsigned int)mir_strlen(query)) { - SystemError = WSAGetLastError(); - throw NetworkError = (uint32_t)ENL_SEND; - } - #ifdef DEBUG_COMM - DebugLog(CommFile, "</send>\n"); - #endif - } - catch (...) { - #ifdef DEBUG_COMM - DebugLog(CommFile, "<error></send>\n"); - #endif - throw; - } -} - -//Reads data from socket -// buf- buffer where to store max. buflen of received characters -// if buf is NULL, creates buffer of buflen size -// buf is NULL by default -//You need free() returned buffer, which can be allocated in this function -//if not success, exception is throwed - -int CNLClient::LocalNetlib_Recv(HNETLIBCONN hConn, char *buf, int len, int flags) -{ - int iReturn = Netlib_Recv(hConn, buf, len, flags); - if (isTLSed) { - #ifdef DEBUG_COMM - SSL_DebugLog("SSL recv: %s", buf); - #endif - } - - return iReturn; -} - -char *CNLClient::Recv(char *buf, int buflen) throw(DWORD) -{ - #ifdef DEBUG_COMM - DebugLog(CommFile, "<reading>"); - #endif - try { - if (buf == nullptr) - buf = (char *)malloc(sizeof(char) * (buflen + 1)); - if (buf == nullptr) - throw NetworkError = (uint32_t)ENL_RECVALLOC; - - if (!isTLSed) { - NETLIBSELECT nls = {}; - nls.dwTimeout = 60000; - nls.hReadConns[0] = hConnection; - switch (Netlib_Select(&nls)) { - case SOCKET_ERROR: - free(buf); - SystemError = WSAGetLastError(); - throw NetworkError = (uint32_t)ENL_RECV; - case 0: // time out! - free(buf); - throw NetworkError = (uint32_t)ENL_TIMEOUT; - } - } - - memset(buf, 0, buflen); - if (SOCKET_ERROR == (Rcv = LocalNetlib_Recv(hConnection, buf, buflen, MSG_DUMPASTEXT))) { - free(buf); - SystemError = WSAGetLastError(); - throw NetworkError = (uint32_t)ENL_RECV; - } - if (!Rcv) { - free(buf); - SystemError = WSAGetLastError(); - throw NetworkError = (uint32_t)ENL_RECV; - } - #ifdef DEBUG_COMM - *(buf + Rcv) = 0; //end the buffer to write it to file - DebugLog(CommFile, "%s", buf); - DebugLog(CommFile, "</reading>\n"); - #endif - return(buf); - } - catch (...) { - #ifdef DEBUG_COMM - DebugLog(CommFile, "<error></reading>\n"); - #endif - throw; - } -} - -//Closes netlib connection -void CNLClient::Disconnect() -{ - Netlib_CloseHandle(hConnection); - hConnection = nullptr; -} - -//Uninitializes netlib library -void UnregisterNLClient() -{ - #ifdef DEBUG_COMM - DebugLog(CommFile, "<Unregister PROXY support>"); - #endif - - Netlib_CloseHandle(hNetlibUser); - hNetlibUser = nullptr; - #ifdef DEBUG_COMM - DebugLog(CommFile, "</Unregister PROXY support>\n"); - #endif -} +/*
+ * This code implements communication based on Miranda netlib library
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "../stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+
+BOOL SSLLoaded = FALSE;
+HNETLIBUSER hNetlibUser = nullptr;
+
+void __stdcall SSL_DebugLog(const char *fmt, ...)
+{
+ char str[4096];
+ va_list vararg;
+
+ va_start(vararg, fmt);
+ int tBytes = mir_vsnprintf(str, _countof(str), fmt, vararg);
+ if (tBytes == 0)
+ return;
+
+ if (tBytes > 0)
+ str[tBytes] = 0;
+ else
+ str[sizeof(str) - 1] = 0;
+
+ Netlib_Log(hNetlibUser, str);
+ va_end(vararg);
+}
+
+HANDLE RegisterNLClient(char *name)
+{
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<Register PROXY support>");
+ #endif
+
+ NETLIBUSER nlu = {};
+ nlu.flags = NUF_OUTGOING | NUF_HTTPCONNS;
+ nlu.szDescriptiveName.a = name;
+ nlu.szSettingsModule = (char *)name;
+ hNetlibUser = Netlib_RegisterUser(&nlu);
+
+ #ifdef DEBUG_COMM
+ if (NULL == hNetlibUser)
+ DebugLog(CommFile, "<error></Register PROXY support>\n");
+ else
+ DebugLog(CommFile, "</Register PROXY support>\n");
+ #endif
+ return hNetlibUser;
+}
+
+//Move connection to SSL
+void CNLClient::SSLify() throw(DWORD)
+{
+ #ifdef DEBUG_COMM
+ SSL_DebugLog("Staring SSL...");
+ #endif
+ int socket = Netlib_GetSocket(hConnection);
+ if (socket != INVALID_SOCKET) {
+ #ifdef DEBUG_COMM
+ SSL_DebugLog("Staring netlib core SSL");
+ #endif
+ if (Netlib_StartSsl(hConnection, nullptr)) {
+ #ifdef DEBUG_COMM
+ SSL_DebugLog("Netlib core SSL started");
+ #endif
+ isTLSed = true;
+ SSLLoaded = TRUE;
+ return;
+ }
+ }
+
+ //ssl could not be created
+ throw NetworkError = (uint32_t)ESSL_CREATESSL;
+}
+
+//Connects to the server through the sock
+//if not success, exception is throwed
+void CNLClient::Connect(const char *servername, const int port) throw(DWORD)
+{
+ NetworkError = SystemError = 0;
+ isTLSed = false;
+
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<connect>\n");
+ #endif
+ try {
+ if (nullptr == (hConnection = Netlib_OpenConnection(hNetlibUser, servername, port))) {
+ SystemError = WSAGetLastError();
+ throw NetworkError = (uint32_t)ENL_CONNECT;
+ }
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "</connect>\n");
+ #endif
+ return;
+ }
+ catch (...) {
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<error></connect>\n");
+ #endif
+ throw;
+ }
+}
+
+//Performs a simple query
+// query- command to send
+int CNLClient::LocalNetlib_Send(HNETLIBCONN hConn, const char *buf, int len, int flags)
+{
+ return Netlib_Send(hConn, buf, len, flags);
+}
+
+void CNLClient::Send(const char *query) throw(DWORD)
+{
+ unsigned int Sent;
+
+ if (nullptr == query)
+ return;
+ if (hConnection == nullptr)
+ return;
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<send>%s", query);
+ #endif
+ try {
+ if ((SOCKET_ERROR == (Sent = LocalNetlib_Send(hConnection, query, (int)mir_strlen(query), MSG_DUMPASTEXT))) || Sent != (unsigned int)mir_strlen(query)) {
+ SystemError = WSAGetLastError();
+ throw NetworkError = (uint32_t)ENL_SEND;
+ }
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "</send>\n");
+ #endif
+ }
+ catch (...) {
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<error></send>\n");
+ #endif
+ throw;
+ }
+}
+
+//Reads data from socket
+// buf- buffer where to store max. buflen of received characters
+// if buf is NULL, creates buffer of buflen size
+// buf is NULL by default
+//You need free() returned buffer, which can be allocated in this function
+//if not success, exception is throwed
+
+int CNLClient::LocalNetlib_Recv(HNETLIBCONN hConn, char *buf, int len, int flags)
+{
+ int iReturn = Netlib_Recv(hConn, buf, len, flags);
+ if (isTLSed) {
+ #ifdef DEBUG_COMM
+ SSL_DebugLog("SSL recv: %s", buf);
+ #endif
+ }
+
+ return iReturn;
+}
+
+char *CNLClient::Recv(char *buf, int buflen) throw(DWORD)
+{
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<reading>");
+ #endif
+ try {
+ if (buf == nullptr)
+ buf = (char *)malloc(sizeof(char) * (buflen + 1));
+ if (buf == nullptr)
+ throw NetworkError = (uint32_t)ENL_RECVALLOC;
+
+ if (!isTLSed) {
+ NETLIBSELECT nls = {};
+ nls.dwTimeout = 60000;
+ nls.hReadConns[0] = hConnection;
+ switch (Netlib_Select(&nls)) {
+ case SOCKET_ERROR:
+ free(buf);
+ SystemError = WSAGetLastError();
+ throw NetworkError = (uint32_t)ENL_RECV;
+ case 0: // time out!
+ free(buf);
+ throw NetworkError = (uint32_t)ENL_TIMEOUT;
+ }
+ }
+
+ memset(buf, 0, buflen);
+ if (SOCKET_ERROR == (Rcv = LocalNetlib_Recv(hConnection, buf, buflen, MSG_DUMPASTEXT))) {
+ free(buf);
+ SystemError = WSAGetLastError();
+ throw NetworkError = (uint32_t)ENL_RECV;
+ }
+ if (!Rcv) {
+ free(buf);
+ SystemError = WSAGetLastError();
+ throw NetworkError = (uint32_t)ENL_RECV;
+ }
+ #ifdef DEBUG_COMM
+ *(buf + Rcv) = 0; //end the buffer to write it to file
+ DebugLog(CommFile, "%s", buf);
+ DebugLog(CommFile, "</reading>\n");
+ #endif
+ return(buf);
+ }
+ catch (...) {
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<error></reading>\n");
+ #endif
+ throw;
+ }
+}
+
+//Closes netlib connection
+void CNLClient::Disconnect()
+{
+ Netlib_CloseHandle(hConnection);
+ hConnection = nullptr;
+}
+
+//Uninitializes netlib library
+void UnregisterNLClient()
+{
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<Unregister PROXY support>");
+ #endif
+
+ Netlib_CloseHandle(hNetlibUser);
+ hNetlibUser = nullptr;
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "</Unregister PROXY support>\n");
+ #endif
+}
diff --git a/protocols/YAMN/src/proto/pop3/pop3.cpp b/protocols/YAMN/src/proto/pop3/pop3.cpp index d8f704dbd6..8d24a5218c 100644 --- a/protocols/YAMN/src/proto/pop3/pop3.cpp +++ b/protocols/YAMN/src/proto/pop3/pop3.cpp @@ -1,344 +1,344 @@ -/* - * This code implements basics of POP3 protocol - * - * (c) majvan 2002-2004 - */ -/* This was made from the libspopc project - * copyright c 2002 Benoit Rouits <brouits@free.fr> - * released under the terms of GNU LGPL - * (GNU Lesser General Public Licence). - * libspopc offers simple API for a pop3 client (MTA). - * See RFC 1725 for pop3 specifications. - * more information on http://brouits.free.fr/libspopc/ - */ -/* - * This file is not original and is changed by majvan <om3tn@psg.sk> - * for mail checker purpose. Please see original web page to - * obtain the original. I rewrote it in C++, but good ideas were, - * I think, unchanged. - * - * Note that this file was not designed to work under Unix. It's - * needed to add Unix-specific features. I was interested only in - * Windows for my project. majvan - * - */ - -#include "../../stdafx.h" - - //-------------------------------------------------------------------------------------------------- - - //Connects to the server through the netlib - //if not success, exception is throwed - //returns welcome string returned by server - //sets AckFlag -char *CPop3Client::Connect(const char *servername, const int port, BOOL UseSSL, BOOL NoTLS) -{ - if (Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - delete NetClient; - SSL = UseSSL; - NetClient = new CNLClient; - - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "Connect:servername: %s port:%d\n", servername, port); - #endif - POP3Error = EPOP3_CONNECT; - NetClient->Connect(servername, port); - POP3Error = 0; - - if (SSL) { - try { - NetClient->SSLify(); - } - catch (...) { - NetClient->Disconnect(); - return nullptr; - } - } - - char *temp = RecvRest(NetClient->Recv(), POP3_SEARCHACK); - extern BOOL SSLLoaded; - if (!NoTLS & !(SSL)) { - if (NetClient->Stopped) //check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - NetClient->Send("STLS\r\n"); - free(temp); - temp = RecvRest(NetClient->Recv(), POP3_SEARCHACK); - if (AckFlag == POP3_FOK) { // Ok, we are going to tls - try { - NetClient->SSLify(); - } - catch (...) { - NetClient->Disconnect(); - return nullptr; - } - } - } - return temp; -} - -//Receives data to the end of packet -// prev- previous data read (appends to this string next received data) -// mode- mode of packet. -// Packet can end with ack state (+OK or -ERR): set mode to POP3_SEARCHACK -// If packet ends with '.' (end of string), set mode to POP3_SEARCHDOT -// size- received data are stored to memory, but if length of data is more than allocated memory, function allocates -// new memory. New allocated memory has allocated size more bytes -// This value can be selectable: if you think it is better to reallocate by 1kB size, select size to 1024, -// default is 128. You do not need to use this parameter - -char *CPop3Client::RecvRest(char *prev, int mode, int size) -{ - int SizeRead = 0; - int SizeLeft = size - NetClient->Rcv; - int RcvAll = NetClient->Rcv; - char *LastString, *PrevString = prev; - - AckFlag = 0; - - while (((mode == POP3_SEARCHDOT) && !SearchFromEnd(PrevString + RcvAll - 1, RcvAll - 3, POP3_SEARCHDOT) && !SearchFromStart(PrevString, 2, POP3_SEARCHERR)) || //we are looking for dot or -err phrase - ((mode == POP3_SEARCHACK) && (!SearchFromStart(PrevString, RcvAll - 3, mode) || !((RcvAll > 3) && SearchFromEnd(PrevString + RcvAll - 1, 1, POP3_SEARCHNL))))) //we are looking for +ok or -err phrase ended with newline - { //if not found - if (NetClient->Stopped) //check if we can work with this POP3 client session - { - if (PrevString != nullptr) - free(PrevString); - throw POP3Error = (uint32_t)EPOP3_STOPPED; - } - if (SizeLeft == 0) //if block is full - { - SizeRead += size; - SizeLeft = size; - LastString = NetClient->Recv(nullptr, SizeLeft); - PrevString = (char *)realloc(PrevString, sizeof(char) * (SizeRead + size)); - if (PrevString == nullptr) - throw POP3Error = (uint32_t)EPOP3_RESTALLOC; - memcpy(PrevString + SizeRead, LastString, size); - free(LastString); - } - else - NetClient->Recv(PrevString + RcvAll, SizeLeft); //to Rcv stores received bytes - SizeLeft = SizeLeft - NetClient->Rcv; - RcvAll += NetClient->Rcv; - } - NetClient->Rcv = RcvAll; //at the end, store the number of all bytes, no the number of last received bytes - return PrevString; -} - -// CPop3Client::SearchFromEnd -// returns 1 if substring DOTLINE or ENDLINE found from end in bs bytes -// if you need to add condition for mode, insert it into switch statement -BOOL CPop3Client::SearchFromEnd(char *end, int bs, int mode) -{ - while (bs >= 0) { - switch (mode) { - case POP3_SEARCHDOT: - if (DOTLINE(end)) - return 1; - break; - - case POP3_SEARCHNL: - if (ENDLINE(end)) - return 1; - break; - } - end--; - bs--; - } - return 0; -} - -//Finds for a occurence of some pattern in string -// returns 1 if substring OKLINE, ERRLINE or any of them found from start in bs bytes -//call only this function to retrieve ack status (+OK or -ERR), because it sets flag AckFlag -//if you need to add condition for mode, insert it into switch statement -BOOL CPop3Client::SearchFromStart(char *start, int bs, int mode) -{ - while (bs >= 0) { - switch (mode) { - case POP3_SEARCHOK: - if (OKLINE(start)) { - AckFlag = POP3_FOK; - return 1; - } - break; - case POP3_SEARCHERR: - if (ERRLINE(start)) { - AckFlag = POP3_FERR; - return 1; - } - break; - case POP3_SEARCHACK: - if (ACKLINE(start)) { - OKLINE(start) ? AckFlag = POP3_FOK : AckFlag = POP3_FERR; - return 1; - } - break; - } - start++; - bs--; - } - return 0; -} - -//Performs "USER" pop query and returns server response -//sets AckFlag -char *CPop3Client::User(char *name) -{ - if (NetClient->Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[128]; - char *Result; - - mir_snprintf(query, "USER %s\r\n", name); - NetClient->Send(query); - Result = RecvRest(NetClient->Recv(), POP3_SEARCHACK); - if (AckFlag == POP3_FERR) - throw POP3Error = (uint32_t)EPOP3_BADUSER; - POP3Error = 0; - return Result; -} - -//Performs "PASS" pop query and returns server response -//sets AckFlag -char *CPop3Client::Pass(char *pw) -{ - if (NetClient->Stopped) //check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[128]; - mir_snprintf(query, "PASS %s\r\n", pw); - NetClient->Send(query); - - char *Result = RecvRest(NetClient->Recv(), POP3_SEARCHACK); - if (AckFlag == POP3_FERR) - throw POP3Error = (uint32_t)EPOP3_BADPASS; - return Result; -} - -//Performs "APOP" pop query and returns server response -//sets AckFlag -char *CPop3Client::APOP(char *name, char *pw, char *timestamp) -{ - if (NetClient->Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[512]; - char *Result; - unsigned char digest[16]; - - if (timestamp == nullptr) - throw POP3Error = (uint32_t)EPOP3_APOP; - mir_md5_state_s ctx; - mir_md5_init(&ctx); - mir_md5_append(&ctx, (const unsigned char *)timestamp, (unsigned int)mir_strlen(timestamp)); - mir_md5_append(&ctx, (const unsigned char *)pw, (unsigned int)mir_strlen(pw)); - mir_md5_finish(&ctx, digest); - - char hexdigest[40]; - mir_snprintf(query, "APOP %s %s\r\n", name, bin2hex(digest, sizeof(digest), hexdigest)); - - NetClient->Send(query); - Result = RecvRest(NetClient->Recv(), POP3_SEARCHACK); - if (AckFlag == POP3_FERR) - throw POP3Error = (uint32_t)EPOP3_BADUSER; - return Result; -} - -//Performs "QUIT" pop query and returns server response -//sets AckFlag -char *CPop3Client::Quit() -{ - char query[] = "QUIT\r\n"; - - NetClient->Send(query); - return RecvRest(NetClient->Recv(), POP3_SEARCHACK); -} - -//Performs "STAT" pop query and returns server response -//sets AckFlag -char *CPop3Client::Stat() -{ - if (NetClient->Stopped) //check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[] = "STAT\r\n"; - NetClient->Send(query); - return RecvRest(NetClient->Recv(), POP3_SEARCHACK); -} - -//Performs "LIST" pop query and returns server response -//sets AckFlag -char *CPop3Client::List() -{ - if (NetClient->Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[] = "LIST\r\n"; - - NetClient->Send(query); - return RecvRest(NetClient->Recv(), POP3_SEARCHDOT); -} - -//Performs "TOP" pop query and returns server response -//sets AckFlag -char *CPop3Client::Top(int nr, int lines) -{ - if (NetClient->Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[128]; - - mir_snprintf(query, "TOP %d %d\r\n", nr, lines); - NetClient->Send(query); - return RecvRest(NetClient->Recv(), POP3_SEARCHDOT); -} - -//Performs "UIDL" pop query and returns server response -//sets AckFlag -char *CPop3Client::Uidl(int nr) -{ - if (NetClient->Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[128]; - if (nr) { - mir_snprintf(query, "UIDL %d\r\n", nr); - NetClient->Send(query); - return RecvRest(NetClient->Recv(), POP3_SEARCHACK); - } - mir_snprintf(query, "UIDL\r\n"); - NetClient->Send(query); - return RecvRest(NetClient->Recv(), POP3_SEARCHDOT); -} - -//Performs "DELE" pop query and returns server response -//sets AckFlag -char *CPop3Client::Dele(int nr) -{ - if (NetClient->Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[128]; - - mir_snprintf(query, "DELE %d\r\n", nr); - NetClient->Send(query); - return RecvRest(NetClient->Recv(), POP3_SEARCHACK); -} - -//Performs "RETR" pop query and returns server response -//sets AckFlag -char *CPop3Client::Retr(int nr) -{ - if (NetClient->Stopped) // check if we can work with this POP3 client session - throw POP3Error = (uint32_t)EPOP3_STOPPED; - - char query[128]; - mir_snprintf(query, "RETR %d\r\n", nr); - NetClient->Send(query); - - RecvRest(NetClient->Recv(), POP3_SEARCHACK); - return NetClient->Recv(); -} +/*
+ * This code implements basics of POP3 protocol
+ *
+ * (c) majvan 2002-2004
+ */
+/* This was made from the libspopc project
+ * copyright c 2002 Benoit Rouits <brouits@free.fr>
+ * released under the terms of GNU LGPL
+ * (GNU Lesser General Public Licence).
+ * libspopc offers simple API for a pop3 client (MTA).
+ * See RFC 1725 for pop3 specifications.
+ * more information on http://brouits.free.fr/libspopc/
+ */
+/*
+ * This file is not original and is changed by majvan <om3tn@psg.sk>
+ * for mail checker purpose. Please see original web page to
+ * obtain the original. I rewrote it in C++, but good ideas were,
+ * I think, unchanged.
+ *
+ * Note that this file was not designed to work under Unix. It's
+ * needed to add Unix-specific features. I was interested only in
+ * Windows for my project. majvan
+ *
+ */
+
+#include "../../stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+
+ //Connects to the server through the netlib
+ //if not success, exception is throwed
+ //returns welcome string returned by server
+ //sets AckFlag
+char *CPop3Client::Connect(const char *servername, const int port, BOOL UseSSL, BOOL NoTLS)
+{
+ if (Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ delete NetClient;
+ SSL = UseSSL;
+ NetClient = new CNLClient;
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "Connect:servername: %s port:%d\n", servername, port);
+ #endif
+ POP3Error = EPOP3_CONNECT;
+ NetClient->Connect(servername, port);
+ POP3Error = 0;
+
+ if (SSL) {
+ try {
+ NetClient->SSLify();
+ }
+ catch (...) {
+ NetClient->Disconnect();
+ return nullptr;
+ }
+ }
+
+ char *temp = RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+ extern BOOL SSLLoaded;
+ if (!NoTLS & !(SSL)) {
+ if (NetClient->Stopped) //check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+ NetClient->Send("STLS\r\n");
+ free(temp);
+ temp = RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+ if (AckFlag == POP3_FOK) { // Ok, we are going to tls
+ try {
+ NetClient->SSLify();
+ }
+ catch (...) {
+ NetClient->Disconnect();
+ return nullptr;
+ }
+ }
+ }
+ return temp;
+}
+
+//Receives data to the end of packet
+// prev- previous data read (appends to this string next received data)
+// mode- mode of packet.
+// Packet can end with ack state (+OK or -ERR): set mode to POP3_SEARCHACK
+// If packet ends with '.' (end of string), set mode to POP3_SEARCHDOT
+// size- received data are stored to memory, but if length of data is more than allocated memory, function allocates
+// new memory. New allocated memory has allocated size more bytes
+// This value can be selectable: if you think it is better to reallocate by 1kB size, select size to 1024,
+// default is 128. You do not need to use this parameter
+
+char *CPop3Client::RecvRest(char *prev, int mode, int size)
+{
+ int SizeRead = 0;
+ int SizeLeft = size - NetClient->Rcv;
+ int RcvAll = NetClient->Rcv;
+ char *LastString, *PrevString = prev;
+
+ AckFlag = 0;
+
+ while (((mode == POP3_SEARCHDOT) && !SearchFromEnd(PrevString + RcvAll - 1, RcvAll - 3, POP3_SEARCHDOT) && !SearchFromStart(PrevString, 2, POP3_SEARCHERR)) || //we are looking for dot or -err phrase
+ ((mode == POP3_SEARCHACK) && (!SearchFromStart(PrevString, RcvAll - 3, mode) || !((RcvAll > 3) && SearchFromEnd(PrevString + RcvAll - 1, 1, POP3_SEARCHNL))))) //we are looking for +ok or -err phrase ended with newline
+ { //if not found
+ if (NetClient->Stopped) //check if we can work with this POP3 client session
+ {
+ if (PrevString != nullptr)
+ free(PrevString);
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+ }
+ if (SizeLeft == 0) //if block is full
+ {
+ SizeRead += size;
+ SizeLeft = size;
+ LastString = NetClient->Recv(nullptr, SizeLeft);
+ PrevString = (char *)realloc(PrevString, sizeof(char) * (SizeRead + size));
+ if (PrevString == nullptr)
+ throw POP3Error = (uint32_t)EPOP3_RESTALLOC;
+ memcpy(PrevString + SizeRead, LastString, size);
+ free(LastString);
+ }
+ else
+ NetClient->Recv(PrevString + RcvAll, SizeLeft); //to Rcv stores received bytes
+ SizeLeft = SizeLeft - NetClient->Rcv;
+ RcvAll += NetClient->Rcv;
+ }
+ NetClient->Rcv = RcvAll; //at the end, store the number of all bytes, no the number of last received bytes
+ return PrevString;
+}
+
+// CPop3Client::SearchFromEnd
+// returns 1 if substring DOTLINE or ENDLINE found from end in bs bytes
+// if you need to add condition for mode, insert it into switch statement
+BOOL CPop3Client::SearchFromEnd(char *end, int bs, int mode)
+{
+ while (bs >= 0) {
+ switch (mode) {
+ case POP3_SEARCHDOT:
+ if (DOTLINE(end))
+ return 1;
+ break;
+
+ case POP3_SEARCHNL:
+ if (ENDLINE(end))
+ return 1;
+ break;
+ }
+ end--;
+ bs--;
+ }
+ return 0;
+}
+
+//Finds for a occurence of some pattern in string
+// returns 1 if substring OKLINE, ERRLINE or any of them found from start in bs bytes
+//call only this function to retrieve ack status (+OK or -ERR), because it sets flag AckFlag
+//if you need to add condition for mode, insert it into switch statement
+BOOL CPop3Client::SearchFromStart(char *start, int bs, int mode)
+{
+ while (bs >= 0) {
+ switch (mode) {
+ case POP3_SEARCHOK:
+ if (OKLINE(start)) {
+ AckFlag = POP3_FOK;
+ return 1;
+ }
+ break;
+ case POP3_SEARCHERR:
+ if (ERRLINE(start)) {
+ AckFlag = POP3_FERR;
+ return 1;
+ }
+ break;
+ case POP3_SEARCHACK:
+ if (ACKLINE(start)) {
+ OKLINE(start) ? AckFlag = POP3_FOK : AckFlag = POP3_FERR;
+ return 1;
+ }
+ break;
+ }
+ start++;
+ bs--;
+ }
+ return 0;
+}
+
+//Performs "USER" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::User(char *name)
+{
+ if (NetClient->Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[128];
+ char *Result;
+
+ mir_snprintf(query, "USER %s\r\n", name);
+ NetClient->Send(query);
+ Result = RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+ if (AckFlag == POP3_FERR)
+ throw POP3Error = (uint32_t)EPOP3_BADUSER;
+ POP3Error = 0;
+ return Result;
+}
+
+//Performs "PASS" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::Pass(char *pw)
+{
+ if (NetClient->Stopped) //check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[128];
+ mir_snprintf(query, "PASS %s\r\n", pw);
+ NetClient->Send(query);
+
+ char *Result = RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+ if (AckFlag == POP3_FERR)
+ throw POP3Error = (uint32_t)EPOP3_BADPASS;
+ return Result;
+}
+
+//Performs "APOP" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::APOP(char *name, char *pw, char *timestamp)
+{
+ if (NetClient->Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[512];
+ char *Result;
+ unsigned char digest[16];
+
+ if (timestamp == nullptr)
+ throw POP3Error = (uint32_t)EPOP3_APOP;
+ mir_md5_state_s ctx;
+ mir_md5_init(&ctx);
+ mir_md5_append(&ctx, (const unsigned char *)timestamp, (unsigned int)mir_strlen(timestamp));
+ mir_md5_append(&ctx, (const unsigned char *)pw, (unsigned int)mir_strlen(pw));
+ mir_md5_finish(&ctx, digest);
+
+ char hexdigest[40];
+ mir_snprintf(query, "APOP %s %s\r\n", name, bin2hex(digest, sizeof(digest), hexdigest));
+
+ NetClient->Send(query);
+ Result = RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+ if (AckFlag == POP3_FERR)
+ throw POP3Error = (uint32_t)EPOP3_BADUSER;
+ return Result;
+}
+
+//Performs "QUIT" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::Quit()
+{
+ char query[] = "QUIT\r\n";
+
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+}
+
+//Performs "STAT" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::Stat()
+{
+ if (NetClient->Stopped) //check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[] = "STAT\r\n";
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+}
+
+//Performs "LIST" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::List()
+{
+ if (NetClient->Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[] = "LIST\r\n";
+
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(), POP3_SEARCHDOT);
+}
+
+//Performs "TOP" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::Top(int nr, int lines)
+{
+ if (NetClient->Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[128];
+
+ mir_snprintf(query, "TOP %d %d\r\n", nr, lines);
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(), POP3_SEARCHDOT);
+}
+
+//Performs "UIDL" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::Uidl(int nr)
+{
+ if (NetClient->Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[128];
+ if (nr) {
+ mir_snprintf(query, "UIDL %d\r\n", nr);
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+ }
+ mir_snprintf(query, "UIDL\r\n");
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(), POP3_SEARCHDOT);
+}
+
+//Performs "DELE" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::Dele(int nr)
+{
+ if (NetClient->Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[128];
+
+ mir_snprintf(query, "DELE %d\r\n", nr);
+ NetClient->Send(query);
+ return RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+}
+
+//Performs "RETR" pop query and returns server response
+//sets AckFlag
+char *CPop3Client::Retr(int nr)
+{
+ if (NetClient->Stopped) // check if we can work with this POP3 client session
+ throw POP3Error = (uint32_t)EPOP3_STOPPED;
+
+ char query[128];
+ mir_snprintf(query, "RETR %d\r\n", nr);
+ NetClient->Send(query);
+
+ RecvRest(NetClient->Recv(), POP3_SEARCHACK);
+ return NetClient->Recv();
+}
diff --git a/protocols/YAMN/src/proto/pop3/pop3comm.cpp b/protocols/YAMN/src/proto/pop3/pop3comm.cpp index 946b93ea54..fc0f5819bb 100644 --- a/protocols/YAMN/src/proto/pop3/pop3comm.cpp +++ b/protocols/YAMN/src/proto/pop3/pop3comm.cpp @@ -1,1329 +1,1329 @@ -/* - * This code implements POP3 server checking for new mail and so on. - * There's function SynchroPOP3 in this file- for checking and synchronising POP3 account - * and DeleteMailsPOP3- for deleting mails from POP3 server - * - * Note this file acts as main file for internal plugin. - * - * (c) majvan 2002-2004 - * 18/08 - */ - - -#include "../../stdafx.h" - -#define ERRORSTR_MAXLEN 1024 //in wide-chars - - //-------------------------------------------------------------------------------------------------- - -HANDLE hNetLib = nullptr; -PSCOUNTER CPOP3Account::AccountWriterSO = nullptr; - -//Creates new CPOP3Account structure -CAccount *WINAPI CreatePOP3Account(HYAMNPROTOPLUGIN Plugin, DWORD CAccountVersion); - -//Deletes CPOP3Account structure -void WINAPI DeletePOP3Account(CAccount *Which); - -//Sets stop flag to account -void WINAPI StopPOP3Account(CAccount *Which); - -//Function registers standard functions for YAMN -int RegisterPOP3Plugin(WPARAM, LPARAM); - -//Unloads all variables created on heap (delete[]) -DWORD WINAPI UnLoadPOP3(void *); - -//Function writes POP3 accounts using YAMN exported functions -DWORD WINAPI WritePOP3Accounts(); - -//Function stores plugin's data for account to file -DWORD WINAPI WritePOP3Options(HANDLE, CAccount *); - -//Function reads plugin's data for account from file -DWORD WINAPI ReadPOP3Options(CAccount *, char **, char *); - -//Creates new mail for an account -HYAMNMAIL WINAPI CreatePOP3Mail(CAccount *Account, DWORD CMimeMailVersion); - -//Function does all needed work when connection failed or any error occured -//Creates structure containing error code, closes internet session, runs "bad connect" function -static void PostErrorProc(HPOP3ACCOUNT ActualAccount, void *ParamToBadConnect, uint32_t POP3PluginParam, BOOL UseSSL); - -//Checks POP3 account and stores all info to account. It deletes old mails=> synchro -// WhichTemp- pointer to strucure containing needed information -DWORD WINAPI SynchroPOP3(struct CheckParam *WhichTemp); - -//Deletes mails from POP3 server -// WhichTemp- structure containing needed information (queued messages to delete) -//Function deletes from memory queue in WhichTemp structure -void __cdecl DeleteMailsPOP3(void *param); - -//Function makes readable message about error. It sends it back to YAMN, so YAMN then -//can show it to the message window -wchar_t *WINAPI GetErrorString(DWORD Code); - -//Function deletes string allocated in GetErrorString -void WINAPI DeleteErrorString(LPVOID String); - -//Extracts info from result of POP3's STAT command -// stream- source string -// len- length of source string -// mboxsize- adreess to integer, that receives size of mailbox -// mails- adreess to integer, that receives number of mails -void ExtractStat(char *stream, int *mboxsize, int *mails); - -//Extracts mail ID on mailbox -// stream- source string -// len- length of source string -// queue- address of first message, where first ID will be stored -void ExtractUIDL(char *stream, int len, HYAMNMAIL queue); - -//Extracts mail size on mailbox -// stream- source string -// len- length of source string -// queue- address of first message, where size of message #1 will be stored -void ExtractList(char *stream, int len, HYAMNMAIL queue); - -void ExtractMail(char *stream, int len, HYAMNMAIL queue); - -YAMNExportedFcns *pYAMNFcn = nullptr; -MailExportedFcns *pYAMNMailFcn = nullptr; - -YAMN_PROTOIMPORTFCN POP3ProtocolFunctions = -{ - CreatePOP3Account, - DeletePOP3Account, - StopPOP3Account, - WritePOP3Options, - ReadPOP3Options, - SynchroPOP3, - SynchroPOP3, - SynchroPOP3, - DeleteMailsPOP3, - GetErrorString, - nullptr, - DeleteErrorString, - WritePOP3Accounts, - nullptr, - UnLoadPOP3, -}; - -YAMN_MAILIMPORTFCN POP3MailFunctions = -{ - CreatePOP3Mail, - nullptr, - nullptr, - nullptr, -}; - -PYAMN_VARIABLES pYAMNVar = nullptr; -HYAMNPROTOPLUGIN POP3Plugin = nullptr; - -YAMN_PROTOREGISTRATION POP3ProtocolRegistration = -{ - "POP3 protocol (internal)", - __VERSION_STRING_DOTS, - __COPYRIGHT, - __DESCRIPTION, - __AUTHORWEB, -}; - -static wchar_t *FileName = nullptr; - -HANDLE RegisterNLClient(char *name); - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -CPOP3Account::CPOP3Account() -{ - //NOTE! This constructor constructs CAccount structure. If your plugin is not internal, - //you will need these constructors. All you need is in Account.cpp. Just copy to your source code - //constructor and destructor of CAccount. - UseInternetFree = CreateEvent(nullptr, FALSE, TRUE, nullptr); - InternetQueries = new SCOUNTER; - AbilityFlags = YAMN_ACC_BROWSE | YAMN_ACC_POPUP; - - SetAccountStatus((CAccount *)this, TranslateT("Disconnected")); -} - -CPOP3Account::~CPOP3Account() -{ - CloseHandle(UseInternetFree); - if (InternetQueries != nullptr) - delete InternetQueries; -} - -CAccount *WINAPI CreatePOP3Account(HYAMNPROTOPLUGIN, DWORD) -{ - //First, we should check whether CAccountVersion matches. - //But this is internal plugin, so YAMN's CAccount structure and our CAccount structure are - //the same, so we do not need to test version. Otherwise, if CAccount version does not match - //in your plugin, you should return NULL, like this: - // if (CAccountVersion != YAMN_ACCOUNTVERSION) return NULL; - - //Now it is needed to construct our POP3 account and return its handle - return (CAccount *)new struct CPOP3Account(); -} - -void WINAPI DeletePOP3Account(CAccount *Which) -{ - delete (HPOP3ACCOUNT)Which; -} - -void WINAPI StopPOP3Account(CAccount *Which) -{ - ((HPOP3ACCOUNT)Which)->Client.Stopped = TRUE; - if (((HPOP3ACCOUNT)Which)->Client.NetClient != nullptr) //we should inform also network client. Usefull only when network client implements this feature - ((HPOP3ACCOUNT)Which)->Client.NetClient->Stopped = TRUE; -} - -//This function is like main function for POP3 internal protocol -int RegisterPOP3Plugin(WPARAM, LPARAM) -{ - // Get YAMN variables we can use - if (nullptr == (pYAMNVar = (PYAMN_VARIABLES)CallService(MS_YAMN_GETVARIABLES, YAMN_VARIABLESVERSION, 0))) - return 0; - - // We have to get pointers to YAMN exported functions: allocate structure and fill it - if (nullptr == (pYAMNFcn = new struct YAMNExportedFcns)) { -LBL_Error: - UnLoadPOP3(nullptr); - return 0; - } - - // Register new pop3 user in netlib - if (nullptr == (hNetLib = RegisterNLClient("YAMN (POP3)"))) - goto LBL_Error; - - pYAMNFcn->SetProtocolPluginFcnImportFcn = (YAMN_SETPROTOCOLPLUGINFCNIMPORTFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SETPROTOCOLPLUGINFCNIMPORTID, 0); - pYAMNFcn->WaitToWriteFcn = (YAMN_WAITTOWRITEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WAITTOWRITEID, 0); - pYAMNFcn->WriteDoneFcn = (YAMN_WRITEDONEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WRITEDONEID, 0); - pYAMNFcn->WaitToReadFcn = (YAMN_WAITTOREADFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WAITTOREADID, 0); - pYAMNFcn->ReadDoneFcn = (YAMN_READDONEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_READDONEID, 0); - pYAMNFcn->SCGetNumberFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCGETNUMBERID, 0); - pYAMNFcn->SCIncFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCINCID, 0); - pYAMNFcn->SCDecFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCDECID, 0); - pYAMNFcn->SetStatusFcn = (YAMN_SETSTATUSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SETSTATUSID, 0); - pYAMNFcn->GetStatusFcn = (YAMN_GETSTATUSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_GETSTATUSID, 0); - - if (nullptr == (pYAMNMailFcn = new struct MailExportedFcns)) - goto LBL_Error; - - pYAMNMailFcn->SynchroMessagesFcn = (YAMN_SYNCHROMIMEMSGSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SYNCHROMIMEMSGSID, 0); - pYAMNMailFcn->TranslateHeaderFcn = (YAMN_TRANSLATEHEADERFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_TRANSLATEHEADERID, 0); - pYAMNMailFcn->AppendQueueFcn = (YAMN_APPENDQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_APPENDQUEUEID, 0); - pYAMNMailFcn->DeleteMessagesToEndFcn = (YAMN_DELETEMIMEQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_DELETEMIMEQUEUEID, 0); - pYAMNMailFcn->DeleteMessageFromQueueFcn = (YAMN_DELETEMIMEMESSAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_DELETEMIMEMESSAGEID, 0); - pYAMNMailFcn->FindMessageByIDFcn = (YAMN_FINDMIMEMESSAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_FINDMIMEMESSAGEID, 0); - pYAMNMailFcn->CreateNewDeleteQueueFcn = (YAMN_CREATENEWDELETEQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_CREATENEWDELETEQUEUEID, 0); - - //set static variable - if (CPOP3Account::AccountWriterSO == nullptr) - if (nullptr == (CPOP3Account::AccountWriterSO = new SCOUNTER)) - goto LBL_Error; - - //First, we register this plugin - //it is quite impossible this function returns zero (failure) as YAMN and internal plugin structre versions are the same - POP3ProtocolRegistration.Name = Translate("POP3 protocol (internal)"); - POP3ProtocolRegistration.Description = Translate(__DESCRIPTION); - if (nullptr == (POP3Plugin = (HYAMNPROTOPLUGIN)CallService(MS_YAMN_REGISTERPROTOPLUGIN, (WPARAM)&POP3ProtocolRegistration, (LPARAM)YAMN_PROTOREGISTRATIONVERSION))) - return 0; - - //Next we set our imported functions for YAMN - if (!SetProtocolPluginFcnImport(POP3Plugin, &POP3ProtocolFunctions, YAMN_PROTOIMPORTFCNVERSION, &POP3MailFunctions, YAMN_MAILIMPORTFCNVERSION)) - return 0; - - //Then, we read all mails for accounts. - //You must first register account, before using this function as YAMN must use CreatePOP3Account function to add new accounts - //But if CreatePOP3Account is not implemented (equals to NULL), YAMN creates account as YAMN's standard CAccount * - if (FileName) CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); //shoud not happen (only for secure) - FileName = (wchar_t *)CallService(MS_YAMN_GETFILENAME, (WPARAM)L"pop3", 0); - - switch (CallService(MS_YAMN_READACCOUNTS, (WPARAM)POP3Plugin, (LPARAM)FileName)) { - case EACC_FILEVERSION: - MessageBox(nullptr, TranslateT("Found new version of account book, not compatible with this version of YAMN."), TranslateT("YAMN (internal POP3) read error"), MB_OK); - CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); - FileName = nullptr; - return 0; - case EACC_FILECOMPATIBILITY: - MessageBox(nullptr, TranslateT("Error reading account file. Account file corrupted."), TranslateT("YAMN (internal POP3) read error"), MB_OK); - CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); - FileName = nullptr; - return 0; - case EACC_ALLOC: - MessageBox(nullptr, TranslateT("Memory allocation error while data reading"), TranslateT("YAMN (internal POP3) read error"), MB_OK); - CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); - FileName = nullptr; - return 0; - case EACC_SYSTEM: - if (ERROR_FILE_NOT_FOUND != GetLastError()) { - wchar_t temp[1024] = {0}; - mir_snwprintf(temp, L"%s\n%s", TranslateT("Reading file error. File already in use?"), FileName); - MessageBox(nullptr, temp, TranslateT("YAMN (internal POP3) read error"), MB_OK); - CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); - FileName = nullptr; - return 0; - } - break; - } - - for (CAccount *Finder = POP3Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) { - Finder->hContact = NULL; - for (auto &hContact : Contacts(YAMN_DBMODULE)) { - DBVARIANT dbv; - if (!g_plugin.getString(hContact, "Id", &dbv)) { - if (mir_strcmp(dbv.pszVal, Finder->Name) == 0) { - Finder->hContact = hContact; - g_plugin.setWord(Finder->hContact, "Status", ID_STATUS_ONLINE); - db_set_s(Finder->hContact, "CList", "StatusMsg", Translate("No new mail message")); - if ((Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) - Contact::Hide(Finder->hContact, false); - - if (!(Finder->Flags & YAMN_ACC_ENA) || !(Finder->NewMailN.Flags & YAMN_ACC_CONT)) - Contact::Hide(Finder->hContact); - } - db_free(&dbv); - } - } - - if (!Finder->hContact && (Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) { - // No account contact found, have to create one - Finder->hContact = db_add_contact(); - Proto_AddToContact(Finder->hContact, YAMN_DBMODULE); - g_plugin.setString(Finder->hContact, "Id", Finder->Name); - g_plugin.setString(Finder->hContact, "Nick", Finder->Name); - g_plugin.setWord(Finder->hContact, "Status", ID_STATUS_OFFLINE); - } - } - - return 0; -} - -DWORD WINAPI UnLoadPOP3(void *) -{ - //pYAMNVar is only a pointr, no need delete or free - if (hNetLib) { - Netlib_CloseHandle(hNetLib); hNetLib = nullptr; - } - if (CPOP3Account::AccountWriterSO) { - delete CPOP3Account::AccountWriterSO; CPOP3Account::AccountWriterSO = nullptr; - } - if (pYAMNMailFcn) { - delete pYAMNMailFcn; pYAMNMailFcn = nullptr; - } - if (pYAMNFcn) { - delete pYAMNFcn; pYAMNFcn = nullptr; - } - if (FileName) { - CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); FileName = nullptr; - } - - return 1; -} - -DWORD WINAPI WritePOP3Accounts() -{ - uint32_t ReturnValue = CallService(MS_YAMN_WRITEACCOUNTS, (WPARAM)POP3Plugin, (LPARAM)FileName); - if (ReturnValue == EACC_SYSTEM) { - wchar_t temp[1024] = {0}; - mir_snwprintf(temp, L"%s\n%s", TranslateT("Error while copying data to disk occurred. Is file in use?"), FileName); - MessageBox(nullptr, temp, TranslateT("POP3 plugin - write file error"), MB_OK); - } - - return ReturnValue; -} - -DWORD WINAPI WritePOP3Options(HANDLE File, CAccount *Which) -{ - DWORD WrittenBytes; - uint32_t Ver = POP3_FILEVERSION; - - if ((!WriteFile(File, (char *)&Ver, sizeof(uint32_t), &WrittenBytes, nullptr)) || - (!WriteFile(File, (char *)&((HPOP3ACCOUNT)Which)->CP, sizeof(uint16_t), &WrittenBytes, nullptr))) - return EACC_SYSTEM; - return 0; -} - -DWORD WINAPI ReadPOP3Options(CAccount *Which, char **Parser, char *End) -{ - uint32_t Ver; - #ifdef DEBUG_FILEREAD - wchar_t Debug[256]; - #endif - Ver = *(uint32_t *)(*Parser); - (*Parser) += sizeof(uint32_t); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - if (Ver != POP3_FILEVERSION) - return EACC_FILECOMPATIBILITY; - - ((HPOP3ACCOUNT)Which)->CP = *(uint16_t *)(*Parser); - (*Parser) += sizeof(uint16_t); - if (*Parser >= End) - return EACC_FILECOMPATIBILITY; - #ifdef DEBUG_FILEREAD - mir_snwprintf(Debug, L"CodePage: %d, remaining %d chars", ((HPOP3ACCOUNT)Which)->CP, End - *Parser); - MessageBox(NULL, Debug, L"debug", MB_OK); - #endif - return 0; -} - -HYAMNMAIL WINAPI CreatePOP3Mail(CAccount *Account, DWORD) -{ - HYAMNMAIL NewMail; - //First, we should check whether MAILDATA matches. - //But this is internal plugin, so YAMN's MAILDATA structure and our MAILDATA structure are - //the same, so we do not need to test version. Otherwise, if MAILDATA version does not match - //in your plugin, you should return NULL, like this: - // if (MailDataVersion != YAMN_MAILDATAVERSION) return NULL; - - //Now it is needed to construct our POP3 account and return its handle - if (nullptr == (NewMail = new YAMNMAIL)) - return nullptr; - - if (nullptr == (NewMail->MailData = new CMailData())) { - delete NewMail; - return nullptr; - } - NewMail->MailData->CP = ((HPOP3ACCOUNT)Account)->CP; - return (HYAMNMAIL)NewMail; -} - -static void SetContactStatus(CAccount *account, int status) -{ - if ((account->hContact) && (account->NewMailN.Flags & YAMN_ACC_CONT)) - g_plugin.setWord(account->hContact, "Status", status); -} - -static void PostErrorProc(HPOP3ACCOUNT ActualAccount, void *ParamToBadConnection, uint32_t POP3PluginParam, BOOL UseSSL) -{ - char *DataRX; - - //We create new structure, that we pass to bad connection dialog procedure. This procedure next calls YAMN imported fuction - //from POP3 protocol to determine the description of error. We can describe error from our error code structure, because later, - //when YAMN calls our function, it passes us our error code. This is pointer to structure for POP3 protocol in fact. - PPOP3_ERRORCODE ErrorCode; - - //We store status before we do Quit(), because quit can destroy our errorcode status - if (nullptr != (ErrorCode = new POP3_ERRORCODE)) { - ErrorCode->SSL = UseSSL; - ErrorCode->AppError = ActualAccount->SystemError; - ErrorCode->POP3Error = ActualAccount->Client.POP3Error; - ErrorCode->NetError = ActualAccount->Client.NetClient->NetworkError; - ErrorCode->SystemError = ActualAccount->Client.NetClient->SystemError; - } - - if (POP3PluginParam == (uint32_t)NULL) //if it was normal YAMN call (force check or so on) - { - try { - DataRX = ActualAccount->Client.Quit(); - if (DataRX != nullptr) - free(DataRX); - } - catch (...) { - } - //We always close connection if error occured - try { - ActualAccount->Client.NetClient->Disconnect(); - } - catch (...) { - } - - SetAccountStatus(ActualAccount, TranslateT("Disconnected")); - - //If we cannot allocate memory, do nothing - if (ErrorCode == nullptr) { - SetEvent(ActualAccount->UseInternetFree); - return; - } - } - else // else it was called from POP3 plugin, probably error when deleting old mail (POP3 synchro calls POP3 delete) - if (ErrorCode == nullptr) - return; - - if ((ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG) || (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) || (ActualAccount->BadConnectN.Flags & YAMN_ACC_POP)) - RunBadConnection(ActualAccount, (UINT_PTR)ErrorCode, ParamToBadConnection); - - if (POP3PluginParam == (uint32_t)NULL) //if it was normal YAMN call - SetEvent(ActualAccount->UseInternetFree); -} - -//Checks POP3 account and synchronizes it -DWORD WINAPI SynchroPOP3(struct CheckParam *WhichTemp) -{ - HPOP3ACCOUNT ActualAccount; - CPop3Client *MyClient; - HYAMNMAIL NewMails = nullptr, MsgQueuePtr = nullptr; - char *DataRX = nullptr, *Temp; - int mboxsize, msgs, i; - SYSTEMTIME now; - LPVOID YAMNParam; - uint32_t CheckFlags; - BOOL UsingInternet = FALSE; - struct - { - char *ServerName; - uint32_t ServerPort; - char *ServerLogin; - char *ServerPasswd; - uint32_t Flags; - uint32_t NFlags; - uint32_t NNFlags; - } ActualCopied; - - //First, we should compare our version of CheckParam structure, but here it is not needed, because YAMN and internal plugin - //have the same version. But your plugin should do that in this way: - // if (((struct CheckParam *)WhichTemp)->Ver != YAMN_CHECKVERSION) - // { - // SetEvent(((struct CheckParam *)WhichTemp)->ThreadRunningEV); //don't forget to unblock YAMN - // return (uint32_t)-1; //ok, but we should return value. - // //When our plugin returns e.g. 0xFFFFFFFF (=-1, this is only our plugin value, YAMN does nothing with return value, - // //but only tests if it is nonzero. If yes, it calls GetErrorStringFcn. We know problem occured in YAMN incompatibility - // //and then we can in our GetErrorStringFcn e.g. return string "Uncompatible version of YAMN". - // } - - ActualAccount = (HPOP3ACCOUNT)WhichTemp->AccountParam; //copy address of structure from calling thread to stack of this thread - YAMNParam = WhichTemp->BrowserParam; - CheckFlags = WhichTemp->Flags; - - SCInc(ActualAccount->UsingThreads); - //Unblock YAMN, signal that we have copied all parameters from YAMN thread stack - if (INVALID_HANDLE_VALUE != WhichTemp->ThreadRunningEV) - SetEvent(WhichTemp->ThreadRunningEV); - - if (WAIT_OBJECT_0 != WaitToRead(ActualAccount)) { - SCDec(ActualAccount->UsingThreads); - return 0; - } - - MyClient = &ActualAccount->Client; - //Now, copy all needed information about account to local variables, so ActualAccount is not blocked in read mode during all connection process, which can last for several minutes. - ActualCopied.ServerName = _strdup(ActualAccount->Server->Name); - ActualCopied.ServerPort = ActualAccount->Server->Port; - ActualCopied.Flags = ActualAccount->Flags; - ActualCopied.ServerLogin = _strdup(ActualAccount->Server->Login); - ActualCopied.ServerPasswd = _strdup(ActualAccount->Server->Passwd); - ActualCopied.NFlags = ActualAccount->NewMailN.Flags; - ActualCopied.NNFlags = ActualAccount->NoNewMailN.Flags; - - ReadDone(ActualAccount); - SCInc(ActualAccount->InternetQueries); //increment counter, that there is one more thread waiting for connection - - WaitForSingleObject(ActualAccount->UseInternetFree, INFINITE); //wait until we can use connection - SCDec(ActualAccount->InternetQueries); - - //OK, we enter the "use internet" section. But after we start communication, we can test if we did not enter the "use internet" section only for the reason, - //that previous thread release the internet section because this account has stop signal (we stop account and there are 2 threads: one communicating, - //the second one waiting for network access- the first one ends because we want to stop account, this one is released, but should be stopped as well). - if (!ActualAccount->AbleToWork) { - SetEvent(ActualAccount->UseInternetFree); - SCDec(ActualAccount->UsingThreads); - return 0; - } - UsingInternet = TRUE; - - GetLocalTime(&now); - ActualAccount->SystemError = 0; //now we can use internet for this socket. First, clear errorcode. - try { - SetContactStatus(ActualAccount, ID_STATUS_OCCUPIED); - - // if we are already connected, we have open session (another thread left us open session), so we don't need to login - // note that connected state without logging cannot occur, because if we close session, we always close socket too (we must close socket is the right word :)) - if ((MyClient->NetClient == nullptr) || !MyClient->NetClient->Connected()) { - SetAccountStatus(ActualAccount, TranslateT("Connecting to server")); - - DataRX = MyClient->Connect(ActualCopied.ServerName, ActualCopied.ServerPort, ActualCopied.Flags & YAMN_ACC_SSL23, ActualCopied.Flags & YAMN_ACC_NOTLS); - char *timestamp = nullptr; - - if (DataRX != nullptr) { - if (ActualCopied.Flags & YAMN_ACC_APOP) { - char *lpos = strchr(DataRX, '<'); - char *rpos = strchr(DataRX, '>'); - if (lpos && rpos && rpos > lpos) { - int sz = (int)(rpos - lpos + 2); - timestamp = new char[sz]; - memcpy(timestamp, lpos, sz - 1); - timestamp[sz - 1] = '\0'; - } - } - free(DataRX); - DataRX = nullptr; - } - - SetAccountStatus(ActualAccount, TranslateT("Entering POP3 account")); - - if (ActualCopied.Flags & YAMN_ACC_APOP) { - DataRX = MyClient->APOP(ActualCopied.ServerLogin, ActualCopied.ServerPasswd, timestamp); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - delete[] timestamp; - } - else { - DataRX = MyClient->User(ActualCopied.ServerLogin); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - DataRX = MyClient->Pass(ActualCopied.ServerPasswd); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - } - } - SetAccountStatus(ActualAccount, TranslateT("Searching for new mail message")); - - DataRX = MyClient->Stat(); - - ExtractStat(DataRX, &mboxsize, &msgs); - - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - for (i = 0; i < msgs; i++) { - if (!i) - MsgQueuePtr = NewMails = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION); - else { - MsgQueuePtr->Next = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION); - MsgQueuePtr = MsgQueuePtr->Next; - } - if (MsgQueuePtr == nullptr) { - ActualAccount->SystemError = EPOP3_QUEUEALLOC; - throw (uint32_t)ActualAccount->SystemError; - } - } - - if (msgs) { - DataRX = MyClient->List(); - ExtractList(DataRX, MyClient->NetClient->Rcv, NewMails); - if (DataRX != nullptr) - free(DataRX); - - DataRX = MyClient->Uidl(); - ExtractUIDL(DataRX, MyClient->NetClient->Rcv, NewMails); - - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - } - - if (WAIT_OBJECT_0 != MsgsWaitToWrite(ActualAccount)) - throw (uint32_t)(ActualAccount->SystemError = EACC_STOPPED); - - ActualAccount->LastChecked = now; - for (MsgQueuePtr = (HYAMNMAIL)ActualAccount->Mails; MsgQueuePtr != nullptr; MsgQueuePtr = MsgQueuePtr->Next) { - if (MsgQueuePtr->Flags & YAMN_MSG_BODYREQUESTED) { - HYAMNMAIL NewMsgsPtr = nullptr; - for (NewMsgsPtr = (HYAMNMAIL)NewMails; NewMsgsPtr != nullptr; NewMsgsPtr = NewMsgsPtr->Next) { - if (!mir_strcmp(MsgQueuePtr->ID, NewMsgsPtr->ID)) { - wchar_t accstatus[512]; - mir_snwprintf(accstatus, TranslateT("Reading body %s"), NewMsgsPtr->ID); - SetAccountStatus(ActualAccount, accstatus); - DataRX = MyClient->Top(MsgQueuePtr->Number, 100); - if (DataRX != nullptr) { - Temp = DataRX; - while ((Temp < DataRX + MyClient->NetClient->Rcv) && (WS(Temp) || ENDLINE(Temp))) Temp++; - - if (OKLINE(DataRX)) - for (Temp = DataRX; (Temp < DataRX + MyClient->NetClient->Rcv) && (!ENDLINE(Temp)); Temp++); - while ((Temp < DataRX + MyClient->NetClient->Rcv) && ENDLINE(Temp)) Temp++; - } - else - continue; - //delete all the headers of the old mail MsgQueuePtr->MailData->TranslatedHeader - struct CMimeItem *TH = MsgQueuePtr->MailData->TranslatedHeader; - if (TH) for (; MsgQueuePtr->MailData->TranslatedHeader != nullptr;) { - TH = TH->Next; - if (MsgQueuePtr->MailData->TranslatedHeader->name != nullptr) - delete[] MsgQueuePtr->MailData->TranslatedHeader->name; - if (MsgQueuePtr->MailData->TranslatedHeader->value != nullptr) - delete[] MsgQueuePtr->MailData->TranslatedHeader->value; - delete MsgQueuePtr->MailData->TranslatedHeader; - MsgQueuePtr->MailData->TranslatedHeader = TH; - } - - TranslateHeader(Temp, MyClient->NetClient->Rcv - (Temp - DataRX), &MsgQueuePtr->MailData->TranslatedHeader); - - MsgQueuePtr->Flags |= YAMN_MSG_BODYRECEIVED; - - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - break; - } - } - } - } - - SynchroMessages(ActualAccount, (HYAMNMAIL *)&ActualAccount->Mails, nullptr, (HYAMNMAIL *)&NewMails, nullptr); //we get only new mails on server! - - MsgsWriteDone(ActualAccount); - for (MsgQueuePtr = (HYAMNMAIL)ActualAccount->Mails; MsgQueuePtr != nullptr; MsgQueuePtr = MsgQueuePtr->Next) { - if ((MsgQueuePtr->Flags & YAMN_MSG_BODYREQUESTED) && (MsgQueuePtr->Flags & YAMN_MSG_BODYRECEIVED)) { - MsgQueuePtr->Flags &= ~YAMN_MSG_BODYREQUESTED; - if (MsgQueuePtr->MsgWindow) - SendMessage(MsgQueuePtr->MsgWindow, WM_YAMN_CHANGECONTENT, 0, 0); - } - } - - for (msgs = 0, MsgQueuePtr = NewMails; MsgQueuePtr != nullptr; MsgQueuePtr = MsgQueuePtr->Next, msgs++); //get number of new mails - - try { - wchar_t accstatus[512]; - - for (i = 0, MsgQueuePtr = NewMails; MsgQueuePtr != nullptr; i++) { - BOOL autoretr = (ActualAccount->Flags & YAMN_ACC_BODY) != 0; - DataRX = MyClient->Top(MsgQueuePtr->Number, autoretr ? 100 : 0); - mir_snwprintf(accstatus, TranslateT("Reading new mail messages (%d%% done)"), 100 * i / msgs); - SetAccountStatus(ActualAccount, accstatus); - - if (DataRX != nullptr) { - Temp = DataRX; - while ((Temp < DataRX + MyClient->NetClient->Rcv) && (WS(Temp) || ENDLINE(Temp))) Temp++; - - if (OKLINE(DataRX)) - for (Temp = DataRX; (Temp < DataRX + MyClient->NetClient->Rcv) && (!ENDLINE(Temp)); Temp++); - while ((Temp < DataRX + MyClient->NetClient->Rcv) && ENDLINE(Temp)) Temp++; - } - else - continue; - - TranslateHeader(Temp, MyClient->NetClient->Rcv - (Temp - DataRX), &MsgQueuePtr->MailData->TranslatedHeader); - - - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</New mail>\n"); - #endif - MsgQueuePtr->Flags |= YAMN_MSG_NORMALNEW; - if (autoretr) MsgQueuePtr->Flags |= YAMN_MSG_BODYRECEIVED; - - //We are going to filter mail. Warning!- we must not be in read access neither write access to mails when calling this service - //This is done, because the "NewMails" queue is not synchronised. It is because it is new queue. Only this thread uses new queue yet, it is not - //connected to account mail queue. - // CallService(MS_YAMN_FILTERMAIL,(WPARAM)ActualAccount,(LPARAM)MsgQueuePtr); - FilterMailSvc((WPARAM)ActualAccount, (LPARAM)MsgQueuePtr); - - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - - //MsgQueuePtr->MailData->Body=MyClient->Retr(MsgQueuePtr->Number); - - MsgQueuePtr = MsgQueuePtr->Next; - - } - - if (WAIT_OBJECT_0 != MsgsWaitToWrite(ActualAccount)) - throw (uint32_t)ActualAccount->SystemError == EACC_STOPPED; - - if (ActualAccount->Mails == nullptr) - ActualAccount->Mails = NewMails; - else { - ActualAccount->LastMail = ActualAccount->LastChecked; - AppendQueue((HYAMNMAIL)ActualAccount->Mails, NewMails); - } - - MsgsWriteDone(ActualAccount); - - // we are going to delete mails having SPAM flag level3 and 4 (see m_mails.h) set - { - struct DeleteParam ParamToDeleteMails = {YAMN_DELETEVERSION, INVALID_HANDLE_VALUE, ActualAccount, YAMNParam, (void *)POP3_DELETEFROMCHECK}; - - // Delete mails from server. Here we should not be in write access for account's mails - DeleteMailsPOP3(&ParamToDeleteMails); - } - - // if there is no waiting thread for internet connection close it - // else leave connection open - if (0 == SCGetNumber(ActualAccount->InternetQueries)) { - DataRX = MyClient->Quit(); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - MyClient->NetClient->Disconnect(); - - SetAccountStatus(ActualAccount, TranslateT("Disconnected")); - } - - UsingInternet = FALSE; - SetEvent(ActualAccount->UseInternetFree); - - ActualAccount->LastSChecked = ActualAccount->LastChecked; - ActualAccount->LastSynchronised = ActualAccount->LastChecked; - } - catch (...) { - throw; //go to the main exception handling - } - - { - YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, ActualCopied.NFlags, ActualCopied.NNFlags, YAMNParam}; - - if (CheckFlags & YAMN_FORCECHECK) - Param.nnflags |= YAMN_ACC_POP; //if force check, show popup anyway and if mailbrowser was opened, do not close - Param.nnflags |= YAMN_ACC_MSGP; //do not close browser if already open - CallService(MS_YAMN_MAILBROWSER, (WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION); - } - SetContactStatus(ActualAccount, ActualAccount->isCounting ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE); - } - #ifdef DEBUG_COMM - catch (uint32_t ErrorCode) - #else - catch (uint32_t) - #endif - { - if (ActualAccount->Client.POP3Error == EPOP3_STOPPED) - ActualAccount->SystemError = EACC_STOPPED; - #ifdef DEBUG_COMM - DebugLog(CommFile, "ERROR: %x\n", ErrorCode); - #endif - if (WAIT_OBJECT_0 == MsgsWaitToWrite(ActualAccount)) { - ActualAccount->LastChecked = now; - MsgsWriteDone(ActualAccount); - } - - DeleteMIMEQueue(ActualAccount, NewMails); - - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - switch (ActualAccount->SystemError) { - case EACC_QUEUEALLOC: - case EACC_STOPPED: - ActualAccount->Client.NetClient->Disconnect(); - break; - default: - PostErrorProc(ActualAccount, YAMNParam, (uint32_t)NULL, MyClient->SSL); //it closes internet connection too - } - - if (UsingInternet) //if our thread still uses internet - SetEvent(ActualAccount->UseInternetFree); - - SetContactStatus(ActualAccount, ID_STATUS_NA); - } - free(ActualCopied.ServerName); - free(ActualCopied.ServerLogin); - free(ActualCopied.ServerPasswd); - #ifdef DEBUG_COMM - DebugLog(CommFile, "</--------Communication-------->\n"); - #endif - - // WriteAccounts(); - SCDec(ActualAccount->UsingThreads); - return 0; -} - -void __cdecl DeleteMailsPOP3(void *param) -{ - DeleteParam *WhichTemp = (DeleteParam *)param; - - CPop3Client *MyClient; - HYAMNMAIL DeleteMails, NewMails = nullptr, MsgQueuePtr = nullptr; - char *DataRX = nullptr; - int mboxsize = 0, msgs = 0, i; - BOOL UsingInternet = FALSE; - struct - { - char *ServerName; - uint32_t ServerPort; - char *ServerLogin; - char *ServerPasswd; - uint32_t Flags; - uint32_t NFlags; - uint32_t NNFlags; - } ActualCopied; - - //First, we should compare our version of DeleteParam structure, but here it is not needed, because YAMN and internal plugin - //have the same version. But your plugin should do that in this way: - // if (((struct DeleteParam *)WhichTemp)->Ver != YAMN_DELETEVERSION) - // { - // SetEvent(((struct DeleteParam *)WhichTemp)->ThreadRunningEV); //don't forget to unblock YAMN - // return (uint32_t)-1; //ok, but we should return value. - // //When our plugin returns e.g. 0xFFFFFFFF (this is only our plugin value, YAMN does nothing with return value, - // //but only tests if it is nonzero. If yes, it calls GetErrorStringFcn), we know problem occured in YAMN incompatibility - // //and then we can in our GetErrorStringFcn e.g. return string "Uncompatible version of YAMN". - // } - - HPOP3ACCOUNT ActualAccount = (HPOP3ACCOUNT)WhichTemp->AccountParam; //copy address of structure from calling thread to stack of this thread - LPVOID YAMNParam = WhichTemp->BrowserParam; - UINT_PTR POP3PluginParam = (UINT_PTR)((struct DeleteParam *)WhichTemp)->CustomParam; - - SCInc(ActualAccount->UsingThreads); - if (INVALID_HANDLE_VALUE != WhichTemp->ThreadRunningEV) - SetEvent(WhichTemp->ThreadRunningEV); - - if (WAIT_OBJECT_0 != WaitToRead(ActualAccount)) { - SCDec(ActualAccount->UsingThreads); - return; - } - - if (nullptr == (DeleteMails = (HYAMNMAIL)CreateNewDeleteQueue((HYAMNMAIL)ActualAccount->Mails))) //if there's no mail for deleting, return - { - if (POP3_DELETEFROMCHECK != POP3PluginParam) //We do not wait for free internet when calling from SynchroPOP3. It is because UseInternetFree is blocked - { - YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, YAMN_ACC_MSGP, YAMN_ACC_MSGP, YAMNParam}; //Just update the window - CallService(MS_YAMN_MAILBROWSER, (WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION); - } - - SCDec(ActualAccount->UsingThreads); - return; - } - - MyClient = &(ActualAccount->Client); - - //Now, copy all needed information about account to local variables, so ActualAccount is not blocked in read mode during all connection process, which can last for several minutes. - ActualCopied.ServerName = _strdup(ActualAccount->Server->Name); - ActualCopied.ServerPort = ActualAccount->Server->Port; - ActualCopied.Flags = ActualAccount->Flags; - ActualCopied.ServerLogin = _strdup(ActualAccount->Server->Login); - ActualCopied.ServerPasswd = _strdup(ActualAccount->Server->Passwd); - ActualCopied.NFlags = ActualAccount->NewMailN.Flags; - ActualCopied.NNFlags = ActualAccount->NoNewMailN.Flags; - - ReadDone(ActualAccount); - - SCInc(ActualAccount->InternetQueries); //This is POP3-internal SCOUNTER, we set another thread wait for this account to be connected to inet - if (POP3_DELETEFROMCHECK != POP3PluginParam) //We do not wait for free internet when calling from SynchroPOP3. It is because UseInternetFree is blocked - WaitForSingleObject(ActualAccount->UseInternetFree, INFINITE); - - SCDec(ActualAccount->InternetQueries); - UsingInternet = TRUE; - - try { - SetContactStatus(ActualAccount, ID_STATUS_OCCUPIED); - #ifdef DEBUG_COMM - DebugLog(CommFile, "<--------Communication-------->\n"); - #endif - if ((MyClient->NetClient == nullptr) || !MyClient->NetClient->Connected()) { - SetAccountStatus(ActualAccount, TranslateT("Connecting to server")); - - DataRX = MyClient->Connect(ActualCopied.ServerName, ActualCopied.ServerPort, ActualCopied.Flags & YAMN_ACC_SSL23, ActualCopied.Flags & YAMN_ACC_NOTLS); - - char *timestamp = nullptr; - if (DataRX != nullptr) { - if (ActualAccount->Flags & YAMN_ACC_APOP) { - char *lpos = strchr(DataRX, '<'); - char *rpos = strchr(DataRX, '>'); - if (lpos && rpos && rpos > lpos) { - int sz = (int)(rpos - lpos + 2); - timestamp = new char[sz]; - memcpy(timestamp, lpos, sz - 1); - timestamp[sz - 1] = '\0'; - } - } - free(DataRX); - DataRX = nullptr; - } - SetAccountStatus(ActualAccount, TranslateT("Entering POP3 account")); - - if (ActualAccount->Flags & YAMN_ACC_APOP) { - DataRX = MyClient->APOP(ActualCopied.ServerLogin, ActualCopied.ServerPasswd, timestamp); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - delete[] timestamp; - } - else { - DataRX = MyClient->User(ActualCopied.ServerLogin); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - DataRX = MyClient->Pass(ActualCopied.ServerPasswd); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - } - } - - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<--------Deleting requested mails-------->\n"); - #endif - if (POP3_DELETEFROMCHECK != POP3PluginParam) //We do not need to get mails on server as we have already it from check function - { - SetAccountStatus(ActualAccount, TranslateT("Deleting requested mails")); - - DataRX = MyClient->Stat(); - - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting stat>\n"); - #endif - ExtractStat(DataRX, &mboxsize, &msgs); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<MailBoxSize>%d</MailBoxSize>\n", mboxsize); - DebugLog(DecodeFile, "<Msgs>%d</Msgs>\n", msgs); - DebugLog(DecodeFile, "</Extracting stat>\n"); - #endif - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - for (i = 0; i < msgs; i++) { - if (!i) - MsgQueuePtr = NewMails = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION); - else { - MsgQueuePtr->Next = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION); - MsgQueuePtr = MsgQueuePtr->Next; - } - if (MsgQueuePtr == nullptr) { - ActualAccount->SystemError = EPOP3_QUEUEALLOC; - throw (uint32_t)ActualAccount->SystemError; - } - } - - if (msgs) { - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Extracting UIDL>\n"); - #endif - DataRX = MyClient->Uidl(); - ExtractUIDL(DataRX, MyClient->NetClient->Rcv, NewMails); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</Extracting UIDL>\n"); - #endif - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - // we get "new mails" on server (NewMails will contain all mails on server not found in DeleteMails) - // but also in DeleteMails we get only those, which are still on server with their responsable numbers - SynchroMessages(ActualAccount, (HYAMNMAIL *)&DeleteMails, nullptr, (HYAMNMAIL *)&NewMails, nullptr); - } - } - else SetAccountStatus(ActualAccount, TranslateT("Deleting spam")); - - if (WAIT_OBJECT_0 != MsgsWaitToWrite(ActualAccount)) - throw (uint32_t)EACC_STOPPED; - - if (msgs || POP3_DELETEFROMCHECK == POP3PluginParam) { - try { - HYAMNMAIL Temp; - - for (i = 0, MsgQueuePtr = DeleteMails; MsgQueuePtr != nullptr; i++) { - if (!(MsgQueuePtr->Flags & YAMN_MSG_VIRTUAL)) //of course we can only delete real mails, not virtual - { - DataRX = MyClient->Dele(MsgQueuePtr->Number); - Temp = MsgQueuePtr->Next; - if (POP3_FOK == MyClient->AckFlag) //if server answers that mail was deleted - { - DeleteMIMEMessage((HYAMNMAIL *)&DeleteMails, MsgQueuePtr); - HYAMNMAIL DeletedMail = FindMIMEMessageByID((HYAMNMAIL)ActualAccount->Mails, MsgQueuePtr->ID); - if ((MsgQueuePtr->Flags & YAMN_MSG_MEMDELETE)) //if mail should be deleted from memory (or disk) - { - DeleteMIMEMessage((HYAMNMAIL *)&ActualAccount->Mails, DeletedMail); //remove from queue - CallService(MS_YAMN_DELETEACCOUNTMAIL, (WPARAM)POP3Plugin, (LPARAM)DeletedMail); - } - else //else mark it only as "deleted mail" - { - DeletedMail->Flags |= (YAMN_MSG_VIRTUAL | YAMN_MSG_DELETED); - DeletedMail->Flags &= ~(YAMN_MSG_NEW | YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE); //clear "new mail" - } - delete MsgQueuePtr->MailData; - delete[] MsgQueuePtr->ID; - delete MsgQueuePtr; - } - MsgQueuePtr = Temp; - - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - } - else - MsgQueuePtr = MsgQueuePtr->Next; - } - } - catch (...) //if any exception in the code where we have write-access to account occured, don't forget to leave write-access - { - MsgsWriteDone(ActualAccount); - throw; //and go to the main exception handling - } - - if (NewMails != nullptr) - // in ActualAccount->Mails we have all mails stored before calling this function - // in NewMails we have all mails not found in DeleteMails (in other words: we performed new ID checking and we - // stored all mails found on server, then we deleted the ones we wanted to delete in this function - // and NewMails queue now contains actual state of mails on server). But we will not use NewMails as actual state, because NewMails does not contain header data (subject, from...) - // We perform deleting from ActualAccount->Mails: we remove from original queue (ActualAccount->Mails) all deleted mails - SynchroMessages(ActualAccount, (HYAMNMAIL *)&ActualAccount->Mails, nullptr, (HYAMNMAIL *)&NewMails, nullptr); - // Now ActualAccount->Mails contains all mails when calling this function except the ones, we wanted to delete (these are in DeleteMails) - // And in NewMails we have new mails (if any) - else if (POP3_DELETEFROMCHECK != POP3PluginParam) { - DeleteMIMEQueue(ActualAccount, (HYAMNMAIL)ActualAccount->Mails); - ActualAccount->Mails = nullptr; - } - } - else { - DeleteMIMEQueue(ActualAccount, (HYAMNMAIL)ActualAccount->Mails); - ActualAccount->Mails = nullptr; - } - - MsgsWriteDone(ActualAccount); - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "</--------Deleting requested mails-------->\n"); - #endif - - // TODO: now, we have in NewMails new mails. If NewMails is not NULL, we found some new mails, so Checking for new mail should be performed - // now, we do not call CheckPOP3 - - // if there is no waiting thread for internet connection close it - // else leave connection open - // if this functin was called from SynchroPOP3, then do not try to disconnect - if (POP3_DELETEFROMCHECK != POP3PluginParam) { - YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, ActualCopied.NFlags, YAMN_ACC_MSGP, YAMNParam}; - - CallService(MS_YAMN_MAILBROWSER, (WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION); - - if (0 == SCGetNumber(ActualAccount->InternetQueries)) { - DataRX = MyClient->Quit(); - if (DataRX != nullptr) - free(DataRX); - DataRX = nullptr; - MyClient->NetClient->Disconnect(); - - SetAccountStatus(ActualAccount, TranslateT("Disconnected")); - } - - UsingInternet = FALSE; - SetEvent(ActualAccount->UseInternetFree); - } - SetContactStatus(ActualAccount, ActualAccount->isCounting ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE); - } - #ifdef DEBUG_COMM - catch (uint32_t ErrorCode) - #else - catch (uint32_t) - #endif - { - if (ActualAccount->Client.POP3Error == EPOP3_STOPPED) - ActualAccount->SystemError = EACC_STOPPED; - #ifdef DEBUG_COMM - DebugLog(CommFile, "ERROR %x\n", ErrorCode); - #endif - if (DataRX != nullptr) - free(DataRX); - switch (ActualAccount->SystemError) { - case EACC_QUEUEALLOC: - case EACC_STOPPED: - ActualAccount->Client.NetClient->Disconnect(); - break; - default: - PostErrorProc(ActualAccount, YAMNParam, POP3PluginParam, MyClient->SSL); //it closes internet connection too - } - - if (UsingInternet && (POP3_DELETEFROMCHECK != POP3PluginParam)) //if our thread still uses internet and it is needed to release internet - SetEvent(ActualAccount->UseInternetFree); - } - - free(ActualCopied.ServerName); - free(ActualCopied.ServerLogin); - free(ActualCopied.ServerPasswd); - - DeleteMIMEQueue(ActualAccount, NewMails); - DeleteMIMEQueue(ActualAccount, DeleteMails); - - #ifdef DEBUG_COMM - DebugLog(CommFile, "</--------Communication-------->\n"); - #endif - - // WriteAccounts(); - SCDec(ActualAccount->UsingThreads); - return; -} - -void ExtractStat(char *stream, int *mboxsize, int *mails) -{ - char *finder = stream; - while (WS(finder) || ENDLINE(finder)) finder++; - if (ACKLINE(finder)) { - while (!WS(finder)) finder++; - while (WS(finder)) finder++; - } - if (1 != sscanf(finder, "%d", mails)) - throw (uint32_t)EPOP3_STAT; - while (!WS(finder)) finder++; - while (WS(finder)) finder++; - if (1 != sscanf(finder, "%d", mboxsize)) - throw (uint32_t)EPOP3_STAT; -} -void ExtractMail(char *stream, int len, HYAMNMAIL queue) -{ - char *finder = stream; - char *finderend; - int msgnr, i; - HYAMNMAIL queueptr = queue; - - while (WS(finder) || ENDLINE(finder)) finder++; - while (!ACKLINE(finder)) finder++; - while (!ENDLINE(finder)) finder++; //now we at the end of first ack line - while (finder <= (stream + len)) { - while (ENDLINE(finder)) finder++; //go to the new line - if (DOTLINE(finder + 1)) //at the end of stream - break; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Message>\n"); - #endif - while (WS(finder)) finder++; //jump whitespace - if (1 != sscanf(finder, "%d", &msgnr)) - throw (uint32_t)EPOP3_UIDL; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Nr>%d</Nr>\n", msgnr); - #endif - // for (i=1,queueptr=queue;(queueptr->Next != NULL) && (i<msgnr);queueptr=queueptr->Next,i++); - // if (i != msgnr) - // throw (uint32_t)EPOP3_UIDL; - while (!WS(finder)) finder++; //jump characters - while (WS(finder)) finder++; //jump whitespace - finderend = finder + 1; - while (!WS(finderend) && !ENDLINE(finderend)) finderend++; - queueptr->ID = new char[finderend - finder + 1]; - for (i = 0; finder != finderend; finder++, i++) - queueptr->MailData->Body[i] = *finder; - queueptr->MailData->Body[i] = 0; //ends string - queueptr->Number = msgnr; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<ID>%s</ID>\n", queueptr->MailData->Body); - DebugLog(DecodeFile, "</Message>\n"); - #endif - queueptr = queueptr->Next; - while (!ENDLINE(finder)) finder++; - } -} - -void ExtractUIDL(char *stream, int len, HYAMNMAIL queue) -{ - char *finder = stream; - char *finderend; - int msgnr, i; - HYAMNMAIL queueptr = queue; - - while (WS(finder) || ENDLINE(finder)) finder++; - while (!ACKLINE(finder)) finder++; - while (!ENDLINE(finder)) finder++; //now we at the end of first ack line - while (finder <= (stream + len)) { - while (ENDLINE(finder)) finder++; //go to the new line - if (DOTLINE(finder + 1)) //at the end of stream - break; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Message>\n"); - #endif - while (WS(finder)) finder++; //jump whitespace - if (1 != sscanf(finder, "%d", &msgnr)) - throw (uint32_t)EPOP3_UIDL; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Nr>%d</Nr>\n", msgnr); - #endif - // for (i=1,queueptr=queue;(queueptr->Next != NULL) && (i<msgnr);queueptr=queueptr->Next,i++); - // if (i != msgnr) - // throw (uint32_t)EPOP3_UIDL; - while (!WS(finder)) finder++; //jump characters - while (WS(finder)) finder++; //jump whitespace - finderend = finder + 1; - while (!WS(finderend) && !ENDLINE(finderend)) finderend++; - queueptr->ID = new char[finderend - finder + 1]; - for (i = 0; finder != finderend; finder++, i++) - queueptr->ID[i] = *finder; - queueptr->ID[i] = 0; //ends string - queueptr->Number = msgnr; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<ID>%s</ID>\n", queueptr->ID); - DebugLog(DecodeFile, "</Message>\n"); - #endif - queueptr = queueptr->Next; - while (!ENDLINE(finder)) finder++; - } -} - -void ExtractList(char *stream, int len, HYAMNMAIL queue) -{ - char *finder = stream; - char *finderend; - int msgnr, i; - HYAMNMAIL queueptr; - - while (WS(finder) || ENDLINE(finder)) finder++; - while (!ACKLINE(finder)) finder++; - while (!ENDLINE(finder)) finder++; //now we at the end of first ack line - while (finder <= (stream + len)) { - while (ENDLINE(finder)) finder++; //go to the new line - if (DOTLINE(finder + 1)) //at the end of stream - break; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Message>\n", NULL, 0); - #endif - while (WS(finder)) finder++; //jump whitespace - if (1 != sscanf(finder, "%d", &msgnr)) //message nr. - throw (uint32_t)EPOP3_LIST; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Nr>%d</Nr>\n", msgnr); - #endif - - for (i = 1, queueptr = queue; (queueptr->Next != nullptr) && (i < msgnr); queueptr = queueptr->Next, i++); - if (i != msgnr) - throw (uint32_t)EPOP3_LIST; - while (!WS(finder)) finder++; //jump characters - while (WS(finder)) finder++; //jump whitespace - finderend = finder + 1; - if (1 != sscanf(finder, "%u", &queueptr->MailData->Size)) - throw (uint32_t)EPOP3_LIST; - #ifdef DEBUG_DECODE - DebugLog(DecodeFile, "<Nr>%d</Nr>\n", queueptr->MailData->Size); - #endif - while (!ENDLINE(finder)) finder++; - } -} - -wchar_t *WINAPI GetErrorString(DWORD Code) -{ - static wchar_t *POP3Errors[] = - { - LPGENW("Memory allocation error."), //memory allocation - LPGENW("Account is about to be stopped."), //stop account - LPGENW("Cannot connect to POP3 server."), - LPGENW("Cannot allocate memory for received data."), - LPGENW("Cannot login to POP3 server."), - LPGENW("Bad user or password."), - LPGENW("Server does not support APOP authorization."), - LPGENW("Error while executing POP3 command."), - LPGENW("Error while executing POP3 command."), - LPGENW("Error while executing POP3 command."), - }; - - static wchar_t *NetlibErrors[] = - { - LPGENW("Cannot connect to server with NetLib."), - LPGENW("Cannot send data."), - LPGENW("Cannot receive data."), - LPGENW("Cannot allocate memory for received data."), - }; - - static wchar_t *SSLErrors[] = - { - LPGENW("OpenSSL not loaded."), - LPGENW("Windows socket 2.0 init failed."), - LPGENW("DNS lookup error."), - LPGENW("Error while creating base socket."), - LPGENW("Error connecting to server with socket."), - LPGENW("Error while creating SSL structure."), - LPGENW("Error connecting socket with SSL."), - LPGENW("Server rejected connection with SSL."), - LPGENW("Cannot write SSL data."), - LPGENW("Cannot read SSL data."), - LPGENW("Cannot allocate memory for received data."), - }; - - wchar_t *ErrorString = new wchar_t[ERRORSTR_MAXLEN]; - POP3_ERRORCODE *ErrorCode = (POP3_ERRORCODE *)(UINT_PTR)Code; - - mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, TranslateT("Error %d-%d-%d-%d:"), ErrorCode->AppError, ErrorCode->POP3Error, ErrorCode->NetError, ErrorCode->SystemError); - if (ErrorCode->POP3Error) - mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(POP3Errors[ErrorCode->POP3Error - 1])); - if (ErrorCode->NetError) { - if (ErrorCode->SSL) - mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(SSLErrors[ErrorCode->NetError - 1])); - else - mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(NetlibErrors[ErrorCode->NetError - 4])); - } - - return ErrorString; -} - -void WINAPI DeleteErrorString(LPVOID String) -{ - delete (char *)String; -} +/*
+ * This code implements POP3 server checking for new mail and so on.
+ * There's function SynchroPOP3 in this file- for checking and synchronising POP3 account
+ * and DeleteMailsPOP3- for deleting mails from POP3 server
+ *
+ * Note this file acts as main file for internal plugin.
+ *
+ * (c) majvan 2002-2004
+ * 18/08
+ */
+
+
+#include "../../stdafx.h"
+
+#define ERRORSTR_MAXLEN 1024 //in wide-chars
+
+ //--------------------------------------------------------------------------------------------------
+
+HANDLE hNetLib = nullptr;
+PSCOUNTER CPOP3Account::AccountWriterSO = nullptr;
+
+//Creates new CPOP3Account structure
+CAccount *WINAPI CreatePOP3Account(HYAMNPROTOPLUGIN Plugin, DWORD CAccountVersion);
+
+//Deletes CPOP3Account structure
+void WINAPI DeletePOP3Account(CAccount *Which);
+
+//Sets stop flag to account
+void WINAPI StopPOP3Account(CAccount *Which);
+
+//Function registers standard functions for YAMN
+int RegisterPOP3Plugin(WPARAM, LPARAM);
+
+//Unloads all variables created on heap (delete[])
+DWORD WINAPI UnLoadPOP3(void *);
+
+//Function writes POP3 accounts using YAMN exported functions
+DWORD WINAPI WritePOP3Accounts();
+
+//Function stores plugin's data for account to file
+DWORD WINAPI WritePOP3Options(HANDLE, CAccount *);
+
+//Function reads plugin's data for account from file
+DWORD WINAPI ReadPOP3Options(CAccount *, char **, char *);
+
+//Creates new mail for an account
+HYAMNMAIL WINAPI CreatePOP3Mail(CAccount *Account, DWORD CMimeMailVersion);
+
+//Function does all needed work when connection failed or any error occured
+//Creates structure containing error code, closes internet session, runs "bad connect" function
+static void PostErrorProc(HPOP3ACCOUNT ActualAccount, void *ParamToBadConnect, uint32_t POP3PluginParam, BOOL UseSSL);
+
+//Checks POP3 account and stores all info to account. It deletes old mails=> synchro
+// WhichTemp- pointer to strucure containing needed information
+DWORD WINAPI SynchroPOP3(struct CheckParam *WhichTemp);
+
+//Deletes mails from POP3 server
+// WhichTemp- structure containing needed information (queued messages to delete)
+//Function deletes from memory queue in WhichTemp structure
+void __cdecl DeleteMailsPOP3(void *param);
+
+//Function makes readable message about error. It sends it back to YAMN, so YAMN then
+//can show it to the message window
+wchar_t *WINAPI GetErrorString(DWORD Code);
+
+//Function deletes string allocated in GetErrorString
+void WINAPI DeleteErrorString(LPVOID String);
+
+//Extracts info from result of POP3's STAT command
+// stream- source string
+// len- length of source string
+// mboxsize- adreess to integer, that receives size of mailbox
+// mails- adreess to integer, that receives number of mails
+void ExtractStat(char *stream, int *mboxsize, int *mails);
+
+//Extracts mail ID on mailbox
+// stream- source string
+// len- length of source string
+// queue- address of first message, where first ID will be stored
+void ExtractUIDL(char *stream, int len, HYAMNMAIL queue);
+
+//Extracts mail size on mailbox
+// stream- source string
+// len- length of source string
+// queue- address of first message, where size of message #1 will be stored
+void ExtractList(char *stream, int len, HYAMNMAIL queue);
+
+void ExtractMail(char *stream, int len, HYAMNMAIL queue);
+
+YAMNExportedFcns *pYAMNFcn = nullptr;
+MailExportedFcns *pYAMNMailFcn = nullptr;
+
+YAMN_PROTOIMPORTFCN POP3ProtocolFunctions =
+{
+ CreatePOP3Account,
+ DeletePOP3Account,
+ StopPOP3Account,
+ WritePOP3Options,
+ ReadPOP3Options,
+ SynchroPOP3,
+ SynchroPOP3,
+ SynchroPOP3,
+ DeleteMailsPOP3,
+ GetErrorString,
+ nullptr,
+ DeleteErrorString,
+ WritePOP3Accounts,
+ nullptr,
+ UnLoadPOP3,
+};
+
+YAMN_MAILIMPORTFCN POP3MailFunctions =
+{
+ CreatePOP3Mail,
+ nullptr,
+ nullptr,
+ nullptr,
+};
+
+PYAMN_VARIABLES pYAMNVar = nullptr;
+HYAMNPROTOPLUGIN POP3Plugin = nullptr;
+
+YAMN_PROTOREGISTRATION POP3ProtocolRegistration =
+{
+ "POP3 protocol (internal)",
+ __VERSION_STRING_DOTS,
+ __COPYRIGHT,
+ __DESCRIPTION,
+ __AUTHORWEB,
+};
+
+static wchar_t *FileName = nullptr;
+
+HANDLE RegisterNLClient(char *name);
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+CPOP3Account::CPOP3Account()
+{
+ //NOTE! This constructor constructs CAccount structure. If your plugin is not internal,
+ //you will need these constructors. All you need is in Account.cpp. Just copy to your source code
+ //constructor and destructor of CAccount.
+ UseInternetFree = CreateEvent(nullptr, FALSE, TRUE, nullptr);
+ InternetQueries = new SCOUNTER;
+ AbilityFlags = YAMN_ACC_BROWSE | YAMN_ACC_POPUP;
+
+ SetAccountStatus((CAccount *)this, TranslateT("Disconnected"));
+}
+
+CPOP3Account::~CPOP3Account()
+{
+ CloseHandle(UseInternetFree);
+ if (InternetQueries != nullptr)
+ delete InternetQueries;
+}
+
+CAccount *WINAPI CreatePOP3Account(HYAMNPROTOPLUGIN, DWORD)
+{
+ //First, we should check whether CAccountVersion matches.
+ //But this is internal plugin, so YAMN's CAccount structure and our CAccount structure are
+ //the same, so we do not need to test version. Otherwise, if CAccount version does not match
+ //in your plugin, you should return NULL, like this:
+ // if (CAccountVersion != YAMN_ACCOUNTVERSION) return NULL;
+
+ //Now it is needed to construct our POP3 account and return its handle
+ return (CAccount *)new struct CPOP3Account();
+}
+
+void WINAPI DeletePOP3Account(CAccount *Which)
+{
+ delete (HPOP3ACCOUNT)Which;
+}
+
+void WINAPI StopPOP3Account(CAccount *Which)
+{
+ ((HPOP3ACCOUNT)Which)->Client.Stopped = TRUE;
+ if (((HPOP3ACCOUNT)Which)->Client.NetClient != nullptr) //we should inform also network client. Usefull only when network client implements this feature
+ ((HPOP3ACCOUNT)Which)->Client.NetClient->Stopped = TRUE;
+}
+
+//This function is like main function for POP3 internal protocol
+int RegisterPOP3Plugin(WPARAM, LPARAM)
+{
+ // Get YAMN variables we can use
+ if (nullptr == (pYAMNVar = (PYAMN_VARIABLES)CallService(MS_YAMN_GETVARIABLES, YAMN_VARIABLESVERSION, 0)))
+ return 0;
+
+ // We have to get pointers to YAMN exported functions: allocate structure and fill it
+ if (nullptr == (pYAMNFcn = new struct YAMNExportedFcns)) {
+LBL_Error:
+ UnLoadPOP3(nullptr);
+ return 0;
+ }
+
+ // Register new pop3 user in netlib
+ if (nullptr == (hNetLib = RegisterNLClient("YAMN (POP3)")))
+ goto LBL_Error;
+
+ pYAMNFcn->SetProtocolPluginFcnImportFcn = (YAMN_SETPROTOCOLPLUGINFCNIMPORTFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SETPROTOCOLPLUGINFCNIMPORTID, 0);
+ pYAMNFcn->WaitToWriteFcn = (YAMN_WAITTOWRITEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WAITTOWRITEID, 0);
+ pYAMNFcn->WriteDoneFcn = (YAMN_WRITEDONEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WRITEDONEID, 0);
+ pYAMNFcn->WaitToReadFcn = (YAMN_WAITTOREADFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_WAITTOREADID, 0);
+ pYAMNFcn->ReadDoneFcn = (YAMN_READDONEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_READDONEID, 0);
+ pYAMNFcn->SCGetNumberFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCGETNUMBERID, 0);
+ pYAMNFcn->SCIncFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCINCID, 0);
+ pYAMNFcn->SCDecFcn = (YAMN_SCMANAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SCDECID, 0);
+ pYAMNFcn->SetStatusFcn = (YAMN_SETSTATUSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SETSTATUSID, 0);
+ pYAMNFcn->GetStatusFcn = (YAMN_GETSTATUSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_GETSTATUSID, 0);
+
+ if (nullptr == (pYAMNMailFcn = new struct MailExportedFcns))
+ goto LBL_Error;
+
+ pYAMNMailFcn->SynchroMessagesFcn = (YAMN_SYNCHROMIMEMSGSFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_SYNCHROMIMEMSGSID, 0);
+ pYAMNMailFcn->TranslateHeaderFcn = (YAMN_TRANSLATEHEADERFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_TRANSLATEHEADERID, 0);
+ pYAMNMailFcn->AppendQueueFcn = (YAMN_APPENDQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_APPENDQUEUEID, 0);
+ pYAMNMailFcn->DeleteMessagesToEndFcn = (YAMN_DELETEMIMEQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_DELETEMIMEQUEUEID, 0);
+ pYAMNMailFcn->DeleteMessageFromQueueFcn = (YAMN_DELETEMIMEMESSAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_DELETEMIMEMESSAGEID, 0);
+ pYAMNMailFcn->FindMessageByIDFcn = (YAMN_FINDMIMEMESSAGEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_FINDMIMEMESSAGEID, 0);
+ pYAMNMailFcn->CreateNewDeleteQueueFcn = (YAMN_CREATENEWDELETEQUEUEFCN)CallService(MS_YAMN_GETFCNPTR, (WPARAM)YAMN_CREATENEWDELETEQUEUEID, 0);
+
+ //set static variable
+ if (CPOP3Account::AccountWriterSO == nullptr)
+ if (nullptr == (CPOP3Account::AccountWriterSO = new SCOUNTER))
+ goto LBL_Error;
+
+ //First, we register this plugin
+ //it is quite impossible this function returns zero (failure) as YAMN and internal plugin structre versions are the same
+ POP3ProtocolRegistration.Name = Translate("POP3 protocol (internal)");
+ POP3ProtocolRegistration.Description = Translate(__DESCRIPTION);
+ if (nullptr == (POP3Plugin = (HYAMNPROTOPLUGIN)CallService(MS_YAMN_REGISTERPROTOPLUGIN, (WPARAM)&POP3ProtocolRegistration, (LPARAM)YAMN_PROTOREGISTRATIONVERSION)))
+ return 0;
+
+ //Next we set our imported functions for YAMN
+ if (!SetProtocolPluginFcnImport(POP3Plugin, &POP3ProtocolFunctions, YAMN_PROTOIMPORTFCNVERSION, &POP3MailFunctions, YAMN_MAILIMPORTFCNVERSION))
+ return 0;
+
+ //Then, we read all mails for accounts.
+ //You must first register account, before using this function as YAMN must use CreatePOP3Account function to add new accounts
+ //But if CreatePOP3Account is not implemented (equals to NULL), YAMN creates account as YAMN's standard CAccount *
+ if (FileName) CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); //shoud not happen (only for secure)
+ FileName = (wchar_t *)CallService(MS_YAMN_GETFILENAME, (WPARAM)L"pop3", 0);
+
+ switch (CallService(MS_YAMN_READACCOUNTS, (WPARAM)POP3Plugin, (LPARAM)FileName)) {
+ case EACC_FILEVERSION:
+ MessageBox(nullptr, TranslateT("Found new version of account book, not compatible with this version of YAMN."), TranslateT("YAMN (internal POP3) read error"), MB_OK);
+ CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0);
+ FileName = nullptr;
+ return 0;
+ case EACC_FILECOMPATIBILITY:
+ MessageBox(nullptr, TranslateT("Error reading account file. Account file corrupted."), TranslateT("YAMN (internal POP3) read error"), MB_OK);
+ CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0);
+ FileName = nullptr;
+ return 0;
+ case EACC_ALLOC:
+ MessageBox(nullptr, TranslateT("Memory allocation error while data reading"), TranslateT("YAMN (internal POP3) read error"), MB_OK);
+ CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0);
+ FileName = nullptr;
+ return 0;
+ case EACC_SYSTEM:
+ if (ERROR_FILE_NOT_FOUND != GetLastError()) {
+ wchar_t temp[1024] = {0};
+ mir_snwprintf(temp, L"%s\n%s", TranslateT("Reading file error. File already in use?"), FileName);
+ MessageBox(nullptr, temp, TranslateT("YAMN (internal POP3) read error"), MB_OK);
+ CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0);
+ FileName = nullptr;
+ return 0;
+ }
+ break;
+ }
+
+ for (CAccount *Finder = POP3Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) {
+ Finder->hContact = NULL;
+ for (auto &hContact : Contacts(YAMN_DBMODULE)) {
+ DBVARIANT dbv;
+ if (!g_plugin.getString(hContact, "Id", &dbv)) {
+ if (mir_strcmp(dbv.pszVal, Finder->Name) == 0) {
+ Finder->hContact = hContact;
+ g_plugin.setWord(Finder->hContact, "Status", ID_STATUS_ONLINE);
+ db_set_s(Finder->hContact, "CList", "StatusMsg", Translate("No new mail message"));
+ if ((Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT))
+ Contact::Hide(Finder->hContact, false);
+
+ if (!(Finder->Flags & YAMN_ACC_ENA) || !(Finder->NewMailN.Flags & YAMN_ACC_CONT))
+ Contact::Hide(Finder->hContact);
+ }
+ db_free(&dbv);
+ }
+ }
+
+ if (!Finder->hContact && (Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) {
+ // No account contact found, have to create one
+ Finder->hContact = db_add_contact();
+ Proto_AddToContact(Finder->hContact, YAMN_DBMODULE);
+ g_plugin.setString(Finder->hContact, "Id", Finder->Name);
+ g_plugin.setString(Finder->hContact, "Nick", Finder->Name);
+ g_plugin.setWord(Finder->hContact, "Status", ID_STATUS_OFFLINE);
+ }
+ }
+
+ return 0;
+}
+
+DWORD WINAPI UnLoadPOP3(void *)
+{
+ //pYAMNVar is only a pointr, no need delete or free
+ if (hNetLib) {
+ Netlib_CloseHandle(hNetLib); hNetLib = nullptr;
+ }
+ if (CPOP3Account::AccountWriterSO) {
+ delete CPOP3Account::AccountWriterSO; CPOP3Account::AccountWriterSO = nullptr;
+ }
+ if (pYAMNMailFcn) {
+ delete pYAMNMailFcn; pYAMNMailFcn = nullptr;
+ }
+ if (pYAMNFcn) {
+ delete pYAMNFcn; pYAMNFcn = nullptr;
+ }
+ if (FileName) {
+ CallService(MS_YAMN_DELETEFILENAME, (WPARAM)FileName, 0); FileName = nullptr;
+ }
+
+ return 1;
+}
+
+DWORD WINAPI WritePOP3Accounts()
+{
+ uint32_t ReturnValue = CallService(MS_YAMN_WRITEACCOUNTS, (WPARAM)POP3Plugin, (LPARAM)FileName);
+ if (ReturnValue == EACC_SYSTEM) {
+ wchar_t temp[1024] = {0};
+ mir_snwprintf(temp, L"%s\n%s", TranslateT("Error while copying data to disk occurred. Is file in use?"), FileName);
+ MessageBox(nullptr, temp, TranslateT("POP3 plugin - write file error"), MB_OK);
+ }
+
+ return ReturnValue;
+}
+
+DWORD WINAPI WritePOP3Options(HANDLE File, CAccount *Which)
+{
+ DWORD WrittenBytes;
+ uint32_t Ver = POP3_FILEVERSION;
+
+ if ((!WriteFile(File, (char *)&Ver, sizeof(uint32_t), &WrittenBytes, nullptr)) ||
+ (!WriteFile(File, (char *)&((HPOP3ACCOUNT)Which)->CP, sizeof(uint16_t), &WrittenBytes, nullptr)))
+ return EACC_SYSTEM;
+ return 0;
+}
+
+DWORD WINAPI ReadPOP3Options(CAccount *Which, char **Parser, char *End)
+{
+ uint32_t Ver;
+ #ifdef DEBUG_FILEREAD
+ wchar_t Debug[256];
+ #endif
+ Ver = *(uint32_t *)(*Parser);
+ (*Parser) += sizeof(uint32_t);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ if (Ver != POP3_FILEVERSION)
+ return EACC_FILECOMPATIBILITY;
+
+ ((HPOP3ACCOUNT)Which)->CP = *(uint16_t *)(*Parser);
+ (*Parser) += sizeof(uint16_t);
+ if (*Parser >= End)
+ return EACC_FILECOMPATIBILITY;
+ #ifdef DEBUG_FILEREAD
+ mir_snwprintf(Debug, L"CodePage: %d, remaining %d chars", ((HPOP3ACCOUNT)Which)->CP, End - *Parser);
+ MessageBox(NULL, Debug, L"debug", MB_OK);
+ #endif
+ return 0;
+}
+
+HYAMNMAIL WINAPI CreatePOP3Mail(CAccount *Account, DWORD)
+{
+ HYAMNMAIL NewMail;
+ //First, we should check whether MAILDATA matches.
+ //But this is internal plugin, so YAMN's MAILDATA structure and our MAILDATA structure are
+ //the same, so we do not need to test version. Otherwise, if MAILDATA version does not match
+ //in your plugin, you should return NULL, like this:
+ // if (MailDataVersion != YAMN_MAILDATAVERSION) return NULL;
+
+ //Now it is needed to construct our POP3 account and return its handle
+ if (nullptr == (NewMail = new YAMNMAIL))
+ return nullptr;
+
+ if (nullptr == (NewMail->MailData = new CMailData())) {
+ delete NewMail;
+ return nullptr;
+ }
+ NewMail->MailData->CP = ((HPOP3ACCOUNT)Account)->CP;
+ return (HYAMNMAIL)NewMail;
+}
+
+static void SetContactStatus(CAccount *account, int status)
+{
+ if ((account->hContact) && (account->NewMailN.Flags & YAMN_ACC_CONT))
+ g_plugin.setWord(account->hContact, "Status", status);
+}
+
+static void PostErrorProc(HPOP3ACCOUNT ActualAccount, void *ParamToBadConnection, uint32_t POP3PluginParam, BOOL UseSSL)
+{
+ char *DataRX;
+
+ //We create new structure, that we pass to bad connection dialog procedure. This procedure next calls YAMN imported fuction
+ //from POP3 protocol to determine the description of error. We can describe error from our error code structure, because later,
+ //when YAMN calls our function, it passes us our error code. This is pointer to structure for POP3 protocol in fact.
+ PPOP3_ERRORCODE ErrorCode;
+
+ //We store status before we do Quit(), because quit can destroy our errorcode status
+ if (nullptr != (ErrorCode = new POP3_ERRORCODE)) {
+ ErrorCode->SSL = UseSSL;
+ ErrorCode->AppError = ActualAccount->SystemError;
+ ErrorCode->POP3Error = ActualAccount->Client.POP3Error;
+ ErrorCode->NetError = ActualAccount->Client.NetClient->NetworkError;
+ ErrorCode->SystemError = ActualAccount->Client.NetClient->SystemError;
+ }
+
+ if (POP3PluginParam == (uint32_t)NULL) //if it was normal YAMN call (force check or so on)
+ {
+ try {
+ DataRX = ActualAccount->Client.Quit();
+ if (DataRX != nullptr)
+ free(DataRX);
+ }
+ catch (...) {
+ }
+ //We always close connection if error occured
+ try {
+ ActualAccount->Client.NetClient->Disconnect();
+ }
+ catch (...) {
+ }
+
+ SetAccountStatus(ActualAccount, TranslateT("Disconnected"));
+
+ //If we cannot allocate memory, do nothing
+ if (ErrorCode == nullptr) {
+ SetEvent(ActualAccount->UseInternetFree);
+ return;
+ }
+ }
+ else // else it was called from POP3 plugin, probably error when deleting old mail (POP3 synchro calls POP3 delete)
+ if (ErrorCode == nullptr)
+ return;
+
+ if ((ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG) || (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) || (ActualAccount->BadConnectN.Flags & YAMN_ACC_POP))
+ RunBadConnection(ActualAccount, (UINT_PTR)ErrorCode, ParamToBadConnection);
+
+ if (POP3PluginParam == (uint32_t)NULL) //if it was normal YAMN call
+ SetEvent(ActualAccount->UseInternetFree);
+}
+
+//Checks POP3 account and synchronizes it
+DWORD WINAPI SynchroPOP3(struct CheckParam *WhichTemp)
+{
+ HPOP3ACCOUNT ActualAccount;
+ CPop3Client *MyClient;
+ HYAMNMAIL NewMails = nullptr, MsgQueuePtr = nullptr;
+ char *DataRX = nullptr, *Temp;
+ int mboxsize, msgs, i;
+ SYSTEMTIME now;
+ LPVOID YAMNParam;
+ uint32_t CheckFlags;
+ BOOL UsingInternet = FALSE;
+ struct
+ {
+ char *ServerName;
+ uint32_t ServerPort;
+ char *ServerLogin;
+ char *ServerPasswd;
+ uint32_t Flags;
+ uint32_t NFlags;
+ uint32_t NNFlags;
+ } ActualCopied;
+
+ //First, we should compare our version of CheckParam structure, but here it is not needed, because YAMN and internal plugin
+ //have the same version. But your plugin should do that in this way:
+ // if (((struct CheckParam *)WhichTemp)->Ver != YAMN_CHECKVERSION)
+ // {
+ // SetEvent(((struct CheckParam *)WhichTemp)->ThreadRunningEV); //don't forget to unblock YAMN
+ // return (uint32_t)-1; //ok, but we should return value.
+ // //When our plugin returns e.g. 0xFFFFFFFF (=-1, this is only our plugin value, YAMN does nothing with return value,
+ // //but only tests if it is nonzero. If yes, it calls GetErrorStringFcn. We know problem occured in YAMN incompatibility
+ // //and then we can in our GetErrorStringFcn e.g. return string "Uncompatible version of YAMN".
+ // }
+
+ ActualAccount = (HPOP3ACCOUNT)WhichTemp->AccountParam; //copy address of structure from calling thread to stack of this thread
+ YAMNParam = WhichTemp->BrowserParam;
+ CheckFlags = WhichTemp->Flags;
+
+ SCInc(ActualAccount->UsingThreads);
+ //Unblock YAMN, signal that we have copied all parameters from YAMN thread stack
+ if (INVALID_HANDLE_VALUE != WhichTemp->ThreadRunningEV)
+ SetEvent(WhichTemp->ThreadRunningEV);
+
+ if (WAIT_OBJECT_0 != WaitToRead(ActualAccount)) {
+ SCDec(ActualAccount->UsingThreads);
+ return 0;
+ }
+
+ MyClient = &ActualAccount->Client;
+ //Now, copy all needed information about account to local variables, so ActualAccount is not blocked in read mode during all connection process, which can last for several minutes.
+ ActualCopied.ServerName = _strdup(ActualAccount->Server->Name);
+ ActualCopied.ServerPort = ActualAccount->Server->Port;
+ ActualCopied.Flags = ActualAccount->Flags;
+ ActualCopied.ServerLogin = _strdup(ActualAccount->Server->Login);
+ ActualCopied.ServerPasswd = _strdup(ActualAccount->Server->Passwd);
+ ActualCopied.NFlags = ActualAccount->NewMailN.Flags;
+ ActualCopied.NNFlags = ActualAccount->NoNewMailN.Flags;
+
+ ReadDone(ActualAccount);
+ SCInc(ActualAccount->InternetQueries); //increment counter, that there is one more thread waiting for connection
+
+ WaitForSingleObject(ActualAccount->UseInternetFree, INFINITE); //wait until we can use connection
+ SCDec(ActualAccount->InternetQueries);
+
+ //OK, we enter the "use internet" section. But after we start communication, we can test if we did not enter the "use internet" section only for the reason,
+ //that previous thread release the internet section because this account has stop signal (we stop account and there are 2 threads: one communicating,
+ //the second one waiting for network access- the first one ends because we want to stop account, this one is released, but should be stopped as well).
+ if (!ActualAccount->AbleToWork) {
+ SetEvent(ActualAccount->UseInternetFree);
+ SCDec(ActualAccount->UsingThreads);
+ return 0;
+ }
+ UsingInternet = TRUE;
+
+ GetLocalTime(&now);
+ ActualAccount->SystemError = 0; //now we can use internet for this socket. First, clear errorcode.
+ try {
+ SetContactStatus(ActualAccount, ID_STATUS_OCCUPIED);
+
+ // if we are already connected, we have open session (another thread left us open session), so we don't need to login
+ // note that connected state without logging cannot occur, because if we close session, we always close socket too (we must close socket is the right word :))
+ if ((MyClient->NetClient == nullptr) || !MyClient->NetClient->Connected()) {
+ SetAccountStatus(ActualAccount, TranslateT("Connecting to server"));
+
+ DataRX = MyClient->Connect(ActualCopied.ServerName, ActualCopied.ServerPort, ActualCopied.Flags & YAMN_ACC_SSL23, ActualCopied.Flags & YAMN_ACC_NOTLS);
+ char *timestamp = nullptr;
+
+ if (DataRX != nullptr) {
+ if (ActualCopied.Flags & YAMN_ACC_APOP) {
+ char *lpos = strchr(DataRX, '<');
+ char *rpos = strchr(DataRX, '>');
+ if (lpos && rpos && rpos > lpos) {
+ int sz = (int)(rpos - lpos + 2);
+ timestamp = new char[sz];
+ memcpy(timestamp, lpos, sz - 1);
+ timestamp[sz - 1] = '\0';
+ }
+ }
+ free(DataRX);
+ DataRX = nullptr;
+ }
+
+ SetAccountStatus(ActualAccount, TranslateT("Entering POP3 account"));
+
+ if (ActualCopied.Flags & YAMN_ACC_APOP) {
+ DataRX = MyClient->APOP(ActualCopied.ServerLogin, ActualCopied.ServerPasswd, timestamp);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ delete[] timestamp;
+ }
+ else {
+ DataRX = MyClient->User(ActualCopied.ServerLogin);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ DataRX = MyClient->Pass(ActualCopied.ServerPasswd);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ }
+ }
+ SetAccountStatus(ActualAccount, TranslateT("Searching for new mail message"));
+
+ DataRX = MyClient->Stat();
+
+ ExtractStat(DataRX, &mboxsize, &msgs);
+
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ for (i = 0; i < msgs; i++) {
+ if (!i)
+ MsgQueuePtr = NewMails = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION);
+ else {
+ MsgQueuePtr->Next = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION);
+ MsgQueuePtr = MsgQueuePtr->Next;
+ }
+ if (MsgQueuePtr == nullptr) {
+ ActualAccount->SystemError = EPOP3_QUEUEALLOC;
+ throw (uint32_t)ActualAccount->SystemError;
+ }
+ }
+
+ if (msgs) {
+ DataRX = MyClient->List();
+ ExtractList(DataRX, MyClient->NetClient->Rcv, NewMails);
+ if (DataRX != nullptr)
+ free(DataRX);
+
+ DataRX = MyClient->Uidl();
+ ExtractUIDL(DataRX, MyClient->NetClient->Rcv, NewMails);
+
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ }
+
+ if (WAIT_OBJECT_0 != MsgsWaitToWrite(ActualAccount))
+ throw (uint32_t)(ActualAccount->SystemError = EACC_STOPPED);
+
+ ActualAccount->LastChecked = now;
+ for (MsgQueuePtr = (HYAMNMAIL)ActualAccount->Mails; MsgQueuePtr != nullptr; MsgQueuePtr = MsgQueuePtr->Next) {
+ if (MsgQueuePtr->Flags & YAMN_MSG_BODYREQUESTED) {
+ HYAMNMAIL NewMsgsPtr = nullptr;
+ for (NewMsgsPtr = (HYAMNMAIL)NewMails; NewMsgsPtr != nullptr; NewMsgsPtr = NewMsgsPtr->Next) {
+ if (!mir_strcmp(MsgQueuePtr->ID, NewMsgsPtr->ID)) {
+ wchar_t accstatus[512];
+ mir_snwprintf(accstatus, TranslateT("Reading body %s"), NewMsgsPtr->ID);
+ SetAccountStatus(ActualAccount, accstatus);
+ DataRX = MyClient->Top(MsgQueuePtr->Number, 100);
+ if (DataRX != nullptr) {
+ Temp = DataRX;
+ while ((Temp < DataRX + MyClient->NetClient->Rcv) && (WS(Temp) || ENDLINE(Temp))) Temp++;
+
+ if (OKLINE(DataRX))
+ for (Temp = DataRX; (Temp < DataRX + MyClient->NetClient->Rcv) && (!ENDLINE(Temp)); Temp++);
+ while ((Temp < DataRX + MyClient->NetClient->Rcv) && ENDLINE(Temp)) Temp++;
+ }
+ else
+ continue;
+ //delete all the headers of the old mail MsgQueuePtr->MailData->TranslatedHeader
+ struct CMimeItem *TH = MsgQueuePtr->MailData->TranslatedHeader;
+ if (TH) for (; MsgQueuePtr->MailData->TranslatedHeader != nullptr;) {
+ TH = TH->Next;
+ if (MsgQueuePtr->MailData->TranslatedHeader->name != nullptr)
+ delete[] MsgQueuePtr->MailData->TranslatedHeader->name;
+ if (MsgQueuePtr->MailData->TranslatedHeader->value != nullptr)
+ delete[] MsgQueuePtr->MailData->TranslatedHeader->value;
+ delete MsgQueuePtr->MailData->TranslatedHeader;
+ MsgQueuePtr->MailData->TranslatedHeader = TH;
+ }
+
+ TranslateHeader(Temp, MyClient->NetClient->Rcv - (Temp - DataRX), &MsgQueuePtr->MailData->TranslatedHeader);
+
+ MsgQueuePtr->Flags |= YAMN_MSG_BODYRECEIVED;
+
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ break;
+ }
+ }
+ }
+ }
+
+ SynchroMessages(ActualAccount, (HYAMNMAIL *)&ActualAccount->Mails, nullptr, (HYAMNMAIL *)&NewMails, nullptr); //we get only new mails on server!
+
+ MsgsWriteDone(ActualAccount);
+ for (MsgQueuePtr = (HYAMNMAIL)ActualAccount->Mails; MsgQueuePtr != nullptr; MsgQueuePtr = MsgQueuePtr->Next) {
+ if ((MsgQueuePtr->Flags & YAMN_MSG_BODYREQUESTED) && (MsgQueuePtr->Flags & YAMN_MSG_BODYRECEIVED)) {
+ MsgQueuePtr->Flags &= ~YAMN_MSG_BODYREQUESTED;
+ if (MsgQueuePtr->MsgWindow)
+ SendMessage(MsgQueuePtr->MsgWindow, WM_YAMN_CHANGECONTENT, 0, 0);
+ }
+ }
+
+ for (msgs = 0, MsgQueuePtr = NewMails; MsgQueuePtr != nullptr; MsgQueuePtr = MsgQueuePtr->Next, msgs++); //get number of new mails
+
+ try {
+ wchar_t accstatus[512];
+
+ for (i = 0, MsgQueuePtr = NewMails; MsgQueuePtr != nullptr; i++) {
+ BOOL autoretr = (ActualAccount->Flags & YAMN_ACC_BODY) != 0;
+ DataRX = MyClient->Top(MsgQueuePtr->Number, autoretr ? 100 : 0);
+ mir_snwprintf(accstatus, TranslateT("Reading new mail messages (%d%% done)"), 100 * i / msgs);
+ SetAccountStatus(ActualAccount, accstatus);
+
+ if (DataRX != nullptr) {
+ Temp = DataRX;
+ while ((Temp < DataRX + MyClient->NetClient->Rcv) && (WS(Temp) || ENDLINE(Temp))) Temp++;
+
+ if (OKLINE(DataRX))
+ for (Temp = DataRX; (Temp < DataRX + MyClient->NetClient->Rcv) && (!ENDLINE(Temp)); Temp++);
+ while ((Temp < DataRX + MyClient->NetClient->Rcv) && ENDLINE(Temp)) Temp++;
+ }
+ else
+ continue;
+
+ TranslateHeader(Temp, MyClient->NetClient->Rcv - (Temp - DataRX), &MsgQueuePtr->MailData->TranslatedHeader);
+
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</New mail>\n");
+ #endif
+ MsgQueuePtr->Flags |= YAMN_MSG_NORMALNEW;
+ if (autoretr) MsgQueuePtr->Flags |= YAMN_MSG_BODYRECEIVED;
+
+ //We are going to filter mail. Warning!- we must not be in read access neither write access to mails when calling this service
+ //This is done, because the "NewMails" queue is not synchronised. It is because it is new queue. Only this thread uses new queue yet, it is not
+ //connected to account mail queue.
+ // CallService(MS_YAMN_FILTERMAIL,(WPARAM)ActualAccount,(LPARAM)MsgQueuePtr);
+ FilterMailSvc((WPARAM)ActualAccount, (LPARAM)MsgQueuePtr);
+
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+
+ //MsgQueuePtr->MailData->Body=MyClient->Retr(MsgQueuePtr->Number);
+
+ MsgQueuePtr = MsgQueuePtr->Next;
+
+ }
+
+ if (WAIT_OBJECT_0 != MsgsWaitToWrite(ActualAccount))
+ throw (uint32_t)ActualAccount->SystemError == EACC_STOPPED;
+
+ if (ActualAccount->Mails == nullptr)
+ ActualAccount->Mails = NewMails;
+ else {
+ ActualAccount->LastMail = ActualAccount->LastChecked;
+ AppendQueue((HYAMNMAIL)ActualAccount->Mails, NewMails);
+ }
+
+ MsgsWriteDone(ActualAccount);
+
+ // we are going to delete mails having SPAM flag level3 and 4 (see m_mails.h) set
+ {
+ struct DeleteParam ParamToDeleteMails = {YAMN_DELETEVERSION, INVALID_HANDLE_VALUE, ActualAccount, YAMNParam, (void *)POP3_DELETEFROMCHECK};
+
+ // Delete mails from server. Here we should not be in write access for account's mails
+ DeleteMailsPOP3(&ParamToDeleteMails);
+ }
+
+ // if there is no waiting thread for internet connection close it
+ // else leave connection open
+ if (0 == SCGetNumber(ActualAccount->InternetQueries)) {
+ DataRX = MyClient->Quit();
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ MyClient->NetClient->Disconnect();
+
+ SetAccountStatus(ActualAccount, TranslateT("Disconnected"));
+ }
+
+ UsingInternet = FALSE;
+ SetEvent(ActualAccount->UseInternetFree);
+
+ ActualAccount->LastSChecked = ActualAccount->LastChecked;
+ ActualAccount->LastSynchronised = ActualAccount->LastChecked;
+ }
+ catch (...) {
+ throw; //go to the main exception handling
+ }
+
+ {
+ YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, ActualCopied.NFlags, ActualCopied.NNFlags, YAMNParam};
+
+ if (CheckFlags & YAMN_FORCECHECK)
+ Param.nnflags |= YAMN_ACC_POP; //if force check, show popup anyway and if mailbrowser was opened, do not close
+ Param.nnflags |= YAMN_ACC_MSGP; //do not close browser if already open
+ CallService(MS_YAMN_MAILBROWSER, (WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION);
+ }
+ SetContactStatus(ActualAccount, ActualAccount->isCounting ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE);
+ }
+ #ifdef DEBUG_COMM
+ catch (uint32_t ErrorCode)
+ #else
+ catch (uint32_t)
+ #endif
+ {
+ if (ActualAccount->Client.POP3Error == EPOP3_STOPPED)
+ ActualAccount->SystemError = EACC_STOPPED;
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "ERROR: %x\n", ErrorCode);
+ #endif
+ if (WAIT_OBJECT_0 == MsgsWaitToWrite(ActualAccount)) {
+ ActualAccount->LastChecked = now;
+ MsgsWriteDone(ActualAccount);
+ }
+
+ DeleteMIMEQueue(ActualAccount, NewMails);
+
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ switch (ActualAccount->SystemError) {
+ case EACC_QUEUEALLOC:
+ case EACC_STOPPED:
+ ActualAccount->Client.NetClient->Disconnect();
+ break;
+ default:
+ PostErrorProc(ActualAccount, YAMNParam, (uint32_t)NULL, MyClient->SSL); //it closes internet connection too
+ }
+
+ if (UsingInternet) //if our thread still uses internet
+ SetEvent(ActualAccount->UseInternetFree);
+
+ SetContactStatus(ActualAccount, ID_STATUS_NA);
+ }
+ free(ActualCopied.ServerName);
+ free(ActualCopied.ServerLogin);
+ free(ActualCopied.ServerPasswd);
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "</--------Communication-------->\n");
+ #endif
+
+ // WriteAccounts();
+ SCDec(ActualAccount->UsingThreads);
+ return 0;
+}
+
+void __cdecl DeleteMailsPOP3(void *param)
+{
+ DeleteParam *WhichTemp = (DeleteParam *)param;
+
+ CPop3Client *MyClient;
+ HYAMNMAIL DeleteMails, NewMails = nullptr, MsgQueuePtr = nullptr;
+ char *DataRX = nullptr;
+ int mboxsize = 0, msgs = 0, i;
+ BOOL UsingInternet = FALSE;
+ struct
+ {
+ char *ServerName;
+ uint32_t ServerPort;
+ char *ServerLogin;
+ char *ServerPasswd;
+ uint32_t Flags;
+ uint32_t NFlags;
+ uint32_t NNFlags;
+ } ActualCopied;
+
+ //First, we should compare our version of DeleteParam structure, but here it is not needed, because YAMN and internal plugin
+ //have the same version. But your plugin should do that in this way:
+ // if (((struct DeleteParam *)WhichTemp)->Ver != YAMN_DELETEVERSION)
+ // {
+ // SetEvent(((struct DeleteParam *)WhichTemp)->ThreadRunningEV); //don't forget to unblock YAMN
+ // return (uint32_t)-1; //ok, but we should return value.
+ // //When our plugin returns e.g. 0xFFFFFFFF (this is only our plugin value, YAMN does nothing with return value,
+ // //but only tests if it is nonzero. If yes, it calls GetErrorStringFcn), we know problem occured in YAMN incompatibility
+ // //and then we can in our GetErrorStringFcn e.g. return string "Uncompatible version of YAMN".
+ // }
+
+ HPOP3ACCOUNT ActualAccount = (HPOP3ACCOUNT)WhichTemp->AccountParam; //copy address of structure from calling thread to stack of this thread
+ LPVOID YAMNParam = WhichTemp->BrowserParam;
+ UINT_PTR POP3PluginParam = (UINT_PTR)((struct DeleteParam *)WhichTemp)->CustomParam;
+
+ SCInc(ActualAccount->UsingThreads);
+ if (INVALID_HANDLE_VALUE != WhichTemp->ThreadRunningEV)
+ SetEvent(WhichTemp->ThreadRunningEV);
+
+ if (WAIT_OBJECT_0 != WaitToRead(ActualAccount)) {
+ SCDec(ActualAccount->UsingThreads);
+ return;
+ }
+
+ if (nullptr == (DeleteMails = (HYAMNMAIL)CreateNewDeleteQueue((HYAMNMAIL)ActualAccount->Mails))) //if there's no mail for deleting, return
+ {
+ if (POP3_DELETEFROMCHECK != POP3PluginParam) //We do not wait for free internet when calling from SynchroPOP3. It is because UseInternetFree is blocked
+ {
+ YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, YAMN_ACC_MSGP, YAMN_ACC_MSGP, YAMNParam}; //Just update the window
+ CallService(MS_YAMN_MAILBROWSER, (WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION);
+ }
+
+ SCDec(ActualAccount->UsingThreads);
+ return;
+ }
+
+ MyClient = &(ActualAccount->Client);
+
+ //Now, copy all needed information about account to local variables, so ActualAccount is not blocked in read mode during all connection process, which can last for several minutes.
+ ActualCopied.ServerName = _strdup(ActualAccount->Server->Name);
+ ActualCopied.ServerPort = ActualAccount->Server->Port;
+ ActualCopied.Flags = ActualAccount->Flags;
+ ActualCopied.ServerLogin = _strdup(ActualAccount->Server->Login);
+ ActualCopied.ServerPasswd = _strdup(ActualAccount->Server->Passwd);
+ ActualCopied.NFlags = ActualAccount->NewMailN.Flags;
+ ActualCopied.NNFlags = ActualAccount->NoNewMailN.Flags;
+
+ ReadDone(ActualAccount);
+
+ SCInc(ActualAccount->InternetQueries); //This is POP3-internal SCOUNTER, we set another thread wait for this account to be connected to inet
+ if (POP3_DELETEFROMCHECK != POP3PluginParam) //We do not wait for free internet when calling from SynchroPOP3. It is because UseInternetFree is blocked
+ WaitForSingleObject(ActualAccount->UseInternetFree, INFINITE);
+
+ SCDec(ActualAccount->InternetQueries);
+ UsingInternet = TRUE;
+
+ try {
+ SetContactStatus(ActualAccount, ID_STATUS_OCCUPIED);
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "<--------Communication-------->\n");
+ #endif
+ if ((MyClient->NetClient == nullptr) || !MyClient->NetClient->Connected()) {
+ SetAccountStatus(ActualAccount, TranslateT("Connecting to server"));
+
+ DataRX = MyClient->Connect(ActualCopied.ServerName, ActualCopied.ServerPort, ActualCopied.Flags & YAMN_ACC_SSL23, ActualCopied.Flags & YAMN_ACC_NOTLS);
+
+ char *timestamp = nullptr;
+ if (DataRX != nullptr) {
+ if (ActualAccount->Flags & YAMN_ACC_APOP) {
+ char *lpos = strchr(DataRX, '<');
+ char *rpos = strchr(DataRX, '>');
+ if (lpos && rpos && rpos > lpos) {
+ int sz = (int)(rpos - lpos + 2);
+ timestamp = new char[sz];
+ memcpy(timestamp, lpos, sz - 1);
+ timestamp[sz - 1] = '\0';
+ }
+ }
+ free(DataRX);
+ DataRX = nullptr;
+ }
+ SetAccountStatus(ActualAccount, TranslateT("Entering POP3 account"));
+
+ if (ActualAccount->Flags & YAMN_ACC_APOP) {
+ DataRX = MyClient->APOP(ActualCopied.ServerLogin, ActualCopied.ServerPasswd, timestamp);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ delete[] timestamp;
+ }
+ else {
+ DataRX = MyClient->User(ActualCopied.ServerLogin);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ DataRX = MyClient->Pass(ActualCopied.ServerPasswd);
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ }
+ }
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<--------Deleting requested mails-------->\n");
+ #endif
+ if (POP3_DELETEFROMCHECK != POP3PluginParam) //We do not need to get mails on server as we have already it from check function
+ {
+ SetAccountStatus(ActualAccount, TranslateT("Deleting requested mails"));
+
+ DataRX = MyClient->Stat();
+
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting stat>\n");
+ #endif
+ ExtractStat(DataRX, &mboxsize, &msgs);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<MailBoxSize>%d</MailBoxSize>\n", mboxsize);
+ DebugLog(DecodeFile, "<Msgs>%d</Msgs>\n", msgs);
+ DebugLog(DecodeFile, "</Extracting stat>\n");
+ #endif
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ for (i = 0; i < msgs; i++) {
+ if (!i)
+ MsgQueuePtr = NewMails = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION);
+ else {
+ MsgQueuePtr->Next = (HYAMNMAIL)CallService(MS_YAMN_CREATEACCOUNTMAIL, (WPARAM)ActualAccount, (LPARAM)YAMN_MAILVERSION);
+ MsgQueuePtr = MsgQueuePtr->Next;
+ }
+ if (MsgQueuePtr == nullptr) {
+ ActualAccount->SystemError = EPOP3_QUEUEALLOC;
+ throw (uint32_t)ActualAccount->SystemError;
+ }
+ }
+
+ if (msgs) {
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Extracting UIDL>\n");
+ #endif
+ DataRX = MyClient->Uidl();
+ ExtractUIDL(DataRX, MyClient->NetClient->Rcv, NewMails);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</Extracting UIDL>\n");
+ #endif
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ // we get "new mails" on server (NewMails will contain all mails on server not found in DeleteMails)
+ // but also in DeleteMails we get only those, which are still on server with their responsable numbers
+ SynchroMessages(ActualAccount, (HYAMNMAIL *)&DeleteMails, nullptr, (HYAMNMAIL *)&NewMails, nullptr);
+ }
+ }
+ else SetAccountStatus(ActualAccount, TranslateT("Deleting spam"));
+
+ if (WAIT_OBJECT_0 != MsgsWaitToWrite(ActualAccount))
+ throw (uint32_t)EACC_STOPPED;
+
+ if (msgs || POP3_DELETEFROMCHECK == POP3PluginParam) {
+ try {
+ HYAMNMAIL Temp;
+
+ for (i = 0, MsgQueuePtr = DeleteMails; MsgQueuePtr != nullptr; i++) {
+ if (!(MsgQueuePtr->Flags & YAMN_MSG_VIRTUAL)) //of course we can only delete real mails, not virtual
+ {
+ DataRX = MyClient->Dele(MsgQueuePtr->Number);
+ Temp = MsgQueuePtr->Next;
+ if (POP3_FOK == MyClient->AckFlag) //if server answers that mail was deleted
+ {
+ DeleteMIMEMessage((HYAMNMAIL *)&DeleteMails, MsgQueuePtr);
+ HYAMNMAIL DeletedMail = FindMIMEMessageByID((HYAMNMAIL)ActualAccount->Mails, MsgQueuePtr->ID);
+ if ((MsgQueuePtr->Flags & YAMN_MSG_MEMDELETE)) //if mail should be deleted from memory (or disk)
+ {
+ DeleteMIMEMessage((HYAMNMAIL *)&ActualAccount->Mails, DeletedMail); //remove from queue
+ CallService(MS_YAMN_DELETEACCOUNTMAIL, (WPARAM)POP3Plugin, (LPARAM)DeletedMail);
+ }
+ else //else mark it only as "deleted mail"
+ {
+ DeletedMail->Flags |= (YAMN_MSG_VIRTUAL | YAMN_MSG_DELETED);
+ DeletedMail->Flags &= ~(YAMN_MSG_NEW | YAMN_MSG_USERDELETE | YAMN_MSG_AUTODELETE); //clear "new mail"
+ }
+ delete MsgQueuePtr->MailData;
+ delete[] MsgQueuePtr->ID;
+ delete MsgQueuePtr;
+ }
+ MsgQueuePtr = Temp;
+
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ }
+ else
+ MsgQueuePtr = MsgQueuePtr->Next;
+ }
+ }
+ catch (...) //if any exception in the code where we have write-access to account occured, don't forget to leave write-access
+ {
+ MsgsWriteDone(ActualAccount);
+ throw; //and go to the main exception handling
+ }
+
+ if (NewMails != nullptr)
+ // in ActualAccount->Mails we have all mails stored before calling this function
+ // in NewMails we have all mails not found in DeleteMails (in other words: we performed new ID checking and we
+ // stored all mails found on server, then we deleted the ones we wanted to delete in this function
+ // and NewMails queue now contains actual state of mails on server). But we will not use NewMails as actual state, because NewMails does not contain header data (subject, from...)
+ // We perform deleting from ActualAccount->Mails: we remove from original queue (ActualAccount->Mails) all deleted mails
+ SynchroMessages(ActualAccount, (HYAMNMAIL *)&ActualAccount->Mails, nullptr, (HYAMNMAIL *)&NewMails, nullptr);
+ // Now ActualAccount->Mails contains all mails when calling this function except the ones, we wanted to delete (these are in DeleteMails)
+ // And in NewMails we have new mails (if any)
+ else if (POP3_DELETEFROMCHECK != POP3PluginParam) {
+ DeleteMIMEQueue(ActualAccount, (HYAMNMAIL)ActualAccount->Mails);
+ ActualAccount->Mails = nullptr;
+ }
+ }
+ else {
+ DeleteMIMEQueue(ActualAccount, (HYAMNMAIL)ActualAccount->Mails);
+ ActualAccount->Mails = nullptr;
+ }
+
+ MsgsWriteDone(ActualAccount);
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "</--------Deleting requested mails-------->\n");
+ #endif
+
+ // TODO: now, we have in NewMails new mails. If NewMails is not NULL, we found some new mails, so Checking for new mail should be performed
+ // now, we do not call CheckPOP3
+
+ // if there is no waiting thread for internet connection close it
+ // else leave connection open
+ // if this functin was called from SynchroPOP3, then do not try to disconnect
+ if (POP3_DELETEFROMCHECK != POP3PluginParam) {
+ YAMN_MAILBROWSERPARAM Param = {(HANDLE)nullptr, ActualAccount, ActualCopied.NFlags, YAMN_ACC_MSGP, YAMNParam};
+
+ CallService(MS_YAMN_MAILBROWSER, (WPARAM)&Param, (LPARAM)YAMN_MAILBROWSERVERSION);
+
+ if (0 == SCGetNumber(ActualAccount->InternetQueries)) {
+ DataRX = MyClient->Quit();
+ if (DataRX != nullptr)
+ free(DataRX);
+ DataRX = nullptr;
+ MyClient->NetClient->Disconnect();
+
+ SetAccountStatus(ActualAccount, TranslateT("Disconnected"));
+ }
+
+ UsingInternet = FALSE;
+ SetEvent(ActualAccount->UseInternetFree);
+ }
+ SetContactStatus(ActualAccount, ActualAccount->isCounting ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE);
+ }
+ #ifdef DEBUG_COMM
+ catch (uint32_t ErrorCode)
+ #else
+ catch (uint32_t)
+ #endif
+ {
+ if (ActualAccount->Client.POP3Error == EPOP3_STOPPED)
+ ActualAccount->SystemError = EACC_STOPPED;
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "ERROR %x\n", ErrorCode);
+ #endif
+ if (DataRX != nullptr)
+ free(DataRX);
+ switch (ActualAccount->SystemError) {
+ case EACC_QUEUEALLOC:
+ case EACC_STOPPED:
+ ActualAccount->Client.NetClient->Disconnect();
+ break;
+ default:
+ PostErrorProc(ActualAccount, YAMNParam, POP3PluginParam, MyClient->SSL); //it closes internet connection too
+ }
+
+ if (UsingInternet && (POP3_DELETEFROMCHECK != POP3PluginParam)) //if our thread still uses internet and it is needed to release internet
+ SetEvent(ActualAccount->UseInternetFree);
+ }
+
+ free(ActualCopied.ServerName);
+ free(ActualCopied.ServerLogin);
+ free(ActualCopied.ServerPasswd);
+
+ DeleteMIMEQueue(ActualAccount, NewMails);
+ DeleteMIMEQueue(ActualAccount, DeleteMails);
+
+ #ifdef DEBUG_COMM
+ DebugLog(CommFile, "</--------Communication-------->\n");
+ #endif
+
+ // WriteAccounts();
+ SCDec(ActualAccount->UsingThreads);
+ return;
+}
+
+void ExtractStat(char *stream, int *mboxsize, int *mails)
+{
+ char *finder = stream;
+ while (WS(finder) || ENDLINE(finder)) finder++;
+ if (ACKLINE(finder)) {
+ while (!WS(finder)) finder++;
+ while (WS(finder)) finder++;
+ }
+ if (1 != sscanf(finder, "%d", mails))
+ throw (uint32_t)EPOP3_STAT;
+ while (!WS(finder)) finder++;
+ while (WS(finder)) finder++;
+ if (1 != sscanf(finder, "%d", mboxsize))
+ throw (uint32_t)EPOP3_STAT;
+}
+void ExtractMail(char *stream, int len, HYAMNMAIL queue)
+{
+ char *finder = stream;
+ char *finderend;
+ int msgnr, i;
+ HYAMNMAIL queueptr = queue;
+
+ while (WS(finder) || ENDLINE(finder)) finder++;
+ while (!ACKLINE(finder)) finder++;
+ while (!ENDLINE(finder)) finder++; //now we at the end of first ack line
+ while (finder <= (stream + len)) {
+ while (ENDLINE(finder)) finder++; //go to the new line
+ if (DOTLINE(finder + 1)) //at the end of stream
+ break;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Message>\n");
+ #endif
+ while (WS(finder)) finder++; //jump whitespace
+ if (1 != sscanf(finder, "%d", &msgnr))
+ throw (uint32_t)EPOP3_UIDL;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Nr>%d</Nr>\n", msgnr);
+ #endif
+ // for (i=1,queueptr=queue;(queueptr->Next != NULL) && (i<msgnr);queueptr=queueptr->Next,i++);
+ // if (i != msgnr)
+ // throw (uint32_t)EPOP3_UIDL;
+ while (!WS(finder)) finder++; //jump characters
+ while (WS(finder)) finder++; //jump whitespace
+ finderend = finder + 1;
+ while (!WS(finderend) && !ENDLINE(finderend)) finderend++;
+ queueptr->ID = new char[finderend - finder + 1];
+ for (i = 0; finder != finderend; finder++, i++)
+ queueptr->MailData->Body[i] = *finder;
+ queueptr->MailData->Body[i] = 0; //ends string
+ queueptr->Number = msgnr;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<ID>%s</ID>\n", queueptr->MailData->Body);
+ DebugLog(DecodeFile, "</Message>\n");
+ #endif
+ queueptr = queueptr->Next;
+ while (!ENDLINE(finder)) finder++;
+ }
+}
+
+void ExtractUIDL(char *stream, int len, HYAMNMAIL queue)
+{
+ char *finder = stream;
+ char *finderend;
+ int msgnr, i;
+ HYAMNMAIL queueptr = queue;
+
+ while (WS(finder) || ENDLINE(finder)) finder++;
+ while (!ACKLINE(finder)) finder++;
+ while (!ENDLINE(finder)) finder++; //now we at the end of first ack line
+ while (finder <= (stream + len)) {
+ while (ENDLINE(finder)) finder++; //go to the new line
+ if (DOTLINE(finder + 1)) //at the end of stream
+ break;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Message>\n");
+ #endif
+ while (WS(finder)) finder++; //jump whitespace
+ if (1 != sscanf(finder, "%d", &msgnr))
+ throw (uint32_t)EPOP3_UIDL;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Nr>%d</Nr>\n", msgnr);
+ #endif
+ // for (i=1,queueptr=queue;(queueptr->Next != NULL) && (i<msgnr);queueptr=queueptr->Next,i++);
+ // if (i != msgnr)
+ // throw (uint32_t)EPOP3_UIDL;
+ while (!WS(finder)) finder++; //jump characters
+ while (WS(finder)) finder++; //jump whitespace
+ finderend = finder + 1;
+ while (!WS(finderend) && !ENDLINE(finderend)) finderend++;
+ queueptr->ID = new char[finderend - finder + 1];
+ for (i = 0; finder != finderend; finder++, i++)
+ queueptr->ID[i] = *finder;
+ queueptr->ID[i] = 0; //ends string
+ queueptr->Number = msgnr;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<ID>%s</ID>\n", queueptr->ID);
+ DebugLog(DecodeFile, "</Message>\n");
+ #endif
+ queueptr = queueptr->Next;
+ while (!ENDLINE(finder)) finder++;
+ }
+}
+
+void ExtractList(char *stream, int len, HYAMNMAIL queue)
+{
+ char *finder = stream;
+ char *finderend;
+ int msgnr, i;
+ HYAMNMAIL queueptr;
+
+ while (WS(finder) || ENDLINE(finder)) finder++;
+ while (!ACKLINE(finder)) finder++;
+ while (!ENDLINE(finder)) finder++; //now we at the end of first ack line
+ while (finder <= (stream + len)) {
+ while (ENDLINE(finder)) finder++; //go to the new line
+ if (DOTLINE(finder + 1)) //at the end of stream
+ break;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Message>\n", NULL, 0);
+ #endif
+ while (WS(finder)) finder++; //jump whitespace
+ if (1 != sscanf(finder, "%d", &msgnr)) //message nr.
+ throw (uint32_t)EPOP3_LIST;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Nr>%d</Nr>\n", msgnr);
+ #endif
+
+ for (i = 1, queueptr = queue; (queueptr->Next != nullptr) && (i < msgnr); queueptr = queueptr->Next, i++);
+ if (i != msgnr)
+ throw (uint32_t)EPOP3_LIST;
+ while (!WS(finder)) finder++; //jump characters
+ while (WS(finder)) finder++; //jump whitespace
+ finderend = finder + 1;
+ if (1 != sscanf(finder, "%u", &queueptr->MailData->Size))
+ throw (uint32_t)EPOP3_LIST;
+ #ifdef DEBUG_DECODE
+ DebugLog(DecodeFile, "<Nr>%d</Nr>\n", queueptr->MailData->Size);
+ #endif
+ while (!ENDLINE(finder)) finder++;
+ }
+}
+
+wchar_t *WINAPI GetErrorString(DWORD Code)
+{
+ static wchar_t *POP3Errors[] =
+ {
+ LPGENW("Memory allocation error."), //memory allocation
+ LPGENW("Account is about to be stopped."), //stop account
+ LPGENW("Cannot connect to POP3 server."),
+ LPGENW("Cannot allocate memory for received data."),
+ LPGENW("Cannot login to POP3 server."),
+ LPGENW("Bad user or password."),
+ LPGENW("Server does not support APOP authorization."),
+ LPGENW("Error while executing POP3 command."),
+ LPGENW("Error while executing POP3 command."),
+ LPGENW("Error while executing POP3 command."),
+ };
+
+ static wchar_t *NetlibErrors[] =
+ {
+ LPGENW("Cannot connect to server with NetLib."),
+ LPGENW("Cannot send data."),
+ LPGENW("Cannot receive data."),
+ LPGENW("Cannot allocate memory for received data."),
+ };
+
+ static wchar_t *SSLErrors[] =
+ {
+ LPGENW("OpenSSL not loaded."),
+ LPGENW("Windows socket 2.0 init failed."),
+ LPGENW("DNS lookup error."),
+ LPGENW("Error while creating base socket."),
+ LPGENW("Error connecting to server with socket."),
+ LPGENW("Error while creating SSL structure."),
+ LPGENW("Error connecting socket with SSL."),
+ LPGENW("Server rejected connection with SSL."),
+ LPGENW("Cannot write SSL data."),
+ LPGENW("Cannot read SSL data."),
+ LPGENW("Cannot allocate memory for received data."),
+ };
+
+ wchar_t *ErrorString = new wchar_t[ERRORSTR_MAXLEN];
+ POP3_ERRORCODE *ErrorCode = (POP3_ERRORCODE *)(UINT_PTR)Code;
+
+ mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, TranslateT("Error %d-%d-%d-%d:"), ErrorCode->AppError, ErrorCode->POP3Error, ErrorCode->NetError, ErrorCode->SystemError);
+ if (ErrorCode->POP3Error)
+ mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(POP3Errors[ErrorCode->POP3Error - 1]));
+ if (ErrorCode->NetError) {
+ if (ErrorCode->SSL)
+ mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(SSLErrors[ErrorCode->NetError - 1]));
+ else
+ mir_snwprintf(ErrorString, ERRORSTR_MAXLEN, L"%s\n%s", ErrorString, TranslateW(NetlibErrors[ErrorCode->NetError - 4]));
+ }
+
+ return ErrorString;
+}
+
+void WINAPI DeleteErrorString(LPVOID String)
+{
+ delete (char *)String;
+}
diff --git a/protocols/YAMN/src/proto/pop3/pop3opt.cpp b/protocols/YAMN/src/proto/pop3/pop3opt.cpp index 80764d85bb..a1dfa14199 100644 --- a/protocols/YAMN/src/proto/pop3/pop3opt.cpp +++ b/protocols/YAMN/src/proto/pop3/pop3opt.cpp @@ -1,1137 +1,1137 @@ -/* - * This code implements POP3 options window handling - * - * (c) majvan 2002-2003 -*/ - -#include "../../stdafx.h" - -//-------------------------------------------------------------------------------------------------- - -static char DlgInput[MAX_PATH]; - -static BOOL DlgSetItemText(HWND hDlg, WPARAM wParam, const char *str) -{ - if (str == nullptr) - SetDlgItemTextA(hDlg, wParam, ""); - else - SetDlgItemTextA(hDlg, wParam, str); - return TRUE; -} - -static BOOL DlgSetItemTextW(HWND hDlg, WPARAM wParam, const wchar_t *str) -{ - if (str == nullptr) - SetDlgItemTextW(hDlg, wParam, L""); - else - SetDlgItemTextW(hDlg, wParam, str); - return TRUE; -} - -struct CBaseOptionsDlg : public CDlgBase -{ - CBaseOptionsDlg(int iDlgId) : - CDlgBase(g_plugin, iDlgId) - {} - - void DlgShowAccount(HPOP3ACCOUNT pAccount) - { - int i; - - if (pAccount) { - // we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread - WaitToRead(pAccount); - - DlgSetItemText(m_hwnd, IDC_EDITSERVER, pAccount->Server->Name); - DlgSetItemText(m_hwnd, IDC_EDITNAME, pAccount->Name); - DlgSetItemText(m_hwnd, IDC_EDITLOGIN, pAccount->Server->Login); - DlgSetItemText(m_hwnd, IDC_EDITPASS, pAccount->Server->Passwd); - DlgSetItemTextW(m_hwnd, IDC_EDITAPP, pAccount->NewMailN.App); - DlgSetItemTextW(m_hwnd, IDC_EDITAPPPARAM, pAccount->NewMailN.AppParam); - SetDlgItemInt(m_hwnd, IDC_EDITPORT, pAccount->Server->Port, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITINTERVAL, pAccount->Interval / 60, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITPOPS, pAccount->NewMailN.PopupTime, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, pAccount->NoNewMailN.PopupTime, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, pAccount->BadConnectN.PopupTime, FALSE); - for (i = 0; i <= CPLENSUPP; i++) - if ((i < CPLENSUPP) && (CodePageNamesSupp[i].CP == pAccount->CP)) { - SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)i, 0); - break; - } - - if (i == CPLENSUPP) - SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)CPDEFINDEX, 0); - - CheckDlgButton(m_hwnd, IDC_CHECK, pAccount->Flags & YAMN_ACC_ENA ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKSND, pAccount->NewMailN.Flags & YAMN_ACC_SND ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKMSG, pAccount->NewMailN.Flags & YAMN_ACC_MSG ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKICO, pAccount->NewMailN.Flags & YAMN_ACC_ICO ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKPOP, pAccount->NewMailN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKCOL, pAccount->NewMailN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKAPP, pAccount->NewMailN.Flags & YAMN_ACC_APP ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKKBN, pAccount->NewMailN.Flags & YAMN_ACC_KBN ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKNPOP, pAccount->NoNewMailN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKNCOL, pAccount->NoNewMailN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKNMSGP, pAccount->NoNewMailN.Flags & YAMN_ACC_MSGP ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFSND, pAccount->BadConnectN.Flags & YAMN_ACC_SND ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFMSG, pAccount->BadConnectN.Flags & YAMN_ACC_MSG ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFICO, pAccount->BadConnectN.Flags & YAMN_ACC_ICO ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFPOP, pAccount->BadConnectN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFCOL, pAccount->BadConnectN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_RADIOPOPN, pAccount->Flags & YAMN_ACC_POPN ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_RADIOPOP1, pAccount->Flags & YAMN_ACC_POPN ? BST_UNCHECKED : BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKSSL, pAccount->Flags & YAMN_ACC_SSL23 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKNOTLS, pAccount->Flags & YAMN_ACC_NOTLS ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKAPOP, pAccount->Flags & YAMN_ACC_APOP ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_AUTOBODY, pAccount->Flags & YAMN_ACC_BODY ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKSTART, pAccount->StatusFlags & YAMN_ACC_STARTS ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFORCE, pAccount->StatusFlags & YAMN_ACC_FORCE ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKCONTACT, pAccount->NewMailN.Flags & YAMN_ACC_CONT ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKCONTACTNICK, pAccount->NewMailN.Flags & YAMN_ACC_CONTNICK ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKCONTACTNOEVENT, pAccount->NewMailN.Flags & YAMN_ACC_CONTNOEVENT ? BST_CHECKED : BST_UNCHECKED); - - wchar_t accstatus[256]; - GetAccountStatus(pAccount, accstatus); - SetDlgItemText(m_hwnd, IDC_STSTATUS, accstatus); - ReadDone(pAccount); - } - else { - DlgSetItemText(m_hwnd, IDC_EDITSERVER, nullptr); - DlgSetItemText(m_hwnd, IDC_EDITNAME, nullptr); - DlgSetItemText(m_hwnd, IDC_EDITLOGIN, nullptr); - DlgSetItemText(m_hwnd, IDC_EDITPASS, nullptr); - DlgSetItemText(m_hwnd, IDC_EDITAPP, nullptr); - DlgSetItemText(m_hwnd, IDC_EDITAPPPARAM, nullptr); - DlgSetItemText(m_hwnd, IDC_STTIMELEFT, nullptr); - SetDlgItemInt(m_hwnd, IDC_EDITPORT, 110, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITINTERVAL, 30, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITPOPS, 0, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, 0, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, 0, FALSE); - SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)CPDEFINDEX, 0); - CheckDlgButton(m_hwnd, IDC_CHECK, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKSND, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKMSG, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKICO, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKPOP, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKCOL, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKAPP, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFSND, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFMSG, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFICO, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFPOP, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFCOL, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKSTART, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKFORCE, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_RADIOPOPN, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_RADIOPOP1, BST_CHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKSSL, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKNOTLS, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKAPOP, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_AUTOBODY, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CHECKCONTACT, BST_CHECKED); - - SetDlgItemText(m_hwnd, IDC_STSTATUS, TranslateT("No account selected")); - } - } -}; - -//======================================================================================= -// General options dialog - -struct CGeneralOptDlg : public CBaseOptionsDlg -{ - CGeneralOptDlg() : - CBaseOptionsDlg(IDD_YAMNOPT) - {} - - bool OnInitDialog() override - { - CheckDlgButton(m_hwnd, IDC_CHECKTTB, g_plugin.getByte(YAMN_TTBFCHECK, 1) ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_LONGDATE, (optDateTime & SHOWDATELONG) ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_SMARTDATE, (optDateTime & SHOWDATENOTODAY) ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_NOSECONDS, (optDateTime & SHOWDATENOSECONDS) ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_CLOSEONDELETE, g_plugin.getByte(YAMN_CLOSEDELETE, 0) ? BST_CHECKED : BST_UNCHECKED); - return true; - } - - bool OnApply() override - { - g_plugin.setByte(YAMN_CLOSEDELETE, IsDlgButtonChecked(m_hwnd, IDC_CLOSEONDELETE)); - g_plugin.setByte(YAMN_TTBFCHECK, IsDlgButtonChecked(m_hwnd, IDC_CHECKTTB)); - - AddTopToolbarIcon(0, 0); - - optDateTime = 0; - if (IsDlgButtonChecked(m_hwnd, IDC_LONGDATE)) optDateTime |= SHOWDATELONG; - if (IsDlgButtonChecked(m_hwnd, IDC_SMARTDATE)) optDateTime |= SHOWDATENOTODAY; - if (IsDlgButtonChecked(m_hwnd, IDC_NOSECONDS)) optDateTime |= SHOWDATENOSECONDS; - g_plugin.setByte(YAMN_DBTIMEOPTIONS, optDateTime); - return true; - } -}; - -//-------------------------------------------------------------------------------------------------- - -static int g_iStatusControls[] = {IDC_CHECKST0, IDC_CHECKST1, IDC_CHECKST2, IDC_CHECKST3, IDC_CHECKST4, IDC_CHECKST5, IDC_CHECKST6, IDC_CHECKST7}; - -static BOOL DlgShowAccountStatus(HWND hDlg, HPOP3ACCOUNT ActualAccount) -{ - if (ActualAccount) { - WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread - - CheckDlgButton(hDlg, IDC_CHECKST0, ActualAccount->StatusFlags & YAMN_ACC_ST0 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST1, ActualAccount->StatusFlags & YAMN_ACC_ST1 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST2, ActualAccount->StatusFlags & YAMN_ACC_ST2 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST3, ActualAccount->StatusFlags & YAMN_ACC_ST3 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST4, ActualAccount->StatusFlags & YAMN_ACC_ST4 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST5, ActualAccount->StatusFlags & YAMN_ACC_ST5 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST6, ActualAccount->StatusFlags & YAMN_ACC_ST6 ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST7, ActualAccount->StatusFlags & YAMN_ACC_ST7 ? BST_CHECKED : BST_UNCHECKED); - - ReadDone(ActualAccount); - } - else { - CheckDlgButton(hDlg, IDC_CHECKST0, BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST1, BST_CHECKED); - CheckDlgButton(hDlg, IDC_CHECKST2, BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST3, BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST4, BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST5, BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST6, BST_UNCHECKED); - CheckDlgButton(hDlg, IDC_CHECKST7, BST_CHECKED); - } - return TRUE; -} - -static INT_PTR CALLBACK DlgProcPOP3AccStatusOpt(HWND hDlg, UINT msg, WPARAM wParam, LPARAM) -{ - static HPOP3ACCOUNT ActualAccount; - switch (msg) { - case WM_INITDIALOG: - ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput); - if (ActualAccount != nullptr) { - DlgShowAccountStatus(hDlg, ActualAccount); - for (auto &it : g_iStatusControls) - EnableWindow(GetDlgItem(hDlg, it), true); - } - else { - for (auto &it : g_iStatusControls) - CheckDlgButton(hDlg, it, BST_CHECKED); - } - TranslateDialogDefault(hDlg); - SendMessage(GetParent(hDlg), PSM_UNCHANGED, (WPARAM)hDlg, 0); - return TRUE; - - case WM_COMMAND: - switch (LOWORD(wParam)) { - case IDCANCEL: - EndDialog(hDlg, 0); - DestroyWindow(hDlg); - break; - - case IDOK: - int iShift = 1; - ActualAccount->StatusFlags = 0; - for (auto &it : g_iStatusControls) { - if (IsDlgButtonChecked(hDlg, it)) - ActualAccount->StatusFlags |= iShift; - iShift <<= 1; - } - - WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_CHANGESTATUSOPTION, 0, 0); - EndDialog(hDlg, 0); - DestroyWindow(hDlg); - break; - } - } - return FALSE; -} - -///////////////////////////////////////////////////////////////////////////////////////// -// Account options - -class CAccOptDlg : public CBaseOptionsDlg -{ - INT_PTR Result; - UCHAR ActualStatus; - HPOP3ACCOUNT ActualAccount = nullptr; - - CCtrlCheck chkContact, chkSsl, chkApp; - CCtrlCombo cmbAccount, cmbCP; - CCtrlButton btnStatus, btnAdd, btnDel, btnApp, btnDefault, btnReset; - - void DlgEnableAccount(bool bEnable) - { - cmbAccount.Enable(POP3Plugin->FirstAccount != nullptr); - - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECK), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITSERVER), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITNAME), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPORT), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITLOGIN), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPASS), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITINTERVAL), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKSND), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKMSG), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKICO), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKAPP), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKKBN), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNAPP), chkApp.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPP), chkApp.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPPPARAM), chkApp.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKNMSGP), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFSND), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFMSG), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFICO), bEnable); - - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKSTART), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFORCE), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_COMBOCP), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_STTIMELEFT), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNRESET), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEFAULT), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNSTATUS), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKSSL), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKAPOP), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKNOTLS), chkSsl.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_AUTOBODY), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACT), bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNICK), chkContact.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNOEVENT), chkContact.IsChecked() && bEnable); - } - -public: - CAccOptDlg() : - CBaseOptionsDlg(IDD_POP3ACCOUNTOPT), - cmbCP(this, IDC_COMBOCP), - btnAdd(this, IDC_BTNADD), - btnApp(this, IDC_BTNAPP), - btnDel(this, IDC_BTNDEL), - chkApp(this, IDC_CHECKAPP), - chkSsl(this, IDC_CHECKSSL), - btnReset(this, IDC_BTNRESET), - btnStatus(this, IDC_BTNSTATUS), - btnDefault(this, IDC_BTNDEFAULT), - cmbAccount(this, IDC_COMBOACCOUNT), - chkContact(this, IDC_CHECKCONTACT) - { - cmbCP.OnSelChanged = Callback(this, &CAccOptDlg::onSelChange_CP); - - cmbAccount.OnChange = Callback(this, &CAccOptDlg::onChange_Account); - cmbAccount.OnKillFocus = Callback(this, &CAccOptDlg::onKillFocus_Account); - cmbAccount.OnSelChanged = Callback(this, &CAccOptDlg::onSelChange_Account); - - chkApp.OnChange = Callback(this, &CAccOptDlg::onChangeApp); - chkSsl.OnChange = Callback(this, &CAccOptDlg::onChangeSsl); - chkContact.OnChange = Callback(this, &CAccOptDlg::onChangeContact); - - btnAdd.OnClick = Callback(this, &CAccOptDlg::onClick_Add); - btnDel.OnClick = Callback(this, &CAccOptDlg::onClick_Del); - btnApp.OnClick = Callback(this, &CAccOptDlg::onClick_App); - btnReset.OnClick = Callback(this, &CAccOptDlg::onClick_Reset); - btnStatus.OnClick = Callback(this, &CAccOptDlg::onClick_Status); - btnDefault.OnClick = Callback(this, &CAccOptDlg::onClick_Default); - } - - bool OnInitDialog() override - { - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE); - - DlgEnableAccount(false); - DlgShowAccount(0); - - // Fill accounts - WaitToReadSO(POP3Plugin->AccountBrowserSO); - - for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next) - if (ActualAccount->Name != nullptr) - cmbAccount.AddStringA(ActualAccount->Name); - cmbAccount.SetCurSel(0); - - ReadDoneSO(POP3Plugin->AccountBrowserSO); - - // Fill code pages - cmbCP.AddString(TranslateT("Default")); - for (int i = 1; i < CPLENSUPP; i++) { - CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[i].CP, 0, &info); - size_t len = mir_wstrlen(info.CodePageName + 7); - info.CodePageName[len + 6] = 0; - cmbCP.AddString(info.CodePageName + 7); - } - cmbCP.SetCurSel(0); - - ActualAccount = nullptr; - SendMessage(GetParent(m_hwnd), PSM_UNCHANGED, (WPARAM)m_hwnd, 0); - - WindowList_Add(pYAMNVar->MessageWnds, m_hwnd); - return true; - } - - void OnDestroy() override - { - WindowList_Remove(pYAMNVar->MessageWnds, m_hwnd); - } - - INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override - { - switch (msg) { - case WM_YAMN_CHANGESTATUS: - if ((HPOP3ACCOUNT)wParam == ActualAccount) { - wchar_t accstatus[256]; - GetAccountStatus(ActualAccount, accstatus); - SetDlgItemText(m_hwnd, IDC_STSTATUS, accstatus); - return TRUE; - } - break; - - case WM_YAMN_CHANGESTATUSOPTION: - NotifyChange(); - return TRUE; - - case WM_YAMN_CHANGETIME: - if ((HPOP3ACCOUNT)wParam == ActualAccount) { - wchar_t Text[256]; - mir_snwprintf(Text, TranslateT("Time left to next check [s]: %d"), (uint32_t)lParam); - SetDlgItemText(m_hwnd, IDC_STTIMELEFT, Text); - } - return TRUE; - } - return CDlgBase::DlgProc(msg, wParam, lParam); - } - - void onChange_Account(CCtrlCombo *) - { - ActualAccount = nullptr; - DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr); - DlgEnableAccount(0 != GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput))); - } - - void onKillFocus_Account(CCtrlCombo *) - { - GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput)); - if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput))) { - DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE); - DlgEnableAccount(mir_strlen(DlgInput) > 0); - } - else { - DlgShowAccount(ActualAccount); - DlgEnableAccount(true); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), TRUE); - } - } - - void onSelChange_Account(CCtrlCombo *) - { - if (CB_ERR != (Result = cmbAccount.GetCurSel())) - SendDlgItemMessageA(m_hwnd, IDC_COMBOACCOUNT, CB_GETLBTEXT, (WPARAM)Result, (LPARAM)DlgInput); - - if ((Result == CB_ERR) || (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput)))) { - DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE); - } - else { - DlgShowAccount(ActualAccount); - DlgEnableAccount(true); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), TRUE); - } - } - - void onSelChange_CP(CCtrlCombo *) - { - int sel = cmbCP.GetCurSel(); - CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[sel].CP, 0, &info); - DlgSetItemTextW(m_hwnd, IDC_STSTATUS, info.CodePageName); - } - - void onChangeContact(CCtrlCheck *) - { - bool bEnabled = chkContact.IsChecked(); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNICK), bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNOEVENT), bEnabled); - } - - void onChangeSsl(CCtrlCheck *) - { - bool bEnabled = chkSsl.IsChecked(); - SetDlgItemInt(m_hwnd, IDC_EDITPORT, bEnabled ? 995 : 110, FALSE); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKNOTLS), !bEnabled); - } - - void onChangeApp(CCtrlCheck *) - { - bool bEnabled = chkApp.IsChecked(); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNAPP), bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPP), bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPPPARAM), bEnabled); - } - - void onClick_Status(CCtrlButton *) - { - DialogBoxParamW(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_CHOOSESTATUSMODES), m_hwnd, DlgProcPOP3AccStatusOpt, NULL); - } - - void onClick_Add(CCtrlButton *) - { - DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr); - DlgShowAccount(0); - DlgEnableAccount(true); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE); - DlgSetItemTextW(m_hwnd, IDC_EDITNAME, TranslateT("New Account")); - - int index = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_ADDSTRING, 0, (LPARAM)TranslateT("New Account")); - if (index != CB_ERR && index != CB_ERRSPACE) - SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_SETCURSEL, index, (LPARAM)TranslateT("New Account")); - } - - void onClick_App(CCtrlButton *) - { - wchar_t filter[MAX_PATH]; - mir_snwprintf(filter, L"%s (*.exe;*.bat;*.cmd;*.com)%c*.exe;*.bat;*.cmd;*.com%c%s (*.*)%c*.*%c", - TranslateT("Executables"), 0, 0, TranslateT("All Files"), 0, 0); - - OPENFILENAME OFNStruct = {0}; - OFNStruct.lStructSize = sizeof(OPENFILENAME); - OFNStruct.hwndOwner = m_hwnd; - OFNStruct.lpstrFilter = filter; - OFNStruct.nFilterIndex = 1; - OFNStruct.nMaxFile = MAX_PATH; - OFNStruct.lpstrFile = new wchar_t[MAX_PATH]; - OFNStruct.lpstrFile[0] = (wchar_t)0; - OFNStruct.lpstrTitle = TranslateT("Select executable used for notification"); - OFNStruct.Flags = OFN_FILEMUSTEXIST | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR; - if (!GetOpenFileName(&OFNStruct)) { - if (CommDlgExtendedError()) - MessageBox(m_hwnd, TranslateT("Dialog box error"), TranslateT("Failed"), MB_OK); - } - else DlgSetItemTextW(m_hwnd, IDC_EDITAPP, OFNStruct.lpstrFile); - delete[] OFNStruct.lpstrFile; - } - - void onClick_Default(CCtrlButton *) - { - DlgShowAccount(0); - } - - void onClick_Del(CCtrlButton *) - { - GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput)); - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE); - if ((CB_ERR == (Result = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0))) - || (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput)))) - return; - - if (IDOK != MessageBox(m_hwnd, TranslateT("Do you really want to delete this account?"), TranslateT("Delete account confirmation"), MB_OKCANCEL | MB_ICONWARNING)) - return; - - DlgSetItemTextW(m_hwnd, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use.")); - - if (ActualAccount->hContact != NULL) - db_delete_contact(ActualAccount->hContact); - - CallService(MS_YAMN_DELETEACCOUNT, (WPARAM)POP3Plugin, (LPARAM)ActualAccount); - - // We can consider our account as deleted. - SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_DELETESTRING, Result, 0); - DlgSetItemText(m_hwnd, IDC_COMBOACCOUNT, nullptr); - DlgEnableAccount(false); - DlgShowAccount(0); - } - - void onClick_Reset(CCtrlButton *) - { - if (ActualAccount != nullptr) - ActualAccount->TimeLeft = ActualAccount->Interval; - } - - bool OnApply() override - { - char Text[MAX_PATH]; - wchar_t TextW[MAX_PATH]; - BOOL Translated, NewAcc = FALSE; - size_t Length, index; - - if (!GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, Text, _countof(Text))) - return false; - - BOOL Check = (IsDlgButtonChecked(m_hwnd, IDC_CHECK) == BST_CHECKED); - BOOL CheckSSL = (IsDlgButtonChecked(m_hwnd, IDC_CHECKSSL) == BST_CHECKED); - BOOL CheckNoTLS = (IsDlgButtonChecked(m_hwnd, IDC_CHECKNOTLS) == BST_CHECKED); - BOOL CheckAPOP = (IsDlgButtonChecked(m_hwnd, IDC_CHECKAPOP) == BST_CHECKED); - - BOOL CheckABody = (IsDlgButtonChecked(m_hwnd, IDC_AUTOBODY) == BST_CHECKED); - BOOL CheckMsg = (IsDlgButtonChecked(m_hwnd, IDC_CHECKMSG) == BST_CHECKED); - BOOL CheckSnd = (IsDlgButtonChecked(m_hwnd, IDC_CHECKSND) == BST_CHECKED); - BOOL CheckIco = (IsDlgButtonChecked(m_hwnd, IDC_CHECKICO) == BST_CHECKED); - - BOOL CheckApp = (IsDlgButtonChecked(m_hwnd, IDC_CHECKAPP) == BST_CHECKED); - BOOL CheckKBN = (IsDlgButtonChecked(m_hwnd, IDC_CHECKKBN) == BST_CHECKED); - BOOL CheckContact = (IsDlgButtonChecked(m_hwnd, IDC_CHECKCONTACT) == BST_CHECKED); - BOOL CheckContactNick = (IsDlgButtonChecked(m_hwnd, IDC_CHECKCONTACTNICK) == BST_CHECKED); - BOOL CheckContactNoEvent = (IsDlgButtonChecked(m_hwnd, IDC_CHECKCONTACTNOEVENT) == BST_CHECKED); - - BOOL CheckFSnd = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFSND) == BST_CHECKED); - BOOL CheckFMsg = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFMSG) == BST_CHECKED); - BOOL CheckFIco = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFICO) == BST_CHECKED); - - BOOL CheckNMsgP = (IsDlgButtonChecked(m_hwnd, IDC_CHECKNMSGP) == BST_CHECKED); - - UINT Port = GetDlgItemInt(m_hwnd, IDC_EDITPORT, &Translated, FALSE); - if (!Translated) { - MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK); - SetFocus(GetDlgItem(m_hwnd, IDC_EDITPORT)); - return false; - } - - UINT Interval = GetDlgItemInt(m_hwnd, IDC_EDITINTERVAL, &Translated, FALSE); - if (!Translated) { - MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK); - SetFocus(GetDlgItem(m_hwnd, IDC_EDITINTERVAL)); - return false; - } - - GetDlgItemTextA(m_hwnd, IDC_EDITAPP, Text, _countof(Text)); - if (CheckApp && !(Length = mir_strlen(Text))) { - MessageBox(m_hwnd, TranslateT("Please select application to run"), TranslateT("Input error"), MB_OK); - return false; - } - - GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, Text, _countof(Text)); - if (!(Length = mir_strlen(Text))) { - GetDlgItemTextA(m_hwnd, IDC_EDITNAME, Text, _countof(Text)); - if (!(Length = mir_strlen(Text))) - return false; - } - - DlgSetItemTextW(m_hwnd, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use.")); - - if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)Text))) { - NewAcc = TRUE; - WaitToWriteSO(POP3Plugin->AccountBrowserSO); - if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_GETNEXTFREEACCOUNT, (WPARAM)POP3Plugin, (LPARAM)YAMN_ACCOUNTVERSION))) { - WriteDoneSO(POP3Plugin->AccountBrowserSO); - MessageBox(m_hwnd, TranslateT("Cannot allocate memory space for new account"), TranslateT("Memory error"), MB_OK); - return false; - } - DlgEnableAccount(true); - } - else { // We have to get full access to AccountBrowser, so other iterating thrads cannot get new account until new account is right set - WaitToWriteSO(POP3Plugin->AccountBrowserSO); - } - - if (WAIT_OBJECT_0 != WaitToWrite(ActualAccount)) - WriteDoneSO(POP3Plugin->AccountBrowserSO); - - GetDlgItemTextA(m_hwnd, IDC_EDITNAME, Text, _countof(Text)); - if (!(Length = mir_strlen(Text))) - return false; - if (nullptr != ActualAccount->Name) - delete[] ActualAccount->Name; - ActualAccount->Name = new char[mir_strlen(Text) + 1]; - mir_strcpy(ActualAccount->Name, Text); - - GetDlgItemTextA(m_hwnd, IDC_EDITSERVER, Text, _countof(Text)); - if (nullptr != ActualAccount->Server->Name) - delete[] ActualAccount->Server->Name; - ActualAccount->Server->Name = new char[mir_strlen(Text) + 1]; - mir_strcpy(ActualAccount->Server->Name, Text); - - GetDlgItemTextA(m_hwnd, IDC_EDITLOGIN, Text, _countof(Text)); - if (nullptr != ActualAccount->Server->Login) - delete[] ActualAccount->Server->Login; - ActualAccount->Server->Login = new char[mir_strlen(Text) + 1]; - mir_strcpy(ActualAccount->Server->Login, Text); - - GetDlgItemTextA(m_hwnd, IDC_EDITPASS, Text, _countof(Text)); - if (nullptr != ActualAccount->Server->Passwd) - delete[] ActualAccount->Server->Passwd; - ActualAccount->Server->Passwd = new char[mir_strlen(Text) + 1]; - mir_strcpy(ActualAccount->Server->Passwd, Text); - - GetDlgItemTextW(m_hwnd, IDC_EDITAPP, TextW, _countof(TextW)); - if (nullptr != ActualAccount->NewMailN.App) - delete[] ActualAccount->NewMailN.App; - ActualAccount->NewMailN.App = new wchar_t[mir_wstrlen(TextW) + 1]; - mir_wstrcpy(ActualAccount->NewMailN.App, TextW); - - GetDlgItemTextW(m_hwnd, IDC_EDITAPPPARAM, TextW, _countof(TextW)); - if (nullptr != ActualAccount->NewMailN.AppParam) - delete[] ActualAccount->NewMailN.AppParam; - ActualAccount->NewMailN.AppParam = new wchar_t[mir_wstrlen(TextW) + 1]; - mir_wstrcpy(ActualAccount->NewMailN.AppParam, TextW); - - ActualAccount->Server->Port = Port; - ActualAccount->Interval = Interval * 60; - - if (CB_ERR == (index = SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_GETCURSEL, 0, 0))) - index = CPDEFINDEX; - ActualAccount->CP = CodePageNamesSupp[index].CP; - - if (NewAcc) - ActualAccount->TimeLeft = Interval * 60; - - BOOL CheckStart = (IsDlgButtonChecked(m_hwnd, IDC_CHECKSTART) == BST_CHECKED); - BOOL CheckForce = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFORCE) == BST_CHECKED); - - ActualAccount->Flags = - (Check ? YAMN_ACC_ENA : 0) | - (CheckSSL ? YAMN_ACC_SSL23 : 0) | - (CheckNoTLS ? YAMN_ACC_NOTLS : 0) | - (CheckAPOP ? YAMN_ACC_APOP : 0) | - (CheckABody ? YAMN_ACC_BODY : 0) | - (ActualAccount->Flags & YAMN_ACC_POPN); - - ActualAccount->StatusFlags &= 0xFFFF; - ActualAccount->StatusFlags |= - (CheckStart ? YAMN_ACC_STARTS : 0) | - (CheckForce ? YAMN_ACC_FORCE : 0); - - ActualAccount->NewMailN.Flags = - (CheckSnd ? YAMN_ACC_SND : 0) | - (CheckMsg ? YAMN_ACC_MSG : 0) | - (CheckIco ? YAMN_ACC_ICO : 0) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_POP) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_POPC) | - (CheckApp ? YAMN_ACC_APP : 0) | - (CheckKBN ? YAMN_ACC_KBN : 0) | - (CheckContact ? YAMN_ACC_CONT : 0) | - (CheckContactNick ? YAMN_ACC_CONTNICK : 0) | - (CheckContactNoEvent ? YAMN_ACC_CONTNOEVENT : 0) | - YAMN_ACC_MSGP; //this is default: when new mail arrives and window was displayed, leave it displayed. - - ActualAccount->NoNewMailN.Flags = - (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POP) | - (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC) | - (CheckNMsgP ? YAMN_ACC_MSGP : 0); - - ActualAccount->BadConnectN.Flags = - (CheckFSnd ? YAMN_ACC_SND : 0) | - (CheckFMsg ? YAMN_ACC_MSG : 0) | - (CheckFIco ? YAMN_ACC_ICO : 0) | - (ActualAccount->BadConnectN.Flags & YAMN_ACC_POP) | - (ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC); - - WriteDone(ActualAccount); - WriteDoneSO(POP3Plugin->AccountBrowserSO); - - EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), TRUE); - - DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr); - - index = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0); - - HPOP3ACCOUNT temp = ActualAccount; - - SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_RESETCONTENT, 0, 0); - if (POP3Plugin->FirstAccount != nullptr) - for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next) - if (ActualAccount->Name != nullptr) - SendDlgItemMessageA(m_hwnd, IDC_COMBOACCOUNT, CB_ADDSTRING, 0, (LPARAM)ActualAccount->Name); - - ActualAccount = temp; - SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_SETCURSEL, (WPARAM)index, (LPARAM)ActualAccount->Name); - - WritePOP3Accounts(); - RefreshContact(); - return TRUE; - } -}; - -///////////////////////////////////////////////////////////////////////////////////////// -// Popup options - -class CPopupOptsDlg : public CBaseOptionsDlg -{ - HPOP3ACCOUNT ActualAccount = nullptr; - UCHAR ActualStatus; - - CCtrlCombo cmbAccount, cmbCP; - CCtrlCheck chkCol, chkFcol, chkNcol, chkPop, chkFpop, chkNpop; - CCtrlButton btnPreview; - - void DlgShowAccountPopup() - { - if (ActualAccount) { - WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread - SetDlgItemInt(m_hwnd, IDC_EDITPOPS, ActualAccount->NewMailN.PopupTime, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, ActualAccount->NoNewMailN.PopupTime, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, ActualAccount->BadConnectN.PopupTime, FALSE); - - chkPop.SetState(ActualAccount->NewMailN.Flags & YAMN_ACC_POP); - chkCol.SetState(ActualAccount->NewMailN.Flags & YAMN_ACC_POPC); - chkNpop.SetState(ActualAccount->NoNewMailN.Flags & YAMN_ACC_POP); - chkNcol.SetState(ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC); - chkFpop.SetState(ActualAccount->BadConnectN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED); - chkFcol.SetState(ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC); - CheckDlgButton(m_hwnd, IDC_RADIOPOPN, ActualAccount->Flags & YAMN_ACC_POPN ? BST_CHECKED : BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_RADIOPOP1, ActualAccount->Flags & YAMN_ACC_POPN ? BST_UNCHECKED : BST_CHECKED); - ReadDone(ActualAccount); - } - else { // default - SetDlgItemInt(m_hwnd, IDC_EDITPOPS, 0, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, 0, FALSE); - SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, 0, FALSE); - chkPop.SetState(true); - chkCol.SetState(true); - chkNpop.SetState(true); - chkNcol.SetState(true); - chkFpop.SetState(true); - chkFcol.SetState(true); - CheckDlgButton(m_hwnd, IDC_RADIOPOPN, BST_UNCHECKED); - CheckDlgButton(m_hwnd, IDC_RADIOPOP1, BST_CHECKED); - } - } - - void DlgEnableAccountPopup(bool bEnable) - { - chkPop.Enable(bEnable); - chkCol.Enable(chkPop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPOPS), chkPop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPB), chkCol.IsChecked() && chkPop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPT), chkCol.IsChecked() && chkPop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOPN), chkPop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOP1), chkPop.IsChecked() && bEnable); - - chkNpop.Enable(bEnable); - chkNcol.Enable(chkNpop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITNPOPS), chkNpop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPNB), chkNcol.IsChecked() && chkNpop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPNT), chkNcol.IsChecked() && chkNpop.IsChecked() && bEnable); - - chkFpop.Enable(bEnable); - chkFcol.Enable(chkFpop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITFPOPS), chkFpop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPFB), chkFcol.IsChecked() && chkFpop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPFT), chkFcol.IsChecked() && chkFpop.IsChecked() && bEnable); - EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKAPOP), bEnable); - } - - void DlgShowAccountColors() - { - WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread - - if (ActualAccount->NewMailN.Flags & YAMN_ACC_POPC) { - SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NewMailN.PopupB); - SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NewMailN.PopupT); - } - else { - SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE)); - SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_WINDOWTEXT)); - } - if (ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC) { - SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->BadConnectN.PopupB); - SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->BadConnectN.PopupT); - } - else { - SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE)); - SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_WINDOWTEXT)); - } - if (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC) { - SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NoNewMailN.PopupB); - SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NoNewMailN.PopupT); - } - else { - SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE)); - SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_WINDOWTEXT)); - } - - ReadDone(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread - } - -public: - CPopupOptsDlg() : - CBaseOptionsDlg(IDD_POP3ACCOUNTPOPUP), - cmbCP(this, IDC_COMBOCP), - chkCol(this, IDC_CHECKCOL), - chkPop(this, IDC_CHECKPOP), - chkFcol(this, IDC_CHECKFCOL), - chkFpop(this, IDC_CHECKFPOP), - chkNcol(this, IDC_CHECKNCOL), - chkNpop(this, IDC_CHECKNPOP), - btnPreview(this, IDC_PREVIEW), - cmbAccount(this, IDC_COMBOACCOUNT) - { - chkPop.OnChange = Callback(this, &CPopupOptsDlg::onChange_Pop); - chkFpop.OnChange = Callback(this, &CPopupOptsDlg::onChange_Fpop); - chkNpop.OnChange = Callback(this, &CPopupOptsDlg::onChange_Npop); - chkCol.OnChange = chkFcol.OnChange = chkNcol.OnChange = Callback(this, &CPopupOptsDlg::onChange_Col); - - cmbCP.OnSelChanged = Callback(this, &CPopupOptsDlg::onSelChange_CP); - - btnPreview.OnClick = Callback(this, &CPopupOptsDlg::onClick_Preview); - - cmbAccount.OnKillFocus = Callback(this, &CPopupOptsDlg::onKillFocus_Account); - cmbAccount.OnSelChanged = Callback(this, &CPopupOptsDlg::onSelChange_Account); - } - - bool OnInitDialog() override - { - WindowList_Add(pYAMNVar->MessageWnds, m_hwnd); - - DlgEnableAccountPopup(false); - DlgShowAccountPopup(); - - WaitToReadSO(POP3Plugin->AccountBrowserSO); - - if (POP3Plugin->FirstAccount != nullptr) - for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next) - if (ActualAccount->Name != nullptr) - cmbAccount.AddStringA(ActualAccount->Name); - - ReadDoneSO(POP3Plugin->AccountBrowserSO); - ActualAccount = nullptr; - cmbAccount.SetCurSel(0); - return true; - } - - void OnDestroy() override - { - WindowList_Remove(pYAMNVar->MessageWnds, m_hwnd); - } - - void onKillFocus_Account(CCtrlCombo *) - { - GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput)); - if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput))) { - DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr); - if (mir_strlen(DlgInput)) - DlgEnableAccountPopup(true); - else - DlgEnableAccountPopup(false); - } - else { - DlgShowAccount(ActualAccount); - DlgShowAccountColors(); - DlgEnableAccountPopup(true); - } - } - - void onSelChange_Account(CCtrlCombo *) - { - int Result = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0); - if (CB_ERR != Result) - SendDlgItemMessageA(m_hwnd, IDC_COMBOACCOUNT, CB_GETLBTEXT, (WPARAM)Result, (LPARAM)DlgInput); - if ((Result == CB_ERR) || (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput)))) { - DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr); - } - else { - DlgShowAccount(ActualAccount); - DlgShowAccountColors(); - DlgEnableAccountPopup(true); - } - } - - void onSelChange_CP(CCtrlCombo *) - { - int sel = SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_GETCURSEL, 0, 0); - CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[sel].CP, 0, &info); - DlgSetItemTextW(m_hwnd, IDC_STSTATUS, info.CodePageName); - } - - void onChange_Col(CCtrlCheck *) - { - EnableWindow(GetDlgItem(m_hwnd, IDC_CPB), chkCol.IsChecked() && chkPop.IsChecked()); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPT), chkCol.IsChecked() && chkPop.IsChecked()); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPNB), chkNcol.IsChecked() && chkNpop.IsChecked()); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPNT), chkNcol.IsChecked() && chkNpop.IsChecked()); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPFB), chkFcol.IsChecked() && chkFpop.IsChecked()); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPFT), chkFcol.IsChecked() && chkFpop.IsChecked()); - } - - void onClick_Preview(CCtrlButton *) - { - if (chkPop.IsChecked()) { - POPUPDATAW Tester = {}; - Tester.lchIcon = g_plugin.getIcon(IDI_NEWMAIL); - mir_wstrncpy(Tester.lpwzContactName, TranslateT("Account Test"), MAX_CONTACTNAME); - mir_wstrncpy(Tester.lpwzText, TranslateT("You have N new mail messages"), MAX_SECONDLINE); - if (chkCol.IsChecked()) { - Tester.colorBack = SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_GETCOLOUR, 0, 0); - Tester.colorText = SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_GETCOLOUR, 0, 0); - } - else { - Tester.colorBack = GetSysColor(COLOR_BTNFACE); - Tester.colorText = GetSysColor(COLOR_WINDOWTEXT); - } - PUAddPopupW(&Tester); - } - - if (chkFpop.IsChecked()) { - POPUPDATAW TesterF = {}; - TesterF.lchIcon = g_plugin.getIcon(IDI_BADCONNECT); - mir_wstrncpy(TesterF.lpwzContactName, TranslateT("Account Test (failed)"), MAX_CONTACTNAME); - mir_wstrncpy(TesterF.lpwzText, TranslateT("Connection failed message"), MAX_SECONDLINE); - if (chkFcol.IsChecked()) { - TesterF.colorBack = SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_GETCOLOUR, 0, 0); - TesterF.colorText = SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_GETCOLOUR, 0, 0); - } - else { - TesterF.colorBack = GetSysColor(COLOR_BTNFACE); - TesterF.colorText = GetSysColor(COLOR_WINDOWTEXT); - } - PUAddPopupW(&TesterF); - } - - if (chkNpop.IsChecked()) { - POPUPDATAW TesterN = {}; - TesterN.lchIcon = g_plugin.getIcon(IDI_LAUNCHAPP); - mir_wstrncpy(TesterN.lpwzContactName, TranslateT("Account Test"), MAX_CONTACTNAME); - mir_wstrncpy(TesterN.lpwzText, TranslateT("No new mail message"), MAX_SECONDLINE); - if (chkNcol.IsChecked()) { - TesterN.colorBack = SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_GETCOLOUR, 0, 0); - TesterN.colorText = SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_GETCOLOUR, 0, 0); - } - else { - TesterN.colorBack = GetSysColor(COLOR_BTNFACE); - TesterN.colorText = GetSysColor(COLOR_WINDOWTEXT); - } - PUAddPopupW(&TesterN); - } - } - - void onChange_Pop(CCtrlCheck *) - { - bool bEnabled = chkPop.IsChecked(); - chkCol.Enable(bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPB), chkCol.IsChecked() && bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPT), chkCol.IsChecked() && bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOPN), bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOP1), bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPOPS), bEnabled); - } - - void onChange_Fpop(CCtrlCheck *) - { - bool bEnabled = chkFpop.IsChecked(); - chkFcol.Enable(bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPFB), chkFcol.IsChecked() && bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPFT), chkFcol.IsChecked() && bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITFPOPS), bEnabled); - } - - void onChange_Npop(CCtrlCheck *) - { - bool bEnabled = chkNpop.IsChecked(); - chkNcol.Enable(bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPNB), chkNcol.IsChecked() && bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_CPNT), chkNcol.IsChecked() && bEnabled); - EnableWindow(GetDlgItem(m_hwnd, IDC_EDITNPOPS), bEnabled); - } - - bool OnApply() override - { - wchar_t Text[MAX_PATH]; - if (!GetDlgItemText(m_hwnd, IDC_COMBOACCOUNT, Text, _countof(Text))) - return false; - - BOOL CheckPopup = chkPop.IsChecked(); - BOOL CheckPopupW = chkCol.IsChecked(); - - BOOL CheckFPopup = chkFpop.IsChecked(); - BOOL CheckFPopupW = chkFcol.IsChecked(); - - BOOL CheckNPopup = chkNpop.IsChecked(); - BOOL CheckNPopupW = chkNcol.IsChecked(); - - BOOL CheckPopN = (IsDlgButtonChecked(m_hwnd, IDC_RADIOPOPN) == BST_CHECKED); - - BOOL Translated; - UINT Time = GetDlgItemInt(m_hwnd, IDC_EDITPOPS, &Translated, FALSE); - if (!Translated) { - MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK); - SetFocus(GetDlgItem(m_hwnd, IDC_EDITPOPS)); - return false; - } - UINT TimeN = GetDlgItemInt(m_hwnd, IDC_EDITNPOPS, &Translated, FALSE); - if (!Translated) { - MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK); - SetFocus(GetDlgItem(m_hwnd, IDC_EDITNPOPS)); - return false; - } - UINT TimeF = GetDlgItemInt(m_hwnd, IDC_EDITFPOPS, &Translated, FALSE); - if (!Translated) { - MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK); - SetFocus(GetDlgItem(m_hwnd, IDC_EDITFPOPS)); - return false; - } - - DlgSetItemTextW(m_hwnd, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use.")); - - ActualAccount->Flags = - (ActualAccount->Flags & YAMN_ACC_ENA) | - (ActualAccount->Flags & YAMN_ACC_SSL23) | - (ActualAccount->Flags & YAMN_ACC_NOTLS) | - (ActualAccount->Flags & YAMN_ACC_APOP) | - (ActualAccount->Flags & YAMN_ACC_BODY) | - (CheckPopN ? YAMN_ACC_POPN : 0); - - ActualAccount->NewMailN.Flags = - (ActualAccount->NewMailN.Flags & YAMN_ACC_SND) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_MSG) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_ICO) | - (CheckPopup ? YAMN_ACC_POP : 0) | - (CheckPopupW ? YAMN_ACC_POPC : 0) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_APP) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_KBN) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_CONT) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_CONTNICK) | - (ActualAccount->NewMailN.Flags & YAMN_ACC_CONTNOEVENT) | - YAMN_ACC_MSGP; - - ActualAccount->NoNewMailN.Flags = - (CheckNPopup ? YAMN_ACC_POP : 0) | - (CheckNPopupW ? YAMN_ACC_POPC : 0) | - (ActualAccount->NoNewMailN.Flags & YAMN_ACC_MSGP); - - ActualAccount->BadConnectN.Flags = - (ActualAccount->BadConnectN.Flags & YAMN_ACC_SND) | - (ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG) | - (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) | - (CheckFPopup ? YAMN_ACC_POP : 0) | - (CheckFPopupW ? YAMN_ACC_POPC : 0); - - ActualAccount->NewMailN.PopupB = SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_GETCOLOUR, 0, 0); - ActualAccount->NewMailN.PopupT = SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_GETCOLOUR, 0, 0); - ActualAccount->NewMailN.PopupTime = Time; - - ActualAccount->NoNewMailN.PopupB = SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_GETCOLOUR, 0, 0); - ActualAccount->NoNewMailN.PopupT = SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_GETCOLOUR, 0, 0); - ActualAccount->NoNewMailN.PopupTime = TimeN; - - ActualAccount->BadConnectN.PopupB = SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_GETCOLOUR, 0, 0); - ActualAccount->BadConnectN.PopupT = SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_GETCOLOUR, 0, 0); - ActualAccount->BadConnectN.PopupTime = TimeF; - - WriteDone(ActualAccount); - WriteDoneSO(POP3Plugin->AccountBrowserSO); - - WritePOP3Accounts(); - RefreshContact(); - return TRUE; - } -}; - -//-------------------------------------------------------------------------------------------------- - -int YAMNOptInitSvc(WPARAM wParam, LPARAM) -{ - OPTIONSDIALOGPAGE odp = {}; - odp.szGroup.a = LPGEN("Network"); - odp.szTitle.a = LPGEN("YAMN"); - odp.flags = ODPF_BOLDGROUPS; - - odp.szTab.a = LPGEN("Accounts"); - odp.pDialog = new CAccOptDlg(); - g_plugin.addOptions(wParam, &odp); - - odp.szTab.a = LPGEN("General"); - odp.pDialog = new CGeneralOptDlg(); - g_plugin.addOptions(wParam, &odp); - - odp.szGroup.a = LPGEN("Popups"); - odp.szTab.a = LPGEN("YAMN"); - odp.pDialog = new CPopupOptsDlg(); - g_plugin.addOptions(wParam, &odp); - return 0; -} +/*
+ * This code implements POP3 options window handling
+ *
+ * (c) majvan 2002-2003
+*/
+
+#include "../../stdafx.h"
+
+//--------------------------------------------------------------------------------------------------
+
+static char DlgInput[MAX_PATH];
+
+static BOOL DlgSetItemText(HWND hDlg, WPARAM wParam, const char *str)
+{
+ if (str == nullptr)
+ SetDlgItemTextA(hDlg, wParam, "");
+ else
+ SetDlgItemTextA(hDlg, wParam, str);
+ return TRUE;
+}
+
+static BOOL DlgSetItemTextW(HWND hDlg, WPARAM wParam, const wchar_t *str)
+{
+ if (str == nullptr)
+ SetDlgItemTextW(hDlg, wParam, L"");
+ else
+ SetDlgItemTextW(hDlg, wParam, str);
+ return TRUE;
+}
+
+struct CBaseOptionsDlg : public CDlgBase
+{
+ CBaseOptionsDlg(int iDlgId) :
+ CDlgBase(g_plugin, iDlgId)
+ {}
+
+ void DlgShowAccount(HPOP3ACCOUNT pAccount)
+ {
+ int i;
+
+ if (pAccount) {
+ // we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread
+ WaitToRead(pAccount);
+
+ DlgSetItemText(m_hwnd, IDC_EDITSERVER, pAccount->Server->Name);
+ DlgSetItemText(m_hwnd, IDC_EDITNAME, pAccount->Name);
+ DlgSetItemText(m_hwnd, IDC_EDITLOGIN, pAccount->Server->Login);
+ DlgSetItemText(m_hwnd, IDC_EDITPASS, pAccount->Server->Passwd);
+ DlgSetItemTextW(m_hwnd, IDC_EDITAPP, pAccount->NewMailN.App);
+ DlgSetItemTextW(m_hwnd, IDC_EDITAPPPARAM, pAccount->NewMailN.AppParam);
+ SetDlgItemInt(m_hwnd, IDC_EDITPORT, pAccount->Server->Port, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITINTERVAL, pAccount->Interval / 60, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITPOPS, pAccount->NewMailN.PopupTime, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, pAccount->NoNewMailN.PopupTime, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, pAccount->BadConnectN.PopupTime, FALSE);
+ for (i = 0; i <= CPLENSUPP; i++)
+ if ((i < CPLENSUPP) && (CodePageNamesSupp[i].CP == pAccount->CP)) {
+ SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)i, 0);
+ break;
+ }
+
+ if (i == CPLENSUPP)
+ SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)CPDEFINDEX, 0);
+
+ CheckDlgButton(m_hwnd, IDC_CHECK, pAccount->Flags & YAMN_ACC_ENA ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKSND, pAccount->NewMailN.Flags & YAMN_ACC_SND ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKMSG, pAccount->NewMailN.Flags & YAMN_ACC_MSG ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKICO, pAccount->NewMailN.Flags & YAMN_ACC_ICO ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKPOP, pAccount->NewMailN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKCOL, pAccount->NewMailN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKAPP, pAccount->NewMailN.Flags & YAMN_ACC_APP ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKKBN, pAccount->NewMailN.Flags & YAMN_ACC_KBN ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKNPOP, pAccount->NoNewMailN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKNCOL, pAccount->NoNewMailN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKNMSGP, pAccount->NoNewMailN.Flags & YAMN_ACC_MSGP ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFSND, pAccount->BadConnectN.Flags & YAMN_ACC_SND ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFMSG, pAccount->BadConnectN.Flags & YAMN_ACC_MSG ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFICO, pAccount->BadConnectN.Flags & YAMN_ACC_ICO ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFPOP, pAccount->BadConnectN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFCOL, pAccount->BadConnectN.Flags & YAMN_ACC_POPC ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOPN, pAccount->Flags & YAMN_ACC_POPN ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOP1, pAccount->Flags & YAMN_ACC_POPN ? BST_UNCHECKED : BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKSSL, pAccount->Flags & YAMN_ACC_SSL23 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKNOTLS, pAccount->Flags & YAMN_ACC_NOTLS ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKAPOP, pAccount->Flags & YAMN_ACC_APOP ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_AUTOBODY, pAccount->Flags & YAMN_ACC_BODY ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKSTART, pAccount->StatusFlags & YAMN_ACC_STARTS ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFORCE, pAccount->StatusFlags & YAMN_ACC_FORCE ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKCONTACT, pAccount->NewMailN.Flags & YAMN_ACC_CONT ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKCONTACTNICK, pAccount->NewMailN.Flags & YAMN_ACC_CONTNICK ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKCONTACTNOEVENT, pAccount->NewMailN.Flags & YAMN_ACC_CONTNOEVENT ? BST_CHECKED : BST_UNCHECKED);
+
+ wchar_t accstatus[256];
+ GetAccountStatus(pAccount, accstatus);
+ SetDlgItemText(m_hwnd, IDC_STSTATUS, accstatus);
+ ReadDone(pAccount);
+ }
+ else {
+ DlgSetItemText(m_hwnd, IDC_EDITSERVER, nullptr);
+ DlgSetItemText(m_hwnd, IDC_EDITNAME, nullptr);
+ DlgSetItemText(m_hwnd, IDC_EDITLOGIN, nullptr);
+ DlgSetItemText(m_hwnd, IDC_EDITPASS, nullptr);
+ DlgSetItemText(m_hwnd, IDC_EDITAPP, nullptr);
+ DlgSetItemText(m_hwnd, IDC_EDITAPPPARAM, nullptr);
+ DlgSetItemText(m_hwnd, IDC_STTIMELEFT, nullptr);
+ SetDlgItemInt(m_hwnd, IDC_EDITPORT, 110, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITINTERVAL, 30, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITPOPS, 0, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, 0, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, 0, FALSE);
+ SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_SETCURSEL, (WPARAM)CPDEFINDEX, 0);
+ CheckDlgButton(m_hwnd, IDC_CHECK, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKSND, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKMSG, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKICO, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKPOP, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKCOL, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKAPP, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFSND, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFMSG, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFICO, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFPOP, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFCOL, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKSTART, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKFORCE, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOPN, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOP1, BST_CHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKSSL, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKNOTLS, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKAPOP, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_AUTOBODY, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CHECKCONTACT, BST_CHECKED);
+
+ SetDlgItemText(m_hwnd, IDC_STSTATUS, TranslateT("No account selected"));
+ }
+ }
+};
+
+//=======================================================================================
+// General options dialog
+
+struct CGeneralOptDlg : public CBaseOptionsDlg
+{
+ CGeneralOptDlg() :
+ CBaseOptionsDlg(IDD_YAMNOPT)
+ {}
+
+ bool OnInitDialog() override
+ {
+ CheckDlgButton(m_hwnd, IDC_CHECKTTB, g_plugin.getByte(YAMN_TTBFCHECK, 1) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_LONGDATE, (optDateTime & SHOWDATELONG) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_SMARTDATE, (optDateTime & SHOWDATENOTODAY) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_NOSECONDS, (optDateTime & SHOWDATENOSECONDS) ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_CLOSEONDELETE, g_plugin.getByte(YAMN_CLOSEDELETE, 0) ? BST_CHECKED : BST_UNCHECKED);
+ return true;
+ }
+
+ bool OnApply() override
+ {
+ g_plugin.setByte(YAMN_CLOSEDELETE, IsDlgButtonChecked(m_hwnd, IDC_CLOSEONDELETE));
+ g_plugin.setByte(YAMN_TTBFCHECK, IsDlgButtonChecked(m_hwnd, IDC_CHECKTTB));
+
+ AddTopToolbarIcon(0, 0);
+
+ optDateTime = 0;
+ if (IsDlgButtonChecked(m_hwnd, IDC_LONGDATE)) optDateTime |= SHOWDATELONG;
+ if (IsDlgButtonChecked(m_hwnd, IDC_SMARTDATE)) optDateTime |= SHOWDATENOTODAY;
+ if (IsDlgButtonChecked(m_hwnd, IDC_NOSECONDS)) optDateTime |= SHOWDATENOSECONDS;
+ g_plugin.setByte(YAMN_DBTIMEOPTIONS, optDateTime);
+ return true;
+ }
+};
+
+//--------------------------------------------------------------------------------------------------
+
+static int g_iStatusControls[] = {IDC_CHECKST0, IDC_CHECKST1, IDC_CHECKST2, IDC_CHECKST3, IDC_CHECKST4, IDC_CHECKST5, IDC_CHECKST6, IDC_CHECKST7};
+
+static BOOL DlgShowAccountStatus(HWND hDlg, HPOP3ACCOUNT ActualAccount)
+{
+ if (ActualAccount) {
+ WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread
+
+ CheckDlgButton(hDlg, IDC_CHECKST0, ActualAccount->StatusFlags & YAMN_ACC_ST0 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST1, ActualAccount->StatusFlags & YAMN_ACC_ST1 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST2, ActualAccount->StatusFlags & YAMN_ACC_ST2 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST3, ActualAccount->StatusFlags & YAMN_ACC_ST3 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST4, ActualAccount->StatusFlags & YAMN_ACC_ST4 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST5, ActualAccount->StatusFlags & YAMN_ACC_ST5 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST6, ActualAccount->StatusFlags & YAMN_ACC_ST6 ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST7, ActualAccount->StatusFlags & YAMN_ACC_ST7 ? BST_CHECKED : BST_UNCHECKED);
+
+ ReadDone(ActualAccount);
+ }
+ else {
+ CheckDlgButton(hDlg, IDC_CHECKST0, BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST1, BST_CHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST2, BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST3, BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST4, BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST5, BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST6, BST_UNCHECKED);
+ CheckDlgButton(hDlg, IDC_CHECKST7, BST_CHECKED);
+ }
+ return TRUE;
+}
+
+static INT_PTR CALLBACK DlgProcPOP3AccStatusOpt(HWND hDlg, UINT msg, WPARAM wParam, LPARAM)
+{
+ static HPOP3ACCOUNT ActualAccount;
+ switch (msg) {
+ case WM_INITDIALOG:
+ ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput);
+ if (ActualAccount != nullptr) {
+ DlgShowAccountStatus(hDlg, ActualAccount);
+ for (auto &it : g_iStatusControls)
+ EnableWindow(GetDlgItem(hDlg, it), true);
+ }
+ else {
+ for (auto &it : g_iStatusControls)
+ CheckDlgButton(hDlg, it, BST_CHECKED);
+ }
+ TranslateDialogDefault(hDlg);
+ SendMessage(GetParent(hDlg), PSM_UNCHANGED, (WPARAM)hDlg, 0);
+ return TRUE;
+
+ case WM_COMMAND:
+ switch (LOWORD(wParam)) {
+ case IDCANCEL:
+ EndDialog(hDlg, 0);
+ DestroyWindow(hDlg);
+ break;
+
+ case IDOK:
+ int iShift = 1;
+ ActualAccount->StatusFlags = 0;
+ for (auto &it : g_iStatusControls) {
+ if (IsDlgButtonChecked(hDlg, it))
+ ActualAccount->StatusFlags |= iShift;
+ iShift <<= 1;
+ }
+
+ WindowList_BroadcastAsync(YAMNVar.MessageWnds, WM_YAMN_CHANGESTATUSOPTION, 0, 0);
+ EndDialog(hDlg, 0);
+ DestroyWindow(hDlg);
+ break;
+ }
+ }
+ return FALSE;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Account options
+
+class CAccOptDlg : public CBaseOptionsDlg
+{
+ INT_PTR Result;
+ UCHAR ActualStatus;
+ HPOP3ACCOUNT ActualAccount = nullptr;
+
+ CCtrlCheck chkContact, chkSsl, chkApp;
+ CCtrlCombo cmbAccount, cmbCP;
+ CCtrlButton btnStatus, btnAdd, btnDel, btnApp, btnDefault, btnReset;
+
+ void DlgEnableAccount(bool bEnable)
+ {
+ cmbAccount.Enable(POP3Plugin->FirstAccount != nullptr);
+
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECK), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITSERVER), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITNAME), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPORT), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITLOGIN), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPASS), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITINTERVAL), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKSND), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKMSG), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKICO), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKAPP), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKKBN), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNAPP), chkApp.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPP), chkApp.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPPPARAM), chkApp.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKNMSGP), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFSND), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFMSG), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFICO), bEnable);
+
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKSTART), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKFORCE), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_COMBOCP), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_STTIMELEFT), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNRESET), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEFAULT), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNSTATUS), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKSSL), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKAPOP), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKNOTLS), chkSsl.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_AUTOBODY), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACT), bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNICK), chkContact.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNOEVENT), chkContact.IsChecked() && bEnable);
+ }
+
+public:
+ CAccOptDlg() :
+ CBaseOptionsDlg(IDD_POP3ACCOUNTOPT),
+ cmbCP(this, IDC_COMBOCP),
+ btnAdd(this, IDC_BTNADD),
+ btnApp(this, IDC_BTNAPP),
+ btnDel(this, IDC_BTNDEL),
+ chkApp(this, IDC_CHECKAPP),
+ chkSsl(this, IDC_CHECKSSL),
+ btnReset(this, IDC_BTNRESET),
+ btnStatus(this, IDC_BTNSTATUS),
+ btnDefault(this, IDC_BTNDEFAULT),
+ cmbAccount(this, IDC_COMBOACCOUNT),
+ chkContact(this, IDC_CHECKCONTACT)
+ {
+ cmbCP.OnSelChanged = Callback(this, &CAccOptDlg::onSelChange_CP);
+
+ cmbAccount.OnChange = Callback(this, &CAccOptDlg::onChange_Account);
+ cmbAccount.OnKillFocus = Callback(this, &CAccOptDlg::onKillFocus_Account);
+ cmbAccount.OnSelChanged = Callback(this, &CAccOptDlg::onSelChange_Account);
+
+ chkApp.OnChange = Callback(this, &CAccOptDlg::onChangeApp);
+ chkSsl.OnChange = Callback(this, &CAccOptDlg::onChangeSsl);
+ chkContact.OnChange = Callback(this, &CAccOptDlg::onChangeContact);
+
+ btnAdd.OnClick = Callback(this, &CAccOptDlg::onClick_Add);
+ btnDel.OnClick = Callback(this, &CAccOptDlg::onClick_Del);
+ btnApp.OnClick = Callback(this, &CAccOptDlg::onClick_App);
+ btnReset.OnClick = Callback(this, &CAccOptDlg::onClick_Reset);
+ btnStatus.OnClick = Callback(this, &CAccOptDlg::onClick_Status);
+ btnDefault.OnClick = Callback(this, &CAccOptDlg::onClick_Default);
+ }
+
+ bool OnInitDialog() override
+ {
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE);
+
+ DlgEnableAccount(false);
+ DlgShowAccount(0);
+
+ // Fill accounts
+ WaitToReadSO(POP3Plugin->AccountBrowserSO);
+
+ for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next)
+ if (ActualAccount->Name != nullptr)
+ cmbAccount.AddStringA(ActualAccount->Name);
+ cmbAccount.SetCurSel(0);
+
+ ReadDoneSO(POP3Plugin->AccountBrowserSO);
+
+ // Fill code pages
+ cmbCP.AddString(TranslateT("Default"));
+ for (int i = 1; i < CPLENSUPP; i++) {
+ CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[i].CP, 0, &info);
+ size_t len = mir_wstrlen(info.CodePageName + 7);
+ info.CodePageName[len + 6] = 0;
+ cmbCP.AddString(info.CodePageName + 7);
+ }
+ cmbCP.SetCurSel(0);
+
+ ActualAccount = nullptr;
+ SendMessage(GetParent(m_hwnd), PSM_UNCHANGED, (WPARAM)m_hwnd, 0);
+
+ WindowList_Add(pYAMNVar->MessageWnds, m_hwnd);
+ return true;
+ }
+
+ void OnDestroy() override
+ {
+ WindowList_Remove(pYAMNVar->MessageWnds, m_hwnd);
+ }
+
+ INT_PTR DlgProc(UINT msg, WPARAM wParam, LPARAM lParam) override
+ {
+ switch (msg) {
+ case WM_YAMN_CHANGESTATUS:
+ if ((HPOP3ACCOUNT)wParam == ActualAccount) {
+ wchar_t accstatus[256];
+ GetAccountStatus(ActualAccount, accstatus);
+ SetDlgItemText(m_hwnd, IDC_STSTATUS, accstatus);
+ return TRUE;
+ }
+ break;
+
+ case WM_YAMN_CHANGESTATUSOPTION:
+ NotifyChange();
+ return TRUE;
+
+ case WM_YAMN_CHANGETIME:
+ if ((HPOP3ACCOUNT)wParam == ActualAccount) {
+ wchar_t Text[256];
+ mir_snwprintf(Text, TranslateT("Time left to next check [s]: %d"), (uint32_t)lParam);
+ SetDlgItemText(m_hwnd, IDC_STTIMELEFT, Text);
+ }
+ return TRUE;
+ }
+ return CDlgBase::DlgProc(msg, wParam, lParam);
+ }
+
+ void onChange_Account(CCtrlCombo *)
+ {
+ ActualAccount = nullptr;
+ DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr);
+ DlgEnableAccount(0 != GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput)));
+ }
+
+ void onKillFocus_Account(CCtrlCombo *)
+ {
+ GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput));
+ if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput))) {
+ DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE);
+ DlgEnableAccount(mir_strlen(DlgInput) > 0);
+ }
+ else {
+ DlgShowAccount(ActualAccount);
+ DlgEnableAccount(true);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), TRUE);
+ }
+ }
+
+ void onSelChange_Account(CCtrlCombo *)
+ {
+ if (CB_ERR != (Result = cmbAccount.GetCurSel()))
+ SendDlgItemMessageA(m_hwnd, IDC_COMBOACCOUNT, CB_GETLBTEXT, (WPARAM)Result, (LPARAM)DlgInput);
+
+ if ((Result == CB_ERR) || (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput)))) {
+ DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE);
+ }
+ else {
+ DlgShowAccount(ActualAccount);
+ DlgEnableAccount(true);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), TRUE);
+ }
+ }
+
+ void onSelChange_CP(CCtrlCombo *)
+ {
+ int sel = cmbCP.GetCurSel();
+ CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[sel].CP, 0, &info);
+ DlgSetItemTextW(m_hwnd, IDC_STSTATUS, info.CodePageName);
+ }
+
+ void onChangeContact(CCtrlCheck *)
+ {
+ bool bEnabled = chkContact.IsChecked();
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNICK), bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKCONTACTNOEVENT), bEnabled);
+ }
+
+ void onChangeSsl(CCtrlCheck *)
+ {
+ bool bEnabled = chkSsl.IsChecked();
+ SetDlgItemInt(m_hwnd, IDC_EDITPORT, bEnabled ? 995 : 110, FALSE);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKNOTLS), !bEnabled);
+ }
+
+ void onChangeApp(CCtrlCheck *)
+ {
+ bool bEnabled = chkApp.IsChecked();
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNAPP), bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPP), bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITAPPPARAM), bEnabled);
+ }
+
+ void onClick_Status(CCtrlButton *)
+ {
+ DialogBoxParamW(g_plugin.getInst(), MAKEINTRESOURCEW(IDD_CHOOSESTATUSMODES), m_hwnd, DlgProcPOP3AccStatusOpt, NULL);
+ }
+
+ void onClick_Add(CCtrlButton *)
+ {
+ DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr);
+ DlgShowAccount(0);
+ DlgEnableAccount(true);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE);
+ DlgSetItemTextW(m_hwnd, IDC_EDITNAME, TranslateT("New Account"));
+
+ int index = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_ADDSTRING, 0, (LPARAM)TranslateT("New Account"));
+ if (index != CB_ERR && index != CB_ERRSPACE)
+ SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_SETCURSEL, index, (LPARAM)TranslateT("New Account"));
+ }
+
+ void onClick_App(CCtrlButton *)
+ {
+ wchar_t filter[MAX_PATH];
+ mir_snwprintf(filter, L"%s (*.exe;*.bat;*.cmd;*.com)%c*.exe;*.bat;*.cmd;*.com%c%s (*.*)%c*.*%c",
+ TranslateT("Executables"), 0, 0, TranslateT("All Files"), 0, 0);
+
+ OPENFILENAME OFNStruct = {0};
+ OFNStruct.lStructSize = sizeof(OPENFILENAME);
+ OFNStruct.hwndOwner = m_hwnd;
+ OFNStruct.lpstrFilter = filter;
+ OFNStruct.nFilterIndex = 1;
+ OFNStruct.nMaxFile = MAX_PATH;
+ OFNStruct.lpstrFile = new wchar_t[MAX_PATH];
+ OFNStruct.lpstrFile[0] = (wchar_t)0;
+ OFNStruct.lpstrTitle = TranslateT("Select executable used for notification");
+ OFNStruct.Flags = OFN_FILEMUSTEXIST | OFN_NONETWORKBUTTON | OFN_PATHMUSTEXIST | OFN_NOCHANGEDIR;
+ if (!GetOpenFileName(&OFNStruct)) {
+ if (CommDlgExtendedError())
+ MessageBox(m_hwnd, TranslateT("Dialog box error"), TranslateT("Failed"), MB_OK);
+ }
+ else DlgSetItemTextW(m_hwnd, IDC_EDITAPP, OFNStruct.lpstrFile);
+ delete[] OFNStruct.lpstrFile;
+ }
+
+ void onClick_Default(CCtrlButton *)
+ {
+ DlgShowAccount(0);
+ }
+
+ void onClick_Del(CCtrlButton *)
+ {
+ GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput));
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), FALSE);
+ if ((CB_ERR == (Result = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0)))
+ || (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput))))
+ return;
+
+ if (IDOK != MessageBox(m_hwnd, TranslateT("Do you really want to delete this account?"), TranslateT("Delete account confirmation"), MB_OKCANCEL | MB_ICONWARNING))
+ return;
+
+ DlgSetItemTextW(m_hwnd, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use."));
+
+ if (ActualAccount->hContact != NULL)
+ db_delete_contact(ActualAccount->hContact);
+
+ CallService(MS_YAMN_DELETEACCOUNT, (WPARAM)POP3Plugin, (LPARAM)ActualAccount);
+
+ // We can consider our account as deleted.
+ SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_DELETESTRING, Result, 0);
+ DlgSetItemText(m_hwnd, IDC_COMBOACCOUNT, nullptr);
+ DlgEnableAccount(false);
+ DlgShowAccount(0);
+ }
+
+ void onClick_Reset(CCtrlButton *)
+ {
+ if (ActualAccount != nullptr)
+ ActualAccount->TimeLeft = ActualAccount->Interval;
+ }
+
+ bool OnApply() override
+ {
+ char Text[MAX_PATH];
+ wchar_t TextW[MAX_PATH];
+ BOOL Translated, NewAcc = FALSE;
+ size_t Length, index;
+
+ if (!GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, Text, _countof(Text)))
+ return false;
+
+ BOOL Check = (IsDlgButtonChecked(m_hwnd, IDC_CHECK) == BST_CHECKED);
+ BOOL CheckSSL = (IsDlgButtonChecked(m_hwnd, IDC_CHECKSSL) == BST_CHECKED);
+ BOOL CheckNoTLS = (IsDlgButtonChecked(m_hwnd, IDC_CHECKNOTLS) == BST_CHECKED);
+ BOOL CheckAPOP = (IsDlgButtonChecked(m_hwnd, IDC_CHECKAPOP) == BST_CHECKED);
+
+ BOOL CheckABody = (IsDlgButtonChecked(m_hwnd, IDC_AUTOBODY) == BST_CHECKED);
+ BOOL CheckMsg = (IsDlgButtonChecked(m_hwnd, IDC_CHECKMSG) == BST_CHECKED);
+ BOOL CheckSnd = (IsDlgButtonChecked(m_hwnd, IDC_CHECKSND) == BST_CHECKED);
+ BOOL CheckIco = (IsDlgButtonChecked(m_hwnd, IDC_CHECKICO) == BST_CHECKED);
+
+ BOOL CheckApp = (IsDlgButtonChecked(m_hwnd, IDC_CHECKAPP) == BST_CHECKED);
+ BOOL CheckKBN = (IsDlgButtonChecked(m_hwnd, IDC_CHECKKBN) == BST_CHECKED);
+ BOOL CheckContact = (IsDlgButtonChecked(m_hwnd, IDC_CHECKCONTACT) == BST_CHECKED);
+ BOOL CheckContactNick = (IsDlgButtonChecked(m_hwnd, IDC_CHECKCONTACTNICK) == BST_CHECKED);
+ BOOL CheckContactNoEvent = (IsDlgButtonChecked(m_hwnd, IDC_CHECKCONTACTNOEVENT) == BST_CHECKED);
+
+ BOOL CheckFSnd = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFSND) == BST_CHECKED);
+ BOOL CheckFMsg = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFMSG) == BST_CHECKED);
+ BOOL CheckFIco = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFICO) == BST_CHECKED);
+
+ BOOL CheckNMsgP = (IsDlgButtonChecked(m_hwnd, IDC_CHECKNMSGP) == BST_CHECKED);
+
+ UINT Port = GetDlgItemInt(m_hwnd, IDC_EDITPORT, &Translated, FALSE);
+ if (!Translated) {
+ MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK);
+ SetFocus(GetDlgItem(m_hwnd, IDC_EDITPORT));
+ return false;
+ }
+
+ UINT Interval = GetDlgItemInt(m_hwnd, IDC_EDITINTERVAL, &Translated, FALSE);
+ if (!Translated) {
+ MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK);
+ SetFocus(GetDlgItem(m_hwnd, IDC_EDITINTERVAL));
+ return false;
+ }
+
+ GetDlgItemTextA(m_hwnd, IDC_EDITAPP, Text, _countof(Text));
+ if (CheckApp && !(Length = mir_strlen(Text))) {
+ MessageBox(m_hwnd, TranslateT("Please select application to run"), TranslateT("Input error"), MB_OK);
+ return false;
+ }
+
+ GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, Text, _countof(Text));
+ if (!(Length = mir_strlen(Text))) {
+ GetDlgItemTextA(m_hwnd, IDC_EDITNAME, Text, _countof(Text));
+ if (!(Length = mir_strlen(Text)))
+ return false;
+ }
+
+ DlgSetItemTextW(m_hwnd, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use."));
+
+ if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)Text))) {
+ NewAcc = TRUE;
+ WaitToWriteSO(POP3Plugin->AccountBrowserSO);
+ if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_GETNEXTFREEACCOUNT, (WPARAM)POP3Plugin, (LPARAM)YAMN_ACCOUNTVERSION))) {
+ WriteDoneSO(POP3Plugin->AccountBrowserSO);
+ MessageBox(m_hwnd, TranslateT("Cannot allocate memory space for new account"), TranslateT("Memory error"), MB_OK);
+ return false;
+ }
+ DlgEnableAccount(true);
+ }
+ else { // We have to get full access to AccountBrowser, so other iterating thrads cannot get new account until new account is right set
+ WaitToWriteSO(POP3Plugin->AccountBrowserSO);
+ }
+
+ if (WAIT_OBJECT_0 != WaitToWrite(ActualAccount))
+ WriteDoneSO(POP3Plugin->AccountBrowserSO);
+
+ GetDlgItemTextA(m_hwnd, IDC_EDITNAME, Text, _countof(Text));
+ if (!(Length = mir_strlen(Text)))
+ return false;
+ if (nullptr != ActualAccount->Name)
+ delete[] ActualAccount->Name;
+ ActualAccount->Name = new char[mir_strlen(Text) + 1];
+ mir_strcpy(ActualAccount->Name, Text);
+
+ GetDlgItemTextA(m_hwnd, IDC_EDITSERVER, Text, _countof(Text));
+ if (nullptr != ActualAccount->Server->Name)
+ delete[] ActualAccount->Server->Name;
+ ActualAccount->Server->Name = new char[mir_strlen(Text) + 1];
+ mir_strcpy(ActualAccount->Server->Name, Text);
+
+ GetDlgItemTextA(m_hwnd, IDC_EDITLOGIN, Text, _countof(Text));
+ if (nullptr != ActualAccount->Server->Login)
+ delete[] ActualAccount->Server->Login;
+ ActualAccount->Server->Login = new char[mir_strlen(Text) + 1];
+ mir_strcpy(ActualAccount->Server->Login, Text);
+
+ GetDlgItemTextA(m_hwnd, IDC_EDITPASS, Text, _countof(Text));
+ if (nullptr != ActualAccount->Server->Passwd)
+ delete[] ActualAccount->Server->Passwd;
+ ActualAccount->Server->Passwd = new char[mir_strlen(Text) + 1];
+ mir_strcpy(ActualAccount->Server->Passwd, Text);
+
+ GetDlgItemTextW(m_hwnd, IDC_EDITAPP, TextW, _countof(TextW));
+ if (nullptr != ActualAccount->NewMailN.App)
+ delete[] ActualAccount->NewMailN.App;
+ ActualAccount->NewMailN.App = new wchar_t[mir_wstrlen(TextW) + 1];
+ mir_wstrcpy(ActualAccount->NewMailN.App, TextW);
+
+ GetDlgItemTextW(m_hwnd, IDC_EDITAPPPARAM, TextW, _countof(TextW));
+ if (nullptr != ActualAccount->NewMailN.AppParam)
+ delete[] ActualAccount->NewMailN.AppParam;
+ ActualAccount->NewMailN.AppParam = new wchar_t[mir_wstrlen(TextW) + 1];
+ mir_wstrcpy(ActualAccount->NewMailN.AppParam, TextW);
+
+ ActualAccount->Server->Port = Port;
+ ActualAccount->Interval = Interval * 60;
+
+ if (CB_ERR == (index = SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_GETCURSEL, 0, 0)))
+ index = CPDEFINDEX;
+ ActualAccount->CP = CodePageNamesSupp[index].CP;
+
+ if (NewAcc)
+ ActualAccount->TimeLeft = Interval * 60;
+
+ BOOL CheckStart = (IsDlgButtonChecked(m_hwnd, IDC_CHECKSTART) == BST_CHECKED);
+ BOOL CheckForce = (IsDlgButtonChecked(m_hwnd, IDC_CHECKFORCE) == BST_CHECKED);
+
+ ActualAccount->Flags =
+ (Check ? YAMN_ACC_ENA : 0) |
+ (CheckSSL ? YAMN_ACC_SSL23 : 0) |
+ (CheckNoTLS ? YAMN_ACC_NOTLS : 0) |
+ (CheckAPOP ? YAMN_ACC_APOP : 0) |
+ (CheckABody ? YAMN_ACC_BODY : 0) |
+ (ActualAccount->Flags & YAMN_ACC_POPN);
+
+ ActualAccount->StatusFlags &= 0xFFFF;
+ ActualAccount->StatusFlags |=
+ (CheckStart ? YAMN_ACC_STARTS : 0) |
+ (CheckForce ? YAMN_ACC_FORCE : 0);
+
+ ActualAccount->NewMailN.Flags =
+ (CheckSnd ? YAMN_ACC_SND : 0) |
+ (CheckMsg ? YAMN_ACC_MSG : 0) |
+ (CheckIco ? YAMN_ACC_ICO : 0) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_POP) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_POPC) |
+ (CheckApp ? YAMN_ACC_APP : 0) |
+ (CheckKBN ? YAMN_ACC_KBN : 0) |
+ (CheckContact ? YAMN_ACC_CONT : 0) |
+ (CheckContactNick ? YAMN_ACC_CONTNICK : 0) |
+ (CheckContactNoEvent ? YAMN_ACC_CONTNOEVENT : 0) |
+ YAMN_ACC_MSGP; //this is default: when new mail arrives and window was displayed, leave it displayed.
+
+ ActualAccount->NoNewMailN.Flags =
+ (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POP) |
+ (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC) |
+ (CheckNMsgP ? YAMN_ACC_MSGP : 0);
+
+ ActualAccount->BadConnectN.Flags =
+ (CheckFSnd ? YAMN_ACC_SND : 0) |
+ (CheckFMsg ? YAMN_ACC_MSG : 0) |
+ (CheckFIco ? YAMN_ACC_ICO : 0) |
+ (ActualAccount->BadConnectN.Flags & YAMN_ACC_POP) |
+ (ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC);
+
+ WriteDone(ActualAccount);
+ WriteDoneSO(POP3Plugin->AccountBrowserSO);
+
+ EnableWindow(GetDlgItem(m_hwnd, IDC_BTNDEL), TRUE);
+
+ DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr);
+
+ index = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0);
+
+ HPOP3ACCOUNT temp = ActualAccount;
+
+ SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_RESETCONTENT, 0, 0);
+ if (POP3Plugin->FirstAccount != nullptr)
+ for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next)
+ if (ActualAccount->Name != nullptr)
+ SendDlgItemMessageA(m_hwnd, IDC_COMBOACCOUNT, CB_ADDSTRING, 0, (LPARAM)ActualAccount->Name);
+
+ ActualAccount = temp;
+ SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_SETCURSEL, (WPARAM)index, (LPARAM)ActualAccount->Name);
+
+ WritePOP3Accounts();
+ RefreshContact();
+ return TRUE;
+ }
+};
+
+/////////////////////////////////////////////////////////////////////////////////////////
+// Popup options
+
+class CPopupOptsDlg : public CBaseOptionsDlg
+{
+ HPOP3ACCOUNT ActualAccount = nullptr;
+ UCHAR ActualStatus;
+
+ CCtrlCombo cmbAccount, cmbCP;
+ CCtrlCheck chkCol, chkFcol, chkNcol, chkPop, chkFpop, chkNpop;
+ CCtrlButton btnPreview;
+
+ void DlgShowAccountPopup()
+ {
+ if (ActualAccount) {
+ WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread
+ SetDlgItemInt(m_hwnd, IDC_EDITPOPS, ActualAccount->NewMailN.PopupTime, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, ActualAccount->NoNewMailN.PopupTime, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, ActualAccount->BadConnectN.PopupTime, FALSE);
+
+ chkPop.SetState(ActualAccount->NewMailN.Flags & YAMN_ACC_POP);
+ chkCol.SetState(ActualAccount->NewMailN.Flags & YAMN_ACC_POPC);
+ chkNpop.SetState(ActualAccount->NoNewMailN.Flags & YAMN_ACC_POP);
+ chkNcol.SetState(ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC);
+ chkFpop.SetState(ActualAccount->BadConnectN.Flags & YAMN_ACC_POP ? BST_CHECKED : BST_UNCHECKED);
+ chkFcol.SetState(ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOPN, ActualAccount->Flags & YAMN_ACC_POPN ? BST_CHECKED : BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOP1, ActualAccount->Flags & YAMN_ACC_POPN ? BST_UNCHECKED : BST_CHECKED);
+ ReadDone(ActualAccount);
+ }
+ else { // default
+ SetDlgItemInt(m_hwnd, IDC_EDITPOPS, 0, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITNPOPS, 0, FALSE);
+ SetDlgItemInt(m_hwnd, IDC_EDITFPOPS, 0, FALSE);
+ chkPop.SetState(true);
+ chkCol.SetState(true);
+ chkNpop.SetState(true);
+ chkNcol.SetState(true);
+ chkFpop.SetState(true);
+ chkFcol.SetState(true);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOPN, BST_UNCHECKED);
+ CheckDlgButton(m_hwnd, IDC_RADIOPOP1, BST_CHECKED);
+ }
+ }
+
+ void DlgEnableAccountPopup(bool bEnable)
+ {
+ chkPop.Enable(bEnable);
+ chkCol.Enable(chkPop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPOPS), chkPop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPB), chkCol.IsChecked() && chkPop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPT), chkCol.IsChecked() && chkPop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOPN), chkPop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOP1), chkPop.IsChecked() && bEnable);
+
+ chkNpop.Enable(bEnable);
+ chkNcol.Enable(chkNpop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITNPOPS), chkNpop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPNB), chkNcol.IsChecked() && chkNpop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPNT), chkNcol.IsChecked() && chkNpop.IsChecked() && bEnable);
+
+ chkFpop.Enable(bEnable);
+ chkFcol.Enable(chkFpop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITFPOPS), chkFpop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPFB), chkFcol.IsChecked() && chkFpop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPFT), chkFcol.IsChecked() && chkFpop.IsChecked() && bEnable);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CHECKAPOP), bEnable);
+ }
+
+ void DlgShowAccountColors()
+ {
+ WaitToRead(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread
+
+ if (ActualAccount->NewMailN.Flags & YAMN_ACC_POPC) {
+ SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NewMailN.PopupB);
+ SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NewMailN.PopupT);
+ }
+ else {
+ SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE));
+ SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_WINDOWTEXT));
+ }
+ if (ActualAccount->BadConnectN.Flags & YAMN_ACC_POPC) {
+ SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->BadConnectN.PopupB);
+ SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->BadConnectN.PopupT);
+ }
+ else {
+ SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE));
+ SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_WINDOWTEXT));
+ }
+ if (ActualAccount->NoNewMailN.Flags & YAMN_ACC_POPC) {
+ SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NoNewMailN.PopupB);
+ SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_SETCOLOUR, 0, (LPARAM)ActualAccount->NoNewMailN.PopupT);
+ }
+ else {
+ SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_BTNFACE));
+ SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_SETCOLOUR, 0, (LPARAM)GetSysColor(COLOR_WINDOWTEXT));
+ }
+
+ ReadDone(ActualAccount); //we do not need to check if account is deleted. It is not deleted, because only thread that can delete account is this thread
+ }
+
+public:
+ CPopupOptsDlg() :
+ CBaseOptionsDlg(IDD_POP3ACCOUNTPOPUP),
+ cmbCP(this, IDC_COMBOCP),
+ chkCol(this, IDC_CHECKCOL),
+ chkPop(this, IDC_CHECKPOP),
+ chkFcol(this, IDC_CHECKFCOL),
+ chkFpop(this, IDC_CHECKFPOP),
+ chkNcol(this, IDC_CHECKNCOL),
+ chkNpop(this, IDC_CHECKNPOP),
+ btnPreview(this, IDC_PREVIEW),
+ cmbAccount(this, IDC_COMBOACCOUNT)
+ {
+ chkPop.OnChange = Callback(this, &CPopupOptsDlg::onChange_Pop);
+ chkFpop.OnChange = Callback(this, &CPopupOptsDlg::onChange_Fpop);
+ chkNpop.OnChange = Callback(this, &CPopupOptsDlg::onChange_Npop);
+ chkCol.OnChange = chkFcol.OnChange = chkNcol.OnChange = Callback(this, &CPopupOptsDlg::onChange_Col);
+
+ cmbCP.OnSelChanged = Callback(this, &CPopupOptsDlg::onSelChange_CP);
+
+ btnPreview.OnClick = Callback(this, &CPopupOptsDlg::onClick_Preview);
+
+ cmbAccount.OnKillFocus = Callback(this, &CPopupOptsDlg::onKillFocus_Account);
+ cmbAccount.OnSelChanged = Callback(this, &CPopupOptsDlg::onSelChange_Account);
+ }
+
+ bool OnInitDialog() override
+ {
+ WindowList_Add(pYAMNVar->MessageWnds, m_hwnd);
+
+ DlgEnableAccountPopup(false);
+ DlgShowAccountPopup();
+
+ WaitToReadSO(POP3Plugin->AccountBrowserSO);
+
+ if (POP3Plugin->FirstAccount != nullptr)
+ for (ActualAccount = (HPOP3ACCOUNT)POP3Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = (HPOP3ACCOUNT)ActualAccount->Next)
+ if (ActualAccount->Name != nullptr)
+ cmbAccount.AddStringA(ActualAccount->Name);
+
+ ReadDoneSO(POP3Plugin->AccountBrowserSO);
+ ActualAccount = nullptr;
+ cmbAccount.SetCurSel(0);
+ return true;
+ }
+
+ void OnDestroy() override
+ {
+ WindowList_Remove(pYAMNVar->MessageWnds, m_hwnd);
+ }
+
+ void onKillFocus_Account(CCtrlCombo *)
+ {
+ GetDlgItemTextA(m_hwnd, IDC_COMBOACCOUNT, DlgInput, _countof(DlgInput));
+ if (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput))) {
+ DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr);
+ if (mir_strlen(DlgInput))
+ DlgEnableAccountPopup(true);
+ else
+ DlgEnableAccountPopup(false);
+ }
+ else {
+ DlgShowAccount(ActualAccount);
+ DlgShowAccountColors();
+ DlgEnableAccountPopup(true);
+ }
+ }
+
+ void onSelChange_Account(CCtrlCombo *)
+ {
+ int Result = SendDlgItemMessage(m_hwnd, IDC_COMBOACCOUNT, CB_GETCURSEL, 0, 0);
+ if (CB_ERR != Result)
+ SendDlgItemMessageA(m_hwnd, IDC_COMBOACCOUNT, CB_GETLBTEXT, (WPARAM)Result, (LPARAM)DlgInput);
+ if ((Result == CB_ERR) || (nullptr == (ActualAccount = (HPOP3ACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)DlgInput)))) {
+ DlgSetItemText(m_hwnd, (WPARAM)IDC_STTIMELEFT, nullptr);
+ }
+ else {
+ DlgShowAccount(ActualAccount);
+ DlgShowAccountColors();
+ DlgEnableAccountPopup(true);
+ }
+ }
+
+ void onSelChange_CP(CCtrlCombo *)
+ {
+ int sel = SendDlgItemMessage(m_hwnd, IDC_COMBOCP, CB_GETCURSEL, 0, 0);
+ CPINFOEX info; GetCPInfoEx(CodePageNamesSupp[sel].CP, 0, &info);
+ DlgSetItemTextW(m_hwnd, IDC_STSTATUS, info.CodePageName);
+ }
+
+ void onChange_Col(CCtrlCheck *)
+ {
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPB), chkCol.IsChecked() && chkPop.IsChecked());
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPT), chkCol.IsChecked() && chkPop.IsChecked());
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPNB), chkNcol.IsChecked() && chkNpop.IsChecked());
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPNT), chkNcol.IsChecked() && chkNpop.IsChecked());
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPFB), chkFcol.IsChecked() && chkFpop.IsChecked());
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPFT), chkFcol.IsChecked() && chkFpop.IsChecked());
+ }
+
+ void onClick_Preview(CCtrlButton *)
+ {
+ if (chkPop.IsChecked()) {
+ POPUPDATAW Tester = {};
+ Tester.lchIcon = g_plugin.getIcon(IDI_NEWMAIL);
+ mir_wstrncpy(Tester.lpwzContactName, TranslateT("Account Test"), MAX_CONTACTNAME);
+ mir_wstrncpy(Tester.lpwzText, TranslateT("You have N new mail messages"), MAX_SECONDLINE);
+ if (chkCol.IsChecked()) {
+ Tester.colorBack = SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_GETCOLOUR, 0, 0);
+ Tester.colorText = SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_GETCOLOUR, 0, 0);
+ }
+ else {
+ Tester.colorBack = GetSysColor(COLOR_BTNFACE);
+ Tester.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ PUAddPopupW(&Tester);
+ }
+
+ if (chkFpop.IsChecked()) {
+ POPUPDATAW TesterF = {};
+ TesterF.lchIcon = g_plugin.getIcon(IDI_BADCONNECT);
+ mir_wstrncpy(TesterF.lpwzContactName, TranslateT("Account Test (failed)"), MAX_CONTACTNAME);
+ mir_wstrncpy(TesterF.lpwzText, TranslateT("Connection failed message"), MAX_SECONDLINE);
+ if (chkFcol.IsChecked()) {
+ TesterF.colorBack = SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_GETCOLOUR, 0, 0);
+ TesterF.colorText = SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_GETCOLOUR, 0, 0);
+ }
+ else {
+ TesterF.colorBack = GetSysColor(COLOR_BTNFACE);
+ TesterF.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ PUAddPopupW(&TesterF);
+ }
+
+ if (chkNpop.IsChecked()) {
+ POPUPDATAW TesterN = {};
+ TesterN.lchIcon = g_plugin.getIcon(IDI_LAUNCHAPP);
+ mir_wstrncpy(TesterN.lpwzContactName, TranslateT("Account Test"), MAX_CONTACTNAME);
+ mir_wstrncpy(TesterN.lpwzText, TranslateT("No new mail message"), MAX_SECONDLINE);
+ if (chkNcol.IsChecked()) {
+ TesterN.colorBack = SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_GETCOLOUR, 0, 0);
+ TesterN.colorText = SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_GETCOLOUR, 0, 0);
+ }
+ else {
+ TesterN.colorBack = GetSysColor(COLOR_BTNFACE);
+ TesterN.colorText = GetSysColor(COLOR_WINDOWTEXT);
+ }
+ PUAddPopupW(&TesterN);
+ }
+ }
+
+ void onChange_Pop(CCtrlCheck *)
+ {
+ bool bEnabled = chkPop.IsChecked();
+ chkCol.Enable(bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPB), chkCol.IsChecked() && bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPT), chkCol.IsChecked() && bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOPN), bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_RADIOPOP1), bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITPOPS), bEnabled);
+ }
+
+ void onChange_Fpop(CCtrlCheck *)
+ {
+ bool bEnabled = chkFpop.IsChecked();
+ chkFcol.Enable(bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPFB), chkFcol.IsChecked() && bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPFT), chkFcol.IsChecked() && bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITFPOPS), bEnabled);
+ }
+
+ void onChange_Npop(CCtrlCheck *)
+ {
+ bool bEnabled = chkNpop.IsChecked();
+ chkNcol.Enable(bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPNB), chkNcol.IsChecked() && bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_CPNT), chkNcol.IsChecked() && bEnabled);
+ EnableWindow(GetDlgItem(m_hwnd, IDC_EDITNPOPS), bEnabled);
+ }
+
+ bool OnApply() override
+ {
+ wchar_t Text[MAX_PATH];
+ if (!GetDlgItemText(m_hwnd, IDC_COMBOACCOUNT, Text, _countof(Text)))
+ return false;
+
+ BOOL CheckPopup = chkPop.IsChecked();
+ BOOL CheckPopupW = chkCol.IsChecked();
+
+ BOOL CheckFPopup = chkFpop.IsChecked();
+ BOOL CheckFPopupW = chkFcol.IsChecked();
+
+ BOOL CheckNPopup = chkNpop.IsChecked();
+ BOOL CheckNPopupW = chkNcol.IsChecked();
+
+ BOOL CheckPopN = (IsDlgButtonChecked(m_hwnd, IDC_RADIOPOPN) == BST_CHECKED);
+
+ BOOL Translated;
+ UINT Time = GetDlgItemInt(m_hwnd, IDC_EDITPOPS, &Translated, FALSE);
+ if (!Translated) {
+ MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK);
+ SetFocus(GetDlgItem(m_hwnd, IDC_EDITPOPS));
+ return false;
+ }
+ UINT TimeN = GetDlgItemInt(m_hwnd, IDC_EDITNPOPS, &Translated, FALSE);
+ if (!Translated) {
+ MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK);
+ SetFocus(GetDlgItem(m_hwnd, IDC_EDITNPOPS));
+ return false;
+ }
+ UINT TimeF = GetDlgItemInt(m_hwnd, IDC_EDITFPOPS, &Translated, FALSE);
+ if (!Translated) {
+ MessageBox(m_hwnd, TranslateT("This is not a valid number value"), TranslateT("Input error"), MB_OK);
+ SetFocus(GetDlgItem(m_hwnd, IDC_EDITFPOPS));
+ return false;
+ }
+
+ DlgSetItemTextW(m_hwnd, IDC_STTIMELEFT, TranslateT("Please wait while no account is in use."));
+
+ ActualAccount->Flags =
+ (ActualAccount->Flags & YAMN_ACC_ENA) |
+ (ActualAccount->Flags & YAMN_ACC_SSL23) |
+ (ActualAccount->Flags & YAMN_ACC_NOTLS) |
+ (ActualAccount->Flags & YAMN_ACC_APOP) |
+ (ActualAccount->Flags & YAMN_ACC_BODY) |
+ (CheckPopN ? YAMN_ACC_POPN : 0);
+
+ ActualAccount->NewMailN.Flags =
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_SND) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_MSG) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_ICO) |
+ (CheckPopup ? YAMN_ACC_POP : 0) |
+ (CheckPopupW ? YAMN_ACC_POPC : 0) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_APP) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_KBN) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_CONT) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_CONTNICK) |
+ (ActualAccount->NewMailN.Flags & YAMN_ACC_CONTNOEVENT) |
+ YAMN_ACC_MSGP;
+
+ ActualAccount->NoNewMailN.Flags =
+ (CheckNPopup ? YAMN_ACC_POP : 0) |
+ (CheckNPopupW ? YAMN_ACC_POPC : 0) |
+ (ActualAccount->NoNewMailN.Flags & YAMN_ACC_MSGP);
+
+ ActualAccount->BadConnectN.Flags =
+ (ActualAccount->BadConnectN.Flags & YAMN_ACC_SND) |
+ (ActualAccount->BadConnectN.Flags & YAMN_ACC_MSG) |
+ (ActualAccount->BadConnectN.Flags & YAMN_ACC_ICO) |
+ (CheckFPopup ? YAMN_ACC_POP : 0) |
+ (CheckFPopupW ? YAMN_ACC_POPC : 0);
+
+ ActualAccount->NewMailN.PopupB = SendDlgItemMessage(m_hwnd, IDC_CPB, CPM_GETCOLOUR, 0, 0);
+ ActualAccount->NewMailN.PopupT = SendDlgItemMessage(m_hwnd, IDC_CPT, CPM_GETCOLOUR, 0, 0);
+ ActualAccount->NewMailN.PopupTime = Time;
+
+ ActualAccount->NoNewMailN.PopupB = SendDlgItemMessage(m_hwnd, IDC_CPNB, CPM_GETCOLOUR, 0, 0);
+ ActualAccount->NoNewMailN.PopupT = SendDlgItemMessage(m_hwnd, IDC_CPNT, CPM_GETCOLOUR, 0, 0);
+ ActualAccount->NoNewMailN.PopupTime = TimeN;
+
+ ActualAccount->BadConnectN.PopupB = SendDlgItemMessage(m_hwnd, IDC_CPFB, CPM_GETCOLOUR, 0, 0);
+ ActualAccount->BadConnectN.PopupT = SendDlgItemMessage(m_hwnd, IDC_CPFT, CPM_GETCOLOUR, 0, 0);
+ ActualAccount->BadConnectN.PopupTime = TimeF;
+
+ WriteDone(ActualAccount);
+ WriteDoneSO(POP3Plugin->AccountBrowserSO);
+
+ WritePOP3Accounts();
+ RefreshContact();
+ return TRUE;
+ }
+};
+
+//--------------------------------------------------------------------------------------------------
+
+int YAMNOptInitSvc(WPARAM wParam, LPARAM)
+{
+ OPTIONSDIALOGPAGE odp = {};
+ odp.szGroup.a = LPGEN("Network");
+ odp.szTitle.a = LPGEN("YAMN");
+ odp.flags = ODPF_BOLDGROUPS;
+
+ odp.szTab.a = LPGEN("Accounts");
+ odp.pDialog = new CAccOptDlg();
+ g_plugin.addOptions(wParam, &odp);
+
+ odp.szTab.a = LPGEN("General");
+ odp.pDialog = new CGeneralOptDlg();
+ g_plugin.addOptions(wParam, &odp);
+
+ odp.szGroup.a = LPGEN("Popups");
+ odp.szTab.a = LPGEN("YAMN");
+ odp.pDialog = new CPopupOptsDlg();
+ g_plugin.addOptions(wParam, &odp);
+ return 0;
+}
diff --git a/protocols/YAMN/src/protoplugin.cpp b/protocols/YAMN/src/protoplugin.cpp index c6e6a6aecc..b192ac1f5f 100644 --- a/protocols/YAMN/src/protoplugin.cpp +++ b/protocols/YAMN/src/protoplugin.cpp @@ -1,172 +1,172 @@ -/* - * YAMN plugin export functions for protocols - * - * (c) majvan 2002-2004 - */ - -#include "stdafx.h" - - //-------------------------------------------------------------------------------------------------- - -PYAMN_PROTOPLUGINQUEUE FirstProtoPlugin = nullptr; - -INT_PTR RegisterProtocolPluginSvc(WPARAM, LPARAM); - -//Removes plugin from queue and deletes registration structures -INT_PTR UnregisterProtocolPlugin(HYAMNPROTOPLUGIN Plugin); - -INT_PTR UnregisterProtocolPluginSvc(WPARAM, LPARAM); - -//Removes plugins from queue and deletes registration structures -INT_PTR UnregisterProtoPlugins(); - -//Sets imported functions for an plugin and therefore it starts plugin to be registered and running -// Plugin- plugin, which wants to set its functions -// YAMNFcn- pointer to imported functions with accounts -// YAMNFcnVer- version of YAMN_PROTOIMPORTFCN, use YAMN_PROTOIMPORTFCNVERSION -// YAMNMailFcn- pointer to imported functions with mails -// YAMNMailFcnVer- version of YAMN_MAILIMPORTFCN, use YAMN_MAILIMPORTFCNVERSION -// returns nonzero if success -int WINAPI SetProtocolPluginFcnImportFcn(HYAMNPROTOPLUGIN Plugin, PYAMN_PROTOIMPORTFCN YAMNFcn, uint32_t YAMNFcnVer, PYAMN_MAILIMPORTFCN YAMNMailFcn, uint32_t YAMNMailFcnVer); - -struct CExportedFunctions ProtoPluginExportedFcn[] = -{ - {YAMN_SETPROTOCOLPLUGINFCNIMPORTID, (void *)SetProtocolPluginFcnImportFcn}, -}; - -struct CExportedServices ProtoPluginExportedSvc[] = -{ - {MS_YAMN_REGISTERPROTOPLUGIN, RegisterProtocolPluginSvc}, - {MS_YAMN_UNREGISTERPROTOPLUGIN, UnregisterProtocolPluginSvc}, - {MS_YAMN_GETFILENAME, GetFileNameSvc}, - {MS_YAMN_DELETEFILENAME, DeleteFileNameSvc}, -}; - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -INT_PTR RegisterProtocolPluginSvc(WPARAM wParam, LPARAM lParam) -{ - PYAMN_PROTOREGISTRATION Registration = (PYAMN_PROTOREGISTRATION)wParam; - HYAMNPROTOPLUGIN Plugin; - - if (lParam != YAMN_PROTOREGISTRATIONVERSION) - return 0; - if ((Registration->Name == nullptr) || (Registration->Ver == nullptr)) - return (INT_PTR)NULL; - if (nullptr == (Plugin = new YAMN_PROTOPLUGIN)) - return (INT_PTR)NULL; - - Plugin->PluginInfo = Registration; - - Plugin->FirstAccount = nullptr; - - Plugin->AccountBrowserSO = new SWMRG; - SWMRGInitialize(Plugin->AccountBrowserSO, nullptr); - - Plugin->Fcn = nullptr; - Plugin->MailFcn = nullptr; - - return (INT_PTR)Plugin; -} - -int WINAPI SetProtocolPluginFcnImportFcn(HYAMNPROTOPLUGIN Plugin, PYAMN_PROTOIMPORTFCN YAMNFcn, uint32_t YAMNFcnVer, PYAMN_MAILIMPORTFCN YAMNMailFcn, uint32_t YAMNMailFcnVer) -{ - PYAMN_PROTOPLUGINQUEUE Parser; - - if (YAMNFcnVer != YAMN_PROTOIMPORTFCNVERSION) - return 0; - if (YAMNMailFcnVer != YAMN_MAILIMPORTFCNVERSION) - return 0; - if (YAMNFcn == nullptr) - return 0; - if (YAMNMailFcn == nullptr) - return 0; - - Plugin->Fcn = YAMNFcn; - Plugin->MailFcn = YAMNMailFcn; - - mir_cslock lck(PluginRegCS); - // We add protocol to the protocol list - for (Parser = FirstProtoPlugin; Parser != nullptr && Parser->Next != nullptr; Parser = Parser->Next); - if (Parser == nullptr) { - FirstProtoPlugin = new YAMN_PROTOPLUGINQUEUE; - Parser = FirstProtoPlugin; - } - else { - Parser->Next = new YAMN_PROTOPLUGINQUEUE; - Parser = Parser->Next; - } - - Parser->Plugin = Plugin; - Parser->Next = nullptr; - return 1; -} - -INT_PTR UnregisterProtocolPlugin(HYAMNPROTOPLUGIN Plugin) -{ - PYAMN_PROTOPLUGINQUEUE Parser, Found; - - if (FirstProtoPlugin->Plugin == Plugin) { - Found = FirstProtoPlugin; - FirstProtoPlugin = FirstProtoPlugin->Next; - } - else { - for (Parser = FirstProtoPlugin; (Parser->Next != nullptr) && (Plugin != Parser->Next->Plugin); Parser = Parser->Next); - if (Parser->Next != nullptr) { - Found = Parser->Next; - Parser->Next = Parser->Next->Next; - } - else - Found = nullptr; - } - if (Found != nullptr) { - StopAccounts(Plugin); - DeleteAccounts(Plugin); - if (Plugin->Fcn->UnLoadFcn != nullptr) - Plugin->Fcn->UnLoadFcn((void *)nullptr); - - delete Found->Plugin->AccountBrowserSO; - delete Found->Plugin; - delete Found; - } - else - return 0; - return 1; -} - -INT_PTR UnregisterProtocolPluginSvc(WPARAM wParam, LPARAM) -{ - HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam; - - mir_cslock lck(PluginRegCS); - UnregisterProtocolPlugin(Plugin); - return 1; -} - -INT_PTR UnregisterProtoPlugins() -{ - mir_cslock lck(PluginRegCS); - // We remove protocols from the protocol list - while (FirstProtoPlugin != nullptr) - UnregisterProtocolPlugin(FirstProtoPlugin->Plugin); - return 1; -} - -INT_PTR GetFileNameSvc(WPARAM wParam, LPARAM) -{ - wchar_t *FileName = new wchar_t[MAX_PATH]; - if (FileName == nullptr) - return NULL; - - mir_snwprintf(FileName, MAX_PATH, L"%s\\yamn-accounts.%s.%s.book", UserDirectory, (wchar_t *)wParam, ProfileName); - return (INT_PTR)FileName; -} - -INT_PTR DeleteFileNameSvc(WPARAM wParam, LPARAM) -{ - if ((wchar_t *)wParam != nullptr) - delete[](wchar_t *) wParam; - - return 0; -} +/*
+ * YAMN plugin export functions for protocols
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+ //--------------------------------------------------------------------------------------------------
+
+PYAMN_PROTOPLUGINQUEUE FirstProtoPlugin = nullptr;
+
+INT_PTR RegisterProtocolPluginSvc(WPARAM, LPARAM);
+
+//Removes plugin from queue and deletes registration structures
+INT_PTR UnregisterProtocolPlugin(HYAMNPROTOPLUGIN Plugin);
+
+INT_PTR UnregisterProtocolPluginSvc(WPARAM, LPARAM);
+
+//Removes plugins from queue and deletes registration structures
+INT_PTR UnregisterProtoPlugins();
+
+//Sets imported functions for an plugin and therefore it starts plugin to be registered and running
+// Plugin- plugin, which wants to set its functions
+// YAMNFcn- pointer to imported functions with accounts
+// YAMNFcnVer- version of YAMN_PROTOIMPORTFCN, use YAMN_PROTOIMPORTFCNVERSION
+// YAMNMailFcn- pointer to imported functions with mails
+// YAMNMailFcnVer- version of YAMN_MAILIMPORTFCN, use YAMN_MAILIMPORTFCNVERSION
+// returns nonzero if success
+int WINAPI SetProtocolPluginFcnImportFcn(HYAMNPROTOPLUGIN Plugin, PYAMN_PROTOIMPORTFCN YAMNFcn, uint32_t YAMNFcnVer, PYAMN_MAILIMPORTFCN YAMNMailFcn, uint32_t YAMNMailFcnVer);
+
+struct CExportedFunctions ProtoPluginExportedFcn[] =
+{
+ {YAMN_SETPROTOCOLPLUGINFCNIMPORTID, (void *)SetProtocolPluginFcnImportFcn},
+};
+
+struct CExportedServices ProtoPluginExportedSvc[] =
+{
+ {MS_YAMN_REGISTERPROTOPLUGIN, RegisterProtocolPluginSvc},
+ {MS_YAMN_UNREGISTERPROTOPLUGIN, UnregisterProtocolPluginSvc},
+ {MS_YAMN_GETFILENAME, GetFileNameSvc},
+ {MS_YAMN_DELETEFILENAME, DeleteFileNameSvc},
+};
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+INT_PTR RegisterProtocolPluginSvc(WPARAM wParam, LPARAM lParam)
+{
+ PYAMN_PROTOREGISTRATION Registration = (PYAMN_PROTOREGISTRATION)wParam;
+ HYAMNPROTOPLUGIN Plugin;
+
+ if (lParam != YAMN_PROTOREGISTRATIONVERSION)
+ return 0;
+ if ((Registration->Name == nullptr) || (Registration->Ver == nullptr))
+ return (INT_PTR)NULL;
+ if (nullptr == (Plugin = new YAMN_PROTOPLUGIN))
+ return (INT_PTR)NULL;
+
+ Plugin->PluginInfo = Registration;
+
+ Plugin->FirstAccount = nullptr;
+
+ Plugin->AccountBrowserSO = new SWMRG;
+ SWMRGInitialize(Plugin->AccountBrowserSO, nullptr);
+
+ Plugin->Fcn = nullptr;
+ Plugin->MailFcn = nullptr;
+
+ return (INT_PTR)Plugin;
+}
+
+int WINAPI SetProtocolPluginFcnImportFcn(HYAMNPROTOPLUGIN Plugin, PYAMN_PROTOIMPORTFCN YAMNFcn, uint32_t YAMNFcnVer, PYAMN_MAILIMPORTFCN YAMNMailFcn, uint32_t YAMNMailFcnVer)
+{
+ PYAMN_PROTOPLUGINQUEUE Parser;
+
+ if (YAMNFcnVer != YAMN_PROTOIMPORTFCNVERSION)
+ return 0;
+ if (YAMNMailFcnVer != YAMN_MAILIMPORTFCNVERSION)
+ return 0;
+ if (YAMNFcn == nullptr)
+ return 0;
+ if (YAMNMailFcn == nullptr)
+ return 0;
+
+ Plugin->Fcn = YAMNFcn;
+ Plugin->MailFcn = YAMNMailFcn;
+
+ mir_cslock lck(PluginRegCS);
+ // We add protocol to the protocol list
+ for (Parser = FirstProtoPlugin; Parser != nullptr && Parser->Next != nullptr; Parser = Parser->Next);
+ if (Parser == nullptr) {
+ FirstProtoPlugin = new YAMN_PROTOPLUGINQUEUE;
+ Parser = FirstProtoPlugin;
+ }
+ else {
+ Parser->Next = new YAMN_PROTOPLUGINQUEUE;
+ Parser = Parser->Next;
+ }
+
+ Parser->Plugin = Plugin;
+ Parser->Next = nullptr;
+ return 1;
+}
+
+INT_PTR UnregisterProtocolPlugin(HYAMNPROTOPLUGIN Plugin)
+{
+ PYAMN_PROTOPLUGINQUEUE Parser, Found;
+
+ if (FirstProtoPlugin->Plugin == Plugin) {
+ Found = FirstProtoPlugin;
+ FirstProtoPlugin = FirstProtoPlugin->Next;
+ }
+ else {
+ for (Parser = FirstProtoPlugin; (Parser->Next != nullptr) && (Plugin != Parser->Next->Plugin); Parser = Parser->Next);
+ if (Parser->Next != nullptr) {
+ Found = Parser->Next;
+ Parser->Next = Parser->Next->Next;
+ }
+ else
+ Found = nullptr;
+ }
+ if (Found != nullptr) {
+ StopAccounts(Plugin);
+ DeleteAccounts(Plugin);
+ if (Plugin->Fcn->UnLoadFcn != nullptr)
+ Plugin->Fcn->UnLoadFcn((void *)nullptr);
+
+ delete Found->Plugin->AccountBrowserSO;
+ delete Found->Plugin;
+ delete Found;
+ }
+ else
+ return 0;
+ return 1;
+}
+
+INT_PTR UnregisterProtocolPluginSvc(WPARAM wParam, LPARAM)
+{
+ HYAMNPROTOPLUGIN Plugin = (HYAMNPROTOPLUGIN)wParam;
+
+ mir_cslock lck(PluginRegCS);
+ UnregisterProtocolPlugin(Plugin);
+ return 1;
+}
+
+INT_PTR UnregisterProtoPlugins()
+{
+ mir_cslock lck(PluginRegCS);
+ // We remove protocols from the protocol list
+ while (FirstProtoPlugin != nullptr)
+ UnregisterProtocolPlugin(FirstProtoPlugin->Plugin);
+ return 1;
+}
+
+INT_PTR GetFileNameSvc(WPARAM wParam, LPARAM)
+{
+ wchar_t *FileName = new wchar_t[MAX_PATH];
+ if (FileName == nullptr)
+ return NULL;
+
+ mir_snwprintf(FileName, MAX_PATH, L"%s\\yamn-accounts.%s.%s.book", UserDirectory, (wchar_t *)wParam, ProfileName);
+ return (INT_PTR)FileName;
+}
+
+INT_PTR DeleteFileNameSvc(WPARAM wParam, LPARAM)
+{
+ if ((wchar_t *)wParam != nullptr)
+ delete[](wchar_t *) wParam;
+
+ return 0;
+}
diff --git a/protocols/YAMN/src/resource.h b/protocols/YAMN/src/resource.h index 3f6a52fa55..70cb2647c8 100644 --- a/protocols/YAMN/src/resource.h +++ b/protocols/YAMN/src/resource.h @@ -1,111 +1,111 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by W:\miranda-ng\protocols\YAMN\res\YAMN.rc -// -#define IDI_CHECKMAIL 104 -#define IDI_LAUNCHAPP 105 -#define IDD_DLGVIEWMESSAGES 107 -#define IDD_DLGSHOWMESSAGE 108 -#define IDI_ICOYAMN2 112 -#define IDI_ICOYAMN1 113 -#define IDD_DLGBADCONNECT 115 -#define IDD_POP3ACCOUNTOPT 121 -#define IDD_YAMNOPT 126 -#define IDI_BADCONNECT 131 -#define IDI_ICOTTBUP 138 -#define IDI_NEWMAIL 159 -#define IDD_CHOOSESTATUSMODES 310 -#define IDD_OPTIONS 311 -#define IDD_POP3ACCOUNTPOPUP 312 -#define IDC_EDITSERVER 1000 -#define IDC_EDITPORT 1001 -#define IDC_EDITLOGIN 1002 -#define IDC_EDITPASS 1003 -#define IDC_COMBOACCOUNT 1005 -#define IDC_BTNDEFAULT 1006 -#define IDC_EDITINTERVAL 1007 -#define IDC_CHECKSND 1008 -#define IDC_CHECKMSG 1009 -#define IDC_CHECKAPP 1010 -#define IDC_BTNAPP 1011 -#define IDC_CHECKICO 1012 -#define IDC_CHECK 1013 -#define IDC_BTNDEL 1014 -#define IDC_CHECKFSND 1016 -#define IDC_CHECKFMSG 1017 -#define IDC_CHECKFICO 1018 -#define IDC_CHECKST0 1019 -#define IDC_CHECKST1 1020 -#define IDC_CHECKST2 1021 -#define IDC_CHECKST3 1022 -#define IDC_CHECKST4 1023 -#define IDC_CHECKST5 1024 -#define IDC_CHECKST6 1025 -#define IDC_CHECKST7 1026 -#define IDC_EDITAPP 1027 -#define IDC_CHECKCONTACT 1030 -#define IDC_CHECKCONTACTNICK 1031 -#define IDC_CHECKCONTACTNOEVENT 1032 -#define IDC_STTIMELEFT 1033 -#define IDC_LISTMAILS 1038 -#define IDC_LISTHEADERS 1039 -#define IDC_EDITAPPPARAM 1044 -#define IDC_BTNOK 1047 -#define IDC_COMBOCP 1050 -#define IDC_STATICMSG 1055 -#define IDC_AUTOBODY 1062 -#define IDC_BTNRESET 1063 -#define IDC_CHECKSTART 1064 -#define IDC_STWCHECK 1065 -#define IDC_CHECKFORCE 1066 -#define IDC_RADIOPOP1 1068 -#define IDC_RADIOPOPN 1069 -#define IDC_CPB 1070 -#define IDC_CPNB 1071 -#define IDC_CHECKCOL 1073 -#define IDC_CPT 1074 -#define IDC_CPFB 1075 -#define IDC_CPFT 1076 -#define IDC_CHECKFCOL 1077 -#define IDC_CHECKNCOL 1078 -#define IDC_CPNT 1079 -#define IDC_CHECKPOP 1087 -#define IDC_CHECKNPOP 1088 -#define IDC_CHECKFPOP 1089 -#define IDC_EDITPOPS 1090 -#define IDC_EDITNPOPS 1091 -#define IDC_EDITFPOPS 1092 -#define IDC_GBNEWMAIL 1094 -#define IDC_GBNONEWMAIL 1095 -#define IDC_GBBADCONNECT 1096 -#define IDC_STSTATUS 1102 -#define IDC_CHECKTTB 1117 -#define IDC_CHECKSSL 1117 -#define IDC_CHECKNMSGP 1118 -#define IDC_CHECKNOTLS 1120 -#define IDC_CHECKKBN 1121 -#define IDC_BTNSTATUS 1123 -#define IDC_OPTIONSTAB 1124 -#define IDC_BTNCHECKALL 1125 -#define IDC_CLOSEONDELETE 1127 -#define IDC_LONGDATE 1128 -#define IDC_SMARTDATE 1129 -#define IDC_NOSECONDS 1130 -#define IDC_CHECKAPOP 1200 -#define IDC_STATUSGROUP 1338 -#define IDC_SPLITTER 1400 -#define IDC_EDITBODY 1401 -#define IDC_PREVIEW 1402 -#define IDC_BTNADD 1403 -#define IDC_EDITNAME 1404 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 144 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1407 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif +//{{NO_DEPENDENCIES}}
+// Microsoft Visual C++ generated include file.
+// Used by W:\miranda-ng\protocols\YAMN\res\YAMN.rc
+//
+#define IDI_CHECKMAIL 104
+#define IDI_LAUNCHAPP 105
+#define IDD_DLGVIEWMESSAGES 107
+#define IDD_DLGSHOWMESSAGE 108
+#define IDI_ICOYAMN2 112
+#define IDI_ICOYAMN1 113
+#define IDD_DLGBADCONNECT 115
+#define IDD_POP3ACCOUNTOPT 121
+#define IDD_YAMNOPT 126
+#define IDI_BADCONNECT 131
+#define IDI_ICOTTBUP 138
+#define IDI_NEWMAIL 159
+#define IDD_CHOOSESTATUSMODES 310
+#define IDD_OPTIONS 311
+#define IDD_POP3ACCOUNTPOPUP 312
+#define IDC_EDITSERVER 1000
+#define IDC_EDITPORT 1001
+#define IDC_EDITLOGIN 1002
+#define IDC_EDITPASS 1003
+#define IDC_COMBOACCOUNT 1005
+#define IDC_BTNDEFAULT 1006
+#define IDC_EDITINTERVAL 1007
+#define IDC_CHECKSND 1008
+#define IDC_CHECKMSG 1009
+#define IDC_CHECKAPP 1010
+#define IDC_BTNAPP 1011
+#define IDC_CHECKICO 1012
+#define IDC_CHECK 1013
+#define IDC_BTNDEL 1014
+#define IDC_CHECKFSND 1016
+#define IDC_CHECKFMSG 1017
+#define IDC_CHECKFICO 1018
+#define IDC_CHECKST0 1019
+#define IDC_CHECKST1 1020
+#define IDC_CHECKST2 1021
+#define IDC_CHECKST3 1022
+#define IDC_CHECKST4 1023
+#define IDC_CHECKST5 1024
+#define IDC_CHECKST6 1025
+#define IDC_CHECKST7 1026
+#define IDC_EDITAPP 1027
+#define IDC_CHECKCONTACT 1030
+#define IDC_CHECKCONTACTNICK 1031
+#define IDC_CHECKCONTACTNOEVENT 1032
+#define IDC_STTIMELEFT 1033
+#define IDC_LISTMAILS 1038
+#define IDC_LISTHEADERS 1039
+#define IDC_EDITAPPPARAM 1044
+#define IDC_BTNOK 1047
+#define IDC_COMBOCP 1050
+#define IDC_STATICMSG 1055
+#define IDC_AUTOBODY 1062
+#define IDC_BTNRESET 1063
+#define IDC_CHECKSTART 1064
+#define IDC_STWCHECK 1065
+#define IDC_CHECKFORCE 1066
+#define IDC_RADIOPOP1 1068
+#define IDC_RADIOPOPN 1069
+#define IDC_CPB 1070
+#define IDC_CPNB 1071
+#define IDC_CHECKCOL 1073
+#define IDC_CPT 1074
+#define IDC_CPFB 1075
+#define IDC_CPFT 1076
+#define IDC_CHECKFCOL 1077
+#define IDC_CHECKNCOL 1078
+#define IDC_CPNT 1079
+#define IDC_CHECKPOP 1087
+#define IDC_CHECKNPOP 1088
+#define IDC_CHECKFPOP 1089
+#define IDC_EDITPOPS 1090
+#define IDC_EDITNPOPS 1091
+#define IDC_EDITFPOPS 1092
+#define IDC_GBNEWMAIL 1094
+#define IDC_GBNONEWMAIL 1095
+#define IDC_GBBADCONNECT 1096
+#define IDC_STSTATUS 1102
+#define IDC_CHECKTTB 1117
+#define IDC_CHECKSSL 1117
+#define IDC_CHECKNMSGP 1118
+#define IDC_CHECKNOTLS 1120
+#define IDC_CHECKKBN 1121
+#define IDC_BTNSTATUS 1123
+#define IDC_OPTIONSTAB 1124
+#define IDC_BTNCHECKALL 1125
+#define IDC_CLOSEONDELETE 1127
+#define IDC_LONGDATE 1128
+#define IDC_SMARTDATE 1129
+#define IDC_NOSECONDS 1130
+#define IDC_CHECKAPOP 1200
+#define IDC_STATUSGROUP 1338
+#define IDC_SPLITTER 1400
+#define IDC_EDITBODY 1401
+#define IDC_PREVIEW 1402
+#define IDC_BTNADD 1403
+#define IDC_EDITNAME 1404
+
+// Next default values for new objects
+//
+#ifdef APSTUDIO_INVOKED
+#ifndef APSTUDIO_READONLY_SYMBOLS
+#define _APS_NEXT_RESOURCE_VALUE 144
+#define _APS_NEXT_COMMAND_VALUE 40001
+#define _APS_NEXT_CONTROL_VALUE 1407
+#define _APS_NEXT_SYMED_VALUE 101
+#endif
+#endif
diff --git a/protocols/YAMN/src/services.cpp b/protocols/YAMN/src/services.cpp index 822f5d9f31..361fb01636 100644 --- a/protocols/YAMN/src/services.cpp +++ b/protocols/YAMN/src/services.cpp @@ -1,378 +1,378 @@ -#include "stdafx.h" - -static INT_PTR Service_GetCaps(WPARAM wParam, LPARAM) -{ - switch (wParam) { - case PFLAGNUM_4: - return PF4_NOCUSTOMAUTH; - case PFLAG_UNIQUEIDTEXT: - return (INT_PTR)TranslateT("Nick"); - case PFLAG_MAXLENOFMESSAGE: - return 400; - case PFLAGNUM_2: - case PFLAGNUM_5: - return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND; - } - - return 0; -} - -static INT_PTR Service_GetName(WPARAM wParam, LPARAM lParam) -{ - mir_strncpy((char *)lParam, YAMN_DBMODULE, wParam); - return 0; -} - -static INT_PTR Service_LoadIcon(WPARAM wParam, LPARAM) -{ - if (LOWORD(wParam) == PLI_PROTOCOL) - return (INT_PTR)CopyIcon(g_plugin.getIcon(IDI_CHECKMAIL)); // noone cares about other than PLI_PROTOCOL - - return (INT_PTR)(HICON)NULL; -} - -INT_PTR ClistContactDoubleclicked(WPARAM, LPARAM lParam) -{ - ContactDoubleclicked(((CLISTEVENT *)lParam)->lParam, lParam); - return 0; -} - -static int Service_ContactDoubleclicked(WPARAM wParam, LPARAM lParam) -{ - ContactDoubleclicked(wParam, lParam); - return 0; -} - -static INT_PTR ContactApplication(WPARAM wParam, LPARAM) -{ - char *szProto = Proto_GetBaseAccountName(wParam); - if (mir_strcmp(szProto, YAMN_DBMODULE)) - return 0; - - DBVARIANT dbv; - if (g_plugin.getString(wParam, "Id", &dbv)) - return 0; - - CAccount *ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); - if (ActualAccount != nullptr) { - STARTUPINFOW si = {0}; - si.cb = sizeof(si); - - if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { - if (ActualAccount->NewMailN.App != nullptr) { - wchar_t *Command; - if (ActualAccount->NewMailN.AppParam != nullptr) - Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6]; - else - Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + 6]; - - if (Command != nullptr) { - mir_wstrcpy(Command, L"\""); - mir_wstrcat(Command, ActualAccount->NewMailN.App); - mir_wstrcat(Command, L"\" "); - if (ActualAccount->NewMailN.AppParam != nullptr) - mir_wstrcat(Command, ActualAccount->NewMailN.AppParam); - - PROCESS_INFORMATION pi; - CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi); - delete[] Command; - } - } - - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - } - db_free(&dbv); - return 0; -} - -uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout); -static INT_PTR AccountMailCheck(WPARAM wParam, LPARAM lParam) -{ - //This service will check/sincronize the account pointed by wParam - CAccount *ActualAccount = (CAccount *)wParam; - // copy/paste make mistakes - if (ActualAccount != nullptr) { - //we use event to signal, that running thread has all needed stack parameters copied - HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (ThreadRunningEV == nullptr) - 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; - - mir_cslock lck(PluginRegCS); - if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualAccount->AccountAccessSO, 0)) { - } - else { - if ((ActualAccount->Flags & YAMN_ACC_ENA) && ActualAccount->Plugin->Fcn->SynchroFcnPtr) { - CheckParam ParamToPlugin = {YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, lParam != 0 ? YAMN_FORCECHECK : YAMN_NORMALCHECK, nullptr, nullptr}; - - ActualAccount->TimeLeft = ActualAccount->Interval; - DWORD tid; - HANDLE NewThread = CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->SynchroFcnPtr, &ParamToPlugin, 0, &tid); - if (NewThread) { - WaitForSingleObject(ThreadRunningEV, INFINITE); - CloseHandle(NewThread); - } - } - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - CloseHandle(ThreadRunningEV); - } - return 0; -} - -static INT_PTR ContactMailCheck(WPARAM hContact, LPARAM) -{ - char *szProto = Proto_GetBaseAccountName(hContact); - if (mir_strcmp(szProto, YAMN_DBMODULE)) - return 0; - - DBVARIANT dbv; - if (g_plugin.getString(hContact, "Id", &dbv)) - return 0; - - CAccount *ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); - if (ActualAccount != nullptr) { - //we use event to signal, that running thread has all needed stack parameters copied - HANDLE ThreadRunningEV; - if (nullptr == (ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr))) - 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; - mir_cslock lck(PluginRegCS); - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) { - } - else { - if ((ActualAccount->Flags & YAMN_ACC_ENA) && (ActualAccount->StatusFlags & YAMN_ACC_FORCE)) //account cannot be forced to check - { - if (ActualAccount->Plugin->Fcn->ForceCheckFcnPtr == nullptr) - ReadDoneFcn(ActualAccount->AccountAccessSO); - - DWORD tid; - struct CheckParam ParamToPlugin = {YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_FORCECHECK, (void *)nullptr, nullptr}; - if (nullptr == CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->ForceCheckFcnPtr, &ParamToPlugin, 0, &tid)) - ReadDoneFcn(ActualAccount->AccountAccessSO); - else - WaitForSingleObject(ThreadRunningEV, INFINITE); - } - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - CloseHandle(ThreadRunningEV); - } - db_free(&dbv); - return 0; -} - -/*static*/ void ContactDoubleclicked(WPARAM wParam, LPARAM) -{ - char *szProto = Proto_GetBaseAccountName(wParam); - if (mir_strcmp(szProto, YAMN_DBMODULE)) - return; - - DBVARIANT dbv; - if (g_plugin.getString(wParam, "Id", &dbv)) - return; - - CAccount *ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); - if (ActualAccount != nullptr) { - if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { - YAMN_MAILBROWSERPARAM Param = {nullptr, ActualAccount, ActualAccount->NewMailN.Flags, ActualAccount->NoNewMailN.Flags, nullptr}; - - Param.nnflags = Param.nnflags | YAMN_ACC_MSG; //show mails in account even no new mail in account - Param.nnflags = Param.nnflags & ~YAMN_ACC_POP; - - Param.nflags = Param.nflags | YAMN_ACC_MSG; //show mails in account even no new mail in account - Param.nflags = Param.nflags & ~YAMN_ACC_POP; - - RunMailBrowserSvc((WPARAM)&Param, YAMN_MAILBROWSERVERSION); - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - } - db_free(&dbv); -} - -///////////////////////////////////////////////////////////////////////////////////////// - -HBITMAP LoadBmpFromIcon(HICON hIcon) -{ - int IconSizeX = 16; - int IconSizeY = 16; - - HBRUSH hBkgBrush = CreateSolidBrush(GetSysColor(COLOR_3DFACE)); - - BITMAPINFOHEADER bih = {0}; - bih.biSize = sizeof(bih); - bih.biBitCount = 24; - bih.biPlanes = 1; - bih.biCompression = BI_RGB; - bih.biHeight = IconSizeY; - bih.biWidth = IconSizeX; - - RECT rc; - rc.top = rc.left = 0; - rc.right = bih.biWidth; - rc.bottom = bih.biHeight; - - HDC hdc = GetDC(nullptr); - HBITMAP hBmp = CreateCompatibleBitmap(hdc, bih.biWidth, bih.biHeight); - HDC hdcMem = CreateCompatibleDC(hdc); - HBITMAP hoBmp = (HBITMAP)SelectObject(hdcMem, hBmp); - FillRect(hdcMem, &rc, hBkgBrush); - DrawIconEx(hdcMem, 0, 0, hIcon, bih.biWidth, bih.biHeight, 0, nullptr, DI_NORMAL); - SelectObject(hdcMem, hoBmp); - return hBmp; -} - -int AddTopToolbarIcon(WPARAM, LPARAM) -{ - if (g_plugin.getByte(YAMN_TTBFCHECK, 1)) { - if (ServiceExists(MS_TTB_REMOVEBUTTON) && hTTButton == nullptr) { - TTBButton btn = {}; - btn.pszService = MS_YAMN_FORCECHECK; - btn.dwFlags = TTBBF_VISIBLE | TTBBF_SHOWTOOLTIP; - btn.hIconHandleUp = btn.hIconHandleDn = g_plugin.getIconHandle(IDI_CHECKMAIL); - btn.name = btn.pszTooltipUp = LPGEN("Check mail"); - hTTButton = g_plugin.addTTB(&btn); - } - } - else { - if (hTTButton != nullptr) { - CallService(MS_TTB_REMOVEBUTTON, (WPARAM)hTTButton, 0); - hTTButton = nullptr; - } - } - - return 0; -} - -///////////////////////////////////////////////////////////////////////////////////////// - -int Shutdown(WPARAM, LPARAM) -{ - CallService(MS_TTB_REMOVEBUTTON, (WPARAM)hTTButton, 0); - - g_plugin.setDword(YAMN_DBMSGPOSX, HeadPosX); - g_plugin.setDword(YAMN_DBMSGPOSY, HeadPosY); - g_plugin.setDword(YAMN_DBMSGSIZEX, HeadSizeX); - g_plugin.setDword(YAMN_DBMSGSIZEY, HeadSizeY); - g_plugin.setWord(YAMN_DBMSGPOSSPLIT, HeadSplitPos); - YAMNVar.Shutdown = TRUE; - KillTimer(nullptr, SecTimer); - - UnregisterProtoPlugins(); - UnregisterFilterPlugins(); - return 0; -} - -int SystemModulesLoaded(WPARAM, LPARAM); //in main.cpp - -void HookEvents(void) -{ - HookEvent(ME_SYSTEM_MODULESLOADED, SystemModulesLoaded); - HookEvent(ME_TTB_MODULELOADED, AddTopToolbarIcon); - HookEvent(ME_OPT_INITIALISE, YAMNOptInitSvc); - HookEvent(ME_SYSTEM_PRESHUTDOWN, Shutdown); - HookEvent(ME_CLIST_DOUBLECLICKED, Service_ContactDoubleclicked); -} - -void CreateServiceFunctions(void) -{ - // Standard 'protocol' services - CreateServiceFunction(YAMN_DBMODULE PS_GETCAPS, Service_GetCaps); - CreateServiceFunction(YAMN_DBMODULE PS_GETNAME, Service_GetName); - CreateServiceFunction(YAMN_DBMODULE PS_LOADICON, Service_LoadIcon); - - // Function with which protocol plugin can register - CreateServiceFunction(MS_YAMN_GETFCNPTR, GetFcnPtrSvc); - - // Function returns pointer to YAMN variables - CreateServiceFunction(MS_YAMN_GETVARIABLES, GetVariablesSvc); - - // Function with which protocol plugin can register - CreateServiceFunction(MS_YAMN_REGISTERPROTOPLUGIN, RegisterProtocolPluginSvc); - - // Function with which protocol plugin can unregister - CreateServiceFunction(MS_YAMN_UNREGISTERPROTOPLUGIN, UnregisterProtocolPluginSvc); - - // Function creates an account for plugin - CreateServiceFunction(MS_YAMN_CREATEPLUGINACCOUNT, CreatePluginAccountSvc); - - // Function deletes plugin account - CreateServiceFunction(MS_YAMN_DELETEPLUGINACCOUNT, DeletePluginAccountSvc); - - // Finds account for plugin by name - CreateServiceFunction(MS_YAMN_FINDACCOUNTBYNAME, FindAccountByNameSvc); - - // Creates next account for plugin - CreateServiceFunction(MS_YAMN_GETNEXTFREEACCOUNT, GetNextFreeAccountSvc); - - // Function removes account from YAMN queue. Does not delete it from memory - CreateServiceFunction(MS_YAMN_DELETEACCOUNT, DeleteAccountSvc); - - // Function finds accounts for specified plugin - CreateServiceFunction(MS_YAMN_READACCOUNTS, AddAccountsFromFileSvc); - - // Function that stores all plugin mails to one file - CreateServiceFunction(MS_YAMN_WRITEACCOUNTS, WriteAccountsToFileSvc); - - // Function that returns user's filename - CreateServiceFunction(MS_YAMN_GETFILENAME, GetFileNameSvc); - - // Releases unicode string from memory - CreateServiceFunction(MS_YAMN_DELETEFILENAME, DeleteFileNameSvc); - - // Checks mail - CreateServiceFunction(MS_YAMN_FORCECHECK, ForceCheckSvc); - - // Runs YAMN's mail browser - CreateServiceFunction(MS_YAMN_MAILBROWSER, RunMailBrowserSvc); - - // Function creates new mail for plugin - CreateServiceFunction(MS_YAMN_CREATEACCOUNTMAIL, CreateAccountMailSvc); - - // Function deletes plugin account - CreateServiceFunction(MS_YAMN_DELETEACCOUNTMAIL, DeleteAccountMailSvc); - - // Function with which filter plugin can register - CreateServiceFunction(MS_YAMN_REGISTERFILTERPLUGIN, RegisterFilterPluginSvc); - - // Function with which filter plugin can unregister - CreateServiceFunction(MS_YAMN_UNREGISTERFILTERPLUGIN, UnregisterFilterPluginSvc); - - // Function filters mail - CreateServiceFunction(MS_YAMN_FILTERMAIL, FilterMailSvc); - - // Function contact list double click - CreateServiceFunction(MS_YAMN_CLISTDBLCLICK, ClistContactDoubleclicked); - - // Function to check individual account - CreateServiceFunction(MS_YAMN_ACCOUNTCHECK, AccountMailCheck); - - // Function contact list context menu click - CreateServiceFunction(MS_YAMN_CLISTCONTEXT, ContactMailCheck); - - // Function contact list context menu click - CreateServiceFunction(MS_YAMN_CLISTCONTEXTAPP, ContactApplication); -} - -// Function to put all enabled contact to the Online status -void RefreshContact(void) -{ - CAccount *Finder; - for (Finder = POP3Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) { - if (Finder->hContact != NULL) { - Contact::Hide(Finder->hContact, !(Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)); - } - else if ((Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) { - Finder->hContact = db_add_contact(); - Proto_AddToContact(Finder->hContact, YAMN_DBMODULE); - g_plugin.setString(Finder->hContact, "Id", Finder->Name); - g_plugin.setString(Finder->hContact, "Nick", Finder->Name); - g_plugin.setWord(Finder->hContact, "Status", ID_STATUS_ONLINE); - db_set_s(Finder->hContact, "CList", "StatusMsg", Translate("No new mail message")); - } - } -} +#include "stdafx.h"
+
+static INT_PTR Service_GetCaps(WPARAM wParam, LPARAM)
+{
+ switch (wParam) {
+ case PFLAGNUM_4:
+ return PF4_NOCUSTOMAUTH;
+ case PFLAG_UNIQUEIDTEXT:
+ return (INT_PTR)TranslateT("Nick");
+ case PFLAG_MAXLENOFMESSAGE:
+ return 400;
+ case PFLAGNUM_2:
+ case PFLAGNUM_5:
+ return PF2_ONLINE | PF2_SHORTAWAY | PF2_LONGAWAY | PF2_LIGHTDND;
+ }
+
+ return 0;
+}
+
+static INT_PTR Service_GetName(WPARAM wParam, LPARAM lParam)
+{
+ mir_strncpy((char *)lParam, YAMN_DBMODULE, wParam);
+ return 0;
+}
+
+static INT_PTR Service_LoadIcon(WPARAM wParam, LPARAM)
+{
+ if (LOWORD(wParam) == PLI_PROTOCOL)
+ return (INT_PTR)CopyIcon(g_plugin.getIcon(IDI_CHECKMAIL)); // noone cares about other than PLI_PROTOCOL
+
+ return (INT_PTR)(HICON)NULL;
+}
+
+INT_PTR ClistContactDoubleclicked(WPARAM, LPARAM lParam)
+{
+ ContactDoubleclicked(((CLISTEVENT *)lParam)->lParam, lParam);
+ return 0;
+}
+
+static int Service_ContactDoubleclicked(WPARAM wParam, LPARAM lParam)
+{
+ ContactDoubleclicked(wParam, lParam);
+ return 0;
+}
+
+static INT_PTR ContactApplication(WPARAM wParam, LPARAM)
+{
+ char *szProto = Proto_GetBaseAccountName(wParam);
+ if (mir_strcmp(szProto, YAMN_DBMODULE))
+ return 0;
+
+ DBVARIANT dbv;
+ if (g_plugin.getString(wParam, "Id", &dbv))
+ return 0;
+
+ CAccount *ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ if (ActualAccount != nullptr) {
+ STARTUPINFOW si = {0};
+ si.cb = sizeof(si);
+
+ if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ if (ActualAccount->NewMailN.App != nullptr) {
+ wchar_t *Command;
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6];
+ else
+ Command = new wchar_t[mir_wstrlen(ActualAccount->NewMailN.App) + 6];
+
+ if (Command != nullptr) {
+ mir_wstrcpy(Command, L"\"");
+ mir_wstrcat(Command, ActualAccount->NewMailN.App);
+ mir_wstrcat(Command, L"\" ");
+ if (ActualAccount->NewMailN.AppParam != nullptr)
+ mir_wstrcat(Command, ActualAccount->NewMailN.AppParam);
+
+ PROCESS_INFORMATION pi;
+ CreateProcessW(nullptr, Command, nullptr, nullptr, FALSE, NORMAL_PRIORITY_CLASS, nullptr, nullptr, &si, &pi);
+ delete[] Command;
+ }
+ }
+
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ }
+ db_free(&dbv);
+ return 0;
+}
+
+uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout);
+static INT_PTR AccountMailCheck(WPARAM wParam, LPARAM lParam)
+{
+ //This service will check/sincronize the account pointed by wParam
+ CAccount *ActualAccount = (CAccount *)wParam;
+ // copy/paste make mistakes
+ if (ActualAccount != nullptr) {
+ //we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (ThreadRunningEV == nullptr)
+ 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;
+
+ mir_cslock lck(PluginRegCS);
+ if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualAccount->AccountAccessSO, 0)) {
+ }
+ else {
+ if ((ActualAccount->Flags & YAMN_ACC_ENA) && ActualAccount->Plugin->Fcn->SynchroFcnPtr) {
+ CheckParam ParamToPlugin = {YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, lParam != 0 ? YAMN_FORCECHECK : YAMN_NORMALCHECK, nullptr, nullptr};
+
+ ActualAccount->TimeLeft = ActualAccount->Interval;
+ DWORD tid;
+ HANDLE NewThread = CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->SynchroFcnPtr, &ParamToPlugin, 0, &tid);
+ if (NewThread) {
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+ CloseHandle(NewThread);
+ }
+ }
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ CloseHandle(ThreadRunningEV);
+ }
+ return 0;
+}
+
+static INT_PTR ContactMailCheck(WPARAM hContact, LPARAM)
+{
+ char *szProto = Proto_GetBaseAccountName(hContact);
+ if (mir_strcmp(szProto, YAMN_DBMODULE))
+ return 0;
+
+ DBVARIANT dbv;
+ if (g_plugin.getString(hContact, "Id", &dbv))
+ return 0;
+
+ CAccount *ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ if (ActualAccount != nullptr) {
+ //we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV;
+ if (nullptr == (ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr)))
+ 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;
+ mir_cslock lck(PluginRegCS);
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ }
+ else {
+ if ((ActualAccount->Flags & YAMN_ACC_ENA) && (ActualAccount->StatusFlags & YAMN_ACC_FORCE)) //account cannot be forced to check
+ {
+ if (ActualAccount->Plugin->Fcn->ForceCheckFcnPtr == nullptr)
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+
+ DWORD tid;
+ struct CheckParam ParamToPlugin = {YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_FORCECHECK, (void *)nullptr, nullptr};
+ if (nullptr == CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->ForceCheckFcnPtr, &ParamToPlugin, 0, &tid))
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ else
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+ }
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ CloseHandle(ThreadRunningEV);
+ }
+ db_free(&dbv);
+ return 0;
+}
+
+/*static*/ void ContactDoubleclicked(WPARAM wParam, LPARAM)
+{
+ char *szProto = Proto_GetBaseAccountName(wParam);
+ if (mir_strcmp(szProto, YAMN_DBMODULE))
+ return;
+
+ DBVARIANT dbv;
+ if (g_plugin.getString(wParam, "Id", &dbv))
+ return;
+
+ CAccount *ActualAccount = (CAccount *)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal);
+ if (ActualAccount != nullptr) {
+ if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) {
+ YAMN_MAILBROWSERPARAM Param = {nullptr, ActualAccount, ActualAccount->NewMailN.Flags, ActualAccount->NoNewMailN.Flags, nullptr};
+
+ Param.nnflags = Param.nnflags | YAMN_ACC_MSG; //show mails in account even no new mail in account
+ Param.nnflags = Param.nnflags & ~YAMN_ACC_POP;
+
+ Param.nflags = Param.nflags | YAMN_ACC_MSG; //show mails in account even no new mail in account
+ Param.nflags = Param.nflags & ~YAMN_ACC_POP;
+
+ RunMailBrowserSvc((WPARAM)&Param, YAMN_MAILBROWSERVERSION);
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ }
+ db_free(&dbv);
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+HBITMAP LoadBmpFromIcon(HICON hIcon)
+{
+ int IconSizeX = 16;
+ int IconSizeY = 16;
+
+ HBRUSH hBkgBrush = CreateSolidBrush(GetSysColor(COLOR_3DFACE));
+
+ BITMAPINFOHEADER bih = {0};
+ bih.biSize = sizeof(bih);
+ bih.biBitCount = 24;
+ bih.biPlanes = 1;
+ bih.biCompression = BI_RGB;
+ bih.biHeight = IconSizeY;
+ bih.biWidth = IconSizeX;
+
+ RECT rc;
+ rc.top = rc.left = 0;
+ rc.right = bih.biWidth;
+ rc.bottom = bih.biHeight;
+
+ HDC hdc = GetDC(nullptr);
+ HBITMAP hBmp = CreateCompatibleBitmap(hdc, bih.biWidth, bih.biHeight);
+ HDC hdcMem = CreateCompatibleDC(hdc);
+ HBITMAP hoBmp = (HBITMAP)SelectObject(hdcMem, hBmp);
+ FillRect(hdcMem, &rc, hBkgBrush);
+ DrawIconEx(hdcMem, 0, 0, hIcon, bih.biWidth, bih.biHeight, 0, nullptr, DI_NORMAL);
+ SelectObject(hdcMem, hoBmp);
+ return hBmp;
+}
+
+int AddTopToolbarIcon(WPARAM, LPARAM)
+{
+ if (g_plugin.getByte(YAMN_TTBFCHECK, 1)) {
+ if (ServiceExists(MS_TTB_REMOVEBUTTON) && hTTButton == nullptr) {
+ TTBButton btn = {};
+ btn.pszService = MS_YAMN_FORCECHECK;
+ btn.dwFlags = TTBBF_VISIBLE | TTBBF_SHOWTOOLTIP;
+ btn.hIconHandleUp = btn.hIconHandleDn = g_plugin.getIconHandle(IDI_CHECKMAIL);
+ btn.name = btn.pszTooltipUp = LPGEN("Check mail");
+ hTTButton = g_plugin.addTTB(&btn);
+ }
+ }
+ else {
+ if (hTTButton != nullptr) {
+ CallService(MS_TTB_REMOVEBUTTON, (WPARAM)hTTButton, 0);
+ hTTButton = nullptr;
+ }
+ }
+
+ return 0;
+}
+
+/////////////////////////////////////////////////////////////////////////////////////////
+
+int Shutdown(WPARAM, LPARAM)
+{
+ CallService(MS_TTB_REMOVEBUTTON, (WPARAM)hTTButton, 0);
+
+ g_plugin.setDword(YAMN_DBMSGPOSX, HeadPosX);
+ g_plugin.setDword(YAMN_DBMSGPOSY, HeadPosY);
+ g_plugin.setDword(YAMN_DBMSGSIZEX, HeadSizeX);
+ g_plugin.setDword(YAMN_DBMSGSIZEY, HeadSizeY);
+ g_plugin.setWord(YAMN_DBMSGPOSSPLIT, HeadSplitPos);
+ YAMNVar.Shutdown = TRUE;
+ KillTimer(nullptr, SecTimer);
+
+ UnregisterProtoPlugins();
+ UnregisterFilterPlugins();
+ return 0;
+}
+
+int SystemModulesLoaded(WPARAM, LPARAM); //in main.cpp
+
+void HookEvents(void)
+{
+ HookEvent(ME_SYSTEM_MODULESLOADED, SystemModulesLoaded);
+ HookEvent(ME_TTB_MODULELOADED, AddTopToolbarIcon);
+ HookEvent(ME_OPT_INITIALISE, YAMNOptInitSvc);
+ HookEvent(ME_SYSTEM_PRESHUTDOWN, Shutdown);
+ HookEvent(ME_CLIST_DOUBLECLICKED, Service_ContactDoubleclicked);
+}
+
+void CreateServiceFunctions(void)
+{
+ // Standard 'protocol' services
+ CreateServiceFunction(YAMN_DBMODULE PS_GETCAPS, Service_GetCaps);
+ CreateServiceFunction(YAMN_DBMODULE PS_GETNAME, Service_GetName);
+ CreateServiceFunction(YAMN_DBMODULE PS_LOADICON, Service_LoadIcon);
+
+ // Function with which protocol plugin can register
+ CreateServiceFunction(MS_YAMN_GETFCNPTR, GetFcnPtrSvc);
+
+ // Function returns pointer to YAMN variables
+ CreateServiceFunction(MS_YAMN_GETVARIABLES, GetVariablesSvc);
+
+ // Function with which protocol plugin can register
+ CreateServiceFunction(MS_YAMN_REGISTERPROTOPLUGIN, RegisterProtocolPluginSvc);
+
+ // Function with which protocol plugin can unregister
+ CreateServiceFunction(MS_YAMN_UNREGISTERPROTOPLUGIN, UnregisterProtocolPluginSvc);
+
+ // Function creates an account for plugin
+ CreateServiceFunction(MS_YAMN_CREATEPLUGINACCOUNT, CreatePluginAccountSvc);
+
+ // Function deletes plugin account
+ CreateServiceFunction(MS_YAMN_DELETEPLUGINACCOUNT, DeletePluginAccountSvc);
+
+ // Finds account for plugin by name
+ CreateServiceFunction(MS_YAMN_FINDACCOUNTBYNAME, FindAccountByNameSvc);
+
+ // Creates next account for plugin
+ CreateServiceFunction(MS_YAMN_GETNEXTFREEACCOUNT, GetNextFreeAccountSvc);
+
+ // Function removes account from YAMN queue. Does not delete it from memory
+ CreateServiceFunction(MS_YAMN_DELETEACCOUNT, DeleteAccountSvc);
+
+ // Function finds accounts for specified plugin
+ CreateServiceFunction(MS_YAMN_READACCOUNTS, AddAccountsFromFileSvc);
+
+ // Function that stores all plugin mails to one file
+ CreateServiceFunction(MS_YAMN_WRITEACCOUNTS, WriteAccountsToFileSvc);
+
+ // Function that returns user's filename
+ CreateServiceFunction(MS_YAMN_GETFILENAME, GetFileNameSvc);
+
+ // Releases unicode string from memory
+ CreateServiceFunction(MS_YAMN_DELETEFILENAME, DeleteFileNameSvc);
+
+ // Checks mail
+ CreateServiceFunction(MS_YAMN_FORCECHECK, ForceCheckSvc);
+
+ // Runs YAMN's mail browser
+ CreateServiceFunction(MS_YAMN_MAILBROWSER, RunMailBrowserSvc);
+
+ // Function creates new mail for plugin
+ CreateServiceFunction(MS_YAMN_CREATEACCOUNTMAIL, CreateAccountMailSvc);
+
+ // Function deletes plugin account
+ CreateServiceFunction(MS_YAMN_DELETEACCOUNTMAIL, DeleteAccountMailSvc);
+
+ // Function with which filter plugin can register
+ CreateServiceFunction(MS_YAMN_REGISTERFILTERPLUGIN, RegisterFilterPluginSvc);
+
+ // Function with which filter plugin can unregister
+ CreateServiceFunction(MS_YAMN_UNREGISTERFILTERPLUGIN, UnregisterFilterPluginSvc);
+
+ // Function filters mail
+ CreateServiceFunction(MS_YAMN_FILTERMAIL, FilterMailSvc);
+
+ // Function contact list double click
+ CreateServiceFunction(MS_YAMN_CLISTDBLCLICK, ClistContactDoubleclicked);
+
+ // Function to check individual account
+ CreateServiceFunction(MS_YAMN_ACCOUNTCHECK, AccountMailCheck);
+
+ // Function contact list context menu click
+ CreateServiceFunction(MS_YAMN_CLISTCONTEXT, ContactMailCheck);
+
+ // Function contact list context menu click
+ CreateServiceFunction(MS_YAMN_CLISTCONTEXTAPP, ContactApplication);
+}
+
+// Function to put all enabled contact to the Online status
+void RefreshContact(void)
+{
+ CAccount *Finder;
+ for (Finder = POP3Plugin->FirstAccount; Finder != nullptr; Finder = Finder->Next) {
+ if (Finder->hContact != NULL) {
+ Contact::Hide(Finder->hContact, !(Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT));
+ }
+ else if ((Finder->Flags & YAMN_ACC_ENA) && (Finder->NewMailN.Flags & YAMN_ACC_CONT)) {
+ Finder->hContact = db_add_contact();
+ Proto_AddToContact(Finder->hContact, YAMN_DBMODULE);
+ g_plugin.setString(Finder->hContact, "Id", Finder->Name);
+ g_plugin.setString(Finder->hContact, "Nick", Finder->Name);
+ g_plugin.setWord(Finder->hContact, "Status", ID_STATUS_ONLINE);
+ db_set_s(Finder->hContact, "CList", "StatusMsg", Translate("No new mail message"));
+ }
+ }
+}
diff --git a/protocols/YAMN/src/stdafx.h b/protocols/YAMN/src/stdafx.h index 05681d467b..38f1c1b5fe 100644 --- a/protocols/YAMN/src/stdafx.h +++ b/protocols/YAMN/src/stdafx.h @@ -1,253 +1,253 @@ - -#ifndef __YAMN_H -#define __YAMN_H - -#define VC_EXTRALEAN - -#include <windows.h> -#include <windowsx.h> -#include <commctrl.h> - -#include <newpluginapi.h> -#include <m_clistint.h> -#include <m_contacts.h> -#include <m_database.h> -#include <m_hotkeys.h> -#include <m_icolib.h> -#include <m_langpack.h> -#include <m_messages.h> -#include <m_netlib.h> -#include <m_options.h> -#include <m_popup.h> -#include <m_protosvc.h> -#include <m_skin.h> -#include <m_timezones.h> - -#include <m_toptoolbar.h> -#include <m_kbdnotify.h> -#include <m_filterplugin.h> -#include <m_yamn.h> -#include <m_protoplugin.h> -#include <m_folders.h> - -#include "main.h" -#include "mails/decode.h" -#include "browser/browser.h" -#include "resource.h" -#include "debug.h" -#include "version.h" -#include "proto/netclient.h" -#include "proto/netlib.h" -#include "proto/pop3/pop3.h" -#include "proto/pop3/pop3comm.h" - -struct CMPlugin : public PLUGIN<CMPlugin> -{ - CMPlugin(); - - int Load() override; - int Unload() override; -}; - -// From services.cpp -void CreateServiceFunctions(void); -void HookEvents(void); -void RefreshContact(void); -void ContactDoubleclicked(WPARAM wParam, LPARAM lParam); -INT_PTR ClistContactDoubleclicked(WPARAM wParam, LPARAM lParam); - -extern mir_cs PluginRegCS; -extern SCOUNTER *AccountWriterSO; -extern HANDLE ExitEV; -extern HANDLE WriteToFileEV; - -// From debug.cpp -#ifdef _DEBUG -void InitDebug(); -void UnInitDebug(); -#endif - -// From yamn.cpp -INT_PTR GetFcnPtrSvc(WPARAM wParam, LPARAM lParam); -INT_PTR GetVariablesSvc(WPARAM, LPARAM); -void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD); -INT_PTR ForceCheckSvc(WPARAM, LPARAM); - -extern struct YAMNExportedFcns *pYAMNFcn; - -// From account.cpp -INT_PTR CreatePluginAccountSvc(WPARAM wParam, LPARAM lParam); -INT_PTR DeletePluginAccountSvc(WPARAM wParam, LPARAM); -int InitAccount(CAccount *Which); -void DeInitAccount(CAccount *Which); -void StopSignalFcn(CAccount *Which); -void CodeDecodeString(char *Dest, BOOL Encrypt); -uint32_t FileToMemory(wchar_t *FileName, char **MemFile, char **End); - -#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES) -uint32_t ReadStringFromMemory(char **Parser,char *End,char **StoreTo,char *DebugString); -#endif -uint32_t ReadStringFromMemory(char **Parser, char *End, char **StoreTo); -uint32_t ReadMessagesFromMemory(CAccount *Which, char **Parser, char *End); -uint32_t ReadAccountFromMemory(CAccount *Which, char **Parser, wchar_t *End); -INT_PTR AddAccountsFromFileSvc(WPARAM wParam, LPARAM lParam); - -uint32_t WriteStringToFile(HANDLE File, char *Source); -uint32_t WriteStringToFileW(HANDLE File, wchar_t *Source); - - -DWORD WriteMessagesToFile(HANDLE File, CAccount *Which); -DWORD WINAPI WritePOP3Accounts(); -INT_PTR WriteAccountsToFileSvc(WPARAM wParam, LPARAM lParam); -INT_PTR FindAccountByNameSvc(WPARAM wParam, LPARAM lParam); -INT_PTR GetNextFreeAccountSvc(WPARAM wParam, LPARAM lParam); - -INT_PTR DeleteAccountSvc(WPARAM wParam, LPARAM); -void __cdecl DeleteAccountInBackground(void *Which); -int StopAccounts(HYAMNPROTOPLUGIN Plugin); -int WaitForAllAccounts(HYAMNPROTOPLUGIN Plugin, BOOL GetAccountBrowserAccess = FALSE); -int DeleteAccounts(HYAMNPROTOPLUGIN Plugin); - -void WINAPI GetStatusFcn(CAccount *Which, wchar_t *Value); -void WINAPI SetStatusFcn(CAccount *Which, wchar_t *Value); - -INT_PTR UnregisterProtoPlugins(); -INT_PTR RegisterProtocolPluginSvc(WPARAM, LPARAM); -INT_PTR UnregisterProtocolPluginSvc(WPARAM, LPARAM); -INT_PTR GetFileNameSvc(WPARAM, LPARAM); -INT_PTR DeleteFileNameSvc(WPARAM, LPARAM); - -//From filterplugin.cpp -//struct CExportedFunctions FilterPluginExported[]; -INT_PTR UnregisterFilterPlugins(); -INT_PTR RegisterFilterPluginSvc(WPARAM, LPARAM); -INT_PTR UnregisterFilterPluginSvc(WPARAM, LPARAM); -INT_PTR FilterMailSvc(WPARAM, LPARAM); - -//From mails.cpp (MIME) -//struct CExportedFunctions MailExported[]; -INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam); -INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam); -INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam); -INT_PTR UnloadMailDataSvc(WPARAM wParam, LPARAM); -INT_PTR SaveMailDataSvc(WPARAM wParam, LPARAM lParam); - -//From mime.cpp -//void WINAPI ExtractHeaderFcn(char *,int,uint16_t,HYAMNMAIL); //already in MailExported -struct _tcptable -{ - char *NameBase, *NameSub; - BOOLEAN isValid; - unsigned short int CP; -}; -extern struct _tcptable CodePageNamesAll[]; // in mime/decode.cpp -extern int CPLENALL; -extern struct _tcptable *CodePageNamesSupp; // in mime/decode.cpp -extern int CPLENSUPP; - -extern int PosX, PosY, SizeX, SizeY; -extern int HeadPosX, HeadPosY, HeadSizeX, HeadSizeY, HeadSplitPos; - -//#define CPDEFINDEX 63 //ISO-8859-1 -#define CPDEFINDEX 0 //ACP - -//From pop3comm.cpp -int RegisterPOP3Plugin(WPARAM, LPARAM); - -//From mailbrowser.cpp -INT_PTR RunMailBrowserSvc(WPARAM, LPARAM); - -//From badconnect.cpp -int RunBadConnection(CAccount *acc, UINT_PTR iErrorCode, void *pUserInfo); - -//From YAMNopts.cpp -int YAMNOptInitSvc(WPARAM, LPARAM); - -//From main.cpp -int PostLoad(WPARAM, LPARAM); //Executed after all plugins loaded YAMN reads mails from file and notify every protocol it should set its functions -int Shutdown(WPARAM, LPARAM); //Executed before Miranda is going to shutdown -int AddTopToolbarIcon(WPARAM, LPARAM); //Executed when TopToolBar plugin loaded Adds bitmap to toolbar - -extern wchar_t UserDirectory[]; //e.g. "F:\WINNT\Profiles\UserXYZ" -extern wchar_t ProfileName[]; //e.g. "majvan" -extern SWMRG *AccountBrowserSO; -extern YAMN_VARIABLES YAMNVar; -extern HANDLE hNewMailHook; -extern HANDLE hTTButton; -extern HCURSOR hCurSplitNS, hCurSplitWE; -extern UINT SecTimer; - -//From synchro.cpp -void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From); -uint32_t WINAPI WaitToWriteFcn(PSWMRG SObject, PSCOUNTER SCounter = nullptr); -void WINAPI WriteDoneFcn(PSWMRG SObject, PSCOUNTER SCounter = nullptr); -uint32_t WINAPI WaitToReadFcn(PSWMRG SObject); -void WINAPI ReadDoneFcn(PSWMRG SObject); -uint32_t WINAPI SCIncFcn(PSCOUNTER SCounter); -uint32_t WINAPI SCDecFcn(PSCOUNTER SCounter); -BOOL WINAPI SWMRGInitialize(PSWMRG, wchar_t *); -void WINAPI SWMRGDelete(PSWMRG); -uint32_t WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG, uint32_t dwTimeout); -void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG); -uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout); -void WINAPI SWMRGDoneReading(PSWMRG pSWMRG); - -//From mails.cpp -void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode); -void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSet, int mode); - -//From mime.cpp -void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head); -void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head); -void DeleteHeaderContent(struct CHeader *head); -void DeleteShortHeaderContent(struct CShortHeader *head); -char *ExtractFromContentType(char *ContentType, char *value); -wchar_t *ParseMultipartBody(char *src, char *bond); - -//From account.cpp -void WINAPI GetStatusFcn(CAccount *Which, wchar_t *Value); - -extern HYAMNPROTOPLUGIN POP3Plugin; - -//from decode.cpp -int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ); -int DecodeBase64(char *Src, char *Dst, int DstLen); - -//From filterplugin.cpp -extern PYAMN_FILTERPLUGINQUEUE FirstFilterPlugin; - -//From protoplugin.cpp -extern PYAMN_PROTOPLUGINQUEUE FirstProtoPlugin; - -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]; - -extern char *iconDescs[]; -extern char *iconNames[]; -extern HIMAGELIST CSImages; - -extern void __stdcall SSL_DebugLog(const char *fmt, ...); - -extern struct WndHandles *MessageWnd; - -extern int GetCharsetFromString(char *input, size_t size); -extern void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode); -extern void __cdecl MailBrowser(void *Param); -extern void __cdecl BadConnection(void *Param); -extern PVOID TLSCtx; -extern PVOID SSLCtx; - -extern PYAMN_VARIABLES pYAMNVar; - -#endif +
+#ifndef __YAMN_H
+#define __YAMN_H
+
+#define VC_EXTRALEAN
+
+#include <windows.h>
+#include <windowsx.h>
+#include <commctrl.h>
+
+#include <newpluginapi.h>
+#include <m_clistint.h>
+#include <m_contacts.h>
+#include <m_database.h>
+#include <m_hotkeys.h>
+#include <m_icolib.h>
+#include <m_langpack.h>
+#include <m_messages.h>
+#include <m_netlib.h>
+#include <m_options.h>
+#include <m_popup.h>
+#include <m_protosvc.h>
+#include <m_skin.h>
+#include <m_timezones.h>
+
+#include <m_toptoolbar.h>
+#include <m_kbdnotify.h>
+#include <m_filterplugin.h>
+#include <m_yamn.h>
+#include <m_protoplugin.h>
+#include <m_folders.h>
+
+#include "main.h"
+#include "mails/decode.h"
+#include "browser/browser.h"
+#include "resource.h"
+#include "debug.h"
+#include "version.h"
+#include "proto/netclient.h"
+#include "proto/netlib.h"
+#include "proto/pop3/pop3.h"
+#include "proto/pop3/pop3comm.h"
+
+struct CMPlugin : public PLUGIN<CMPlugin>
+{
+ CMPlugin();
+
+ int Load() override;
+ int Unload() override;
+};
+
+// From services.cpp
+void CreateServiceFunctions(void);
+void HookEvents(void);
+void RefreshContact(void);
+void ContactDoubleclicked(WPARAM wParam, LPARAM lParam);
+INT_PTR ClistContactDoubleclicked(WPARAM wParam, LPARAM lParam);
+
+extern mir_cs PluginRegCS;
+extern SCOUNTER *AccountWriterSO;
+extern HANDLE ExitEV;
+extern HANDLE WriteToFileEV;
+
+// From debug.cpp
+#ifdef _DEBUG
+void InitDebug();
+void UnInitDebug();
+#endif
+
+// From yamn.cpp
+INT_PTR GetFcnPtrSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR GetVariablesSvc(WPARAM, LPARAM);
+void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD);
+INT_PTR ForceCheckSvc(WPARAM, LPARAM);
+
+extern struct YAMNExportedFcns *pYAMNFcn;
+
+// From account.cpp
+INT_PTR CreatePluginAccountSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR DeletePluginAccountSvc(WPARAM wParam, LPARAM);
+int InitAccount(CAccount *Which);
+void DeInitAccount(CAccount *Which);
+void StopSignalFcn(CAccount *Which);
+void CodeDecodeString(char *Dest, BOOL Encrypt);
+uint32_t FileToMemory(wchar_t *FileName, char **MemFile, char **End);
+
+#if defined(DEBUG_FILEREAD) || defined(DEBUG_FILEREADMESSAGES)
+uint32_t ReadStringFromMemory(char **Parser,char *End,char **StoreTo,char *DebugString);
+#endif
+uint32_t ReadStringFromMemory(char **Parser, char *End, char **StoreTo);
+uint32_t ReadMessagesFromMemory(CAccount *Which, char **Parser, char *End);
+uint32_t ReadAccountFromMemory(CAccount *Which, char **Parser, wchar_t *End);
+INT_PTR AddAccountsFromFileSvc(WPARAM wParam, LPARAM lParam);
+
+uint32_t WriteStringToFile(HANDLE File, char *Source);
+uint32_t WriteStringToFileW(HANDLE File, wchar_t *Source);
+
+
+DWORD WriteMessagesToFile(HANDLE File, CAccount *Which);
+DWORD WINAPI WritePOP3Accounts();
+INT_PTR WriteAccountsToFileSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR FindAccountByNameSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR GetNextFreeAccountSvc(WPARAM wParam, LPARAM lParam);
+
+INT_PTR DeleteAccountSvc(WPARAM wParam, LPARAM);
+void __cdecl DeleteAccountInBackground(void *Which);
+int StopAccounts(HYAMNPROTOPLUGIN Plugin);
+int WaitForAllAccounts(HYAMNPROTOPLUGIN Plugin, BOOL GetAccountBrowserAccess = FALSE);
+int DeleteAccounts(HYAMNPROTOPLUGIN Plugin);
+
+void WINAPI GetStatusFcn(CAccount *Which, wchar_t *Value);
+void WINAPI SetStatusFcn(CAccount *Which, wchar_t *Value);
+
+INT_PTR UnregisterProtoPlugins();
+INT_PTR RegisterProtocolPluginSvc(WPARAM, LPARAM);
+INT_PTR UnregisterProtocolPluginSvc(WPARAM, LPARAM);
+INT_PTR GetFileNameSvc(WPARAM, LPARAM);
+INT_PTR DeleteFileNameSvc(WPARAM, LPARAM);
+
+//From filterplugin.cpp
+//struct CExportedFunctions FilterPluginExported[];
+INT_PTR UnregisterFilterPlugins();
+INT_PTR RegisterFilterPluginSvc(WPARAM, LPARAM);
+INT_PTR UnregisterFilterPluginSvc(WPARAM, LPARAM);
+INT_PTR FilterMailSvc(WPARAM, LPARAM);
+
+//From mails.cpp (MIME)
+//struct CExportedFunctions MailExported[];
+INT_PTR CreateAccountMailSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR DeleteAccountMailSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR LoadMailDataSvc(WPARAM wParam, LPARAM lParam);
+INT_PTR UnloadMailDataSvc(WPARAM wParam, LPARAM);
+INT_PTR SaveMailDataSvc(WPARAM wParam, LPARAM lParam);
+
+//From mime.cpp
+//void WINAPI ExtractHeaderFcn(char *,int,uint16_t,HYAMNMAIL); //already in MailExported
+struct _tcptable
+{
+ char *NameBase, *NameSub;
+ BOOLEAN isValid;
+ unsigned short int CP;
+};
+extern struct _tcptable CodePageNamesAll[]; // in mime/decode.cpp
+extern int CPLENALL;
+extern struct _tcptable *CodePageNamesSupp; // in mime/decode.cpp
+extern int CPLENSUPP;
+
+extern int PosX, PosY, SizeX, SizeY;
+extern int HeadPosX, HeadPosY, HeadSizeX, HeadSizeY, HeadSplitPos;
+
+//#define CPDEFINDEX 63 //ISO-8859-1
+#define CPDEFINDEX 0 //ACP
+
+//From pop3comm.cpp
+int RegisterPOP3Plugin(WPARAM, LPARAM);
+
+//From mailbrowser.cpp
+INT_PTR RunMailBrowserSvc(WPARAM, LPARAM);
+
+//From badconnect.cpp
+int RunBadConnection(CAccount *acc, UINT_PTR iErrorCode, void *pUserInfo);
+
+//From YAMNopts.cpp
+int YAMNOptInitSvc(WPARAM, LPARAM);
+
+//From main.cpp
+int PostLoad(WPARAM, LPARAM); //Executed after all plugins loaded YAMN reads mails from file and notify every protocol it should set its functions
+int Shutdown(WPARAM, LPARAM); //Executed before Miranda is going to shutdown
+int AddTopToolbarIcon(WPARAM, LPARAM); //Executed when TopToolBar plugin loaded Adds bitmap to toolbar
+
+extern wchar_t UserDirectory[]; //e.g. "F:\WINNT\Profiles\UserXYZ"
+extern wchar_t ProfileName[]; //e.g. "majvan"
+extern SWMRG *AccountBrowserSO;
+extern YAMN_VARIABLES YAMNVar;
+extern HANDLE hNewMailHook;
+extern HANDLE hTTButton;
+extern HCURSOR hCurSplitNS, hCurSplitWE;
+extern UINT SecTimer;
+
+//From synchro.cpp
+void WINAPI DeleteMessagesToEndFcn(CAccount *Account, HYAMNMAIL From);
+uint32_t WINAPI WaitToWriteFcn(PSWMRG SObject, PSCOUNTER SCounter = nullptr);
+void WINAPI WriteDoneFcn(PSWMRG SObject, PSCOUNTER SCounter = nullptr);
+uint32_t WINAPI WaitToReadFcn(PSWMRG SObject);
+void WINAPI ReadDoneFcn(PSWMRG SObject);
+uint32_t WINAPI SCIncFcn(PSCOUNTER SCounter);
+uint32_t WINAPI SCDecFcn(PSCOUNTER SCounter);
+BOOL WINAPI SWMRGInitialize(PSWMRG, wchar_t *);
+void WINAPI SWMRGDelete(PSWMRG);
+uint32_t WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG, uint32_t dwTimeout);
+void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG);
+uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout);
+void WINAPI SWMRGDoneReading(PSWMRG pSWMRG);
+
+//From mails.cpp
+void WINAPI DeleteMessageFromQueueFcn(HYAMNMAIL *From, HYAMNMAIL Which, int mode);
+void WINAPI SetRemoveFlagsInQueueFcn(HYAMNMAIL From, uint32_t FlagsSet, uint32_t FlagsNotSet, uint32_t FlagsToSet, int mode);
+
+//From mime.cpp
+void ExtractHeader(struct CMimeItem *items, int &CP, struct CHeader *head);
+void ExtractShortHeader(struct CMimeItem *items, struct CShortHeader *head);
+void DeleteHeaderContent(struct CHeader *head);
+void DeleteShortHeaderContent(struct CShortHeader *head);
+char *ExtractFromContentType(char *ContentType, char *value);
+wchar_t *ParseMultipartBody(char *src, char *bond);
+
+//From account.cpp
+void WINAPI GetStatusFcn(CAccount *Which, wchar_t *Value);
+
+extern HYAMNPROTOPLUGIN POP3Plugin;
+
+//from decode.cpp
+int DecodeQuotedPrintable(char *Src, char *Dst, int DstLen, BOOL isQ);
+int DecodeBase64(char *Src, char *Dst, int DstLen);
+
+//From filterplugin.cpp
+extern PYAMN_FILTERPLUGINQUEUE FirstFilterPlugin;
+
+//From protoplugin.cpp
+extern PYAMN_PROTOPLUGINQUEUE FirstProtoPlugin;
+
+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];
+
+extern char *iconDescs[];
+extern char *iconNames[];
+extern HIMAGELIST CSImages;
+
+extern void __stdcall SSL_DebugLog(const char *fmt, ...);
+
+extern struct WndHandles *MessageWnd;
+
+extern int GetCharsetFromString(char *input, size_t size);
+extern void ConvertCodedStringToUnicode(char *stream, wchar_t **storeto, uint32_t cp, int mode);
+extern void __cdecl MailBrowser(void *Param);
+extern void __cdecl BadConnection(void *Param);
+extern PVOID TLSCtx;
+extern PVOID SSLCtx;
+
+extern PYAMN_VARIABLES pYAMNVar;
+
+#endif
diff --git a/protocols/YAMN/src/synchro.cpp b/protocols/YAMN/src/synchro.cpp index c4bb58e6de..184156787d 100644 --- a/protocols/YAMN/src/synchro.cpp +++ b/protocols/YAMN/src/synchro.cpp @@ -1,315 +1,315 @@ -/* - * This code implements synchronization objects code between threads. If you want, you can include it to your - * code. This file is not dependent on any other external code (functions) - * - * (c) majvan 2002-2004 - */ - -#include "stdafx.h" - - // Initializes a SWMRG structure. This structure must be - // initialized before any writer or reader threads attempt - // to wait on it. - // The structure must be allocated by the application and - // the structure's address is passed as the first parameter. - // The lpszName parameter is the name of the object. Pass - // NULL if you do not want to share the object. -BOOL WINAPI SWMRGInitialize(PSWMRG pSWMRG, wchar_t *Name); - -// Deletes the system resources associated with a SWMRG -// structure. The structure must be deleted only when -// no writer or reader threads in the calling process -// will wait on it. -void WINAPI SWMRGDelete(PSWMRG pSWMRG); - -// A writer thread calls this function to know when -// it can successfully write to the shared data. -// returns WAIT_FINISH when we are in write-access or WAIT_FAILED -// when event about quick finishing is set (or when system returns fail when waiting for synchro object) -uint32_t WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG, uint32_t dwTimeout); - -// A writer thread calls this function to let other threads -// know that it no longer needs to write to the shared data. -void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG); - -// A reader thread calls this function to know when -// it can successfully read the shared data. -// returns WAIT_FINISH when we are in read-access or WAIT_FAILED -// when event about quick finishing is set (or when system returns fail when waiting for synchro object) -uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout); - -// A reader thread calls this function to let other threads -// know when it no longer needs to read the shared data. -void WINAPI SWMRGDoneReading(PSWMRG pSWMRG); - -// WaitToReadFcn -// is used to wait for read access with SWMRG SO, but it also increments counter if successfull -// returns WAIT_FAILED or WAIT_FINISH -// when WAIT_FAILED, we should not begin to access datas, we are not in read-access mode -uint32_t WINAPI WaitToReadFcn(PSWMRG SObject); - -// WriteDoneFcn -// is used to release read access with SWMRG SO, but it also decrements counter if successfull -void WINAPI ReadDoneFcn(PSWMRG SObject); - -// This functions is for export purposes -// Plugin can call this function to manage SCOUNTER synchronization object - -// Gets number value stored in SCOUNTER SO -// Note you must not read the number from memory directly, because -// CPU can stop reading thread when it has read HI-Word, then another thread -// can change the value and then OS starts the previous thread, that reads the -// LO-uint16_t of uint32_t. And the return value HI+LO-uint16_t is corrupted -uint32_t WINAPI SCGetNumberFcn(PSCOUNTER SCounter); - -// Increments SCOUNTER and unsets event -// Returns Number after incrementing -uint32_t WINAPI SCIncFcn(PSCOUNTER SCounter); - -// Decrements SCOUNTER and sets event if zero -// Returns Number after decrementing -uint32_t WINAPI SCDecFcn(PSCOUNTER SCounter); - -struct CExportedFunctions SynchroExportedFcn[] = -{ - {YAMN_WAITTOWRITEID, (void *)WaitToWriteFcn}, - {YAMN_WRITEDONEID, (void *)WriteDoneFcn}, - {YAMN_WAITTOREADID, (void *)WaitToReadFcn}, - {YAMN_READDONEID, (void *)ReadDoneFcn}, - {YAMN_SCGETNUMBERID, (void *)SCGetNumberFcn}, - {YAMN_SCINCID, (void *)SCIncFcn}, - {YAMN_SCDECID, (void *)SCDecFcn}, -}; - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -void WINAPI SWMRGDelete(PSWMRG pSWMRG) -{ - // Destroys any synchronization objects that were - // successfully created. - if (nullptr != pSWMRG->hEventNoWriter) - CloseHandle(pSWMRG->hEventNoWriter); - if (nullptr != pSWMRG->hEventNoReaders) - CloseHandle(pSWMRG->hEventNoReaders); - if (nullptr != pSWMRG->hSemNumReaders) - CloseHandle(pSWMRG->hSemNumReaders); - if (nullptr != pSWMRG->hFinishEV) - CloseHandle(pSWMRG->hFinishEV); -} - -BOOL WINAPI SWMRGInitialize(PSWMRG pSWMRG, wchar_t *Name) -{ - pSWMRG->hEventNoWriter = nullptr; - pSWMRG->hEventNoReaders = nullptr; - pSWMRG->hSemNumReaders = nullptr; - pSWMRG->hFinishEV = nullptr; - - // Creates the automatic-reset event that is signalled when - // no writer threads are writing. - // Initially no reader threads are reading. - if (Name != nullptr) - Name[0] = (wchar_t)'W'; - pSWMRG->hEventNoWriter = CreateEvent(nullptr, FALSE, TRUE, Name); - - // Creates the manual-reset event that is signalled when - // no reader threads are reading. - // Initially no reader threads are reading. - if (Name != nullptr) - Name[0] = (wchar_t)'R'; - pSWMRG->hEventNoReaders = CreateEvent(nullptr, TRUE, TRUE, Name); - - // Initializes the variable that indicates the number of - // reader threads that are reading. - // Initially no reader threads are reading. - if (Name != nullptr) - Name[0] = (wchar_t)'C'; - pSWMRG->hSemNumReaders = CreateSemaphore(nullptr, 0, 0x7FFFFFFF, Name); - - if (Name != nullptr) - Name[0] = (wchar_t)'F'; - pSWMRG->hFinishEV = CreateEvent(nullptr, TRUE, FALSE, Name); - - // If a synchronization object could not be created, - // destroys any created objects and return failure. - if ((nullptr == pSWMRG->hEventNoWriter) || (nullptr == pSWMRG->hEventNoReaders) || (nullptr == pSWMRG->hSemNumReaders) || (nullptr == pSWMRG->hFinishEV)) { - SWMRGDelete(pSWMRG); - return FALSE; - } - return TRUE; -} - -uint32_t WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG, uint32_t dwTimeout) -{ - uint32_t dw; - HANDLE aHandles[2]; - - // We can write if the following are true: - // 1. No other threads are writing. - // 2. No threads are reading. - // But first we have to know if SWMRG structure is not about to delete - aHandles[0] = pSWMRG->hEventNoWriter; - aHandles[1] = pSWMRG->hEventNoReaders; - if (WAIT_OBJECT_0 == (dw = WaitForSingleObject(pSWMRG->hFinishEV, 0))) - return WAIT_FINISH; - if (WAIT_FAILED == dw) - return dw; - dw = WaitForMultipleObjects(2, aHandles, TRUE, dwTimeout); - // if a request to delete became later, we should not catch it. Try once more to ask if account is not about to delete - if ((dw != WAIT_FAILED) && (WAIT_OBJECT_0 == (WaitForSingleObject(pSWMRG->hFinishEV, 0)))) { - SetEvent(pSWMRG->hEventNoWriter); - return WAIT_FINISH; - } - - // This thread can write to the shared data. - // Automatic event for NoWriter sets hEventNoWriter to nonsignaled after WaitForMultipleObject - - // Because a writer thread is writing, the Event - // should not be reset. This stops other - // writers and readers. - return dw; -} - -void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG) -// Presumably, a writer thread calling this function has -// successfully called WaitToWrite. This means that we -// do not have to wait on any synchronization objects -// here because the writer already owns the Event. -{ - // Allow other writer/reader threads to use - // the SWMRG synchronization object. - SetEvent(pSWMRG->hEventNoWriter); -} - -uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout) -{ - uint32_t dw; - LONG lPreviousCount; - - // We can read if no threads are writing. - // And there's not request to delete structure - if (WAIT_OBJECT_0 == (dw = WaitForSingleObject(pSWMRG->hFinishEV, 0))) - return WAIT_FINISH; - if (WAIT_FAILED == dw) - return dw; - dw = WaitForSingleObject(pSWMRG->hEventNoWriter, dwTimeout); - // if a request to delete became later, we should not catch it. Try once more to ask if account is not about to delete - if ((dw != WAIT_FAILED) && (WAIT_OBJECT_0 == (WaitForSingleObject(pSWMRG->hFinishEV, 0)))) { - SetEvent(pSWMRG->hEventNoWriter); - return WAIT_FINISH; - } - - if (dw == WAIT_OBJECT_0) { - // This thread can read from the shared data. - // Increment the number of reader threads. - // But there can't be more than one thread incrementing readers, - // so this is why we use semaphore. - ReleaseSemaphore(pSWMRG->hSemNumReaders, 1, &lPreviousCount); - if (lPreviousCount == 0) - // If this is the first reader thread, - // set event to reflect this. Other reader threads can read, no writer thread can write. - ResetEvent(pSWMRG->hEventNoReaders); - - // Allow other writer/reader threads to use - // the SWMRG synchronization object. hEventNoWrite is still non-signaled - // (it looks like writer is processing thread, but it is not true) - SetEvent(pSWMRG->hEventNoWriter); - } - - return(dw); -} - -void WINAPI SWMRGDoneReading(PSWMRG pSWMRG) -{ - HANDLE aHandles[2]; - LONG lNumReaders; - - // We can stop reading if the events are available, - // but when we stop reading we must also decrement the - // number of reader threads. - aHandles[0] = pSWMRG->hEventNoWriter; - aHandles[1] = pSWMRG->hSemNumReaders; - WaitForMultipleObjects(2, aHandles, TRUE, INFINITE); - - // Get the remaining number of readers by releasing the - // semaphore and then restoring the count by immediately - // performing a wait. - ReleaseSemaphore(pSWMRG->hSemNumReaders, 1, &lNumReaders); - WaitForSingleObject(pSWMRG->hSemNumReaders, INFINITE); - - // If there are no remaining readers, - // set the event to relect this. - if (lNumReaders == 0) - // If there are no reader threads, - // set our event to reflect this. - SetEvent(pSWMRG->hEventNoReaders); - - // Allow other writer/reader threads to use - // the SWMRG synchronization object. - // (it looks like writer is processing thread, but it is not true) - SetEvent(pSWMRG->hEventNoWriter); -} - -uint32_t WINAPI WaitToWriteFcn(PSWMRG SObject, PSCOUNTER SCounter) -{ - uint32_t EnterCode; - - if (WAIT_OBJECT_0 == (EnterCode = SWMRGWaitToWrite(SObject, INFINITE))) - if (SCounter != nullptr) - SCIncFcn(SCounter); - - return EnterCode; -} - -void WINAPI WriteDoneFcn(PSWMRG SObject, PSCOUNTER SCounter) -{ - SWMRGDoneWriting(SObject); - if (SCounter != nullptr) - SCDecFcn(SCounter); -} - -uint32_t WINAPI WaitToReadFcn(PSWMRG SObject) -{ - uint32_t EnterCode = SWMRGWaitToRead(SObject, INFINITE); - return EnterCode; -} - -void WINAPI ReadDoneFcn(PSWMRG SObject) -{ - SWMRGDoneReading(SObject); -} - -uint32_t WINAPI SCGetNumberFcn(PSCOUNTER SCounter) -{ - - EnterCriticalSection(&SCounter->CounterCS); - - uint32_t Temp = SCounter->Number; - - LeaveCriticalSection(&SCounter->CounterCS); - return Temp; -} - -uint32_t WINAPI SCIncFcn(PSCOUNTER SCounter) -{ - EnterCriticalSection(&SCounter->CounterCS); - - uint32_t Temp = ++SCounter->Number; - ResetEvent(SCounter->Event); - - LeaveCriticalSection(&SCounter->CounterCS); - return Temp; -} - -uint32_t WINAPI SCDecFcn(PSCOUNTER SCounter) -{ - uint32_t Temp; - EnterCriticalSection(&SCounter->CounterCS); - - if (!(Temp = --SCounter->Number)) { - SetEvent(SCounter->Event); - } - - LeaveCriticalSection(&SCounter->CounterCS); - return Temp; -} +/*
+ * This code implements synchronization objects code between threads. If you want, you can include it to your
+ * code. This file is not dependent on any other external code (functions)
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+ // Initializes a SWMRG structure. This structure must be
+ // initialized before any writer or reader threads attempt
+ // to wait on it.
+ // The structure must be allocated by the application and
+ // the structure's address is passed as the first parameter.
+ // The lpszName parameter is the name of the object. Pass
+ // NULL if you do not want to share the object.
+BOOL WINAPI SWMRGInitialize(PSWMRG pSWMRG, wchar_t *Name);
+
+// Deletes the system resources associated with a SWMRG
+// structure. The structure must be deleted only when
+// no writer or reader threads in the calling process
+// will wait on it.
+void WINAPI SWMRGDelete(PSWMRG pSWMRG);
+
+// A writer thread calls this function to know when
+// it can successfully write to the shared data.
+// returns WAIT_FINISH when we are in write-access or WAIT_FAILED
+// when event about quick finishing is set (or when system returns fail when waiting for synchro object)
+uint32_t WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG, uint32_t dwTimeout);
+
+// A writer thread calls this function to let other threads
+// know that it no longer needs to write to the shared data.
+void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG);
+
+// A reader thread calls this function to know when
+// it can successfully read the shared data.
+// returns WAIT_FINISH when we are in read-access or WAIT_FAILED
+// when event about quick finishing is set (or when system returns fail when waiting for synchro object)
+uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout);
+
+// A reader thread calls this function to let other threads
+// know when it no longer needs to read the shared data.
+void WINAPI SWMRGDoneReading(PSWMRG pSWMRG);
+
+// WaitToReadFcn
+// is used to wait for read access with SWMRG SO, but it also increments counter if successfull
+// returns WAIT_FAILED or WAIT_FINISH
+// when WAIT_FAILED, we should not begin to access datas, we are not in read-access mode
+uint32_t WINAPI WaitToReadFcn(PSWMRG SObject);
+
+// WriteDoneFcn
+// is used to release read access with SWMRG SO, but it also decrements counter if successfull
+void WINAPI ReadDoneFcn(PSWMRG SObject);
+
+// This functions is for export purposes
+// Plugin can call this function to manage SCOUNTER synchronization object
+
+// Gets number value stored in SCOUNTER SO
+// Note you must not read the number from memory directly, because
+// CPU can stop reading thread when it has read HI-Word, then another thread
+// can change the value and then OS starts the previous thread, that reads the
+// LO-uint16_t of uint32_t. And the return value HI+LO-uint16_t is corrupted
+uint32_t WINAPI SCGetNumberFcn(PSCOUNTER SCounter);
+
+// Increments SCOUNTER and unsets event
+// Returns Number after incrementing
+uint32_t WINAPI SCIncFcn(PSCOUNTER SCounter);
+
+// Decrements SCOUNTER and sets event if zero
+// Returns Number after decrementing
+uint32_t WINAPI SCDecFcn(PSCOUNTER SCounter);
+
+struct CExportedFunctions SynchroExportedFcn[] =
+{
+ {YAMN_WAITTOWRITEID, (void *)WaitToWriteFcn},
+ {YAMN_WRITEDONEID, (void *)WriteDoneFcn},
+ {YAMN_WAITTOREADID, (void *)WaitToReadFcn},
+ {YAMN_READDONEID, (void *)ReadDoneFcn},
+ {YAMN_SCGETNUMBERID, (void *)SCGetNumberFcn},
+ {YAMN_SCINCID, (void *)SCIncFcn},
+ {YAMN_SCDECID, (void *)SCDecFcn},
+};
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+void WINAPI SWMRGDelete(PSWMRG pSWMRG)
+{
+ // Destroys any synchronization objects that were
+ // successfully created.
+ if (nullptr != pSWMRG->hEventNoWriter)
+ CloseHandle(pSWMRG->hEventNoWriter);
+ if (nullptr != pSWMRG->hEventNoReaders)
+ CloseHandle(pSWMRG->hEventNoReaders);
+ if (nullptr != pSWMRG->hSemNumReaders)
+ CloseHandle(pSWMRG->hSemNumReaders);
+ if (nullptr != pSWMRG->hFinishEV)
+ CloseHandle(pSWMRG->hFinishEV);
+}
+
+BOOL WINAPI SWMRGInitialize(PSWMRG pSWMRG, wchar_t *Name)
+{
+ pSWMRG->hEventNoWriter = nullptr;
+ pSWMRG->hEventNoReaders = nullptr;
+ pSWMRG->hSemNumReaders = nullptr;
+ pSWMRG->hFinishEV = nullptr;
+
+ // Creates the automatic-reset event that is signalled when
+ // no writer threads are writing.
+ // Initially no reader threads are reading.
+ if (Name != nullptr)
+ Name[0] = (wchar_t)'W';
+ pSWMRG->hEventNoWriter = CreateEvent(nullptr, FALSE, TRUE, Name);
+
+ // Creates the manual-reset event that is signalled when
+ // no reader threads are reading.
+ // Initially no reader threads are reading.
+ if (Name != nullptr)
+ Name[0] = (wchar_t)'R';
+ pSWMRG->hEventNoReaders = CreateEvent(nullptr, TRUE, TRUE, Name);
+
+ // Initializes the variable that indicates the number of
+ // reader threads that are reading.
+ // Initially no reader threads are reading.
+ if (Name != nullptr)
+ Name[0] = (wchar_t)'C';
+ pSWMRG->hSemNumReaders = CreateSemaphore(nullptr, 0, 0x7FFFFFFF, Name);
+
+ if (Name != nullptr)
+ Name[0] = (wchar_t)'F';
+ pSWMRG->hFinishEV = CreateEvent(nullptr, TRUE, FALSE, Name);
+
+ // If a synchronization object could not be created,
+ // destroys any created objects and return failure.
+ if ((nullptr == pSWMRG->hEventNoWriter) || (nullptr == pSWMRG->hEventNoReaders) || (nullptr == pSWMRG->hSemNumReaders) || (nullptr == pSWMRG->hFinishEV)) {
+ SWMRGDelete(pSWMRG);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+uint32_t WINAPI SWMRGWaitToWrite(PSWMRG pSWMRG, uint32_t dwTimeout)
+{
+ uint32_t dw;
+ HANDLE aHandles[2];
+
+ // We can write if the following are true:
+ // 1. No other threads are writing.
+ // 2. No threads are reading.
+ // But first we have to know if SWMRG structure is not about to delete
+ aHandles[0] = pSWMRG->hEventNoWriter;
+ aHandles[1] = pSWMRG->hEventNoReaders;
+ if (WAIT_OBJECT_0 == (dw = WaitForSingleObject(pSWMRG->hFinishEV, 0)))
+ return WAIT_FINISH;
+ if (WAIT_FAILED == dw)
+ return dw;
+ dw = WaitForMultipleObjects(2, aHandles, TRUE, dwTimeout);
+ // if a request to delete became later, we should not catch it. Try once more to ask if account is not about to delete
+ if ((dw != WAIT_FAILED) && (WAIT_OBJECT_0 == (WaitForSingleObject(pSWMRG->hFinishEV, 0)))) {
+ SetEvent(pSWMRG->hEventNoWriter);
+ return WAIT_FINISH;
+ }
+
+ // This thread can write to the shared data.
+ // Automatic event for NoWriter sets hEventNoWriter to nonsignaled after WaitForMultipleObject
+
+ // Because a writer thread is writing, the Event
+ // should not be reset. This stops other
+ // writers and readers.
+ return dw;
+}
+
+void WINAPI SWMRGDoneWriting(PSWMRG pSWMRG)
+// Presumably, a writer thread calling this function has
+// successfully called WaitToWrite. This means that we
+// do not have to wait on any synchronization objects
+// here because the writer already owns the Event.
+{
+ // Allow other writer/reader threads to use
+ // the SWMRG synchronization object.
+ SetEvent(pSWMRG->hEventNoWriter);
+}
+
+uint32_t WINAPI SWMRGWaitToRead(PSWMRG pSWMRG, uint32_t dwTimeout)
+{
+ uint32_t dw;
+ LONG lPreviousCount;
+
+ // We can read if no threads are writing.
+ // And there's not request to delete structure
+ if (WAIT_OBJECT_0 == (dw = WaitForSingleObject(pSWMRG->hFinishEV, 0)))
+ return WAIT_FINISH;
+ if (WAIT_FAILED == dw)
+ return dw;
+ dw = WaitForSingleObject(pSWMRG->hEventNoWriter, dwTimeout);
+ // if a request to delete became later, we should not catch it. Try once more to ask if account is not about to delete
+ if ((dw != WAIT_FAILED) && (WAIT_OBJECT_0 == (WaitForSingleObject(pSWMRG->hFinishEV, 0)))) {
+ SetEvent(pSWMRG->hEventNoWriter);
+ return WAIT_FINISH;
+ }
+
+ if (dw == WAIT_OBJECT_0) {
+ // This thread can read from the shared data.
+ // Increment the number of reader threads.
+ // But there can't be more than one thread incrementing readers,
+ // so this is why we use semaphore.
+ ReleaseSemaphore(pSWMRG->hSemNumReaders, 1, &lPreviousCount);
+ if (lPreviousCount == 0)
+ // If this is the first reader thread,
+ // set event to reflect this. Other reader threads can read, no writer thread can write.
+ ResetEvent(pSWMRG->hEventNoReaders);
+
+ // Allow other writer/reader threads to use
+ // the SWMRG synchronization object. hEventNoWrite is still non-signaled
+ // (it looks like writer is processing thread, but it is not true)
+ SetEvent(pSWMRG->hEventNoWriter);
+ }
+
+ return(dw);
+}
+
+void WINAPI SWMRGDoneReading(PSWMRG pSWMRG)
+{
+ HANDLE aHandles[2];
+ LONG lNumReaders;
+
+ // We can stop reading if the events are available,
+ // but when we stop reading we must also decrement the
+ // number of reader threads.
+ aHandles[0] = pSWMRG->hEventNoWriter;
+ aHandles[1] = pSWMRG->hSemNumReaders;
+ WaitForMultipleObjects(2, aHandles, TRUE, INFINITE);
+
+ // Get the remaining number of readers by releasing the
+ // semaphore and then restoring the count by immediately
+ // performing a wait.
+ ReleaseSemaphore(pSWMRG->hSemNumReaders, 1, &lNumReaders);
+ WaitForSingleObject(pSWMRG->hSemNumReaders, INFINITE);
+
+ // If there are no remaining readers,
+ // set the event to relect this.
+ if (lNumReaders == 0)
+ // If there are no reader threads,
+ // set our event to reflect this.
+ SetEvent(pSWMRG->hEventNoReaders);
+
+ // Allow other writer/reader threads to use
+ // the SWMRG synchronization object.
+ // (it looks like writer is processing thread, but it is not true)
+ SetEvent(pSWMRG->hEventNoWriter);
+}
+
+uint32_t WINAPI WaitToWriteFcn(PSWMRG SObject, PSCOUNTER SCounter)
+{
+ uint32_t EnterCode;
+
+ if (WAIT_OBJECT_0 == (EnterCode = SWMRGWaitToWrite(SObject, INFINITE)))
+ if (SCounter != nullptr)
+ SCIncFcn(SCounter);
+
+ return EnterCode;
+}
+
+void WINAPI WriteDoneFcn(PSWMRG SObject, PSCOUNTER SCounter)
+{
+ SWMRGDoneWriting(SObject);
+ if (SCounter != nullptr)
+ SCDecFcn(SCounter);
+}
+
+uint32_t WINAPI WaitToReadFcn(PSWMRG SObject)
+{
+ uint32_t EnterCode = SWMRGWaitToRead(SObject, INFINITE);
+ return EnterCode;
+}
+
+void WINAPI ReadDoneFcn(PSWMRG SObject)
+{
+ SWMRGDoneReading(SObject);
+}
+
+uint32_t WINAPI SCGetNumberFcn(PSCOUNTER SCounter)
+{
+
+ EnterCriticalSection(&SCounter->CounterCS);
+
+ uint32_t Temp = SCounter->Number;
+
+ LeaveCriticalSection(&SCounter->CounterCS);
+ return Temp;
+}
+
+uint32_t WINAPI SCIncFcn(PSCOUNTER SCounter)
+{
+ EnterCriticalSection(&SCounter->CounterCS);
+
+ uint32_t Temp = ++SCounter->Number;
+ ResetEvent(SCounter->Event);
+
+ LeaveCriticalSection(&SCounter->CounterCS);
+ return Temp;
+}
+
+uint32_t WINAPI SCDecFcn(PSCOUNTER SCounter)
+{
+ uint32_t Temp;
+ EnterCriticalSection(&SCounter->CounterCS);
+
+ if (!(Temp = --SCounter->Number)) {
+ SetEvent(SCounter->Event);
+ }
+
+ LeaveCriticalSection(&SCounter->CounterCS);
+ return Temp;
+}
diff --git a/protocols/YAMN/src/yamn.cpp b/protocols/YAMN/src/yamn.cpp index d0d80021f8..2af7efd74f 100644 --- a/protocols/YAMN/src/yamn.cpp +++ b/protocols/YAMN/src/yamn.cpp @@ -1,230 +1,230 @@ -/* - * This code implements miscellaneous usefull functions - * - * (c) majvan 2002-2004 - */ - -#include "stdafx.h" - -//-------------------------------------------------------------------------------------------------- -//-------------------------------------------------------------------------------------------------- - -//Plugin registration CS -//Used if we add (register) plugin to YAMN plugins and when we browse through registered plugins -mir_cs 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); - -// 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, uint32_t); - -// 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 -//uint32_t 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) -{ - int i; - - for (i=0;i<sizeof(ProtoPluginExportedFcn)/sizeof(ProtoPluginExportedFcn[0]);i++) - if (0==mir_strcmp((char *)wParam, ProtoPluginExportedFcn[i].ID)) - return (INT_PTR)ProtoPluginExportedFcn[i].Ptr; - for (i=0;i<sizeof(ProtoPluginExportedSvc)/sizeof(ProtoPluginExportedSvc[0]);i++) - if (0==mir_strcmp((char *)wParam, ProtoPluginExportedSvc[i].ID)) - return (INT_PTR)ProtoPluginExportedSvc[i].Ptr; - for (i=0;i<sizeof(SynchroExportedFcn)/sizeof(SynchroExportedFcn[0]);i++) - if (0==mir_strcmp((char *)wParam, SynchroExportedFcn[i].ID)) - return (INT_PTR)SynchroExportedFcn[i].Ptr; - for (i=0;i<sizeof(AccountExportedFcn)/sizeof(AccountExportedFcn[0]);i++) - if (0==mir_strcmp((char *)wParam, AccountExportedFcn[i].ID)) - return (INT_PTR)AccountExportedFcn[i].Ptr; - for (i=0;i<sizeof(AccountExportedSvc)/sizeof(AccountExportedSvc[0]);i++) - if (0==mir_strcmp((char *)wParam, AccountExportedSvc[i].ID)) - return (INT_PTR)AccountExportedSvc[i].Ptr; - for (i=0;i<sizeof(MailExportedFcn)/sizeof(MailExportedFcn[0]);i++) - if (0==mir_strcmp((char *)wParam, MailExportedFcn[i].ID)) - return (INT_PTR)MailExportedFcn[i].Ptr; - for (i=0;i<sizeof(MailExportedSvc)/sizeof(MailExportedSvc[0]);i++) - if (0==mir_strcmp((char *)wParam, MailExportedSvc[i].ID)) - return (INT_PTR)MailExportedSvc[i].Ptr; - for (i=0;i<sizeof(FilterPluginExportedFcn)/sizeof(FilterPluginExportedFcn[0]);i++) - if (0==mir_strcmp((char *)wParam, FilterPluginExportedFcn[i].ID)) - return (INT_PTR)FilterPluginExportedFcn[i].Ptr; - for (i=0;i<sizeof(FilterPluginExportedSvc)/sizeof(FilterPluginExportedSvc[0]);i++) - if (0==mir_strcmp((char *)wParam, FilterPluginExportedSvc[i].ID)) - return (INT_PTR)FilterPluginExportedSvc[i].Ptr; - return (INT_PTR)NULL; -} - -INT_PTR GetVariablesSvc(WPARAM wParam, LPARAM) -{ - return wParam==YAMN_VARIABLESVERSION ? (INT_PTR)&YAMNVar : (INT_PTR)NULL; -} - -void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD) -{ - CAccount *ActualAccount; - DWORD Status, tid; - - // we use event to signal, that running thread has all needed stack parameters copied - HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (ThreadRunningEV == nullptr) - return; - - // if we want to close miranda, we get event and do not run checking anymore - if (WAIT_OBJECT_0 == WaitForSingleObject(ExitEV, 0)) - return; - - // Get actual status of current user in Miranda - Status = CallService(MS_CLIST_GETSTATUSMODE, 0, 0); - - mir_cslock lck(PluginRegCS); - for (PYAMN_PROTOPLUGINQUEUE ActualPlugin = FirstProtoPlugin; ActualPlugin != nullptr; ActualPlugin = ActualPlugin->Next) { - if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualPlugin->Plugin->AccountBrowserSO, 0)) // we want to access accounts immiadtelly - return; - - for (ActualAccount = ActualPlugin->Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = ActualAccount->Next) { - if (ActualAccount->Plugin == nullptr || ActualAccount->Plugin->Fcn == nullptr) //account not inited - continue; - - if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualAccount->AccountAccessSO, 0)) - continue; - - 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)))) - { - if ((!ActualAccount->Interval && !ActualAccount->TimeLeft) || ActualAccount->Plugin->Fcn->TimeoutFcnPtr == nullptr) - goto ChangeIsCountingStatusLabel; - - if (ActualAccount->TimeLeft) { - ActualAccount->TimeLeft--; - isAccountCounting = TRUE; - } - - 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 *)nullptr, nullptr}; - - ActualAccount->TimeLeft = ActualAccount->Interval; - HANDLE NewThread = CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->TimeoutFcnPtr, &ParamToPlugin, 0, &tid); - if (NewThread == nullptr) { - ReadDoneFcn(ActualAccount->AccountAccessSO); - continue; - } - else { - WaitForSingleObject(ThreadRunningEV, INFINITE); - CloseHandle(NewThread); - } - } - } - -ChangeIsCountingStatusLabel: - if (((ActualAccount->isCounting) != 0) != isAccountCounting) { - ActualAccount->isCounting = isAccountCounting; - uint16_t cStatus = g_plugin.getWord(ActualAccount->hContact, "Status"); - switch (cStatus) { - case ID_STATUS_ONLINE: - case ID_STATUS_OFFLINE: - g_plugin.setWord(ActualAccount->hContact, "Status", isAccountCounting ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE); - default: - break; - } - } - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - SWMRGDoneReading(ActualPlugin->Plugin->AccountBrowserSO); - } - CloseHandle(ThreadRunningEV); -} - -INT_PTR ForceCheckSvc(WPARAM, LPARAM) -{ - CAccount *ActualAccount; - DWORD tid; - - //we use event to signal, that running thread has all needed stack parameters copied - HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr); - if (ThreadRunningEV == nullptr) - 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; - - { - mir_cslock lck(PluginRegCS); - for (PYAMN_PROTOPLUGINQUEUE ActualPlugin = FirstProtoPlugin; ActualPlugin != nullptr; ActualPlugin = ActualPlugin->Next) { - SWMRGWaitToRead(ActualPlugin->Plugin->AccountBrowserSO, INFINITE); - for (ActualAccount = ActualPlugin->Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = ActualAccount->Next) { - if (ActualAccount->Plugin->Fcn == nullptr) //account not inited - continue; - - if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) - continue; - - if ((ActualAccount->Flags & YAMN_ACC_ENA) && (ActualAccount->StatusFlags & YAMN_ACC_FORCE)) { //account cannot be forced to check - if (ActualAccount->Plugin->Fcn->ForceCheckFcnPtr == nullptr) { - ReadDoneFcn(ActualAccount->AccountAccessSO); - continue; - } - struct CheckParam ParamToPlugin = { YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_FORCECHECK, (void *)nullptr, nullptr }; - - if (nullptr == CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->ForceCheckFcnPtr, &ParamToPlugin, 0, &tid)) { - ReadDoneFcn(ActualAccount->AccountAccessSO); - continue; - } - else - WaitForSingleObject(ThreadRunningEV, INFINITE); - } - ReadDoneFcn(ActualAccount->AccountAccessSO); - } - SWMRGDoneReading(ActualPlugin->Plugin->AccountBrowserSO); - } - } - - CloseHandle(ThreadRunningEV); - - if (hTTButton) - CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)hTTButton, 0); - return 1; -} +/*
+ * This code implements miscellaneous usefull functions
+ *
+ * (c) majvan 2002-2004
+ */
+
+#include "stdafx.h"
+
+//--------------------------------------------------------------------------------------------------
+//--------------------------------------------------------------------------------------------------
+
+//Plugin registration CS
+//Used if we add (register) plugin to YAMN plugins and when we browse through registered plugins
+mir_cs 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);
+
+// 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, uint32_t);
+
+// 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
+//uint32_t 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)
+{
+ int i;
+
+ for (i=0;i<sizeof(ProtoPluginExportedFcn)/sizeof(ProtoPluginExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, ProtoPluginExportedFcn[i].ID))
+ return (INT_PTR)ProtoPluginExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(ProtoPluginExportedSvc)/sizeof(ProtoPluginExportedSvc[0]);i++)
+ if (0==mir_strcmp((char *)wParam, ProtoPluginExportedSvc[i].ID))
+ return (INT_PTR)ProtoPluginExportedSvc[i].Ptr;
+ for (i=0;i<sizeof(SynchroExportedFcn)/sizeof(SynchroExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, SynchroExportedFcn[i].ID))
+ return (INT_PTR)SynchroExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(AccountExportedFcn)/sizeof(AccountExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, AccountExportedFcn[i].ID))
+ return (INT_PTR)AccountExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(AccountExportedSvc)/sizeof(AccountExportedSvc[0]);i++)
+ if (0==mir_strcmp((char *)wParam, AccountExportedSvc[i].ID))
+ return (INT_PTR)AccountExportedSvc[i].Ptr;
+ for (i=0;i<sizeof(MailExportedFcn)/sizeof(MailExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, MailExportedFcn[i].ID))
+ return (INT_PTR)MailExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(MailExportedSvc)/sizeof(MailExportedSvc[0]);i++)
+ if (0==mir_strcmp((char *)wParam, MailExportedSvc[i].ID))
+ return (INT_PTR)MailExportedSvc[i].Ptr;
+ for (i=0;i<sizeof(FilterPluginExportedFcn)/sizeof(FilterPluginExportedFcn[0]);i++)
+ if (0==mir_strcmp((char *)wParam, FilterPluginExportedFcn[i].ID))
+ return (INT_PTR)FilterPluginExportedFcn[i].Ptr;
+ for (i=0;i<sizeof(FilterPluginExportedSvc)/sizeof(FilterPluginExportedSvc[0]);i++)
+ if (0==mir_strcmp((char *)wParam, FilterPluginExportedSvc[i].ID))
+ return (INT_PTR)FilterPluginExportedSvc[i].Ptr;
+ return (INT_PTR)NULL;
+}
+
+INT_PTR GetVariablesSvc(WPARAM wParam, LPARAM)
+{
+ return wParam==YAMN_VARIABLESVERSION ? (INT_PTR)&YAMNVar : (INT_PTR)NULL;
+}
+
+void CALLBACK TimerProc(HWND, UINT, UINT_PTR, DWORD)
+{
+ CAccount *ActualAccount;
+ DWORD Status, tid;
+
+ // we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (ThreadRunningEV == nullptr)
+ return;
+
+ // if we want to close miranda, we get event and do not run checking anymore
+ if (WAIT_OBJECT_0 == WaitForSingleObject(ExitEV, 0))
+ return;
+
+ // Get actual status of current user in Miranda
+ Status = CallService(MS_CLIST_GETSTATUSMODE, 0, 0);
+
+ mir_cslock lck(PluginRegCS);
+ for (PYAMN_PROTOPLUGINQUEUE ActualPlugin = FirstProtoPlugin; ActualPlugin != nullptr; ActualPlugin = ActualPlugin->Next) {
+ if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualPlugin->Plugin->AccountBrowserSO, 0)) // we want to access accounts immiadtelly
+ return;
+
+ for (ActualAccount = ActualPlugin->Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = ActualAccount->Next) {
+ if (ActualAccount->Plugin == nullptr || ActualAccount->Plugin->Fcn == nullptr) //account not inited
+ continue;
+
+ if (WAIT_OBJECT_0 != SWMRGWaitToRead(ActualAccount->AccountAccessSO, 0))
+ continue;
+
+ 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))))
+ {
+ if ((!ActualAccount->Interval && !ActualAccount->TimeLeft) || ActualAccount->Plugin->Fcn->TimeoutFcnPtr == nullptr)
+ goto ChangeIsCountingStatusLabel;
+
+ if (ActualAccount->TimeLeft) {
+ ActualAccount->TimeLeft--;
+ isAccountCounting = TRUE;
+ }
+
+ 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 *)nullptr, nullptr};
+
+ ActualAccount->TimeLeft = ActualAccount->Interval;
+ HANDLE NewThread = CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->TimeoutFcnPtr, &ParamToPlugin, 0, &tid);
+ if (NewThread == nullptr) {
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ continue;
+ }
+ else {
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+ CloseHandle(NewThread);
+ }
+ }
+ }
+
+ChangeIsCountingStatusLabel:
+ if (((ActualAccount->isCounting) != 0) != isAccountCounting) {
+ ActualAccount->isCounting = isAccountCounting;
+ uint16_t cStatus = g_plugin.getWord(ActualAccount->hContact, "Status");
+ switch (cStatus) {
+ case ID_STATUS_ONLINE:
+ case ID_STATUS_OFFLINE:
+ g_plugin.setWord(ActualAccount->hContact, "Status", isAccountCounting ? ID_STATUS_ONLINE : ID_STATUS_OFFLINE);
+ default:
+ break;
+ }
+ }
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ SWMRGDoneReading(ActualPlugin->Plugin->AccountBrowserSO);
+ }
+ CloseHandle(ThreadRunningEV);
+}
+
+INT_PTR ForceCheckSvc(WPARAM, LPARAM)
+{
+ CAccount *ActualAccount;
+ DWORD tid;
+
+ //we use event to signal, that running thread has all needed stack parameters copied
+ HANDLE ThreadRunningEV = CreateEvent(nullptr, FALSE, FALSE, nullptr);
+ if (ThreadRunningEV == nullptr)
+ 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;
+
+ {
+ mir_cslock lck(PluginRegCS);
+ for (PYAMN_PROTOPLUGINQUEUE ActualPlugin = FirstProtoPlugin; ActualPlugin != nullptr; ActualPlugin = ActualPlugin->Next) {
+ SWMRGWaitToRead(ActualPlugin->Plugin->AccountBrowserSO, INFINITE);
+ for (ActualAccount = ActualPlugin->Plugin->FirstAccount; ActualAccount != nullptr; ActualAccount = ActualAccount->Next) {
+ if (ActualAccount->Plugin->Fcn == nullptr) //account not inited
+ continue;
+
+ if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO))
+ continue;
+
+ if ((ActualAccount->Flags & YAMN_ACC_ENA) && (ActualAccount->StatusFlags & YAMN_ACC_FORCE)) { //account cannot be forced to check
+ if (ActualAccount->Plugin->Fcn->ForceCheckFcnPtr == nullptr) {
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ continue;
+ }
+ struct CheckParam ParamToPlugin = { YAMN_CHECKVERSION, ThreadRunningEV, ActualAccount, YAMN_FORCECHECK, (void *)nullptr, nullptr };
+
+ if (nullptr == CreateThread(nullptr, 0, (YAMN_STANDARDFCN)ActualAccount->Plugin->Fcn->ForceCheckFcnPtr, &ParamToPlugin, 0, &tid)) {
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ continue;
+ }
+ else
+ WaitForSingleObject(ThreadRunningEV, INFINITE);
+ }
+ ReadDoneFcn(ActualAccount->AccountAccessSO);
+ }
+ SWMRGDoneReading(ActualPlugin->Plugin->AccountBrowserSO);
+ }
+ }
+
+ CloseHandle(ThreadRunningEV);
+
+ if (hTTButton)
+ CallService(MS_TTB_SETBUTTONSTATE, (WPARAM)hTTButton, 0);
+ return 1;
+}
|