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.
 
 
 
 
 
 

2612 lines
75 KiB

#include "pch.hxx"
#include <iert.h>
#include <store.h>
#include <storecb.h>
#include "resource.h"
#include "ourguid.h"
#include "thormsgs.h"
#include "goptions.h"
#include "strconst.h"
#include <inetcfg.h>
#include <fonts.h>
#include <columns.h>
#include <imagelst.h>
#include <instance.h>
#include <spoolui.h>
#include <options.h>
#include <acctutil.h>
#include "shlwapip.h"
#include <menuutil.h>
#include "storutil.h"
#include <outbar.h>
#include <subscr.h>
#include "newsutil.h"
#include "acctview.h"
#include <newfldr.h>
#include <mailutil.h>
#include "menures.h"
#include "demand.h"
ASSERTDATA
#define SUBSCRIBE_BORDER 7
#define CALLOCIDBUF 256
#define IDC_SUBSCRIBE_LIST (ID_FIRST - 4)
#define FOLDER_SYNCMASK (FOLDER_DOWNLOADHEADERS | FOLDER_DOWNLOADNEW | FOLDER_DOWNLOADALL)
static const char c_szAcctViewWndClass[] = "Outlook Express AcctView";
int __cdecl GroupCompare(const void *lParam1, const void *lParam2) ;
void DrawSettingsButton(HWND hwnd, LPDRAWITEMSTRUCT pdi);
#define C_RGBCOLORS 16
extern const DWORD rgrgbColors16[C_RGBCOLORS];
typedef struct tagACCTVIEWBTN
{
int idsText;
int cmd;
} ACCTVIEWBTN;
static const ACCTVIEWBTN c_rgMailBtns[] =
{
{ idsDeliverMailTT, ID_SEND_RECEIVE }
};
static const ACCTVIEWBTN c_rgImapBtns[] =
{
{ idsSynchronizeNowBtn, ID_SYNC_THIS_NOW },
{ idsIMAPFoldersBtn, ID_IMAP_FOLDERS },
{ idsSettingsBtn, ID_POPUP_SYNCHRONIZE }
};
static const ACCTVIEWBTN c_rgNewsBtns[] =
{
{ idsSynchronizeNowBtn, ID_SYNC_THIS_NOW },
{ idsNewsgroupsBtn, ID_NEWSGROUPS },
{ idsSettingsBtn, ID_POPUP_SYNCHRONIZE }
};
static const ACCTVIEWBTN c_rgHttpBtns[] =
{
{ idsSynchronizeNowBtn, ID_SYNC_THIS_NOW },
{ idsSettingsBtn, ID_POPUP_SYNCHRONIZE }
};
CAccountView::CAccountView()
{
m_cRef = 1;
// m_ftType
m_pShellBrowser = NULL;
m_fFirstActive = FALSE;
m_pColumns = NULL;
m_uActivation = SVUIA_DEACTIVATE;
m_hwndOwner = NULL;
m_hwnd = NULL;
m_idFolder = FOLDERID_INVALID;
m_fRegistered = FALSE;
m_hwndList = NULL;
m_pszMajor = NULL;
m_pszMinor = NULL;
m_cBtns = 0;
m_cnode = 0;
m_cnodeBuf = 0;
m_rgnode = NULL;
m_himlFolders = NULL;
m_pEmptyList = NULL;
m_pGroups = NULL;
m_clrWatched = 0;
}
CAccountView::~CAccountView()
{
if (m_pGroups != NULL)
{
m_pGroups->Close();
m_pGroups->Release();
}
if (m_rgnode != NULL)
MemFree(m_rgnode);
SafeRelease(m_pShellBrowser);
SafeRelease(m_pColumns);
if (m_pEmptyList != NULL)
delete m_pEmptyList;
if (m_himlFolders != NULL)
ImageList_Destroy(m_himlFolders);
if (m_pszMajor != NULL)
MemFree(m_pszMajor);
if (m_pszMinor != NULL)
MemFree(m_pszMinor);
}
HRESULT CAccountView::HrInit(FOLDERID idFolder)
{
WNDCLASS wc;
if (!GetClassInfo(g_hInst, c_szAcctViewWndClass, &wc))
{
wc.style = 0;
wc.lpfnWndProc = CAccountView::AcctViewWndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = g_hInst;
wc.hIcon = NULL;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1);
wc.lpszMenuName = NULL;
wc.lpszClassName = c_szAcctViewWndClass;
if (RegisterClass(&wc) == 0 && GetLastError() != ERROR_CLASS_ALREADY_EXISTS)
return E_FAIL;
}
m_idFolder = idFolder;
m_ftType = GetFolderType(idFolder);
m_dwDownloadDef = (m_ftType == FOLDER_NEWS) ? FOLDER_DOWNLOADNEW : FOLDER_DOWNLOADALL;
// Set the image lists for the listview
Assert(m_himlFolders == NULL);
m_himlFolders = InitImageList(16, 16, MAKEINTRESOURCE(idbFolders), cFolderIcon, RGB(255, 0, 255));
Assert(m_himlFolders);
m_pEmptyList = new CEmptyList;
if (m_pEmptyList == NULL)
return(E_OUTOFMEMORY);
return S_OK;
}
/////////////////////////////////////////////////////////////////////////
//
// OLE Interfaces
//
////////////////////////////////////////////////////////////////////////
//
// IUnknown
//
////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE CAccountView::QueryInterface(REFIID riid, void **ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown))
*ppvObj = (void*) (IUnknown *)(IViewWindow *)this;
else if (IsEqualIID(riid, IID_IViewWindow))
*ppvObj = (void*) (IViewWindow *) this;
else if (IsEqualIID(riid, IID_IOleCommandTarget))
*ppvObj = (void*) (IOleCommandTarget *) this;
else
{
*ppvObj = NULL;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
}
ULONG STDMETHODCALLTYPE CAccountView::AddRef()
{
DOUT(TEXT("CAccountView::AddRef() - m_cRef = %d"), m_cRef + 1);
return ++m_cRef;
}
ULONG STDMETHODCALLTYPE CAccountView::Release()
{
DOUT(TEXT("CAccountView::Release() - m_cRef = %d"), m_cRef - 1);
if (--m_cRef == 0)
{
delete this;
return 0;
}
return m_cRef;
}
////////////////////////////////////////////////////////////////////////
//
// IOleWindow
//
////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE CAccountView::GetWindow(HWND * lphwnd)
{
*lphwnd = m_hwnd;
return (m_hwnd ? S_OK : E_FAIL);
}
HRESULT STDMETHODCALLTYPE CAccountView::ContextSensitiveHelp(BOOL fEnterMode)
{
return E_NOTIMPL;
}
////////////////////////////////////////////////////////////////////////
//
// IAthenaView
//
////////////////////////////////////////////////////////////////////////
HRESULT STDMETHODCALLTYPE CAccountView::TranslateAccelerator(LPMSG lpmsg)
{
return(S_FALSE);
}
HRESULT STDMETHODCALLTYPE CAccountView::UIActivate(UINT uActivation)
{
if (uActivation != SVUIA_DEACTIVATE)
_OnActivate(uActivation);
else
_OnDeactivate();
return S_OK;
}
HRESULT STDMETHODCALLTYPE CAccountView::CreateViewWindow(IViewWindow *lpPrevView, IAthenaBrowser *psb,
RECT *prcView, HWND *phWnd)
{
FOLDERINFO info;
m_pShellBrowser = psb;
Assert(m_pShellBrowser);
m_pShellBrowser->AddRef();
m_pShellBrowser->GetWindow(&m_hwndOwner);
Assert(IsWindow(m_hwndOwner));
m_pColumns = new CColumns;
if (m_pColumns == NULL)
return(E_OUTOFMEMORY);
m_hwnd = CreateWindowEx(WS_EX_CONTROLPARENT|WS_EX_CLIENTEDGE,
c_szAcctViewWndClass,
NULL,
WS_VISIBLE|WS_CHILD|WS_CLIPCHILDREN|WS_CLIPSIBLINGS,
prcView->left,
prcView->top,
prcView->right - prcView->left,
prcView->bottom - prcView->top,
m_hwndOwner,
NULL,
g_hInst,
(LPVOID)this);
if (!m_hwnd)
return E_FAIL;
*phWnd = m_hwnd;
return(S_OK);
}
HRESULT STDMETHODCALLTYPE CAccountView::DestroyViewWindow()
{
HRESULT hr;
HWND hwndDest;
if (m_fRegistered)
g_pStore->UnregisterNotify((IDatabaseNotify *)this);
if (m_hwnd)
{
hwndDest = m_hwnd;
m_hwnd = NULL;
DestroyWindow(hwndDest);
}
return S_OK;
}
HRESULT STDMETHODCALLTYPE CAccountView::SaveViewState()
{
Assert(m_pColumns != NULL);
m_pColumns->Save(NULL, NULL);
OptionUnadvise(m_hwnd);
return S_OK;
}
//
// FUNCTION: CAccountView::OnInitMenuPopup
//
// PURPOSE: Called when the user is about to display a menu. We use this
// to update the enabled or disabled status of many of the
// commands on each menu.
//
// PARAMETERS:
// hmenu - Handle of the main menu.
// hmenuPopup - Handle of the popup menu being displayed.
// uID - Specifies the id of the menu item that
// invoked the popup.
//
// RETURN VALUE:
// Returns S_OK if we process the message.
//
//
HRESULT CAccountView::OnPopupMenu(HMENU hmenu, HMENU hmenuPopup, UINT uID)
{
return(S_OK);
}
DWORD CAccountView::_GetDownloadCmdStatus(int iSel, FLDRFLAGS dwFlags)
{
DWORD cmdf;
cmdf = OLECMDF_SUPPORTED;
if (m_ftType != FOLDER_LOCAL)
{
if (iSel != -1)
{
if (_IsSelectedFolder(FOLDER_SUBSCRIBED, TRUE, FALSE))
{
cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
if (_IsSelectedFolder(dwFlags, TRUE, TRUE))
cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED | OLECMDF_NINCHED;
}
}
}
return(cmdf);
}
HRESULT CAccountView::QueryStatus(const GUID *pguidCmdGroup, ULONG cCmds, OLECMD prgCmds[], OLECMDTEXT *pCmdText)
{
ULONG i;
BOOL fTree, fSpecial;
FOLDERID idFolder;
FOLDERINFO info;
HRESULT hr;
int iSel, cSel, cItems, iSelT;
OLECMD *pcmd;
Assert(prgCmds != NULL);
cSel = ListView_GetSelectedCount(m_hwndList);
cItems = ListView_GetItemCount(m_hwndList);
iSel = ListView_GetNextItem(m_hwndList, -1, LVNI_ALL | LVNI_SELECTED | LVNI_FOCUSED);
if (iSel != -1 && (DWORD)iSel >= m_cnode)
iSel = -1;
fTree = !(S_OK == m_pShellBrowser->HasFocus(ITB_OEVIEW));
for (i = 0, pcmd = prgCmds; i < cCmds; i++, pcmd++)
{
if (pcmd->cmdf == 0)
{
switch (pcmd->cmdID)
{
case ID_POPUP_SYNCHRONIZE:
pcmd->cmdf = OLECMDF_SUPPORTED;
if (m_ftType != FOLDER_LOCAL && iSel != -1)
{
if (_IsSelectedFolder(FOLDER_SUBSCRIBED, TRUE, FALSE))
pcmd->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
}
break;
case ID_MARK_RETRIEVE_FLD_NEW_HDRS:
pcmd->cmdf = _GetDownloadCmdStatus(iSel, FOLDER_DOWNLOADHEADERS);
break;
case ID_MARK_RETRIEVE_FLD_NEW_MSGS:
pcmd->cmdf = _GetDownloadCmdStatus(iSel, FOLDER_DOWNLOADNEW);
break;
case ID_MARK_RETRIEVE_FLD_ALL_MSGS:
pcmd->cmdf = _GetDownloadCmdStatus(iSel, FOLDER_DOWNLOADALL);
break;
case ID_UNMARK_RETRIEVE_FLD:
pcmd->cmdf = OLECMDF_SUPPORTED;
if (iSel != -1)
{
if (_IsSelectedFolder(FOLDER_SUBSCRIBED, TRUE, FALSE))
{
pcmd->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
if (_IsSelectedFolder(FOLDER_SYNCMASK, FALSE, TRUE))
pcmd->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED | OLECMDF_NINCHED;
}
}
break;
case ID_SUBSCRIBE:
case ID_UNSUBSCRIBE:
pcmd->cmdf = OLECMDF_SUPPORTED;
if ((m_ftType == FOLDER_IMAP || m_ftType == FOLDER_NEWS) && iSel != -1)
{
if (_IsSelectedFolder(FOLDER_SUBSCRIBED, pcmd->cmdID == ID_UNSUBSCRIBE, FALSE, TRUE))
pcmd->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
}
break;
case ID_SELECT_ALL:
case ID_COLUMNS:
pcmd->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
break;
case ID_CATCH_UP:
if (m_ftType == FOLDER_NEWS && iSel != -1)
pcmd->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
else
pcmd->cmdf = OLECMDF_SUPPORTED;
break;
case ID_OPEN_FOLDER:
case ID_OPEN:
case ID_GO_SELECTED:
case ID_COMPACT:
case ID_MARK_ALL_READ:
if (iSel == -1)
pcmd->cmdf = OLECMDF_SUPPORTED;
else
pcmd->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
break;
// TODO: support ID_PURGE_DELETED???
// commands below are handled by the treeview if it has the focus
// otherwise we'll handle them based on what is selected in us
case ID_PROPERTIES:
case ID_ADD_SHORTCUT:
if (!fTree)
{
if (iSel != -1)
pcmd->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
else
pcmd->cmdf = OLECMDF_SUPPORTED;
}
break;
case ID_NEW_FOLDER:
case ID_NEW_FOLDER2:
if (!fTree)
{
pcmd->cmdf = OLECMDF_SUPPORTED;
if (m_ftType != FOLDER_NEWS && iSel != -1)
{
hr = g_pStore->GetFolderInfo(_IdFromIndex(iSel), &info);
if (SUCCEEDED(hr))
{
if (info.tySpecial != FOLDER_DELETED)
pcmd->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
g_pStore->FreeRecord(&info);
}
}
}
break;
case ID_DELETE:
case ID_DELETE_FOLDER:
if (!fTree)
{
pcmd->cmdf = OLECMDF_SUPPORTED;
if (iSel != -1 && m_ftType != FOLDER_NEWS)
{
iSelT = iSel;
while (iSelT != -1)
{
hr = g_pStore->GetFolderInfo(_IdFromIndex(iSelT), &info);
if (SUCCEEDED(hr))
{
fSpecial = (info.tySpecial != FOLDER_NOTSPECIAL);
g_pStore->FreeRecord(&info);
if (!fSpecial)
{
pcmd->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
break;
}
}
iSelT = ListView_GetNextItem(m_hwndList, iSelT, LVNI_SELECTED);
}
}
}
break;
case ID_MOVE:
case ID_RENAME:
if (!fTree)
{
pcmd->cmdf = OLECMDF_SUPPORTED;
if (m_ftType != FOLDER_NEWS && iSel != -1)
{
hr = g_pStore->GetFolderInfo(_IdFromIndex(iSel), &info);
if (SUCCEEDED(hr))
{
if (info.tySpecial == FOLDER_NOTSPECIAL)
pcmd->cmdf = OLECMDF_SUPPORTED | OLECMDF_ENABLED;
g_pStore->FreeRecord(&info);
}
}
}
break;
}
}
}
return(S_OK);
}
HRESULT CAccountView::Exec(const GUID *pguidCmdGroup, DWORD nCmdID, DWORD nCmdExecOpt, VARIANTARG *pvaIn, VARIANTARG *pvaOut)
{
int iSel;
BOOL fTree;
HRESULT hr;
FOLDERID id;
iSel = ListView_GetNextItem(m_hwndList, -1, LVNI_ALL | LVNI_FOCUSED);
if (iSel != -1)
{
if (MenuUtil_HandleNewMessageIDs(nCmdID, m_hwndOwner, _IdFromIndex((DWORD)iSel), m_ftType != FOLDER_NEWS, FALSE, NULL))
return(S_OK);
}
fTree = !(S_OK == m_pShellBrowser->HasFocus(ITB_OEVIEW));
hr = OLECMDERR_E_NOTSUPPORTED;
switch (nCmdID)
{
case ID_MARK_RETRIEVE_FLD_NEW_HDRS:
case ID_MARK_RETRIEVE_FLD_NEW_MSGS:
case ID_MARK_RETRIEVE_FLD_ALL_MSGS:
case ID_UNMARK_RETRIEVE_FLD:
_MarkForDownload(nCmdID);
hr = S_OK;
break;
case ID_COLUMNS:
m_pColumns->ColumnsDialog(m_hwndOwner);
hr = S_OK;
break;
case ID_SUBSCRIBE:
case ID_UNSUBSCRIBE:
_Subscribe(nCmdID == ID_SUBSCRIBE);
hr = S_OK;
break;
case ID_COMPACT:
if (iSel != -1)
CompactFolders(m_hwndOwner, RECURSE_INCLUDECURRENT, _IdFromIndex((DWORD)iSel));
hr = S_OK;
break;
case ID_CATCH_UP:
iSel = -1;
while (-1 != (iSel = ListView_GetNextItem(m_hwndList, iSel, LVNI_SELECTED | LVNI_ALL)))
MenuUtil_OnCatchUp(_IdFromIndex((DWORD)iSel));
hr = S_OK;
break;
case ID_GO_SELECTED:
case ID_OPEN:
case ID_OPEN_FOLDER:
if (iSel != -1)
g_pInstance->BrowseToObject(SW_SHOWNORMAL, _IdFromIndex((DWORD)iSel));
hr = S_OK;
break;
case ID_SELECT_ALL:
ListView_SelectAll(m_hwndList);
if (m_hwndList != GetFocus())
SetFocus(m_hwndList);
hr = S_OK;
break;
case ID_MARK_ALL_READ:
_MarkAllRead();
hr = S_OK;
break;
// commands below are handled by the treeview if it has the focus
// otherwise we'll handle them based on what is selected in us
case ID_ADD_SHORTCUT:
if (!fTree)
{
if (iSel != -1)
OutlookBar_AddShortcut(_IdFromIndex((DWORD)iSel));
hr = S_OK;
}
break;
case ID_PROPERTIES:
if (!fTree)
{
if (iSel != -1)
MenuUtil_OnProperties(m_hwndOwner, _IdFromIndex(iSel));
hr = S_OK;
}
break;
case ID_NEW_FOLDER:
case ID_NEW_FOLDER2:
if (!fTree)
{
if (iSel != -1)
SelectFolderDialog(m_hwndOwner, SFD_NEWFOLDER, _IdFromIndex((DWORD)iSel), TREEVIEW_NONEWS | TREEVIEW_DIALOG | FD_DISABLEROOT | FD_FORCEINITSELFOLDER,
NULL, NULL, NULL);
hr = S_OK;
}
break;
case ID_MOVE:
if (!fTree)
{
if (iSel != -1)
{
// TODO: move all selected folders, not just the one with focus
SelectFolderDialog(m_hwndOwner, SFD_MOVEFOLDER, _IdFromIndex((DWORD)iSel), TREEVIEW_NONEWS | TREEVIEW_DIALOG | FD_DISABLEROOT,
MAKEINTRESOURCE(idsMove), MAKEINTRESOURCE(idsMoveCaption), NULL);
}
hr = S_OK;
}
break;
case ID_RENAME:
if (!fTree)
{
if (iSel != -1)
RenameFolderDlg(m_hwndOwner, _IdFromIndex((DWORD)iSel));
hr = S_OK;
}
break;
case ID_DELETE:
case ID_DELETE_NO_TRASH:
case ID_DELETE_FOLDER:
if (!fTree)
{
if (iSel != -1)
_HandleDelete(nCmdID == ID_DELETE_NO_TRASH);
hr = S_OK;
}
break;
}
return(hr);
}
void CAccountView::_HandleSettingsButton(HWND hwndBtn)
{
HRESULT hr;
HMENU hMenu;
HWND hwndBrowser;
RECT rc;
DWORD state;
hMenu = LoadPopupMenu(IDR_SYNCHRONIZE_POPUP);
if (hMenu != NULL)
{
// Enable / disable
MenuUtil_EnablePopupMenu(hMenu, (IOleCommandTarget *)this);
GetWindowRect(hwndBtn, &rc);
m_pShellBrowser->GetWindow(&hwndBrowser);
TrackPopupMenu(hMenu, TPM_NONOTIFY | TPM_LEFTALIGN | TPM_TOPALIGN,
rc.left, rc.bottom, 0, hwndBrowser, NULL);
DestroyMenu(hMenu);
}
}
void CAccountView::_HandleDelete(BOOL fNoTrash)
{
FOLDERID *pid;
int iSel, cSel, cid;
cSel = ListView_GetSelectedCount(m_hwndList);
if (cSel > 0)
{
if (MemAlloc((void **)&pid, cSel * sizeof(FOLDERID)))
{
cid = cSel;
iSel = -1;
while (-1 != (iSel = ListView_GetNextItem(m_hwndList, iSel, LVNI_SELECTED | LVNI_ALL)))
{
cid--;
Assert(cid >= 0);
pid[cid] = _IdFromIndex(iSel);
}
Assert(cid == 0);
if (m_ftType == FOLDER_NEWS)
{
MenuUtil_OnSubscribeGroups(m_hwndOwner, pid, cSel, FALSE);
}
else
{
MenuUtil_DeleteFolders(m_hwndOwner, pid, cSel, fNoTrash);
}
MemFree(pid);
}
}
}
BOOL CAccountView::_IsSelectedFolder(FLDRFLAGS dwFlags, BOOL fCondition, BOOL fAll, BOOL fIgnoreSpecial)
{
BOOL fSpecial;
HRESULT hr;
FLDRFLAGS dw;
FOLDERINFO info;
DWORD iItem = -1;
BOOL fHTTPFolder = FALSE;
while (-1 != (iItem = ListView_GetNextItem(m_hwndList, iItem, LVNI_SELECTED)))
{
hr = g_pStore->GetFolderInfo(_IdFromIndex(iItem), &info);
if (SUCCEEDED(hr))
{
dw = info.dwFlags;
fHTTPFolder = (BOOL) (info.tyFolder & FOLDER_HTTPMAIL);
fSpecial = fIgnoreSpecial && (info.tySpecial != FOLDER_NOTSPECIAL);
g_pStore->FreeRecord(&info);
if (fSpecial)
continue;
if (fAll)
{
// If all must match and this one doesn't, then we can quit now.
if (!(fCondition == !!(dw & dwFlags)))
return (FALSE);
}
else
{
// If only one needs to match and this one does, then we can
// quit now.
if (fCondition == !!(dw & dwFlags))
{
if(fHTTPFolder)
{
FOLDERINFO SvrFolderInfo = {0};
IImnAccount *pAccount = NULL;
CHAR szAccountId[CCHMAX_ACCOUNT_NAME];
HRESULT hr = S_OK;
DWORD dwShow = 0;
// Get the server for this folder
IF_FAILEXIT(hr = GetFolderServer(_IdFromIndex(iItem), &SvrFolderInfo));
// Get the account ID for the server
*szAccountId = 0;
IF_FAILEXIT(hr = GetFolderAccountId(&SvrFolderInfo, szAccountId, ARRAYSIZE(szAccountId)));
// Get the account interface
IF_FAILEXIT(hr = g_pAcctMan->FindAccount(AP_ACCOUNT_ID, szAccountId, &pAccount));
IF_FAILEXIT(hr = pAccount->GetPropDw(AP_HTTPMAIL_DOMAIN_MSN, &dwShow));
if(dwShow)
{
if(HideHotmail())
return (FALSE);
}
}
exit:
return (TRUE);
}
}
}
}
// If the user wanted all to match, and we get here all did match. If the
// user wanted only one to match and we get here, then none matched and we
// fail.
return (fAll);
}
LRESULT CALLBACK CAccountView::AcctViewWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
LRESULT lRet;
CAccountView *pThis;
if (msg == WM_NCCREATE)
{
pThis = (CAccountView *)((LPCREATESTRUCT)lParam)->lpCreateParams;
SetWindowLongPtr(hwnd, GWLP_USERDATA, (LPARAM)pThis);
}
else
pThis = (CAccountView *)GetWindowLongPtr(hwnd, GWLP_USERDATA);
Assert(pThis);
return pThis->_WndProc(hwnd, msg, wParam, lParam);
}
LRESULT CAccountView::_WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
HWND hwndFocus, hwndBrowser;
BOOL fTip;
RECT rc;
switch (msg)
{
HANDLE_MSG(hwnd, WM_CREATE, _OnCreate);
HANDLE_MSG(hwnd, WM_SIZE, _OnSize);
HANDLE_MSG(hwnd, WM_NOTIFY, _OnNotify);
HANDLE_MSG(hwnd, WM_SETFOCUS, _OnSetFocus);
case WM_MENUSELECT:
CStatusBar *pStatusBar;
m_pShellBrowser->GetStatusBar(&pStatusBar);
HandleMenuSelect(pStatusBar, wParam, lParam);
pStatusBar->Release();
return 0;
case WM_COMMAND:
_OnCommand(wParam, lParam);
break;
case WM_PAINT:
return(_OnPaint(hwnd, (HDC)wParam));
case WM_DRAWITEM:
if (wParam == ID_POPUP_SYNCHRONIZE)
{
DrawSettingsButton(hwnd, (LPDRAWITEMSTRUCT)lParam);
return(TRUE);
}
break;
case WM_CONTEXTMENU:
_OnContextMenu(hwnd, (HWND)wParam, (int)(short)LOWORD(lParam), (int)(short)HIWORD(lParam));
return(0);
case NVM_INITHEADERS:
_PostCreate();
return 0;
case WM_ACTIVATE:
_HandleItemStateChange();
if (LOWORD(wParam) != WA_INACTIVE)
{
// DefWindowProc will set the focus to our view window, which
// is not what we want. Instead, we will let the explorer set
// the focus to our view window if we should get it, at which
// point we will set it to the proper control.
return 0;
}
break;
case WM_SYSCOLORCHANGE:
SendMessage(m_hwndList, msg, wParam, lParam);
break;
case WM_WININICHANGE:
SendMessage(m_hwndList, msg, wParam, lParam);
// reposition and resize things with the new font
_OnWinIniChange(hwnd);
break;
case NVM_GETNEWGROUPS:
if (m_pGroups != NULL)
{
m_pGroups->HandleGetNewGroups();
m_pGroups->Release();
m_pGroups = NULL;
}
return(0);
case CM_OPTIONADVISE:
m_clrWatched = DwGetOption(OPT_WATCHED_COLOR);
return (0);
default:
if (g_msgMSWheel && (msg == g_msgMSWheel))
{
hwndFocus = GetFocus();
if (IsChild(hwnd, hwndFocus))
return SendMessage(hwndFocus, msg, wParam, lParam);
}
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
void CAccountView::_OnCommand(WPARAM wParam, LPARAM lParam)
{
HWND hwndBrowser;
HRESULT hr;
if (HIWORD(wParam) == BN_CLICKED)
{
switch (LOWORD(wParam))
{
case ID_SEND_RECEIVE:
case ID_SYNC_THIS_NOW:
case ID_IMAP_FOLDERS:
case ID_NEWSGROUPS:
m_pShellBrowser->GetWindow(&hwndBrowser);
SendMessage(hwndBrowser, WM_COMMAND, wParam, lParam);
break;
case ID_POPUP_SYNCHRONIZE:
_HandleSettingsButton((HWND)lParam);
break;
default:
Assert(FALSE);
break;
}
}
}
//
// FUNCTION: CAccountView::OnCreate
//
// PURPOSE: Creates the child windows necessary for the view and
// initializes the data in those child windows.
//
// PARAMETERS:
// hwnd - Handle of the view being created.
// lpCreateStruct - Pointer to the creation params passed to
// CreateWindow().
//
// RETURN VALUE:
// Returns TRUE if the initialization is successful.
//
BOOL CAccountView::_OnCreate(HWND hwnd, LPCREATESTRUCT lpCreateStruct)
{
HRESULT hr;
DWORD style;
FOLDERINFO info;
COLUMN_SET_TYPE set;
const ACCTVIEWBTN *pBtn;
int i, cBtn, idsMajor, idsMinor;
char sz[CCHMAX_STRINGRES];
switch (m_ftType)
{
case FOLDER_LOCAL:
set = COLUMN_SET_LOCAL_STORE;
pBtn = c_rgMailBtns;
cBtn = ARRAYSIZE(c_rgMailBtns);
idsMajor = 0;
idsMinor = idsLocalFoldersMinor;
break;
case FOLDER_IMAP:
set = COLUMN_SET_IMAP_ACCOUNT;
pBtn = c_rgImapBtns;
cBtn = ARRAYSIZE(c_rgImapBtns);
idsMajor = idsSyncManager;
idsMinor = idsSetSyncSettings;
break;
case FOLDER_HTTPMAIL:
set = COLUMN_SET_HTTPMAIL_ACCOUNT;
pBtn = c_rgHttpBtns;
cBtn = ARRAYSIZE(c_rgHttpBtns);
idsMajor = idsSyncManager;
idsMinor = idsSetSyncSettings;
break;
case FOLDER_NEWS:
set = COLUMN_SET_NEWS_ACCOUNT;
pBtn = c_rgNewsBtns;
cBtn = ARRAYSIZE(c_rgNewsBtns);
idsMajor = idsSyncManagerNews;
idsMinor = idsSetNewsSyncSettings;
break;
default:
Assert(FALSE);
break;
}
for (i = 0; i < cBtn; i++, pBtn++)
{
if (pBtn->cmd == ID_POPUP_SYNCHRONIZE)
style = WS_VISIBLE | WS_TABSTOP | WS_CHILD | BS_NOTIFY | BS_OWNERDRAW | WS_DISABLED;
else
style = WS_VISIBLE | WS_TABSTOP | WS_CHILD | BS_NOTIFY;
AthLoadString(pBtn->idsText, sz, ARRAYSIZE(sz));
m_rgBtns[m_cBtns] = CreateWindow("button", sz, style,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
hwnd, (HMENU)LongToHandle(pBtn->cmd), g_hInst, 0);
if (m_rgBtns[m_cBtns] != NULL)
m_cBtns++;
}
m_hwndList = CreateWindowEx(0, WC_LISTVIEW, c_szEmpty,
WS_VISIBLE | WS_TABSTOP | WS_CHILD | LVS_REPORT | LVS_NOSORTHEADER |
LVS_OWNERDATA | LVS_SHOWSELALWAYS | LVS_SHAREIMAGELISTS,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
hwnd, (HMENU)IDC_SUBSCRIBE_LIST, g_hInst, 0);
Assert(m_hwndList != NULL);
hr = m_pColumns->Initialize(m_hwndList, set);
Assert(SUCCEEDED(hr));
hr = m_pColumns->ApplyColumns(COLUMN_LOAD_REGISTRY, 0, 0);
Assert(SUCCEEDED(hr));
m_hwndHeader = ListView_GetHeader(m_hwndList);
Assert(m_hwndHeader != NULL);
// Initialize the extended styles so we get full row select. Just because
// it looks better.
ListView_SetExtendedListViewStyle(m_hwndList, LVS_EX_FULLROWSELECT | LVS_EX_SUBITEMIMAGES);
Assert(m_himlFolders != NULL);
ListView_SetImageList(m_hwndList, m_himlFolders, LVSIL_SMALL);
SetIntlFont(m_hwndList);
hr = g_pStore->GetFolderInfo(m_idFolder, &info);
if (SUCCEEDED(hr))
{
if (MemAlloc((void **)&m_pszMajor, CCHMAX_STRINGRES))
{
if (idsMajor != 0)
{
AthLoadString(idsMajor, sz, ARRAYSIZE(sz));
wnsprintf(m_pszMajor, CCHMAX_STRINGRES, sz, info.pszName);
}
else
{
StrCpyN(m_pszMajor, info.pszName, CCHMAX_STRINGRES);
}
}
if (idsMinor != 0)
m_pszMinor = AthLoadString(idsMinor, NULL, 0);
g_pStore->FreeRecord(&info);
}
m_clrWatched = DwGetOption(OPT_WATCHED_COLOR);
OptionAdvise(hwnd);
_OnWinIniChange(hwnd);
return TRUE;
}
BOOL CAccountView::_OnWinIniChange(HWND hwnd)
{
char sz[CCHMAX_STRINGRES];
TEXTMETRIC tm;
HDC hdc;
int i, cch, cxMax;
SIZE size;
HFONT hfont, hfontBold, hfontOld;
RECT rc, rcBtn;
GetClientRect(hwnd, &rc);
hfont = HGetCharSetFont(FNT_SYS_ICON, NULL);
hfontBold = HGetCharSetFont(FNT_SYS_ICON_BOLD, NULL);
hdc = GetDC(hwnd);
hfontOld = (HFONT)SelectObject(hdc, (HGDIOBJ)hfontBold);
Assert(m_pszMajor != NULL);
GetTextExtentPoint32(hdc, m_pszMajor, lstrlen(m_pszMajor), &size);
m_rcMajor.left = SUBSCRIBE_BORDER;
m_rcMajor.top = SUBSCRIBE_BORDER;
m_rcMajor.right = m_rcMajor.left + size.cx;
m_rcMajor.bottom = m_rcMajor.top + size.cy;
m_rcMinor.left = m_rcMajor.left;
m_rcMinor.top = m_rcMajor.bottom + 1;
if (m_pszMinor != NULL)
{
SelectObject(hdc, (HGDIOBJ)hfont);
GetTextExtentPoint32(hdc, m_pszMinor, lstrlen(m_pszMinor), &size);
}
m_rcMinor.right = m_rcMinor.left + size.cx;
m_rcMinor.bottom = m_rcMinor.top + size.cy;
m_rcHeader.left = 0;
m_rcHeader.top = 0;
m_rcHeader.right = rc.right;
m_rcHeader.bottom = m_rcMinor.bottom + SUBSCRIBE_BORDER;
m_rcButtons.left = m_rcHeader.left;
m_rcButtons.top = m_rcHeader.bottom + 1;
m_rcButtons.right = m_rcHeader.right;
m_rcButtons.bottom = m_rcButtons.top + m_rcHeader.bottom;
SelectObject(hdc, hfont);
cxMax = 0;
for (i = 0; i < m_cBtns; i++)
{
cch = GetWindowText(m_rgBtns[i], sz, ARRAYSIZE(sz));
GetTextExtentPoint32(hdc, sz, cch, &size);
if (size.cx > cxMax)
cxMax = size.cx;
}
SelectObject(hdc, hfontOld);
ReleaseDC(hwnd, hdc);
rcBtn.top = m_rcButtons.top + SUBSCRIBE_BORDER;
rcBtn.bottom = rcBtn.top + (m_rcMinor.bottom - m_rcMajor.top);
rcBtn.left = m_rcMajor.left;
rcBtn.right = cxMax + 2 * GetSystemMetrics(SM_CXEDGE) + 6 + (rcBtn.bottom - rcBtn.top);
cxMax = SUBSCRIBE_BORDER + (rcBtn.right - rcBtn.left);
for (i = 0; i < m_cBtns; i++)
{
SendMessage(m_rgBtns[i], WM_SETFONT, (WPARAM)hfont, 0);
SetWindowPos(m_rgBtns[i], NULL, rcBtn.left, rcBtn.top,
rcBtn.right - rcBtn.left, rcBtn.bottom - rcBtn.top,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
rcBtn.left += cxMax;
rcBtn.right += cxMax;
}
rc.top = m_rcButtons.bottom + 1;
SendMessage(m_hwndList, WM_SETFONT, (WPARAM)hfont, 0);
SetWindowPos(m_hwndList, NULL, rc.left, rc.top, rc.right - rc.left, rc.bottom - rc.top,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER);
return(TRUE);
}
//
// FUNCTION: CAccountView::OnSize
//
// PURPOSE: Notification that the view window has been resized. In
// response we update the positions of our child windows and
// controls.
//
// PARAMETERS:
// hwnd - Handle of the view window being resized.
// state - Type of resizing requested.
// cxClient - New width of the client area.
// cyClient - New height of the client area.
//
void CAccountView::_OnSize(HWND hwnd, UINT state, int cxClient, int cyClient)
{
int cy;
BOOL fUpdate;
fUpdate = (cxClient > m_rcHeader.right);
m_rcHeader.right = cxClient;
m_rcMajor.right = m_rcHeader.right - SUBSCRIBE_BORDER;
m_rcMinor.right = m_rcMajor.right;
m_rcButtons.right = m_rcHeader.right;
if ((m_rcButtons.bottom + 1) < cyClient)
cy = cyClient - (m_rcButtons.bottom + 1);
else
cy = 1;
SetWindowPos(m_hwndList, NULL, 0, 0, cxClient, cy,
SWP_NOACTIVATE | SWP_NOOWNERZORDER | SWP_NOZORDER | SWP_NOMOVE);
if (fUpdate)
{
InvalidateRect(hwnd, NULL, FALSE);
UpdateWindow(hwnd);
}
}
LRESULT CAccountView::_OnPaint(HWND hwnd, HDC hdc)
{
HFONT hfont, hfontBold, hfontOld;
RECT rc, rcT;
PAINTSTRUCT ps;
COLORREF crText, crBackground;
HBRUSH hBrush, hBrushOld;
if (0 != GetUpdateRect(hwnd, &rc, FALSE))
{
hdc = BeginPaint(hwnd, &ps);
if (IntersectRect(&rcT, &rc, &m_rcHeader))
{
crText = GetSysColor(COLOR_WINDOW);
crBackground = GetSysColor(COLOR_3DSHADOW);
hBrush = CreateSolidBrush(crBackground);
hBrushOld = SelectBrush(hdc, hBrush);
PatBlt(hdc, rcT.left, rcT.top, rcT.right - rcT.left, rcT.bottom - rcT.top, PATCOPY);
SelectBrush(hdc, hBrushOld);
DeleteBrush(hBrush);
SetBkColor(hdc, crBackground);
SetTextColor(hdc, crText);
if (m_pszMajor != NULL &&
IntersectRect(&rcT, &rc, &m_rcMajor))
{
hfontBold = HGetCharSetFont(FNT_SYS_ICON_BOLD, NULL);
hfontOld = (HFONT)SelectObject(hdc, (HGDIOBJ)hfontBold);
DrawText(hdc, m_pszMajor, lstrlen(m_pszMajor), &m_rcMajor, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX);
SelectObject(hdc, (HGDIOBJ)hfontOld);
}
if (m_pszMinor != NULL &&
IntersectRect(&rcT, &rc, &m_rcMinor))
{
hfontBold = HGetCharSetFont(FNT_SYS_ICON, NULL);
hfontOld = (HFONT)SelectObject(hdc, (HGDIOBJ)hfontBold);
DrawText(hdc, m_pszMinor, lstrlen(m_pszMinor), &m_rcMinor, DT_LEFT | DT_TOP | DT_SINGLELINE | DT_NOPREFIX);
SelectObject(hdc, (HGDIOBJ)hfontOld);
}
}
rc.bottom = m_rcButtons.bottom;
DrawEdge(hdc, &rc, EDGE_ETCHED, BF_BOTTOM);
EndPaint(hwnd, &ps);
}
return(0);
}
BOOL DrawArrow(HDC hdc, LPARAM x, WPARAM y, int dx, int dy)
{
int i, iCount;
iCount = (dx + 1) / 2;
// draw arrow head
for (i = 0; i < iCount; i++, dx -= 2, x += 1)
PatBlt(hdc, (int) x, (int) y++, dx, 1, PATCOPY);
return(TRUE);
}
#define CXARROW 9
#define CYARROW 5
void DrawSettingsButton(HWND hwnd, LPDRAWITEMSTRUCT pdi)
{
BOOL fPushed, fDisabled;
TCHAR sz[CCHMAX_STRINGRES];
RECT rcFocus;
int d, cch, x, y, xArrow, yArrow;
SIZE size;
UINT dsFlags;
HGDIOBJ hbrOld;
Assert(pdi->CtlType == ODT_BUTTON);
Assert(pdi->CtlID == ID_POPUP_SYNCHRONIZE);
if (!!(pdi->itemAction & (ODA_DRAWENTIRE | ODA_SELECT)))
{
fPushed = !!(pdi->itemState & ODS_SELECTED);
fDisabled = !!(pdi->itemState & ODS_DISABLED);
if (fPushed)
dsFlags = DFCS_BUTTONPUSH | DFCS_PUSHED;
else
dsFlags = DFCS_BUTTONPUSH;
DrawFrameControl(pdi->hDC, &pdi->rcItem, DFC_BUTTON, dsFlags);
cch = GetWindowText(pdi->hwndItem, sz, ARRAYSIZE(sz));
GetTextExtentPoint32(pdi->hDC, sz, cch, &size);
size.cy++;
x = (pdi->rcItem.left + pdi->rcItem.right - size.cx) / 2;
y = (pdi->rcItem.top + pdi->rcItem.bottom - size.cy) / 2;
if (fPushed)
{
x++;
y++;
}
xArrow = x + size.cx + 7;
yArrow = (pdi->rcItem.top + pdi->rcItem.bottom - CYARROW) / 2;
yArrow++;
if (fPushed)
yArrow++;
if (fDisabled)
{
DrawState(pdi->hDC, NULL, DrawArrow, 0, 0,
xArrow, yArrow, CXARROW, CYARROW, DST_COMPLEX | DSS_DISABLED);
}
else
{
hbrOld = SelectObject(pdi->hDC, GetSysColorBrush(COLOR_BTNTEXT));
DrawArrow(pdi->hDC, xArrow, yArrow, CXARROW, CYARROW);
SelectObject(pdi->hDC, hbrOld);
}
if (fDisabled)
dsFlags = DST_TEXT | DSS_DISABLED;
else
dsFlags = DST_TEXT | DSS_NORMAL;
DrawState(pdi->hDC, NULL, NULL, (LPARAM)sz, (WPARAM)cch,
x, y, size.cx, size.cy, dsFlags);
}
if (!!(pdi->itemAction & ODA_FOCUS) || !!(pdi->itemState & ODS_FOCUS))
{
rcFocus = pdi->rcItem;
d = GetSystemMetrics(SM_CXEDGE) + 1;
rcFocus.left += d;
rcFocus.right -= d;
d = GetSystemMetrics(SM_CYEDGE) + 1;
rcFocus.top += d;
rcFocus.bottom -= d;
DrawFocusRect(pdi->hDC, &rcFocus);
}
}
//
// FUNCTION: CAccountView::OnSetFocus
//
// PURPOSE: If the focus ever is set to the view window, we want to
// make sure it goes to one of our child windows. Preferably
// the focus will go to the last child to have the focus.
//
// PARAMETERS:
// hwnd - Handle of the view window.
// hwndOldFocus - Handle of the window losing focus.
//
void CAccountView::_OnSetFocus(HWND hwnd, HWND hwndOldFocus)
{
SetFocus(m_hwndList);
}
//
// FUNCTION: CAccountView::OnNotify
//
// PURPOSE: Processes the various notifications we receive from our child
// controls.
//
// PARAMETERS:
// hwnd - Handle of the view window.
// idCtl - identifies the control sending the notification
// pnmh - points to a NMHDR struct with more information regarding the
// notification
//
// RETURN VALUE:
// Dependant on the specific notification.
//
LRESULT CAccountView::_OnNotify(HWND hwnd, int idFrom, LPNMHDR pnmhdr)
{
LRESULT lRes=0;
HD_NOTIFY *phdn;
int iSel;
DWORD dwPos;
UINT uChanged;
FOLDERINFO info;
LV_HITTESTINFO lvhti;
NM_LISTVIEW *pnmlv;
LV_DISPINFO *pDispInfo;
DWORD cColumns;
NMCUSTOMDRAW *pnmcd;
COLUMN_ID id;
FOLDERID idFolder;
COLUMN_SET *rgColumns;
HRESULT hr;
FNTSYSTYPE fntType;
if (pnmhdr->hwndFrom != m_hwndList &&
pnmhdr->hwndFrom != m_hwndHeader)
return(0);
switch (pnmhdr->code)
{
case NM_SETFOCUS:
m_pShellBrowser->OnViewWindowActive(this);
_HandleItemStateChange();
break;
case LVN_ITEMACTIVATE:
// Tell our host to open the selected items
iSel = ListView_GetNextItem(m_hwndList, -1, LVNI_ALL | LVNI_SELECTED | LVNI_FOCUSED);
if (iSel >= 0)
g_pInstance->BrowseToObject(SW_SHOWNORMAL, _IdFromIndex(iSel));
break;
case LVN_GETDISPINFO:
pDispInfo = (LV_DISPINFO *)pnmhdr;
id = m_pColumns->GetId(pDispInfo->item.iSubItem);
if ((DWORD)pDispInfo->item.iItem < m_cnode)
_GetDisplayInfo(pDispInfo, id);
break;
case NM_CLICK:
dwPos = GetMessagePos();
lvhti.pt.x = (int)(short)LOWORD(dwPos);
lvhti.pt.y = (int)(short)HIWORD(dwPos);
ScreenToClient(m_hwndList, &(lvhti.pt));
// Ask the ListView where this is
if (-1 == ListView_SubItemHitTest(m_hwndList, &lvhti))
break;
id = m_pColumns->GetId(lvhti.iSubItem);
if (lvhti.flags == LVHT_ONITEMICON)
{
if (id == COLUMN_DOWNLOAD)
{
_ToggleDownload(lvhti.iItem);
}
}
break;
case NM_CUSTOMDRAW:
pnmcd = (NMCUSTOMDRAW *)pnmhdr;
// If this is a prepaint notification, we tell the control we're interested
// in further notfications.
if (pnmcd->dwDrawStage == CDDS_PREPAINT)
{
lRes = CDRF_NOTIFYITEMDRAW;
break;
}
// Do some extra work here to not show the selection on the priority or
// attachment sub columns.
// $REVIEW - Why?
if ((pnmcd->dwDrawStage == CDDS_ITEMPREPAINT) || (pnmcd->dwDrawStage == (CDDS_ITEMPREPAINT | CDDS_SUBITEM)))
{
fntType = FNT_SYS_ICON;
if (pnmcd->dwItemSpec >= m_cnode)
{
lRes = CDRF_DODEFAULT;
break;
}
if (SUCCEEDED(g_pStore->GetFolderInfo(_IdFromIndex((DWORD)(pnmcd->dwItemSpec)), &info)))
{
if (pnmcd->dwDrawStage == (CDDS_ITEMPREPAINT | CDDS_SUBITEM))
{
if ((info.cWatchedUnread) && (m_clrWatched > 0 && m_clrWatched < 16))
{
LPNMLVCUSTOMDRAW(pnmcd)->clrText = rgrgbColors16[m_clrWatched - 1];
}
else
{
id = m_pColumns->GetId(LPNMLVCUSTOMDRAW(pnmcd)->iSubItem);
if (id == COLUMN_DOWNLOAD && 0 == (info.dwFlags & FOLDER_SYNCMASK))
{
LPNMLVCUSTOMDRAW(pnmcd)->clrText = GetSysColor(COLOR_GRAYTEXT);
}
}
}
if (info.cUnread > 0 ||
(info.tyFolder == FOLDER_NEWS && info.dwNotDownloaded > 0))
fntType = FNT_SYS_ICON_BOLD;
g_pStore->FreeRecord(&info);
}
SelectObject(pnmcd->hdc, HGetCharSetFont(fntType, GetListViewCharset()));
lRes = CDRF_NEWFONT | CDRF_NOTIFYSUBITEMDRAW;
break;
}
lRes = CDRF_DODEFAULT;
break;
case LVN_ITEMCHANGED:
pnmlv = (NM_LISTVIEW *)pnmhdr;
if (!!(pnmlv->uChanged & LVIF_STATE) &&
!!((LVIS_SELECTED | LVIS_FOCUSED) & (pnmlv->uOldState ^ pnmlv->uNewState)))
{
_HandleItemStateChange();
}
break;
case HDN_ENDTRACK:
phdn = (HD_NOTIFY *)pnmhdr;
m_pColumns->SetColumnWidth(phdn->iItem, phdn->pitem->cxy);
break;
case HDN_DIVIDERDBLCLICK:
phdn = (HD_NOTIFY *)pnmhdr;
// When the user double clicks on a header divider, we're supposed to
// autosize that column.
m_pColumns->SetColumnWidth(phdn->iItem, ListView_GetColumnWidth(m_hwndList, phdn->iItem));
break;
default:
lRes = 0;
break;
}
return(lRes);
}
void CAccountView::_HandleItemStateChange()
{
OLECMD rgCmds[3];
HRESULT hr;
IOleCommandTarget *pTarget;
int i;
hr = m_pShellBrowser->QueryInterface(IID_IOleCommandTarget, (void **)&pTarget);
if (SUCCEEDED(hr))
{
for (i = 0; i < m_cBtns; i++)
{
rgCmds[i].cmdID = GetWindowLong(m_rgBtns[i], GWL_ID);
rgCmds[i].cmdf = 0;
}
hr = pTarget->QueryStatus(NULL, m_cBtns, rgCmds, NULL);
if (SUCCEEDED(hr))
{
for (i = 0; i < m_cBtns; i++)
{
EnableWindow(m_rgBtns[i], !!(rgCmds[i].cmdf & OLECMDF_ENABLED));
Assert(0 == (rgCmds[i].cmdf & OLECMDF_LATCHED));
Assert(0 == (rgCmds[i].cmdf & OLECMDF_NINCHED));
}
}
pTarget->Release();
}
m_pShellBrowser->UpdateToolbar();
}
HRESULT CAccountView::_GetDisplayInfo(LV_DISPINFO *pDispInfo, COLUMN_ID id)
{
DWORD dwFlags;
int count;
FOLDERINFO info;
HRESULT hr;
FLDRNODE *pNode;
pNode = _NodeFromIndex((DWORD)pDispInfo->item.iItem);
if (pNode == NULL)
return(S_OK);
hr = g_pStore->GetFolderInfo(pNode->id, &info);
if (FAILED(hr))
return(hr);
if (!!(pDispInfo->item.mask & LVIF_TEXT))
{
if (id == COLUMN_NEWSGROUP || id == COLUMN_FOLDER)
{
StrCpyN(pDispInfo->item.pszText, info.pszName, pDispInfo->item.cchTextMax);
}
else if (id == COLUMN_DOWNLOAD)
{
if (!!(info.dwFlags & FOLDER_SUBSCRIBED))
{
if (0 == (info.dwFlags & FOLDER_SYNCMASK))
dwFlags = pNode->dwDownload;
else
dwFlags = info.dwFlags;
Assert(!!(dwFlags & FOLDER_SYNCMASK));
if (!!(dwFlags & FOLDER_DOWNLOADALL))
AthLoadString(idsAllMessages, pDispInfo->item.pszText, pDispInfo->item.cchTextMax);
else if (!!(dwFlags & FOLDER_DOWNLOADNEW))
AthLoadString(idsNewMessages, pDispInfo->item.pszText, pDispInfo->item.cchTextMax);
else if (!!(dwFlags & FOLDER_DOWNLOADHEADERS))
AthLoadString(idsNewHeaders, pDispInfo->item.pszText, pDispInfo->item.cchTextMax);
}
}
else if (id == COLUMN_TOTAL || id == COLUMN_UNREAD)
{
if (id == COLUMN_UNREAD)
count = info.cUnread;
else
count = info.cMessages;
if (FOLDER_NEWS == info.tyFolder)
count += info.dwNotDownloaded;
if (count < 0)
count = 0;
wnsprintf(pDispInfo->item.pszText, pDispInfo->item.cchTextMax, "%d", count);
}
}
if (!!(pDispInfo->item.mask & LVIF_IMAGE))
{
if (id == COLUMN_NEWSGROUP)
{
pDispInfo->item.iImage = iNullBitmap;
if (!!(info.dwFlags & FOLDER_SUBSCRIBED))
{
pDispInfo->item.iImage = iNewsGroup;
if (!!(info.dwFlags & FOLDER_SYNCMASK))
pDispInfo->item.iImage = iNewsGroupSync;
}
}
else if (COLUMN_FOLDER == id)
{
pDispInfo->item.iImage = iNullBitmap;
if (!!(info.dwFlags & FOLDER_SUBSCRIBED))
{
if (info.tySpecial == FOLDER_NOTSPECIAL)
pDispInfo->item.iImage = iFolderClosed;
else
pDispInfo->item.iImage = (iInbox + (((info.tySpecial == FOLDER_BULKMAIL) ? FOLDER_JUNK : info.tySpecial) - 1));
}
}
else if (COLUMN_DOWNLOAD == id)
{
pDispInfo->item.iImage = iNullBitmap;
if (!!(info.dwFlags & FOLDER_SUBSCRIBED))
{
if (!!(info.dwFlags & FOLDER_SYNCMASK))
pDispInfo->item.iImage = iChecked;
else
pDispInfo->item.iImage = iUnchecked;
}
}
}
if (!!(pDispInfo->item.mask & LVIF_INDENT))
{
if (COLUMN_FOLDER == id)
pDispInfo->item.iIndent = pNode->indent;
}
g_pStore->FreeRecord(&info);
return(S_OK);
}
BOOL CAccountView::_OnActivate(UINT uActivation)
{
// if focus stays within the frame, but goes outside our view.
// ie.. TreeView gets focus then we get an activate nofocus. Be sure
// to UIDeactivate the docobj in this case
if (uActivation == SVUIA_ACTIVATE_NOFOCUS)
{
}
if (m_uActivation != uActivation)
{
_OnDeactivate();
m_uActivation = uActivation;
if (!m_fFirstActive)
{
PostMessage(m_hwnd, NVM_INITHEADERS, 0, 0L);
m_fFirstActive = TRUE;
}
}
return TRUE;
}
BOOL CAccountView::_OnDeactivate()
{
return TRUE;
}
HRESULT CAccountView::_InsertChildren(FOLDERID idFolder, DWORD indent, DWORD *piNode)
{
DWORD cnode;
ULONG cFolders;
IEnumerateFolders *pEnum;
FOLDERINFO info;
HRESULT hr;
Assert(piNode != NULL);
Assert(*piNode <= m_cnode);
hr = g_pStore->EnumChildren(idFolder, TRUE, &pEnum);
if (SUCCEEDED(hr))
{
hr = pEnum->Count(&cFolders);
if (SUCCEEDED(hr) && cFolders > 0)
{
while (S_OK == pEnum->Next(1, &info, NULL))
{
Assert(m_cnode <= m_cnodeBuf);
// Skip folders which are hidden
if (ISFLAGSET(info.dwFlags, FOLDER_HIDDEN))
continue;
if (m_cnode == m_cnodeBuf)
{
cnode = m_cnode + cFolders + CALLOCIDBUF;
if (!MemRealloc((void **)&m_rgnode, cnode * sizeof(FLDRNODE)))
{
pEnum->Release();
return(E_OUTOFMEMORY);
}
m_cnodeBuf = cnode;
}
if (*piNode < m_cnode)
MoveMemory(&m_rgnode[*piNode + 1], &m_rgnode[*piNode], (m_cnode - *piNode) * sizeof(FLDRNODE));
m_rgnode[*piNode].id = info.idFolder;
m_rgnode[*piNode].indent = indent;
m_rgnode[*piNode].dwDownload = m_dwDownloadDef;
(*piNode)++;
m_cnode++;
if (!!(info.dwFlags & FOLDER_HASCHILDREN))
hr = _InsertChildren(info.idFolder, indent + 1, piNode);
g_pStore->FreeRecord(&info);
if (FAILED(hr))
break;
}
}
pEnum->Release();
}
return(hr);
}
HRESULT CAccountView::_InsertChildrenSpecial(FOLDERID idFolder, DWORD indent, DWORD *piNode)
{
DWORD cnode;
ULONG iFolder, cFolders;
IEnumerateFolders *pEnum;
FOLDERINFO info;
HRESULT hr;
FLDRNODE *rgNode, *pNode;
Assert(piNode != NULL);
Assert(*piNode <= m_cnode);
Assert(indent == 0);
rgNode = NULL;
hr = g_pStore->EnumChildren(idFolder, TRUE, &pEnum);
if (SUCCEEDED(hr))
{
hr = pEnum->Count(&cFolders);
if (SUCCEEDED(hr) && cFolders > 0)
{
if (!MemAlloc((void **)&rgNode, cFolders * sizeof(FLDRNODE)))
{
hr = E_OUTOFMEMORY;
}
else
{
pNode = rgNode;
cFolders = 0;
while (S_OK == pEnum->Next(1, &info, NULL))
{
if ((!(g_dwAthenaMode & MODE_NEWSONLY) || (info.tySpecial != FOLDER_INBOX)) &&
ISFLAGCLEAR(info.dwFlags, FOLDER_HIDDEN))
{
pNode->id = info.idFolder;
pNode->indent = !!(info.dwFlags & FOLDER_HASCHILDREN) ? 1 : 0;
pNode->dwDownload = m_dwDownloadDef;
pNode++;
cFolders++;
}
g_pStore->FreeRecord(&info);
}
qsort(rgNode, cFolders, sizeof(FLDRNODE), GroupCompare);
}
}
pEnum->Release();
}
if (rgNode != NULL)
{
Assert(SUCCEEDED(hr));
Assert(cFolders > 0);
Assert(m_cnode == 0);
Assert(m_cnodeBuf == 0);
for (iFolder = 0, pNode = rgNode; iFolder < cFolders; iFolder++, pNode++)
{
if (m_cnode == m_cnodeBuf)
{
cnode = m_cnode + cFolders + CALLOCIDBUF;
if (!MemRealloc((void **)&m_rgnode, cnode * sizeof(FLDRNODE)))
{
hr = E_OUTOFMEMORY;
break;
}
m_cnodeBuf = cnode;
}
m_rgnode[*piNode].id = pNode->id;
m_rgnode[*piNode].indent = indent;
m_rgnode[*piNode].dwDownload = m_dwDownloadDef;
(*piNode)++;
m_cnode++;
if (pNode->indent == 1)
{
hr = _InsertChildren(pNode->id, indent + 1, piNode);
if (FAILED(hr))
break;
}
}
MemFree(rgNode);
}
return(hr);
}
void CAccountView::_PostCreate()
{
HRESULT hr;
DWORD iNode;
BOOL fNews, fSub;
Assert(m_cnode == 0);
ProcessICW(m_hwndOwner, m_ftType);
fNews = m_ftType == FOLDER_NEWS;
iNode = 0;
if (fNews)
hr = _InsertChildren(m_idFolder, 0, &iNode);
else
hr = _InsertChildrenSpecial(m_idFolder, 0, &iNode);
if (FAILED(hr))
{
if (m_rgnode != NULL)
{
MemFree(m_rgnode);
m_rgnode = NULL;
}
m_cnode = 0;
m_cnodeBuf = 0;
}
else
{
Assert(iNode == m_cnode);
}
ListView_SetItemCount(m_hwndList, m_cnode);
if (m_cnode > 0)
{
ListView_SetItemState(m_hwndList, -1, 0, LVIS_SELECTED | LVIS_FOCUSED);
ListView_SetItemState(m_hwndList, 0, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
}
if (m_cnode == 0)
m_pEmptyList->Show(m_hwndList, m_ftType == FOLDER_NEWS ? (LPSTR)idsEmptyNewsAcct : (LPSTR)idsEmptyMailAcct);
UpdateWindow(m_hwndList);
g_pStore->RegisterNotify(IINDEX_SUBSCRIBED, REGISTER_NOTIFY_NOADDREF, 0, (IDatabaseNotify *)this);
m_fRegistered = TRUE;
fSub = FALSE;
if (m_cnode == 0 && (fNews || m_ftType == FOLDER_IMAP || m_ftType == FOLDER_HTTPMAIL))
{
if (IDYES == AthMessageBoxW(m_hwndOwner, MAKEINTRESOURCEW(idsAthena),
fNews ? MAKEINTRESOURCEW(idsErrNoSubscribedGroups) : MAKEINTRESOURCEW(idsErrNoSubscribedFolders),
0, MB_YESNO))
{
if (m_ftType == FOLDER_HTTPMAIL)
DownloadNewsgroupList(m_hwndOwner, m_idFolder);
else
DoSubscriptionDialog(m_hwndOwner, fNews, m_idFolder);
fSub = TRUE;
}
}
else if (m_ftType == FOLDER_IMAP && NULL != g_pStore)
{
FOLDERINFO fiServer;
if (SUCCEEDED(g_pStore->GetFolderInfo(m_idFolder, &fiServer)))
{
CheckIMAPDirty(fiServer.pszAccountId, m_hwnd, fiServer.idFolder, NOFLAGS);
g_pStore->FreeRecord(&fiServer);
}
}
if (!fSub && fNews)
hr = NewsUtil_CheckForNewGroups(m_hwnd, m_idFolder, &m_pGroups);
}
void CAccountView::_OnContextMenu(HWND hwnd, HWND hwndFrom, int x, int y)
{
HRESULT hr;
int iSel, i, id;
HMENU hmenu;
FOLDERID idFolder;
LV_HITTESTINFO lvhti;
POINT pt = {x, y};
// We only have context menus for the ListView
if (hwndFrom != m_hwndList)
return;
if (MAKELPARAM(x, y) == -1) // invoked from keyboard: figure out pos.
{
Assert(hwndFrom == m_hwndList);
i = ListView_GetFirstSel(m_hwndList);
if (i == -1)
return;
ListView_GetItemPosition(m_hwndList, i, &pt);
ClientToScreen(m_hwndList, &pt);
x = pt.x;
y = pt.y;
}
id = 0;
if (WindowFromPoint(pt) == m_hwndHeader)
{
// Pop up the context menu.
hmenu = LoadPopupMenu(IDR_COLUMNS_POPUP);
if (hmenu != NULL)
{
// Disable sort options because we don't support sorting
EnableMenuItem(hmenu, ID_SORT_ASCENDING, MF_GRAYED|MF_DISABLED);
EnableMenuItem(hmenu, ID_SORT_ASCENDING, MF_GRAYED|MF_DISABLED);
id = TrackPopupMenuEx(hmenu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
x, y, m_hwnd, NULL);
DestroyMenu(hmenu);
}
}
else
{
// Find out where the click happened
lvhti.pt.x = x;
lvhti.pt.y = y;
ScreenToClient(m_hwndList, &lvhti.pt);
// Have the ListView tell us what element this was on
iSel = ListView_HitTest(m_hwndList, &lvhti);
if (iSel >= 0)
{
idFolder = _IdFromIndex((DWORD)iSel);
hr = MenuUtil_GetContextMenu(idFolder, (IOleCommandTarget *)this, &hmenu);
if (SUCCEEDED(hr))
{
id = TrackPopupMenuEx(hmenu, TPM_RETURNCMD | TPM_LEFTALIGN | TPM_LEFTBUTTON | TPM_RIGHTBUTTON,
x, y, m_hwnd, NULL);
DestroyMenu(hmenu);
}
}
}
if (id != 0)
Exec(NULL, id, OLECMDEXECOPT_DODEFAULT, NULL, NULL);
}
int __cdecl GroupCompare(const void *lParam1, const void *lParam2)
{
int cmp;
HRESULT hr;
FOLDERINFO info1, info2;
IxpAssert(lParam1 != NULL);
IxpAssert(lParam2 != NULL);
if (FAILED(g_pStore->GetFolderInfo(((FLDRNODE *)lParam1)->id, &info1)))
return -1;
if (FAILED(g_pStore->GetFolderInfo(((FLDRNODE *)lParam2)->id, &info2)))
{
g_pStore->FreeRecord(&info1);
return 1;
}
IxpAssert(0 == (info1.dwFlags & FOLDER_SERVER));
IxpAssert(0 == (info2.dwFlags & FOLDER_SERVER));
IxpAssert(info1.idParent == info2.idParent);
if (info1.tySpecial != FOLDER_NOTSPECIAL)
{
if (info2.tySpecial != FOLDER_NOTSPECIAL)
cmp = info1.tySpecial - info2.tySpecial;
else
cmp = -1;
}
else
{
if (info2.tySpecial != FOLDER_NOTSPECIAL)
cmp = 1;
else
cmp = lstrcmpi(info1.pszName, info2.pszName);
}
g_pStore->FreeRecord(&info1);
g_pStore->FreeRecord(&info2);
return(cmp);
}
HRESULT CAccountView::_InsertFolder(LPFOLDERINFO pFolder)
{
BOOL fHide;
DWORD cnode, cSibs, indent, index, iFirstSib, iSib, iEnd;
HRESULT hr;
LV_ITEM lvi;
FLDRNODE *rgNodeSib, *pNode;
Assert(!!(pFolder->dwFlags & FOLDER_SUBSCRIBED));
// Check if folder is hidden
if (pFolder->dwFlags & FOLDER_HIDDEN)
return S_OK; // Do not display to user
if (pFolder->tyFolder == FOLDER_NEWS)
return(_InsertFolderNews(pFolder));
fHide = (m_cnode == 0);
index = _GetFolderIndex(pFolder->idFolder);
if (index != -1)
{
// TODO: are we safe to assume that this one doesn't have subscribed
// children that we aren't aware of????
return(S_OK);
}
// figure out which folder the new folder is being inserted under
if (pFolder->idParent == m_idFolder)
{
iFirstSib = 0;
indent = 0;
}
else
{
index = _GetFolderIndex(pFolder->idParent);
if (index == -1)
return(S_OK);
indent = m_rgnode[index].indent + 1;
iFirstSib = index + 1;
}
// get all of the siblings of the new folder
if (!MemAlloc((void **)&rgNodeSib, (m_cnode - iFirstSib + 1) * sizeof(FLDRNODE)))
return(E_OUTOFMEMORY);
cSibs = 0;
for (iSib = iFirstSib, pNode = &m_rgnode[iSib]; iSib < m_cnode; iSib++, pNode++)
{
if (pNode->indent < indent)
{
break;
}
else if (pNode->indent == indent)
{
rgNodeSib[cSibs].id = pNode->id;
cSibs++;
}
}
iEnd = iSib;
// sort the new folder and its siblings, so we know where the new one needs
// to be inserted
rgNodeSib[cSibs].id = pFolder->idFolder;
cSibs++;
qsort(rgNodeSib, cSibs, sizeof(FLDRNODE), GroupCompare);
// find out where we're sticking the new folder
for (iSib = 0, pNode = rgNodeSib; iSib < cSibs; iSib++, pNode++)
{
if (pNode->id == pFolder->idFolder)
break;
}
Assert(iSib < cSibs);
if (iSib + 1 < cSibs)
index = _GetFolderIndex(rgNodeSib[iSib + 1].id);
else
index = iEnd;
MemFree(rgNodeSib);
if (m_cnode == m_cnodeBuf)
{
cnode = m_cnodeBuf + CALLOCIDBUF;
if (!MemRealloc((void **)&m_rgnode, cnode * sizeof(FLDRNODE)))
return(E_OUTOFMEMORY);
m_cnodeBuf = cnode;
}
SetWindowRedraw(m_hwndList, FALSE);
if (index < m_cnode)
MoveMemory(&m_rgnode[index + 1], &m_rgnode[index], (m_cnode - index) * sizeof(FLDRNODE));
m_rgnode[index].id = pFolder->idFolder;
m_rgnode[index].indent = indent;
m_rgnode[index].dwDownload = m_dwDownloadDef;
m_cnode++;
iEnd = index + 1;
if (!!(pFolder->dwFlags & FOLDER_HASCHILDREN))
{
hr = _InsertChildren(pFolder->idFolder, indent + 1, &iEnd);
// TODO: error handling
Assert(SUCCEEDED(hr));
}
ZeroMemory(&lvi, sizeof(LV_ITEM));
while (index < iEnd)
{
lvi.iItem = index++;
ListView_InsertItem(m_hwndList, &lvi);
}
if (fHide)
m_pEmptyList->Hide();
SetWindowRedraw(m_hwndList, TRUE);
UpdateWindow(m_hwndList);
return(S_OK);
}
HRESULT CAccountView::_InsertFolderNews(LPFOLDERINFO pFolder)
{
DWORD cnode;
HRESULT hr;
LV_ITEM lvi;
if (m_cnode == m_cnodeBuf)
{
cnode = m_cnodeBuf + CALLOCIDBUF;
if (!MemRealloc((void **)&m_rgnode, cnode * sizeof(FLDRNODE)))
return(E_OUTOFMEMORY);
m_cnodeBuf = cnode;
}
m_rgnode[m_cnode].id = pFolder->idFolder;
m_rgnode[m_cnode].indent = 0;
m_rgnode[m_cnode].dwDownload = m_dwDownloadDef;
m_cnode++;
qsort(m_rgnode, m_cnode, sizeof(FLDRNODE), GroupCompare);
ZeroMemory(&lvi, sizeof(LV_ITEM));
lvi.iItem = _GetFolderIndex(pFolder->idFolder);
Assert(lvi.iItem != -1);
ListView_InsertItem(m_hwndList, &lvi);
if (m_cnode == 1)
m_pEmptyList->Hide();
return(S_OK);
}
int CAccountView::_GetFolderIndex(FOLDERID id)
{
int i;
FLDRNODE *pnode;
for (i = 0, pnode = m_rgnode; (DWORD)i < m_cnode; i++, pnode++)
{
if (id == pnode->id)
break;
}
if ((DWORD)i == m_cnode)
i = -1;
return(i);
}
HRESULT CAccountView::_UpdateFolder(LPFOLDERINFO pFolder1, LPFOLDERINFO pFolder2)
{
HRESULT hr;
int iItem;
// Visibility change (FOLDER_SUBSCRIBED or FOLDER_HIDDEN)
if (ISFLAGSET(pFolder1->dwFlags, FOLDER_SUBSCRIBED) != ISFLAGSET(pFolder2->dwFlags, FOLDER_SUBSCRIBED) ||
ISFLAGSET(pFolder1->dwFlags, FOLDER_HIDDEN) != ISFLAGSET(pFolder2->dwFlags, FOLDER_HIDDEN))
{
if (ISFLAGSET(pFolder2->dwFlags, FOLDER_SUBSCRIBED) && ISFLAGCLEAR(pFolder2->dwFlags, FOLDER_HIDDEN))
{
hr = _InsertFolder(pFolder2);
}
else
{
hr = _DeleteFolder(pFolder2);
}
return(hr);
}
// Moved or renamed
if (pFolder1->idParent != pFolder2->idParent ||
0 != lstrcmpi(pFolder1->pszName, pFolder2->pszName))
{
Assert(m_ftType != FOLDER_NEWS);
hr = _DeleteFolder(pFolder1);
hr = _InsertFolder(pFolder2);
return(hr);
}
// State change
if (pFolder1->cUnread != pFolder2->cUnread ||
pFolder1->cMessages != pFolder2->cMessages ||
(pFolder1->dwFlags & FOLDER_SYNCMASK) != (pFolder2->dwFlags & FOLDER_SYNCMASK) ||
0 != lstrcmp(pFolder1->pszName, pFolder2->pszName) ||
// news only
(pFolder1->tyFolder == FOLDER_NEWS &&
(pFolder1->dwServerCount != pFolder2->dwServerCount ||
pFolder1->dwServerHigh != pFolder2->dwServerHigh ||
pFolder1->dwServerLow != pFolder2->dwServerLow)))
{
iItem = _GetFolderIndex(pFolder1->idFolder);
if (iItem != -1)
ListView_RedrawItems(m_hwndList, iItem, iItem);
}
return(S_OK);
}
int CAccountView::_GetSubFolderCount(int index)
{
DWORD indent;
int indexT;
Assert((DWORD)index < m_cnode);
indent = m_rgnode[index].indent;
index++;
indexT = index;
while ((DWORD)index < m_cnode)
{
if (m_rgnode[index].indent <= indent)
break;
index++;
}
return(index - indexT);
}
HRESULT CAccountView::_DeleteFolder(LPFOLDERINFO pFolder)
{
HRESULT hr;
int iItem, cSub;
iItem = _GetFolderIndex(pFolder->idFolder);
if (iItem == -1)
return(S_OK);
SetWindowRedraw(m_hwndList, FALSE);
cSub = _GetSubFolderCount(iItem);
if ((DWORD)(iItem + cSub) < (m_cnode - 1))
MoveMemory(&m_rgnode[iItem], &m_rgnode[iItem + cSub + 1], (m_cnode - (iItem + cSub + 1)) * sizeof(FLDRNODE));
m_cnode -= cSub + 1;
while (cSub >= 0)
{
ListView_DeleteItem(m_hwndList, iItem + cSub);
cSub--;
}
if (m_cnode == 0)
m_pEmptyList->Show(m_hwndList, m_ftType == FOLDER_NEWS ? (LPSTR)idsEmptyNewsAcct : (LPSTR)idsEmptyMailAcct);
SetWindowRedraw(m_hwndList, TRUE);
UpdateWindow(m_hwndList);
return(S_OK);
}
HRESULT CAccountView::_HandleAccountRename(LPFOLDERINFO pFolder)
{
char sz[CCHMAX_STRINGRES];
HDC hdc;
SIZE size;
HFONT hfontBold, hfontOld;
Assert(m_pszMajor != NULL);
Assert(pFolder != NULL);
AthLoadString(idsSyncManager, sz, ARRAYSIZE(sz));
wnsprintf(m_pszMajor, CCHMAX_STRINGRES, sz, pFolder->pszName);
hfontBold = HGetCharSetFont(FNT_SYS_ICON_BOLD, NULL);
hdc = GetDC(m_hwnd);
hfontOld = (HFONT)SelectObject(hdc, (HGDIOBJ)hfontBold);
GetTextExtentPoint32(hdc, m_pszMajor, lstrlen(m_pszMajor), &size);
m_rcMajor.left = SUBSCRIBE_BORDER;
m_rcMajor.top = SUBSCRIBE_BORDER;
m_rcMajor.right = m_rcMajor.left + size.cx;
m_rcMajor.bottom = m_rcMajor.top + size.cy;
SelectObject(hdc, hfontOld);
ReleaseDC(m_hwnd, hdc);
InvalidateRect(m_hwnd, NULL, FALSE);
UpdateWindow(m_hwnd);
return(S_OK);
}
STDMETHODIMP CAccountView::OnTransaction(HTRANSACTION hTransaction, DWORD_PTR dwCookie, IDatabase *pDB)
{
BOOL fMatch;
DWORD i;
FOLDERINFO Folder1={0};
FOLDERINFO Folder2={0};
FOLDERINFO Server;
ORDINALLIST Ordinals;
TRANSACTIONTYPE tyTransaction;
INDEXORDINAL iIndex;
HRESULT hr;
while (hTransaction)
{
hr = pDB->GetTransaction(&hTransaction, &tyTransaction, &Folder1, &Folder2, &iIndex, &Ordinals);
if (FAILED(hr))
break;
if (Folder1.idFolder == m_idFolder)
{
if (TRANSACTION_UPDATE == tyTransaction &&
0 != lstrcmp(Folder1.pszName, Folder2.pszName))
{
hr = _HandleAccountRename(&Folder2);
}
}
else if (Folder1.tyFolder == m_ftType && 0 == (Folder1.dwFlags & FOLDER_SERVER))
{
fMatch = FALSE;
if (m_ftType == FOLDER_LOCAL)
{
if (Folder1.tyFolder == FOLDER_LOCAL)
fMatch = TRUE;
}
else
{
hr = GetFolderServer(Folder1.idParent, &Server);
if (SUCCEEDED(hr))
{
fMatch = (Server.idFolder == m_idFolder);
g_pStore->FreeRecord(&Server);
}
}
if (fMatch)
{
// Insert (new Folder notification)
if (TRANSACTION_INSERT == tyTransaction)
{
hr = _InsertFolder(&Folder1);
}
// Update
else if (TRANSACTION_UPDATE == tyTransaction)
{
hr = _UpdateFolder(&Folder1, &Folder2);
}
// Delete
else if (TRANSACTION_DELETE == tyTransaction)
{
hr = _DeleteFolder(&Folder1);
}
}
}
}
g_pStore->FreeRecord(&Folder1);
g_pStore->FreeRecord(&Folder2);
return(S_OK);
}
HRESULT CAccountView::_ToggleDownload(int iItem)
{
FLDRNODE *pnode;
FOLDERINFO info;
HRESULT hr;
pnode = _NodeFromIndex(iItem);
Assert(pnode != NULL);
hr = g_pStore->GetFolderInfo(pnode->id, &info);
if (SUCCEEDED(hr))
{
if (!!(info.dwFlags & FOLDER_SUBSCRIBED))
{
if (!!(info.dwFlags & FOLDER_SYNCMASK))
{
pnode->dwDownload = (info.dwFlags & FOLDER_SYNCMASK);
info.dwFlags &= ~FOLDER_SYNCMASK;
}
else
{
Assert(0 == (pnode->dwDownload & ~FOLDER_SYNCMASK));
info.dwFlags |= pnode->dwDownload;
}
hr = g_pStore->UpdateRecord(&info);
}
g_pStore->FreeRecord(&info);
}
return(S_OK);
}
HRESULT CAccountView::_MarkForDownload(DWORD nCmdID)
{
int iSel;
FLDRFLAGS flag;
FOLDERINFO info;
HRESULT hr;
FLDRNODE *pnode;
switch (nCmdID)
{
case ID_MARK_RETRIEVE_FLD_NEW_HDRS:
flag = FOLDER_DOWNLOADHEADERS;
break;
case ID_MARK_RETRIEVE_FLD_NEW_MSGS:
flag = FOLDER_DOWNLOADNEW;
break;
case ID_MARK_RETRIEVE_FLD_ALL_MSGS:
flag = FOLDER_DOWNLOADALL;
break;
case ID_UNMARK_RETRIEVE_FLD:
flag = 0;
break;
default:
Assert(FALSE);
break;
}
iSel = -1;
while (-1 != (iSel = ListView_GetNextItem(m_hwndList, iSel, LVNI_SELECTED | LVNI_ALL)))
{
pnode = _NodeFromIndex(iSel);
hr = g_pStore->GetFolderInfo(pnode->id, &info);
if (SUCCEEDED(hr))
{
if (!!(info.dwFlags & FOLDER_SUBSCRIBED) &&
(info.dwFlags & FOLDER_SYNCMASK) != flag)
{
if (flag == 0)
pnode->dwDownload = (info.dwFlags & FOLDER_SYNCMASK);
info.dwFlags &= ~FOLDER_SYNCMASK;
if (flag != 0)
info.dwFlags |= flag;
hr = g_pStore->UpdateRecord(&info);
}
g_pStore->FreeRecord(&info);
}
}
return(S_OK);
}
HRESULT CAccountView::_Subscribe(BOOL fSubscribe)
{
FOLDERID *pid;
int iSel, cSel, cid;
cSel = ListView_GetSelectedCount(m_hwndList);
if (cSel > 0)
{
if (!MemAlloc((void **)&pid, cSel * sizeof(FOLDERID)))
return(E_OUTOFMEMORY);
cid = 0;
iSel = -1;
while (-1 != (iSel = ListView_GetNextItem(m_hwndList, iSel, LVNI_SELECTED | LVNI_ALL)))
{
Assert(cid < cSel);
pid[cid] = _IdFromIndex(iSel);
cid++;
}
MenuUtil_OnSubscribeGroups(m_hwndOwner, pid, cid, fSubscribe);
MemFree(pid);
}
return(S_OK);
}
HRESULT CAccountView::_MarkAllRead()
{
int iSel;
IMessageFolder *pFolder;
ADJUSTFLAGS flags;
FOLDERID idFolder;
CStoreCB *pCB;
HRESULT hr;
pCB = new CStoreCB;
if (pCB == NULL)
return(E_OUTOFMEMORY);
hr = pCB->Initialize(m_hwndOwner, MAKEINTRESOURCE(idsSettingMessageFlags), FALSE);
if (SUCCEEDED(hr))
{
flags.dwAdd = ARF_READ;
flags.dwRemove = 0;
iSel = -1;
while (-1 != (iSel = ListView_GetNextItem(m_hwndList, iSel, LVNI_SELECTED | LVNI_ALL)))
{
idFolder = _IdFromIndex(iSel);
if (SUCCEEDED(g_pStore->OpenFolder(idFolder, NULL, NOFLAGS, &pFolder)))
{
hr = pFolder->SetMessageFlags(NULL, &flags, NULL, (IStoreCallback *)pCB);
if (hr == E_PENDING)
{
hr = pCB->Block();
pCB->Reset();
}
pFolder->Release();
}
if (FAILED(hr))
break;
}
pCB->Close();
}
pCB->Release();
return(S_OK);
}