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.
 
 
 
 
 
 

1504 lines
48 KiB

// --------------------------------------------------------------------------------
// Acctutil.cpp
// Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
// Steven J. Bailey
// --------------------------------------------------------------------------------
#include "pch.hxx"
#include "goptions.h"
#include "imnact.h"
#include "acctutil.h"
#include "strconst.h"
#include "error.h"
#include "resource.h"
#include <storfldr.h>
#include <notify.h>
#include "conman.h"
#include "shlwapip.h"
#include "browser.h"
#include "instance.h"
#include "menures.h"
#include "subscr.h"
#include "msident.h"
#include "acctcach.h"
#include <demand.h> // must be last!
CNewAcctMonitor *g_pNewAcctMonitor = NULL;
HRESULT IsValidSendAccount(LPSTR pszAccount);
CImnAdviseAccount::CImnAdviseAccount(void)
{
m_cRef = 1;
m_pNotify = NULL;
}
CImnAdviseAccount::~CImnAdviseAccount(void)
{
if (m_pNotify != NULL)
m_pNotify->Release();
}
HRESULT CImnAdviseAccount::Initialize()
{
HRESULT hr;
hr = CreateNotify(&m_pNotify);
if (SUCCEEDED(hr))
hr = m_pNotify->Initialize((TCHAR *)c_szMailFolderNotify);
return(hr);
}
STDMETHODIMP CImnAdviseAccount::QueryInterface(REFIID riid, LPVOID *ppv)
{
// Locals
HRESULT hr=S_OK;
// Bad param
if (ppv == NULL)
{
hr = TRAPHR(E_INVALIDARG);
goto exit;
}
// Init
*ppv=NULL;
// IID_IImnAccountManager
if (IID_IImnAdviseAccount == riid)
*ppv = (IImnAdviseAccount *)this;
// IID_IUnknown
else if (IID_IUnknown == riid)
*ppv = (IUnknown *)this;
// If not null, addref it and return
if (NULL!=*ppv)
{
((LPUNKNOWN)*ppv)->AddRef();
goto exit;
}
// No Interface
hr = TRAPHR(E_NOINTERFACE);
exit:
// Done
return hr;
}
STDMETHODIMP_(ULONG) CImnAdviseAccount::AddRef(void)
{
return ++m_cRef;
}
STDMETHODIMP_(ULONG) CImnAdviseAccount::Release(void)
{
if (0 != --m_cRef)
return m_cRef;
delete this;
return 0;
}
STDMETHODIMP CImnAdviseAccount::AdviseAccount(DWORD dwAdviseType, ACTX *pactx)
{
Assert(pactx != NULL);
if (pactx->AcctType == ACCT_DIR_SERV)
return(S_OK);
if (g_pBrowser)
g_pBrowser->AccountsChanged();
if (dwAdviseType == AN_DEFAULT_CHANGED)
return(S_OK);
HandleAccountChange(pactx->AcctType, dwAdviseType, pactx->pszAccountID, pactx->pszOldName, pactx->dwServerType);
if (g_pNewAcctMonitor != NULL)
g_pNewAcctMonitor->OnAdvise(pactx->AcctType, dwAdviseType, pactx->pszAccountID);
// No matter what the notification, we need to tell the connection manager
if (g_pConMan)
g_pConMan->AdviseAccount(dwAdviseType, pactx);
return S_OK;
}
void CImnAdviseAccount::HandleAccountChange(ACCTTYPE AcctType, DWORD dwAN, LPTSTR pszID, LPTSTR pszOldName, DWORD dwSrvTypesOld)
{
HRESULT hr;
IImnAccount *pAccount;
char szName[CCHMAX_ACCOUNT_NAME];
FOLDERID id;
Assert(pszID != NULL);
switch (dwAN)
{
case AN_ACCOUNT_DELETED:
AccountCache_AccountDeleted(pszID);
if (!!(dwSrvTypesOld & (SRV_IMAP | SRV_NNTP | SRV_HTTPMAIL)))
{
hr = g_pStore->FindServerId(pszID, &id);
if (SUCCEEDED(hr))
{
HCURSOR hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
hr = g_pStore->DeleteFolder(id, DELETE_FOLDER_RECURSIVE | DELETE_FOLDER_NOTRASHCAN, (IStoreCallback *)g_pBrowser);
Assert(SUCCEEDED(hr));
SetCursor(hCursor);
}
}
if (g_pBrowser != NULL)
g_pBrowser->UpdateToolbar();
break;
case AN_ACCOUNT_ADDED:
if (SUCCEEDED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszID, &pAccount)))
{
hr = g_pStore->CreateServer(pAccount, NOFLAGS, &id);
Assert(SUCCEEDED(hr));
if (g_pBrowser != NULL)
g_pBrowser->UpdateToolbar();
pAccount->Release();
}
break;
case AN_ACCOUNT_CHANGED:
AccountCache_AccountChanged(pszID);
if (pszOldName != NULL)
{
hr = g_pStore->FindServerId(pszID, &id);
if (SUCCEEDED(hr))
{
if (SUCCEEDED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszID, &pAccount)))
{
hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, szName, ARRAYSIZE(szName));
Assert(SUCCEEDED(hr));
hr = g_pStore->RenameFolder(id, szName, NOFLAGS, NOSTORECALLBACK);
Assert(SUCCEEDED(hr));
pAccount->Release();
}
}
}
break;
}
}
// -----------------------------------------------------------------------------
// AcctUtil_HrCreateAccountMenu
// -----------------------------------------------------------------------------
#define CCHMAX_RES 255
HRESULT AcctUtil_HrCreateAccountMenu(ACCOUNTMENUTYPE type, HMENU hPopup, UINT uidmPopup,
HMENU *phAccounts, LPACCTMENU *pprgAccount, ULONG *pcAccounts, LPSTR pszThisAccount, BOOL fMail)
{
// Locals
HRESULT hr=S_OK;
ULONG cAccounts=0;
IImnEnumAccounts *pEnum=NULL;
IImnAccount *pAccount=NULL;
CHAR szDefault[CCHMAX_ACCOUNT_NAME];
CHAR szAccount[CCHMAX_ACCOUNT_NAME];
CHAR szQuoted[CCHMAX_ACCOUNT_NAME + CCHMAX_ACCOUNT_NAME + CCHMAX_RES];
LPACCTMENU prgAccount=NULL;
HMENU hAccounts=NULL;
MENUITEMINFO mii;
UINT uPos=0;
ULONG iAccount=0;
CHAR szRes[CCHMAX_RES];
CHAR szRes1[CCHMAX_RES];
CHAR szRes2[CCHMAX_RES];
UINT idmFirst;
CHAR szTitle[CCHMAX_RES + CCHMAX_RES + CCHMAX_ACCOUNT_NAME];
BOOL fNeedUsingMenu = FALSE;
// Check Parameters
Assert(g_pAcctMan && phAccounts && pprgAccount && pcAccounts);
// Init
*szDefault = '\0';
*pprgAccount = NULL;
*pcAccounts = 0;
*phAccounts = NULL;
if (type == ACCTMENU_SENDLATER)
idmFirst = ID_SEND_LATER_ACCOUNT_FIRST;
else
idmFirst = ID_SEND_NOW_ACCOUNT_FIRST;
// Verify Default SMTP Account
CHECKHR(hr = g_pAcctMan->ValidateDefaultSendAccount());
// Get the default
CHECKHR(hr = hr = g_pAcctMan->GetDefaultAccountName(ACCT_MAIL, szDefault, ARRAYSIZE(szDefault)));
// Enumerate through the server types
CHECKHR(hr = g_pAcctMan->Enumerate(((ACCTMENU_SEND == type || ACCTMENU_SENDLATER == type) ? SRV_SMTP : SRV_SMTP | SRV_POP3), &pEnum));
// sort the accoutns
CHECKHR(hr = pEnum->SortByAccountName());
// Get Count
CHECKHR(hr = pEnum->GetCount(&cAccounts));
// No Accounts
if (cAccounts == 0)
goto exit;
// Exceeded menu ids...
Assert(cAccounts <= 50);
// Add one if ACCTMENU_SENDRECV
if (ACCTMENU_SENDRECV == type)
cAccounts++;
// Allocate prgAccount
CHECKALLOC(prgAccount = (LPACCTMENU)g_pMalloc->Alloc(cAccounts * sizeof(ACCTMENU)));
// Zero Init
ZeroMemory(prgAccount, cAccounts * sizeof(ACCTMENU));
// Only one account
if (((ACCTMENU_SENDRECV == type) && (cAccounts == 2)) ||
(cAccounts == 1) || !fMail)
{
// Return default Account
prgAccount[iAccount].fDefault = TRUE;
prgAccount[iAccount].fThisAccount = TRUE;
StrCpyN(prgAccount[iAccount].szAccount, szDefault, ARRAYSIZE(prgAccount[iAccount].szAccount));
// Return Everything
*pprgAccount = prgAccount;
prgAccount = NULL;
*pcAccounts = cAccounts;
// Done
goto exit;
}
// Create a Menu
CHECKALLOC(hAccounts = CreatePopupMenu());
// if not using a specific account or the account is illegal, then let's default to the default-account
if (pszThisAccount==NULL || *pszThisAccount == NULL || IsValidSendAccount(pszThisAccount)!=S_OK)
pszThisAccount = szDefault;
// Lets insert the default item
if ((ACCTMENU_SENDLATER == type || ACCTMENU_SEND == type) && !FIsEmptyA(szDefault))
{
// Load String
StrCpyN(szTitle, pszThisAccount, ARRAYSIZE(szTitle));
prgAccount[iAccount].fDefault = lstrcmpi(pszThisAccount, szDefault)==0;
// if this is the default, flag it.
if (prgAccount[iAccount].fDefault)
{
AthLoadString(idsDefaultAccount, szRes1, ARRAYSIZE(szRes1));
StrCatBuff(szTitle, " ", ARRAYSIZE(szTitle));
StrCatBuff(szTitle, szRes1, ARRAYSIZE(szTitle));
}
if (((ACCTMENU_SEND == type && DwGetOption(OPT_SENDIMMEDIATE) && !g_pConMan->IsGlobalOffline()) ||
(ACCTMENU_SENDLATER == type && (!DwGetOption(OPT_SENDIMMEDIATE) || g_pConMan->IsGlobalOffline()))))
{
// if this menu is the default action add the 'Alt+S' accelerator string
AthLoadString(idsSendMsgAccelTip, szRes, ARRAYSIZE(szRes));
StrCatBuff(szTitle, "\t", ARRAYSIZE(szTitle));
StrCatBuff(szTitle, szRes, ARRAYSIZE(szTitle));
}
// Get mii ready
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID;
mii.fType = MFT_STRING;
mii.fState = MFS_DEFAULT; // first item is the default verb
mii.dwTypeData = PszEscapeMenuStringA(szTitle, szQuoted, sizeof(szQuoted) / sizeof(char));
mii.cch = lstrlen(szQuoted);
mii.wID = idmFirst + uPos;
// Set acctmenu item
prgAccount[iAccount].fThisAccount= TRUE;
prgAccount[iAccount].uidm = mii.wID;
StrCpyN(prgAccount[iAccount].szAccount, pszThisAccount, ARRAYSIZE(prgAccount[iAccount].szAccount));
iAccount++;
// Insert the item
if (InsertMenuItem(hAccounts, uPos, TRUE, &mii))
{
uPos++;
mii.fMask = MIIM_TYPE;
mii.fType = MFT_SEPARATOR;
if (InsertMenuItem(hAccounts, uPos, TRUE, &mii))
uPos++;
}
}
// Otherwise Send & Receive
else if (ACCTMENU_SENDRECV == type)
{
// Setup Menu
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID;
mii.fType = MFT_STRING;
mii.fState = MFS_DEFAULT;
AthLoadString(idsPollAllAccounts, szRes, ARRAYSIZE(szRes));
mii.dwTypeData = szRes;
mii.cch = lstrlen(szRes);
mii.wID = idmFirst + uPos;
// Set acctmenu item
prgAccount[iAccount].fDefault = TRUE;
prgAccount[iAccount].uidm = mii.wID;
*prgAccount[iAccount].szAccount = '\0';
iAccount++;
// Insert the item
if (InsertMenuItem(hAccounts, uPos, TRUE, &mii))
{
uPos++;
mii.fMask = MIIM_TYPE;
mii.fType = MFT_SEPARATOR;
if (InsertMenuItem(hAccounts, uPos, TRUE, &mii))
uPos++;
}
}
// Standard
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(mii);
mii.fMask = MIIM_TYPE | MIIM_ID;
mii.fType = MFT_STRING;
// Loop accounts
while(SUCCEEDED(pEnum->GetNext(&pAccount)))
{
// Get Account Name
CHECKHR(hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, szAccount, ARRAYSIZE(szAccount)));
// Skip the 'This' account. Note for the send & receive menu this will always be the default
if (lstrcmpi(pszThisAccount, szAccount) == 0)
{
// We've already added this account
if (ACCTMENU_SEND == type || ACCTMENU_SENDLATER == type)
{
SafeRelease(pAccount);
continue;
}
// Otherwise, Account (Default)
else
{
// for send a recieve menu pszThisAccount should == szDefault
Assert (pszThisAccount == szDefault);
// Load String
AthLoadString(idsDefaultAccount, szRes, ARRAYSIZE(szRes));
// Make String - Saranac (Default)
wnsprintf(szTitle, ARRAYSIZE(szTitle), "%s %s", szAccount, szRes);
// Setup the menu item name
mii.dwTypeData = PszEscapeMenuStringA(szTitle, szQuoted, sizeof(szQuoted) / sizeof(char));
mii.cch = lstrlen(szQuoted);
prgAccount[iAccount].fDefault = TRUE;
}
}
else
{
*szTitle=0;
// this might be the default
prgAccount[iAccount].fDefault = lstrcmpi(szAccount, szDefault)==0;
// build the string on the fly as any one of these accounts might be the 'default'
PszEscapeMenuStringA(szAccount, szTitle, sizeof(szTitle) / sizeof(char));
// if this is the default, flag it.
if (prgAccount[iAccount].fDefault)
{
AthLoadString(idsDefaultAccount, szRes1, ARRAYSIZE(szRes1));
StrCatBuff(szTitle, " ", ARRAYSIZE(szTitle));
StrCatBuff(szTitle, szRes1, ARRAYSIZE(szTitle));
}
// Setup the menu item name
mii.dwTypeData = szTitle;
mii.cch = lstrlen(szTitle);
}
// Insert into menu
mii.wID = idmFirst + uPos;
if (InsertMenuItem(hAccounts, uPos, TRUE, &mii))
uPos++;
// Set acctmenu item
Assert(iAccount < cAccounts);
prgAccount[iAccount].uidm = mii.wID;
StrCpyN(prgAccount[iAccount].szAccount, szAccount, ARRAYSIZE(prgAccount[iAccount].szAccount));
iAccount++;
// Release Account
SafeRelease(pAccount);
}
// Return Everything
*phAccounts = hAccounts;
hAccounts = NULL;
*pprgAccount = prgAccount;
prgAccount = NULL;
*pcAccounts = cAccounts;
exit:
// Lets Setup the Accounts Menu
ZeroMemory(&mii, sizeof(mii));
mii.cbSize = sizeof(MENUITEMINFO);
fNeedUsingMenu = (cAccounts <= 1) || !fMail;
if (ACCTMENU_SEND == type)
{
mii.fMask = MIIM_SUBMENU | MIIM_TYPE;
if (fNeedUsingMenu)
{
AthLoadString(idsSendMsgOneAccount, szRes, ARRAYSIZE(szRes));
AthLoadString(idsSendMsgAccelTip, szRes1, ARRAYSIZE(szRes1));
// If send now is default, add the Alt + S at the end
if (DwGetOption(OPT_SENDIMMEDIATE) && !g_pConMan->IsGlobalOffline())
wnsprintf(szTitle, ARRAYSIZE(szTitle), "%s\t%s", szRes, szRes1);
else
wnsprintf(szTitle, ARRAYSIZE(szTitle), "%s", szRes);
}
else
AthLoadString(idsSendMsgUsing, szTitle, ARRAYSIZE(szTitle));
mii.fType = MFT_STRING;
mii.dwTypeData = szTitle;
mii.cch = lstrlen(szTitle);
mii.hSubMenu = fNeedUsingMenu ? NULL : *phAccounts;
}
else if (ACCTMENU_SENDLATER == type)
{
if (fNeedUsingMenu)
{
AthLoadString(idsSendLaterOneAccount, szRes, ARRAYSIZE(szRes));
AthLoadString(idsSendMsgAccelTip, szRes1, ARRAYSIZE(szRes1));
// If send now is default, add the Alt + S at the end
if (!DwGetOption(OPT_SENDIMMEDIATE) || g_pConMan->IsGlobalOffline())
wnsprintf(szTitle, ARRAYSIZE(szTitle), "%s\t%s", szRes, szRes1);
else
wnsprintf(szTitle, ARRAYSIZE(szTitle), "%s", szRes);
}
else
AthLoadString(idsSendLaterUsing, szTitle, ARRAYSIZE(szTitle));
mii.fMask = MIIM_SUBMENU | MIIM_TYPE;
mii.fType = MFT_STRING;
mii.dwTypeData = szTitle;
mii.cch = lstrlen(szTitle);
mii.hSubMenu = fNeedUsingMenu ? NULL : *phAccounts;
}
else
{
mii.fMask = MIIM_SUBMENU | MIIM_TYPE;
AthLoadString(fNeedUsingMenu ? idsSendRecvOneAccount : idsSendRecvUsing, szRes, ARRAYSIZE(szRes));
mii.fType = MFT_STRING;
mii.dwTypeData = szRes;
mii.cch = lstrlen(szRes);
mii.hSubMenu = fNeedUsingMenu ? NULL : *phAccounts;
}
// Set the menu item
SideAssert(SetMenuItemInfo(hPopup, uidmPopup, FALSE, &mii));
// Cleanup
SafeRelease(pEnum);
SafeRelease(pAccount);
SafeMemFree(prgAccount);
if (hAccounts)
DestroyMenu(hAccounts);
// Done
return hr;
}
HRESULT AcctUtil_GetServerCount(DWORD dwSrvTypes, DWORD *pcSrv)
{
HRESULT hr;
IImnEnumAccounts *pEnum;
Assert(dwSrvTypes != 0);
Assert(pcSrv != NULL);
hr = g_pAcctMan->Enumerate(dwSrvTypes, &pEnum);
if (SUCCEEDED(hr))
{
hr = pEnum->GetCount(pcSrv);
Assert(SUCCEEDED(hr));
pEnum->Release();
}
return(hr);
}
/////////////////////////////////////////////////////////////////////////////
// CNewAcctMonitor
//
CNewAcctMonitor::CNewAcctMonitor()
{
m_cRef = 1;
m_rgAccounts = NULL;
m_cAlloc = 0;
m_cAccounts = 0;
m_fMonitor = FALSE;
}
CNewAcctMonitor::~CNewAcctMonitor()
{
Assert(m_rgAccounts == NULL);
}
ULONG CNewAcctMonitor::AddRef(void)
{
return (++m_cRef);
}
ULONG CNewAcctMonitor::Release(void)
{
ULONG cRefT = --m_cRef;
if (0 == m_cRef)
delete this;
return (cRefT);
}
void CNewAcctMonitor::OnAdvise(ACCTTYPE atType, DWORD dwNotify, LPCSTR pszAcctId)
{
UINT i;
IImnAccount *pAccount;
DWORD dwSrvTypes;
HRESULT hr;
FOLDERTYPE type;
if (atType == ACCT_DIR_SERV)
return;
switch (dwNotify)
{
case AN_ACCOUNT_ADDED:
if (atType == ACCT_MAIL)
{
if (FAILED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAcctId, &pAccount)))
break;
hr = pAccount->GetServerTypes(&dwSrvTypes);
Assert(SUCCEEDED(hr));
pAccount->Release();
if (!!(dwSrvTypes & SRV_IMAP))
type = FOLDER_IMAP;
else if (!!(dwSrvTypes & SRV_HTTPMAIL))
type = FOLDER_HTTPMAIL;
else
break;
}
else
{
Assert(atType == ACCT_NEWS);
type = FOLDER_NEWS;
}
// Check to see if we need to grow our array
if ((1 + m_cAccounts) >= m_cAlloc)
{
if (!MemRealloc((LPVOID *)&m_rgAccounts, sizeof(NEWACCTINFO) * (10 + m_cAlloc)))
break;
m_cAlloc += 10;
}
m_rgAccounts[m_cAccounts].pszAcctId = PszDupA(pszAcctId);
m_rgAccounts[m_cAccounts].type = type;
m_cAccounts++;
break;
case AN_ACCOUNT_DELETED:
// Check to see if we've already added this to our list.
for (i = 0; i < m_cAccounts; i++)
{
if (0 == lstrcmpi(pszAcctId, m_rgAccounts[i].pszAcctId))
{
// We found it. We need to remove it, and adjust our array
MemFree(m_rgAccounts[i].pszAcctId);
m_cAccounts--;
for (; i < m_cAccounts; i++)
m_rgAccounts[i] = m_rgAccounts[i + 1];
break;
}
}
break;
}
}
void CNewAcctMonitor::StartMonitor(void)
{
Assert(m_rgAccounts == NULL);
Assert(m_cAccounts == NULL);
Assert(m_fMonitor == FALSE);
m_fMonitor = TRUE;
}
void CNewAcctMonitor::StopMonitor(HWND hwndParent)
{
FOLDERID id;
HRESULT hr;
UINT i;
Assert(m_fMonitor == TRUE);
// If we have any new newsgroups left, ask if the user want's to display
// the subscription dialog.
if (m_cAccounts != 0)
{
int ResId;
BOOL fOffline = (g_pConMan && g_pConMan->IsGlobalOffline());
if (m_rgAccounts[0].type == FOLDER_NEWS)
{
ResId = fOffline ? idsDisplayNewsSubDlgOffline : idsDisplayNewsSubDlg;
}
else
{
ResId = fOffline ? idsDisplayImapSubDlgOffline : idsDisplayImapSubDlg;
}
if (IDYES == AthMessageBoxW(hwndParent, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(ResId), 0, MB_ICONEXCLAMATION | MB_YESNO))
{
hr = g_pStore->FindServerId(m_rgAccounts[0].pszAcctId, &id);
if (SUCCEEDED(hr))
{
if (fOffline)
g_pConMan->SetGlobalOffline(FALSE);
if (FOLDER_HTTPMAIL == m_rgAccounts[0].type)
DownloadNewsgroupList(hwndParent, id);
else
DoSubscriptionDialog(hwndParent, m_rgAccounts[0].type == FOLDER_NEWS, id);
}
}
}
for (i = 0; i < m_cAccounts; i++)
{
if (m_rgAccounts[i].pszAcctId != NULL)
MemFree(m_rgAccounts[i].pszAcctId);
}
m_cAccounts = 0;
m_cAlloc = 0;
SafeMemFree(m_rgAccounts);
m_fMonitor = FALSE;
}
void CheckIMAPDirty(LPSTR pszAccountID, HWND hwndParent, FOLDERID idServer,
DWORD dwFlags)
{
HRESULT hr;
IImnAccount *pAcct = NULL;
DWORD dw;
TraceCall("CheckIMAPDirty");
hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAccountID, &pAcct);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
hr = pAcct->GetPropDw(AP_IMAP_DIRTY, &dw);
if (FAILED(hr) || 0 == dw)
{
TraceError(hr);
goto exit;
}
// IMAP is dirty, deal with each dirty flag
if ((dw & IMAP_OE4MIGRATE_DIRTY) && FOLDERID_INVALID != idServer && NULL != g_pStore)
{
IEnumerateFolders *pEnum;
BOOL fSentItems = FALSE;
BOOL fDrafts = FALSE;
BOOL fInbox = FALSE;
Assert(0 == (dw & IMAP_OE4MIGRATE_DIRTY) || (dw & IMAP_FLDRLIST_DIRTY));
// We may or may not be dirty. Check if all IMAP special fldrs already present
hr = g_pStore->EnumChildren(idServer, FALSE, &pEnum);
TraceError(hr);
if (SUCCEEDED(hr))
{
FOLDERINFO fiFolderInfo;
while (S_OK == pEnum->Next(1, &fiFolderInfo, NULL))
{
switch (fiFolderInfo.tySpecial)
{
case FOLDER_INBOX:
fInbox = TRUE;
break;
case FOLDER_SENT:
fSentItems = TRUE;
break;
case FOLDER_DRAFT:
fDrafts = TRUE;
break;
}
g_pStore->FreeRecord(&fiFolderInfo);
}
pEnum->Release();
}
if (fInbox && fSentItems && fDrafts)
{
// All special folders present: remove dirty flags
dw &= ~(IMAP_FLDRLIST_DIRTY | IMAP_OE4MIGRATE_DIRTY);
}
}
if (dw & IMAP_FLDRLIST_DIRTY)
{
int iResult;
// Ask user if he would like to reset his folderlist
if (0 == (dwFlags & CID_NOPROMPT))
{
UINT uiReasonStrID;
AssertSz(0 == (dwFlags & CID_RESETLISTOK), "If I have permission to reset, why prompt?");
// Figure out why we are asking to refresh the folderlist
if (dw & IMAP_OE4MIGRATE_DIRTY)
uiReasonStrID = idsOE5IMAPSpecialFldrs;
else
uiReasonStrID = idsYouMadeChanges;
iResult = AthMessageBoxW(hwndParent, MAKEINTRESOURCEW(idsAthena),
MAKEINTRESOURCEW(uiReasonStrID), MAKEINTRESOURCEW(idsRefreshFolderListPrompt),
MB_ICONEXCLAMATION | MB_YESNO);
}
else
iResult = (dwFlags & CID_RESETLISTOK) ? IDYES : IDNO;
if (IDYES == iResult)
{
if (FOLDERID_INVALID == idServer)
{
hr = g_pStore->FindServerId(pszAccountID, &idServer);
TraceError(hr);
}
if (FOLDERID_INVALID != idServer)
{
//The user wants to download the list of newsgroups, so if we are offline, go online
if (g_pConMan)
g_pConMan->SetGlobalOffline(FALSE);
hr = DownloadNewsgroupList(hwndParent, idServer);
TraceError(hr);
if (SUCCEEDED(hr))
{
// The sent items and drafts folders should not be dirty any longer
dw &= ~(IMAP_SENTITEMS_DIRTY | IMAP_DRAFTS_DIRTY);
}
}
}
// Regardless of yes or no, reset dirty flag
dw &= ~(IMAP_FLDRLIST_DIRTY | IMAP_OE4MIGRATE_DIRTY);
}
if (dw & (IMAP_SENTITEMS_DIRTY | IMAP_DRAFTS_DIRTY))
{
IEnumerateFolders *pEnum;
char szSentItems[MAX_PATH];
char szDrafts[MAX_PATH];
DWORD dwIMAPSpecial = 0;
BOOL fSetSentItems = FALSE;
BOOL fSetDrafts = FALSE;
// Remove all affected special folder types from cache. If new path is
// found in folderlist, set its special folder type
szSentItems[0] = '\0';
szDrafts[0] = '\0';
hr = pAcct->GetPropDw(AP_IMAP_SVRSPECIALFLDRS, &dwIMAPSpecial);
if (SUCCEEDED(hr) && dwIMAPSpecial)
{
if (dw & IMAP_SENTITEMS_DIRTY)
{
hr = pAcct->GetPropSz(AP_IMAP_SENTITEMSFLDR, szSentItems, ARRAYSIZE(szSentItems));
TraceError(hr);
}
if (dw & IMAP_DRAFTS_DIRTY)
{
hr = pAcct->GetPropSz(AP_IMAP_DRAFTSFLDR, szDrafts, ARRAYSIZE(szDrafts));
TraceError(hr);
}
}
hr = g_pStore->EnumChildren(idServer, FALSE, &pEnum);
TraceError(hr);
if (SUCCEEDED(hr))
{
FOLDERINFO fiFolderInfo;
while (S_OK == pEnum->Next(1, &fiFolderInfo, NULL))
{
BOOL fUpdate = FALSE;
if (dw & IMAP_SENTITEMS_DIRTY)
{
if (0 == lstrcmp(szSentItems, fiFolderInfo.pszName))
{
fiFolderInfo.tySpecial = FOLDER_SENT;
fUpdate = TRUE;
fSetSentItems = TRUE;
// IE5 Bug #62765: if new special folder is unsubscribed, we need to subscribe it
if (0 == (fiFolderInfo.dwFlags & FOLDER_SUBSCRIBED))
fiFolderInfo.dwFlags |= FOLDER_SUBSCRIBED | FOLDER_CREATEONDEMAND;
}
else if (FOLDER_SENT == fiFolderInfo.tySpecial)
{
// Ignore FOLDER_HIDDEN. I'm assuming it's no big deal to leave a tombstone
fiFolderInfo.tySpecial = FOLDER_NOTSPECIAL;
fUpdate = TRUE;
}
}
if (dw & IMAP_DRAFTS_DIRTY)
{
if (0 == lstrcmp(szDrafts, fiFolderInfo.pszName))
{
fiFolderInfo.tySpecial = FOLDER_DRAFT;
fUpdate = TRUE;
fSetDrafts = TRUE;
// IE5 Bug #62765: if new special folder exists and is unsubscribed, we must subscribe it
if (0 == (fiFolderInfo.dwFlags & FOLDER_SUBSCRIBED))
fiFolderInfo.dwFlags |= FOLDER_SUBSCRIBED | FOLDER_CREATEONDEMAND;
}
else if (FOLDER_DRAFT == fiFolderInfo.tySpecial)
{
// Ignore FOLDER_HIDDEN. I'm assuming it's no big deal to leave a tombstone
fiFolderInfo.tySpecial = FOLDER_NOTSPECIAL;
fUpdate = TRUE;
}
}
if (fUpdate)
{
hr = g_pStore->UpdateRecord(&fiFolderInfo);
TraceError(hr);
}
g_pStore->FreeRecord(&fiFolderInfo);
} // while
pEnum->Release();
} // if (SUCCEEDED(EnumChildren))
// If the new special folder path(s) not found in folderlist, need to create placeholder folder
if (dwIMAPSpecial && (dw & IMAP_SENTITEMS_DIRTY) && FALSE == fSetSentItems && '\0' != szSentItems[0])
{
FOLDERINFO fiFolderInfo;
BOOL bHierarchy = 0xFF; // Invalid hierarchy char
hr = g_pStore->GetFolderInfo(idServer, &fiFolderInfo);
if (SUCCEEDED(hr))
{
bHierarchy = fiFolderInfo.bHierarchy;
g_pStore->FreeRecord(&fiFolderInfo);
}
ZeroMemory(&fiFolderInfo, sizeof(fiFolderInfo));
fiFolderInfo.idParent = idServer;
fiFolderInfo.pszName = szSentItems;
fiFolderInfo.dwFlags = FOLDER_HIDDEN | FOLDER_SUBSCRIBED | FOLDER_CREATEONDEMAND;
fiFolderInfo.tySpecial = FOLDER_SENT;
fiFolderInfo.tyFolder = FOLDER_IMAP;
fiFolderInfo.bHierarchy = (BYTE)bHierarchy;
hr = g_pStore->CreateFolder(CREATE_FOLDER_LOCALONLY, &fiFolderInfo, NULL);
TraceError(hr);
}
if (dwIMAPSpecial && (dw & IMAP_DRAFTS_DIRTY) && FALSE == fSetDrafts && '\0' != szDrafts[0])
{
FOLDERINFO fiFolderInfo;
BOOL bHierarchy = 0xFF; // Invalid hierarchy char
hr = g_pStore->GetFolderInfo(idServer, &fiFolderInfo);
if (SUCCEEDED(hr))
{
bHierarchy = fiFolderInfo.bHierarchy;
g_pStore->FreeRecord(&fiFolderInfo);
}
ZeroMemory(&fiFolderInfo, sizeof(fiFolderInfo));
fiFolderInfo.idParent = idServer;
fiFolderInfo.pszName = szDrafts;
fiFolderInfo.dwFlags = FOLDER_HIDDEN | FOLDER_SUBSCRIBED | FOLDER_CREATEONDEMAND;
fiFolderInfo.tySpecial = FOLDER_DRAFT;
fiFolderInfo.tyFolder = FOLDER_IMAP;
fiFolderInfo.bHierarchy = (BYTE)bHierarchy;
hr = g_pStore->CreateFolder(CREATE_FOLDER_LOCALONLY, &fiFolderInfo, NULL);
TraceError(hr);
}
// Regardless of error, reset dirty flag
dw &= ~(IMAP_SENTITEMS_DIRTY | IMAP_DRAFTS_DIRTY);
} // if (dw & (IMAP_SENTITEMS_DIRTY | IMAP_DRAFTS_DIRTY))
AssertSz(0 == dw, "Unhandled IMAP dirty flag");
// Reset IMAP dirty property
hr = pAcct->SetPropDw(AP_IMAP_DIRTY, dw);
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
// Save changes
hr = pAcct->SaveChanges();
if (FAILED(hr))
{
TraceResult(hr);
goto exit;
}
exit:
if (NULL != pAcct)
pAcct->Release();
}
void CheckAllIMAPDirty(HWND hwndParent)
{
HRESULT hrResult;
IImnEnumAccounts *pAcctEnum = NULL;
IImnAccount *pAcct = NULL;
BOOL fPromptedUser = FALSE;
BOOL fPermissionToReset = FALSE;
TraceCall("CheckAllIMAPDirty");
if (NULL == g_pAcctMan)
return;
hrResult = g_pAcctMan->Enumerate(SRV_IMAP, &pAcctEnum);
if (FAILED(hrResult))
{
TraceResult(hrResult);
goto exit;
}
// Enumerate through ALL IMAP accounts (even if user denied permission to reset list)
hrResult = pAcctEnum->GetNext(&pAcct);
while(SUCCEEDED(hrResult))
{
DWORD dwIMAPDirty;
// Is this IMAP account dirty?
hrResult = pAcct->GetPropDw(AP_IMAP_DIRTY, &dwIMAPDirty);
if (FAILED(hrResult))
dwIMAPDirty = 0;
if (dwIMAPDirty & IMAP_FLDRLIST_DIRTY)
{
// Prompt user only once to see if he would like to refresh folder list
if (FALSE == fPromptedUser)
{
int iResult;
iResult = AthMessageBoxW(hwndParent, MAKEINTRESOURCEW(idsAthena),
MAKEINTRESOURCEW(idsYouMadeChangesOneOrMore),
MAKEINTRESOURCEW(idsRefreshFolderListPrompt),
MB_ICONEXCLAMATION | MB_YESNO);
if (IDYES == iResult)
fPermissionToReset = TRUE;
fPromptedUser = TRUE;
} // if (FALSE == fPromptedUser)
}
if (dwIMAPDirty)
{
FOLDERID idServer;
char szAccountID[CCHMAX_ACCOUNT_NAME];
hrResult = pAcct->GetPropSz(AP_ACCOUNT_ID, szAccountID, ARRAYSIZE(szAccountID));
TraceError(hrResult);
if (SUCCEEDED(hrResult))
{
hrResult = g_pStore->FindServerId(szAccountID, &idServer);
TraceError(hrResult);
if (SUCCEEDED(hrResult))
{
CheckIMAPDirty(szAccountID, hwndParent, idServer,
CID_NOPROMPT | (fPermissionToReset ? CID_RESETLISTOK : 0));
}
}
}
// Load in the next IMAP account
SafeRelease(pAcct);
hrResult = pAcctEnum->GetNext(&pAcct);
} // while
exit:
SafeRelease(pAcctEnum);
SafeRelease(pAcct);
}
void DoAccountListDialog(HWND hwnd, ACCTTYPE type)
{
ACCTLISTINFO ali;
// Create the monitor
if (NULL == g_pNewAcctMonitor)
g_pNewAcctMonitor = new CNewAcctMonitor();
if (g_pNewAcctMonitor)
g_pNewAcctMonitor->StartMonitor();
Assert(g_pAcctMan != NULL);
ali.cbSize = sizeof(ACCTLISTINFO);
ali.AcctTypeInit = type;
if (g_dwAthenaMode & MODE_NEWSONLY)
ali.dwAcctFlags = ACCT_FLAG_NEWS | ACCT_FLAG_DIR_SERV;
else if (g_dwAthenaMode & MODE_MAILONLY)
ali.dwAcctFlags = ACCT_FLAG_MAIL | ACCT_FLAG_DIR_SERV;
else
ali.dwAcctFlags = ACCT_FLAG_ALL;
ali.dwFlags = ACCTDLG_SHOWIMAPSPECIAL | ACCTDLG_OE;
//Account wizard uses this flag to distinguish between OE and outlook.
ali.dwFlags |= (ACCTDLG_INTERNETCONNECTION | ACCTDLG_HTTPMAIL);
// Revocation checking flag
if((DwGetOption(OPT_REVOKE_CHECK) != 0) && !g_pConMan->IsGlobalOffline())
ali.dwFlags |= ACCTDLG_REVOCATION;
g_pAcctMan->AccountListDialog(hwnd, &ali);
if (g_pNewAcctMonitor)
{
g_pNewAcctMonitor->StopMonitor(hwnd);
g_pNewAcctMonitor->Release();
g_pNewAcctMonitor = 0;
}
// Look for any dirty IMAP accounts
CheckAllIMAPDirty(hwnd);
}
HRESULT IsValidSendAccount(LPSTR pszAccount)
{
IImnAccount *pAccount;
DWORD dwSrvTypes=0;
if (g_pAcctMan &&
g_pAcctMan->FindAccount(AP_ACCOUNT_NAME, pszAccount, &pAccount)==S_OK)
{
pAccount->GetServerTypes(&dwSrvTypes);
pAccount->Release();
return dwSrvTypes & SRV_SMTP ? S_OK : S_FALSE;
}
return S_FALSE;
}
HRESULT AcctUtil_CreateSendReceieveMenu(HMENU hMenu, DWORD *pcItems)
{
IImnAccount *pAccount;
TCHAR szDefaultAccount[CCHMAX_ACCOUNT_NAME];
HRESULT hr;
IImnEnumAccounts *pEnum;
DWORD cAccounts = 0;
TCHAR szTitle[CCHMAX_ACCOUNT_NAME + 30];
TCHAR szAccountQuoted[CCHMAX_ACCOUNT_NAME + 60];
TCHAR szDefaultString[CCHMAX_STRINGRES];
TCHAR szAccount[CCHMAX_ACCOUNT_NAME];
TCHAR szTruncAcct[128];
MENUITEMINFO mii;
DWORD iAccount = 0;
LPTSTR pszAccount;
LPSTR pszAcctID;
// Get the default account's ID. If this fails we just go on.
if (SUCCEEDED(hr = g_pAcctMan->GetDefaultAccount(ACCT_MAIL, &pAccount)))
{
// Get the account ID from the default account
pAccount->GetPropSz(AP_ACCOUNT_NAME, szDefaultAccount, ARRAYSIZE(szDefaultAccount));
pAccount->Release();
}
if (!(g_dwAthenaMode & MODE_NEWSONLY))
{
// Enumerate through the servers
if (SUCCEEDED(hr = g_pAcctMan->Enumerate(SRV_SMTP | SRV_POP3 | SRV_HTTPMAIL, &pEnum)))
{
// Sort the accounts. If this fails, we just go on.
pEnum->SortByAccountName();
// Get the number of accounts we'll be enumerating
if (SUCCEEDED(hr = pEnum->GetCount(&cAccounts)))
{
// If there are zero accounts, there's nothing to do.
if (0 != cAccounts)
{
// Make sure we have enough ID's reserved for this
Assert(cAccounts < ID_ACCOUNT_LAST - ID_ACCOUNT_FIRST);
// Set this struct up before we start
ZeroMemory(&mii, sizeof(MENUITEMINFO));
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_DATA | MIIM_ID | MIIM_TYPE;
mii.fType = MFT_STRING;
// Loop through the accounts
while (SUCCEEDED(pEnum->GetNext(&pAccount)))
{
if (MemAlloc((LPVOID *) &pszAcctID, sizeof(TCHAR) * CCHMAX_ACCOUNT_NAME))
{
// Get the name of the account
pAccount->GetPropSz(AP_ACCOUNT_NAME, szAccount, CCHMAX_ACCOUNT_NAME);
pAccount->GetPropSz(AP_ACCOUNT_ID, pszAcctID, CCHMAX_ACCOUNT_NAME);
// If this account is the default account, we need to append
// "(Default)" to the end. Limit the string to 80 since Win95 seems
// to have some problems with really really long menus.
if (0 == lstrcmp(szAccount, szDefaultAccount))
{
AthLoadString(idsDefaultAccount, szDefaultString, ARRAYSIZE(szDefaultString));
StrCpyN(szTruncAcct, szAccount, 80);
wnsprintf(szTitle, ARRAYSIZE(szTitle), "%s %s", szTruncAcct, szDefaultString);
}
else
{
StrCpyN(szTitle, szAccount, 80);
}
// For account names with "&" characters like AT&T, we need to
// quote the "&".
PszEscapeMenuStringA(szTitle, szAccountQuoted, ARRAYSIZE(szAccountQuoted));
// Fill in the struct
mii.wID = ID_ACCOUNT_FIRST + iAccount;
mii.dwItemData = (DWORD_PTR) pszAcctID;
mii.dwTypeData = szAccountQuoted;
// Append the item
InsertMenuItem(hMenu, -1, TRUE, &mii);
// Increment the count
iAccount++;
}
// Release the account pointer
pAccount->Release();
}
}
}
// Release the enumerator
pEnum->Release();
Assert(iAccount == cAccounts);
}
}
else
{
//Remove Seperator in NEWSONLY mode.
int ItemCount;
ItemCount = GetMenuItemCount(hMenu);
if (ItemCount != -1)
{
DeleteMenu(hMenu, ItemCount - 1, MF_BYPOSITION);
}
}
//iAccount could be less than cAccounts if we are in news only mode.
if (pcItems)
*pcItems = cAccounts;
return (S_OK);
}
HRESULT AcctUtil_FreeSendReceieveMenu(HMENU hMenu, DWORD cItems)
{
DWORD i;
MENUITEMINFO mii;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_DATA;
for (i = 0; i < cItems; i++)
{
mii.dwItemData = 0;
if (GetMenuItemInfo(hMenu, ID_ACCOUNT_FIRST + i, FALSE, &mii))
{
if (mii.dwItemData)
MemFree((LPTSTR) mii.dwItemData);
DeleteMenu(hMenu, ID_ACCOUNT_FIRST + i, MF_BYCOMMAND);
}
}
return (S_OK);
}
HRESULT AcctUtil_CreateAccountManagerForIdentity(GUID *puidIdentity, IImnAccountManager2 **ppAccountManager)
{
HRESULT hr;
IImnAccountManager *pAccountManager = NULL;
IImnAccountManager2 *pAccountManager2 = NULL;
*ppAccountManager = NULL;
if (FAILED(hr = HrCreateAccountManager(&pAccountManager)))
goto exit;
if (FAILED(hr = pAccountManager->QueryInterface(IID_IImnAccountManager2, (LPVOID *)&pAccountManager2)))
goto exit;
// The *puidIdentity does not result in a new GUID object being created (formal param is by reference)
if (FAILED(hr = pAccountManager2->InitUser(NULL, *puidIdentity, 0)))
goto exit;
*ppAccountManager = pAccountManager2;
pAccountManager2 = NULL;
exit:
SafeRelease(pAccountManager);
SafeRelease(pAccountManager2);
return hr;
}
void InitNewAcctMenu(HMENU hmenu)
{
HKEY hkey, hkeyT;
LONG lResult;
DWORD cServices, cb, i, type, cItem, dwMsn;
char szKey[MAX_PATH], sz[512], szQuoted[512];
HMENU hsubmenu;
MENUITEMINFO mii;
LPSTR pszKey;
BOOL fHideHotmail = HideHotmail();
cItem = 0;
hsubmenu = NULL;
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szHTTPMailServiceRoot, 0, KEY_READ, &hkey))
{
if (ERROR_SUCCESS == RegQueryInfoKey(hkey, NULL, NULL, 0, &cServices, NULL, NULL, NULL, NULL, NULL, NULL, NULL) &&
cServices > 0)
{
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_DATA | MIIM_ID | MIIM_TYPE;
mii.fType = MFT_STRING;
hsubmenu = CreatePopupMenu();
if (hsubmenu != NULL)
{
// Start Enumerating the keys
for (i = 0; i < cServices; i++)
{
// Enumerate Friendly Names
cb = sizeof(szKey);
lResult = RegEnumKeyEx(hkey, i, szKey, &cb, 0, NULL, NULL, NULL);
// No more items
if (lResult == ERROR_NO_MORE_ITEMS)
break;
// Error, lets move onto the next account
if (lResult != ERROR_SUCCESS)
{
Assert(FALSE);
continue;
}
if (ERROR_SUCCESS == RegOpenKeyEx(hkey, szKey, 0, KEY_QUERY_VALUE, &hkeyT))
{
cb = sizeof(dwMsn);
if (!fHideHotmail ||
ERROR_SUCCESS != RegQueryValueEx(hkeyT, c_szHTTPMailDomainMSN, 0, NULL, (LPBYTE)&dwMsn, &cb) ||
dwMsn == 0)
{
cb = sizeof(sz);
if (ERROR_SUCCESS == RegQueryValueEx(hkeyT, c_szHTTPMailSignUp, NULL, &type, (LPBYTE)sz, &cb) &&
*sz != 0)
{
cb = sizeof(sz);
if (ERROR_SUCCESS == RegQueryValueEx(hkeyT, c_szHTTPMailServiceName, NULL, &type, (LPBYTE)sz, &cb) &&
*sz != 0)
{
pszKey = PszDup(szKey);
if (pszKey != NULL)
{
PszEscapeMenuStringA(sz, szQuoted, ARRAYSIZE(szQuoted));
// Fill in the struct
mii.wID = ID_NEW_ACCT_FIRST + cItem;
mii.dwItemData = (DWORD_PTR)pszKey;
mii.dwTypeData = szQuoted;
// Append the item
InsertMenuItem(hsubmenu, -1, TRUE, &mii);
cItem++;
}
}
}
}
RegCloseKey(hkeyT);
}
}
}
}
RegCloseKey(hkey);
}
if (cItem == 0)
{
if (hsubmenu != NULL)
DestroyMenu(hsubmenu);
DeleteMenu(hmenu, ID_POPUP_NEW_ACCT, MF_BYCOMMAND);
}
else
{
Assert(hsubmenu != NULL);
mii.fMask = MIIM_SUBMENU;
mii.hSubMenu = hsubmenu;
SetMenuItemInfo(hmenu, ID_POPUP_NEW_ACCT, FALSE, &mii);
}
}
void FreeNewAcctMenu(HMENU hmenu)
{
int i, cItem;
MENUITEMINFO mii;
HMENU hsubmenu;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_SUBMENU;
mii.hSubMenu = NULL;
if (GetMenuItemInfo(hmenu, ID_POPUP_NEW_ACCT, FALSE, &mii) &&
mii.hSubMenu != NULL)
{
hsubmenu = mii.hSubMenu;
cItem = GetMenuItemCount(hsubmenu);
mii.fMask = MIIM_DATA;
for (i = 0; i < cItem; i++)
{
mii.dwItemData = 0;
if (GetMenuItemInfo(hsubmenu, ID_NEW_ACCT_FIRST + i, FALSE, &mii))
{
if (mii.dwItemData)
MemFree((LPSTR)mii.dwItemData);
}
}
DestroyMenu(hsubmenu);
}
}
HRESULT HandleNewAcctMenu(HWND hwnd, HMENU hmenu, int id)
{
MENUITEMINFO mii;
char szKey[MAX_PATH], szUrl[512];
HKEY hkey;
DWORD type, cb, dwUseWizard;
TCHAR rgch[MAX_PATH];
BOOL bFoundUrl = TRUE;
mii.cbSize = sizeof(MENUITEMINFO);
mii.fMask = MIIM_DATA|MIIM_TYPE;
mii.dwItemData = 0;
mii.dwTypeData = rgch;
mii.cch = ARRAYSIZE(rgch);
if (GetMenuItemInfo(hmenu, id, FALSE, &mii) && mii.dwItemData != 0)
{
wnsprintf(szKey, ARRAYSIZE(szKey), c_szPathFileFmt, c_szHTTPMailServiceRoot, (LPSTR)mii.dwItemData);
if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, &hkey))
{
// look for a config url
cb = sizeof(szUrl);
if (ERROR_SUCCESS != RegQueryValueEx(hkey, c_szHTTPMailConfig, NULL, &type, (LPBYTE)szUrl, &cb))
{
// config url wasn't found. fall back to sign up url
cb = sizeof(szUrl);
if (ERROR_SUCCESS != RegQueryValueEx(hkey, c_szHTTPMailSignUp, NULL, &type, (LPBYTE)szUrl, &cb))
bFoundUrl = FALSE;
}
if (bFoundUrl)
{
cb = sizeof(DWORD);
if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szHTTPMailUseWizard, NULL, &type, (LPBYTE)&dwUseWizard, &cb) &&
dwUseWizard != 0)
DoHotMailWizard(GetTopMostParent(hwnd), szUrl, rgch, NULL, NULL);
else
ShellExecute(hwnd, "open", szUrl, NULL, NULL, SW_SHOWNORMAL);
}
RegCloseKey(hkey);
}
}
return(S_OK);
}