Windows2003-3790/inetcore/outlookexpress/mailnews/store/newfldr.cpp
2020-09-30 16:53:55 +02:00

802 lines
24 KiB
C++

//--------------------------------------------------------------------------
// Newfldr.cpp
//--------------------------------------------------------------------------
#include "pch.hxx"
#include "imagelst.h"
#include "newfldr.h"
#include <ourguid.h>
#include "conman.h"
#include "storutil.h"
#include "storecb.h"
#include "shlwapip.h"
#include "instance.h"
#include "demand.h"
//--------------------------------------------------------------------------
// Constants
//--------------------------------------------------------------------------
#define WM_SETFOLDERSELECT (WM_USER + 1666)
//--------------------------------------------------------------------------
// SELECTFOLDER
//--------------------------------------------------------------------------
typedef struct tagSELECTFOLDER {
DWORD op;
FOLDERID idCurrent; // Current Selected Folder
FOLDERDIALOGFLAGS dwFlags; // Folder dialog flags
LPSTR pszTitle; // Title of the dialog box
LPSTR pszText; // Why are you asking for a folder
FOLDERID idSelected; // The selected folder
CTreeViewFrame *pFrame; // Treeview frame object
BOOL fPending;
CStoreDlgCB *pCallback;
FOLDERID idParent;
char szName[CCHMAX_FOLDER_NAME];
} SELECTFOLDER, *LPSELECTFOLDER;
//--------------------------------------------------------------------------
// NEWFOLDERDIALOGINIT
//--------------------------------------------------------------------------
typedef struct tagNEWFOLDERDIALOGINIT {
IN FOLDERID idParent;
OUT FOLDERID idNew;
BOOL fPending;
IN CStoreDlgCB *pCallback;
char szName[CCHMAX_FOLDER_NAME];
} NEWFOLDERDIALOGINIT, *LPNEWFOLDERDIALOGINIT;
//--------------------------------------------------------------------------
// SelectFolderDlgProc
//--------------------------------------------------------------------------
INT_PTR CALLBACK SelectFolderDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
INT_PTR CALLBACK NewFolderDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
HRESULT CreateNewFolder(HWND hwnd, LPCSTR pszName, FOLDERID idParent, LPFOLDERID pidNew, IStoreCallback *pCallback);
BOOL EnabledFolder(HWND hwnd, LPSELECTFOLDER pSelect, FOLDERID idFolder);
HRESULT GetCreatedFolderId(FOLDERID idParent, LPCSTR pszName, FOLDERID *pid);
BOOL SelectFolder_HandleCommand(HWND hwnd, WORD wID, LPSELECTFOLDER pSelect);
void SelectFolder_HandleStoreComplete(HWND hwnd, LPSELECTFOLDER pSelect);
//--------------------------------------------------------------------------
// Globals
//--------------------------------------------------------------------------
static FOLDERID g_idPrevSel = FOLDERID_LOCAL_STORE;
//--------------------------------------------------------------------------
// SelectFolderDialog
//--------------------------------------------------------------------------
HRESULT SelectFolderDialog(
IN HWND hwnd,
IN DWORD op,
IN FOLDERID idCurrent,
IN FOLDERDIALOGFLAGS dwFlags,
IN_OPT LPCSTR pszTitle,
IN_OPT LPCSTR pszText,
OUT_OPT LPFOLDERID pidSelected)
{
// Locals
HRESULT hr=S_OK;
UINT uAnswer;
SELECTFOLDER Select={0};
// Trace
TraceCall("SelectFolderDialog");
// Invalid Args
Assert(IsWindow(hwnd));
Assert(((int) op) >= SFD_SELECTFOLDER && op < SFD_LAST);
// Initialize Select Folder
Select.op = op;
if (SFD_MOVEFOLDER == op || (!!(dwFlags & FD_FORCEINITSELFOLDER) && FOLDERID_ROOT != idCurrent))
{
Assert(idCurrent != FOLDERID_INVALID);
Select.idCurrent = idCurrent;
}
else
{
Select.idCurrent = g_idPrevSel;
}
Select.dwFlags = dwFlags | TREEVIEW_DIALOG;
if (g_dwAthenaMode & MODE_OUTLOOKNEWS)
Select.dwFlags |= TREEVIEW_NOIMAP | TREEVIEW_NOHTTP;
Select.pszTitle = (LPSTR)pszTitle;
Select.pszText = (LPSTR)pszText;
Select.pCallback = new CStoreDlgCB;
if (Select.pCallback == NULL)
return(E_OUTOFMEMORY);
// Create the Dialog Box
if (IDOK != DialogBoxParam(g_hLocRes, ((op == SFD_NEWFOLDER) ? MAKEINTRESOURCE(iddCreateFolder) : MAKEINTRESOURCE(iddSelectFolder)), hwnd, SelectFolderDlgProc, (LPARAM)&Select))
{
hr = TraceResult(hrUserCancel);
goto exit;
}
// Return selected folderid
g_idPrevSel = Select.idSelected;
if (pidSelected)
*pidSelected = Select.idSelected;
exit:
Select.pCallback->Release();
// Done
return hr;
}
//--------------------------------------------------------------------------
// SelectFolderDlgProc
//--------------------------------------------------------------------------
INT_PTR CALLBACK SelectFolderDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Locals
FOLDERINFO info;
HRESULT hr;
BOOL fEnable;
LPSELECTFOLDER pSelect;
HWND hwndT;
HWND hwndTree;
CHAR sz[256];
WORD wID;
RECT rc;
FOLDERID id;
NEWFOLDERDIALOGINIT NewFolder;
FOLDERINFO Folder;
CTreeView *pTreeView;
// Trace
TraceCall("SelectFolderDlgProc");
// Get pSelect
pSelect = (LPSELECTFOLDER)GetWndThisPtr(hwnd);
switch (msg)
{
case WM_INITDIALOG:
// Better not have it yet
Assert(NULL == pSelect);
// Set pSelect
pSelect = (LPSELECTFOLDER)lParam;
// Set This pointer
SetWndThisPtr(hwnd, (LPSELECTFOLDER)lParam);
if (pSelect->op != SFD_SELECTFOLDER)
{
Assert(pSelect->pCallback != NULL);
pSelect->pCallback->Initialize(hwnd);
}
if (pSelect->op == SFD_NEWFOLDER)
{
hwndT = GetDlgItem(hwnd, idcFolderEdit);
SetIntlFont(hwndT);
SendMessage(hwndT, EM_LIMITTEXT, CCHMAX_FOLDER_NAME - 1, 0);
}
else if (ISFLAGSET(pSelect->dwFlags, FD_NONEWFOLDERS))
{
ShowWindow(GetDlgItem(hwnd, idcNewFolderBtn), SW_HIDE);
}
// Set the title
if (pSelect->pszTitle != NULL)
{
// Must be a string resourceid
if (IS_INTRESOURCE(pSelect->pszTitle))
{
// Load the String
AthLoadString(PtrToUlong(pSelect->pszTitle), sz, ARRAYSIZE(sz));
// Set Temp
SetWindowText(hwnd, sz);
}
// Otherwise, just use the string
else
SetWindowText(hwnd, pSelect->pszTitle);
}
// Do we have some status text
if (pSelect->pszText != NULL)
{
// Must be a resource string id
if (IS_INTRESOURCE(pSelect->pszText))
{
// Load the String
AthLoadString(PtrToUlong(pSelect->pszText), sz, ARRAYSIZE(sz));
// Set Temp
SetWindowText(GetDlgItem(hwnd, idcTreeViewText), sz);
}
// Otherwise, just use the string
else
SetWindowText(GetDlgItem(hwnd, idcTreeViewText), pSelect->pszText);
}
// Set the treeview font
hwndT = GetDlgItem(hwnd, idcTreeView);
Assert(hwndT != NULL);
SetIntlFont(hwndT);
GetWindowRect(hwndT, &rc);
MapWindowPoints(NULL, hwnd, (LPPOINT)&rc, 2);
DestroyWindow(hwndT);
// Create a Frame
pSelect->pFrame = new CTreeViewFrame;
if (NULL == pSelect->pFrame)
{
EndDialog(hwnd, IDCANCEL);
return FALSE;
}
// Initialzie the tree view frame
if (FAILED(pSelect->pFrame->Initialize(hwnd, &rc, (TREEVIEW_FLAGS & pSelect->dwFlags))))
{
EndDialog(hwnd, IDCANCEL);
return FALSE;
}
// Get the Tree View Object from the Frame
pTreeView = pSelect->pFrame->GetTreeView();
// Get the Window Handle
if (SUCCEEDED(pTreeView->GetWindow(&hwndTree)))
{
hwndT = GetDlgItem(hwnd, idcTreeViewText);
SetWindowPos(hwndTree, hwndT, 0, 0, 0, 0, SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOOWNERZORDER | SWP_NOREDRAW | SWP_NOSIZE);
}
// Refresh the Treeview
pTreeView->Refresh();
// Set current selection
if (FAILED(pTreeView->SetSelection(pSelect->idCurrent, 0)))
{
pSelect->idCurrent = g_idPrevSel;
pTreeView->SetSelection(pSelect->idCurrent, 0);
}
// Center Myself
CenterDialog(hwnd);
// Done
return(TRUE);
case WM_SETFOLDERSELECT:
// Validate Params
Assert(wParam != NULL && pSelect != NULL);
// Get the Tree View Object
pTreeView = pSelect->pFrame->GetTreeView();
// Validate
Assert(pTreeView != NULL);
// Set current selection
pTreeView->SetSelection((FOLDERID)wParam, 0);
// Done
return(TRUE);
case WM_STORE_COMPLETE:
SelectFolder_HandleStoreComplete(hwnd, pSelect);
return(TRUE);
case WM_COMMAND:
// Get the Command Id
wID = LOWORD(wParam);
return(SelectFolder_HandleCommand(hwnd, wID, pSelect));
case TVM_SELCHANGED:
// Possibly disable choosing the newly selected folder based on flags we were given
fEnable = EnabledFolder(hwnd, pSelect, (FOLDERID)lParam);
// Enable the OK Button
EnableWindow(GetDlgItem(hwnd, IDOK), fEnable);
// Get the new folder button hwnd
hwndT = GetDlgItem(hwnd, SFD_SELECTFOLDER == pSelect->op ? idcNewFolderBtn : IDOK);
if (hwndT != NULL)
{
// Get Folder Info
if (SUCCEEDED(g_pStore->GetFolderInfo((FOLDERID)lParam, &Folder)))
{
// fEnable
fEnable = Folder.idFolder != FOLDERID_ROOT &&
Folder.tyFolder != FOLDER_NEWS &&
!ISFLAGSET(Folder.dwFlags, FOLDER_NOCHILDCREATE);
// Enable/disable the window
EnableWindow(hwndT, fEnable);
// Free
g_pStore->FreeRecord(&Folder);
}
}
// Done
return(TRUE);
case TVM_DBLCLICK:
// If Not Creating a Folder:
if (pSelect->op != SFD_NEWFOLDER)
{
// If the OK button isn't enabled, I can't select this folder
if (FALSE == IsWindowEnabled(GetDlgItem(hwnd, IDOK)))
return(TRUE);
pTreeView = pSelect->pFrame->GetTreeView();
id = pTreeView->GetSelection();
hr = g_pStore->GetFolderInfo(id, &info);
if (SUCCEEDED(hr))
{
if (!FHasChildren(&info, TRUE))
SelectFolder_HandleCommand(hwnd, IDOK, pSelect);
g_pStore->FreeRecord(&info);
}
}
// Done
return(TRUE);
case WM_DESTROY:
// Close the Tree View
if (pSelect != NULL && pSelect->pFrame != NULL)
{
// Close the TreeView
pSelect->pFrame->CloseTreeView();
// Release the Frame
SideAssert(pSelect->pFrame->Release() == 0);
}
// Done
return(TRUE);
}
// Done
return(FALSE);
}
//--------------------------------------------------------------------------
// SelectFolderDlgProc
//--------------------------------------------------------------------------
INT_PTR CALLBACK NewFolderDlgProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
// Locals
HRESULT hr;
LPNEWFOLDERDIALOGINIT pNew;
WORD wID;
FOLDERID id;
HWND hwndEdit;
// Trace
TraceCall("NewFolderDlgProc");
// Get This
pNew = (LPNEWFOLDERDIALOGINIT)GetWndThisPtr(hwnd);
// Handle the Message
switch (msg)
{
case WM_INITDIALOG:
// Shouldn't Have This
Assert(pNew == NULL);
// Set pNew
pNew = (LPNEWFOLDERDIALOGINIT)lParam;
// Set this Pointer
SetWndThisPtr(hwnd, (LPNEWFOLDERDIALOGINIT)lParam);
Assert(pNew->pCallback != NULL);
pNew->pCallback->Initialize(hwnd);
// Get the Folder Name Edit
hwndEdit = GetDlgItem(hwnd, idtxtFolderName);
// Correct for intl.
SetIntlFont(hwndEdit);
// Limit the text
SendMessage(hwndEdit, EM_LIMITTEXT, CCHMAX_FOLDER_NAME - 1, 0);
// Center
CenterDialog(hwnd);
// Done
return(TRUE);
case WM_STORE_COMPLETE:
Assert(pNew->fPending);
pNew->fPending = FALSE;
hr = pNew->pCallback->GetResult();
if (hr == S_FALSE)
{
EndDialog(hwnd, IDCANCEL);
}
else if (SUCCEEDED(hr))
{
hr = GetCreatedFolderId(pNew->idParent, pNew->szName, &id);
if (SUCCEEDED(hr))
pNew->idNew = id;
else
pNew->idNew = pNew->idParent;
EndDialog(hwnd, IDOK);
}
else
{
// No need to put up error dialog, CStoreDlgCB already did this on failed OnComplete
hwndEdit = GetDlgItem(hwnd, idtxtFolderName);
SendMessage(hwndEdit, EM_SETSEL, 0, -1);
SetFocus(hwndEdit);
}
return(TRUE);
case WM_COMMAND:
// Get the Command Id
wID = LOWORD(wParam);
// Handle the Command
switch (wID)
{
case IDOK:
if (pNew->fPending)
return(TRUE);
Assert(pNew->pCallback != NULL);
pNew->pCallback->Reset();
hwndEdit = GetDlgItem(hwnd, idtxtFolderName);
GetWindowText(hwndEdit, pNew->szName, ARRAYSIZE(pNew->szName));
// Try to Create the Folder
hr = CreateNewFolder(hwnd, pNew->szName, pNew->idParent, &pNew->idNew, (IStoreCallback *)pNew->pCallback);
if (hr == E_PENDING)
{
pNew->fPending = TRUE;
break;
}
else if (FAILED(hr))
{
AthErrorMessageW(hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrCreateNewFld), hr);
SendMessage(hwndEdit, EM_SETSEL, 0, -1);
SetFocus(hwndEdit);
break;
}
// End the dialog
EndDialog(hwnd, IDOK);
// done
return(TRUE);
case IDCANCEL:
if (pNew->fPending)
pNew->pCallback->Cancel();
else
// End the dialog
EndDialog(hwnd, IDCANCEL);
// Done
return(TRUE);
}
// Done
break;
}
// Done
return(FALSE);
}
//--------------------------------------------------------------------------
// CreateNewFolder
//--------------------------------------------------------------------------
HRESULT CreateNewFolder(HWND hwnd, LPCSTR pszName, FOLDERID idParent, LPFOLDERID pidNew, IStoreCallback *pCallback)
{
// Locals
HRESULT hr;
ULONG cchFolder;
FOLDERINFO Folder;
// Trace
TraceCall("CreateNewFolder");
Assert(pCallback != NULL);
// Get Text Length
cchFolder = lstrlen(pszName);
// Invalid
if (0 == cchFolder)
return(STORE_E_BADFOLDERNAME);
// Filup the Folder Info
ZeroMemory(&Folder, sizeof(FOLDERINFO));
Folder.idParent = idParent;
Folder.tySpecial = FOLDER_NOTSPECIAL;
Folder.pszName = (LPSTR)pszName;
Folder.dwFlags = FOLDER_SUBSCRIBED;
// Create the Folder
hr = g_pStore->CreateFolder(NOFLAGS, &Folder, pCallback);
if (hr == E_PENDING)
return(hr);
// Return the Folder Id
if (pidNew)
*pidNew = Folder.idFolder;
// Done
return (hr);
}
//--------------------------------------------------------------------------
// EnabledFolder
//--------------------------------------------------------------------------
BOOL EnabledFolder(HWND hwnd, LPSELECTFOLDER pSelect, FOLDERID idFolder)
{
// Locals
BOOL fRet = FALSE;
FOLDERINFO Folder;
// Trace
TraceCall("EnabledFolder");
// Get Folder Info
if (FAILED(g_pStore->GetFolderInfo(idFolder, &Folder)))
goto exit;
// FD_DISABLEROOT
if (ISFLAGSET(pSelect->dwFlags, FD_DISABLEROOT) && FOLDERID_ROOT == idFolder)
goto exit;
// FD_DISABLEINBOX
if (ISFLAGSET(pSelect->dwFlags, FD_DISABLEINBOX) && FOLDER_INBOX == Folder.tySpecial)
goto exit;
// FD_DISABLEOUTBOX
if (ISFLAGSET(pSelect->dwFlags, FD_DISABLEOUTBOX) && FOLDER_OUTBOX == Folder.tySpecial)
goto exit;
// FD_DISABLESENTITEMS
if (ISFLAGSET(pSelect->dwFlags, FD_DISABLESENTITEMS) && FOLDER_SENT == Folder.tySpecial)
goto exit;
// FD_DISABLESERVERS
if (ISFLAGSET(pSelect->dwFlags, FD_DISABLESERVERS) && ISFLAGSET(Folder.dwFlags, FOLDER_SERVER))
goto exit;
fRet = TRUE;
exit:
// Cleanup
g_pStore->FreeRecord(&Folder);
// Default
return fRet;
}
HRESULT GetCreatedFolderId(FOLDERID idParent, LPCSTR pszName, FOLDERID *pid)
{
HRESULT hr;
HLOCK hLock;
FOLDERINFO Folder = {0};
Assert(pszName != NULL);
Assert(pid != NULL);
hr = g_pStore->Lock(&hLock);
if (FAILED(hr))
return(hr);
Folder.idParent = idParent;
Folder.pszName = (LPSTR)pszName;
if (DB_S_FOUND == g_pStore->FindRecord(IINDEX_ALL, COLUMNS_ALL, &Folder, NULL))
{
*pid = Folder.idFolder;
g_pStore->FreeRecord(&Folder);
}
else
{
hr = E_FAIL;
}
g_pStore->Unlock(&hLock);
return(hr);
}
BOOL SelectFolder_HandleCommand(HWND hwnd, WORD wID, LPSELECTFOLDER pSelect)
{
HRESULT hr;
HWND hwndT;
FOLDERID id=FOLDERID_INVALID;
NEWFOLDERDIALOGINIT NewFolder;
CTreeView *pTreeView;
switch (wID)
{
case idcNewFolderBtn:
pTreeView = pSelect->pFrame->GetTreeView();
ZeroMemory(&NewFolder, sizeof(NEWFOLDERDIALOGINIT));
NewFolder.idParent = pTreeView->GetSelection();
NewFolder.pCallback = new CStoreDlgCB;
if (NewFolder.pCallback == NULL)
// TODO: an error message might be helpful
return(TRUE);
// Launch the dialog to create a new folder
if (IDOK == DialogBoxParam(g_hLocRes, MAKEINTRESOURCE(iddNewFolder), hwnd, NewFolderDlgProc, (LPARAM)&NewFolder))
{
// Select the new folder
PostMessage(hwnd, WM_SETFOLDERSELECT, (WPARAM)NewFolder.idNew, 0);
}
NewFolder.pCallback->Release();
return(TRUE);
case IDOK:
if (pSelect->fPending)
return(TRUE);
pTreeView = pSelect->pFrame->GetTreeView();
pSelect->idSelected = pTreeView->GetSelection();
switch (pSelect->op)
{
case SFD_SELECTFOLDER:
break;
case SFD_NEWFOLDER:
Assert(pSelect->pCallback != NULL);
pSelect->pCallback->Reset();
hwndT = GetDlgItem(hwnd, idcFolderEdit);
GetWindowText(hwndT, pSelect->szName, ARRAYSIZE(pSelect->szName));
hr = CreateNewFolder(hwnd, pSelect->szName, pSelect->idSelected, &id, (IStoreCallback *)pSelect->pCallback);
if (hr == E_PENDING)
{
pSelect->fPending = TRUE;
pSelect->idParent = pSelect->idSelected;
return(TRUE);
}
else if (STORE_S_ALREADYEXISTS == hr)
{
AthMessageBoxW(hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrCreateExists), 0, MB_OK | MB_ICONEXCLAMATION);
SendMessage(hwndT, EM_SETSEL, 0, -1);
SetFocus(hwndT);
return(TRUE);
}
else if (FAILED(hr))
{
AthErrorMessageW(hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrCreateNewFld), hr);
SendMessage(hwndT, EM_SETSEL, 0, -1);
SetFocus(hwndT);
return(TRUE);
}
pSelect->idSelected = id;
break;
case SFD_MOVEFOLDER:
Assert(pSelect->pCallback != NULL);
pSelect->pCallback->Reset();
hr = g_pStore->MoveFolder(pSelect->idCurrent, pSelect->idSelected, 0, (IStoreCallback *)pSelect->pCallback);
if (hr == E_PENDING)
{
pSelect->fPending = TRUE;
return(TRUE);
}
else if (FAILED(hr))
{
AthErrorMessageW(hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrFolderMove), hr);
return(TRUE);
}
pSelect->idSelected = id;
break;
default:
Assert(FALSE);
break;
}
EndDialog(hwnd, IDOK);
return(TRUE);
case IDCANCEL:
if (pSelect->fPending)
pSelect->pCallback->Cancel();
else
EndDialog(hwnd, IDCANCEL);
return(TRUE);
default:
break;
}
return(FALSE);
}
void SelectFolder_HandleStoreComplete(HWND hwnd, LPSELECTFOLDER pSelect)
{
HRESULT hr;
FOLDERID id;
HWND hwndT;
Assert(pSelect->op != SFD_SELECTFOLDER);
Assert(pSelect->fPending);
pSelect->fPending = FALSE;
hr = pSelect->pCallback->GetResult();
if (hr == S_FALSE)
{
EndDialog(hwnd, IDCANCEL);
return;
}
switch (pSelect->op)
{
case SFD_NEWFOLDER:
if (SUCCEEDED(hr))
{
hr = GetCreatedFolderId(pSelect->idParent, pSelect->szName, &id);
if (SUCCEEDED(hr))
pSelect->idSelected = id;
else
pSelect->idSelected = pSelect->idParent;
EndDialog(hwnd, IDOK);
}
else
{
// No need to put up error dialog, CStoreDlgCB already did this on failed OnComplete
hwndT = GetDlgItem(hwnd, idcFolderEdit);
SendMessage(hwndT, EM_SETSEL, 0, -1);
SetFocus(hwndT);
}
break;
case SFD_MOVEFOLDER:
if (SUCCEEDED(hr))
{
pSelect->idSelected = pSelect->idCurrent;
EndDialog(hwnd, IDOK);
}
else if (FAILED(hr))
{
AthErrorMessageW(hwnd, MAKEINTRESOURCEW(idsAthena), MAKEINTRESOURCEW(idsErrFolderMove), hr);
}
break;
default:
Assert(FALSE);
break;
}
}