/* * 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 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 { HACCOUNT Account; int TrayIconState; BOOL UpdateMailsMessagesAccess; BOOL Seen; BOOL RunFirstTime; }; struct CChangeContent { DWORD nflags; DWORD nnflags; }; struct CUpdateMails { struct CChangeContent *Flags; BOOL Waiting; HANDLE Copied; }; struct CSortList { HWND hDlg; int iSubItem; }; // Retrieves HACCOUNT, whose mails are displayed in ListMails // hLM- handle of dialog window // returns handle of account inline HACCOUNT 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, HACCOUNT ActualAccount, DWORD nflags, DWORD 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, HACCOUNT ActualAccount, struct CMailNumbers *MN, DWORD nflags, DWORD 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, HACCOUNT 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, HACCOUNT ActualAccount, DWORD 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, DWORD iItem) { LVITEM item; item.mask = LVIF_PARAM; item.iItem = iItem; item.iSubItem = 0; SendMessage(hwnd, LVM_GETITEM, 0, (LPARAM)&item); return item.lParam; } inline HACCOUNT 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, HACCOUNT ActualAccount, DWORD nflags, DWORD 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 #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "UpdateMails:ActualAccountSO-read wait\n"); #endif if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "UpdateMails:ActualAccountSO-read wait failed\n"); #endif PostMessage(hDlg, WM_DESTROY, 0, 0); return UPDATE_FAIL; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "UpdateMails:ActualAccountSO-read enter\n"); #endif #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "UpdateMails:ActualAccountMsgsSO-write wait\n"); #endif if (WAIT_OBJECT_0 != WaitToWriteFcn(ActualAccount->MessagesAccessSO)) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "UpdateMails:ActualAccountMsgsSO-write wait failed\n"); DebugLog(SynchroFile, "UpdateMails:ActualAccountSO-read done\n"); #endif ReadDoneFcn(ActualAccount->AccountAccessSO); PostMessage(hDlg, WM_DESTROY, 0, 0); return UPDATE_FAIL; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "UpdateMails:ActualAccountMsgsSO-write enter\n"); #endif 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 *TitleStrW = new WCHAR[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; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "UpdateMails:Do mail actions\n"); #endif DoMailActions(hDlg, ActualAccount, &MN, nflags, nnflags); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "UpdateMails:Do mail actions done\n"); #endif 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; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "UpdateMails:ActualAccountMsgsSO-write done\n"); DebugLog(SynchroFile, "UpdateMails:ActualAccountSO-read done\n"); #endif 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, HACCOUNT 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 *dateout, int lendateout); int AddNewMailsToListView(HWND hListView, HACCOUNT ActualAccount, DWORD nflags) { WCHAR *FromStr; WCHAR SizeStr[20]; WCHAR 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; } POPUPDATAT NewMailPopup = { 0 }; NewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount; NewMailPopup.lchIcon = g_LoadIconEx(2); 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[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*)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.lptzContactName, FromStr, _countof(NewMailPopup.lptzContactName)); mir_wstrncpy(NewMailPopup.lptzText, UnicodeHeader.Subject, _countof(NewMailPopup.lptzText)); PYAMN_MAILSHOWPARAM MailParam = (PYAMN_MAILSHOWPARAM)malloc(sizeof(YAMN_MAILSHOWPARAM)); if (MailParam) { MailParam->account = ActualAccount; MailParam->mail = msgq; MailParam->ThreadRunningEV = nullptr; NewMailPopup.PluginData = MailParam; PUAddPopupT(&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, HACCOUNT ActualAccount, struct CMailNumbers *MN, DWORD nflags, DWORD 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), 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_LoadIconEx(2); evt.hDbEvent = ActualAccount->hContact; evt.lParam = ActualAccount->hContact; evt.pszService = MS_YAMN_CLISTDBLCLICK; evt.szTooltip.w = tszMsg; pcli->pfnAddEvent(&evt); } db_set_ws(ActualAccount->hContact, "CList", "StatusMsg", tszMsg); if (nflags & YAMN_ACC_CONTNICK) db_set_ws(ActualAccount->hContact, YAMN_DBMODULE, "Nick", tszMsg); } if ((nflags & YAMN_ACC_POP) && !(ActualAccount->Flags & YAMN_ACC_POPN) && (MN->Real.PopupRun + MN->Virtual.PopupRun)) { POPUPDATAT NewMailPopup = { 0 }; NewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount; NewMailPopup.lchIcon = g_LoadIconEx(2); 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.lptzContactName, _A2T(ActualAccount->Name), _countof(NewMailPopup.lptzContactName)); mir_snwprintf(NewMailPopup.lptzText, TranslateT("%d new mail message(s), %d total"), MN->Real.PopupNC + MN->Virtual.PopupNC, MN->Real.PopupTC + MN->Virtual.PopupTC); PUAddPopupT(&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)) pcli->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_LoadIconEx(2); 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 *Command; if (ActualAccount->NewMailN.AppParam != nullptr) Command = new WCHAR[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6]; else Command = new WCHAR[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)) { POPUPDATAT NoNewMailPopup; NoNewMailPopup.lchContact = (ActualAccount->hContact != NULL) ? ActualAccount->hContact : (UINT_PTR)ActualAccount; NoNewMailPopup.lchIcon = g_LoadIconEx(1); 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.lptzContactName, _A2T(ActualAccount->Name), _countof(NoNewMailPopup.lptzContactName)); if (MN->Real.PopupSL2NC + MN->Virtual.PopupSL2NC) mir_snwprintf(NoNewMailPopup.lptzText, TranslateT("No new mail message, %d spam(s)"), MN->Real.PopupSL2NC + MN->Virtual.PopupSL2NC); else mir_wstrncpy(NoNewMailPopup.lptzText, TranslateT("No new mail message"), _countof(NoNewMailPopup.lptzText)); PUAddPopupT(&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) db_set_s(ActualAccount->hContact, YAMN_DBMODULE, "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 = CallService(MS_POPUP_GETPLUGINDATA, (WPARAM)hWnd, (LPARAM)&PluginParam)))) { MCONTACT hContact = 0; HACCOUNT 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 (!db_get(hContact, YAMN_DBMODULE, "Id", &dbv)) { Account = (HACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); db_free(&dbv); } else Account = (HACCOUNT)hContact; //???? #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "PopupProc:LEFTCLICK:ActualAccountSO-read wait\n"); #endif if (WAIT_OBJECT_0 == WaitToReadFcn(Account->AccountAccessSO)) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "PopupProc:LEFTCLICK:ActualAccountSO-read enter\n"); #endif 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; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "PopupProc:LEFTCLICK:ActualAccountSO-read done\n"); #endif ReadDoneFcn(Account->AccountAccessSO); } #ifdef DEBUG_SYNCHRO else DebugLog(SynchroFile, "PopupProc:LEFTCLICK:ActualAccountSO-read enter failed\n"); #endif } if ((Account->NewMailN.Flags & YAMN_ACC_CONT) && !(Account->NewMailN.Flags & YAMN_ACC_CONTNOEVENT)) pcli->pfnRemoveEvent(hContact, hContact); } // fall through 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: { HACCOUNT ActualAccount; DBVARIANT dbv; MCONTACT hContact = PUGetContact(hWnd); if (!db_get(hContact, YAMN_DBMODULE, "Id", &dbv)) { ActualAccount = (HACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); db_free(&dbv); } else ActualAccount = (HACCOUNT)hContact; if ((HACCOUNT)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)) { HACCOUNT ActualAccount; DBVARIANT dbv; MCONTACT hContact = PUGetContact(hWnd); if (!db_get(hContact, YAMN_DBMODULE, "Id", &dbv)) { ActualAccount = (HACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); db_free(&dbv); } else ActualAccount = (HACCOUNT)hContact; #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "PopupProc:LEFTCLICK:ActualAccountSO-read wait\n"); #endif if (WAIT_OBJECT_0 == WaitToReadFcn(ActualAccount->AccountAccessSO)) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "PopupProc:LEFTCLICK:ActualAccountSO-read enter\n"); #endif 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; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "PopupProc:LEFTCLICK:ActualAccountSO-read done\n"); #endif ReadDoneFcn(ActualAccount->AccountAccessSO); } #ifdef DEBUG_SYNCHRO else DebugLog(SynchroFile, "PopupProc:LEFTCLICK:ActualAccountSO-read enter failed\n"); #endif 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: { HACCOUNT ActualAccount; DBVARIANT dbv; MCONTACT hContact = PUGetContact(hWnd); if (!db_get(hContact, YAMN_DBMODULE, "Id", &dbv)) { ActualAccount = (HACCOUNT)CallService(MS_YAMN_FINDACCOUNTBYNAME, (WPARAM)POP3Plugin, (LPARAM)dbv.pszVal); db_free(&dbv); } else ActualAccount = (HACCOUNT)hContact; if ((HACCOUNT)wParam != ActualAccount) break; DestroyWindow(hWnd); return 0; } case WM_NOTIFY: /* switch(((LPNMHDR)lParam)->code) { case NM_CLICK: { } } break; */ default: break; } 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((DWORD)wShiftSeconds, 10000000); res -= w100nano; } else { res = 0; } return res; } void FileTimeToLocalizedDateTime(LONGLONG filetime, WCHAR *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; WORD 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 = (DWORD)filetime; ft.dwHighDateTime = (DWORD)(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 *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 **storeto, DWORD cp, int mode); int ConvertStringToUnicode(char *stream, unsigned int cp, WCHAR **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 *iHeaderW = nullptr; WCHAR *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_GetIconHandle(2)); ListView_SetUnicodeFormat(hListView, TRUE); ListView_SetExtendedListViewStyle(hListView, LVS_EX_FULLROWSELECT); StrLen = MultiByteToWideChar(CP_ACP, MB_USEGLYPHCHARS, Translate("Header"), -1, nullptr, 0); iHeaderW = new WCHAR[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[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 *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 *str1 = nullptr; WCHAR *str2 = nullptr; WCHAR 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 *)malloc(sizeof(WCHAR) * (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 *)str_nul; }// the header value may be NULL if (!From) if (!_stricmp(Header->name, "From")) { From = new WCHAR[mir_wstrlen(str2) + 1]; mir_wstrcpy(From, str2); } if (!Subj) if (!_stricmp(Header->name, "Subject")) { Subj = new WCHAR[mir_wstrlen(str2) + 1]; mir_wstrcpy(Subj, str2); } //if (!hasBody) if (!mir_strcmp(Header->name,"Body")) hasBody = true; int count = 0; WCHAR **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*[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 *)(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 *)str_nul) free(str2); } if (body) { WCHAR *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 *title = nullptr; size_t size = (From ? mir_wstrlen(From) : 0) + (Subj ? mir_wstrlen(Subj) : 0) + 4; title = new WCHAR[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 ((HACCOUNT)wParam != MailParam->account) break; #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "ShowMessage:STOPACCOUNT:sending destroy msg\n"); #endif 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; #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "ShowMessage:Incrementing \"using threads\" %x (account %x)\n", MyParam.account->UsingThreads, MyParam.account); #endif 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; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "ShowMessage:Decrementing \"using threads\" %x (account %x)\n", MyParam.account->UsingThreads, MyParam.account); #endif SCDecFcn(MyParam.account->UsingThreads); delete (struct MailShowMsgWinParam*)Param; } INT_PTR CALLBACK DlgProcYAMNMailBrowser(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { HACCOUNT 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) pcli->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; #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "MailBrowser:DESTROY:save window position\n"); #endif if (!YAMNVar.Shutdown && GetWindowRect(hDlg, &coord)) //the YAMNVar.Shutdown testing is because MMessagesAccessSO)) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "MailBrowser:DESTROY:ActualAccountMsgsSO-write wait failed\n"); #endif break; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "MailBrowser:DESTROY:ActualAccountMsgsSO-write enter\n"); #endif //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); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "MailBrowser:DESTROY:ActualAccountMsgsSO-write done\n"); #endif 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 ((HACCOUNT)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; #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "MailBrowser:CHANGECONTENT:posting UPDATEMAILS\n"); #endif if (ThisThreadWindow) { if (!UpdateMails(hDlg, (HACCOUNT)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) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "MailBrowser:CHANGECONTENT:waiting for event\n"); #endif WaitForSingleObject(UpdateParams.Copied, INFINITE); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "MailBrowser:CHANGECONTENT:event signaled\n"); #endif } } CloseHandle(UpdateParams.Copied); } return 1; case WM_YAMN_UPDATEMAILS: { struct CUpdateMails *um = (struct CUpdateMails *)lParam; DWORD nflags, nnflags; #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "MailBrowser:UPDATEMAILS\n"); #endif if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) return 0; if ((HACCOUNT)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 ((HACCOUNT)wParam != ActualAccount) break; PostQuitMessage(0); return 1; case WM_YAMN_NOTIFYICON: if (nullptr == (ActualAccount = GetWindowAccount(hDlg))) break; switch (lParam) { case WM_LBUTTONDBLCLK: #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "MailBrowser:DBLCLICKICON:ActualAccountSO-read wait\n"); #endif if (WAIT_OBJECT_0 != WaitToReadFcn(ActualAccount->AccountAccessSO)) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "MailBrowser:DBLCLICKICON:ActualAccountSO-read wait failed\n"); #endif return 0; } #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "MailBrowser:DBLCLICKICON:ActualAccountSO-read enter\n"); #endif if (ActualAccount->AbilityFlags & YAMN_ACC_BROWSE) { ShowWindow(hDlg, SW_SHOWNORMAL); SetForegroundWindow(hDlg); } else DestroyWindow(hDlg); #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "MailBrowser:DBLCLICKICON:ActualAccountSO-read done\n"); #endif 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 *Command; if (ActualAccount->NewMailN.AppParam != nullptr) Command = new WCHAR[mir_wstrlen(ActualAccount->NewMailN.App) + mir_wstrlen(ActualAccount->NewMailN.AppParam) + 6]; else Command = new WCHAR[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; DWORD 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 (db_get_b(NULL, YAMN_DBMODULE, 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_LoadIconEx(0); else nid.hIcon = g_LoadIconEx(2); 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)) { #ifdef DEBUG_SYNCHRO DebugLog(SynchroFile, "MailBrowser:COLUMNCLICK:ActualAccountSO-read enter\n"); #endif 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; HACCOUNT 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_GetIconHandle(2)); 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 ((DWORD)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; }