Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1388 lines
42 KiB

/*****************************************************************************\
FILE: MailBox.cpp
DESCRIPTION:
This file implements the logic of the MailBox feature.
BryanSt 2/26/2000
Copyright (C) Microsoft Corp 2000-2000. All rights reserved.
\*****************************************************************************/
#include "priv.h"
#include <atlbase.h> // USES_CONVERSION
#include "util.h"
#include "objctors.h"
#include <comdef.h>
#include <limits.h> // INT_MAX
#include <commctrl.h> // Str_SetPtr
#include "wizard.h"
#include "MailBox.h"
#include "emailassoc.h"
#ifdef FEATURE_MAILBOX
#define WM_AUTODISCOVERY_FINISHED (WM_USER + 1)
// These are the wizard control IDs for the Back, Next, and Finished buttons.
#define IDD_WIZARD_BACK_BUTTON 0x3023
#define IDD_WIZARD_NEXT_BUTTON 0x3024
#define IDD_WIZARD_FINISH_BUTTON 0x3025
/**************************************************************************
CLASS: CMailBoxProcess
**************************************************************************/
class CMailBoxProcess : public IUnknown
{
public:
//IUnknown methods
STDMETHODIMP QueryInterface(REFIID, LPVOID*);
STDMETHODIMP_(DWORD) AddRef();
STDMETHODIMP_(DWORD) Release();
HRESULT ParseCmdLine(LPTSTR lpCmdLine);
HRESULT Run(void);
CMailBoxProcess();
~CMailBoxProcess();
private:
// Private Member Variables
DWORD m_cRef;
TCHAR m_szEmailAddress[MAX_EMAIL_ADDRESSS];
TCHAR m_szNextText[MAX_PATH];
BOOL m_fAutoDiscoveryFailed; // Did the AutoDiscovery process fail?
LPTSTR m_pszMailApp; // Which app was chosen?
LPTSTR m_pszURL; // Which URL should be used to read mail?
HWND m_hwndDialog;
HRESULT m_hr;
IMailAutoDiscovery * m_pMailAutoDiscovery;
BOOL m_fGetDefaultAccount; // If yes, open to wizard page asking for email address.
BOOL m_fShowGetEmailAddressPage; // Do we want to show the get email address wizard page?
BOOL m_fCreateNewEmailAccount; // Does the user want to create a new email account (like on one of the free email servers: hotmail, yahoo, etc.)
// Private Member Functions
HRESULT _DisplayDialogAndAutoDiscover(void);
HRESULT _OpenWebBasedEmail(HKEY hkey);
HRESULT _OpenExeBasedEmailApp(IN LPCWSTR pszMailApp);
HRESULT _OpenProprietaryEmailApp(IN BSTR bstrProtocol, IN IMailProtocolADEntry * pMailProtocol);
HRESULT _OpenEmailApp(void);
HRESULT _RestoreNextButton(void);
HRESULT _FillListWithApps(HWND hwndList);
HRESULT _OnGetDispInfo(LV_DISPINFO * pDispInfo, bool fUnicode);
HRESULT _OnChooseAppListFocus(void);
HRESULT _OnChooseAppURLFocus(void);
HRESULT _OnAppListSelection(LPNMLISTVIEW pListview);
INT_PTR _MailBoxProgressDialogProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
INT_PTR _ChooseAppDialogProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
INT_PTR _GetEmailAddressDialogProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
INT_PTR _OnInit(HWND hDlg);
INT_PTR _OnInitChooseApp(HWND hDlg);
INT_PTR _OnUserCancelled(void);
INT_PTR _OnFinished(HRESULT hr, BSTR bstrXML);
INT_PTR _OnGetEmailAddressNext(void);
INT_PTR _OnCommand(WPARAM wParam, LPARAM lParam);
INT_PTR _OnFinishedManualAssociate(void);
friend INT_PTR CALLBACK MailBoxProgressDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
friend INT_PTR CALLBACK ChooseAppDialogProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam);
friend INT_PTR CALLBACK GetEmailAddressDialogProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
};
typedef struct tagEMAILCLIENT
{
LPTSTR pszFriendlyName;
LPTSTR pszPath;
LPTSTR pszCmdLine;
LPTSTR pszIconPath;
LPTSTR pszEmailApp;
} EMAILCLIENT;
//===========================
// *** Class Internals & Helpers ***
//===========================
BOOL IsWhitespace(TCHAR Char)
{
return ((Char == TEXT(' ')) || (Char == TEXT('\t')));
}
LPTSTR APIENTRY SkipWhite(LPTSTR pszString)
{
while (pszString[0] && IsWhitespace(pszString[0]))
{
pszString = CharNext(pszString);
}
return pszString;
}
BOOL IsFlagSpecified(IN LPCTSTR pwzFlag, IN LPCTSTR pszArg)
{
BOOL fIsFlagSpecified = FALSE;
if ((TEXT('/') == pszArg[0]) ||
(TEXT('-') == pszArg[0]))
{
if ((0 == StrCmpI(pwzFlag, &pszArg[1])) ||
((0 == StrCmpNI(pwzFlag, &pszArg[1], lstrlen(pwzFlag))) &&
(IsWhitespace(pszArg[lstrlen(pwzFlag) + 1])) ) )
{
fIsFlagSpecified = TRUE;
}
}
return fIsFlagSpecified;
}
LPTSTR GetNextArgument(LPTSTR pszCmdLine)
{
pszCmdLine = StrChr(pszCmdLine, TEXT(' '));
if (pszCmdLine)
{
pszCmdLine = SkipWhite(pszCmdLine);
}
return pszCmdLine;
}
void FreeEmailClient(EMAILCLIENT * pEmailClient)
{
if (pEmailClient)
{
Str_SetPtr(&pEmailClient->pszFriendlyName, NULL);
Str_SetPtr(&pEmailClient->pszPath, NULL);
Str_SetPtr(&pEmailClient->pszCmdLine, NULL);
Str_SetPtr(&pEmailClient->pszIconPath, NULL);
Str_SetPtr(&pEmailClient->pszEmailApp, NULL);
LocalFree(pEmailClient);
}
}
HRESULT CMailBoxProcess::_DisplayDialogAndAutoDiscover(void)
{
HWND hwndParent = NULL; // Do we need a parent?
ATOMICRELEASE(m_pMailAutoDiscovery);
m_fShowGetEmailAddressPage = (m_szEmailAddress[0] ? FALSE : TRUE);
DisplayMailBoxWizard((LPARAM)this, m_fShowGetEmailAddressPage);
HRESULT hr = m_hr;
if (SUCCEEDED(hr))
{
// Create account.
hr = E_FAIL;
long nSize;
// Loop thru the list looking for the first instance of a protocol
// that we support.
if (m_pMailAutoDiscovery)
{
hr = m_pMailAutoDiscovery->get_length(&nSize);
if (SUCCEEDED(hr))
{
VARIANT varIndex;
IMailProtocolADEntry * pMailProtocol = NULL;
hr = E_FAIL;
varIndex.vt = VT_I4;
for (long nIndex = 0; (nIndex < nSize); nIndex++)
{
varIndex.lVal = nIndex;
if (SUCCEEDED(m_pMailAutoDiscovery->get_item(varIndex, &pMailProtocol)))
{
BSTR bstrProtocol;
hr = pMailProtocol->get_Protocol(&bstrProtocol);
if (SUCCEEDED(hr))
{
// Is this protocol one of the ones we support?
if (!StrCmpIW(bstrProtocol, STR_PT_WEBBASED))
{
SysFreeString(bstrProtocol);
hr = EmailAssoc_CreateWebAssociation(m_szEmailAddress, pMailProtocol);
break;
}
// Is this protocol one of the ones we support?
if (!StrCmpIW(bstrProtocol, STR_PT_POP) ||
!StrCmpIW(bstrProtocol, STR_PT_IMAP) ||
!StrCmpIW(bstrProtocol, STR_PT_DAVMAIL))
{
hr = EmailAssoc_CreateStandardsBaseAssociation(m_szEmailAddress, bstrProtocol);
if (SUCCEEDED(hr))
{
SysFreeString(bstrProtocol);
break;
}
}
hr = _OpenProprietaryEmailApp(bstrProtocol, pMailProtocol);
SysFreeString(bstrProtocol);
if (SUCCEEDED(hr))
{
break;
}
}
ATOMICRELEASE(pMailProtocol);
}
}
ATOMICRELEASE(pMailProtocol);
}
}
// We may have failed up until now because AutoDiscovery failed or was skipped,
// but the user may have selected an app from the list.
if (FAILED(hr))
{
if (m_pszMailApp)
{
HKEY hkey;
hr = EmailAssoc_CreateEmailAccount(m_szEmailAddress, &hkey);
if (SUCCEEDED(hr))
{
hr = EmailAssoc_SetEmailAccountPreferredApp(hkey, m_pszMailApp);
RegCloseKey(hkey);
}
}
else if (m_pszURL && m_pszURL[0])
{
HKEY hkey;
hr = EmailAssoc_CreateEmailAccount(m_szEmailAddress, &hkey);
if (SUCCEEDED(hr))
{
hr = EmailAssoc_SetEmailAccountProtocol(hkey, SZ_REGDATA_WEB);
if (SUCCEEDED(hr))
{
hr = EmailAssoc_SetEmailAccountWebURL(hkey, m_pszURL);
}
RegCloseKey(hkey);
}
}
}
}
return hr;
}
INT_PTR CALLBACK MailBoxProgressDialogProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
CMailBoxProcess * pMBProgress = (CMailBoxProcess *)GetWindowLongPtr(hDlg, DWLP_USER);
if (WM_INITDIALOG == wMsg)
{
PROPSHEETPAGE * pPropSheetPage = (PROPSHEETPAGE *) lParam;
if (pPropSheetPage)
{
SetWindowLongPtr(hDlg, DWLP_USER, pPropSheetPage->lParam);
pMBProgress = (CMailBoxProcess *)pPropSheetPage->lParam;
}
}
if (pMBProgress)
return pMBProgress->_MailBoxProgressDialogProc(hDlg, wMsg, wParam, lParam);
return DefWindowProc(hDlg, wMsg, wParam, lParam);
}
INT_PTR CMailBoxProcess::_MailBoxProgressDialogProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
INT_PTR fHandled = TRUE; // handled
switch (wMsg)
{
case WM_INITDIALOG:
fHandled = _OnInit(hDlg);
break;
case WM_AUTODISCOVERY_FINISHED:
fHandled = _OnFinished((HRESULT)wParam, (BSTR)lParam);
break;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch (pnmh->code)
{
case LVN_GETDISPINFO:
wMsg++;
break;
case PSN_SETACTIVE:
PropSheet_SetWizButtons(GetParent(hDlg), ((TRUE == m_fShowGetEmailAddressPage) ? PSWIZB_NEXT | PSWIZB_BACK : PSWIZB_NEXT));
fHandled = TRUE; // Return zero to accept the activation.
break;
case PSN_WIZBACK:
fHandled = TRUE; // Return zero to allow the user to go to the next page.
break;
case PSN_WIZNEXT:
m_hr = S_FALSE;
_RestoreNextButton();
fHandled = 0; // Return zero to allow the user to go to the next page.
break;
case PSN_QUERYCANCEL:
_OnUserCancelled();
fHandled = FALSE;
break;
default:
//TraceMsg(TF_ALWAYS, "CMailBoxProcess::_MailBoxProgressDialogProc(wMsg = %d, pnmh->code = %d) WM_NOTIFY", wMsg, pnmh->code);
break;
}
}
default:
//TraceMsg(TF_ALWAYS, "CMailBoxProcess::_MailBoxProgressDialogProc(wMsg = %d) WM_NOTIFY", wMsg);
fHandled = FALSE; // Not handled
break;
}
return fHandled;
}
INT_PTR CALLBACK ChooseAppDialogProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
CMailBoxProcess * pMBProgress = (CMailBoxProcess *)GetWindowLongPtr(hDlg, DWLP_USER);
if (WM_INITDIALOG == wMsg)
{
PROPSHEETPAGE * pPropSheetPage = (PROPSHEETPAGE *) lParam;
if (pPropSheetPage)
{
SetWindowLongPtr(hDlg, DWLP_USER, pPropSheetPage->lParam);
pMBProgress = (CMailBoxProcess *)pPropSheetPage->lParam;
}
}
if (pMBProgress)
return pMBProgress->_ChooseAppDialogProc(hDlg, wMsg, wParam, lParam);
return DefWindowProc(hDlg, wMsg, wParam, lParam);
}
HRESULT CMailBoxProcess::_OnChooseAppURLFocus(void)
{
HWND hwndURLEditbox = GetDlgItem(m_hwndDialog, IDC_CHOOSEAPP_WEBURL_EDIT);
// Something happened to cause to have us shift into the "Other:" case.
CheckDlgButton(m_hwndDialog, IDC_CHOOSEAPP_WEB_RADIO, BST_CHECKED); // Uncheck the Web radio button
CheckDlgButton(m_hwndDialog, IDC_CHOOSEAPP_OTHERAPP_RADIO, BST_UNCHECKED); // Uncheck the Web radio button
SetFocus(hwndURLEditbox);
return S_OK;
}
INT_PTR CMailBoxProcess::_OnFinishedManualAssociate(void)
{
// TODO: Only succeed the finished part if something is selected in the app list.
// Also gray out the button.
m_hr = S_OK;
// Did the user manually configure via "Web" or an app?
if (IsDlgButtonChecked(m_hwndDialog, IDC_CHOOSEAPP_WEB_RADIO))
{
// Web. So save the URL.
TCHAR szURL[MAX_URL_STRING];
GetWindowText(GetDlgItem(m_hwndDialog, IDC_CHOOSEAPP_WEBURL_EDIT), szURL, ARRAYSIZE(szURL));
Str_SetPtr(&m_pszURL, szURL);
Str_SetPtr(&m_pszMailApp, NULL);
}
return FALSE; // FALSE mean means allow it to close. TRUE means keep it open.
}
HRESULT CMailBoxProcess::_OnAppListSelection(LPNMLISTVIEW pListview)
{
LPTSTR pszNewApp = NULL; // None selected.
// The user choose from the list. So store the name of the app
if (pListview && (-1 != pListview->iItem))
{
HWND hwndList = GetDlgItem(m_hwndDialog, IDC_CHOOSEAPP_APPLIST);
LVITEM pItem = {0};
pItem.iItem = pListview->iItem;
pItem.iSubItem = pListview->iSubItem;
pItem.mask = LVIF_PARAM;
if (ListView_GetItem(hwndList, &pItem))
{
EMAILCLIENT * pEmailClient = (EMAILCLIENT *) pItem.lParam;
if (pEmailClient)
{
pszNewApp = pEmailClient->pszEmailApp;
}
}
}
Str_SetPtr(&m_pszMailApp, pszNewApp);
return S_OK;
}
HRESULT CMailBoxProcess::_OnChooseAppListFocus(void)
{
HWND hwndAppList = GetDlgItem(m_hwndDialog, IDC_CHOOSEAPP_APPLIST);
// Something happened to cause to have us shift into the "Other:" case.
CheckDlgButton(m_hwndDialog, IDC_CHOOSEAPP_WEB_RADIO, BST_UNCHECKED); // Uncheck the Web radio button
CheckDlgButton(m_hwndDialog, IDC_CHOOSEAPP_OTHERAPP_RADIO, BST_CHECKED); // Uncheck the Web radio button
SetFocus(hwndAppList);
return S_OK;
}
INT_PTR CMailBoxProcess::_ChooseAppDialogProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
INT_PTR fHandled = TRUE; // handled
switch (wMsg)
{
case WM_INITDIALOG:
fHandled = _OnInitChooseApp(hDlg);
PropSheet_SetWizButtons(GetParent(hDlg), ((TRUE == m_fShowGetEmailAddressPage) ? (PSWIZB_BACK | PSWIZB_FINISH) : PSWIZB_FINISH));
break;
case WM_COMMAND:
fHandled = _OnCommand(wParam, lParam);
break;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
int idEvent = pnmh->code;
switch (idEvent)
{
case LVN_GETDISPINFOA:
_OnGetDispInfo((LV_DISPINFO *)lParam, false);
break;
case LVN_GETDISPINFOW:
_OnGetDispInfo((LV_DISPINFO *)lParam, true);
break;
case LVN_DELETEITEM:
if (lParam)
{
FreeEmailClient((EMAILCLIENT *) ((NM_LISTVIEW *)lParam)->lParam);
}
break;
case LVN_ITEMCHANGED:
_OnChooseAppListFocus();
_OnAppListSelection((LPNMLISTVIEW) lParam); // Keep track of the last selected item.
break;
case LVN_ITEMACTIVATE:
break;
case PSN_SETACTIVE:
PropSheet_SetWizButtons(GetParent(hDlg), (PSWIZB_BACK | PSWIZB_FINISH));
fHandled = TRUE; // Return zero to accept the activation.
break;
case PSN_WIZBACK:
// Set the prev. page to show
SetWindowLongPtr(hDlg, DWLP_MSGRESULT, (LONG_PTR) 0);
fHandled = -1;
break;
case PSN_WIZFINISH:
fHandled = _OnFinishedManualAssociate();
break;
case PSN_QUERYCANCEL:
m_hr = HRESULT_FROM_WIN32(ERROR_CANCELLED);
// TODO:
fHandled = FALSE;
break;
default:
//TraceMsg(TF_ALWAYS, "CMailBoxProcess::_ChooseAppDialogProc(wMsg = %d, pnmh->code = %d) WM_NOTIFY", wMsg, pnmh->code);
break;
}
break;
}
default:
fHandled = FALSE; // Not handled
//TraceMsg(TF_ALWAYS, "CMailBoxProcess::_ChooseAppDialogProc(wMsg = %d)", wMsg);
break;
}
return fHandled;
}
HRESULT CMailBoxProcess::_RestoreNextButton(void)
{
HWND hwndNextButton = GetDlgItem(GetParent(m_hwndDialog), IDD_WIZARD_NEXT_BUTTON);
if (hwndNextButton && m_szNextText[0])
{
SetWindowText(hwndNextButton, m_szNextText);
}
return S_OK;
}
INT_PTR CMailBoxProcess::_OnInit(HWND hDlg)
{
BOOL fHandled = FALSE; // Not handled
HWND hwndWizard = GetParent(hDlg);
TCHAR szSkipButton[MAX_PATH];
HWND hwndNextButton = GetDlgItem(GetParent(hDlg), IDD_WIZARD_NEXT_BUTTON);
m_hwndDialog = hDlg;
if (hwndNextButton &&
GetWindowText(hwndNextButton, m_szNextText, ARRAYSIZE(m_szNextText)))
{
// First, change the "Next" button into "Skip"
// Save the text on the next button before we rename it.
LoadString(HINST_THISDLL, IDS_SKIP_BUTTON, szSkipButton, ARRAYSIZE(szSkipButton));
// Set the next text.
SetWindowText(hwndNextButton, szSkipButton);
}
// Set Animation.
HWND hwndAnimation = GetDlgItem(hDlg, IDC_AUTODISCOVERY_ANIMATION);
if (hwndAnimation)
{
Animate_OpenEx(hwndAnimation, HINST_THISDLL, IDA_DOWNLOADINGSETTINGS);
}
// Start the background task.
m_hr = CMailAccountDiscovery_CreateInstance(NULL, IID_PPV_ARG(IMailAutoDiscovery, &m_pMailAutoDiscovery));
if (SUCCEEDED(m_hr))
{
m_hr = m_pMailAutoDiscovery->WorkAsync(hDlg, WM_AUTODISCOVERY_FINISHED);
if (SUCCEEDED(m_hr))
{
m_hr = m_pMailAutoDiscovery->DiscoverMail(m_szEmailAddress);
}
}
if (FAILED(m_hr))
{
PropSheet_PressButton(GetParent(hDlg), PSBTN_NEXT);
}
return fHandled;
}
INT_PTR CMailBoxProcess::_OnCommand(WPARAM wParam, LPARAM lParam)
{
BOOL fHandled = 1; // Not handled (WM_COMMAND seems to be different)
WORD wMsg = HIWORD(wParam);
WORD idCtrl = LOWORD(wParam);
switch (idCtrl)
{
case IDC_CHOOSEAPP_WEBURL_EDIT:
switch (wMsg)
{
case EN_SETFOCUS:
case STN_CLICKED:
_OnChooseAppURLFocus();
break;
default:
//TraceMsg(TF_ALWAYS, "in CMailBoxProcess::_OnCommand() wMsg=%#08lx, idCtrl=%#08lx", wMsg, idCtrl);
break;
}
break;
case IDC_CHOOSEAPP_WEB_RADIO:
switch (wMsg)
{
case BN_CLICKED:
_OnChooseAppURLFocus();
break;
default:
//TraceMsg(TF_ALWAYS, "in CMailBoxProcess::_OnCommand() wMsg=%#08lx, idCtrl=%#08lx", wMsg, idCtrl);
break;
}
break;
case IDC_CHOOSEAPP_OTHERAPP_RADIO:
switch (wMsg)
{
case BN_CLICKED:
_OnChooseAppListFocus();
break;
default:
//TraceMsg(TF_ALWAYS, "in CMailBoxProcess::_OnCommand() wMsg=%#08lx, idCtrl=%#08lx", wMsg, idCtrl);
break;
}
break;
default:
//TraceMsg(TF_ALWAYS, "in CMailBoxProcess::_OnCommand() wMsg=%#08lx, idCtrl=%#08lx", wMsg, idCtrl);
break;
}
return fHandled;
}
INT_PTR CMailBoxProcess::_OnInitChooseApp(HWND hDlg)
{
BOOL fHandled = FALSE; // Not handled
HWND hwndWizard = GetParent(hDlg);
HWND hwndURLEditbox = GetDlgItem(hDlg, IDC_CHOOSEAPP_WEBURL_EDIT);
m_hwndDialog = hDlg;
// TODO: 2) Handle someone changing the combox box.
LPCTSTR pszDomain = StrChr(m_szEmailAddress, CH_EMAIL_AT);
if (pszDomain)
{
TCHAR szDesc[MAX_URL_STRING];
pszDomain = CharNext(pszDomain); // Skip past the "@"
// Update the description on the dialog if the download failed.
if (m_fAutoDiscoveryFailed)
{
TCHAR szTemplate[MAX_URL_STRING];
LoadString(HINST_THISDLL, IDS_CHOOSEAPP_FAILED_RESULTS, szTemplate, ARRAYSIZE(szTemplate));
wnsprintf(szDesc, ARRAYSIZE(szDesc), szTemplate, pszDomain);
SetWindowText(GetDlgItem(hDlg, IDC_CHOOSEAPP_DESC), szDesc);
}
wnsprintf(szDesc, ARRAYSIZE(szDesc), TEXT("http://www.%s/"), pszDomain);
SetWindowText(hwndURLEditbox, szDesc);
}
// Populate the List of Apps
HWND hwndList = GetDlgItem(hDlg, IDC_CHOOSEAPP_APPLIST);
if (hwndList)
{
HIMAGELIST himlLarge;
HIMAGELIST himlSmall;
if (Shell_GetImageLists(&himlLarge, &himlSmall))
{
RECT rc;
LV_COLUMN col = {LVCF_FMT | LVCF_WIDTH, LVCFMT_LEFT};
ListView_SetImageList(hwndList, himlLarge, LVSIL_NORMAL);
ListView_SetImageList(hwndList, himlSmall, LVSIL_SMALL);
GetWindowRect(hwndList, &rc);
col.cx = rc.right - GetSystemMetrics(SM_CXVSCROLL) - (4 * GetSystemMetrics(SM_CXEDGE));
ListView_InsertColumn(hwndList, 0, &col);
_FillListWithApps(hwndList);
// TODO: 1) On select in the list, force "Other:" to be checked. 2) If editbox changes, set "Web:"
}
}
// Choose the Web Radio button because that will be the default.
// (Most email systems tend to use web based)
_OnChooseAppURLFocus();
Edit_SetSel(hwndURLEditbox, 0, -1);
return fHandled;
}
HRESULT _AddEmailClientToList(HWND hwndList, HKEY hkey, LPCTSTR pszMailApp, LPCTSTR pszFriendlyName)
{
TCHAR szPath[MAX_PATH];
HRESULT hr = EmailAssoc_GetAppPath(hkey, szPath, ARRAYSIZE(szPath));
if (SUCCEEDED(hr))
{
TCHAR szCmdLine[MAX_PATH];
hr = EmailAssoc_GetAppCmdLine(hkey, szCmdLine, ARRAYSIZE(szCmdLine));
if (SUCCEEDED(hr))
{
// Get the path we will use for the icon.
TCHAR szIconPath[MAX_PATH];
hr = EmailAssoc_GetIconPath(hkey, szIconPath, ARRAYSIZE(szIconPath));
if (SUCCEEDED(hr))
{
EMAILCLIENT * pEmailClient = (EMAILCLIENT *) LocalAlloc(LPTR, sizeof(*pEmailClient));
if (pEmailClient)
{
if (PathFileExists(szIconPath))
{
// TODO: Add a separate reg value for icon in the new case.
Str_SetPtr(&pEmailClient->pszIconPath, szIconPath);
}
// TODO: We may want to use the dll's version resource because it
// has a product description which may be localized.
Str_SetPtr(&pEmailClient->pszFriendlyName, pszFriendlyName);
Str_SetPtr(&pEmailClient->pszEmailApp, pszMailApp);
if (pEmailClient->pszFriendlyName)
{
Str_SetPtr(&pEmailClient->pszPath, szPath);
if (pEmailClient->pszPath)
{
if (szCmdLine[0])
{
Str_SetPtr(&pEmailClient->pszCmdLine, szCmdLine);
}
LV_ITEM item = {0};
item.mask = LVIF_TEXT | LVIF_IMAGE | LVIF_PARAM | LVIF_STATE;
item.iItem = INT_MAX;
item.iSubItem = 0;
item.state = 0;
item.iImage = I_IMAGECALLBACK;
item.pszText = pEmailClient->pszFriendlyName;
item.lParam = (LPARAM)pEmailClient;
if (-1 == ListView_InsertItem(hwndList, &item))
{
hr = E_FAIL;
}
}
}
else
{
hr = E_OUTOFMEMORY;
}
if (FAILED(hr))
{
FreeEmailClient(pEmailClient);
}
}
else
{
hr = E_OUTOFMEMORY;
}
}
}
}
return hr;
}
HRESULT CMailBoxProcess::_FillListWithApps(HWND hwndList)
{
HRESULT hr = S_OK;
HKEY hkey;
DWORD dwError = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SZ_REGKEY_MAILCLIENTS, 0, KEY_READ, &hkey);
hr = HRESULT_FROM_WIN32(dwError);
if (SUCCEEDED(hr))
{
TCHAR szFriendlyName[MAX_PATH];
TCHAR szKeyName[MAX_PATH];
TCHAR szCurrent[MAX_PATH]; // Nuke?
TCHAR szFriendlyCurrent[MAX_PATH];
FILETIME ftLastWriteTime;
DWORD nIndex; // Index counter
DWORD cb;
DWORD nSelected = 0;
// find the currently selected client
cb = sizeof(szCurrent);
dwError = RegQueryValueEx(hkey, NULL, NULL, NULL, (LPBYTE)szCurrent, &cb);
hr = HRESULT_FROM_WIN32(dwError);
if (FAILED(hr))
{
// if not found then blank the friendly name and keyname.
szCurrent[0] = 0;
szFriendlyCurrent[0] = 0;
}
// populate the list
for(nIndex = 0;
cb = ARRAYSIZE(szKeyName), dwError = RegEnumKeyEx(hkey, nIndex, szKeyName, &cb, NULL, NULL, NULL, &ftLastWriteTime), hr = HRESULT_FROM_WIN32(dwError), SUCCEEDED(hr);
nIndex++)
{
HKEY hkeyClient;
// get the friendly name of the client
dwError = RegOpenKeyEx(hkey, szKeyName, 0, KEY_READ, &hkeyClient);
hr = HRESULT_FROM_WIN32(dwError);
if (SUCCEEDED(hr))
{
cb = sizeof(szFriendlyName);
dwError = RegQueryValueEx(hkeyClient, NULL, NULL, NULL, (LPBYTE)szFriendlyName, &cb);
hr = HRESULT_FROM_WIN32(dwError);
if (SUCCEEDED(hr))
{
hr = _AddEmailClientToList(hwndList, hkeyClient, szKeyName, szFriendlyName);
// check to see if it's the current default
if (!StrCmp(szKeyName, szCurrent))
{
// save its the friendly name which we'll use later to
// select the current client and what index it is.
StrCpyN(szFriendlyCurrent, szFriendlyName, ARRAYSIZE(szFriendlyCurrent));
nSelected = nIndex;
}
}
// close key
RegCloseKey(hkeyClient);
}
} // for
// use a custom sort to delay the friendly names being used
// ListView_SortItems(hwndList, _CompareApps, 0);
// Lets select the appropriate entre.
ListView_SetItemState(hwndList, nSelected, LVNI_FOCUSED, LVNI_SELECTED);
// close the keys
RegCloseKey(hkey);
}
return hr;
}
HRESULT CMailBoxProcess::_OnGetDispInfo(LV_DISPINFO * pDispInfo, bool fUnicode)
{
HRESULT hr = S_OK;
if (pDispInfo && pDispInfo->item.mask & LVIF_IMAGE)
{
EMAILCLIENT * pEmailClient = (EMAILCLIENT *) pDispInfo->item.lParam;
if (pEmailClient)
{
pDispInfo->item.iImage = -1;
if (pEmailClient->pszIconPath)
{
pDispInfo->item.iImage = Shell_GetCachedImageIndex(pEmailClient->pszIconPath, 0, 0);
}
if (-1 == pDispInfo->item.iImage)
{
pDispInfo->item.iImage = Shell_GetCachedImageIndex(TEXT("shell32.dll"), II_APPLICATION, 0);
}
if (-1 != pDispInfo->item.iImage)
{
pDispInfo->item.mask = LVIF_IMAGE;
}
}
}
return hr;
}
INT_PTR CMailBoxProcess::_OnUserCancelled(void)
{
m_hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); // Means user cancelled
_RestoreNextButton();
return FALSE; // Not handled
}
INT_PTR CMailBoxProcess::_OnFinished(HRESULT hr, BSTR bstrXML)
{
SysFreeString(bstrXML);
_RestoreNextButton();
m_hr = hr; // whatever the success value was...
if (S_OK == m_hr)
{
// We succeeded so we can end the dialog
PropSheet_PressButton(GetParent(m_hwndDialog), PSBTN_FINISH);
}
else
{
// The results came back but we can't continue. So advance
// to the Choose App page.
m_fAutoDiscoveryFailed = TRUE;
PropSheet_PressButton(GetParent(m_hwndDialog), PSBTN_NEXT);
}
return TRUE; // handled
}
INT_PTR CALLBACK GetEmailAddressDialogProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
CMailBoxProcess * pMBProgress = (CMailBoxProcess *)GetWindowLongPtr(hDlg, DWLP_USER);
if (WM_INITDIALOG == wMsg)
{
PROPSHEETPAGE * pPropSheetPage = (PROPSHEETPAGE *) lParam;
if (pPropSheetPage)
{
SetWindowLongPtr(hDlg, DWLP_USER, pPropSheetPage->lParam);
pMBProgress = (CMailBoxProcess *)pPropSheetPage->lParam;
}
}
if (pMBProgress)
return pMBProgress->_GetEmailAddressDialogProc(hDlg, wMsg, wParam, lParam);
return DefWindowProc(hDlg, wMsg, wParam, lParam);
}
INT_PTR CMailBoxProcess::_GetEmailAddressDialogProc(HWND hDlg, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
INT_PTR fHandled = TRUE; // handled
switch (wMsg)
{
case WM_INITDIALOG:
m_hwndDialog = hDlg;
break;
case WM_NOTIFY:
{
LPNMHDR pnmh = (LPNMHDR)lParam;
switch (pnmh->code)
{
case PSN_SETACTIVE:
PropSheet_SetWizButtons(GetParent(hDlg), PSWIZB_NEXT);
fHandled = TRUE; // Return zero to accept the activation.
break;
case PSN_WIZNEXT:
fHandled = _OnGetEmailAddressNext();
break;
case PSN_QUERYCANCEL:
m_hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); // Means user cancelled
fHandled = FALSE;
break;
default:
//TraceMsg(TF_ALWAYS, "CMailBoxProcess::_MailBoxProgressDialogProc(wMsg = %d, pnmh->code = %d) WM_NOTIFY", wMsg, pnmh->code);
break;
}
}
default:
//TraceMsg(TF_ALWAYS, "CMailBoxProcess::_MailBoxProgressDialogProc(wMsg = %d) WM_NOTIFY", wMsg);
fHandled = FALSE; // Not handled
break;
}
return fHandled;
}
INT_PTR CMailBoxProcess::_OnGetEmailAddressNext(void)
{
BOOL fCancel = TRUE;
GetWindowText(GetDlgItem(m_hwndDialog, IDC_GETEMAILADDRESS_EDIT), m_szEmailAddress, ARRAYSIZE(m_szEmailAddress));
if (m_szEmailAddress[0] && StrChr(m_szEmailAddress, CH_EMAIL_AT))
{
// Looks valid to me.
fCancel = 0;
// TODO: Add more verification code
}
return fCancel; // 0 mean means allow it to close. TRUE means keep it open.
}
HRESULT CMailBoxProcess::_OpenEmailApp(void)
{
HKEY hkey;
HRESULT hr = EmailAssoc_OpenEmailAccount(m_szEmailAddress, &hkey);
if (SUCCEEDED(hr))
{
WCHAR wzPreferredApp[MAX_PATH];
// Did the user customize the app for this Email address? (Default is no)
hr = EmailAssoc_GetEmailAccountPreferredApp(hkey, wzPreferredApp, ARRAYSIZE(wzPreferredApp));
if (SUCCEEDED(hr))
{
// Yes, so let's launch that app.
hr = _OpenExeBasedEmailApp(wzPreferredApp);
}
else
{
WCHAR wzProtocol[MAX_PATH];
hr = EmailAssoc_GetEmailAccountProtocol(hkey, wzProtocol, ARRAYSIZE(wzProtocol));
if (SUCCEEDED(hr))
{
// No, but that's fine because it's the default.
if (!StrCmpIW(wzProtocol, SZ_REGDATA_WEB))
{
hr = _OpenWebBasedEmail(hkey);
}
else
{
hr = EmailAssoc_GetEmailAccountGetAppFromProtocol(wzProtocol, wzPreferredApp, ARRAYSIZE(wzPreferredApp));
if (SUCCEEDED(hr))
{
hr = _OpenExeBasedEmailApp(wzPreferredApp);
}
}
}
}
RegCloseKey(hkey);
}
return hr;
}
HRESULT CMailBoxProcess::_OpenWebBasedEmail(HKEY hkey)
{
WCHAR wzURL[MAX_URL_STRING];
HRESULT hr = EmailAssoc_GetEmailAccountWebURL(hkey, wzURL, ARRAYSIZE(wzURL));
if (0 == wzURL[0])
{
hr = E_FAIL;
}
if (SUCCEEDED(hr))
{
// TODO: In the future, we can get more information from get_PostHTML(). With
// that information, we can either:
// 1. Do an HTTP POST with header data that will simmulate logging into the server.
// This is good except that we need the password.
// 2. We can put form value/data pair information into an pidl created from the URL.
// We can then have the browser pull this information out and pre-populate form
// items. This will pre-populate the "User:" form item. This way the user
// only needs to enter their password.
hr = HrShellExecute(NULL, NULL, wzURL, NULL, NULL, SW_SHOW);
if (SUCCEEDED(hr))
{
AddEmailToAutoComplete(m_szEmailAddress);
}
}
return hr;
}
HRESULT CMailBoxProcess::_OpenExeBasedEmailApp(IN LPCWSTR pszMailApp)
{
HKEY hkey;
HRESULT hr = EmailAssoc_OpenMailApp(pszMailApp, &hkey);
// TODO: Call _InstallLegacyAssociations() to make sure the associations are correct.
if (SUCCEEDED(hr))
{
TCHAR szPath[MAX_URL_STRING];
hr = EmailAssoc_GetAppPath(hkey, szPath, ARRAYSIZE(szPath));
if (SUCCEEDED(hr))
{
TCHAR szCmdLine[MAX_URL_STRING];
szCmdLine[0] = 0;
if (SUCCEEDED(EmailAssoc_GetAppCmdLine(hkey, szCmdLine, ARRAYSIZE(szCmdLine))) && // optional
!StrStrI(SZ_TOKEN_EMAILADDRESS, szCmdLine))
{
// They have a cmdline and they want us to replace a token.
StrReplaceToken(SZ_TOKEN_EMAILADDRESS, m_szEmailAddress, szCmdLine, ARRAYSIZE(szCmdLine));
}
hr = HrShellExecute(NULL, NULL, szPath, (szCmdLine[0] ? szCmdLine : NULL), NULL, SW_SHOW);
if (SUCCEEDED(hr))
{
AddEmailToAutoComplete(m_szEmailAddress);
}
}
RegCloseKey(hkey);
}
return hr;
}
HRESULT CMailBoxProcess::_OpenProprietaryEmailApp(BSTR bstrProtocol, IMailProtocolADEntry * pMailProtocol)
{
HRESULT hr = E_FAIL;
// TODO:
MessageBox(NULL, TEXT("Open Proprietary Email App here. We look up in the registry for these types of apps. AOL, MSN, Compuserv are examples."), TEXT("Looser"), MB_OK);
return hr;
}
//===========================
// *** Public Methods ***
//===========================
HRESULT CMailBoxProcess::ParseCmdLine(LPTSTR pszCmdLine)
{
// We don't treat quote sections as blocks.
PathUnquoteSpaces(pszCmdLine);
while (pszCmdLine && pszCmdLine[0])
{
if (IsFlagSpecified(TEXT("email"), pszCmdLine))
{
pszCmdLine = GetNextArgument(pszCmdLine);
if (pszCmdLine)
{
if ((TEXT('/') == pszCmdLine[0]) || (TEXT('-') == pszCmdLine[0]))
{
}
else
{
LPTSTR pszEndOfEmailAddress = StrChr(pszCmdLine, TEXT(' '));
SIZE_T cchSizeToCopy = ARRAYSIZE(m_szEmailAddress);
if (pszEndOfEmailAddress && (cchSizeToCopy > (SIZE_T)(pszEndOfEmailAddress - pszCmdLine)))
{
cchSizeToCopy = (pszEndOfEmailAddress - pszCmdLine) + 1;
}
StrCpyN(m_szEmailAddress, pszCmdLine, (int)cchSizeToCopy);
pszCmdLine = GetNextArgument(pszCmdLine);
}
}
continue;
}
if (IsFlagSpecified(TEXT("GetDefaultAccount"), pszCmdLine))
{
pszCmdLine = GetNextArgument(pszCmdLine);
m_fGetDefaultAccount = TRUE;
continue;
}
if (IsFlagSpecified(TEXT("CreateNewEmailAccount"), pszCmdLine))
{
pszCmdLine = GetNextArgument(pszCmdLine);
m_fCreateNewEmailAccount = TRUE;
continue;
}
pszCmdLine = GetNextArgument(pszCmdLine);
}
return S_OK;
}
HRESULT CMailBoxProcess::Run(void)
{
HRESULT hr = CoInitialize(0);
if (SUCCEEDED(hr))
{
if (TRUE == m_fCreateNewEmailAccount)
{
// TODO: look in the registry for the default email account and
// copy it into m_szEmailAddress.
MessageBox(NULL, TEXT("Create New Email Account"), TEXT("TODO: Add code here."), MB_OK);
}
else
{
if (TRUE == m_fGetDefaultAccount)
{
// If the caller wants to use the default email address, then look in the registry
// for it and use that address.
if (FAILED(EmailAssoc_GetDefaultEmailAccount(m_szEmailAddress, ARRAYSIZE(m_szEmailAddress))))
{
m_szEmailAddress[0] = 0;
}
}
// Legacy email applications didn't install email associations, so we
// do that for them now.
EmailAssoc_InstallLegacyMailAppAssociations();
if (m_szEmailAddress[0])
{
// Since we know the email address, try to open it now.
// (We will see if the associations are installed)
hr = _OpenEmailApp();
}
else
{
hr = E_FAIL;
}
if (FAILED(hr))
{
hr = _DisplayDialogAndAutoDiscover();
if (SUCCEEDED(hr)) // If we got the protocol, then open the app
{
hr = _OpenEmailApp();
}
ATOMICRELEASE(m_pMailAutoDiscovery);
}
}
}
else
{
CoUninitialize();
}
return hr;
}
//===========================
// *** IUnknown Interface ***
//===========================
STDMETHODIMP CMailBoxProcess::QueryInterface(REFIID riid, LPVOID *ppvObj)
{
static const QITAB qit[] =
{
QITABENT(CMailBoxProcess, IUnknown),
{ 0 },
};
return QISearch(this, qit, riid, ppvObj);
}
STDMETHODIMP_(DWORD) CMailBoxProcess::AddRef()
{
return ++m_cRef;
}
STDMETHODIMP_(DWORD) CMailBoxProcess::Release()
{
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
//===========================
// *** Class Methods ***
//===========================
CMailBoxProcess::CMailBoxProcess()
{
DllAddRef();
m_szNextText[0] = 0;
m_szEmailAddress[0] = 0;
m_fAutoDiscoveryFailed = FALSE;
m_hwndDialog = NULL;
m_pMailAutoDiscovery = NULL;
m_pszMailApp = NULL;
m_pszURL = NULL;
m_fGetDefaultAccount = FALSE;
m_fShowGetEmailAddressPage = FALSE;
m_fCreateNewEmailAccount = FALSE;
_InitComCtl32(); // So we can use the ICC_ANIMATE_CLASS common controls.
m_cRef = 1;
}
CMailBoxProcess::~CMailBoxProcess()
{
ATOMICRELEASE(m_pMailAutoDiscovery);
Str_SetPtr(&m_pszMailApp, NULL);
Str_SetPtr(&m_pszURL, NULL);
DllRelease();
}
//===========================
// *** Non-Class Functons ***
//===========================
int AutoDiscoverAndOpenEmail(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
TCHAR szCmdLine[MAX_EMAIL_ADDRESSS];
szCmdLine[0] = 0;
if (lpCmdLine)
{
// TODO: Either support Unicode or tounel thru UTF8
SHAnsiToTChar((LPCSTR)lpCmdLine, szCmdLine, ARRAYSIZE(szCmdLine));
}
CMailBoxProcess mailboxProcess;
if (SUCCEEDED(mailboxProcess.ParseCmdLine(szCmdLine)))
{
mailboxProcess.Run();
}
return 0;
}
#else // FEATURE_MAILBOX
int AutoDiscoverAndOpenEmail(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow)
{
return 0;
}
#endif // FEATURE_MAILBOX