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

  1. // --------------------------------------------------------------------------------
  2. // Acctutil.cpp
  3. // Copyright (c)1993-1995 Microsoft Corporation, All Rights Reserved
  4. // Steven J. Bailey
  5. // --------------------------------------------------------------------------------
  6. #include "pch.hxx"
  7. #include "goptions.h"
  8. #include "imnact.h"
  9. #include "acctutil.h"
  10. #include "strconst.h"
  11. #include "error.h"
  12. #include "resource.h"
  13. #include <storfldr.h>
  14. #include <notify.h>
  15. #include "conman.h"
  16. #include "shlwapip.h"
  17. #include "browser.h"
  18. #include "instance.h"
  19. #include "menures.h"
  20. #include "subscr.h"
  21. #include "msident.h"
  22. #include "acctcach.h"
  23. #include <demand.h> // must be last!
  24. CNewAcctMonitor *g_pNewAcctMonitor = NULL;
  25. HRESULT IsValidSendAccount(LPSTR pszAccount);
  26. CImnAdviseAccount::CImnAdviseAccount(void)
  27. {
  28. m_cRef = 1;
  29. m_pNotify = NULL;
  30. }
  31. CImnAdviseAccount::~CImnAdviseAccount(void)
  32. {
  33. if (m_pNotify != NULL)
  34. m_pNotify->Release();
  35. }
  36. HRESULT CImnAdviseAccount::Initialize()
  37. {
  38. HRESULT hr;
  39. hr = CreateNotify(&m_pNotify);
  40. if (SUCCEEDED(hr))
  41. hr = m_pNotify->Initialize((TCHAR *)c_szMailFolderNotify);
  42. return(hr);
  43. }
  44. STDMETHODIMP CImnAdviseAccount::QueryInterface(REFIID riid, LPVOID *ppv)
  45. {
  46. // Locals
  47. HRESULT hr=S_OK;
  48. // Bad param
  49. if (ppv == NULL)
  50. {
  51. hr = TRAPHR(E_INVALIDARG);
  52. goto exit;
  53. }
  54. // Init
  55. *ppv=NULL;
  56. // IID_IImnAccountManager
  57. if (IID_IImnAdviseAccount == riid)
  58. *ppv = (IImnAdviseAccount *)this;
  59. // IID_IUnknown
  60. else if (IID_IUnknown == riid)
  61. *ppv = (IUnknown *)this;
  62. // If not null, addref it and return
  63. if (NULL!=*ppv)
  64. {
  65. ((LPUNKNOWN)*ppv)->AddRef();
  66. goto exit;
  67. }
  68. // No Interface
  69. hr = TRAPHR(E_NOINTERFACE);
  70. exit:
  71. // Done
  72. return hr;
  73. }
  74. STDMETHODIMP_(ULONG) CImnAdviseAccount::AddRef(void)
  75. {
  76. return ++m_cRef;
  77. }
  78. STDMETHODIMP_(ULONG) CImnAdviseAccount::Release(void)
  79. {
  80. if (0 != --m_cRef)
  81. return m_cRef;
  82. delete this;
  83. return 0;
  84. }
  85. STDMETHODIMP CImnAdviseAccount::AdviseAccount(DWORD dwAdviseType, ACTX *pactx)
  86. {
  87. Assert(pactx != NULL);
  88. if (pactx->AcctType == ACCT_DIR_SERV)
  89. return(S_OK);
  90. if (g_pBrowser)
  91. g_pBrowser->AccountsChanged();
  92. if (dwAdviseType == AN_DEFAULT_CHANGED)
  93. return(S_OK);
  94. HandleAccountChange(pactx->AcctType, dwAdviseType, pactx->pszAccountID, pactx->pszOldName, pactx->dwServerType);
  95. if (g_pNewAcctMonitor != NULL)
  96. g_pNewAcctMonitor->OnAdvise(pactx->AcctType, dwAdviseType, pactx->pszAccountID);
  97. // No matter what the notification, we need to tell the connection manager
  98. if (g_pConMan)
  99. g_pConMan->AdviseAccount(dwAdviseType, pactx);
  100. return S_OK;
  101. }
  102. void CImnAdviseAccount::HandleAccountChange(ACCTTYPE AcctType, DWORD dwAN, LPTSTR pszID, LPTSTR pszOldName, DWORD dwSrvTypesOld)
  103. {
  104. HRESULT hr;
  105. IImnAccount *pAccount;
  106. char szName[CCHMAX_ACCOUNT_NAME];
  107. FOLDERID id;
  108. Assert(pszID != NULL);
  109. switch (dwAN)
  110. {
  111. case AN_ACCOUNT_DELETED:
  112. AccountCache_AccountDeleted(pszID);
  113. if (!!(dwSrvTypesOld & (SRV_IMAP | SRV_NNTP | SRV_HTTPMAIL)))
  114. {
  115. hr = g_pStore->FindServerId(pszID, &id);
  116. if (SUCCEEDED(hr))
  117. {
  118. HCURSOR hCursor = SetCursor(LoadCursor(NULL, IDC_WAIT));
  119. hr = g_pStore->DeleteFolder(id, DELETE_FOLDER_RECURSIVE | DELETE_FOLDER_NOTRASHCAN, (IStoreCallback *)g_pBrowser);
  120. Assert(SUCCEEDED(hr));
  121. SetCursor(hCursor);
  122. }
  123. }
  124. if (g_pBrowser != NULL)
  125. g_pBrowser->UpdateToolbar();
  126. break;
  127. case AN_ACCOUNT_ADDED:
  128. if (SUCCEEDED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszID, &pAccount)))
  129. {
  130. hr = g_pStore->CreateServer(pAccount, NOFLAGS, &id);
  131. Assert(SUCCEEDED(hr));
  132. if (g_pBrowser != NULL)
  133. g_pBrowser->UpdateToolbar();
  134. pAccount->Release();
  135. }
  136. break;
  137. case AN_ACCOUNT_CHANGED:
  138. AccountCache_AccountChanged(pszID);
  139. if (pszOldName != NULL)
  140. {
  141. hr = g_pStore->FindServerId(pszID, &id);
  142. if (SUCCEEDED(hr))
  143. {
  144. if (SUCCEEDED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszID, &pAccount)))
  145. {
  146. hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, szName, ARRAYSIZE(szName));
  147. Assert(SUCCEEDED(hr));
  148. hr = g_pStore->RenameFolder(id, szName, NOFLAGS, NOSTORECALLBACK);
  149. Assert(SUCCEEDED(hr));
  150. pAccount->Release();
  151. }
  152. }
  153. }
  154. break;
  155. }
  156. }
  157. // -----------------------------------------------------------------------------
  158. // AcctUtil_HrCreateAccountMenu
  159. // -----------------------------------------------------------------------------
  160. #define CCHMAX_RES 255
  161. HRESULT AcctUtil_HrCreateAccountMenu(ACCOUNTMENUTYPE type, HMENU hPopup, UINT uidmPopup,
  162. HMENU *phAccounts, LPACCTMENU *pprgAccount, ULONG *pcAccounts, LPSTR pszThisAccount, BOOL fMail)
  163. {
  164. // Locals
  165. HRESULT hr=S_OK;
  166. ULONG cAccounts=0;
  167. IImnEnumAccounts *pEnum=NULL;
  168. IImnAccount *pAccount=NULL;
  169. CHAR szDefault[CCHMAX_ACCOUNT_NAME];
  170. CHAR szAccount[CCHMAX_ACCOUNT_NAME];
  171. CHAR szQuoted[CCHMAX_ACCOUNT_NAME + CCHMAX_ACCOUNT_NAME + CCHMAX_RES];
  172. LPACCTMENU prgAccount=NULL;
  173. HMENU hAccounts=NULL;
  174. MENUITEMINFO mii;
  175. UINT uPos=0;
  176. ULONG iAccount=0;
  177. CHAR szRes[CCHMAX_RES];
  178. CHAR szRes1[CCHMAX_RES];
  179. CHAR szRes2[CCHMAX_RES];
  180. UINT idmFirst;
  181. CHAR szTitle[CCHMAX_RES + CCHMAX_RES + CCHMAX_ACCOUNT_NAME];
  182. BOOL fNeedUsingMenu = FALSE;
  183. // Check Parameters
  184. Assert(g_pAcctMan && phAccounts && pprgAccount && pcAccounts);
  185. // Init
  186. *szDefault = '\0';
  187. *pprgAccount = NULL;
  188. *pcAccounts = 0;
  189. *phAccounts = NULL;
  190. if (type == ACCTMENU_SENDLATER)
  191. idmFirst = ID_SEND_LATER_ACCOUNT_FIRST;
  192. else
  193. idmFirst = ID_SEND_NOW_ACCOUNT_FIRST;
  194. // Verify Default SMTP Account
  195. CHECKHR(hr = g_pAcctMan->ValidateDefaultSendAccount());
  196. // Get the default
  197. CHECKHR(hr = hr = g_pAcctMan->GetDefaultAccountName(ACCT_MAIL, szDefault, ARRAYSIZE(szDefault)));
  198. // Enumerate through the server types
  199. CHECKHR(hr = g_pAcctMan->Enumerate(((ACCTMENU_SEND == type || ACCTMENU_SENDLATER == type) ? SRV_SMTP : SRV_SMTP | SRV_POP3), &pEnum));
  200. // sort the accoutns
  201. CHECKHR(hr = pEnum->SortByAccountName());
  202. // Get Count
  203. CHECKHR(hr = pEnum->GetCount(&cAccounts));
  204. // No Accounts
  205. if (cAccounts == 0)
  206. goto exit;
  207. // Exceeded menu ids...
  208. Assert(cAccounts <= 50);
  209. // Add one if ACCTMENU_SENDRECV
  210. if (ACCTMENU_SENDRECV == type)
  211. cAccounts++;
  212. // Allocate prgAccount
  213. CHECKALLOC(prgAccount = (LPACCTMENU)g_pMalloc->Alloc(cAccounts * sizeof(ACCTMENU)));
  214. // Zero Init
  215. ZeroMemory(prgAccount, cAccounts * sizeof(ACCTMENU));
  216. // Only one account
  217. if (((ACCTMENU_SENDRECV == type) && (cAccounts == 2)) ||
  218. (cAccounts == 1) || !fMail)
  219. {
  220. // Return default Account
  221. prgAccount[iAccount].fDefault = TRUE;
  222. prgAccount[iAccount].fThisAccount = TRUE;
  223. StrCpyN(prgAccount[iAccount].szAccount, szDefault, ARRAYSIZE(prgAccount[iAccount].szAccount));
  224. // Return Everything
  225. *pprgAccount = prgAccount;
  226. prgAccount = NULL;
  227. *pcAccounts = cAccounts;
  228. // Done
  229. goto exit;
  230. }
  231. // Create a Menu
  232. CHECKALLOC(hAccounts = CreatePopupMenu());
  233. // if not using a specific account or the account is illegal, then let's default to the default-account
  234. if (pszThisAccount==NULL || *pszThisAccount == NULL || IsValidSendAccount(pszThisAccount)!=S_OK)
  235. pszThisAccount = szDefault;
  236. // Lets insert the default item
  237. if ((ACCTMENU_SENDLATER == type || ACCTMENU_SEND == type) && !FIsEmptyA(szDefault))
  238. {
  239. // Load String
  240. StrCpyN(szTitle, pszThisAccount, ARRAYSIZE(szTitle));
  241. prgAccount[iAccount].fDefault = lstrcmpi(pszThisAccount, szDefault)==0;
  242. // if this is the default, flag it.
  243. if (prgAccount[iAccount].fDefault)
  244. {
  245. AthLoadString(idsDefaultAccount, szRes1, ARRAYSIZE(szRes1));
  246. StrCatBuff(szTitle, " ", ARRAYSIZE(szTitle));
  247. StrCatBuff(szTitle, szRes1, ARRAYSIZE(szTitle));
  248. }
  249. if (((ACCTMENU_SEND == type && DwGetOption(OPT_SENDIMMEDIATE) && !g_pConMan->IsGlobalOffline()) ||
  250. (ACCTMENU_SENDLATER == type && (!DwGetOption(OPT_SENDIMMEDIATE) || g_pConMan->IsGlobalOffline()))))
  251. {
  252. // if this menu is the default action add the 'Alt+S' accelerator string
  253. AthLoadString(idsSendMsgAccelTip, szRes, ARRAYSIZE(szRes));
  254. StrCatBuff(szTitle, "\t", ARRAYSIZE(szTitle));
  255. StrCatBuff(szTitle, szRes, ARRAYSIZE(szTitle));
  256. }
  257. // Get mii ready
  258. ZeroMemory(&mii, sizeof(mii));
  259. mii.cbSize = sizeof(mii);
  260. mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID;
  261. mii.fType = MFT_STRING;
  262. mii.fState = MFS_DEFAULT; // first item is the default verb
  263. mii.dwTypeData = PszEscapeMenuStringA(szTitle, szQuoted, sizeof(szQuoted) / sizeof(char));
  264. mii.cch = lstrlen(szQuoted);
  265. mii.wID = idmFirst + uPos;
  266. // Set acctmenu item
  267. prgAccount[iAccount].fThisAccount= TRUE;
  268. prgAccount[iAccount].uidm = mii.wID;
  269. StrCpyN(prgAccount[iAccount].szAccount, pszThisAccount, ARRAYSIZE(prgAccount[iAccount].szAccount));
  270. iAccount++;
  271. // Insert the item
  272. if (InsertMenuItem(hAccounts, uPos, TRUE, &mii))
  273. {
  274. uPos++;
  275. mii.fMask = MIIM_TYPE;
  276. mii.fType = MFT_SEPARATOR;
  277. if (InsertMenuItem(hAccounts, uPos, TRUE, &mii))
  278. uPos++;
  279. }
  280. }
  281. // Otherwise Send & Receive
  282. else if (ACCTMENU_SENDRECV == type)
  283. {
  284. // Setup Menu
  285. ZeroMemory(&mii, sizeof(mii));
  286. mii.cbSize = sizeof(mii);
  287. mii.fMask = MIIM_TYPE | MIIM_STATE | MIIM_ID;
  288. mii.fType = MFT_STRING;
  289. mii.fState = MFS_DEFAULT;
  290. AthLoadString(idsPollAllAccounts, szRes, ARRAYSIZE(szRes));
  291. mii.dwTypeData = szRes;
  292. mii.cch = lstrlen(szRes);
  293. mii.wID = idmFirst + uPos;
  294. // Set acctmenu item
  295. prgAccount[iAccount].fDefault = TRUE;
  296. prgAccount[iAccount].uidm = mii.wID;
  297. *prgAccount[iAccount].szAccount = '\0';
  298. iAccount++;
  299. // Insert the item
  300. if (InsertMenuItem(hAccounts, uPos, TRUE, &mii))
  301. {
  302. uPos++;
  303. mii.fMask = MIIM_TYPE;
  304. mii.fType = MFT_SEPARATOR;
  305. if (InsertMenuItem(hAccounts, uPos, TRUE, &mii))
  306. uPos++;
  307. }
  308. }
  309. // Standard
  310. ZeroMemory(&mii, sizeof(mii));
  311. mii.cbSize = sizeof(mii);
  312. mii.fMask = MIIM_TYPE | MIIM_ID;
  313. mii.fType = MFT_STRING;
  314. // Loop accounts
  315. while(SUCCEEDED(pEnum->GetNext(&pAccount)))
  316. {
  317. // Get Account Name
  318. CHECKHR(hr = pAccount->GetPropSz(AP_ACCOUNT_NAME, szAccount, ARRAYSIZE(szAccount)));
  319. // Skip the 'This' account. Note for the send & receive menu this will always be the default
  320. if (lstrcmpi(pszThisAccount, szAccount) == 0)
  321. {
  322. // We've already added this account
  323. if (ACCTMENU_SEND == type || ACCTMENU_SENDLATER == type)
  324. {
  325. SafeRelease(pAccount);
  326. continue;
  327. }
  328. // Otherwise, Account (Default)
  329. else
  330. {
  331. // for send a recieve menu pszThisAccount should == szDefault
  332. Assert (pszThisAccount == szDefault);
  333. // Load String
  334. AthLoadString(idsDefaultAccount, szRes, ARRAYSIZE(szRes));
  335. // Make String - Saranac (Default)
  336. wnsprintf(szTitle, ARRAYSIZE(szTitle), "%s %s", szAccount, szRes);
  337. // Setup the menu item name
  338. mii.dwTypeData = PszEscapeMenuStringA(szTitle, szQuoted, sizeof(szQuoted) / sizeof(char));
  339. mii.cch = lstrlen(szQuoted);
  340. prgAccount[iAccount].fDefault = TRUE;
  341. }
  342. }
  343. else
  344. {
  345. *szTitle=0;
  346. // this might be the default
  347. prgAccount[iAccount].fDefault = lstrcmpi(szAccount, szDefault)==0;
  348. // build the string on the fly as any one of these accounts might be the 'default'
  349. PszEscapeMenuStringA(szAccount, szTitle, sizeof(szTitle) / sizeof(char));
  350. // if this is the default, flag it.
  351. if (prgAccount[iAccount].fDefault)
  352. {
  353. AthLoadString(idsDefaultAccount, szRes1, ARRAYSIZE(szRes1));
  354. StrCatBuff(szTitle, " ", ARRAYSIZE(szTitle));
  355. StrCatBuff(szTitle, szRes1, ARRAYSIZE(szTitle));
  356. }
  357. // Setup the menu item name
  358. mii.dwTypeData = szTitle;
  359. mii.cch = lstrlen(szTitle);
  360. }
  361. // Insert into menu
  362. mii.wID = idmFirst + uPos;
  363. if (InsertMenuItem(hAccounts, uPos, TRUE, &mii))
  364. uPos++;
  365. // Set acctmenu item
  366. Assert(iAccount < cAccounts);
  367. prgAccount[iAccount].uidm = mii.wID;
  368. StrCpyN(prgAccount[iAccount].szAccount, szAccount, ARRAYSIZE(prgAccount[iAccount].szAccount));
  369. iAccount++;
  370. // Release Account
  371. SafeRelease(pAccount);
  372. }
  373. // Return Everything
  374. *phAccounts = hAccounts;
  375. hAccounts = NULL;
  376. *pprgAccount = prgAccount;
  377. prgAccount = NULL;
  378. *pcAccounts = cAccounts;
  379. exit:
  380. // Lets Setup the Accounts Menu
  381. ZeroMemory(&mii, sizeof(mii));
  382. mii.cbSize = sizeof(MENUITEMINFO);
  383. fNeedUsingMenu = (cAccounts <= 1) || !fMail;
  384. if (ACCTMENU_SEND == type)
  385. {
  386. mii.fMask = MIIM_SUBMENU | MIIM_TYPE;
  387. if (fNeedUsingMenu)
  388. {
  389. AthLoadString(idsSendMsgOneAccount, szRes, ARRAYSIZE(szRes));
  390. AthLoadString(idsSendMsgAccelTip, szRes1, ARRAYSIZE(szRes1));
  391. // If send now is default, add the Alt + S at the end
  392. if (DwGetOption(OPT_SENDIMMEDIATE) && !g_pConMan->IsGlobalOffline())
  393. wnsprintf(szTitle, ARRAYSIZE(szTitle), "%s\t%s", szRes, szRes1);
  394. else
  395. wnsprintf(szTitle, ARRAYSIZE(szTitle), "%s", szRes);
  396. }
  397. else
  398. AthLoadString(idsSendMsgUsing, szTitle, ARRAYSIZE(szTitle));
  399. mii.fType = MFT_STRING;
  400. mii.dwTypeData = szTitle;
  401. mii.cch = lstrlen(szTitle);
  402. mii.hSubMenu = fNeedUsingMenu ? NULL : *phAccounts;
  403. }
  404. else if (ACCTMENU_SENDLATER == type)
  405. {
  406. if (fNeedUsingMenu)
  407. {
  408. AthLoadString(idsSendLaterOneAccount, szRes, ARRAYSIZE(szRes));
  409. AthLoadString(idsSendMsgAccelTip, szRes1, ARRAYSIZE(szRes1));
  410. // If send now is default, add the Alt + S at the end
  411. if (!DwGetOption(OPT_SENDIMMEDIATE) || g_pConMan->IsGlobalOffline())
  412. wnsprintf(szTitle, ARRAYSIZE(szTitle), "%s\t%s", szRes, szRes1);
  413. else
  414. wnsprintf(szTitle, ARRAYSIZE(szTitle), "%s", szRes);
  415. }
  416. else
  417. AthLoadString(idsSendLaterUsing, szTitle, ARRAYSIZE(szTitle));
  418. mii.fMask = MIIM_SUBMENU | MIIM_TYPE;
  419. mii.fType = MFT_STRING;
  420. mii.dwTypeData = szTitle;
  421. mii.cch = lstrlen(szTitle);
  422. mii.hSubMenu = fNeedUsingMenu ? NULL : *phAccounts;
  423. }
  424. else
  425. {
  426. mii.fMask = MIIM_SUBMENU | MIIM_TYPE;
  427. AthLoadString(fNeedUsingMenu ? idsSendRecvOneAccount : idsSendRecvUsing, szRes, ARRAYSIZE(szRes));
  428. mii.fType = MFT_STRING;
  429. mii.dwTypeData = szRes;
  430. mii.cch = lstrlen(szRes);
  431. mii.hSubMenu = fNeedUsingMenu ? NULL : *phAccounts;
  432. }
  433. // Set the menu item
  434. SideAssert(SetMenuItemInfo(hPopup, uidmPopup, FALSE, &mii));
  435. // Cleanup
  436. SafeRelease(pEnum);
  437. SafeRelease(pAccount);
  438. SafeMemFree(prgAccount);
  439. if (hAccounts)
  440. DestroyMenu(hAccounts);
  441. // Done
  442. return hr;
  443. }
  444. HRESULT AcctUtil_GetServerCount(DWORD dwSrvTypes, DWORD *pcSrv)
  445. {
  446. HRESULT hr;
  447. IImnEnumAccounts *pEnum;
  448. Assert(dwSrvTypes != 0);
  449. Assert(pcSrv != NULL);
  450. hr = g_pAcctMan->Enumerate(dwSrvTypes, &pEnum);
  451. if (SUCCEEDED(hr))
  452. {
  453. hr = pEnum->GetCount(pcSrv);
  454. Assert(SUCCEEDED(hr));
  455. pEnum->Release();
  456. }
  457. return(hr);
  458. }
  459. /////////////////////////////////////////////////////////////////////////////
  460. // CNewAcctMonitor
  461. //
  462. CNewAcctMonitor::CNewAcctMonitor()
  463. {
  464. m_cRef = 1;
  465. m_rgAccounts = NULL;
  466. m_cAlloc = 0;
  467. m_cAccounts = 0;
  468. m_fMonitor = FALSE;
  469. }
  470. CNewAcctMonitor::~CNewAcctMonitor()
  471. {
  472. Assert(m_rgAccounts == NULL);
  473. }
  474. ULONG CNewAcctMonitor::AddRef(void)
  475. {
  476. return (++m_cRef);
  477. }
  478. ULONG CNewAcctMonitor::Release(void)
  479. {
  480. ULONG cRefT = --m_cRef;
  481. if (0 == m_cRef)
  482. delete this;
  483. return (cRefT);
  484. }
  485. void CNewAcctMonitor::OnAdvise(ACCTTYPE atType, DWORD dwNotify, LPCSTR pszAcctId)
  486. {
  487. UINT i;
  488. IImnAccount *pAccount;
  489. DWORD dwSrvTypes;
  490. HRESULT hr;
  491. FOLDERTYPE type;
  492. if (atType == ACCT_DIR_SERV)
  493. return;
  494. switch (dwNotify)
  495. {
  496. case AN_ACCOUNT_ADDED:
  497. if (atType == ACCT_MAIL)
  498. {
  499. if (FAILED(g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAcctId, &pAccount)))
  500. break;
  501. hr = pAccount->GetServerTypes(&dwSrvTypes);
  502. Assert(SUCCEEDED(hr));
  503. pAccount->Release();
  504. if (!!(dwSrvTypes & SRV_IMAP))
  505. type = FOLDER_IMAP;
  506. else if (!!(dwSrvTypes & SRV_HTTPMAIL))
  507. type = FOLDER_HTTPMAIL;
  508. else
  509. break;
  510. }
  511. else
  512. {
  513. Assert(atType == ACCT_NEWS);
  514. type = FOLDER_NEWS;
  515. }
  516. // Check to see if we need to grow our array
  517. if ((1 + m_cAccounts) >= m_cAlloc)
  518. {
  519. if (!MemRealloc((LPVOID *)&m_rgAccounts, sizeof(NEWACCTINFO) * (10 + m_cAlloc)))
  520. break;
  521. m_cAlloc += 10;
  522. }
  523. m_rgAccounts[m_cAccounts].pszAcctId = PszDupA(pszAcctId);
  524. m_rgAccounts[m_cAccounts].type = type;
  525. m_cAccounts++;
  526. break;
  527. case AN_ACCOUNT_DELETED:
  528. // Check to see if we've already added this to our list.
  529. for (i = 0; i < m_cAccounts; i++)
  530. {
  531. if (0 == lstrcmpi(pszAcctId, m_rgAccounts[i].pszAcctId))
  532. {
  533. // We found it. We need to remove it, and adjust our array
  534. MemFree(m_rgAccounts[i].pszAcctId);
  535. m_cAccounts--;
  536. for (; i < m_cAccounts; i++)
  537. m_rgAccounts[i] = m_rgAccounts[i + 1];
  538. break;
  539. }
  540. }
  541. break;
  542. }
  543. }
  544. void CNewAcctMonitor::StartMonitor(void)
  545. {
  546. Assert(m_rgAccounts == NULL);
  547. Assert(m_cAccounts == NULL);
  548. Assert(m_fMonitor == FALSE);
  549. m_fMonitor = TRUE;
  550. }
  551. void CNewAcctMonitor::StopMonitor(HWND hwndParent)
  552. {
  553. FOLDERID id;
  554. HRESULT hr;
  555. UINT i;
  556. Assert(m_fMonitor == TRUE);
  557. // If we have any new newsgroups left, ask if the user want's to display
  558. // the subscription dialog.
  559. if (m_cAccounts != 0)
  560. {
  561. int ResId;
  562. BOOL fOffline = (g_pConMan && g_pConMan->IsGlobalOffline());
  563. if (m_rgAccounts[0].type == FOLDER_NEWS)
  564. {
  565. ResId = fOffline ? idsDisplayNewsSubDlgOffline : idsDisplayNewsSubDlg;
  566. }
  567. else
  568. {
  569. ResId = fOffline ? idsDisplayImapSubDlgOffline : idsDisplayImapSubDlg;
  570. }
  571. if (IDYES == AthMessageBoxW(hwndParent, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(ResId), 0, MB_ICONEXCLAMATION | MB_YESNO))
  572. {
  573. hr = g_pStore->FindServerId(m_rgAccounts[0].pszAcctId, &id);
  574. if (SUCCEEDED(hr))
  575. {
  576. if (fOffline)
  577. g_pConMan->SetGlobalOffline(FALSE);
  578. if (FOLDER_HTTPMAIL == m_rgAccounts[0].type)
  579. DownloadNewsgroupList(hwndParent, id);
  580. else
  581. DoSubscriptionDialog(hwndParent, m_rgAccounts[0].type == FOLDER_NEWS, id);
  582. }
  583. }
  584. }
  585. for (i = 0; i < m_cAccounts; i++)
  586. {
  587. if (m_rgAccounts[i].pszAcctId != NULL)
  588. MemFree(m_rgAccounts[i].pszAcctId);
  589. }
  590. m_cAccounts = 0;
  591. m_cAlloc = 0;
  592. SafeMemFree(m_rgAccounts);
  593. m_fMonitor = FALSE;
  594. }
  595. void CheckIMAPDirty(LPSTR pszAccountID, HWND hwndParent, FOLDERID idServer,
  596. DWORD dwFlags)
  597. {
  598. HRESULT hr;
  599. IImnAccount *pAcct = NULL;
  600. DWORD dw;
  601. TraceCall("CheckIMAPDirty");
  602. hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, pszAccountID, &pAcct);
  603. if (FAILED(hr))
  604. {
  605. TraceResult(hr);
  606. goto exit;
  607. }
  608. hr = pAcct->GetPropDw(AP_IMAP_DIRTY, &dw);
  609. if (FAILED(hr) || 0 == dw)
  610. {
  611. TraceError(hr);
  612. goto exit;
  613. }
  614. // IMAP is dirty, deal with each dirty flag
  615. if ((dw & IMAP_OE4MIGRATE_DIRTY) && FOLDERID_INVALID != idServer && NULL != g_pStore)
  616. {
  617. IEnumerateFolders *pEnum;
  618. BOOL fSentItems = FALSE;
  619. BOOL fDrafts = FALSE;
  620. BOOL fInbox = FALSE;
  621. Assert(0 == (dw & IMAP_OE4MIGRATE_DIRTY) || (dw & IMAP_FLDRLIST_DIRTY));
  622. // We may or may not be dirty. Check if all IMAP special fldrs already present
  623. hr = g_pStore->EnumChildren(idServer, FALSE, &pEnum);
  624. TraceError(hr);
  625. if (SUCCEEDED(hr))
  626. {
  627. FOLDERINFO fiFolderInfo;
  628. while (S_OK == pEnum->Next(1, &fiFolderInfo, NULL))
  629. {
  630. switch (fiFolderInfo.tySpecial)
  631. {
  632. case FOLDER_INBOX:
  633. fInbox = TRUE;
  634. break;
  635. case FOLDER_SENT:
  636. fSentItems = TRUE;
  637. break;
  638. case FOLDER_DRAFT:
  639. fDrafts = TRUE;
  640. break;
  641. }
  642. g_pStore->FreeRecord(&fiFolderInfo);
  643. }
  644. pEnum->Release();
  645. }
  646. if (fInbox && fSentItems && fDrafts)
  647. {
  648. // All special folders present: remove dirty flags
  649. dw &= ~(IMAP_FLDRLIST_DIRTY | IMAP_OE4MIGRATE_DIRTY);
  650. }
  651. }
  652. if (dw & IMAP_FLDRLIST_DIRTY)
  653. {
  654. int iResult;
  655. // Ask user if he would like to reset his folderlist
  656. if (0 == (dwFlags & CID_NOPROMPT))
  657. {
  658. UINT uiReasonStrID;
  659. AssertSz(0 == (dwFlags & CID_RESETLISTOK), "If I have permission to reset, why prompt?");
  660. // Figure out why we are asking to refresh the folderlist
  661. if (dw & IMAP_OE4MIGRATE_DIRTY)
  662. uiReasonStrID = idsOE5IMAPSpecialFldrs;
  663. else
  664. uiReasonStrID = idsYouMadeChanges;
  665. iResult = AthMessageBoxW(hwndParent, MAKEINTRESOURCEW(idsAthena),
  666. MAKEINTRESOURCEW(uiReasonStrID), MAKEINTRESOURCEW(idsRefreshFolderListPrompt),
  667. MB_ICONEXCLAMATION | MB_YESNO);
  668. }
  669. else
  670. iResult = (dwFlags & CID_RESETLISTOK) ? IDYES : IDNO;
  671. if (IDYES == iResult)
  672. {
  673. if (FOLDERID_INVALID == idServer)
  674. {
  675. hr = g_pStore->FindServerId(pszAccountID, &idServer);
  676. TraceError(hr);
  677. }
  678. if (FOLDERID_INVALID != idServer)
  679. {
  680. //The user wants to download the list of newsgroups, so if we are offline, go online
  681. if (g_pConMan)
  682. g_pConMan->SetGlobalOffline(FALSE);
  683. hr = DownloadNewsgroupList(hwndParent, idServer);
  684. TraceError(hr);
  685. if (SUCCEEDED(hr))
  686. {
  687. // The sent items and drafts folders should not be dirty any longer
  688. dw &= ~(IMAP_SENTITEMS_DIRTY | IMAP_DRAFTS_DIRTY);
  689. }
  690. }
  691. }
  692. // Regardless of yes or no, reset dirty flag
  693. dw &= ~(IMAP_FLDRLIST_DIRTY | IMAP_OE4MIGRATE_DIRTY);
  694. }
  695. if (dw & (IMAP_SENTITEMS_DIRTY | IMAP_DRAFTS_DIRTY))
  696. {
  697. IEnumerateFolders *pEnum;
  698. char szSentItems[MAX_PATH];
  699. char szDrafts[MAX_PATH];
  700. DWORD dwIMAPSpecial = 0;
  701. BOOL fSetSentItems = FALSE;
  702. BOOL fSetDrafts = FALSE;
  703. // Remove all affected special folder types from cache. If new path is
  704. // found in folderlist, set its special folder type
  705. szSentItems[0] = '\0';
  706. szDrafts[0] = '\0';
  707. hr = pAcct->GetPropDw(AP_IMAP_SVRSPECIALFLDRS, &dwIMAPSpecial);
  708. if (SUCCEEDED(hr) && dwIMAPSpecial)
  709. {
  710. if (dw & IMAP_SENTITEMS_DIRTY)
  711. {
  712. hr = pAcct->GetPropSz(AP_IMAP_SENTITEMSFLDR, szSentItems, ARRAYSIZE(szSentItems));
  713. TraceError(hr);
  714. }
  715. if (dw & IMAP_DRAFTS_DIRTY)
  716. {
  717. hr = pAcct->GetPropSz(AP_IMAP_DRAFTSFLDR, szDrafts, ARRAYSIZE(szDrafts));
  718. TraceError(hr);
  719. }
  720. }
  721. hr = g_pStore->EnumChildren(idServer, FALSE, &pEnum);
  722. TraceError(hr);
  723. if (SUCCEEDED(hr))
  724. {
  725. FOLDERINFO fiFolderInfo;
  726. while (S_OK == pEnum->Next(1, &fiFolderInfo, NULL))
  727. {
  728. BOOL fUpdate = FALSE;
  729. if (dw & IMAP_SENTITEMS_DIRTY)
  730. {
  731. if (0 == lstrcmp(szSentItems, fiFolderInfo.pszName))
  732. {
  733. fiFolderInfo.tySpecial = FOLDER_SENT;
  734. fUpdate = TRUE;
  735. fSetSentItems = TRUE;
  736. // IE5 Bug #62765: if new special folder is unsubscribed, we need to subscribe it
  737. if (0 == (fiFolderInfo.dwFlags & FOLDER_SUBSCRIBED))
  738. fiFolderInfo.dwFlags |= FOLDER_SUBSCRIBED | FOLDER_CREATEONDEMAND;
  739. }
  740. else if (FOLDER_SENT == fiFolderInfo.tySpecial)
  741. {
  742. // Ignore FOLDER_HIDDEN. I'm assuming it's no big deal to leave a tombstone
  743. fiFolderInfo.tySpecial = FOLDER_NOTSPECIAL;
  744. fUpdate = TRUE;
  745. }
  746. }
  747. if (dw & IMAP_DRAFTS_DIRTY)
  748. {
  749. if (0 == lstrcmp(szDrafts, fiFolderInfo.pszName))
  750. {
  751. fiFolderInfo.tySpecial = FOLDER_DRAFT;
  752. fUpdate = TRUE;
  753. fSetDrafts = TRUE;
  754. // IE5 Bug #62765: if new special folder exists and is unsubscribed, we must subscribe it
  755. if (0 == (fiFolderInfo.dwFlags & FOLDER_SUBSCRIBED))
  756. fiFolderInfo.dwFlags |= FOLDER_SUBSCRIBED | FOLDER_CREATEONDEMAND;
  757. }
  758. else if (FOLDER_DRAFT == fiFolderInfo.tySpecial)
  759. {
  760. // Ignore FOLDER_HIDDEN. I'm assuming it's no big deal to leave a tombstone
  761. fiFolderInfo.tySpecial = FOLDER_NOTSPECIAL;
  762. fUpdate = TRUE;
  763. }
  764. }
  765. if (fUpdate)
  766. {
  767. hr = g_pStore->UpdateRecord(&fiFolderInfo);
  768. TraceError(hr);
  769. }
  770. g_pStore->FreeRecord(&fiFolderInfo);
  771. } // while
  772. pEnum->Release();
  773. } // if (SUCCEEDED(EnumChildren))
  774. // If the new special folder path(s) not found in folderlist, need to create placeholder folder
  775. if (dwIMAPSpecial && (dw & IMAP_SENTITEMS_DIRTY) && FALSE == fSetSentItems && '\0' != szSentItems[0])
  776. {
  777. FOLDERINFO fiFolderInfo;
  778. BOOL bHierarchy = 0xFF; // Invalid hierarchy char
  779. hr = g_pStore->GetFolderInfo(idServer, &fiFolderInfo);
  780. if (SUCCEEDED(hr))
  781. {
  782. bHierarchy = fiFolderInfo.bHierarchy;
  783. g_pStore->FreeRecord(&fiFolderInfo);
  784. }
  785. ZeroMemory(&fiFolderInfo, sizeof(fiFolderInfo));
  786. fiFolderInfo.idParent = idServer;
  787. fiFolderInfo.pszName = szSentItems;
  788. fiFolderInfo.dwFlags = FOLDER_HIDDEN | FOLDER_SUBSCRIBED | FOLDER_CREATEONDEMAND;
  789. fiFolderInfo.tySpecial = FOLDER_SENT;
  790. fiFolderInfo.tyFolder = FOLDER_IMAP;
  791. fiFolderInfo.bHierarchy = (BYTE)bHierarchy;
  792. hr = g_pStore->CreateFolder(CREATE_FOLDER_LOCALONLY, &fiFolderInfo, NULL);
  793. TraceError(hr);
  794. }
  795. if (dwIMAPSpecial && (dw & IMAP_DRAFTS_DIRTY) && FALSE == fSetDrafts && '\0' != szDrafts[0])
  796. {
  797. FOLDERINFO fiFolderInfo;
  798. BOOL bHierarchy = 0xFF; // Invalid hierarchy char
  799. hr = g_pStore->GetFolderInfo(idServer, &fiFolderInfo);
  800. if (SUCCEEDED(hr))
  801. {
  802. bHierarchy = fiFolderInfo.bHierarchy;
  803. g_pStore->FreeRecord(&fiFolderInfo);
  804. }
  805. ZeroMemory(&fiFolderInfo, sizeof(fiFolderInfo));
  806. fiFolderInfo.idParent = idServer;
  807. fiFolderInfo.pszName = szDrafts;
  808. fiFolderInfo.dwFlags = FOLDER_HIDDEN | FOLDER_SUBSCRIBED | FOLDER_CREATEONDEMAND;
  809. fiFolderInfo.tySpecial = FOLDER_DRAFT;
  810. fiFolderInfo.tyFolder = FOLDER_IMAP;
  811. fiFolderInfo.bHierarchy = (BYTE)bHierarchy;
  812. hr = g_pStore->CreateFolder(CREATE_FOLDER_LOCALONLY, &fiFolderInfo, NULL);
  813. TraceError(hr);
  814. }
  815. // Regardless of error, reset dirty flag
  816. dw &= ~(IMAP_SENTITEMS_DIRTY | IMAP_DRAFTS_DIRTY);
  817. } // if (dw & (IMAP_SENTITEMS_DIRTY | IMAP_DRAFTS_DIRTY))
  818. AssertSz(0 == dw, "Unhandled IMAP dirty flag");
  819. // Reset IMAP dirty property
  820. hr = pAcct->SetPropDw(AP_IMAP_DIRTY, dw);
  821. if (FAILED(hr))
  822. {
  823. TraceResult(hr);
  824. goto exit;
  825. }
  826. // Save changes
  827. hr = pAcct->SaveChanges();
  828. if (FAILED(hr))
  829. {
  830. TraceResult(hr);
  831. goto exit;
  832. }
  833. exit:
  834. if (NULL != pAcct)
  835. pAcct->Release();
  836. }
  837. void CheckAllIMAPDirty(HWND hwndParent)
  838. {
  839. HRESULT hrResult;
  840. IImnEnumAccounts *pAcctEnum = NULL;
  841. IImnAccount *pAcct = NULL;
  842. BOOL fPromptedUser = FALSE;
  843. BOOL fPermissionToReset = FALSE;
  844. TraceCall("CheckAllIMAPDirty");
  845. if (NULL == g_pAcctMan)
  846. return;
  847. hrResult = g_pAcctMan->Enumerate(SRV_IMAP, &pAcctEnum);
  848. if (FAILED(hrResult))
  849. {
  850. TraceResult(hrResult);
  851. goto exit;
  852. }
  853. // Enumerate through ALL IMAP accounts (even if user denied permission to reset list)
  854. hrResult = pAcctEnum->GetNext(&pAcct);
  855. while(SUCCEEDED(hrResult))
  856. {
  857. DWORD dwIMAPDirty;
  858. // Is this IMAP account dirty?
  859. hrResult = pAcct->GetPropDw(AP_IMAP_DIRTY, &dwIMAPDirty);
  860. if (FAILED(hrResult))
  861. dwIMAPDirty = 0;
  862. if (dwIMAPDirty & IMAP_FLDRLIST_DIRTY)
  863. {
  864. // Prompt user only once to see if he would like to refresh folder list
  865. if (FALSE == fPromptedUser)
  866. {
  867. int iResult;
  868. iResult = AthMessageBoxW(hwndParent, MAKEINTRESOURCEW(idsAthena),
  869. MAKEINTRESOURCEW(idsYouMadeChangesOneOrMore),
  870. MAKEINTRESOURCEW(idsRefreshFolderListPrompt),
  871. MB_ICONEXCLAMATION | MB_YESNO);
  872. if (IDYES == iResult)
  873. fPermissionToReset = TRUE;
  874. fPromptedUser = TRUE;
  875. } // if (FALSE == fPromptedUser)
  876. }
  877. if (dwIMAPDirty)
  878. {
  879. FOLDERID idServer;
  880. char szAccountID[CCHMAX_ACCOUNT_NAME];
  881. hrResult = pAcct->GetPropSz(AP_ACCOUNT_ID, szAccountID, ARRAYSIZE(szAccountID));
  882. TraceError(hrResult);
  883. if (SUCCEEDED(hrResult))
  884. {
  885. hrResult = g_pStore->FindServerId(szAccountID, &idServer);
  886. TraceError(hrResult);
  887. if (SUCCEEDED(hrResult))
  888. {
  889. CheckIMAPDirty(szAccountID, hwndParent, idServer,
  890. CID_NOPROMPT | (fPermissionToReset ? CID_RESETLISTOK : 0));
  891. }
  892. }
  893. }
  894. // Load in the next IMAP account
  895. SafeRelease(pAcct);
  896. hrResult = pAcctEnum->GetNext(&pAcct);
  897. } // while
  898. exit:
  899. SafeRelease(pAcctEnum);
  900. SafeRelease(pAcct);
  901. }
  902. void DoAccountListDialog(HWND hwnd, ACCTTYPE type)
  903. {
  904. ACCTLISTINFO ali;
  905. // Create the monitor
  906. if (NULL == g_pNewAcctMonitor)
  907. g_pNewAcctMonitor = new CNewAcctMonitor();
  908. if (g_pNewAcctMonitor)
  909. g_pNewAcctMonitor->StartMonitor();
  910. Assert(g_pAcctMan != NULL);
  911. ali.cbSize = sizeof(ACCTLISTINFO);
  912. ali.AcctTypeInit = type;
  913. if (g_dwAthenaMode & MODE_NEWSONLY)
  914. ali.dwAcctFlags = ACCT_FLAG_NEWS | ACCT_FLAG_DIR_SERV;
  915. else if (g_dwAthenaMode & MODE_MAILONLY)
  916. ali.dwAcctFlags = ACCT_FLAG_MAIL | ACCT_FLAG_DIR_SERV;
  917. else
  918. ali.dwAcctFlags = ACCT_FLAG_ALL;
  919. ali.dwFlags = ACCTDLG_SHOWIMAPSPECIAL | ACCTDLG_OE;
  920. //Account wizard uses this flag to distinguish between OE and outlook.
  921. ali.dwFlags |= (ACCTDLG_INTERNETCONNECTION | ACCTDLG_HTTPMAIL);
  922. // Revocation checking flag
  923. if((DwGetOption(OPT_REVOKE_CHECK) != 0) && !g_pConMan->IsGlobalOffline())
  924. ali.dwFlags |= ACCTDLG_REVOCATION;
  925. g_pAcctMan->AccountListDialog(hwnd, &ali);
  926. if (g_pNewAcctMonitor)
  927. {
  928. g_pNewAcctMonitor->StopMonitor(hwnd);
  929. g_pNewAcctMonitor->Release();
  930. g_pNewAcctMonitor = 0;
  931. }
  932. // Look for any dirty IMAP accounts
  933. CheckAllIMAPDirty(hwnd);
  934. }
  935. HRESULT IsValidSendAccount(LPSTR pszAccount)
  936. {
  937. IImnAccount *pAccount;
  938. DWORD dwSrvTypes=0;
  939. if (g_pAcctMan &&
  940. g_pAcctMan->FindAccount(AP_ACCOUNT_NAME, pszAccount, &pAccount)==S_OK)
  941. {
  942. pAccount->GetServerTypes(&dwSrvTypes);
  943. pAccount->Release();
  944. return dwSrvTypes & SRV_SMTP ? S_OK : S_FALSE;
  945. }
  946. return S_FALSE;
  947. }
  948. HRESULT AcctUtil_CreateSendReceieveMenu(HMENU hMenu, DWORD *pcItems)
  949. {
  950. IImnAccount *pAccount;
  951. TCHAR szDefaultAccount[CCHMAX_ACCOUNT_NAME];
  952. HRESULT hr;
  953. IImnEnumAccounts *pEnum;
  954. DWORD cAccounts = 0;
  955. TCHAR szTitle[CCHMAX_ACCOUNT_NAME + 30];
  956. TCHAR szAccountQuoted[CCHMAX_ACCOUNT_NAME + 60];
  957. TCHAR szDefaultString[CCHMAX_STRINGRES];
  958. TCHAR szAccount[CCHMAX_ACCOUNT_NAME];
  959. TCHAR szTruncAcct[128];
  960. MENUITEMINFO mii;
  961. DWORD iAccount = 0;
  962. LPTSTR pszAccount;
  963. LPSTR pszAcctID;
  964. // Get the default account's ID. If this fails we just go on.
  965. if (SUCCEEDED(hr = g_pAcctMan->GetDefaultAccount(ACCT_MAIL, &pAccount)))
  966. {
  967. // Get the account ID from the default account
  968. pAccount->GetPropSz(AP_ACCOUNT_NAME, szDefaultAccount, ARRAYSIZE(szDefaultAccount));
  969. pAccount->Release();
  970. }
  971. if (!(g_dwAthenaMode & MODE_NEWSONLY))
  972. {
  973. // Enumerate through the servers
  974. if (SUCCEEDED(hr = g_pAcctMan->Enumerate(SRV_SMTP | SRV_POP3 | SRV_HTTPMAIL, &pEnum)))
  975. {
  976. // Sort the accounts. If this fails, we just go on.
  977. pEnum->SortByAccountName();
  978. // Get the number of accounts we'll be enumerating
  979. if (SUCCEEDED(hr = pEnum->GetCount(&cAccounts)))
  980. {
  981. // If there are zero accounts, there's nothing to do.
  982. if (0 != cAccounts)
  983. {
  984. // Make sure we have enough ID's reserved for this
  985. Assert(cAccounts < ID_ACCOUNT_LAST - ID_ACCOUNT_FIRST);
  986. // Set this struct up before we start
  987. ZeroMemory(&mii, sizeof(MENUITEMINFO));
  988. mii.cbSize = sizeof(MENUITEMINFO);
  989. mii.fMask = MIIM_DATA | MIIM_ID | MIIM_TYPE;
  990. mii.fType = MFT_STRING;
  991. // Loop through the accounts
  992. while (SUCCEEDED(pEnum->GetNext(&pAccount)))
  993. {
  994. if (MemAlloc((LPVOID *) &pszAcctID, sizeof(TCHAR) * CCHMAX_ACCOUNT_NAME))
  995. {
  996. // Get the name of the account
  997. pAccount->GetPropSz(AP_ACCOUNT_NAME, szAccount, CCHMAX_ACCOUNT_NAME);
  998. pAccount->GetPropSz(AP_ACCOUNT_ID, pszAcctID, CCHMAX_ACCOUNT_NAME);
  999. // If this account is the default account, we need to append
  1000. // "(Default)" to the end. Limit the string to 80 since Win95 seems
  1001. // to have some problems with really really long menus.
  1002. if (0 == lstrcmp(szAccount, szDefaultAccount))
  1003. {
  1004. AthLoadString(idsDefaultAccount, szDefaultString, ARRAYSIZE(szDefaultString));
  1005. StrCpyN(szTruncAcct, szAccount, 80);
  1006. wnsprintf(szTitle, ARRAYSIZE(szTitle), "%s %s", szTruncAcct, szDefaultString);
  1007. }
  1008. else
  1009. {
  1010. StrCpyN(szTitle, szAccount, 80);
  1011. }
  1012. // For account names with "&" characters like AT&T, we need to
  1013. // quote the "&".
  1014. PszEscapeMenuStringA(szTitle, szAccountQuoted, ARRAYSIZE(szAccountQuoted));
  1015. // Fill in the struct
  1016. mii.wID = ID_ACCOUNT_FIRST + iAccount;
  1017. mii.dwItemData = (DWORD_PTR) pszAcctID;
  1018. mii.dwTypeData = szAccountQuoted;
  1019. // Append the item
  1020. InsertMenuItem(hMenu, -1, TRUE, &mii);
  1021. // Increment the count
  1022. iAccount++;
  1023. }
  1024. // Release the account pointer
  1025. pAccount->Release();
  1026. }
  1027. }
  1028. }
  1029. // Release the enumerator
  1030. pEnum->Release();
  1031. Assert(iAccount == cAccounts);
  1032. }
  1033. }
  1034. else
  1035. {
  1036. //Remove Seperator in NEWSONLY mode.
  1037. int ItemCount;
  1038. ItemCount = GetMenuItemCount(hMenu);
  1039. if (ItemCount != -1)
  1040. {
  1041. DeleteMenu(hMenu, ItemCount - 1, MF_BYPOSITION);
  1042. }
  1043. }
  1044. //iAccount could be less than cAccounts if we are in news only mode.
  1045. if (pcItems)
  1046. *pcItems = cAccounts;
  1047. return (S_OK);
  1048. }
  1049. HRESULT AcctUtil_FreeSendReceieveMenu(HMENU hMenu, DWORD cItems)
  1050. {
  1051. DWORD i;
  1052. MENUITEMINFO mii;
  1053. mii.cbSize = sizeof(MENUITEMINFO);
  1054. mii.fMask = MIIM_DATA;
  1055. for (i = 0; i < cItems; i++)
  1056. {
  1057. mii.dwItemData = 0;
  1058. if (GetMenuItemInfo(hMenu, ID_ACCOUNT_FIRST + i, FALSE, &mii))
  1059. {
  1060. if (mii.dwItemData)
  1061. MemFree((LPTSTR) mii.dwItemData);
  1062. DeleteMenu(hMenu, ID_ACCOUNT_FIRST + i, MF_BYCOMMAND);
  1063. }
  1064. }
  1065. return (S_OK);
  1066. }
  1067. HRESULT AcctUtil_CreateAccountManagerForIdentity(GUID *puidIdentity, IImnAccountManager2 **ppAccountManager)
  1068. {
  1069. HRESULT hr;
  1070. IImnAccountManager *pAccountManager = NULL;
  1071. IImnAccountManager2 *pAccountManager2 = NULL;
  1072. *ppAccountManager = NULL;
  1073. if (FAILED(hr = HrCreateAccountManager(&pAccountManager)))
  1074. goto exit;
  1075. if (FAILED(hr = pAccountManager->QueryInterface(IID_IImnAccountManager2, (LPVOID *)&pAccountManager2)))
  1076. goto exit;
  1077. // The *puidIdentity does not result in a new GUID object being created (formal param is by reference)
  1078. if (FAILED(hr = pAccountManager2->InitUser(NULL, *puidIdentity, 0)))
  1079. goto exit;
  1080. *ppAccountManager = pAccountManager2;
  1081. pAccountManager2 = NULL;
  1082. exit:
  1083. SafeRelease(pAccountManager);
  1084. SafeRelease(pAccountManager2);
  1085. return hr;
  1086. }
  1087. void InitNewAcctMenu(HMENU hmenu)
  1088. {
  1089. HKEY hkey, hkeyT;
  1090. LONG lResult;
  1091. DWORD cServices, cb, i, type, cItem, dwMsn;
  1092. char szKey[MAX_PATH], sz[512], szQuoted[512];
  1093. HMENU hsubmenu;
  1094. MENUITEMINFO mii;
  1095. LPSTR pszKey;
  1096. BOOL fHideHotmail = HideHotmail();
  1097. cItem = 0;
  1098. hsubmenu = NULL;
  1099. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, c_szHTTPMailServiceRoot, 0, KEY_READ, &hkey))
  1100. {
  1101. if (ERROR_SUCCESS == RegQueryInfoKey(hkey, NULL, NULL, 0, &cServices, NULL, NULL, NULL, NULL, NULL, NULL, NULL) &&
  1102. cServices > 0)
  1103. {
  1104. mii.cbSize = sizeof(MENUITEMINFO);
  1105. mii.fMask = MIIM_DATA | MIIM_ID | MIIM_TYPE;
  1106. mii.fType = MFT_STRING;
  1107. hsubmenu = CreatePopupMenu();
  1108. if (hsubmenu != NULL)
  1109. {
  1110. // Start Enumerating the keys
  1111. for (i = 0; i < cServices; i++)
  1112. {
  1113. // Enumerate Friendly Names
  1114. cb = sizeof(szKey);
  1115. lResult = RegEnumKeyEx(hkey, i, szKey, &cb, 0, NULL, NULL, NULL);
  1116. // No more items
  1117. if (lResult == ERROR_NO_MORE_ITEMS)
  1118. break;
  1119. // Error, lets move onto the next account
  1120. if (lResult != ERROR_SUCCESS)
  1121. {
  1122. Assert(FALSE);
  1123. continue;
  1124. }
  1125. if (ERROR_SUCCESS == RegOpenKeyEx(hkey, szKey, 0, KEY_QUERY_VALUE, &hkeyT))
  1126. {
  1127. cb = sizeof(dwMsn);
  1128. if (!fHideHotmail ||
  1129. ERROR_SUCCESS != RegQueryValueEx(hkeyT, c_szHTTPMailDomainMSN, 0, NULL, (LPBYTE)&dwMsn, &cb) ||
  1130. dwMsn == 0)
  1131. {
  1132. cb = sizeof(sz);
  1133. if (ERROR_SUCCESS == RegQueryValueEx(hkeyT, c_szHTTPMailSignUp, NULL, &type, (LPBYTE)sz, &cb) &&
  1134. *sz != 0)
  1135. {
  1136. cb = sizeof(sz);
  1137. if (ERROR_SUCCESS == RegQueryValueEx(hkeyT, c_szHTTPMailServiceName, NULL, &type, (LPBYTE)sz, &cb) &&
  1138. *sz != 0)
  1139. {
  1140. pszKey = PszDup(szKey);
  1141. if (pszKey != NULL)
  1142. {
  1143. PszEscapeMenuStringA(sz, szQuoted, ARRAYSIZE(szQuoted));
  1144. // Fill in the struct
  1145. mii.wID = ID_NEW_ACCT_FIRST + cItem;
  1146. mii.dwItemData = (DWORD_PTR)pszKey;
  1147. mii.dwTypeData = szQuoted;
  1148. // Append the item
  1149. InsertMenuItem(hsubmenu, -1, TRUE, &mii);
  1150. cItem++;
  1151. }
  1152. }
  1153. }
  1154. }
  1155. RegCloseKey(hkeyT);
  1156. }
  1157. }
  1158. }
  1159. }
  1160. RegCloseKey(hkey);
  1161. }
  1162. if (cItem == 0)
  1163. {
  1164. if (hsubmenu != NULL)
  1165. DestroyMenu(hsubmenu);
  1166. DeleteMenu(hmenu, ID_POPUP_NEW_ACCT, MF_BYCOMMAND);
  1167. }
  1168. else
  1169. {
  1170. Assert(hsubmenu != NULL);
  1171. mii.fMask = MIIM_SUBMENU;
  1172. mii.hSubMenu = hsubmenu;
  1173. SetMenuItemInfo(hmenu, ID_POPUP_NEW_ACCT, FALSE, &mii);
  1174. }
  1175. }
  1176. void FreeNewAcctMenu(HMENU hmenu)
  1177. {
  1178. int i, cItem;
  1179. MENUITEMINFO mii;
  1180. HMENU hsubmenu;
  1181. mii.cbSize = sizeof(MENUITEMINFO);
  1182. mii.fMask = MIIM_SUBMENU;
  1183. mii.hSubMenu = NULL;
  1184. if (GetMenuItemInfo(hmenu, ID_POPUP_NEW_ACCT, FALSE, &mii) &&
  1185. mii.hSubMenu != NULL)
  1186. {
  1187. hsubmenu = mii.hSubMenu;
  1188. cItem = GetMenuItemCount(hsubmenu);
  1189. mii.fMask = MIIM_DATA;
  1190. for (i = 0; i < cItem; i++)
  1191. {
  1192. mii.dwItemData = 0;
  1193. if (GetMenuItemInfo(hsubmenu, ID_NEW_ACCT_FIRST + i, FALSE, &mii))
  1194. {
  1195. if (mii.dwItemData)
  1196. MemFree((LPSTR)mii.dwItemData);
  1197. }
  1198. }
  1199. DestroyMenu(hsubmenu);
  1200. }
  1201. }
  1202. HRESULT HandleNewAcctMenu(HWND hwnd, HMENU hmenu, int id)
  1203. {
  1204. MENUITEMINFO mii;
  1205. char szKey[MAX_PATH], szUrl[512];
  1206. HKEY hkey;
  1207. DWORD type, cb, dwUseWizard;
  1208. TCHAR rgch[MAX_PATH];
  1209. BOOL bFoundUrl = TRUE;
  1210. mii.cbSize = sizeof(MENUITEMINFO);
  1211. mii.fMask = MIIM_DATA|MIIM_TYPE;
  1212. mii.dwItemData = 0;
  1213. mii.dwTypeData = rgch;
  1214. mii.cch = ARRAYSIZE(rgch);
  1215. if (GetMenuItemInfo(hmenu, id, FALSE, &mii) && mii.dwItemData != 0)
  1216. {
  1217. wnsprintf(szKey, ARRAYSIZE(szKey), c_szPathFileFmt, c_szHTTPMailServiceRoot, (LPSTR)mii.dwItemData);
  1218. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE, szKey, 0, KEY_READ, &hkey))
  1219. {
  1220. // look for a config url
  1221. cb = sizeof(szUrl);
  1222. if (ERROR_SUCCESS != RegQueryValueEx(hkey, c_szHTTPMailConfig, NULL, &type, (LPBYTE)szUrl, &cb))
  1223. {
  1224. // config url wasn't found. fall back to sign up url
  1225. cb = sizeof(szUrl);
  1226. if (ERROR_SUCCESS != RegQueryValueEx(hkey, c_szHTTPMailSignUp, NULL, &type, (LPBYTE)szUrl, &cb))
  1227. bFoundUrl = FALSE;
  1228. }
  1229. if (bFoundUrl)
  1230. {
  1231. cb = sizeof(DWORD);
  1232. if (ERROR_SUCCESS == RegQueryValueEx(hkey, c_szHTTPMailUseWizard, NULL, &type, (LPBYTE)&dwUseWizard, &cb) &&
  1233. dwUseWizard != 0)
  1234. DoHotMailWizard(GetTopMostParent(hwnd), szUrl, rgch, NULL, NULL);
  1235. else
  1236. ShellExecute(hwnd, "open", szUrl, NULL, NULL, SW_SHOWNORMAL);
  1237. }
  1238. RegCloseKey(hkey);
  1239. }
  1240. }
  1241. return(S_OK);
  1242. }