/*****************************************************************************\ FILE: AutoDiscovery.cpp DESCRIPTION: This is AutoDiscovery progress UI for the Outlook Express's email configuration wizard. BryanSt 1/18/2000 Copyright (C) Microsoft Corp 2000-2000. All rights reserved. \*****************************************************************************/ #include "pch.hxx" #include #include #include #include #include "icwwiz.h" #include "acctui.h" #include "acctman.h" #include #include #include "server.h" #include "connect.h" #include #include "shlwapip.h" #include "strconst.h" #include "demand.h" #include "hotwiz.h" #include "shared.h" #include #include "AutoDiscoveryUI.h" ASSERTDATA #define RECTWIDTH(rect) (rect.right - rect.left) #define RECTHEIGHT(rect) (rect.bottom - rect.top) #define MAX_URL_STRING 2048 #define SIZE_STR_AUTODISC_DESC 2048 // 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 #define SZ_DLL_AUTODISC TEXT("autodisc.dll") #define IDA_DOWNLOADINGSETTINGS 801 // In autodisc.dll #define ATOMICRELEASE(punk) {if (punk) { punk->Release(); punk = NULL;} } WCHAR g_szInfoURL[MAX_URL_STRING] = {0}; WCHAR g_szWebMailURL[MAX_URL_STRING] = {0}; typedef struct { // Default Protocol (POP3, IMAP, DAV, WEB) int nProtocol; // What is the email protocol? POP3 vs. IMAP vs. DAV vs. WEB BSTR bstrDisplayName; // What is the user's display name. BSTR bstrServer1Name; // What is the downloading email server name (POP3, IMAP, DAV, or WEB) int nServer1Port; // What is that server's port number? BSTR bstrLoginName; // What is the login name for the POP3 server. (Normall the same as the email address w/out the domain) BOOL fUsesSSL; // Use SSL when connecting to the POP3 or IMAP server? BOOL fUsesSPA; // Use SPA when connecting to the POP3 or IMAP server? // SMTP Protocol (If used) BSTR bstrServer2Name; // What is the uploading email server name (SMTP) int nServer2Port; // What is that server's port number? BOOL fSMTPUsesSSL; // Use SSL when connecting to the SMTP server? BOOL fAuthSMTP; // Does SMTP need Authentication? BOOL fAuthSMTPPOP; // Use POP3's auth for SMTP? BOOL fAuthSMTPSPA; // Use SPA auth for SMTP? BOOL fUseWebMail; // Is Web Bassed mail the only protocol we recognizer? BSTR bstrSMTPLoginName; // What is the login name for the SMTP server. BOOL fDisplayInfoURL; // Is there an URL for Info about the email server/services? BSTR bstrInfoURL; // If fDisplayInfoURL, this is the URL. } EMAIL_SERVER_SETTINGS; class CICWApprentice; /*****************************************************************************\ Class: CAutoDiscoveryHelper DESCRIPTION: StartAutoDiscovery: hwndParent: This is the caller's hwnd. If we need to display UI, we will parent it off this hwnd. We also send this hwnd messages on progress. \*****************************************************************************/ class CAutoDiscoveryHelper { public: // Public Methods HRESULT StartAutoDiscovery(IN CICWApprentice *pApp, IN HWND hDlg, IN BOOL fFirstInit); HRESULT OnCompleted(IN CICWApprentice *pApp, IN ACCTDATA * pData); HRESULT SetNextButton(HWND hwndButton); HRESULT RestoreNextButton(HWND hwndButton); CAutoDiscoveryHelper(); ~CAutoDiscoveryHelper(void); private: // Private Member Variables // Other internal state. HWND _hwndDlgParent; // parent window for message boxes TCHAR _szNextText[MAX_PATH]; // IMailAutoDiscovery * _pMailAutoDiscovery; // HINSTANCE _hInstAutoDisc; // We use this to get the animation // Private Member Functions HRESULT _GetAccountInformation(EMAIL_SERVER_SETTINGS * pEmailServerSettings); }; CAutoDiscoveryHelper * g_pAutoDiscoveryObject = NULL; // This is the AutoDisc obj used while downloading the settings. BOOL g_fRequestCancelled = TRUE; UINT g_uNextPage = ORD_PAGE_AD_MAILNAME; // ORD_PAGE_AD_MAILNAME, ORD_PAGE_AD_MAILSERVER, ORD_PAGE_AD_USEWEBMAIL, ORD_PAGE_AD_GOTOSERVERINFO //=========================== // *** Class Internals & Helpers *** //=========================== HRESULT FreeEmailServerSettings(EMAIL_SERVER_SETTINGS * pEmailServerSettings) { SysFreeString(pEmailServerSettings->bstrDisplayName); // It's okay to pass NULL to this API SysFreeString(pEmailServerSettings->bstrServer1Name); SysFreeString(pEmailServerSettings->bstrLoginName); SysFreeString(pEmailServerSettings->bstrServer2Name); SysFreeString(pEmailServerSettings->bstrSMTPLoginName); SysFreeString(pEmailServerSettings->bstrInfoURL); return S_OK; } BSTR SysAllocStringA(LPCSTR pszStr) { BSTR bstrOut = NULL; if (pszStr) { DWORD cchSize = (lstrlenA(pszStr) + 1); LPWSTR pwszThunkTemp = (LPWSTR) LocalAlloc(LPTR, (sizeof(pwszThunkTemp[0]) * cchSize)); // assumes INFOTIPSIZE number of chars max if (pwszThunkTemp) { SHAnsiToUnicode(pszStr, pwszThunkTemp, cchSize); bstrOut = SysAllocString(pwszThunkTemp); LocalFree(pwszThunkTemp); } } return bstrOut; } HRESULT ADRestoreNextButton(CICWApprentice *pApp, HWND hDlg) { HRESULT hr = S_OK; g_fRequestCancelled = TRUE; if (g_pAutoDiscoveryObject) { g_pAutoDiscoveryObject->RestoreNextButton(GetDlgItem(GetParent(hDlg), IDD_WIZARD_NEXT_BUTTON)); delete g_pAutoDiscoveryObject; g_pAutoDiscoveryObject = NULL; } return hr; } HRESULT CreateAccountName(IN CICWApprentice *pApp, IN ACCTDATA * pData); HRESULT OnADCompleted(CICWApprentice *pApp, HWND hDlg) { HRESULT hr = E_OUTOFMEMORY; if (g_pAutoDiscoveryObject) { ACCTDATA * pData = pApp->GetAccountData(); hr = g_pAutoDiscoveryObject->OnCompleted(pApp, pData); if (SUCCEEDED(hr)) { // Set the display name for the account. CreateAccountName(pApp, pData); } else { // TODO: If _fUseWebMail is set, we will probably want // to navigate to a page telling the user to use a web // page to get their email. } } return hr; } #define SZ_HOTMAILDOMAIN "@hotmail.com" #define CH_EMAILDOMAINSEPARATOR '@' HRESULT CAutoDiscoveryHelper::StartAutoDiscovery(IN CICWApprentice *pApp, IN HWND hDlg, IN BOOL fFirstInit) { HRESULT hr = E_OUTOFMEMORY; ACCTDATA * pData = pApp->GetAccountData(); if (pData && pData->szEmail) { LPCSTR pszEmailDomain = StrChrA(pData->szEmail, CH_EMAILDOMAINSEPARATOR); if (pszEmailDomain && !StrCmpI(SZ_HOTMAILDOMAIN, pszEmailDomain)) // Is this a HOTMAIL.COM account? { // Yes, so skip AutoDiscovery since we don't require the user // to enter hard settings in that case. (Protocol and server settings never // change) hr = HRESULT_FROM_WIN32(ERROR_CANCELLED); } else { WCHAR szEmail[1024]; SHAnsiToUnicode(pData->szEmail, szEmail, ARRAYSIZE(szEmail)); _hwndDlgParent = hDlg; // Set Animation. HWND hwndAnimation = GetDlgItem(hDlg, IDC_AUTODISCOVERY_ANIMATION); if (hwndAnimation) { _hInstAutoDisc = LoadLibrary(SZ_DLL_AUTODISC); if (_hInstAutoDisc) { Animate_OpenEx(hwndAnimation, _hInstAutoDisc, IDA_DOWNLOADINGSETTINGS); } } HWND hwndWizard = GetParent(hDlg); if (hwndWizard) { SetNextButton(GetDlgItem(hwndWizard, IDD_WIZARD_NEXT_BUTTON)); } ATOMICRELEASE(_pMailAutoDiscovery); // Start the background task. hr = CoCreateInstance(CLSID_MailAutoDiscovery, NULL, CLSCTX_INPROC_SERVER, IID_IMailAutoDiscovery, (void **)&_pMailAutoDiscovery); if (SUCCEEDED(hr)) { hr = _pMailAutoDiscovery->WorkAsync(hDlg, WM_AUTODISCOVERY_FINISHED); if (SUCCEEDED(hr)) { BSTR bstrEmail = SysAllocString(szEmail); if (bstrEmail) { hr = _pMailAutoDiscovery->DiscoverMail(bstrEmail); if (SUCCEEDED(hr)) { g_fRequestCancelled = FALSE; } SysFreeString(bstrEmail); } else { hr = E_OUTOFMEMORY; } } } } } else { hr = E_FAIL; } if (FAILED(hr)) { PropSheet_PressButton(GetParent(hDlg), PSBTN_NEXT); } return hr; } HRESULT CAutoDiscoveryHelper::SetNextButton(HWND hwndButton) { HRESULT hr = S_OK; TCHAR szSkipButton[MAX_PATH]; // First, change the "Next" button into "Skip" // Save the text on the next button before we rename it. if (hwndButton && !GetWindowText(hwndButton, _szNextText, ARRAYSIZE(_szNextText))) { _szNextText[0] = 0; // terminate string in failure case. } // Set the next text. LoadString(g_hInstRes, idsADSkipButton, szSkipButton, ARRAYSIZE(szSkipButton)); SetWindowText(hwndButton, szSkipButton); return hr; } HRESULT CAutoDiscoveryHelper::RestoreNextButton(HWND hwndButton) { HRESULT hr = S_OK; if (_szNextText[0]) { // Restore the Next button text. SetWindowText(hwndButton, _szNextText); } return hr; } /****************************************************\ DESCRIPTION: \****************************************************/ HRESULT CAutoDiscoveryHelper::OnCompleted(IN CICWApprentice *pApp, IN ACCTDATA *pData) { // Step 1. Get all the settings from IMailAutoDiscovery to EMAIL_SERVER_SETTINGS EMAIL_SERVER_SETTINGS emailServerSettings = {0}; emailServerSettings.nProtocol = -1; emailServerSettings.nServer1Port = -1; emailServerSettings.nServer2Port = -1; HRESULT hr = _GetAccountInformation(&emailServerSettings); g_uNextPage = ORD_PAGE_AD_MAILSERVER; // Assume we fail and we need to ask for the server settings. // Did the AutoDiscovery process succeed? if (SUCCEEDED(hr)) { if (emailServerSettings.fDisplayInfoURL) { g_uNextPage = ORD_PAGE_AD_GOTOSERVERINFO; StrCpyNW(g_szInfoURL, emailServerSettings.bstrInfoURL, ARRAYSIZE(g_szInfoURL)); } else if (emailServerSettings.fUseWebMail) { g_uNextPage = ORD_PAGE_AD_USEWEBMAIL; StrCpyNW(g_szWebMailURL, emailServerSettings.bstrServer1Name, ARRAYSIZE(g_szWebMailURL)); } else { g_uNextPage = ORD_PAGE_AD_MAILNAME; if (pApp && pData && pApp->m_pAcct) { // Step 2. Move all the settings from EMAIL_SERVER_SETTINGS to the OE mail account (ACCTDATA). IImnAccount * pAcct = pApp->m_pAcct; pData->fLogon = FALSE; // BUGBUG: When is this needed? DAV? pData->fSPA = emailServerSettings.fUsesSPA; pData->fServerTypes = emailServerSettings.nProtocol; Assert(!pData->fCreateNewAccount); if (emailServerSettings.bstrDisplayName) { SHUnicodeToAnsi(emailServerSettings.bstrDisplayName, pData->szName, ARRAYSIZE(pData->szName)); } if (emailServerSettings.bstrServer1Name) { SHUnicodeToAnsi(emailServerSettings.bstrServer1Name, pData->szSvr1, ARRAYSIZE(pData->szSvr1)); } if (emailServerSettings.bstrLoginName) { SHUnicodeToAnsi(emailServerSettings.bstrLoginName, pData->szUsername, ARRAYSIZE(pData->szUsername)); } if (emailServerSettings.nProtocol & (SRV_POP3 | SRV_IMAP)) { pAcct->SetPropDw(((emailServerSettings.nProtocol & SRV_POP3) ? AP_POP3_SSL : AP_IMAP_SSL), emailServerSettings.fUsesSSL); if (-1 != emailServerSettings.nServer1Port) { pAcct->SetPropDw(((emailServerSettings.nProtocol & SRV_POP3) ? AP_POP3_PORT : AP_IMAP_PORT), emailServerSettings.nServer1Port); } } if (emailServerSettings.nProtocol & SRV_SMTP) { if (emailServerSettings.bstrServer2Name) { SHUnicodeToAnsi(emailServerSettings.bstrServer2Name, pData->szSvr2, ARRAYSIZE(pData->szSvr2)); } if (-1 != emailServerSettings.nServer2Port) { pAcct->SetPropDw(AP_SMTP_PORT, emailServerSettings.nServer2Port); } pAcct->SetPropDw(AP_SMTP_SSL, emailServerSettings.fSMTPUsesSSL); if (!emailServerSettings.fAuthSMTP) { pAcct->SetPropDw(AP_SMTP_USE_SICILY, SMTP_AUTH_NONE); } else { if (emailServerSettings.fAuthSMTPPOP) { pAcct->SetPropDw(AP_SMTP_USE_SICILY, SMTP_AUTH_USE_POP3ORIMAP_SETTINGS); } else { if (emailServerSettings.fAuthSMTPSPA) { pAcct->SetPropDw(AP_SMTP_USE_SICILY, SMTP_AUTH_SICILY); } else { pAcct->SetPropDw(AP_SMTP_USE_SICILY, SMTP_AUTH_USE_SMTP_SETTINGS); } if (emailServerSettings.bstrSMTPLoginName) { TCHAR szSMTPUserName[CCHMAX_ACCT_PROP_SZ]; WideCharToMultiByte(CP_ACP, 0, emailServerSettings.bstrSMTPLoginName, -1, szSMTPUserName, ARRAYSIZE(szSMTPUserName), NULL, NULL); pAcct->SetPropSz(AP_SMTP_USERNAME, szSMTPUserName); } pAcct->SetPropDw(AP_SMTP_PROMPT_PASSWORD, TRUE); } } } } } // Step 3. Free all the memory in EMAIL_SERVER_SETTINGS FreeEmailServerSettings(&emailServerSettings); } return hr; } /****************************************************\ DESCRIPTION: \****************************************************/ HRESULT CAutoDiscoveryHelper::_GetAccountInformation(EMAIL_SERVER_SETTINGS * pEmailServerSettings) { BSTR bstrPreferedProtocol; HRESULT hr = S_OK; // We ignore hr because getting the display name is optinal. _pMailAutoDiscovery->get_DisplayName(&pEmailServerSettings->bstrDisplayName); hr = _pMailAutoDiscovery->get_PreferedProtocolType(&bstrPreferedProtocol); // Loop thru the list looking for the first instance of a protocol // that we support. if (StrCmpIW(bstrPreferedProtocol, STR_PT_POP) && StrCmpIW(bstrPreferedProtocol, STR_PT_IMAP) && StrCmpIW(bstrPreferedProtocol, STR_PT_DAVMAIL)) { long nSize; hr = _pMailAutoDiscovery->get_length(&nSize); if (SUCCEEDED(hr)) { VARIANT varIndex; varIndex.vt = VT_I4; SysFreeString(bstrPreferedProtocol); for (long nIndex = 1; (nIndex < nSize); nIndex++) { IMailProtocolADEntry * pMailProtocol; varIndex.lVal = nIndex; if (SUCCEEDED(_pMailAutoDiscovery->get_item(varIndex, &pMailProtocol))) { hr = pMailProtocol->get_Protocol(&bstrPreferedProtocol); pMailProtocol->Release(); pMailProtocol = NULL; if (SUCCEEDED(hr)) { // Is this protocol one of the ones we support? if (!StrCmpIW(bstrPreferedProtocol, STR_PT_POP) || !StrCmpIW(bstrPreferedProtocol, STR_PT_IMAP) || !StrCmpIW(bstrPreferedProtocol, STR_PT_DAVMAIL)) { hr = S_OK; break; } SysFreeString(bstrPreferedProtocol); bstrPreferedProtocol = NULL; } } } } } // TODO: Handle the Web Based mail case. if (!StrCmpIW(bstrPreferedProtocol, STR_PT_POP)) pEmailServerSettings->nProtocol = (SRV_POP3 | SRV_SMTP); else if (!StrCmpIW(bstrPreferedProtocol, STR_PT_IMAP)) pEmailServerSettings->nProtocol = (SRV_IMAP | SRV_SMTP); else if (!StrCmpIW(bstrPreferedProtocol, STR_PT_DAVMAIL)) pEmailServerSettings->nProtocol = SRV_HTTPMAIL; // We need to reject Web Base Mail. In the future, we may want to give a page // for them to launch the web browser to read their mail. if (SUCCEEDED(hr) && bstrPreferedProtocol && (!StrCmpIW(bstrPreferedProtocol, STR_PT_POP) || !StrCmpIW(bstrPreferedProtocol, STR_PT_IMAP) || !StrCmpIW(bstrPreferedProtocol, STR_PT_DAVMAIL))) { VARIANT varIndex; IMailProtocolADEntry * pMailProtocol; varIndex.vt = VT_BSTR; varIndex.bstrVal = bstrPreferedProtocol; hr = _pMailAutoDiscovery->get_item(varIndex, &pMailProtocol); if (SUCCEEDED(hr)) { hr = pMailProtocol->get_ServerName(&pEmailServerSettings->bstrServer1Name); if (SUCCEEDED(hr)) { BSTR bstrPortNum; // Having a custom port number is optional. if (SUCCEEDED(pMailProtocol->get_ServerPort(&bstrPortNum))) { pEmailServerSettings->nServer1Port = StrToIntW(bstrPortNum); SysFreeString(bstrPortNum); } if (SUCCEEDED(hr)) { VARIANT_BOOL vfSPA = VARIANT_FALSE; if (SUCCEEDED(pMailProtocol->get_UseSPA(&vfSPA))) { pEmailServerSettings->fUsesSPA = (VARIANT_TRUE == vfSPA); } pMailProtocol->get_LoginName(&pEmailServerSettings->bstrLoginName); } VARIANT_BOOL vfSSL = VARIANT_FALSE; if (SUCCEEDED(pMailProtocol->get_UseSSL(&vfSSL))) { pEmailServerSettings->fUsesSSL = (VARIANT_TRUE == vfSSL); } } pMailProtocol->Release(); } // Is this one of the protocols that requires a second server? if (!StrCmpIW(bstrPreferedProtocol, STR_PT_POP) || !StrCmpIW(bstrPreferedProtocol, STR_PT_IMAP)) { varIndex.bstrVal = STR_PT_SMTP; hr = _pMailAutoDiscovery->get_item(varIndex, &pMailProtocol); if (SUCCEEDED(hr)) { hr = pMailProtocol->get_ServerName(&pEmailServerSettings->bstrServer2Name); if (SUCCEEDED(hr)) { BSTR bstrPortNum; // Having a custom port number is optional. if (SUCCEEDED(pMailProtocol->get_ServerPort(&bstrPortNum))) { pEmailServerSettings->nServer2Port = StrToIntW(bstrPortNum); SysFreeString(bstrPortNum); } // TODO: Read in _fAuthSMTP and _fAuthSMTPPOP VARIANT_BOOL vfSPA = VARIANT_FALSE; if (SUCCEEDED(pMailProtocol->get_UseSPA(&vfSPA))) { pEmailServerSettings->fAuthSMTPSPA = (VARIANT_TRUE == vfSPA); } VARIANT_BOOL vfAuthSMTP = VARIANT_FALSE; if (SUCCEEDED(pMailProtocol->get_IsAuthRequired(&vfAuthSMTP))) { pEmailServerSettings->fAuthSMTP = (VARIANT_TRUE == vfAuthSMTP); } VARIANT_BOOL vfAuthFromPOP = VARIANT_FALSE; if (SUCCEEDED(pMailProtocol->get_SMTPUsesPOP3Auth(&vfAuthFromPOP))) { pEmailServerSettings->fAuthSMTPPOP = (VARIANT_TRUE == vfAuthFromPOP); } VARIANT_BOOL vfSSL = VARIANT_FALSE; if (SUCCEEDED(pMailProtocol->get_UseSSL(&vfSSL))) { pEmailServerSettings->fSMTPUsesSSL = (VARIANT_TRUE == vfSSL); } pMailProtocol->get_LoginName(&pEmailServerSettings->bstrSMTPLoginName); } pMailProtocol->Release(); } } SysFreeString(bstrPreferedProtocol); } if (SUCCEEDED(hr) && (-1 == pEmailServerSettings->nProtocol)) { hr = E_FAIL; } if (FAILED(hr) && (-1 == pEmailServerSettings->nProtocol)) { // Does this email account work with web based email? VARIANT varIndex; varIndex.vt = VT_BSTR; varIndex.bstrVal = SysAllocString(STR_PT_WEBBASED); if (varIndex.bstrVal) { IMailProtocolADEntry * pMailProtocol; if (SUCCEEDED(_pMailAutoDiscovery->get_item(varIndex, &pMailProtocol))) { // Yes, web bases mail is supported. So remember that for later. pEmailServerSettings->fUseWebMail = TRUE; hr = pMailProtocol->get_ServerName(&pEmailServerSettings->bstrServer1Name); pMailProtocol->Release(); } VariantClear(&varIndex); } } if (FAILED(hr) && (-1 == pEmailServerSettings->nProtocol)) { // Did the server provide an INFO URL for the user? hr = _pMailAutoDiscovery->get_InfoURL(&pEmailServerSettings->bstrInfoURL); if (SUCCEEDED(hr)) { pEmailServerSettings->fDisplayInfoURL = TRUE; } } return hr; } /****************************************************\ Constructor \****************************************************/ CAutoDiscoveryHelper::CAutoDiscoveryHelper() { DllAddRef(); // ASSERT zero initialized because we can only be created in the heap. (Private destructor) _hwndDlgParent = NULL; _szNextText[0] = 0; _pMailAutoDiscovery = NULL; _hInstAutoDisc = NULL; } /****************************************************\ Destructor \****************************************************/ CAutoDiscoveryHelper::~CAutoDiscoveryHelper() { if (_pMailAutoDiscovery) { _pMailAutoDiscovery->Release(); _pMailAutoDiscovery = NULL; } if (_hInstAutoDisc) { FreeLibrary(_hInstAutoDisc); } DllRelease(); } //=========================== // *** Public APIs *** //=========================== BOOL CALLBACK AutoDiscoveryInitProc(CICWApprentice *pApp, HWND hDlg, BOOL fFirstInit) { if (fFirstInit) { g_fRequestCancelled = TRUE; g_uNextPage = ORD_PAGE_AD_MAILSERVER; // Assume we fail and we need to ask for the server settings. } if (!g_pAutoDiscoveryObject) { Assert(!g_pAutoDiscoveryObject); g_pAutoDiscoveryObject = new CAutoDiscoveryHelper(); if (g_pAutoDiscoveryObject) { g_pAutoDiscoveryObject->StartAutoDiscovery(pApp, hDlg, fFirstInit); } } return TRUE; } BOOL CALLBACK AutoDiscoveryOKProc(CICWApprentice *pApp, HWND hDlg, BOOL fForward, UINT *puNextPage) { g_fRequestCancelled = TRUE; if (fForward) { *puNextPage = g_uNextPage; } else { // If we have the passifier page turned off, we want to skip that page. if (!SHRegGetBoolUSValue(SZ_REGKEY_AUTODISCOVERY, SZ_REGVALUE_AUTODISCOVERY_PASSIFIER, FALSE, TRUE)) { *puNextPage = ORD_PAGE_AD_MAILADDRESS; } } ADRestoreNextButton(pApp, hDlg); g_uNextPage = ORD_PAGE_AD_MAILSERVER; // Assume we fail and we need to ask for the server settings. return(TRUE); } BOOL CALLBACK AutoDiscoveryCmdProc(CICWApprentice *pApp, HWND hDlg, WPARAM wParam, LPARAM lParam) { return(TRUE); } BOOL CALLBACK AutoDiscoveryWMUserProc(CICWApprentice *pApp, HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_AUTODISCOVERY_FINISHED: if (FALSE == g_fRequestCancelled) { // This is WM_AUTODISCOVERY_FINISHED BSTR bstXML = (BSTR) lParam; HRESULT hrAutoDiscoverySucceeded = (HRESULT) wParam; if (bstXML) { SysFreeString(bstXML); // We don't need the XML. This works if NULL } if (SUCCEEDED(hrAutoDiscoverySucceeded)) { OnADCompleted(pApp, hDlg); } // Go to the next page. ADRestoreNextButton(pApp, hDlg); PropSheet_PressButton(GetParent(hDlg), PSBTN_NEXT); } break; case WM_AUTODISCOVERY_STATUSMSG: { // This is WM_AUTODISCOVERY_STATUSMSG LPWSTR pwzStatusMsg = (BSTR) wParam; if (pwzStatusMsg) { HWND hwndStatusText = GetDlgItem(hDlg, IDC_AUTODISCOVERY_STATUS); if (hwndStatusText) { SetWindowTextW(hwndStatusText, pwzStatusMsg); } LocalFree(pwzStatusMsg); } } break; } return(TRUE); } BOOL CALLBACK AutoDiscoveryCancelProc(CICWApprentice *pApp, HWND hDlg) { // This call will clean up our state and retore the back button. ADRestoreNextButton(pApp, hDlg); g_uNextPage = ORD_PAGE_AD_MAILSERVER; // Assume we fail and we need to ask for the server settings. return TRUE; } typedef BOOL (* PFN_LINKWINDOW_REGISTERCLASS) (void); typedef BOOL (* PFN_LINKWINDOW_UNREGISTERCLASS) (IN HINSTANCE hInst); #define ORD_LINKWINDOW_REGISTERCLASS 258 #define ORD_LINKWINDOW_UNREGISTERCLASS 259 BOOL LinkWindow_RegisterClass_DelayLoad(void) { BOOL returnValue = FALSE; // Delay load the SHELL32.DLL export (ordinal #258). This only works on Win2k and later. HINSTANCE hInstSHELL32 = LoadLibrary(TEXT("SHELL32.DLL")); if (hInstSHELL32) { PFN_LINKWINDOW_REGISTERCLASS pfnDelayLoad = (PFN_LINKWINDOW_REGISTERCLASS)GetProcAddress(hInstSHELL32, (LPCSTR)ORD_LINKWINDOW_REGISTERCLASS); if (pfnDelayLoad) { returnValue = pfnDelayLoad(); } FreeLibrary(hInstSHELL32); } return returnValue; } void LinkWindow_UnregisterClass_DelayLoad(IN HINSTANCE hInst) { // Delay load the SHELL32.DLL export (ordinal #259). This only works on Win2k and later. HINSTANCE hInstSHELL32 = LoadLibrary(TEXT("SHELL32.DLL")); if (hInstSHELL32) { PFN_LINKWINDOW_UNREGISTERCLASS pfnDelayLoad = (PFN_LINKWINDOW_UNREGISTERCLASS)GetProcAddress(hInstSHELL32, (LPCSTR)ORD_LINKWINDOW_UNREGISTERCLASS); if (pfnDelayLoad) { BOOL returnValue = pfnDelayLoad(hInst); } FreeLibrary(hInstSHELL32); } } #define LINKWINDOW_CLASSW L"Link Window" BOOL IsOSNT(void) { OSVERSIONINFOA osVerInfoA; osVerInfoA.dwOSVersionInfoSize = sizeof(osVerInfoA); if (!GetVersionExA(&osVerInfoA)) return VER_PLATFORM_WIN32_WINDOWS; // Default to this. return (VER_PLATFORM_WIN32_NT == osVerInfoA.dwPlatformId); } DWORD GetOSVer(void) { OSVERSIONINFOA osVerInfoA; osVerInfoA.dwOSVersionInfoSize = sizeof(osVerInfoA); if (!GetVersionExA(&osVerInfoA)) return VER_PLATFORM_WIN32_WINDOWS; // Default to this. return osVerInfoA.dwMajorVersion; } HRESULT ConvertTextToLinkWindow(HWND hDlg, int idControl, int idStringID) { WCHAR szTempString[MAX_URL_STRING]; HRESULT hr = S_OK; HWND hwndText = GetDlgItem(hDlg, idControl); RECT rcWindow; HMENU hMenu = (HMENU)IntToPtr(idControl + 10); LoadStringW(g_hInstRes, idStringID, szTempString, ARRAYSIZE(szTempString)); GetClientRect(hwndText, &rcWindow); MapWindowPoints(hwndText, hDlg, (POINT*)&rcWindow, 2); HWND hwndLink = CreateWindowW(LINKWINDOW_CLASSW, szTempString, (WS_TABSTOP | WS_CHILDWINDOW), rcWindow.left, rcWindow.top, RECTWIDTH(rcWindow), RECTHEIGHT(rcWindow), hDlg, hMenu, g_hInstRes, NULL); DWORD dwError = GetLastError(); //todo; if (hwndLink) { SetWindowTextW(hwndLink, szTempString); ShowWindow(hwndLink, SW_SHOW); } EnableWindow(hwndText, FALSE); ShowWindow(hwndText, SW_HIDE); return hr; } HRESULT GetEmailAddress(CICWApprentice *pApp, LPSTR pszEmailAddress, int cchSize) { ACCTDATA * pData = pApp->GetAccountData(); StrCpyNA(pszEmailAddress, "", cchSize); // Initialize the string to empty. if (pData && pData->szEmail) { StrCpyNA(pszEmailAddress, pData->szEmail, cchSize); // Initialize the string to empty. } return S_OK; } HRESULT GetEmailAddressDomain(CICWApprentice *pApp, LPSTR pszEmailAddress, int cchSize) { ACCTDATA * pData = pApp->GetAccountData(); StrCpyNA(pszEmailAddress, "", cchSize); // Initialize the string to empty. if (pData && pData->szEmail) { LPCSTR pszEmailDomain = StrChrA(pData->szEmail, CH_EMAILDOMAINSEPARATOR); if (pszEmailDomain) { StrCpyNA(pszEmailAddress, CharNext(pszEmailDomain), cchSize); // Initialize the string to empty. } } return S_OK; } BOOL CALLBACK TheInitProc(CICWApprentice *pApp, HWND hDlg, BOOL fFirstInit, int idControlFirst, LPWSTR pszURL, int cchURLSize) { BOOL fReset = fFirstInit; if (!fReset) { WCHAR szPreviousURL[MAX_URL_STRING]; GetWindowTextW(GetDlgItem(hDlg, idControlFirst+1), szPreviousURL, ARRAYSIZE(szPreviousURL)); // If the URL has changed, we need to reload the info. if (StrCmpIW(pszURL, szPreviousURL)) { DestroyWindow(GetDlgItem(hDlg, idControlFirst+1+10)); DestroyWindow(GetDlgItem(hDlg, idControlFirst+2+10)); fReset = TRUE; } } if (fReset) { // TODO: This won't work on downlevel. So use plain text. BOOL fLinksSupported = LinkWindow_RegisterClass_DelayLoad(); TCHAR szTempStr1[MAX_URL_STRING*3]; TCHAR szTempStr2[MAX_URL_STRING*3]; CHAR szTempStr3[MAX_PATH]; // Replace the %s in the first line to the domain name. GetWindowText(GetDlgItem(hDlg, idControlFirst), szTempStr1, ARRAYSIZE(szTempStr1)); GetEmailAddress(pApp, szTempStr3, ARRAYSIZE(szTempStr3)); wnsprintf(szTempStr2, ARRAYSIZE(szTempStr2), szTempStr1, szTempStr3, szTempStr3); SetWindowText(GetDlgItem(hDlg, idControlFirst), szTempStr2); SetWindowTextW(GetDlgItem(hDlg, idControlFirst+1), pszURL); // We only support Win2k and later because we don't want to worry about // the fact that the "LinkWindow" class doesn't have an "W" and "A" version. if (fLinksSupported && IsOSNT() && (5 <= GetOSVer())) { ConvertTextToLinkWindow(hDlg, idControlFirst+1, idsADURLLink); ConvertTextToLinkWindow(hDlg, idControlFirst+2, idsADUseWebMsg); // Replace the %s in the second line to the URL. GetWindowText(GetDlgItem(hDlg, idControlFirst+1+10), szTempStr1, ARRAYSIZE(szTempStr1)); wnsprintf(szTempStr2, ARRAYSIZE(szTempStr2), szTempStr1, pszURL, pszURL); SetWindowText(GetDlgItem(hDlg, idControlFirst+1+10), szTempStr2); // Set the hyperlink URL in the Click here link. GetWindowText(GetDlgItem(hDlg, idControlFirst+2+10), szTempStr1, ARRAYSIZE(szTempStr1)); wnsprintf(szTempStr2, ARRAYSIZE(szTempStr2), szTempStr1, pszURL); SetWindowText(GetDlgItem(hDlg, idControlFirst+2+10), szTempStr2); } } return TRUE; } BOOL CALLBACK UseWebMailInitProc(CICWApprentice *pApp, HWND hDlg, BOOL fFirstInit) { return TheInitProc(pApp, hDlg, fFirstInit, IDC_USEWEB_LINE1, g_szWebMailURL, ARRAYSIZE(g_szWebMailURL)); } BOOL CALLBACK UseWebMailOKProc(CICWApprentice *pApp, HWND hDlg, BOOL fForward, UINT *puNextPage) { if (fForward) { *puNextPage = ORD_PAGE_AD_MAILSERVER; } else { *puNextPage = ORD_PAGE_AD_MAILADDRESS; } LinkWindow_UnregisterClass_DelayLoad(g_hInstRes); return(TRUE); } BOOL CALLBACK UseWebMailCmdProc(CICWApprentice *pApp, HWND hDlg, WPARAM wParam, LPARAM lParam) { LinkWindow_UnregisterClass_DelayLoad(g_hInstRes); return(TRUE); } BOOL CALLBACK GotoServerInfoInitProc(CICWApprentice *pApp, HWND hDlg, BOOL fFirstInit) { return TheInitProc(pApp, hDlg, fFirstInit, IDC_GETINFO_LINE1, g_szInfoURL, ARRAYSIZE(g_szInfoURL)); } BOOL CALLBACK GotoServerInfoOKProc(CICWApprentice *pApp, HWND hDlg, BOOL fForward, UINT *puNextPage) { if (fForward) { *puNextPage = ORD_PAGE_AD_MAILSERVER; } else { *puNextPage = ORD_PAGE_AD_MAILADDRESS; } return(TRUE); } BOOL CALLBACK GotoServerInfoCmdProc(CICWApprentice *pApp, HWND hDlg, WPARAM wParam, LPARAM lParam) { LinkWindow_UnregisterClass_DelayLoad(g_hInstRes); return(TRUE); } BOOL CALLBACK PassifierInitProc(CICWApprentice *pApp, HWND hDlg, BOOL fFirstInit) { TCHAR szTemplate[1024]; TCHAR szPrivacyText[1024]; TCHAR szEmail[MAX_PATH]; TCHAR szDomain[MAX_PATH]; if (FAILED(GetEmailAddressDomain(pApp, szDomain, ARRAYSIZE(szDomain)))) { szDomain[0] = 0; } // Set the next text. LoadString(g_hInstRes, ids_ADPassifier_Warning, szTemplate, ARRAYSIZE(szTemplate)); wnsprintf(szPrivacyText, ARRAYSIZE(szPrivacyText), szTemplate, szDomain); SetWindowText(GetDlgItem(hDlg, IDC_PASSIFIER_PRIVACYWARNING), szPrivacyText); // Load up the list boxes IMailAutoDiscovery * pMailAutoDiscovery; HWND hwndListBox; if (FAILED(GetEmailAddress(pApp, szEmail, ARRAYSIZE(szEmail)))) { szEmail[0] = 0; } HRESULT hr = CoCreateInstance(CLSID_MailAutoDiscovery, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IMailAutoDiscovery, &pMailAutoDiscovery)); if (SUCCEEDED(hr)) { IAutoDiscoveryProvider * pProviders; BSTR bstrEmail = SysAllocStringA(szEmail); hr = pMailAutoDiscovery->getPrimaryProviders(bstrEmail, &pProviders); if (SUCCEEDED(hr)) { long nTotal = 0; VARIANT varIndex; hwndListBox = GetDlgItem(hDlg, IDC_PASSIFIER_PRIMARYLIST); if (hwndListBox) { varIndex.vt = VT_I4; pProviders->get_length(&nTotal); for (varIndex.lVal = 0; (varIndex.lVal < nTotal) && (varIndex.lVal <= 3); varIndex.lVal++) { BSTR bstrDomain; if (SUCCEEDED(pProviders->get_item(varIndex, &bstrDomain))) { CHAR szDomain[MAX_PATH]; SHUnicodeToAnsi(bstrDomain, szDomain, ARRAYSIZE(szDomain)); SetWindowTextA(GetDlgItem(hDlg, IDC_PASSIFIER_PRIMARYLIST + varIndex.lVal), szDomain); SysFreeString(bstrDomain); } } } pProviders->Release(); } hr = pMailAutoDiscovery->getSecondaryProviders(bstrEmail, &pProviders); if (SUCCEEDED(hr)) { long nTotal = 0; VARIANT varIndex; hwndListBox = GetDlgItem(hDlg, IDC_PASSIFIER_SECONDARYLIST); if (hwndListBox) { varIndex.vt = VT_I4; pProviders->get_length(&nTotal); for (varIndex.lVal = 0; (varIndex.lVal < nTotal) && (varIndex.lVal <= 3); varIndex.lVal++) { BSTR bstrURL; // The secondary servers are URLs if (SUCCEEDED(pProviders->get_item(varIndex, &bstrURL))) { CHAR szURL[MAX_PATH]; CHAR szDomain[MAX_PATH]; DWORD cchSize = ARRAYSIZE(szDomain); SHUnicodeToAnsi(bstrURL, szURL, ARRAYSIZE(szURL)); UrlGetPart(szURL, szDomain, &cchSize, URL_PART_HOSTNAME, 0); SetWindowTextA(GetDlgItem(hDlg, IDC_PASSIFIER_SECONDARYLIST + varIndex.lVal), szDomain); SysFreeString(bstrURL); } } } pProviders->Release(); } SysFreeString(bstrEmail); pMailAutoDiscovery->Release(); } // Set the manual checkbox BOOL fManuallyConfigure = SHRegGetBoolUSValue(SZ_REGKEY_AUTODISCOVERY, SZ_REGVALUE_AUTODISCOVERY_OEMANUAL, FALSE, FALSE); CheckDlgButton(hDlg, IDC_PASSIFIER_SKIPCHECKBOX, (fManuallyConfigure ? BST_CHECKED : BST_UNCHECKED)); return TRUE; } #define SZ_TRUE TEXT("TRUE") #define SZ_FALSE TEXT("FALSE") BOOL CALLBACK PassifierOKProc(CICWApprentice *pApp, HWND hDlg, BOOL fForward, UINT *puNextPage) { if (fForward) { BOOL fManuallyConfigure = (BST_CHECKED == IsDlgButtonChecked(hDlg, IDC_PASSIFIER_SKIPCHECKBOX)); SHSetValue(HKEY_CURRENT_USER, SZ_REGKEY_AUTODISCOVERY, SZ_REGVALUE_AUTODISCOVERY_OEMANUAL, REG_SZ, (LPCVOID)(fManuallyConfigure ? SZ_TRUE : SZ_FALSE), (fManuallyConfigure ? sizeof(SZ_TRUE) : sizeof(SZ_FALSE))); *puNextPage = (fManuallyConfigure ? ORD_PAGE_AD_MAILSERVER : ORD_PAGE_AD_AUTODISCOVERY); } else { *puNextPage = ORD_PAGE_AD_MAILADDRESS; } return TRUE; } BOOL CALLBACK PassifierCmdProc(CICWApprentice *pApp, HWND hDlg, WPARAM wParam, LPARAM lParam) { return TRUE; }