You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2988 lines
86 KiB
2988 lines
86 KiB
////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// UTIL.CPP
|
|
//
|
|
// Purpose:
|
|
// misc utility functions
|
|
//
|
|
// Owner:
|
|
// Sung Rhee ([email protected])
|
|
//
|
|
// Copyright (C) Microsoft Corp. 1994, 1995.
|
|
//
|
|
////////////////////////////////////////////////////////////////////////
|
|
#include <pch.hxx>
|
|
#include <shlwapip.h>
|
|
#include "storfldr.h"
|
|
#include "options.h"
|
|
#include <io.h>
|
|
#include "docobj.h"
|
|
#include <string.h>
|
|
#include <mbstring.h>
|
|
#include "spell.h"
|
|
#include "cmdtargt.h"
|
|
#include "mimeolep.h"
|
|
#include "oleutil.h"
|
|
#include "regutil.h"
|
|
#include "secutil.h"
|
|
#include "imagelst.h"
|
|
#include "inetcfg.h"
|
|
#include "url.h"
|
|
#include <mshtmcid.h>
|
|
#include <mshtmhst.h>
|
|
#include "bodyutil.h"
|
|
#include "htmlstr.h"
|
|
#include "sigs.h"
|
|
#include "imsgcont.h"
|
|
#include <dlgs.h>
|
|
#include "msgfldr.h"
|
|
#include "shared.h"
|
|
#include "demand.h"
|
|
#include "note.h"
|
|
#include "ipab.h"
|
|
#include "menures.h"
|
|
#include <iert.h>
|
|
#include <multiusr.h>
|
|
#include "mirror.h"
|
|
ASSERTDATA
|
|
|
|
#define IS_EXTENDED(ch) ((ch > 126 || ch < 32) && ch != '\t' && ch != '\n' && ch != '\r')
|
|
#define IS_BINARY(ch) ((ch < 32) && ch != '\t' && ch != '\n' && ch != '\r')
|
|
#define MAX_SIG_SIZE 4096
|
|
|
|
INT_PTR CALLBACK DontShowAgainDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
|
|
BOOL CALLBACK EnumThreadCB(HWND hwnd, LPARAM lParam);
|
|
|
|
enum
|
|
{
|
|
SAVEAS_RFC822 =1, // KEEP IN ORDER of FILTER IN SAVEAS DIALOG
|
|
SAVEAS_TEXT,
|
|
SAVEAS_UNICODETEXT,
|
|
SAVEAS_HTML,
|
|
SAVEAS_NUMTYPES = SAVEAS_HTML
|
|
};
|
|
|
|
HRESULT HrSaveMsgSourceToFile(LPMIMEMESSAGE pMsg, DWORD dwSaveAs, LPWSTR pwszFile, BOOL fCanBeDirty);
|
|
|
|
#define CBPATHMAX 512
|
|
|
|
VOID DoReadme(HWND hwndOwner)
|
|
{
|
|
TCHAR szbuf[MAX_PATH];
|
|
LPTSTR psz;
|
|
|
|
if((fIsNT5() && g_OSInfo.dwMinorVersion >=1) ||
|
|
((g_OSInfo.dwMajorVersion > 5) && (g_OSInfo.dwPlatformId == VER_PLATFORM_WIN32_NT)))
|
|
{
|
|
AthMessageBox(hwndOwner, MAKEINTRESOURCE(idsAthena), MAKEINTRESOURCE(idsReadme), NULL, MB_OK);
|
|
return;
|
|
}
|
|
if (GetExePath(c_szIexploreExe, szbuf, ARRAYSIZE(szbuf), TRUE))
|
|
{
|
|
// need to delete stup ';' in IE path
|
|
TCHAR *pch = CharPrev(szbuf, szbuf + lstrlen(szbuf));
|
|
*pch = TEXT('\0');
|
|
|
|
PathAddBackslash(szbuf);
|
|
|
|
StrCatBuff(szbuf, c_szReadme, ARRAYSIZE(szbuf));
|
|
|
|
ShellExecute(hwndOwner, "open", (LPCTSTR)szbuf, NULL, NULL, SW_SHOWNORMAL);
|
|
}
|
|
}
|
|
|
|
|
|
void AthErrorMessage(HWND hwnd, LPTSTR pszTitle, LPTSTR pszError, HRESULT hrDetail)
|
|
{
|
|
LPWSTR pwszTitle = NULL,
|
|
pwszError = NULL;
|
|
|
|
// Title can be null. So is PszToUnicode fails, we are ok. Title just becomes "Error"
|
|
pwszTitle = IS_INTRESOURCE(pszTitle) ? (LPWSTR)pszTitle : PszToUnicode(CP_ACP, pszTitle);
|
|
|
|
pwszError = IS_INTRESOURCE(pszError) ? (LPWSTR)pszError : PszToUnicode(CP_ACP, pszError);
|
|
|
|
// pwszError must be valid. If not, don't do the error box.
|
|
if (pwszError)
|
|
AthErrorMessageW(hwnd, pwszTitle, pwszError, hrDetail);
|
|
|
|
if (!IS_INTRESOURCE(pszTitle))
|
|
MemFree(pwszTitle);
|
|
|
|
if (!IS_INTRESOURCE(pszError))
|
|
MemFree(pwszError);
|
|
}
|
|
|
|
void AthErrorMessageW(HWND hwnd, LPWSTR pwszTitle, LPWSTR pwszError, HRESULT hrDetail)
|
|
{
|
|
register WORD ids;
|
|
|
|
Assert(FAILED(hrDetail));
|
|
|
|
switch (hrDetail)
|
|
{
|
|
case E_OUTOFMEMORY:
|
|
ids = idsMemory;
|
|
break;
|
|
|
|
case DB_E_CREATEFILEMAPPING:
|
|
case STG_E_MEDIUMFULL:
|
|
case DB_E_DISKFULL:
|
|
case hrDiskFull:
|
|
ids = idsDiskFull;
|
|
break;
|
|
|
|
case DB_E_ACCESSDENIED:
|
|
ids = idsDBAccessDenied;
|
|
break;
|
|
|
|
case hrFolderIsLocked:
|
|
ids = idsFolderLocked;
|
|
break;
|
|
|
|
case hrEmptyDistList:
|
|
ids = idsErrOneOrMoreEmptyDistLists;
|
|
break;
|
|
|
|
case hrNoSubject:
|
|
ids = idsErrNoSubject;
|
|
break;
|
|
|
|
case hrNoSender:
|
|
ids = idsErrNoPoster;
|
|
break;
|
|
|
|
case HR_E_POST_WITHOUT_NEWS:
|
|
ids = idsErrPostWithoutNewsgroup;
|
|
break;
|
|
|
|
case HR_E_CONFIGURE_SERVER:
|
|
ids = idsErrConfigureServer;
|
|
break;
|
|
|
|
case hrEmptyRecipientAddress:
|
|
ids = idsErrEmptyRecipientAddress;
|
|
break;
|
|
|
|
case MIME_E_URL_NOTFOUND:
|
|
ids = idsErrSendDownloadFail;
|
|
break;
|
|
|
|
case hrUnableToLoadMapi32Dll:
|
|
ids = idsCantLoadMapi32Dll;
|
|
break;
|
|
|
|
case hrImportLoad:
|
|
ids = idsErrImportLoad;
|
|
break;
|
|
|
|
case hrFolderNameConflict:
|
|
ids = idsErrFolderNameConflict;
|
|
break;
|
|
|
|
case STORE_E_CANTRENAMESPECIAL:
|
|
ids = idsErrRenameSpecialFld;
|
|
break;
|
|
|
|
case STORE_E_BADFOLDERNAME:
|
|
ids = idsErrBadFolderName;
|
|
break;
|
|
|
|
case MAPI_E_INVALID_ENTRYID:
|
|
ids = idsErrBadRecips;
|
|
break;
|
|
|
|
case MIME_E_SECURITY_CERTERROR:
|
|
ids = idsSecCerificateErr;
|
|
break;
|
|
|
|
case MIME_E_SECURITY_NOCERT:
|
|
ids = idsNoCerificateErr;
|
|
break;
|
|
|
|
case HR_E_COULDNOTFINDACCOUNT:
|
|
ids = idsErrNoSendAccounts; //:idsErrConfigureServer;
|
|
break;
|
|
|
|
case hrDroppedConn:
|
|
ids = idsErrPeerClosed;
|
|
break;
|
|
|
|
case hrInvalidPassword:
|
|
ids = idsErrAuthenticate;
|
|
break;
|
|
|
|
case hrCantMoveIntoSubfolder:
|
|
ids = idsErrCantMoveIntoSubfolder;
|
|
break;
|
|
|
|
case STORE_E_CANTDELETESPECIAL:
|
|
case hrCantDeleteSpecialFolder:
|
|
ids = idsErrDeleteSpecialFolder;
|
|
break;
|
|
|
|
case hrNoRecipients:
|
|
ids = idsErrNoRecipients;
|
|
break;
|
|
|
|
case hrBadRecipients:
|
|
ids = idsErrBadRecipients;
|
|
break;
|
|
|
|
case HR_E_ATHSEC_NOCERTTOSIGN:
|
|
{
|
|
ids = idsErrSecurityNoSigningCert;
|
|
if(DialogBoxParam(g_hLocRes,
|
|
MAKEINTRESOURCE(iddErrSecurityNoSigningCert), hwnd,
|
|
ErrSecurityNoSigningCertDlgProc, NULL) == idGetDigitalIDs)
|
|
GetDigitalIDs(NULL);
|
|
return;
|
|
}
|
|
break;
|
|
|
|
case HR_E_ATHSEC_CERTBEGONE:
|
|
ids = idsErrSecurityCertDisappeared;
|
|
break;
|
|
|
|
case MIME_E_SECURITY_NOSIGNINGCERT:
|
|
//N for the MIME error, may need to do better
|
|
// ? delete the reg key if invalid? sure, they
|
|
// can always go to the combo box again. Maybe
|
|
// prompt them toward this
|
|
ids = idsErrSecurityNoSigningCert;
|
|
break;
|
|
|
|
case hrCantMoveSpecialFolder:
|
|
ids = idsErrCannotMoveSpecial;
|
|
break;
|
|
|
|
case MIME_E_SECURITY_LABELACCESSDENIED:
|
|
case MIME_E_SECURITY_LABELACCESSCANCELLED:
|
|
case MIME_E_SECURITY_LABELCORRUPT:
|
|
ids = idsErrAccessDenied;
|
|
break;
|
|
|
|
default:
|
|
ids = idsGenericError;
|
|
break;
|
|
}
|
|
|
|
AthMessageBoxW(hwnd, pwszTitle, pwszError, MAKEINTRESOURCEW(ids), MB_OK | MB_ICONEXCLAMATION);
|
|
}
|
|
|
|
INT_PTR CALLBACK ErrSecurityNoSigningCertDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
INT id;
|
|
switch(msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
CenterDialog(hwnd);
|
|
return TRUE;
|
|
|
|
case WM_COMMAND:
|
|
switch(id=GET_WM_COMMAND_ID(wParam, lParam))
|
|
{
|
|
case idGetDigitalIDs:
|
|
/* GetDigitalIDs(NULL);
|
|
break; */
|
|
|
|
case IDCANCEL:
|
|
EndDialog(hwnd, id);
|
|
break;
|
|
}
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
|
|
BOOL FNewMessage(HWND hwnd, BOOL fModal, BOOL fNoStationery, BOOL fNews, FOLDERID folderID, IUnknown *pUnkPump)
|
|
{
|
|
INIT_MSGSITE_STRUCT initStruct;
|
|
DWORD dwCreateFlags = 0;
|
|
HRESULT hr;
|
|
FOLDERTYPE ftype;
|
|
|
|
ftype = fNews ? FOLDER_NEWS : FOLDER_LOCAL;
|
|
|
|
ProcessICW(hwnd, ftype);
|
|
|
|
// Create new mail message
|
|
initStruct.dwInitType = OEMSIT_VIRGIN;
|
|
initStruct.folderID = folderID;
|
|
if(fNoStationery)
|
|
dwCreateFlags = OENCF_NOSTATIONERY;
|
|
if (fModal)
|
|
dwCreateFlags |= OENCF_MODAL;
|
|
if (fNews)
|
|
dwCreateFlags |= OENCF_NEWSFIRST;
|
|
|
|
hr = CreateAndShowNote(OENA_COMPOSE, dwCreateFlags, &initStruct, hwnd, pUnkPump);
|
|
|
|
return (SUCCEEDED(hr) || (MAPI_E_USER_CANCEL == hr));
|
|
}
|
|
|
|
|
|
|
|
// ********* WARNING THESE ARE NOT READY FOR PRIME TIME USE *********//
|
|
// I put them here so that they are in the right place. brent,03/24
|
|
// I will clean them up when I return from Florida.
|
|
|
|
HRESULT CreateNewShortCut(LPWSTR pwszPathName, LPWSTR pwszLinkPath, DWORD cchLink)
|
|
{
|
|
WCHAR wszDisplayName[MAX_PATH];
|
|
|
|
Assert(pwszPathName);
|
|
Assert(pwszLinkPath);
|
|
Assert(0 < cchLink);
|
|
|
|
if (!FBuildTempPathW(pwszPathName, pwszLinkPath, cchLink, TRUE))
|
|
return(E_FAIL);
|
|
|
|
GetDisplayNameForFile(pwszPathName, wszDisplayName, ARRAYSIZE(wszDisplayName));
|
|
return CreateLink(pwszPathName, pwszLinkPath, wszDisplayName);
|
|
}
|
|
|
|
//===================================================
|
|
//
|
|
// HRESULT GetDisplayNameForFile
|
|
//
|
|
//===================================================
|
|
|
|
void GetDisplayNameForFile(LPWSTR pwszPathName, LPWSTR pwszDisplayName, ULONG cchDisplayName)
|
|
{
|
|
SHFILEINFOW sfi={0};
|
|
|
|
SHGetFileInfoWrapW(pwszPathName, NULL, &sfi, sizeof(sfi), SHGFI_DISPLAYNAME);
|
|
StrCpyNW(pwszDisplayName, sfi.szDisplayName, cchDisplayName);
|
|
}
|
|
|
|
//===================================================
|
|
//
|
|
// HRESULT CreateLink()
|
|
//
|
|
/*
|
|
* CreateLink
|
|
*
|
|
* uses the shell's IShellLink and IPersistFile interfaces
|
|
* to create and store a shortcut to the specified object.
|
|
* Returns the result of calling the member functions of the interfaces.
|
|
* lpszPathObj - address of a buffer containing the path of the object
|
|
* lpszPathLink - address of a buffer containing the path where the
|
|
* shell link is to be stored
|
|
* lpszDesc - address of a buffer containing the description of the
|
|
* shell link
|
|
*/
|
|
|
|
HRESULT CreateLink(LPWSTR pwszPathObj, LPWSTR pwszPathLink, LPWSTR pwszDesc)
|
|
{
|
|
HRESULT hr;
|
|
IShellLink *psl = NULL;
|
|
IShellLinkW *pslW = NULL;
|
|
LPSTR pszPathObj = NULL,
|
|
pszDesc = NULL;
|
|
|
|
// Get a pointer to the IShellLink interface.
|
|
hr = CoCreateInstance( CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IShellLinkW, (LPVOID *)&pslW);
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
// Set the path to the shortcut target, and add the description.
|
|
pslW->SetPath(pwszPathObj);
|
|
pslW->SetDescription(pwszDesc);
|
|
hr = HrIPersistFileSaveW((LPUNKNOWN)pslW, pwszPathLink);
|
|
}
|
|
else
|
|
{
|
|
hr = CoCreateInstance( CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
|
|
IID_IShellLink, (LPVOID *)&psl);
|
|
|
|
if(SUCCEEDED(hr))
|
|
{
|
|
IF_NULLEXIT(pszPathObj = PszToANSI(CP_ACP, pwszPathObj));
|
|
IF_NULLEXIT(pszDesc = PszToANSI(CP_ACP, pwszDesc));
|
|
|
|
// Set the path to the shortcut target, and add the description.
|
|
psl->SetPath(pszPathObj);
|
|
psl->SetDescription(pszDesc);
|
|
hr = HrIPersistFileSaveW((LPUNKNOWN)psl, pwszPathLink);
|
|
}
|
|
}
|
|
|
|
exit:
|
|
ReleaseObj(psl);
|
|
ReleaseObj(pslW);
|
|
|
|
MemFree(pszPathObj);
|
|
MemFree(pszDesc);
|
|
|
|
return hr;
|
|
}
|
|
|
|
DWORD DwGetDontShowAgain (LPCSTR pszRegString)
|
|
{
|
|
DWORD dwDontShow, dwType;
|
|
ULONG cb;
|
|
|
|
cb = sizeof(DWORD);
|
|
if (AthUserGetValue(c_szRegPathDontShowDlgs, pszRegString, &dwType, (LPBYTE)&dwDontShow, &cb) != ERROR_SUCCESS ||
|
|
dwType != REG_DWORD ||
|
|
cb != sizeof(DWORD))
|
|
{
|
|
dwDontShow = 0; // default to show if something fails!
|
|
}
|
|
|
|
return dwDontShow;
|
|
}
|
|
|
|
VOID SetDontShowAgain (DWORD dwDontShow, LPCSTR pszRegString)
|
|
{
|
|
AthUserSetValue(c_szRegPathDontShowDlgs, pszRegString, REG_DWORD, (LPBYTE)&dwDontShow, sizeof(DWORD));
|
|
}
|
|
|
|
typedef struct _tagDONTSHOWPARAMS
|
|
{
|
|
LPTSTR pszMessage;
|
|
LPTSTR pszTitle;
|
|
UINT uType;
|
|
} DONTSHOWPARAMS, *LPDONTSHOWPARAMS;
|
|
|
|
void SetDlgButtonText(HWND hBtn, int ids)
|
|
{
|
|
TCHAR szBuf[CCHMAX_STRINGRES];
|
|
int id;
|
|
|
|
AthLoadString(ids, szBuf, sizeof(szBuf));
|
|
SetWindowText(hBtn, szBuf);
|
|
|
|
switch (ids)
|
|
{
|
|
case idsYES: id = IDYES; break;
|
|
case idsNO: id = IDNO; break;
|
|
case idsCANCEL: id = IDCANCEL; break;
|
|
case idsOK: id = IDOK; break;
|
|
default: AssertSz(FALSE, "Bad button type."); return;
|
|
}
|
|
|
|
SetWindowLong(hBtn, GWL_ID, id);
|
|
}
|
|
|
|
void DoDontShowInitDialog(HWND hwnd, LPDONTSHOWPARAMS pParams)
|
|
{
|
|
int btnTop,
|
|
heightDelta = 0,
|
|
btnLeftDelta = 0,
|
|
nShowStyle1 = SWP_SHOWWINDOW,
|
|
nShowStyle2 = SWP_SHOWWINDOW,
|
|
nShowStyle3 = SWP_SHOWWINDOW;
|
|
TCHAR rgchTitle[CCHMAX_STRINGRES], rgchMsg[CCHMAX_STRINGRES], rgchCheck[CCHMAX_STRINGRES];
|
|
HWND hText, hBtn1, hBtn2, hBtn3, hCheck, hIconStat;
|
|
HICON hIcon;
|
|
LONG uBtnStyle;
|
|
UINT idsCheckBoxString = 0;
|
|
UINT uShowBtns = (MB_OK|MB_OKCANCEL|MB_YESNO|MB_YESNOCANCEL) & pParams->uType;
|
|
UINT uDefBtn = (MB_DEFBUTTON1|MB_DEFBUTTON2|MB_DEFBUTTON3) & pParams->uType;
|
|
UINT uIconStyle = (MB_ICONASTERISK|MB_ICONEXCLAMATION|MB_ICONHAND|MB_ICONEXCLAMATION ) & pParams->uType;
|
|
RECT rc;
|
|
LPTSTR szTitle = pParams->pszTitle,
|
|
szMessage = pParams->pszMessage;
|
|
|
|
if (0 == uShowBtns)
|
|
uShowBtns= MB_OK;
|
|
|
|
if (0 == uDefBtn)
|
|
uDefBtn = MB_DEFBUTTON1;
|
|
|
|
if (!uIconStyle)
|
|
{
|
|
switch(uShowBtns)
|
|
{
|
|
case MB_OK:
|
|
uIconStyle = MB_ICONINFORMATION;
|
|
idsCheckBoxString = idsDontShowMeAgain;
|
|
break;
|
|
case MB_OKCANCEL:
|
|
uIconStyle = MB_ICONEXCLAMATION;
|
|
idsCheckBoxString = idsDontShowMeAgain;
|
|
break;
|
|
case MB_YESNO:
|
|
case MB_YESNOCANCEL:
|
|
uIconStyle = MB_ICONEXCLAMATION ;
|
|
idsCheckBoxString = idsDontAskMeAgain;
|
|
break;
|
|
default:
|
|
AssertSz(FALSE, "Didn't get a valid box type");
|
|
uIconStyle = MB_ICONWARNING;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (IS_INTRESOURCE(szTitle))
|
|
{
|
|
// its a string resource id
|
|
if (0 == AthLoadString(PtrToUlong(szTitle), rgchTitle, sizeof(rgchTitle)))
|
|
return;
|
|
|
|
szTitle = rgchTitle;
|
|
}
|
|
|
|
if (IS_INTRESOURCE(szMessage))
|
|
{
|
|
// its a string resource id
|
|
if (0 == AthLoadString(PtrToUlong(szMessage), rgchMsg, sizeof(rgchMsg)))
|
|
return;
|
|
|
|
szMessage = rgchMsg;
|
|
}
|
|
|
|
switch(uIconStyle)
|
|
{
|
|
case MB_ICONASTERISK: hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_ASTERISK)); break;
|
|
case MB_ICONEXCLAMATION: hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_EXCLAMATION)); break;
|
|
case MB_ICONHAND: hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_HAND)); break;
|
|
case MB_ICONQUESTION : hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_EXCLAMATION)); break; // fixes BUG 18105
|
|
default: hIcon = LoadIcon(NULL, MAKEINTRESOURCE(IDI_APPLICATION)); break;
|
|
}
|
|
AssertSz(hIcon, "Didn't get the appropriate system icon.");
|
|
|
|
hIconStat = GetDlgItem(hwnd, ico1);
|
|
AssertSz(hIconStat, "Didn't get the handle to the static icon dgl item.");
|
|
SendMessage(hIconStat, STM_SETICON, (WPARAM)hIcon, 0);
|
|
|
|
CenterDialog(hwnd);
|
|
|
|
hText = GetDlgItem(hwnd, stc1);
|
|
AssertSz(hText, "Didn't get a static text handle.");
|
|
|
|
GetChildRect(hwnd, hText, &rc);
|
|
HDC dc = GetDC(hwnd);
|
|
if (dc)
|
|
{
|
|
switch (uShowBtns)
|
|
{
|
|
case MB_OK:
|
|
{
|
|
nShowStyle1 = SWP_HIDEWINDOW;
|
|
nShowStyle3 = SWP_HIDEWINDOW;
|
|
break;
|
|
}
|
|
|
|
case MB_OKCANCEL:
|
|
case MB_YESNO:
|
|
{
|
|
nShowStyle3 = SWP_HIDEWINDOW;
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Size the static text
|
|
heightDelta = DrawText(dc, szMessage, -1, &rc, DT_CALCRECT|DT_WORDBREAK|DT_CENTER);
|
|
ReleaseDC(hwnd, dc);
|
|
SetWindowPos(hText, 0, 0, 0, rc.right-rc.left, heightDelta, SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOZORDER);
|
|
}
|
|
|
|
// Move buttons
|
|
hBtn1 = GetDlgItem(hwnd, psh1);
|
|
hBtn2 = GetDlgItem(hwnd, psh2);
|
|
hBtn3 = GetDlgItem(hwnd, psh3);
|
|
AssertSz(hBtn1 && hBtn2 && hBtn3, "Didn't get one of button handles.");
|
|
|
|
GetChildRect(hwnd, hBtn1, &rc);
|
|
btnTop = rc.top+heightDelta;
|
|
|
|
// With these two cases, buttons must be shifted a bit to the right
|
|
if ((MB_OKCANCEL == uShowBtns) || (MB_YESNO == uShowBtns))
|
|
{
|
|
RECT tempRC;
|
|
GetChildRect(hwnd, hBtn2, &tempRC);
|
|
btnLeftDelta = (tempRC.left - rc.left) / 2;
|
|
}
|
|
|
|
SetWindowPos(hBtn1, 0, rc.left+btnLeftDelta, btnTop, 0, 0, nShowStyle1|SWP_NOSIZE|SWP_NOZORDER);
|
|
GetChildRect(hwnd, hBtn2, &rc);
|
|
SetWindowPos(hBtn2, 0, rc.left+btnLeftDelta, btnTop, 0, 0, nShowStyle2|SWP_NOSIZE|SWP_NOZORDER);
|
|
GetChildRect(hwnd, hBtn3, &rc);
|
|
SetWindowPos(hBtn3, 0, rc.left+btnLeftDelta, btnTop, 0, 0, nShowStyle3|SWP_NOSIZE|SWP_NOZORDER);
|
|
|
|
// Move check box
|
|
hCheck = GetDlgItem(hwnd, idchkDontShowMeAgain);
|
|
AssertSz(hCheck, "Didn't get a handle to the check box.");
|
|
GetChildRect(hwnd, hCheck, &rc);
|
|
SetWindowPos(hCheck, 0, rc.left, rc.top+heightDelta, 0, 0, SWP_SHOWWINDOW|SWP_NOSIZE|SWP_NOZORDER);
|
|
AthLoadString(idsCheckBoxString, rgchCheck, sizeof(rgchCheck));
|
|
SetWindowText(hCheck, rgchCheck);
|
|
|
|
// Size dialog
|
|
GetWindowRect(hwnd, &rc);
|
|
heightDelta += rc.bottom - rc.top;
|
|
SetWindowPos(hwnd, 0, 0, 0, rc.right-rc.left, heightDelta, SWP_SHOWWINDOW|SWP_NOMOVE|SWP_NOOWNERZORDER);
|
|
|
|
SetWindowText(hText, szMessage);
|
|
|
|
SetWindowText(hwnd, szTitle);
|
|
|
|
switch(uShowBtns)
|
|
{
|
|
case MB_OK:
|
|
{
|
|
SetFocus(hBtn2);
|
|
SetDlgButtonText(hBtn2, idsOK);
|
|
break;
|
|
}
|
|
|
|
case MB_OKCANCEL:
|
|
case MB_YESNO:
|
|
{
|
|
SetFocus((MB_DEFBUTTON1 == uDefBtn) ? hBtn1 : hBtn2);
|
|
|
|
if (MB_OKCANCEL == uShowBtns)
|
|
{
|
|
SetDlgButtonText(hBtn1, idsOK);
|
|
SetDlgButtonText(hBtn2, idsCANCEL);
|
|
}
|
|
else
|
|
{
|
|
SetDlgButtonText(hBtn1, idsYES);
|
|
SetDlgButtonText(hBtn2, idsNO);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case MB_YESNOCANCEL:
|
|
{
|
|
switch (uDefBtn)
|
|
{
|
|
case MB_DEFBUTTON1: SetFocus(hBtn1); break;
|
|
case MB_DEFBUTTON2: SetFocus(hBtn2); break;
|
|
case MB_DEFBUTTON3: SetFocus(hBtn3); break;
|
|
default: SetFocus(hBtn1); break;
|
|
}
|
|
|
|
SetDlgButtonText(hBtn1, idsYES);
|
|
SetDlgButtonText(hBtn2, idsNO);
|
|
SetDlgButtonText(hBtn3, idsCANCEL);
|
|
break;
|
|
}
|
|
|
|
default:
|
|
AssertSz(FALSE, "Not a valid box type.");
|
|
}
|
|
}
|
|
|
|
INT_PTR CALLBACK DontShowAgainDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
switch(msg)
|
|
{
|
|
case WM_INITDIALOG:
|
|
DoDontShowInitDialog(hwnd, (LPDONTSHOWPARAMS)lParam);
|
|
return FALSE;
|
|
|
|
case WM_COMMAND:
|
|
if(GET_WM_COMMAND_ID(wParam, lParam) == IDOK ||
|
|
GET_WM_COMMAND_ID(wParam, lParam) == IDYES ||
|
|
GET_WM_COMMAND_ID(wParam, lParam) == IDNO ||
|
|
GET_WM_COMMAND_ID(wParam, lParam) == IDCANCEL)
|
|
// We'll put the yes, no, cancel return value in the HIWORD of
|
|
// the return, and the don't show again status in the LOWORD.
|
|
EndDialog(hwnd, (int) MAKELPARAM(IsDlgButtonChecked(hwnd, idchkDontShowMeAgain),
|
|
GET_WM_COMMAND_ID(wParam, lParam)));
|
|
}
|
|
return FALSE;
|
|
}
|
|
|
|
LRESULT DoDontShowMeAgainDlg(HWND hwndOwner, LPCSTR pszRegString, LPTSTR pszTitle, LPTSTR pszMessage, UINT uType)
|
|
{
|
|
DWORD dwDontShow=0;
|
|
LRESULT lResult;
|
|
DONTSHOWPARAMS dlgParams;
|
|
|
|
AssertSz(pszRegString, "Pass me a reg key string!");
|
|
AssertSz(pszRegString, "Pass me a message to display!");
|
|
AssertSz(pszRegString, "Pass me a title to display!");
|
|
|
|
// read the folder view from the registry...
|
|
dwDontShow = DwGetDontShowAgain (pszRegString);
|
|
|
|
if (dwDontShow) // return what was stored as if the user clicked on the button stored
|
|
return (LRESULT) dwDontShow;
|
|
|
|
dlgParams.pszMessage = pszMessage;
|
|
dlgParams.pszTitle = pszTitle;
|
|
dlgParams.uType = uType;
|
|
|
|
lResult = (LRESULT) DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddDontShow), hwndOwner,
|
|
DontShowAgainDlgProc, (LPARAM)&dlgParams);
|
|
if((IDCANCEL != HIWORD(lResult)) && LOWORD(lResult))
|
|
{
|
|
// save the dontshow flag
|
|
SetDontShowAgain (HIWORD(lResult), pszRegString);
|
|
}
|
|
|
|
return (HIWORD(lResult));
|
|
}
|
|
|
|
HRESULT SubstituteWelcomeURLs(LPSTREAM pstmIn, LPSTREAM *ppstmOut)
|
|
{
|
|
HRESULT hr;
|
|
IHTMLDocument2 *pDoc;
|
|
LPSTREAM pstm=0;
|
|
|
|
// BUGBUG: this cocreate should also go thro' the same code path as the DocHost one
|
|
// so that if this is the first trident in the process, we keep it's CF around
|
|
|
|
hr = MimeEditDocumentFromStream(pstmIn, IID_IHTMLDocument2, (LPVOID *)&pDoc);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
URLSUB rgUrlSub[] = {
|
|
{ "mslink", idsHelpMSWebHome },
|
|
{ "certlink", idsHelpMSWebCert },
|
|
};
|
|
|
|
if (SUCCEEDED(hr = SubstituteURLs(pDoc, rgUrlSub, ARRAYSIZE(rgUrlSub))))
|
|
{
|
|
hr = MimeOleCreateVirtualStream(&pstm);
|
|
if (!FAILED(hr))
|
|
{
|
|
IPersistStreamInit *pPSI;
|
|
|
|
HrSetDirtyFlagImpl(pDoc, TRUE);
|
|
|
|
hr = pDoc->QueryInterface(IID_IPersistStreamInit, (LPVOID*)&pPSI);
|
|
if (!FAILED(hr))
|
|
{
|
|
hr = pPSI->Save(pstm, TRUE);
|
|
pPSI->Release();
|
|
}
|
|
}
|
|
}
|
|
pDoc->Release();
|
|
}
|
|
|
|
if (!FAILED(hr))
|
|
{
|
|
Assert(pstm);
|
|
*ppstmOut=pstm;
|
|
pstm->AddRef();
|
|
}
|
|
|
|
ReleaseObj(pstm);
|
|
return hr;
|
|
|
|
}
|
|
|
|
HRESULT IAddWelcomeMessage(IMessageFolder *pfolder, LPWABAL pWabal, LPCTSTR szFile, LPCTSTR szRes)
|
|
{
|
|
PROPVARIANT pv;
|
|
SYSTEMTIME st;
|
|
HRESULT hr;
|
|
LPMIMEMESSAGE pMsg;
|
|
LPSTREAM pstmBody,
|
|
pstmSub,
|
|
pstmStore;
|
|
TCHAR sz[CCHMAX_STRINGRES];
|
|
|
|
// Create the mail msg
|
|
if (FAILED(hr = HrCreateMessage(&pMsg)))
|
|
return(hr);
|
|
|
|
HrSetWabalOnMsg(pMsg, pWabal);
|
|
|
|
// Subject
|
|
SideAssert(LoadString(g_hLocRes, idsWelcomeMessageSubj, sz, ARRAYSIZE(sz)));
|
|
MimeOleSetBodyPropA(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, sz);
|
|
|
|
// Set Date
|
|
pv.vt = VT_FILETIME;
|
|
GetSystemTime(&st);
|
|
SystemTimeToFileTime(&st, &pv.filetime);
|
|
pMsg->SetProp(PIDTOSTR(PID_ATT_SENTTIME), 0, &pv);
|
|
|
|
pstmBody = NULL;
|
|
pstmSub = NULL;
|
|
|
|
if (szFile == NULL || *szFile == 0)
|
|
{
|
|
if (SUCCEEDED(hr = HrLoadStreamFileFromResource(szRes, &pstmBody)))
|
|
{
|
|
if (SUCCEEDED(SubstituteWelcomeURLs(pstmBody, &pstmSub)))
|
|
{
|
|
pMsg->SetTextBody(TXT_HTML, IET_DECODED, NULL, pstmSub, NULL);
|
|
pstmSub->Release();
|
|
}
|
|
else
|
|
{
|
|
pMsg->SetTextBody(TXT_HTML, IET_DECODED, NULL, pstmBody, NULL);
|
|
}
|
|
|
|
pstmBody->Release();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (SUCCEEDED(hr = OpenFileStream((TCHAR *)szFile, OPEN_EXISTING, GENERIC_READ, &pstmBody)))
|
|
{
|
|
pMsg->SetTextBody(TXT_HTML, IET_DECODED, NULL, pstmBody, NULL);
|
|
pstmBody->Release();
|
|
}
|
|
}
|
|
|
|
// Get a stream from the store
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
// set encoding options
|
|
pv.vt = VT_UI4;
|
|
pv.ulVal = SAVE_RFC1521;
|
|
pMsg->SetOption(OID_SAVE_FORMAT, &pv);
|
|
|
|
pv.ulVal = (ULONG)IET_QP;
|
|
pMsg->SetOption(OID_TRANSMIT_TEXT_ENCODING, &pv);
|
|
|
|
pv.boolVal = FALSE;
|
|
pMsg->SetOption(OID_WRAP_BODY_TEXT, &pv);
|
|
|
|
hr = pMsg->Commit(0);
|
|
if (!FAILED(hr))
|
|
{
|
|
hr = pfolder->SaveMessage(NULL, SAVE_MESSAGE_GENID, NOFLAGS, 0, pMsg, NOSTORECALLBACK);
|
|
}
|
|
}
|
|
|
|
pMsg->Release();
|
|
|
|
return(hr);
|
|
}
|
|
|
|
static const TCHAR c_szWelcomeMsgHotmailHtm[] = TEXT("welcome.htm");
|
|
static const TCHAR c_szWelcomeMsgHtm[] = TEXT("welcome2.htm");
|
|
|
|
void AddWelcomeMessage(IMessageFolder *pfolder)
|
|
{
|
|
HRESULT hr;
|
|
LPWABAL pWabal;
|
|
TCHAR szName[CCHMAX_DISPLAY_NAME + 1],
|
|
szEmail[CCHMAX_EMAIL_ADDRESS + 1],
|
|
szFromName[CCHMAX_STRINGRES],
|
|
szFromEmail[CCHMAX_STRINGRES],
|
|
szHtm[MAX_PATH],
|
|
szExpanded[MAX_PATH];
|
|
LPTSTR psz = szHtm;
|
|
DWORD type, cb;
|
|
HKEY hkey;
|
|
BOOL fName, fEmail, fFromName, fFromEmail;
|
|
IImnEnumAccounts *pEnum;
|
|
IImnAccount *pAccount;
|
|
|
|
if (FAILED(HrCreateWabalObject(&pWabal)))
|
|
return;
|
|
|
|
fName = FALSE;
|
|
fEmail = FALSE;
|
|
fFromName = FALSE;
|
|
fFromEmail = FALSE;
|
|
*szHtm = 0;
|
|
|
|
if (ERROR_SUCCESS == AthUserOpenKey(c_szRegPathMail, KEY_READ, &hkey))
|
|
{
|
|
cb = sizeof(szHtm);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szWelcomeHtm, NULL, &type, (LPBYTE)szHtm, &cb))
|
|
{
|
|
if (REG_EXPAND_SZ == type)
|
|
{
|
|
ExpandEnvironmentStrings(szHtm, szExpanded, ARRAYSIZE(szExpanded));
|
|
psz = szExpanded;
|
|
}
|
|
|
|
if (PathFileExists(psz))
|
|
{
|
|
cb = sizeof(szFromName);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szWelcomeName, NULL, &type, (LPBYTE)szFromName, &cb) &&
|
|
cb > sizeof(TCHAR))
|
|
fFromName = TRUE;
|
|
|
|
cb = sizeof(szFromEmail);
|
|
if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szWelcomeEmail, NULL, &type, (LPBYTE)szFromEmail, &cb) &&
|
|
cb > sizeof(TCHAR))
|
|
fFromEmail = TRUE;
|
|
}
|
|
else
|
|
{
|
|
*psz = 0;
|
|
}
|
|
}
|
|
|
|
RegCloseKey(hkey);
|
|
}
|
|
|
|
Assert(g_pAcctMan != NULL);
|
|
if (SUCCEEDED(g_pAcctMan->Enumerate(SRV_IMAP | SRV_SMTP | SRV_POP3, &pEnum)))
|
|
{
|
|
Assert(pEnum != NULL);
|
|
|
|
while (!fName || !fEmail)
|
|
{
|
|
hr = pEnum->GetNext(&pAccount);
|
|
if (FAILED(hr) || pAccount == NULL)
|
|
break;
|
|
|
|
if (!fName)
|
|
{
|
|
if (!FAILED(pAccount->GetPropSz(AP_SMTP_DISPLAY_NAME, szName, ARRAYSIZE(szName)))
|
|
&& !FIsEmpty(szName))
|
|
fName = TRUE;
|
|
}
|
|
|
|
if (!fEmail)
|
|
{
|
|
if (!FAILED(pAccount->GetPropSz(AP_SMTP_EMAIL_ADDRESS, szEmail, ARRAYSIZE(szEmail)))
|
|
&& SUCCEEDED(ValidEmailAddress(szEmail)))
|
|
fEmail = TRUE;
|
|
}
|
|
|
|
pAccount->Release();
|
|
}
|
|
|
|
pEnum->Release();
|
|
}
|
|
|
|
// Add Recipient
|
|
if (!fName)
|
|
LoadString(g_hLocRes, idsNewAthenaUser, szName, ARRAYSIZE(szName));
|
|
|
|
if (!fFromName)
|
|
LoadString(g_hLocRes, idsWelcomeFromDisplay, szFromName, ARRAYSIZE(szFromName));
|
|
if (!fFromEmail)
|
|
LoadString(g_hLocRes, idsWelcomeFromEmail, szFromEmail, ARRAYSIZE(szFromEmail));
|
|
|
|
// add recipient and sender
|
|
if (SUCCEEDED(pWabal->HrAddEntryA(szName, fEmail ? szEmail : NULL, MAPI_TO)) &&
|
|
SUCCEEDED(pWabal->HrAddEntryA(szFromName, szFromEmail, MAPI_ORIG)))
|
|
{
|
|
if (SUCCEEDED(IAddWelcomeMessage(pfolder, pWabal, psz, HideHotmail() ? c_szWelcomeMsgHtm:c_szWelcomeMsgHotmailHtm)))
|
|
{
|
|
SetDwOption(OPT_NEEDWELCOMEMSG, FALSE, NULL, 0);
|
|
}
|
|
}
|
|
|
|
pWabal->Release();
|
|
}
|
|
|
|
// Direct WM_HELP/WM_CONTEXTMENU help here:
|
|
BOOL OnContextHelp(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam, HELPMAP const * rgCtxMap)
|
|
{
|
|
if (uMsg == WM_HELP)
|
|
{
|
|
LPHELPINFO lphi = (LPHELPINFO) lParam;
|
|
if (lphi->iContextType == HELPINFO_WINDOW) // must be for a control
|
|
{
|
|
OEWinHelp ((HWND)lphi->hItemHandle,
|
|
c_szCtxHelpFile,
|
|
HELP_WM_HELP,
|
|
(DWORD_PTR)(LPVOID)rgCtxMap);
|
|
}
|
|
return (TRUE);
|
|
}
|
|
else if (uMsg == WM_CONTEXTMENU)
|
|
{
|
|
OEWinHelp ((HWND) wParam,
|
|
c_szCtxHelpFile,
|
|
HELP_CONTEXTMENU,
|
|
(DWORD_PTR)(LPVOID)rgCtxMap);
|
|
return (TRUE);
|
|
}
|
|
|
|
Assert(0);
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
HRESULT HrSaveMessageToFile(HWND hwnd, LPMIMEMESSAGE pMsg, LPMIMEMESSAGE pDelSecMsg, BOOL fNews, BOOL fCanBeDirty)
|
|
{
|
|
OPENFILENAMEW ofn;
|
|
WCHAR wszFile[MAX_PATH],
|
|
wszTitle[CCHMAX_STRINGRES],
|
|
wszFilter[MAX_PATH],
|
|
wszDefExt[30];
|
|
LPWSTR pwszSubject=0;
|
|
HRESULT hr;
|
|
int rgidsSaveAsFilter[SAVEAS_NUMTYPES],
|
|
rgFilterType[SAVEAS_NUMTYPES],
|
|
cFilter=0;
|
|
DWORD dwFlags=0;
|
|
|
|
if(!pMsg || !hwnd)
|
|
return E_INVALIDARG;
|
|
|
|
*wszDefExt=0;
|
|
*wszTitle=0;
|
|
*wszFile=0;
|
|
*wszFilter=0;
|
|
|
|
pMsg->GetFlags(&dwFlags);
|
|
|
|
// Load Res Strings
|
|
rgidsSaveAsFilter[cFilter] = fNews?idsNwsFileFilter:idsEmlFileFilter;
|
|
rgFilterType[cFilter++] = SAVEAS_RFC822;
|
|
AthLoadStringW(fNews?idsDefNewsExt:idsDefMailExt, wszDefExt, ARRAYSIZE(wszDefExt));
|
|
|
|
if (dwFlags & IMF_PLAIN)
|
|
{
|
|
rgidsSaveAsFilter[cFilter] = idsTextFileFilter;
|
|
rgFilterType[cFilter++] = SAVEAS_TEXT;
|
|
|
|
rgidsSaveAsFilter[cFilter] = idsUniTextFileFilter;
|
|
rgFilterType[cFilter++] = SAVEAS_UNICODETEXT;
|
|
}
|
|
|
|
if (dwFlags & IMF_HTML)
|
|
{
|
|
rgidsSaveAsFilter[cFilter] = idsHtmlFileFilter;
|
|
rgFilterType[cFilter++] = SAVEAS_HTML;
|
|
}
|
|
|
|
CombineFiltersW(rgidsSaveAsFilter, cFilter, wszFilter);
|
|
AthLoadStringW(idsMailSaveAsTitle, wszTitle, ARRAYSIZE(wszTitle));
|
|
|
|
// Use Subject ?
|
|
hr=MimeOleGetBodyPropW(pMsg, HBODY_ROOT, PIDTOSTR(PID_HDR_SUBJECT), NOFLAGS, &pwszSubject);
|
|
if (!FAILED(hr))
|
|
{
|
|
wnsprintfW(wszFile, ARRAYSIZE(wszFile), L"%.240s", pwszSubject);
|
|
|
|
// Bug 84793. "." is not valid char for filename: "test.com"
|
|
ULONG ich=0;
|
|
ULONG cch=lstrlenW(wszFile);
|
|
|
|
// Loop and remove invalids
|
|
while (ich < cch)
|
|
{
|
|
// Illeagl file name character ?
|
|
if (!FIsValidFileNameCharW(wszFile[ich]) || (wszFile[ich] == L'.'))
|
|
wszFile[ich]=L'_';
|
|
|
|
ich++;
|
|
}
|
|
|
|
}
|
|
|
|
// Setup Save file struct
|
|
ZeroMemory (&ofn, sizeof (ofn));
|
|
ofn.lStructSize = sizeof (ofn);
|
|
ofn.hwndOwner = hwnd;
|
|
ofn.lpstrFilter = wszFilter;
|
|
ofn.nFilterIndex = 1;
|
|
ofn.lpstrFile = wszFile;
|
|
ofn.nMaxFile = ARRAYSIZE(wszFile);
|
|
ofn.lpstrTitle = wszTitle;
|
|
ofn.lpstrDefExt = wszDefExt;
|
|
ofn.Flags = OFN_NOREADONLYRETURN | OFN_OVERWRITEPROMPT | OFN_PATHMUSTEXIST | OFN_HIDEREADONLY | OFN_NOCHANGEDIR;
|
|
|
|
// Show SaveAs Dialog
|
|
if (HrAthGetFileNameW(&ofn, FALSE)!=S_OK)
|
|
{
|
|
// usercancel is cool.
|
|
hr=hrUserCancel;
|
|
goto error;
|
|
}
|
|
|
|
// ofn.nFilterIndex returns the currently selected filter. this is the index into
|
|
// the filter pair specified by lpstrFilter = idsMailSaveAsFilter. currently:
|
|
// 1 => eml
|
|
// 2 => txt
|
|
// 3 => unicode txt
|
|
// 4 => html
|
|
|
|
Assert ((int)ofn.nFilterIndex -1 < cFilter);
|
|
|
|
if(ofn.nFilterIndex != SAVEAS_RFC822)
|
|
{
|
|
if(IsEncrypted(pMsg, TRUE))
|
|
{
|
|
if(AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsSaveEncrypted), NULL, MB_YESNO) == IDNO)
|
|
{
|
|
hr=hrUserCancel;
|
|
goto error;
|
|
}
|
|
}
|
|
|
|
hr = HrSaveMsgSourceToFile((pDelSecMsg ? pDelSecMsg : pMsg), rgFilterType[ofn.nFilterIndex-1], wszFile, fCanBeDirty);
|
|
}
|
|
else
|
|
hr = HrSaveMsgSourceToFile(pMsg, rgFilterType[ofn.nFilterIndex-1], wszFile, fCanBeDirty);
|
|
|
|
error:
|
|
MemFree(pwszSubject);
|
|
|
|
if (FAILED(hr) && hr!=hrUserCancel)
|
|
AthErrorMessageW(hwnd, MAKEINTRESOURCEW(idsAthenaMail), MAKEINTRESOURCEW(idsUnableToSaveMessage), hr);
|
|
|
|
return hr;
|
|
};
|
|
|
|
VOID OnHelpGoto(HWND hwnd, UINT id)
|
|
{
|
|
UINT idh;
|
|
DWORD cb;
|
|
HRESULT hr;
|
|
CLSID clsid;
|
|
LPWSTR pwszCLSID;
|
|
IContextMenu *pMenu;
|
|
CMINVOKECOMMANDINFO info;
|
|
TCHAR szURL[INTERNET_MAX_URL_LENGTH];
|
|
|
|
if (id == ID_MSWEB_SEARCH)
|
|
{
|
|
cb = sizeof(szURL);
|
|
if (ERROR_SUCCESS == RegQueryValue(HKEY_LOCAL_MACHINE, c_szRegIEWebSearch, szURL, (LONG *)&cb))
|
|
{
|
|
pwszCLSID = PszToUnicode(CP_ACP, szURL);
|
|
if (pwszCLSID != NULL)
|
|
{
|
|
hr = CLSIDFromString(pwszCLSID, &clsid);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
hr = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IContextMenu, (void **)&pMenu);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
ZeroMemory(&info, sizeof(CMINVOKECOMMANDINFO));
|
|
info.cbSize = sizeof(CMINVOKECOMMANDINFO);
|
|
info.hwnd = hwnd;
|
|
pMenu->InvokeCommand(&info);
|
|
|
|
pMenu->Release();
|
|
}
|
|
}
|
|
|
|
MemFree(pwszCLSID);
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
hr = E_FAIL;
|
|
if (id == ID_MSWEB_SUPPORT)
|
|
{
|
|
cb = sizeof(szURL);
|
|
if (ERROR_SUCCESS == AthUserGetValue(NULL, c_szRegHelpUrl, NULL, (LPBYTE)szURL, &cb) &&
|
|
!FIsEmpty(szURL))
|
|
hr = S_OK;
|
|
}
|
|
|
|
if (hr != S_OK)
|
|
{
|
|
idh = id - ID_MSWEB_BASE;
|
|
hr = URLSubLoadStringA(idsHelpMSWebFirst + idh, szURL, ARRAYSIZE(szURL), URLSUB_ALL, NULL);
|
|
}
|
|
|
|
if (SUCCEEDED(hr))
|
|
ShellExecute(NULL, "open", szURL, c_szEmpty, c_szEmpty, SW_SHOWNORMAL);
|
|
}
|
|
|
|
|
|
VOID OnMailGoto(HWND hwnd)
|
|
{
|
|
OpenClient(hwnd, c_szRegPathMail);
|
|
}
|
|
|
|
VOID OnNewsGoto(HWND hwnd)
|
|
{
|
|
OpenClient(hwnd, c_szRegPathNews);
|
|
}
|
|
|
|
// Get the command line to launch the requested client.
|
|
BOOL GetClientCmdLine(LPCTSTR szClient, LPTSTR szCmdLine, int cch)
|
|
{
|
|
HKEY hKey = 0;
|
|
TCHAR sz[MAX_PATH];
|
|
TCHAR szClientKey[MAX_PATH];
|
|
TCHAR szClientPath[MAX_PATH];
|
|
TCHAR szExpanded[MAX_PATH];
|
|
LPTSTR psz;
|
|
DWORD dwType;
|
|
DWORD cb;
|
|
|
|
szCmdLine[0] = 0;
|
|
|
|
wnsprintf(sz, ARRAYSIZE(sz), TEXT("%s%s%s"), c_szRegPathClients, g_szBackSlash, szClient);
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, sz, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
|
|
goto LErr;
|
|
|
|
cb = ARRAYSIZE(szClientKey);
|
|
if (RegQueryValueEx(hKey, c_szEmpty, NULL, &dwType, (LPBYTE) szClientKey, &cb) != ERROR_SUCCESS)
|
|
goto LErr;
|
|
|
|
if (dwType != REG_SZ || szClientKey[0] == 0)
|
|
goto LErr;
|
|
|
|
StrCatBuff(sz, g_szBackSlash, ARRAYSIZE(sz));
|
|
StrCatBuff(sz, szClientKey, ARRAYSIZE(sz));
|
|
StrCatBuff(sz, g_szBackSlash, ARRAYSIZE(sz));
|
|
StrCatBuff(sz, c_szRegClientPath, ARRAYSIZE(sz));
|
|
|
|
if (RegCloseKey(hKey) != ERROR_SUCCESS)
|
|
goto LErr;
|
|
|
|
hKey = 0;
|
|
|
|
if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, sz, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
|
|
goto LErr;
|
|
|
|
cb = ARRAYSIZE(szClientPath);
|
|
if (RegQueryValueEx(hKey, c_szEmpty, NULL, &dwType, (LPBYTE) szClientPath, &cb) != ERROR_SUCCESS)
|
|
goto LErr;
|
|
|
|
if (REG_EXPAND_SZ == dwType)
|
|
{
|
|
ExpandEnvironmentStrings(szClientPath, szExpanded, ARRAYSIZE(szExpanded));
|
|
psz = szExpanded;
|
|
}
|
|
else if (dwType != REG_SZ || szClientPath[0] == 0)
|
|
goto LErr;
|
|
else
|
|
psz=szClientPath;
|
|
|
|
StrCpyN(szCmdLine, psz, cch);
|
|
|
|
LErr:
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
|
|
return (szCmdLine[0] != '\0');
|
|
}
|
|
|
|
VOID OpenClient(HWND hwnd, LPCTSTR szClient)
|
|
{
|
|
TCHAR szCmdLine[MAX_PATH];
|
|
|
|
if (!GetClientCmdLine(szClient, szCmdLine, MAX_PATH))
|
|
{
|
|
// TODO: Report error
|
|
return;
|
|
}
|
|
|
|
ShellExecute(hwnd, NULL, szCmdLine, NULL, NULL, SW_SHOW);
|
|
}
|
|
|
|
|
|
VOID OnBrowserGoto(HWND hwnd, LPCTSTR szRegPage, UINT idDefault)
|
|
{
|
|
HKEY hKey = 0;
|
|
TCHAR szStartPage[INTERNET_MAX_URL_LENGTH];
|
|
DWORD dw;
|
|
DWORD cb;
|
|
|
|
if (RegOpenKeyEx(HKEY_CURRENT_USER, c_szRegStartPageKey, 0, KEY_READ, &hKey) != ERROR_SUCCESS)
|
|
return;
|
|
|
|
szStartPage[0] = 0;
|
|
cb = sizeof(szStartPage) / sizeof(TCHAR);
|
|
|
|
if (RegQueryValueEx(hKey, szRegPage, NULL, &dw, (LPBYTE) szStartPage, &cb) != ERROR_SUCCESS ||
|
|
dw != REG_SZ ||
|
|
szStartPage[0] == 0)
|
|
{
|
|
URLSubLoadStringA(idDefault, szStartPage, ARRAYSIZE(szStartPage), URLSUB_ALL, NULL);
|
|
}
|
|
|
|
if (szStartPage[0])
|
|
ShellExecute(NULL, NULL, szStartPage, "", "", SW_SHOWNORMAL);
|
|
|
|
if (hKey)
|
|
RegCloseKey(hKey);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// AthLoadStringW
|
|
// --------------------------------------------------------------------------------
|
|
LPWSTR AthLoadStringW(UINT id, LPWSTR sz, int cch)
|
|
{
|
|
LPWSTR szT;
|
|
|
|
if (sz == NULL)
|
|
{
|
|
if (!MemAlloc((LPVOID*)&szT, CCHMAX_STRINGRES*sizeof(WCHAR)))
|
|
return(NULL);
|
|
cch = CCHMAX_STRINGRES;
|
|
}
|
|
else
|
|
szT = sz;
|
|
|
|
cch = LoadStringWrapW(g_hLocRes, id, szT, cch);
|
|
Assert(cch > 0);
|
|
|
|
if (cch == 0)
|
|
{
|
|
if (sz == NULL)
|
|
MemFree(szT);
|
|
szT = NULL;
|
|
}
|
|
|
|
return(szT);
|
|
}
|
|
|
|
// --------------------------------------------------------------------------------
|
|
// AthLoadString
|
|
// --------------------------------------------------------------------------------
|
|
LPTSTR AthLoadString(UINT id, LPTSTR sz, int cch)
|
|
{
|
|
LPTSTR szT;
|
|
|
|
if (sz == NULL)
|
|
{
|
|
if (!MemAlloc((LPVOID*)&szT, CCHMAX_STRINGRES))
|
|
return(NULL);
|
|
cch = CCHMAX_STRINGRES;
|
|
}
|
|
else
|
|
szT = sz;
|
|
|
|
cch = LoadString(g_hLocRes, id, szT, cch);
|
|
Assert(cch > 0);
|
|
|
|
if (cch == 0)
|
|
{
|
|
if (sz == NULL)
|
|
MemFree(szT);
|
|
szT = NULL;
|
|
}
|
|
|
|
return(szT);
|
|
}
|
|
|
|
/*
|
|
* hwnd - hwnd for error UI
|
|
* fHtmlOk - if html sigs are cool or not. If not and a html sig is chosen it will be spewed as plain-text
|
|
* pdwSigOpts - returns sig options
|
|
* pbstr - returns a BSTR of the HTML signature
|
|
* uCodePage - codepage to use when converting multibyte
|
|
* fMail - use mail or news options
|
|
*/
|
|
HRESULT HrGetMailNewsSignature(GETSIGINFO *pSigInfo, LPDWORD pdwSigOptions, BSTR *pbstr)
|
|
{
|
|
PROPVARIANT var;
|
|
IOptionBucket *pSig = NULL;
|
|
TCHAR szSigID[MAXSIGID+2];
|
|
unsigned char rgchSig[MAX_SIG_SIZE+2]; // might have to append a unicode null
|
|
unsigned char *pszSig;
|
|
DWORD dwSigOptions;
|
|
LPSTREAM pstm=0;
|
|
ULONG i,
|
|
cb=0;
|
|
BOOL fFile,
|
|
fUniPlainText = FALSE;
|
|
LPWSTR lpwsz=0;
|
|
LPSTR lpsz=0;
|
|
HRESULT hr;
|
|
BSTR bstr=0;
|
|
|
|
Assert(pSigInfo != NULL);
|
|
Assert(pdwSigOptions != NULL);
|
|
|
|
dwSigOptions = SIGOPT_TOP;
|
|
|
|
if (!pSigInfo->fMail) // news sigs. always have the prefix.
|
|
dwSigOptions |= SIGOPT_PREFIX;
|
|
|
|
*szSigID = 0;
|
|
if (pSigInfo->szSigID != NULL)
|
|
{
|
|
Assert(*pSigInfo->szSigID != 0);
|
|
StrCpyN((LPTSTR)szSigID, pSigInfo->szSigID, ARRAYSIZE(szSigID));
|
|
}
|
|
else if (pSigInfo->pAcct != NULL)
|
|
{
|
|
pSigInfo->pAcct->GetPropSz(pSigInfo->fMail ? AP_SMTP_SIGNATURE : AP_NNTP_SIGNATURE,
|
|
(LPTSTR)szSigID, ARRAYSIZE(szSigID));
|
|
// TODO: should we validate the sig here???
|
|
// if the sig has been deleted and for some reason the acct wasn't updated, this
|
|
// could point to a non-existent sig or a different sig. this shouldn't happen if
|
|
// everything else works properly...
|
|
}
|
|
|
|
if (*szSigID == 0)
|
|
{
|
|
Assert(g_pSigMgr != NULL);
|
|
hr = g_pSigMgr->GetDefaultSignature((LPTSTR)szSigID, ARRAYSIZE(szSigID));
|
|
if (FAILED(hr))
|
|
return(hr);
|
|
}
|
|
|
|
hr = g_pSigMgr->GetSignature((LPTSTR)szSigID, &pSig);
|
|
if (FAILED(hr))
|
|
return(hr);
|
|
Assert(pSig != NULL);
|
|
|
|
hr = pSig->GetProperty(MAKEPROPSTRING(SIG_TYPE), &var, 0);
|
|
Assert(SUCCEEDED(hr));
|
|
Assert(var.vt == VT_UI4);
|
|
fFile = (var.ulVal == SIGTYPE_FILE);
|
|
|
|
hr = pSig->GetProperty(fFile ? MAKEPROPSTRING(SIG_FILE) : MAKEPROPSTRING(SIG_TEXT), &var, 0);
|
|
Assert(SUCCEEDED(hr));
|
|
|
|
if(fFile)
|
|
{
|
|
Assert(var.vt == VT_LPWSTR);
|
|
Assert(var.pwszVal != NULL);
|
|
lpwsz = var.pwszVal;
|
|
}
|
|
else
|
|
{
|
|
Assert(var.vt == VT_LPSTR);
|
|
Assert(var.pszVal != NULL);
|
|
lpsz = var.pszVal;
|
|
}
|
|
|
|
if (fFile && FIsHTMLFileW(lpwsz))
|
|
dwSigOptions |= SIGOPT_HTML; // we're giving back a HTML sig
|
|
|
|
if (pbstr)
|
|
{
|
|
*pbstr = 0;
|
|
|
|
if (!fFile)
|
|
{
|
|
StrCpyN((char *)rgchSig, lpsz, ARRAYSIZE(rgchSig));
|
|
}
|
|
else
|
|
{
|
|
// if it has a htm or html extension then assume it's a html file
|
|
hr=CreateStreamOnHFileW(lpwsz, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL, &pstm);
|
|
if (FAILED(hr))
|
|
{
|
|
DWORD dwErr;
|
|
dwErr=GetLastError();
|
|
|
|
if(dwErr==ERROR_PATH_NOT_FOUND || dwErr==ERROR_FILE_NOT_FOUND)
|
|
{
|
|
// Don't turn off auto sig settings, just remove current.
|
|
g_pSigMgr->DeleteSignature((LPTSTR)szSigID);
|
|
|
|
// if filenotfound, warn user and disable the option
|
|
AthMessageBoxW(pSigInfo->hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsWarnSigNotFound), NULL, MB_OK);
|
|
|
|
}
|
|
goto error;
|
|
}
|
|
|
|
// perform the boundary check and binary check only on signature files
|
|
// on others, we let them insert whatever they want.
|
|
*rgchSig=0;
|
|
pstm->Read(rgchSig, MAX_SIG_SIZE, &cb);
|
|
rgchSig[cb]=0; // null term
|
|
pszSig=rgchSig;
|
|
|
|
fUniPlainText = ((cb > 2) && (0xFF == pszSig[0]) && (0xFE == pszSig[1]) && (0 == (dwSigOptions & SIGOPT_HTML)));
|
|
|
|
if (!fUniPlainText)
|
|
for(i=0; i<cb; i++)
|
|
{
|
|
if(IS_BINARY(*pszSig))
|
|
{
|
|
// Don't turn off auto sig settings, just remove current.
|
|
g_pSigMgr->DeleteSignature((LPTSTR)szSigID);
|
|
|
|
// signature contains invalid binary. Fail and disable option
|
|
AthMessageBoxW(pSigInfo->hwnd, MAKEINTRESOURCEW(idsAthena),
|
|
MAKEINTRESOURCEW(idsWarnSigBinary), NULL, MB_OK);
|
|
|
|
hr=E_FAIL;
|
|
goto error;
|
|
}
|
|
pszSig++;
|
|
}
|
|
|
|
// warn that size is too large and we have truncated. Don't disable option
|
|
if(cb==MAX_SIG_SIZE)
|
|
{
|
|
AthMessageBoxW(pSigInfo->hwnd, MAKEINTRESOURCEW(idsAthena),
|
|
MAKEINTRESOURCEW(idsWarnSigTruncated),
|
|
NULL, MB_OK);
|
|
}
|
|
SafeRelease(pstm);
|
|
}
|
|
|
|
// pstm contains our MultiByte data, let's convert the first cb bytes to a WideStream
|
|
if (dwSigOptions & SIGOPT_HTML)
|
|
{
|
|
if (pSigInfo->fHtmlOk)
|
|
{
|
|
// the sig is already HTML. Let's just alloc a bstr
|
|
hr = HrLPSZCPToBSTR(pSigInfo->uCodePage, (LPSTR)rgchSig, pbstr);
|
|
}
|
|
else
|
|
{
|
|
// the sig is HTML, but that's not cool. So let's downgrade it to plain-text
|
|
LPSTREAM pstmPlainW;
|
|
ULARGE_INTEGER uli;
|
|
|
|
// if the signature is HTML and the user want's a plain-text signature. They we need to convert the HTML to plain-text (strip formatting)
|
|
// and then convert the stripped plain-text to HTML.
|
|
|
|
Assert (pstm==NULL);
|
|
|
|
if (FAILED(hr=MimeOleCreateVirtualStream(&pstm)))
|
|
goto error;
|
|
|
|
pstm->Write(rgchSig, cb, NULL);
|
|
|
|
// $REVIEW: this is a little odd. For a non-html sig file, we'll use the codepage that
|
|
// the message is in (passed into this function). For a html file, we'll let Trident parse
|
|
// the meta tag and figure out the code page as we convert to plain-text via trident
|
|
if (!FAILED(hr=HrConvertHTMLToPlainText(pstm, &pstmPlainW, CF_UNICODETEXT)))
|
|
{
|
|
hr = HrIStreamWToBSTR(pstmPlainW, pbstr);
|
|
pstmPlainW->Release();
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// the signature is Plain-Text
|
|
if (fUniPlainText)
|
|
{
|
|
// We had added an ANSI NULL, now let's make it a unicode null
|
|
rgchSig[cb+1] = 0;
|
|
*pbstr = SysAllocString((LPWSTR)(&rgchSig[2]));
|
|
if (NULL == pbstr)
|
|
hr = E_OUTOFMEMORY;
|
|
}
|
|
else
|
|
hr = HrLPSZCPToBSTR(pSigInfo->uCodePage, (LPSTR)rgchSig, pbstr);
|
|
}
|
|
|
|
AssertSz((FAILED(hr) || *pbstr), "how come we succeeded with no BSTR allocated?");
|
|
}
|
|
|
|
*pdwSigOptions = dwSigOptions;
|
|
|
|
error:
|
|
MemFree(lpwsz);
|
|
MemFree(lpsz);
|
|
SafeRelease(pstm);
|
|
SafeRelease(pSig);
|
|
return hr;
|
|
}
|
|
|
|
HRESULT HrSaveMsgSourceToFile(LPMIMEMESSAGE pMsg, DWORD dwSaveAs, LPWSTR pwszFile, BOOL fCanBeDirty)
|
|
{
|
|
LPSTREAM pstmFile=0,
|
|
pstm=0;
|
|
HRESULT hr;
|
|
TCHAR sz[CCHMAX_STRINGRES],
|
|
szCset[CCHMAX_CSET_NAME];
|
|
HCHARSET hCharset;
|
|
|
|
hr = CreateStreamOnHFileW(pwszFile, GENERIC_READ|GENERIC_WRITE, NULL,
|
|
NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0, &pstmFile);
|
|
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
//N need to be able to save txt files as insecure messages
|
|
|
|
switch(dwSaveAs)
|
|
{
|
|
case SAVEAS_RFC822:
|
|
hr = pMsg->GetMessageSource(&pstm, fCanBeDirty ? COMMIT_ONLYIFDIRTY : 0);
|
|
break;
|
|
|
|
case SAVEAS_TEXT:
|
|
hr = HrGetDataStream((LPUNKNOWN)pMsg, CF_TEXT, &pstm);
|
|
break;
|
|
|
|
case SAVEAS_UNICODETEXT:
|
|
hr = HrGetDataStream((LPUNKNOWN)pMsg, CF_UNICODETEXT, &pstm);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
BYTE bUniMark = 0xFF;
|
|
hr = pstmFile->Write(&bUniMark, sizeof(bUniMark), NULL);
|
|
if (SUCCEEDED(hr))
|
|
{
|
|
bUniMark = 0xFE;
|
|
hr = pstmFile->Write(&bUniMark, sizeof(bUniMark), NULL);
|
|
}
|
|
}
|
|
break;
|
|
|
|
case SAVEAS_HTML:
|
|
// if saving as HTML always get the internet cset
|
|
hr = pMsg->GetTextBody(TXT_HTML, IET_INETCSET, &pstm, NULL);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = HrRewindStream(pstm);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
if (dwSaveAs == SAVEAS_HTML)
|
|
{
|
|
// if saving as HTML, append a meta charset into the head of the document
|
|
if (SUCCEEDED(pMsg->GetCharset(&hCharset)) && SUCCEEDED(HrGetMetaTagName(hCharset, szCset, ARRAYSIZE(szCset))))
|
|
{
|
|
wnsprintf(sz, ARRAYSIZE(sz), c_szHtml_MetaTagf, szCset);
|
|
pstmFile->Write(sz, lstrlen(sz)*sizeof(*sz), NULL);
|
|
}
|
|
}
|
|
|
|
hr = HrCopyStream(pstm, pstmFile, NULL);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
hr = pstmFile->Commit(STGC_DEFAULT);
|
|
if (FAILED(hr))
|
|
goto error;
|
|
|
|
error:
|
|
ReleaseObj(pstm);
|
|
ReleaseObj(pstmFile);
|
|
return hr;
|
|
|
|
}
|
|
|
|
void nyi(LPSTR lpsz)
|
|
{
|
|
TCHAR rgch[CCHMAX_STRINGRES];
|
|
TCHAR rgchNYI[CCHMAX_STRINGRES];
|
|
|
|
if (IS_INTRESOURCE(lpsz))
|
|
{
|
|
// its a string resource id
|
|
if (!LoadString(g_hLocRes, PtrToUlong(lpsz), rgch, CCHMAX_STRINGRES))
|
|
return;
|
|
|
|
lpsz = rgch;
|
|
}
|
|
|
|
if (!LoadString(g_hLocRes, idsNYITitle, rgchNYI, CCHMAX_STRINGRES))
|
|
return;
|
|
|
|
MessageBox(GetFocus(), lpsz, rgchNYI, MB_OK|MB_ICONSTOP|MB_SETFOREGROUND);
|
|
}
|
|
|
|
|
|
//NOTE: if *ppstm == NULL, then the stream is created.
|
|
//Otherwise it is written to.
|
|
HRESULT HrLoadStreamFileFromResource(LPCSTR lpszResourceName, LPSTREAM *ppstm)
|
|
{
|
|
HRESULT hr=E_FAIL;
|
|
HRSRC hres;
|
|
HGLOBAL hGlobal;
|
|
LPBYTE pb;
|
|
DWORD cb;
|
|
|
|
if (!ppstm || !lpszResourceName)
|
|
return E_INVALIDARG;
|
|
|
|
hres = FindResource(g_hLocRes, lpszResourceName, MAKEINTRESOURCE(RT_FILE));
|
|
if (!hres)
|
|
goto error;
|
|
|
|
hGlobal = LoadResource(g_hLocRes, hres);
|
|
if (!hGlobal)
|
|
goto error;
|
|
|
|
pb = (LPBYTE)LockResource(hGlobal);
|
|
if (!pb)
|
|
goto error;
|
|
|
|
cb = SizeofResource(g_hLocRes, hres);
|
|
if (!cb)
|
|
goto error;
|
|
|
|
if (*ppstm)
|
|
hr = (*ppstm)->Write(pb, cb, NULL);
|
|
else
|
|
{
|
|
if (SUCCEEDED(hr = MimeOleCreateVirtualStream(ppstm)))
|
|
hr = (*ppstm)->Write (pb, cb, NULL);
|
|
}
|
|
|
|
error:
|
|
return hr;
|
|
}
|
|
|
|
|
|
void ConvertTabsToSpaces(LPSTR lpsz)
|
|
{
|
|
if (lpsz)
|
|
{
|
|
while(*lpsz)
|
|
{
|
|
if (*lpsz == '\t')
|
|
*lpsz = ' ';
|
|
|
|
lpsz=CharNext(lpsz);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ConvertTabsToSpacesW(LPWSTR lpsz)
|
|
{
|
|
if (lpsz)
|
|
{
|
|
while(*lpsz)
|
|
{
|
|
if (*lpsz == L'\t')
|
|
*lpsz = L' ';
|
|
|
|
lpsz++;
|
|
}
|
|
}
|
|
}
|
|
|
|
// =================================================================================
|
|
// From strutil.cpp
|
|
// =================================================================================
|
|
#define SPECIAL_CHAR '|'
|
|
#define SPECIAL_CHAR_W L'|'
|
|
|
|
int LoadStringReplaceSpecial(UINT id, LPTSTR sz, int cch)
|
|
{
|
|
int cchRet=0;
|
|
|
|
if(sz)
|
|
{
|
|
cchRet=LoadString(g_hLocRes, id, sz, cch);
|
|
ReplaceChars(sz, SPECIAL_CHAR, '\0');
|
|
}
|
|
return cchRet;
|
|
}
|
|
|
|
int LoadStringReplaceSpecialW(UINT id, LPWSTR wsz, int cch)
|
|
{
|
|
int cchRet=0;
|
|
|
|
if(wsz)
|
|
{
|
|
cchRet=LoadStringWrapW(g_hLocRes, id, wsz, cch);
|
|
ReplaceCharsW(wsz, SPECIAL_CHAR_W, L'\0');
|
|
}
|
|
return cchRet;
|
|
}
|
|
|
|
void CombineFilters(int *rgidsFilter, int nFilters, LPSTR pszFilter)
|
|
{
|
|
DWORD cchFilter,
|
|
dw,
|
|
cch;
|
|
|
|
Assert (rgidsFilter);
|
|
Assert (nFilters);
|
|
Assert (pszFilter);
|
|
|
|
// we pray to the resource-editing gods that rgchFilter (MAX_PATH) is big enough...
|
|
|
|
*pszFilter = 0;
|
|
cchFilter = 0;
|
|
for (dw = 0; dw < (DWORD)nFilters; dw++)
|
|
{
|
|
cch = LoadStringReplaceSpecial(rgidsFilter[dw], &pszFilter[cchFilter], MAX_PATH);
|
|
Assert(cch);
|
|
cchFilter += cch-1; // -1 as each filter is double null terminated
|
|
}
|
|
}
|
|
|
|
void CombineFiltersW(int *rgidsFilter, int nFilters, LPWSTR pwszFilter)
|
|
{
|
|
DWORD cchFilter,
|
|
dw,
|
|
cch;
|
|
|
|
Assert (rgidsFilter);
|
|
Assert (nFilters);
|
|
Assert (pwszFilter);
|
|
|
|
// we pray to the resource-editing gods that rgchFilter (MAX_PATH) is big enough...
|
|
|
|
*pwszFilter = 0;
|
|
cchFilter = 0;
|
|
for (dw = 0; dw < (DWORD)nFilters; dw++)
|
|
{
|
|
cch = LoadStringReplaceSpecialW(rgidsFilter[dw], &pwszFilter[cchFilter], MAX_PATH);
|
|
Assert(cch);
|
|
cchFilter += cch-1; // -1 as each filter is double null terminated
|
|
}
|
|
}
|
|
|
|
void AthFormatSizeK(DWORD dw, LPTSTR szOut, UINT uiBufSize)
|
|
{
|
|
TCHAR szFmt[CCHMAX_STRINGRES];
|
|
TCHAR szBuf[CCHMAX_STRINGRES];
|
|
|
|
AthLoadString(idsFormatK, szFmt, ARRAYSIZE(szFmt));
|
|
if (dw == 0)
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szFmt, 0);
|
|
else if (dw <= 1024)
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szFmt, 1);
|
|
else
|
|
wnsprintf(szBuf, ARRAYSIZE(szBuf), szFmt, (dw + 512) / 1024);
|
|
StrCpyN(szOut, szBuf, uiBufSize);
|
|
}
|
|
|
|
|
|
|
|
|
|
void GetDigitalIDs(IImnAccount *pCertAccount)
|
|
{
|
|
HRESULT hr;
|
|
TCHAR szTemp[INTERNET_MAX_URL_LENGTH];
|
|
TCHAR szURL[INTERNET_MAX_URL_LENGTH];
|
|
DWORD cchOut = ARRAYSIZE(szURL);
|
|
CHAR szIexplore[MAX_PATH];
|
|
|
|
if (FAILED(hr = URLSubLoadStringA(idsHelpMSWebCertSubName, szTemp, ARRAYSIZE(szTemp), URLSUB_ALL, pCertAccount)) ||
|
|
FAILED(hr = UrlEscape(szTemp, szURL, &cchOut, URL_ESCAPE_SPACES_ONLY)))
|
|
hr = URLSubLoadStringA(idsHelpMSWebCert, szURL, ARRAYSIZE(szURL), URLSUB_ALL, pCertAccount);
|
|
|
|
// NOTE: we shellexec iexplore.exe here NOT the default handler for http://
|
|
// links. We have to make sure we launch this link with IE even if
|
|
// netscape is the browser. see georgeh for explanation of why.
|
|
if (SUCCEEDED(hr) && GetExePath(c_szIexploreExe, szIexplore, ARRAYSIZE(szIexplore), FALSE))
|
|
ShellExecute(NULL, "open", szIexplore, szURL, NULL, SW_SHOWNORMAL);
|
|
}
|
|
|
|
BOOL FGetSelectedCachedMsg(IMsgContainer *pIMC, HWND hwndList, BOOL fSecure, LPMIMEMESSAGE *ppMsg)
|
|
{
|
|
int iSel;
|
|
BOOL fCached = FALSE;
|
|
|
|
// Get the selected article header from the list view
|
|
iSel = ListView_GetFirstSel(hwndList);
|
|
if (-1 != iSel)
|
|
{
|
|
Assert(pIMC);
|
|
if (pIMC->HasBody(iSel))
|
|
pIMC->GetMsgByIndex(iSel, ppMsg, NULL, &fCached, FALSE, fSecure);
|
|
}
|
|
return fCached;
|
|
}
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Cached Password Support
|
|
//---------------------------------------------------------------------------
|
|
|
|
|
|
//-----------------
|
|
// Data Structures
|
|
//-----------------
|
|
typedef struct tagCACHED_PASSWORD {
|
|
DWORD dwPort;
|
|
char szServer[CCHMAX_SERVER_NAME];
|
|
char szUsername[CCHMAX_PASSWORD];
|
|
char szPassword[CCHMAX_PASSWORD];
|
|
struct tagCACHED_PASSWORD *pNext;
|
|
} CACHED_PASSWORD;
|
|
|
|
|
|
//------------------
|
|
// Static Variables
|
|
//------------------
|
|
static CACHED_PASSWORD *s_pPasswordList = NULL;
|
|
|
|
//***************************************************************************
|
|
// Function: SavePassword
|
|
//
|
|
// Purpose:
|
|
// This function saves a password for later retrieval using GetPassword.
|
|
// It allows OE to cache passwords for the session in order to avoid asking
|
|
// a user for his password more than once. If the given password has already
|
|
// been cached, this function replaces the old password with the new password.
|
|
// It is assumed that a password's recipient may be uniquely identified
|
|
// by servername and port number.
|
|
//
|
|
// Arguments:
|
|
// DWORD dwPort [in] - the port number of the server we are trying to
|
|
// connect to. This allows us to keep separate passwords for SMTP and
|
|
// POP/IMAP servers on the same machine.
|
|
// LPSTR pszServer [in] - the server name for which the password was
|
|
// supplied. Server names are treated as case-insensitive.
|
|
// LPSTR pszUsername [in] - the username for which the password was supplied.
|
|
// LPSTR pszPassword [in] - the password for this server and port number.
|
|
//
|
|
// Returns:
|
|
// HRESULT indicating success or failure.
|
|
//***************************************************************************
|
|
HRESULT SavePassword(DWORD dwPort, LPSTR pszServer, LPSTR pszUsername, LPSTR pszPassword)
|
|
{
|
|
CACHED_PASSWORD *pExisting;
|
|
HRESULT hrResult = S_OK;
|
|
|
|
EnterCriticalSection(&s_csPasswordList);
|
|
|
|
// Check if we already have a cached password entry for this server
|
|
pExisting = s_pPasswordList;
|
|
while (NULL != pExisting)
|
|
{
|
|
if (dwPort == pExisting->dwPort &&
|
|
0 == lstrcmpi(pszServer, pExisting->szServer) &&
|
|
0 == lstrcmp(pszUsername, pExisting->szUsername))
|
|
break;
|
|
|
|
pExisting = pExisting->pNext;
|
|
}
|
|
|
|
if (NULL == pExisting)
|
|
{
|
|
CACHED_PASSWORD *pNewPassword;
|
|
|
|
// Insert new password at head of linked list
|
|
pNewPassword = new CACHED_PASSWORD;
|
|
if (NULL == pNewPassword)
|
|
{
|
|
hrResult = E_OUTOFMEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
pNewPassword->dwPort = dwPort;
|
|
StrCpyN(pNewPassword->szServer, pszServer, ARRAYSIZE(pNewPassword->szServer));
|
|
StrCpyN(pNewPassword->szUsername, pszUsername, ARRAYSIZE(pNewPassword->szUsername));
|
|
StrCpyN(pNewPassword->szPassword, pszPassword, ARRAYSIZE(pNewPassword->szPassword));
|
|
pNewPassword->pNext = s_pPasswordList;
|
|
|
|
s_pPasswordList = pNewPassword;
|
|
}
|
|
else
|
|
// Replace existing cached value
|
|
StrCpyN(pExisting->szPassword, pszPassword, ARRAYSIZE(pExisting->szPassword));
|
|
|
|
exit:
|
|
LeaveCriticalSection(&s_csPasswordList);
|
|
return hrResult;
|
|
} // SavePassword
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
// Function: GetPassword
|
|
//
|
|
// Purpose:
|
|
// This function retrieves a password previously saved using SavePassword.
|
|
//
|
|
// Arguments:
|
|
// DWORD dwPort [in] - the port number of the server we are trying to
|
|
// connect to. This allows us to keep separate passwords for SMTP and
|
|
// POP/IMAP servers on the same machine.
|
|
// LPSTR pszServer [in] - the server name which we are trying to connect to.
|
|
// Server names are treated as case-insensitive.
|
|
// LPSTR pszUsername [in] - the username which we are trying to connect for.
|
|
// LPSTR pszPassword [out] - if successful, the function returns the password
|
|
// for the given server and port number here. If the caller only wants to
|
|
// check if a password is cached, he may pass in NULL.
|
|
// DWORD dwSizeOfPassword [in] - the size of the buffer pointed to by
|
|
// pszPassword, to avoid overflow.
|
|
//
|
|
// Returns:
|
|
// HRESULT indicating success or failure.
|
|
//***************************************************************************
|
|
HRESULT GetPassword(DWORD dwPort, LPSTR pszServer, LPSTR pszUsername,
|
|
LPSTR pszPassword, DWORD dwSizeOfPassword)
|
|
{
|
|
HRESULT hrResult = E_FAIL;
|
|
CACHED_PASSWORD *pCurrent;
|
|
|
|
EnterCriticalSection(&s_csPasswordList);
|
|
|
|
// Traverse the linked list looking for password
|
|
pCurrent = s_pPasswordList;
|
|
while (NULL != pCurrent)
|
|
{
|
|
if (dwPort == pCurrent->dwPort &&
|
|
0 == lstrcmpi(pszServer, pCurrent->szServer) &&
|
|
0 == lstrcmp(pszUsername, pCurrent->szUsername))
|
|
{
|
|
if (NULL != pszPassword && 0 != dwSizeOfPassword)
|
|
StrCpyN(pszPassword, pCurrent->szPassword, dwSizeOfPassword);
|
|
|
|
hrResult = S_OK;
|
|
goto exit;
|
|
}
|
|
|
|
pCurrent = pCurrent->pNext;
|
|
} // while
|
|
|
|
exit:
|
|
LeaveCriticalSection(&s_csPasswordList);
|
|
return hrResult;
|
|
} // GetPassword
|
|
|
|
|
|
|
|
//***************************************************************************
|
|
// Function: DestroyPasswordList
|
|
// Purpose:
|
|
// This function deallocates all cached passwords saved using SavePassword.
|
|
//***************************************************************************
|
|
void DestroyPasswordList(void)
|
|
{
|
|
CACHED_PASSWORD *pCurrent;
|
|
|
|
EnterCriticalSection(&s_csPasswordList);
|
|
|
|
pCurrent = s_pPasswordList;
|
|
while (NULL != pCurrent)
|
|
{
|
|
CACHED_PASSWORD *pDeleteMe;
|
|
|
|
pDeleteMe = pCurrent;
|
|
pCurrent = pCurrent->pNext;
|
|
delete pDeleteMe;
|
|
} // while
|
|
s_pPasswordList = NULL;
|
|
|
|
LeaveCriticalSection(&s_csPasswordList);
|
|
|
|
} // DestroyPasswordList
|
|
|
|
HRESULT CALLBACK FreeAthenaDataObj(PDATAOBJINFO pDataObjInfo, DWORD celt)
|
|
{
|
|
// Loop through the data and free it all
|
|
if (pDataObjInfo)
|
|
{
|
|
for (DWORD i = 0; i < celt; i++)
|
|
{
|
|
SafeMemFree(pDataObjInfo[i].pData);
|
|
}
|
|
SafeMemFree(pDataObjInfo);
|
|
}
|
|
return S_OK;
|
|
}
|
|
|
|
HRESULT _IsSameObject(IUnknown* punk1, IUnknown* punk2)
|
|
{
|
|
IUnknown* punkI1;
|
|
HRESULT hres = punk1->QueryInterface(IID_IUnknown, (LPVOID*)&punkI1);
|
|
if (FAILED(hres))
|
|
{
|
|
Assert(0);
|
|
return hres;
|
|
}
|
|
|
|
IUnknown* punkI2;
|
|
hres = punk2->QueryInterface(IID_IUnknown, (LPVOID*)&punkI2);
|
|
if (SUCCEEDED(hres))
|
|
{
|
|
hres = (punkI1 == punkI2) ? S_OK : S_FALSE;
|
|
punkI2->Release();
|
|
}
|
|
else
|
|
{
|
|
Assert(0);
|
|
}
|
|
punkI1->Release();
|
|
return hres;
|
|
}
|
|
|
|
BOOL FileExists(TCHAR *szFile, BOOL fNew)
|
|
{
|
|
WIN32_FIND_DATA fd;
|
|
HANDLE hnd;
|
|
BOOL fRet;
|
|
|
|
fRet = FALSE;
|
|
|
|
hnd = FindFirstFile(szFile, &fd);
|
|
if (hnd != INVALID_HANDLE_VALUE)
|
|
{
|
|
FindClose(hnd);
|
|
|
|
if (fNew)
|
|
fRet = TRUE;
|
|
else
|
|
fRet = (0 == (fd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY));
|
|
}
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
BOOL FIsSubDir(LPCSTR szOld, LPCSTR szNew)
|
|
{
|
|
BOOL fRet;
|
|
int cchNew, cchOld;
|
|
|
|
Assert(szOld != NULL);
|
|
Assert(szNew != NULL);
|
|
|
|
cchOld = lstrlen(szOld);
|
|
cchNew = lstrlen(szNew);
|
|
|
|
fRet = (cchNew > cchOld &&
|
|
szNew[cchOld] == '\\' &&
|
|
0 == StrCmpNI(szOld, szNew, cchOld));
|
|
|
|
return(fRet);
|
|
}
|
|
|
|
BOOL CALLBACK EnumThreadCB(HWND hwnd, LPARAM lParam);
|
|
|
|
#define SetMenuItem(hmenu, id, fOn) EnableMenuItem(hmenu, id, fOn?MF_ENABLED:MF_DISABLED|MF_GRAYED);
|
|
|
|
HWND GetTopMostParent(HWND hwndChild)
|
|
{
|
|
HWND hwnd=hwndChild;
|
|
LONG_PTR lStyle;
|
|
|
|
if (FALSE == IsWindow(hwndChild))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
do
|
|
{
|
|
hwnd = hwndChild;
|
|
|
|
// Get the style of the current window
|
|
lStyle = GetWindowLongPtr(hwnd, GWL_STYLE);
|
|
|
|
// Are we at the top window?
|
|
if (0 == (lStyle & WS_CHILD))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Get the parent of the window
|
|
} while (NULL != (hwndChild = GetParent(hwnd)));
|
|
|
|
exit:
|
|
return hwnd;
|
|
}
|
|
|
|
|
|
HCURSOR HourGlass()
|
|
{
|
|
return SetCursor(LoadCursor(NULL, IDC_WAIT));
|
|
}
|
|
|
|
|
|
HRESULT CEmptyList::Show(HWND hwndList, LPTSTR pszString)
|
|
{
|
|
// We're already doing a window
|
|
if (m_hwndList)
|
|
{
|
|
Hide();
|
|
}
|
|
|
|
// Keep a copy of the listview window handle
|
|
m_hwndList = hwndList;
|
|
|
|
if (IS_INTRESOURCE(pszString))
|
|
{
|
|
// If the provided string is actually a resource ID, load it
|
|
m_pszString = AthLoadString(PtrToUlong(pszString), NULL, 0);
|
|
}
|
|
else
|
|
{
|
|
// Otherwise make a copy
|
|
m_pszString = PszDupA(pszString);
|
|
}
|
|
|
|
// Get the header window handle from the listview
|
|
m_hwndHeader = ListView_GetHeader(m_hwndList);
|
|
|
|
// Save our this pointer on the listview window
|
|
SetProp(m_hwndList, _T("EmptyListClass"), (HANDLE) this);
|
|
|
|
// Subclass the listview so we can steal sizing messages
|
|
if (!m_pfnWndProc)
|
|
m_pfnWndProc = SubclassWindow(m_hwndList, SubclassWndProc);
|
|
|
|
// Create our window on top
|
|
if (!m_hwndBlocker)
|
|
{
|
|
m_hwndBlocker = CreateWindow(_T("Static"), _T("Blocker!"),
|
|
WS_CHILD | WS_TABSTOP | WS_CLIPSIBLINGS | SS_CENTER,
|
|
0, 0, 10, 10, m_hwndList, 0, g_hInst, NULL);
|
|
Assert(m_hwndBlocker);
|
|
}
|
|
|
|
// Set the text for the blocker
|
|
SetWindowText(m_hwndBlocker, m_pszString);
|
|
|
|
// Set the font for the blocker
|
|
HFONT hf = (HFONT) SendMessage(m_hwndList, WM_GETFONT, 0, 0);
|
|
SendMessage(m_hwndBlocker, WM_SETFONT, (WPARAM) hf, MAKELPARAM(TRUE, 0));
|
|
|
|
// Position the blocker
|
|
RECT rcList, rcHead;
|
|
GetClientRect(m_hwndList, &rcList);
|
|
GetClientRect(m_hwndHeader, &rcHead);
|
|
|
|
SetWindowPos(m_hwndBlocker, 0, 0, rcHead.bottom, rcList.right,
|
|
rcList.bottom - rcHead.bottom, SWP_NOACTIVATE | SWP_NOZORDER);
|
|
|
|
// Show the thing
|
|
ShowWindow(m_hwndBlocker, SW_SHOW);
|
|
|
|
return (S_OK);
|
|
}
|
|
|
|
HRESULT CEmptyList::Hide(void)
|
|
{
|
|
// Verify we have the blocker up first
|
|
if (m_pfnWndProc)
|
|
{
|
|
// Hide the window
|
|
ShowWindow(m_hwndBlocker, SW_HIDE);
|
|
|
|
// Unsubclass the window
|
|
SubclassWindow(m_hwndList, m_pfnWndProc);
|
|
|
|
// Delete the property
|
|
RemoveProp(m_hwndList, _T("EmptyListClass"));
|
|
|
|
// Free the string
|
|
SafeMemFree(m_pszString);
|
|
|
|
// NULL everything out
|
|
m_pfnWndProc = 0;
|
|
m_hwndList = 0;
|
|
}
|
|
|
|
return (S_OK);
|
|
|
|
}
|
|
|
|
|
|
LRESULT CEmptyList::SubclassWndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
CEmptyList* pThis = (CEmptyList *) GetProp(hwnd, _T("EmptyListClass"));
|
|
Assert(pThis);
|
|
|
|
switch (uMsg)
|
|
{
|
|
case WM_SIZE:
|
|
if (pThis && IsWindow(pThis->m_hwndBlocker))
|
|
{
|
|
RECT rcHeader;
|
|
|
|
GetClientRect(pThis->m_hwndHeader, &rcHeader);
|
|
SetWindowPos(pThis->m_hwndBlocker, 0, 0, 0, LOWORD(lParam),
|
|
HIWORD(lParam) - rcHeader.bottom,
|
|
SWP_NOZORDER | SWP_NOMOVE | SWP_NOACTIVATE);
|
|
InvalidateRect(pThis->m_hwndBlocker, NULL, FALSE);
|
|
}
|
|
break;
|
|
|
|
case WM_CTLCOLORSTATIC:
|
|
if ((HWND) lParam == pThis->m_hwndBlocker)
|
|
{
|
|
if (!pThis->m_hbrBack)
|
|
{
|
|
pThis->m_hbrBack = CreateSolidBrush(GetSysColor(COLOR_WINDOW));
|
|
}
|
|
SetBkColor((HDC) wParam, GetSysColor(COLOR_WINDOW));
|
|
return (LRESULT) pThis->m_hbrBack;
|
|
}
|
|
break;
|
|
|
|
case WM_SYSCOLORCHANGE:
|
|
if (pThis)
|
|
{
|
|
DeleteObject(pThis->m_hbrBack);
|
|
pThis->m_hbrBack = 0;
|
|
|
|
SendMessage(pThis->m_hwndBlocker, uMsg, wParam, lParam);
|
|
}
|
|
break;
|
|
|
|
case WM_WININICHANGE:
|
|
case WM_FONTCHANGE:
|
|
if (pThis)
|
|
{
|
|
LRESULT lResult = CallWindowProc(pThis->m_pfnWndProc, hwnd, uMsg, wParam, lParam);
|
|
|
|
SendMessage(pThis->m_hwndBlocker, uMsg, wParam, lParam);
|
|
HFONT hf = (HFONT) SendMessage(pThis->m_hwndList, WM_GETFONT, 0, 0);
|
|
SendMessage(pThis->m_hwndBlocker, WM_SETFONT, (WPARAM) hf, MAKELPARAM(TRUE, 0));
|
|
|
|
return (lResult);
|
|
}
|
|
|
|
case WM_DESTROY:
|
|
{
|
|
if (pThis)
|
|
{
|
|
WNDPROC pfn = pThis->m_pfnWndProc;
|
|
pThis->Hide();
|
|
return (CallWindowProc(pfn, hwnd, uMsg, wParam, lParam));
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (pThis)
|
|
return (CallWindowProc(pThis->m_pfnWndProc, hwnd, uMsg, wParam, lParam));
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
BOOL AllocStringFromDlg(HWND hwnd, UINT id, LPTSTR * lplpsz)
|
|
{
|
|
UINT cb;
|
|
HWND hwndEdit;
|
|
|
|
if (*lplpsz)
|
|
{
|
|
MemFree(*lplpsz);
|
|
}
|
|
|
|
*lplpsz = NULL;
|
|
|
|
hwndEdit = GetDlgItem(hwnd, id);
|
|
if (hwndEdit == NULL)
|
|
return(TRUE);
|
|
|
|
cb = Edit_GetTextLength(hwndEdit);
|
|
|
|
if (cb)
|
|
{
|
|
cb++; // null terminator
|
|
MemAlloc((LPVOID *) lplpsz, cb * sizeof(TCHAR));
|
|
if (*lplpsz)
|
|
{
|
|
Edit_GetText(hwndEdit, *lplpsz, cb);
|
|
return TRUE;
|
|
}
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
void GetChildRect(HWND hwndDlg, HWND hwndChild, RECT *prc)
|
|
{
|
|
RECT rc;
|
|
POINT pt;
|
|
|
|
Assert(IsWindow(hwndDlg)&&IsWindow(hwndChild));
|
|
Assert(GetParent(hwndChild)==hwndDlg);
|
|
Assert(prc);
|
|
GetWindowRect(hwndChild, &rc);
|
|
// a-msadek; Do not check for hwndChild since we already disabled mirroring
|
|
// for Richedit controls
|
|
pt.x= IS_WINDOW_RTL_MIRRORED(hwndDlg)? rc.right : rc.left;
|
|
pt.y=rc.top;
|
|
ScreenToClient(hwndDlg, &pt);
|
|
SetRect(prc, pt.x, pt.y, pt.x+(rc.right-rc.left), pt.y+(rc.bottom-rc.top));
|
|
}
|
|
|
|
|
|
|
|
|
|
void GetEditDisableFlags(HWND hwndEdit, DWORD *pdwFlags)
|
|
{
|
|
DWORD dwFlags=0;
|
|
|
|
Assert(pdwFlags);
|
|
*pdwFlags=0;
|
|
|
|
// RICHEDIT's
|
|
// Figure out whether the edit has any selection or content
|
|
if(GetFocus()==hwndEdit)
|
|
dwFlags|=edfEditFocus;
|
|
|
|
if(SendMessage(hwndEdit, EM_SELECTIONTYPE, 0, 0)!=SEL_EMPTY)
|
|
{
|
|
dwFlags |= edfEditHasSel;
|
|
if(!FReadOnlyEdit(hwndEdit))
|
|
dwFlags |= edfEditHasSelAndIsRW;
|
|
}
|
|
|
|
if (Edit_CanUndo(hwndEdit))
|
|
dwFlags |= edfUndo;
|
|
if (SendMessage(hwndEdit, EM_CANPASTE, 0, 0))
|
|
dwFlags |= edfPaste;
|
|
|
|
*pdwFlags=dwFlags;
|
|
}
|
|
|
|
|
|
|
|
|
|
void EnableDisableEditToolbar(HWND hwndToolbar, DWORD dwFlags)
|
|
{
|
|
SendMessage(hwndToolbar, TB_ENABLEBUTTON, ID_CUT,
|
|
MAKELONG(dwFlags&edfEditHasSelAndIsRW,0));
|
|
SendMessage(hwndToolbar, TB_ENABLEBUTTON, ID_COPY,
|
|
MAKELONG(dwFlags&edfEditHasSel,0));
|
|
SendMessage(hwndToolbar, TB_ENABLEBUTTON, ID_PASTE,
|
|
MAKELONG(dwFlags&edfPaste,0));
|
|
SendMessage(hwndToolbar, TB_ENABLEBUTTON, ID_UNDO,
|
|
MAKELONG(dwFlags&edfUndo,0));
|
|
}
|
|
|
|
|
|
void EnableDisableEditMenu(HMENU hmenuEdit, DWORD dwFlags)
|
|
{
|
|
if(!hmenuEdit)
|
|
return;
|
|
|
|
SetMenuItem(hmenuEdit, ID_UNDO, dwFlags&edfUndo);
|
|
SetMenuItem(hmenuEdit, ID_CUT, dwFlags&edfEditHasSelAndIsRW);
|
|
SetMenuItem(hmenuEdit, ID_COPY, dwFlags&edfEditHasSel);
|
|
SetMenuItem(hmenuEdit, ID_PASTE, dwFlags&edfPaste);
|
|
SetMenuItem(hmenuEdit, ID_SELECT_ALL, dwFlags&edfEditFocus);
|
|
}
|
|
|
|
void StopBlockingPaints(HWND hwndBlock)
|
|
{
|
|
if (hwndBlock)
|
|
DestroyWindow(hwndBlock);
|
|
}
|
|
|
|
LRESULT CALLBACK BlockingWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
|
|
{
|
|
if (msg==WM_PAINT)
|
|
{
|
|
PAINTSTRUCT ps;
|
|
|
|
BeginPaint(hwnd, &ps);
|
|
EndPaint(hwnd, &ps);
|
|
return 1;
|
|
}
|
|
if(msg==WM_ERASEBKGND)
|
|
return 1;
|
|
return DefWindowProc(hwnd, msg, wParam, lParam);
|
|
}
|
|
|
|
HWND HwndStartBlockingPaints(HWND hwnd)
|
|
{
|
|
WNDCLASS wc;
|
|
RECT rc;
|
|
HWND hwndBlock;
|
|
|
|
// Create WNDCLASS for Paint Block
|
|
if (!GetClassInfo(g_hInst, c_szBlockingPaintsClass, &wc))
|
|
{
|
|
ZeroMemory(&wc, sizeof(WNDCLASS));
|
|
wc.hInstance = g_hInst;
|
|
wc.lpfnWndProc = BlockingWndProc;
|
|
wc.hCursor = LoadCursor(NULL, IDC_WAIT);
|
|
wc.lpszClassName = c_szBlockingPaintsClass;
|
|
if (!RegisterClass(&wc))
|
|
return NULL;
|
|
}
|
|
|
|
GetWindowRect(hwnd, &rc);
|
|
|
|
if(hwndBlock = CreateWindow(c_szBlockingPaintsClass, NULL,
|
|
WS_POPUP, rc.left, rc.top,
|
|
rc.right - rc.left, rc.bottom - rc.top,
|
|
hwnd, NULL, g_hInst, NULL))
|
|
ShowWindow(hwndBlock, SW_SHOWNA);
|
|
return hwndBlock;
|
|
}
|
|
|
|
|
|
void SaveFocus(BOOL fActive, HWND *phwnd)
|
|
{
|
|
if(fActive&&IsWindow(*phwnd))
|
|
SetFocus(*phwnd);
|
|
else
|
|
*phwnd=GetFocus();
|
|
#ifdef DEBUG
|
|
if(fActive)
|
|
DOUTL(4, "Setting focus to 0x%x", *phwnd);
|
|
else
|
|
DOUTL(4, "Focus was on 0x%x", *phwnd);
|
|
#endif
|
|
}
|
|
|
|
|
|
void DoToolbarDropdown(HWND hwnd, LPNMHDR lpnmh, HMENU hmenu)
|
|
{
|
|
RECT rc;
|
|
DWORD dwCmd;
|
|
NMTOOLBAR *ptbn = (NMTOOLBAR *) lpnmh;
|
|
|
|
rc = ptbn->rcButton;
|
|
MapWindowRect(lpnmh->hwndFrom, HWND_DESKTOP, &rc);
|
|
|
|
dwCmd = TrackPopupMenuEx(hmenu, TPM_RETURNCMD | TPM_LEFTALIGN,
|
|
rc.left, rc.bottom, hwnd, NULL);
|
|
|
|
if (dwCmd)
|
|
PostMessage(hwnd, WM_COMMAND, dwCmd, 0);
|
|
}
|
|
|
|
|
|
HWND FindModalOwner()
|
|
{
|
|
HWND hwndPopup = NULL;
|
|
HWND hwnd;
|
|
DWORD dwThreadId = GetCurrentThreadId();
|
|
|
|
// Check the windows in Z-Order to find one that belongs to this
|
|
// task.
|
|
hwnd = GetLastActivePopup(GetActiveWindow());
|
|
while (IsWindow(hwnd) && IsWindowVisible(hwnd))
|
|
{
|
|
if (GetWindowThreadProcessId(hwnd, NULL) == dwThreadId)
|
|
{
|
|
hwndPopup = hwnd;
|
|
break;
|
|
}
|
|
hwnd = GetNextWindow(hwnd, GW_HWNDNEXT);
|
|
}
|
|
|
|
return hwndPopup;
|
|
}
|
|
|
|
//
|
|
// FUNCTION: FreeMessageInfo
|
|
//
|
|
// PURPOSE: Free all of the memory in a MESSAGEINFO structure.
|
|
// All non-allocated pointers should be null on entry.
|
|
// Freed pointers will be nulled on return. The
|
|
// pMsgInfo is not freed.
|
|
//
|
|
// PARAMETERS:
|
|
// pMsgInfo - Pointer to an LPMESSAGEINFO structure.
|
|
//
|
|
// RETURN VALUE:
|
|
// ignored
|
|
//
|
|
void FreeMessageInfo(LPMESSAGEINFO pMsgInfo)
|
|
{
|
|
SafeMemFree(pMsgInfo->pszMessageId);
|
|
SafeMemFree(pMsgInfo->pszSubject);
|
|
SafeMemFree(pMsgInfo->pszFromHeader);
|
|
SafeMemFree(pMsgInfo->pszReferences);
|
|
SafeMemFree(pMsgInfo->pszXref);
|
|
SafeMemFree(pMsgInfo->pszServer);
|
|
SafeMemFree(pMsgInfo->pszDisplayFrom);
|
|
SafeMemFree(pMsgInfo->pszEmailFrom);
|
|
SafeMemFree(pMsgInfo->pszDisplayTo);
|
|
SafeMemFree(pMsgInfo->pszEmailTo);
|
|
SafeMemFree(pMsgInfo->pszUidl);
|
|
SafeMemFree(pMsgInfo->pszPartialId);
|
|
SafeMemFree(pMsgInfo->pszForwardTo);
|
|
SafeMemFree(pMsgInfo->pszAcctName);
|
|
SafeMemFree(pMsgInfo->pszAcctId);
|
|
SafeMemFree(pMsgInfo->pszUrlComponent);
|
|
SafeMemFree(pMsgInfo->pszFolder);
|
|
SafeMemFree(pMsgInfo->pszMSOESRec);
|
|
}
|
|
|
|
|
|
//
|
|
// FUNCTION: Util_EnumFiles()
|
|
//
|
|
// PURPOSE: Enumerates files in a directory that match a wildcard
|
|
//
|
|
// PARAMETERS:
|
|
// <in> pszDir - Handle of a window we can display UI over.
|
|
// <in> pszMatch - wildcard to match (*.nch)
|
|
//
|
|
// RETURN VALUE:
|
|
// double-null terminated list of filenames
|
|
//
|
|
LPWSTR Util_EnumFiles(LPCWSTR pwszDir, LPCWSTR pwszMatch)
|
|
{
|
|
// Locals
|
|
WCHAR wszSearchPath[MAX_PATH];
|
|
LPWSTR pwszFiles=NULL;
|
|
WIN32_FIND_DATAW rfd;
|
|
HANDLE hFind = INVALID_HANDLE_VALUE;
|
|
ULONG iFiles = 0,
|
|
cbFileName,
|
|
cbFiles = 0;
|
|
HRESULT hr = S_OK;
|
|
|
|
// Check Params
|
|
Assert(pwszDir);
|
|
Assert(pwszMatch);
|
|
|
|
// Make Search Path
|
|
wnsprintfW(wszSearchPath, ARRAYSIZE(wszSearchPath), c_wszPathWildExtFmt, pwszDir, pwszMatch);
|
|
|
|
// Build list of file names
|
|
hFind = FindFirstFileWrapW(wszSearchPath, &rfd);
|
|
|
|
// Good ...
|
|
while (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
// Get Length of file name
|
|
cbFileName = (lstrlenW(rfd.cFileName) + 1)*sizeof(WCHAR);
|
|
|
|
// Add onto cbFiles
|
|
cbFiles += cbFileName;
|
|
|
|
// Realloc pszFiles
|
|
// sizeof(WCHAR) to handle the final double null
|
|
IF_NULLEXIT(MemRealloc((LPVOID *)&pwszFiles, cbFiles+sizeof(WCHAR)));
|
|
|
|
// Copy String - include null terminator
|
|
CopyMemory(pwszFiles + iFiles, rfd.cFileName, cbFileName);
|
|
|
|
// Increment iFiles
|
|
iFiles += cbFileName/sizeof(WCHAR);
|
|
|
|
// Find Next
|
|
if (FindNextFileWrapW(hFind, &rfd) == FALSE)
|
|
{
|
|
FindClose (hFind);
|
|
hFind = INVALID_HANDLE_VALUE;
|
|
}
|
|
}
|
|
|
|
// Double null terminator at the end
|
|
if (pwszFiles)
|
|
*(pwszFiles + iFiles) = L'\0';
|
|
|
|
exit:
|
|
// Cleanup
|
|
if (hFind != INVALID_HANDLE_VALUE)
|
|
FindClose (hFind);
|
|
|
|
if (FAILED(hr))
|
|
SafeMemFree(pwszFiles);
|
|
|
|
// Done
|
|
return pwszFiles;
|
|
}
|
|
|
|
//
|
|
// FUNCTION: GetDefaultNewsServer()
|
|
//
|
|
// PURPOSE: Returns the id of the user's default news server.
|
|
//
|
|
// PARAMETERS:
|
|
// pszServer - Pointer to the string where the server account id should
|
|
// be returned.
|
|
// cchMax - Size of the string pszServer.
|
|
//
|
|
HRESULT GetDefaultNewsServer(LPTSTR pszServerId, DWORD cchMax)
|
|
{
|
|
IImnAccount* pAcct;
|
|
HRESULT hr;
|
|
ULONG cSrv;
|
|
|
|
if (SUCCEEDED(hr = g_pAcctMan->GetDefaultAccount(ACCT_NEWS, &pAcct)))
|
|
{
|
|
hr = pAcct->GetPropSz(AP_ACCOUNT_ID, pszServerId, cchMax);
|
|
pAcct->Release();
|
|
}
|
|
|
|
Assert(!FAILED(hr) || (!FAILED(g_pAcctMan->GetAccountCount(ACCT_NEWS, &cSrv)) && cSrv == 0));
|
|
|
|
return(hr);
|
|
}
|
|
|
|
|
|
|
|
BOOL WINAPI EnumTopLevelWindows(HWND hwnd, LPARAM lParam)
|
|
{
|
|
HWNDLIST *pHwndList = (HWNDLIST *)lParam;
|
|
|
|
// Add the window to the list only if it is active and visible
|
|
// if ETW_OE_WINDOWS_ONLY is set, only add registered OE windows to the list
|
|
// [PaulHi] 6/4/99 Raid 76713
|
|
// We need to also enumerate disabled windows, for the enumeration that
|
|
// closes them. Otherwise they will remain open and the user will be
|
|
// unable to close them.
|
|
if (/* IsWindowVisible(hwnd) && IsWindowEnabled(hwnd) && */
|
|
(!(pHwndList->dwFlags & ETW_OE_WINDOWS_ONLY) || GetProp(hwnd, c_szOETopLevel)))
|
|
{
|
|
// If pHwndList->cAlloc is 0 then we are only counting
|
|
// the active windows
|
|
if (pHwndList->cAlloc)
|
|
{
|
|
Assert(pHwndList->cHwnd < pHwndList->cAlloc);
|
|
pHwndList->rgHwnd[pHwndList->cHwnd] = hwnd;
|
|
}
|
|
|
|
pHwndList->cHwnd++;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
HRESULT EnableThreadWindows(HWNDLIST *pHwndList, BOOL fEnable, DWORD dwFlags, HWND hwndExcept)
|
|
{
|
|
if (fEnable)
|
|
{
|
|
// Enable keyboard and mouse input on the list of windows
|
|
for (int i = 0; i < pHwndList->cHwnd; i++)
|
|
{
|
|
if (hwndExcept != pHwndList->rgHwnd[i])
|
|
{
|
|
if (dwFlags & ETW_OE_WINDOWS_ONLY)
|
|
SendMessage(pHwndList->rgHwnd[i], WM_OE_ENABLETHREADWINDOW, TRUE, 0);
|
|
else
|
|
EnableWindow(pHwndList->rgHwnd[i], TRUE);
|
|
}
|
|
}
|
|
if (pHwndList->rgHwnd)
|
|
MemFree(pHwndList->rgHwnd);
|
|
|
|
ZeroMemory(pHwndList, sizeof(HWNDLIST));
|
|
return S_OK;
|
|
}
|
|
else
|
|
{
|
|
|
|
ZeroMemory(pHwndList, sizeof(HWNDLIST));
|
|
|
|
pHwndList->dwFlags = dwFlags;
|
|
|
|
// Count the number of active and visible windows
|
|
EnumThreadWindows(GetCurrentThreadId(), EnumTopLevelWindows, (DWORD_PTR)pHwndList);
|
|
|
|
// Allocate space for the window list
|
|
if (pHwndList->cHwnd)
|
|
{
|
|
if (!MemAlloc((LPVOID*)&pHwndList->rgHwnd, pHwndList->cHwnd * sizeof(HWND)))
|
|
return E_OUTOFMEMORY;
|
|
|
|
pHwndList->cAlloc = pHwndList->cHwnd;
|
|
pHwndList->cHwnd = 0;
|
|
}
|
|
|
|
// List the active and visible windows
|
|
EnumThreadWindows(GetCurrentThreadId(), EnumTopLevelWindows, (DWORD_PTR)pHwndList);
|
|
|
|
// Disable keyboard and mouse input on the active and visible windows
|
|
for (int i = 0; i < pHwndList->cHwnd; i++)
|
|
{
|
|
if ( (hwndExcept != pHwndList->rgHwnd[i]) &&
|
|
IsWindowVisible(pHwndList->rgHwnd[i]) && IsWindowEnabled(pHwndList->rgHwnd[i]) )
|
|
{
|
|
if (dwFlags & ETW_OE_WINDOWS_ONLY)
|
|
SendMessage(pHwndList->rgHwnd[i], WM_OE_ENABLETHREADWINDOW, FALSE, 0);
|
|
else
|
|
EnableWindow(pHwndList->rgHwnd[i], FALSE);
|
|
}
|
|
}
|
|
|
|
return S_OK;
|
|
}
|
|
}
|
|
|
|
void ActivatePopupWindow(HWND hwnd)
|
|
{
|
|
HWND hwndOwner;
|
|
|
|
// set the popup to be active
|
|
SetActiveWindow(hwnd);
|
|
|
|
// walk the owner chain, and z-order the windows behind it
|
|
while(hwndOwner = GetWindow(hwnd, GW_OWNER))
|
|
{
|
|
SetWindowPos(hwndOwner, hwnd, 0, 0, 0, 0, SWP_NOSIZE|SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOOWNERZORDER);
|
|
hwnd = hwndOwner;
|
|
}
|
|
}
|
|
|
|
|
|
HRESULT GetOEUserName(BSTR *pbstr)
|
|
{
|
|
TCHAR rgch[CCHMAX_STRINGRES];
|
|
HRESULT hr=E_FAIL;
|
|
LPCSTR pszName;
|
|
IImnAccount *pAccount;
|
|
|
|
Assert (pbstr);
|
|
|
|
*pbstr=NULL;
|
|
|
|
// get multi-user name, if applicable
|
|
pszName = MU_GetCurrentIdentityName();
|
|
if (pszName && *pszName)
|
|
hr = HrLPSZToBSTR(pszName, pbstr);
|
|
else
|
|
{
|
|
if (g_pAcctMan &&
|
|
g_pAcctMan->GetDefaultAccount(ACCT_MAIL, &pAccount)==S_OK)
|
|
{
|
|
if (pAccount->GetPropSz(AP_SMTP_DISPLAY_NAME, rgch, ARRAYSIZE(rgch))==S_OK && *rgch)
|
|
hr = HrLPSZToBSTR(rgch, pbstr);
|
|
|
|
pAccount->Release();
|
|
}
|
|
}
|
|
return hr;
|
|
}
|
|
HRESULT CloseThreadWindows(HWND hwndExcept, DWORD uiThreadId)
|
|
{
|
|
HWNDLIST HwndList = {0};
|
|
|
|
// Count the number of active and visible windows
|
|
HwndList.dwFlags = ETW_OE_WINDOWS_ONLY;
|
|
EnumThreadWindows(uiThreadId, EnumTopLevelWindows, ((DWORD_PTR) &HwndList));
|
|
|
|
// Allocate space for the window list
|
|
if (HwndList.cHwnd)
|
|
{
|
|
if (!MemAlloc((LPVOID*)&(HwndList.rgHwnd), HwndList.cHwnd * sizeof(HWND)))
|
|
return E_OUTOFMEMORY;
|
|
|
|
HwndList.cAlloc = HwndList.cHwnd;
|
|
HwndList.cHwnd = 0;
|
|
}
|
|
|
|
// List the active and visible windows
|
|
EnumThreadWindows(uiThreadId, EnumTopLevelWindows, ((DWORD_PTR)&HwndList));
|
|
|
|
// Close all OE top level windows
|
|
for (int i = 0; i < HwndList.cHwnd; i++)
|
|
{
|
|
if (hwndExcept != HwndList.rgHwnd[i])
|
|
{
|
|
SendMessage(HwndList.rgHwnd[i], WM_CLOSE, 0, 0);
|
|
}
|
|
}
|
|
|
|
MemFree(HwndList.rgHwnd);
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
BOOL HideHotmail()
|
|
{
|
|
int cch;
|
|
DWORD dw, cb, type;
|
|
char sz[8];
|
|
|
|
cch = LoadString(g_hLocRes, idsHideHotmailMenu, sz, ARRAYSIZE(sz));
|
|
if (cch == 1 && *sz == '1')
|
|
return(TRUE);
|
|
|
|
cb = sizeof(dw);
|
|
if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, c_szRegFlat, c_szRegDisableHotmail, &type, &dw, &cb) &&
|
|
dw == 2)
|
|
return(FALSE);
|
|
|
|
cb = sizeof(dw);
|
|
if (ERROR_SUCCESS == SHGetValue(HKEY_CURRENT_USER, c_szRegFlat, c_szRegDisableHotmail, &type, &dw, &cb) &&
|
|
dw == 2)
|
|
return(FALSE);
|
|
|
|
return(TRUE);
|
|
}
|
|
|
|
BOOL FIsIMAPOrHTTPAvailable(VOID)
|
|
{
|
|
BOOL fRet = FALSE;
|
|
IImnEnumAccounts * pEnumAcct = NULL;
|
|
IImnAccount * pAccount = NULL;
|
|
|
|
// Get the account enumerator
|
|
Assert(g_pAcctMan);
|
|
if (FAILED(g_pAcctMan->Enumerate(SRV_HTTPMAIL | SRV_IMAP, &pEnumAcct)))
|
|
{
|
|
fRet = FALSE;
|
|
goto exit;
|
|
}
|
|
|
|
// Do we have any accounts?
|
|
if ((SUCCEEDED(pEnumAcct->GetNext(&pAccount))) && (NULL != pAccount))
|
|
{
|
|
fRet = TRUE;
|
|
}
|
|
|
|
exit:
|
|
SafeRelease(pAccount);
|
|
SafeRelease(pEnumAcct);
|
|
return fRet;
|
|
}
|
|
|
|
// HACKHACK [neilbren]
|
|
// A recent public header change wrapped some CALENDAR constants from winnls.h
|
|
// in a WINVER >= 5. It's too late to change our WINVER, so we'll manually
|
|
// define these - a problem waiting to happen :-(
|
|
#ifndef CAL_GREGORIAN_ARABIC
|
|
#define CAL_GREGORIAN_ARABIC 10 // Gregorian Arabic calendar
|
|
#endif
|
|
|
|
#ifndef CAL_GREGORIAN_XLIT_ENGLISH
|
|
#define CAL_GREGORIAN_XLIT_ENGLISH 11 // Gregorian Transliterated English calendar
|
|
#endif
|
|
|
|
#ifndef CAL_GREGORIAN_XLIT_FRENCH
|
|
#define CAL_GREGORIAN_XLIT_FRENCH 12 // Gregorian Transliterated French calendar
|
|
#endif
|
|
|
|
BOOL IsBiDiCalendar(void)
|
|
{
|
|
TCHAR chCalendar[32];
|
|
CALTYPE defCalendar;
|
|
static BOOL bRet = (BOOL)(DWORD)-1;
|
|
|
|
if (bRet != (BOOL)(DWORD)-1)
|
|
{
|
|
return bRet;
|
|
}
|
|
|
|
bRet = FALSE;
|
|
|
|
//
|
|
// Let's verify the calendar type whether it's gregorian or not.
|
|
if (GetLocaleInfo(LOCALE_USER_DEFAULT,
|
|
LOCALE_ICALENDARTYPE,
|
|
(TCHAR *) &chCalendar[0],
|
|
ARRAYSIZE(chCalendar)))
|
|
{
|
|
defCalendar = StrToInt((TCHAR *)&chCalendar[0]);
|
|
|
|
if ((defCalendar == CAL_HIJRI) ||
|
|
(defCalendar == CAL_HEBREW) ||
|
|
(defCalendar == CAL_GREGORIAN_ARABIC) ||
|
|
(defCalendar == CAL_GREGORIAN_XLIT_ENGLISH) ||
|
|
(defCalendar == CAL_GREGORIAN_XLIT_FRENCH))
|
|
{
|
|
bRet = TRUE;
|
|
}
|
|
}
|
|
|
|
return bRet;
|
|
}
|
|
|
|
|
|
LPSTR PszAllocResUrl(LPSTR pszRelative)
|
|
{
|
|
TCHAR rgch[MAX_PATH];
|
|
LPSTR psz;
|
|
|
|
*rgch = 0;
|
|
|
|
GetModuleFileName(g_hLocRes, rgch, MAX_PATH);
|
|
|
|
DWORD cchSize = (lstrlen(rgch) + lstrlen(pszRelative) + 8);
|
|
psz = PszAllocA(cchSize); //+8 "res:///0"
|
|
if (psz)
|
|
wnsprintf(psz, cchSize, "res://%s/%s", rgch, pszRelative);
|
|
|
|
return psz;
|
|
}
|
|
|
|
//
|
|
// If you are calling this function and you use the result to draw text, you
|
|
// must use a function that supports font substitution (DrawTextWrapW, ExtTextOutWrapW).
|
|
//
|
|
BOOL GetTextExtentPoint32AthW(HDC hdc, LPCWSTR lpwString, int cchString, LPSIZE lpSize, DWORD dwFlags)
|
|
{
|
|
RECT rect = {0};
|
|
int rc;
|
|
|
|
rc = DrawTextWrapW(hdc, lpwString, cchString, &rect, DT_CALCRECT | dwFlags);
|
|
|
|
lpSize->cx = rect.right - rect.left + 1;
|
|
lpSize->cy = rect.bottom - rect.top + 1;
|
|
|
|
return((BOOL)rc);
|
|
}
|