COMWINDS.CPP

/////////////////////////////////////////////////////////////////////////////// 
//
// File Name
// COMWINDS.CPP
//
// Description
// This file implement the RPC code to talk to the WINDS Sample Server
// Messaging Host.
// Here we also implement common code used by providers in the service
// that talking to WINDS and that share similiar configuration UI.
//
// Author
// Irving De la Cruz
//
// Revision: 1.7
//
// Written for Microsoft Windows Developer Support
// Copyright (c) 1995-1996 Microsoft Corporation. All rights reserved.
//
#include "COMWINDS.H"

// Remark this line to turn verbose tracing OFF
#define DO_INFO_TRACES
#ifdef DO_INFO_TRACES
#define InfoTrace(a) TraceInfoMessage(a)
#else
#define InfoTrace(a)
#endif // DO_INFO_TRACES

typedef struct tagSELECTED_MAILBOX_INFO
{
HANDLE hPipe;
HRESULT hLastError;
LPTSTR szMailBoxName;
LPTSTR szDisplayName;
LPTSTR szPassword;
DWORD * pdwMailboxID;
} SELECTED_MAILBOX_INFO;

HINSTANCE ghUIControl = NULL;
typedef BOOL (WINAPI CTL3DFUNCTION) (HINSTANCE hInstance);
typedef CTL3DFUNCTION *LPCTL3DFUNCTION;
typedef BOOL (WINAPI CTL3DSUBCLASS) (HWND hDlg, DWORD dwFlags);
typedef CTL3DSUBCLASS *LPCTL3DSUBCLASS;

LPCTL3DFUNCTION pfn3DRegister = NULL, pfn3DUnregister = NULL, pfn3DAutoSubclass = NULL;
LPCTL3DSUBCLASS pfnDlgSubclassEx = NULL;

LPFREEBUFFER pfnMAPIFreeBuffer;

extern "C"
{
void STDAPICALLTYPE BrowseMailboxes
(CUIMAPIProp * pObj,
HWND hOwnerWnd,
HINSTANCE hInstance);
void STDAPICALLTYPE ConfigChangePassword
(CUIMAPIProp * pObj,
HWND hOwnerWnd,
HINSTANCE hInstance);
HRESULT WINAPI ShowServerAccounts
(HWND hOwnerWnd,
HINSTANCE hInstance,
LPTSTR szServerName,
LPTSTR szMailboxName,
LPTSTR szFullName,
LPTSTR szPassword,
DWORD * pdwMailboxID);
BOOL CALLBACK PasswordDlgProc
(HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam);
BOOL CALLBACK EnterMBPasswordDlgProc
(HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam);
BOOL CALLBACK SelectMailBoxDlgProc
(HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam);
void WINAPI TogglePage
(HWND hDlg,
UINT iPage,
BOOL fState);
HRESULT WINAPI LogonServerMailbox
(LPTSTR szServerName,
LPTSTR szMailboxName,
LPTSTR szDisplayName,
LPTSTR szPassword,
DWORD * pdwMailboxID);
};

HRESULT WINAPI LogonServerMailboxAndSetNotif
(LPTSTR szServerName,
LPTSTR szMailboxName,
LPTSTR szDisplayName,
LPTSTR szPassword,
DWORD * pdwMailboxID,
DWORD dwNotifMask,
DWORD & dwConnectID);

// Static data for the transport provider configuration property sheets
TCHAR szFilter[] = TEXT("*"); // "*" to allow any character
TCHAR szTimeFilter[] = TEXT("[0-9:]");
TCHAR szPhoneFilter[] = TEXT("[0-9-]");
TCHAR szBlank[] = TEXT("");

extern TCHAR gszProviderName[];

// Control description structures
DTBLLABEL DtLabel = { sizeof(DTBLLABEL), fMapiUnicode};
DTBLGROUPBOX DtGroupBox = { sizeof(DTBLGROUPBOX), fMapiUnicode};
DTBLPAGE DtPage = { sizeof(DTBLPAGE), fMapiUnicode};
DTBLEDIT DtServer = { sizeof(DTBLEDIT), fMapiUnicode, MAX_STRING_SIZE, PR_SMP_REMOTE_SERVER};
DTBLEDIT DtUserName = { sizeof(DTBLEDIT), fMapiUnicode, MAX_STRING_SIZE, PR_SMP_USER_NAME};
DTBLEDIT DtMBAlias = { sizeof(DTBLEDIT), fMapiUnicode, MAX_ALIAS_SIZE, PR_SMP_MAILBOX_NAME};
DTBLBUTTON DtBrowseMB = { sizeof(DTBLBUTTON), fMapiUnicode, PR_SMP_BROWSE_MB};
DTBLBUTTON DtChangePW = { sizeof(DTBLBUTTON), fMapiUnicode, PR_SMP_CHANGE_PASSWORD};
DTBLRADIOBUTTON DtLANConnect = { sizeof(DTBLRADIOBUTTON), fMapiUnicode, 2, PR_SMP_CONNECTION_TYPE, LAN_CONNECT };
DTBLRADIOBUTTON DtREMConnect = { sizeof(DTBLRADIOBUTTON), fMapiUnicode, 2, PR_SMP_CONNECTION_TYPE, OFFLINE_CONNECT };

// Keys for field the we are going to update dynamically and we
// want MAPI's property pages to pick the changes on thes
#define ALIAS_KEY_VALUE "UI_CONTROL_ALIAS"
#define ALIAS_KEY ((LPBYTE)ALIAS_KEY_VALUE)
#define CB_ALIAS_KEY sizeof(ALIAS_KEY_VALUE)

#define NAME_KEY_VALUE "UI_CONTROL_NAME"
#define NAME_KEY ((LPBYTE)NAME_KEY_VALUE)
#define CB_NAME_KEY sizeof(NAME_KEY_VALUE)

// Description table for the controls
DTCTL UserConfigPage[] =
{
{ DTCT_PAGE, 0, NULL, 0, NULL, 0, &DtPage },
{ DTCT_EDIT, DT_REQUIRED, NULL, 0, szFilter, IDC_SERVERNAME, &DtServer },
{ DTCT_EDIT, DT_REQUIRED, ALIAS_KEY, CB_ALIAS_KEY, szFilter, IDC_MAILBOXNAME, &DtMBAlias },
{ DTCT_BUTTON, 0, NULL, 0, NULL, IDC_BROWSE_MB, &DtBrowseMB },
{ DTCT_EDIT, DT_REQUIRED, NAME_KEY, CB_NAME_KEY, szFilter, IDC_USER_NAME, &DtUserName },
{ DTCT_BUTTON, 0, NULL, 0, NULL, IDC_CHANGE_PASSWORD, &DtChangePW },
{ DTCT_RADIOBUTTON, DT_SET_IMMEDIATE,NULL, 0, NULL, IDC_CONNECT_ONLINE, &DtLANConnect },
{ DTCT_RADIOBUTTON, DT_SET_IMMEDIATE,NULL, 0, NULL, IDC_CONNECT_OFFLINE, &DtREMConnect },
{ DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC1, &DtLabel },
{ DTCT_LABEL, 0, NULL, 0, NULL, IDC_STATIC2, &DtLabel },
{ DTCT_GROUPBOX, 0, NULL, 0, NULL, IDC_STATIC3, &DtGroupBox },
{ DTCT_GROUPBOX, 0, NULL, 0, NULL, IDC_STATIC4, &DtGroupBox },
{ DTCT_GROUPBOX, 0, NULL, 0, NULL, IDC_STATIC5, &DtGroupBox }
};

// Global data used in the WizardDlgProc function
LPMAPIPROP pPropObj = NULL;
BOOL fInitalizeControls, fDownloadMBList;

extern "C"
{
HINSTANCE ghInstance = NULL;
WIZARDENTRY WizardEntry;
SERVICEWIZARDDLGPROC WizardDlgProc;
};

///////////////////////////////////////////////////////////////////////////////
// IsWINDSServerAvailable()
//
// Parameters
// szServer Pointer to a string with the name of the remote
// server to verify
//
// Purpose
// This functions makes remote procedure call to a server to make sure
// the remote machine is available.
// The remote server must be running the WINDS sample server messaging
// host because that is the server procedure that will answer the
// RPC call.
//
// Return Value
// TRUE if the server was found, FALSE otherwise.
//
BOOL WINAPI IsWINDSServerAvailable (LPTSTR szServer)
{
// We the user didn't supply a server, then fail.
if (!szServer)
{
TraceMessage ("IsWINDSServerAvailable: No server name?");
return FALSE;
}
HCURSOR hCursor = SetCursor (LoadCursor (NULL, IDC_WAIT));
// Before we make an RPC call, we must initialize the RPC runtime
// binding handle with the server
HRESULT hResult = BindToServer (szServer);
if (!hResult)
{
RpcTryExcept
{
// Call the server.
hResult = RemoteIsServerRunning();
}
RpcExcept(1)
{
// If we got here is because there was an error while call was made
// or when it was about to be made.
hResult = RpcExceptionCode();
if (RPC_S_SERVER_UNAVAILABLE == hResult)
{
hResult = HRESULT_FROM_WIN32(ERROR_HOST_UNREACHABLE);
}
else
{
hResult = MAKE_HRESULT(1, FACILITY_RPC, hResult);
}
}
RpcEndExcept
TraceResult ("IsWINDServerAvailable", hResult);
}
SetCursor (hCursor);
return (S_OK == hResult ? TRUE : FALSE);
}

///////////////////////////////////////////////////////////////////////////////
// ShowServerAccounts()
//
// Parameters
// hOwnerWnd Handle to a parent window. If NULL we don't display a
// list of available mailboxes in the server.
// hInstance Handle to the instance of the DLL where the dialog
// resource is located
// szServerName Name of the server we are going to make an RPC call to
// szMailboxName Where we return the name of the mailbox selected.
// szFullName Where we return the name of the owner of the
// mailbox seleted.
// szPassword Where we return the password of the mailbox seleted
// pdwMailboxID Where we return the ID of the mailbox seleted
//
// Purpose
// This function displays a list of available mailboxes in the server.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI ShowServerAccounts (HWND hOwnerWnd,
HINSTANCE hInstance,
LPTSTR szServerName,
LPTSTR szMailboxName,
LPTSTR szFullName,
LPTSTR szPassword,
DWORD * pdwMailboxID)
{
ASSERT (hOwnerWnd);
ASSERT (hInstance);
ASSERT (szServerName);
ASSERT (szMailboxName);
ASSERT (szFullName);
ASSERT (szPassword);
ASSERT (pdwMailboxID);
HRESULT hResult = BindToServer (szServerName);
if (hResult)
{
return hResult;
}
long lPipeNumber;
HANDLE hPipe;
TCHAR szPipeName[64];
SELECTED_MAILBOX_INFO info = { 0 };
RpcTryExcept
{
hResult = RemoteGetAllAccounts (&lPipeNumber);
if (S_OK == hResult)
{
wsprintf (szPipeName, PIPE_NAME_FORMAT, szServerName, lPipeNumber);
hPipe = CreateFile (szPipeName,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (INVALID_HANDLE_VALUE == hPipe)
{
hResult = HRESULT_FROM_WIN32(GetLastError());
TraceResult ("ShowServerAccounts: Failed to open pipe to server", hResult);
}
else
{
info.hPipe = hPipe;
info.hLastError = E_FAIL;
info.szDisplayName = szFullName;
info.szMailBoxName = szMailboxName;
info.szPassword = szPassword;
info.pdwMailboxID = pdwMailboxID;
hResult = DialogBoxParam (hInstance,
MAKEINTRESOURCE(IDD_SELECTMB),
hOwnerWnd,
SelectMailBoxDlgProc,
(LPARAM)&info);
if (-1 == hResult)
{
hResult = info.hLastError;
}
else
{
if (FALSE == hResult)
{
hResult = MAPI_E_USER_CANCEL;
}
else
{
hResult = S_OK;
}
}
CloseHandle (hPipe);
}
}
}
RpcExcept(1)
{
// If we got here is because there was an error while call was made
// or when it was about to be made.
hResult = RpcExceptionCode();
if (RPC_S_SERVER_UNAVAILABLE == hResult)
{
hResult = HRESULT_FROM_WIN32(ERROR_HOST_UNREACHABLE);
}
else
{
hResult = MAKE_HRESULT(1, FACILITY_RPC, hResult);
}
}
RpcEndExcept
TraceResult ("ShowServerAccounts", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// LogonServerMailbox()
//
// Parameters
// szServerName Name of the server where are connecting to.
// szMailboxName Name of the mailbox we are attempting to access
// szDisplayName Name of the owner of the mailbox
// szPassword Password to access the mailbox
// pdwMailboxID Where we return the ID of the mailbox as stored
// on the server
//
// Purpose
// This function makes a connection to the remote server and makes sure
// we can access it with the given password. Upon success, the remote
// call returns us the full name of the owner of the mailbox and the
// ID of the recipient.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI LogonServerMailbox (LPTSTR szServerName,
LPTSTR szMailboxName,
LPTSTR szDisplayName,
LPTSTR szPassword,
DWORD * pdwMailboxID)
{
ASSERT (szServerName);
ASSERT (szMailboxName);
ASSERT (szDisplayName);
ASSERT (szPassword);
ASSERT (pdwMailboxID);
HRESULT hResult = BindToServer (szServerName);
if (hResult)
{
return hResult;
}
RpcTryExcept
{
hResult = RemoteLogonMailBox ((WINDS_RPC_STRING)szMailboxName,
(WINDS_RPC_STRING)szPassword,
(WINDS_RPC_STRING)szDisplayName,
pdwMailboxID);
}
RpcExcept(1)
{
// If we got here is because there was an error while call was made
// or when it was about to be made.
hResult = RpcExceptionCode();
if (RPC_S_SERVER_UNAVAILABLE == hResult)
{
hResult = HRESULT_FROM_WIN32(ERROR_HOST_UNREACHABLE);
}
else
{
hResult = MAKE_HRESULT(1, FACILITY_RPC, hResult);
}
}
RpcEndExcept
TraceResult ("LogonServerMailbox", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// LogonServerMailboxAndSetNotif()
//
// Parameters
// szServerName Name of the server where are connecting to.
// szMailboxName Name of the mailbox we are attempting to access
// szDisplayName Name of the owner of the mailbox
// szPassword Password to access the mailbox
// pdwMailboxID Where we return the ID of the mailbox as stored
// on the server
// dwNotifMask Mask of events the loggin service is intersted in.
// dwConnectID Where we return the connection number the server
// assigned to us.
//
// Purpose
// In addition to what LogonServerMailbox() does, this function also
// instructs the remote server to set up a notification link with us
// to advise us of changes in the server's data or the server state.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI LogonServerMailboxAndSetNotif (LPTSTR szServerName,
LPTSTR szMailboxName,
LPTSTR szDisplayName,
LPTSTR szPassword,
DWORD * pdwMailboxID,
DWORD dwNotifMask,
DWORD & dwConnectID)
{
ASSERT (szServerName);
ASSERT (szMailboxName);
ASSERT (szDisplayName);
ASSERT (szPassword);
ASSERT (pdwMailboxID);

// Get the computer name of us (the client) so that the server can
// create the mailslot name appropiately.
TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
HRESULT hResult;
DWORD dwNameSize = MAX_COMPUTERNAME_LENGTH + 1;
if (!GetComputerName (szComputerName, &dwNameSize))
{
hResult = HRESULT_FROM_WIN32(GetLastError());
TraceResult ("LogonServerMailboxAndSetNotif: Failed to get the computer name", hResult);
}
else
{
hResult = BindToServer (szServerName);
}
if (hResult)
{
return hResult;
}
RpcTryExcept
{
hResult = RemoteLogonMailBoxAndSetNotif ((WINDS_RPC_STRING)szMailboxName,
(WINDS_RPC_STRING)szPassword,
(WINDS_RPC_STRING)szDisplayName,
pdwMailboxID,
(WINDS_RPC_STRING)szComputerName,
dwNotifMask,
&dwConnectID);
}
RpcExcept(1)
{
// If we got here is because there was an error while call was made
// or when it was about to be made.
hResult = RpcExceptionCode();
if (RPC_S_SERVER_UNAVAILABLE == hResult)
{
hResult = HRESULT_FROM_WIN32(ERROR_HOST_UNREACHABLE);
}
else
{
hResult = MAKE_HRESULT(1, FACILITY_RPC, hResult);
}
}
RpcEndExcept
TraceResult ("LogonServerMailboxAndSetNotif", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// TerminateServerNotifications()
//
// Parameters
// szServerName Name of the server we want to terminate
// connections with.
// dwConnectionID Connection ID assigned to us in that server
//
// Purpose
// Tell the server that this provider is shutting down an it show remove
// it from the list of advise clients.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI TerminateServerNotifications (LPTSTR szServerName,
DWORD dwConnectionID)
{
// If the connection is zero, there is nothing to do here.
if (0 == dwConnectionID)
{
return S_OK;
}
TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
HRESULT hResult;
DWORD dwNameSize = MAX_COMPUTERNAME_LENGTH + 1;
if (!GetComputerName (szComputerName, &dwNameSize))
{
hResult = HRESULT_FROM_WIN32(GetLastError());
TraceResult ("TerminateServerNotifications: Failed to get the computer name", hResult);
}
else
{
hResult = BindToServer (szServerName);
}
if (hResult)
{
return hResult;
}
RpcTryExcept
{
hResult = RemoteTerminateNotif ((WINDS_RPC_STRING)szComputerName, dwConnectionID);
}
RpcExcept(1)
{
// If we got here is because there was an error while call was made
// or when it was about to be made.
hResult = RpcExceptionCode();
if (RPC_S_SERVER_UNAVAILABLE == hResult)
{
hResult = HRESULT_FROM_WIN32(ERROR_HOST_UNREACHABLE);
}
else
{
hResult = MAKE_HRESULT(1, FACILITY_RPC, hResult);
}
}
RpcEndExcept
TraceResult ("TerminateServerNotifications", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// ResetServerNotifications()
//
// Parameters
// szServerName Name of the remote server
// szMailboxName Name of the owner mailbox where the notifations
// are set
// dwNotifMask Mask of events the service is interested in.
// pdwConnectionID Where the server returns the new connection number
//
// Purpose
// This function is called in response to a notification sent by the
// server to advise clients that they need to reset the notification
// because the old connection is no longer valid.
// The server send this notification periodically to make sure the advise
// client he sending notifications to are still around.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI ResetServerNotifications (LPTSTR szServerName,
LPTSTR szMailboxName,
DWORD dwNotifMask,
DWORD * pdwConnectionID)
{
// The connections with the server is dead anyways so 0 the connection ID even we fail.
*pdwConnectionID = 0;
TCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
HRESULT hResult;
DWORD dwNameSize = MAX_COMPUTERNAME_LENGTH + 1;
if (!GetComputerName (szComputerName, &dwNameSize))
{
hResult = HRESULT_FROM_WIN32(GetLastError());
TraceResult ("ResetServerNotifications: Failed to get the computer name", hResult);
}
else
{
hResult = BindToServer (szServerName);
}
if (hResult)
{
return hResult;
}
RpcTryExcept
{
hResult = RemoteValidateNotif ((WINDS_RPC_STRING)szComputerName,
(WINDS_RPC_STRING)szMailboxName,
dwNotifMask,
pdwConnectionID);
}
RpcExcept(1)
{
// If we got here is because there was an error while call was made
// or when it was about to be made.
hResult = RpcExceptionCode();
if (RPC_S_SERVER_UNAVAILABLE == hResult)
{
hResult = HRESULT_FROM_WIN32(ERROR_HOST_UNREACHABLE);
}
else
{
hResult = MAKE_HRESULT(1, FACILITY_RPC, hResult);
}
}
RpcEndExcept
TraceResult ("ResetServerNotifications", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// GetHeadersFromServer()
//
// Parameters
// szServerName Name of the server we are going to make an RPC call to
// szMailbox Mailbox for which we are going to retrieve the
// headers for.
// szHeaderFile The name of the local file where we will copy the
// message headers found in the remote mailbox
//
// Purpose
// This function makes an RPC call to the remote server host to retrieve
// the message header information of a particular mailbox. The headers
// found are save to a local file and then used to fill the contents
// table of the remote folder object we return to a client remote
// viewer application.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI GetHeadersFromServer (LPTSTR szServerName,
LPTSTR szMailbox,
LPTSTR szHeaderFile)
{
HANDLE hFile, hPipe;
DWORD dwBytesWrite, dwBytesRead;
BYTE abBuffer[IO_BUFFERSIZE];
long lPipeNumber;
HRESULT hResult = BindToServer (szServerName);
if (hResult)
{
return hResult;
}
HCURSOR hCursor = SetCursor (LoadCursor (NULL, IDC_WAIT));
RpcTryExcept
{
hResult = RemoteOpenHeaderDownloadPipe ((WINDS_RPC_STRING)szMailbox, &lPipeNumber);
if (S_OK == hResult)
{
wsprintf ((LPTSTR)abBuffer, PIPE_NAME_FORMAT,szServerName, lPipeNumber);
hPipe = CreateFile ((LPTSTR)abBuffer,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (INVALID_HANDLE_VALUE == hPipe)
{
hResult = HRESULT_FROM_WIN32(GetLastError());
TraceResult ("GetHeadersFromServer: Failed to open pipe to server", hResult);
}
else
{
hFile = CreateFile (szHeaderFile,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
hResult = HRESULT_FROM_WIN32(GetLastError());
TraceResult ("GetHeadersFromServer: Failed to open local headers file", hResult);
}
else
{
do
{
// Read the pipe handle.
if (!ReadFile (hPipe, abBuffer, IO_BUFFERSIZE, &dwBytesRead, NULL))
{
hResult = HRESULT_FROM_WIN32(GetLastError());
if (HRESULT_FROM_WIN32(ERROR_BROKEN_PIPE) != hResult && // For Windows NT
HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) != hResult) // For Windows 95
{
// There was an error and we can't continue
TraceResult ("GetHeadersFromServer: Failed to read from the pipe", hResult);
}
else
{
// If the pipe was broken, it means the server finished writing
// to the it, so we are finished reading from it.
hResult = S_OK;
}
}
if (dwBytesRead)
{
if (!WriteFile (hFile, abBuffer, dwBytesRead, &dwBytesWrite, NULL))
{
hResult = HRESULT_FROM_WIN32(GetLastError());
TraceResult ("GetHeadersFromServer: Failed to write to local header file", hResult);
}
}
} while (dwBytesRead && !hResult);
CloseHandle (hFile);
}
CloseHandle (hPipe);
}
}
}
RpcExcept(1)
{
// If we got here is because there was an error while call was made
// or when it was about to be made.
hResult = RpcExceptionCode();
if (RPC_S_SERVER_UNAVAILABLE == hResult)
{
hResult = HRESULT_FROM_WIN32(ERROR_HOST_UNREACHABLE);
}
else
{
hResult = MAKE_HRESULT(1, FACILITY_RPC, hResult);
}
}
RpcEndExcept
// Terminate connections with the remote server
BindToServer (NULL);
SetCursor (hCursor);
TraceResult ("GetHeadersFromServer", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// OpenServerUploadPipe()
//
// Parameters
// hMsgFile Handle to the local TNEF file with the message to
// upload
// szServerName String with the name of the remote server
// szRecipMailbox String with the name of the mailbox where the
// message will be uploaded.
//

//    Purpose 
// This function uploads a file to a server. The file must have been
// opened by the caller and a handle to it must have been passed in
// hMsgFile. The function will bind to the server (the name is is
// szServerName).
// This functions makes a remote procedure call to a server to request
// the a pipe to upload the data through.
// The remote server must be running the WINDS sample server messaging
// host because that is the server procedure that will answer the
// RPC call.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI OpenServerUploadPipe (LPTSTR szServerName,
LPTSTR szSenderMailbox,
HANDLE hMsgFile,
LPTSTR szConnectionInfo,
BOOL * pfErrorInTheServer)
{
*pfErrorInTheServer = FALSE;
HANDLE hPipe;
char szPipeName[64];
DWORD dwBytesWrite, dwBytesRead;
BYTE abBuffer[IO_BUFFERSIZE];
long lPipeNumber, hResult = BindToServer (szServerName);
if (hResult)
{
return hResult;
}
RpcTryExcept
{
hResult = RemoteOpenMsgUploadPipe ((WINDS_RPC_STRING)szSenderMailbox,
&lPipeNumber,
(WINDS_RPC_STRING)szConnectionInfo);
if (!hResult)
{
wsprintf (szPipeName, PIPE_NAME_FORMAT, szServerName, lPipeNumber);
hPipe = CreateFile (szPipeName,
GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (INVALID_HANDLE_VALUE == hPipe)
{
hResult = HRESULT_FROM_WIN32(GetLastError());
TraceResult ("OpenServerUploadPipe: Failed to open pipe to server", hResult);
}
else
{
do
{
if (!ReadFile (hMsgFile, abBuffer, IO_BUFFERSIZE, &dwBytesRead, NULL))
{
hResult = HRESULT_FROM_WIN32(GetLastError());
TraceResult ("OpenServerUploadPipe: Failed to read local msg file", hResult);
}
if (dwBytesRead)
{
if (!WriteFile (hPipe, abBuffer, dwBytesRead, &dwBytesWrite, NULL))
{
hResult = HRESULT_FROM_WIN32(GetLastError());
TraceResult ("OpenServerUploadPipe: Failed to write to the pipe", hResult);
}
}
} while (dwBytesRead && !hResult);
CloseHandle (hPipe);
}
}
else
{
if (hResult)
{
*pfErrorInTheServer = TRUE;
}
}
}
RpcExcept(1)
{
// If we got here is because there was an error while call was made
// or when it was about to be made.
hResult = RpcExceptionCode();
if (RPC_S_SERVER_UNAVAILABLE == hResult)
{
*pfErrorInTheServer = TRUE;
hResult = HRESULT_FROM_WIN32(ERROR_HOST_UNREACHABLE);
}
else
{
hResult = MAKE_HRESULT(1, FACILITY_RPC, hResult);
}
}
RpcEndExcept
TraceResult ("OpenServerUploadPipe", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// SendMsgToAccount()
//
// Parameters
//
// Purpose
//
// Return Value
// An HRESULT
//
HRESULT WINAPI SendMsgToAccount (LPTSTR szServerName,
LPTSTR szRecipMailbox,
LPTSTR szHeader,
LPTSTR szConnectionInfo,
BOOL * pfErrorInTheServer)
{
*pfErrorInTheServer = FALSE;
long hResult = BindToServer (szServerName);
if (hResult)
{
return hResult;
}
RpcTryExcept
{
hResult = RemoteSendMsgToAccount ((WINDS_RPC_STRING)szRecipMailbox,
(WINDS_RPC_STRING)szHeader,
(WINDS_RPC_STRING)szConnectionInfo);
if (hResult)
{
*pfErrorInTheServer = TRUE;
}
}
RpcExcept(1)
{
// If we got here is because there was an error while call was made
// or when it was about to be made.
hResult = RpcExceptionCode();
if (RPC_S_SERVER_UNAVAILABLE == hResult)
{
*pfErrorInTheServer = TRUE;
hResult = HRESULT_FROM_WIN32(ERROR_HOST_UNREACHABLE);
}
else
{
hResult = MAKE_HRESULT(1, FACILITY_RPC, hResult);
}
}
RpcEndExcept
TraceResult ("SendMsgToAccount", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// FinishUploadConnection()
//
// Parameters
//
// Purpose
//
// Return Value
// An HRESULT
//
HRESULT WINAPI FinishUploadConnection (LPTSTR szServerName,
LPTSTR szConnectionInfo)
{
long hResult = BindToServer (szServerName);
if (hResult)
{
return hResult;
}
RpcTryExcept
{
hResult = RemoteFinishUpload ((WINDS_RPC_STRING)szConnectionInfo);
}
RpcExcept(1)
{
// If we got here is because there was an error while call was made
// or when it was about to be made.
hResult = RpcExceptionCode();
if (RPC_S_SERVER_UNAVAILABLE == hResult)
{
hResult = HRESULT_FROM_WIN32(ERROR_HOST_UNREACHABLE);
}
else
{
hResult = MAKE_HRESULT(1, FACILITY_RPC, hResult);
}
}
RpcEndExcept
TraceResult ("FinishUploadConnection", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// OpenRemoteServerDownLoadPipe()
//
// Parameters
// szServer Name of the server we are downloading the message from
// szMBox Name of the mailbox we are downloading from.
// phPipe Pointer where I return the handle to the opened named
// pipe to the server machine.
//
// Purpose
// Makes an RPC to the remote server which sets up a pipe
// over which the download occurs. The RPC returns to the
// client (us) the pipe's ID that the server creates. We
// then connect to the pipe.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI OpenRemoteServerDownLoadPipe (LPTSTR szServer,
LPTSTR szMBox,
HANDLE * phPipe)
{
ASSERT (szServer);
ASSERT (szMBox);
HRESULT hResult = BindToServer (szServer);
if (hResult)
{
return hResult;
}
RpcTryExcept
{
ULONG ulPipeNum;
hResult = RemoteOpenMsgDownloadPipe ((WINDS_RPC_STRING)szMBox, &ulPipeNum);
if (!hResult)
{
TCHAR szPipeName[_MAX_PATH];
HANDLE hPipe;
// Construct the download pipe name
wsprintf (szPipeName, PIPE_NAME_FORMAT, szServer, ulPipeNum);
// Create our endpoint and connect
hPipe = CreateFile (szPipeName,
GENERIC_READ | GENERIC_WRITE,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (INVALID_HANDLE_VALUE == hPipe)
{
hResult = HRESULT_FROM_WIN32(GetLastError());
}
else
{
*phPipe = hPipe;
}
}
}
RpcExcept(1)
{
// If we got here is because there was an error while call was made
// or when it was about to be made.
hResult = RpcExceptionCode();
if (RPC_S_SERVER_UNAVAILABLE == hResult)
{
hResult = HRESULT_FROM_WIN32(ERROR_HOST_UNREACHABLE);
}
else
{
hResult = MAKE_HRESULT(1, FACILITY_RPC, hResult);
}
}
RpcEndExcept
// Terminate connections with the remote server
BindToServer (NULL);
TraceResult ("OpenRemoteServerDownLoadPipe", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// SelectMailBoxDlgProc()
//
// Parameters
// { Refer to Win32 API documentation on dialog procedures }
//
// Purpose
// Displays a dialog with all available mailboxes in the remote machine
//
// Return Value
// TRUE if message was handled, FALSE if we don't handle the message
//
BOOL CALLBACK SelectMailBoxDlgProc (HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
static SELECTED_MAILBOX_INFO * pInfo;
switch (message)
{
case WM_INITDIALOG :
{
HWND hCtl = GetDlgItem (hDlg, IDC_LIST);
int nTabStops[3];
nTabStops[0] = 75;
nTabStops[1] = 1000; // Off the screen
nTabStops[2] = 1015; // Off the screen
ListBox_SetTabStops (hCtl, sizeof(nTabStops)/sizeof(int), nTabStops);
pInfo = (SELECTED_MAILBOX_INFO *)lParam;
TCHAR szFormated[256];
AB_ENTRY_INFO abEntry = { 0 };
DWORD dwLastError = 0, dwBytesRead = 0;
do
{
// Read the pipe handle.
if (!ReadFile (pInfo->hPipe, &abEntry, sizeof(AB_ENTRY_INFO), &dwBytesRead, NULL))
{
dwLastError = HRESULT_FROM_WIN32(GetLastError());
if (HRESULT_FROM_WIN32(ERROR_BROKEN_PIPE) != dwLastError && // For Windows NT
HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) != dwLastError) // For Windows 95
{
// There was an error and we can't continue
TraceResult ("SelectMailBoxDlgProc: Failed to read from the pipe", dwLastError);
}
else
{
// If the pipe was broken, it means the server finished writing
// to the it, so we are finished reading from it.
dwLastError = 0;
}
}
else
{
wsprintf (szFormated,
TEXT("%s\t%s\t%s\t%d"),
abEntry.Info.MB.szMailboxName,
abEntry.Info.MB.szFullName,
abEntry.Info.MB.szPassword,
abEntry.Info.MB.dwObjID);
ListBox_AddString (hCtl, szFormated);
}
} while (dwBytesRead && !dwLastError);
if (!dwLastError)
{
if (pfnDlgSubclassEx)
{
pfnDlgSubclassEx (hDlg, CTL3D_ALL);
}
return TRUE;
}
pInfo->hLastError = dwLastError;
EndDialog (hDlg, -1);
}
return TRUE;

case WM_COMMAND :
switch (LOWORD(wParam))
{
case IDC_LIST :
if (LBN_DBLCLK != HIWORD(wParam))
{
break;
}
case IDOK :
{
TCHAR szBuffer[256];
LPTSTR pStr;
HWND hCtl = GetDlgItem (hDlg, IDC_LIST);
int i = ListBox_GetCurSel (hCtl);
if (i != LB_ERR)
{
ListBox_GetText (hCtl, i, szBuffer);
pStr = strtok (szBuffer, "\t");
lstrcpy (pInfo->szMailBoxName, pStr);
pStr = strtok (NULL, "\t");
lstrcpy (pInfo->szDisplayName, pStr);
pStr = strtok (NULL, "\t");
lstrcpy (pInfo->szPassword, pStr);
pStr = strtok (NULL, "\t");
*(pInfo->pdwMailboxID) = (DWORD)atol (pStr);
}
else
{
PrivateMessageBox (IDS_MSG_SELECT_MB_NAME, hDlg);
return FALSE;
}
}
case IDCANCEL :
EndDialog (hDlg, (LOWORD(wParam) == IDCANCEL ? FALSE : TRUE));
return TRUE;
}
break;
}
return FALSE;
}

///////////////////////////////////////////////////////////////////////////////
// ChangeMBServerPassword()
//
// Parameters
// szServerName Name of the server machine we are connecting to
// szMailboxName Name of the mailbox where the password will
// be changed.
// szOldPassword Old password of the mailbox
// szNewPassword New password for the mailbox
//
// Purpose
// Changes the access password in the specified mailbox in
// the specified server.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI ChangeMBServerPassword (LPTSTR szServerName,
LPTSTR szMailboxName,
LPTSTR szOldPassword,
LPTSTR szNewPassword)
{
if (BindToServer (szServerName))
{
return FALSE;
}
HRESULT hResult;
RpcTryExcept
{
hResult = RemoteChangePassword ((WINDS_RPC_STRING)szMailboxName,
(WINDS_RPC_STRING)szOldPassword,
(WINDS_RPC_STRING)szNewPassword);
}
RpcExcept(1)
{
// If we got here is because there was an error while call was made
// or when it was about to be made.
hResult = RpcExceptionCode();
if (RPC_S_SERVER_UNAVAILABLE == hResult)
{
hResult = HRESULT_FROM_WIN32(ERROR_HOST_UNREACHABLE);
}
else
{
hResult = MAKE_HRESULT(1, FACILITY_RPC, hResult);
}
}
RpcEndExcept
BindToServer (NULL);
TraceResult ("ChangeMBServerPassword", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// PrivateMessageBox()
//
// Parameters
// ids String ID of a string in the resource string table
// hOwnerWnd Window who will own the Message Box
// uFlags Flags (options) for the message box
//
// Purpose
// This function display a message box with a string loaded from the
// string table of this app. The ID of the string is passed in the ids
// parameter. The dialog box is modal with respect to the window
// identified in hOwnerWnd. The options to display the dialog box are
// passed in uFlags
//
// Return Value
// ID of the button pressed in the message box dialog box
//
int WINAPI PrivateMessageBox (UINT ids,
HWND hOwnerWnd,
UINT uFlags,
HINSTANCE hInst)
{
int nResponse = -1; // Default response
// Get the string from the string table. The size of the buffer is the
// maximum number of character allowed in the character buffer, without
// the accounting for the NULL terminator
if (NULL == hInst)
{
hInst = ghInstance;
}
ASSERT (hInst);
TCHAR szBuffer[256];
if (LoadString (hInst, ids, szBuffer, 255))
{
if (!(MB_ICONSTOP & uFlags))
{
uFlags |= MB_ICONINFORMATION;
}
// Show the message box and get the ID of the button pressed
nResponse = MessageBox (hOwnerWnd,
szBuffer,
gszProviderName,
uFlags |
MB_SETFOREGROUND |
MB_SYSTEMMODAL);
}
return nResponse;
}

///////////////////////////////////////////////////////////////////////////////
// IsValidServerName()
//
// Parameters
// szServerName Pointer to a string with the UNC name of a
// network or local server
// Purpose
// Check the string for a server name and determines if the name is a
// valid UNC name for a network server
//
// Return Value
// TRUE if the server name is valid, FALSE otherwise.
//
BOOL WINAPI IsValidServerName (LPTSTR szServerName)
{
// Server name need to be at least "\\x"
if (lstrlen(szServerName) < 3)
{
return FALSE;
}
// The first two character in the string must be "\". This is standard
// UNC (Universal Naming Convention) for server names
if (szServerName[0] != '\\' || szServerName[1] != '\\')
{
return FALSE;
}
return TRUE;
}

///////////////////////////////////////////////////////////////////////////////
// BindToServer()
//
// Parameters
// [IN] szServer Name of the remote server to which we will bind
// for RPC calls. If this pointer is NULL, we
// unbind from that server.
//
// Purpose
// This function makes the necessary calls to the RPC runtime library
// to bind to the remote server so that we can start RPC function calls.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI BindToServer (LPTSTR szServer)
{
static unsigned char * szStringBinding = NULL;
static char szLastServer[32] = { 0 };

// If a server name was given, we compare to the current server that we are
// already bounded to. If we are connected return the call.
if (szServer)
{
if (0 == lstrcmpi (szLastServer, szServer))
{
if (szStringBinding)
{
return 0;
}
}
else
{
// Save the name of the server in the static buffer
lstrcpy (szLastServer, szServer);
}
}

RPC_STATUS status = 0;
if (szStringBinding) // Unbind only if bound
{
status = RpcStringFree (&szStringBinding);
TraceRPCError ("BindToServer: RpcStringFree failed", status);
if (!status)
{
szStringBinding = NULL;
status = RpcBindingFree (&hWINDSREM); // hWINDSREM is defined in WINDS.H and WINDS.ACF
TraceRPCError ("BindToServer: RpcBindingFree failed", status);
}
}
// If this is NULL, then we don't need to bind to anything.
if (!szServer)
{
szLastServer[0] = 0;
return 0;
}
if (!status)
{
status = RpcStringBindingCompose (NULL,
(WINDS_RPC_STRING)WINDS_RPC_PROTOCOL,
(WINDS_RPC_STRING)szServer,
(WINDS_RPC_STRING)WINDS_PROVIDERS_RPC_ENDPOINT,
NULL,
&szStringBinding);
TraceRPCError ("BindToServer: RpcStringBindingCompose failed", status);
if (!status)
{
status = RpcBindingFromStringBinding (szStringBinding, &hWINDSREM); // hWINDSREM is defined in WINDS.H and WINDS.ACF
TraceRPCError ("BindToServer: RpcBindingFromStringBinding failed", status);
}
}
if (status)
{
szLastServer[0] = 0;
status = MAKE_HRESULT(1, FACILITY_RPC, status);;
}
return status;
}

///////////////////////////////////////////////////////////////////////////////
// TerminateRemoteConnections()
//
// Parameters
// None.
//
// Purpose
// Termintes the binding links in the RPC runtime library to the remote
// server after a sequence of RPC calls.
//
// Return Value
// None
//
void WINAPI TerminateRemoteConnections()
{
BindToServer (NULL);
}

///////////////////////////////////////////////////////////////////////////////
// midl_user_allcate()
//
// Parameters
// len Size (in bytes) of the memory block to allocate for the
// RPC object
//
// Purpose
// Allocates memory as needed by the RPC runtime library.
// The stubs or runtime libraries may need to allocate memory.
// By convention, they call a user-specified function named
// midl_user_allocate.
//
// Return Value
// Pointer to a block of memory of len byte in size
//
void __RPC_FAR * __RPC_API midl_user_allocate (size_t len)
{
LPVOID pVoid = HeapAlloc (GetProcessHeap(), HEAP_ZERO_MEMORY, (DWORD)len);
if (NULL == pVoid)
{
TraceMessage ("midl_user_allocate: Failed to allocated RPC memory block");
}
return pVoid;
}

///////////////////////////////////////////////////////////////////////////////
// midl_user_free()
//
// Parameters
// ptr Pointer to memory block to release
//
// Purpose
// Free memory as needed by the RPC runtime library.
// The stubs or runtime libraries may need to free memory.
// By convention, they call a user-specified function named
// midl_user_free.
//
// Return Value
// None
//
void __RPC_API midl_user_free (void __RPC_FAR * ptr)
{
HeapFree (GetProcessHeap(), 0, ptr);
}

///////////////////////////////////////////////////////////////////////////////
// CUIMAPIProp::CUIMAPIProp()
//
// Parameters
// hInstance Instance of the DLL where this provider is
// pfnAllocateBuffer MAPI allocation function
// pfnAllocateMore MAPI allocation function
// pfnFreeBuffer MAPI allocation function
// fReadOnly Weather or not the UI is in read-only mode
//
// Purpose
// Constructor of the class.
//
// Return Value
// None.
//
CUIMAPIProp::CUIMAPIProp (HINSTANCE hInstance,
LPALLOCATEBUFFER pfnAllocateBuffer,
LPALLOCATEMORE pfnAllocateMore,
LPFREEBUFFER pfnFreeBuffer,
BOOL fReadOnly)
{
// Save in global pointer
pfnMAPIFreeBuffer = pfnFreeBuffer;

// Use MAPI's IMAPIProp in-memory implementation to do the actual
// work of store the properties. If we fail to create this, we throw
// and exception, to new creator of this object must have the
// construction of this object protected within a try-catch block.
HRESULT hResult = CreateIProp ((LPIID)&IID_IMAPIPropData,
pfnAllocateBuffer,
pfnAllocateMore,
pfnFreeBuffer,
NULL,
&m_pImpObj);
if (hResult)
{
TraceResult ("CUIMAPIProp: CreateIProp failed to create IPropData object", hResult);
throw CException (hResult);
}
m_hInstance = hInstance;
m_fReadOnly = fReadOnly;
m_cRef = 1;
m_ulCustomPropTag = 0;
m_pfnCallBack = NULL;
m_pTableData = NULL;
InitializeCriticalSection (&m_csObj);
}

///////////////////////////////////////////////////////////////////////////////
// CUIMAPIProp::OpenProperty()
//
// Parameters
// { Refer to the MAPI documentation for parameter description }
//
// Purpose
// Open the property for the BUTTON control on the display table. We
// only allow the IID_IMAPIControl interface specified in this method.
// If we have the property specified, create a new IMAPIControl
// interface and return it to the caller.
//
// Return Value
// An HRESULT
//
STDMETHODIMP CUIMAPIProp::OpenProperty (ULONG ulPropTag,
LPCIID piid,
ULONG ulInterfaceOptions,
ULONG ulFlags,
LPUNKNOWN * ppUnk)
{
Validate_IMAPIProp_OpenProperty (this,
ulPropTag,
piid,
ulInterfaceOptions,
ulFlags,
ppUnk);
if (IID_IMAPIControl != *piid)
{
return E_NOINTERFACE;
}
LPBUTTONCALLBACK pfnCallBack = NULL;
switch (ulPropTag)
{
case PR_SMP_BROWSE_MB :
pfnCallBack = BrowseMailboxes;
break;
case PR_SMP_CHANGE_PASSWORD :
pfnCallBack = ConfigChangePassword;
break;
default :
// We allow client of CUIMAPIProp to set one custom property
// that is not know internally and a custom callback.
if (m_ulCustomPropTag == ulPropTag)
{
pfnCallBack = m_pfnCallBack;
}
}
if (NULL == pfnCallBack)
{
return MAPI_E_NOT_FOUND;
}
CMAPIControl * pControl = new CMAPIControl (this, pfnCallBack, m_fReadOnly);
if (!pControl)
{
return E_OUTOFMEMORY;
}
*ppUnk = (LPUNKNOWN)pControl;
return S_OK;
}

///////////////////////////////////////////////////////////////////////////////
// EnterMBPasswordDlgProc()
//
// Parameters
// { Refer to Win32 API documentation on dialog procedures }
//
// Purpose
// Display a dialog where the user enters the password for a mailbox
// on the server.
//
// Return Value
// TRUE if message was handled, FALSE if we don't handle the message
//
BOOL CALLBACK EnterMBPasswordDlgProc (HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
static LPTSTR szStoredPassword;
static LPTSTR szReturningBuffer;
switch (message)
{
case WM_INITDIALOG :
{
// On this message only, the lParam is an argument passed by the
// caller who instantiated this dialog.
LPSPropValue pProps = (LPSPropValue)lParam;
SetWindowText (GetDlgItem (hDlg, IDC_MAILBOXNAME), pProps[0].Value.LPSZ);
SetWindowText (GetDlgItem (hDlg, IDC_USER_NAME), pProps[1].Value.LPSZ);
szStoredPassword = pProps[2].Value.LPSZ;
szReturningBuffer = pProps[3].Value.LPSZ;
Edit_LimitText (GetDlgItem (hDlg, IDC_PASSWORD), MAX_PASSWORD_SIZE);
// If this value is false, we should disable the BROWSE button to prevent
// users from changing the mailbox.
if (FALSE == pProps[4].Value.b)
{
EnableWindow (GetDlgItem (hDlg, IDC_BROWSE_MB), FALSE);
}
if (pfnDlgSubclassEx)
{
pfnDlgSubclassEx (hDlg, CTL3D_ALL);
}
}
return TRUE;
case WM_COMMAND :
switch (LOWORD(wParam))
{
case IDC_BROWSE_MB :
EndDialog (hDlg, IDC_BROWSE_MB);
break;
case IDOK :
// Get the password and do a CASE-SENSITIVE comparison of the stored and entered psswords.
GetWindowText (GetDlgItem (hDlg, IDC_PASSWORD), szReturningBuffer, MAX_PASSWORD_SIZE);

if (szStoredPassword && (0 != lstrcmp (szReturningBuffer, szStoredPassword))) 
{
MessageBeep (MB_ICONEXCLAMATION);
PrivateMessageBox (IDS_MSG_INVALID_MB_PASSWORD, hDlg);
SetFocus (GetDlgItem (hDlg, IDC_PASSWORD));
return TRUE;
}
// else fall through
case IDCANCEL :
EndDialog (hDlg, (LOWORD(wParam) == IDCANCEL ? FALSE : TRUE));
return TRUE;
}
}
return FALSE;
}

///////////////////////////////////////////////////////////////////////////////
// PasswordDlgProc()
//
// Parameters
// { Refer to Win32 API documentation on dialog procedures }
//
// Purpose
// Display a dialog where the user enters a new password for the mailbox.
//
// Return Value
// TRUE if message was handled, FALSE if we don't handle the message
//
BOOL CALLBACK PasswordDlgProc (HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
static LPTSTR * pszPasswords;
switch (message)
{
case WM_INITDIALOG :
// On this message only, the lParam is an argument passed by the
// caller who instantiated this dialog.
pszPasswords = (LPTSTR *)lParam;
// Limit the fields the user can type in.
Edit_LimitText (GetDlgItem (hDlg, IDC_PASSWORD), MAX_PASSWORD_SIZE);
Edit_LimitText (GetDlgItem (hDlg, IDC_PASSWORD_CONFIRM), MAX_PASSWORD_SIZE);
Edit_LimitText (GetDlgItem (hDlg, IDC_OLD_PASSWORD), MAX_PASSWORD_SIZE);
if (pfnDlgSubclassEx)
{
pfnDlgSubclassEx (hDlg, CTL3D_ALL);
}
return TRUE;
case WM_COMMAND :
switch (LOWORD(wParam))
{
case IDOK :
{
// Get and verify the OLD password
TCHAR szConfirm[MAX_PASSWORD_SIZE+1], szOldPassword[MAX_PASSWORD_SIZE+1];
if (!GetWindowText (GetDlgItem (hDlg, IDC_OLD_PASSWORD), szOldPassword, MAX_PASSWORD_SIZE+1))
{
MessageBeep (MB_ICONEXCLAMATION);
PrivateMessageBox (IDS_MSG_NEED_OLD_PASSWORD, hDlg);
SetFocus (GetDlgItem (hDlg, IDC_OLD_PASSWORD));
return TRUE;
}
if (lstrcmp (szOldPassword, pszPasswords[1]))
{
MessageBeep (MB_ICONEXCLAMATION);
PrivateMessageBox (IDS_MSG_OLD_PASSWORD_NO_MATCH, hDlg);
SetWindowText (GetDlgItem (hDlg, IDC_OLD_PASSWORD), szBlank);
SetFocus (GetDlgItem (hDlg, IDC_OLD_PASSWORD));
return TRUE;
}
// Get the NEW password
if (!GetWindowText (GetDlgItem (hDlg, IDC_PASSWORD), pszPasswords[0], MAX_PASSWORD_SIZE+1))
{
MessageBeep (MB_ICONEXCLAMATION);
PrivateMessageBox (IDS_MSG_NEED_PASSWORD, hDlg);
SetFocus (GetDlgItem (hDlg, IDC_PASSWORD));
return TRUE;
}
// Get the NEW password (CONFIRM)
if (!GetWindowText (GetDlgItem (hDlg, IDC_PASSWORD_CONFIRM), szConfirm, MAX_PASSWORD_SIZE+1))
{
MessageBeep (MB_ICONEXCLAMATION);
PrivateMessageBox (IDS_MSG_NEED_PASSWORD_CONFIRM, hDlg);
SetFocus (GetDlgItem (hDlg, IDC_PASSWORD_CONFIRM));
return TRUE;
}
// Compare (case-sensitive) the instances of the new password typed in
if (lstrcmp (szConfirm, pszPasswords[0]))
{
MessageBeep (MB_ICONEXCLAMATION);
PrivateMessageBox (IDS_MSG_NEW_PASSWORD_NO_MATCH, hDlg);
SetWindowText (GetDlgItem (hDlg, IDC_PASSWORD), szBlank);
SetWindowText (GetDlgItem (hDlg, IDC_PASSWORD_CONFIRM), szBlank);
SetFocus (GetDlgItem (hDlg, IDC_PASSWORD));
return TRUE;
}
}
case IDCANCEL :
EndDialog (hDlg, (IDOK == LOWORD(wParam) ? TRUE : FALSE));
return TRUE;
}
}
return FALSE;
}

///////////////////////////////////////////////////////////////////////////////
// BrowseMailboxes()
//
// Parameters
// pObj Pointer to our IMAPIProp implementation (CUIMAPIProp)
// passed in to the DoConfidPropSheet() function
// hOwnerWnd The owner of any window we display
// hInstance The instance of this DLL
//
// Purpose
// This function get called by our implementation of
// IMAPIControl::Active() by a user hitting a "Browse"
// on the provider configuration property sheet.
// Display a dialog box with all the mailboxes in the remote system
//
// Return Value
// None
//
void STDAPICALLTYPE BrowseMailboxes (CUIMAPIProp * pObj,
HWND hOwnerWnd,
HINSTANCE hInstance)
{
TCHAR szDisplayName[MAX_STRING_SIZE+1], szMailboxName[MAX_ALIAS_SIZE+1];
TCHAR szStoredPassword[MAX_PASSWORD_SIZE+1], szEnterPassword[MAX_PASSWORD_SIZE+1];
LPSPropValue pProp = NULL;
DWORD dwMailboxID;
SPropTagArray sptServer;
sptServer.cValues = 1;
sptServer.aulPropTag[0] = PR_SMP_REMOTE_SERVER;
ULONG cValues;
// Get the server name the user may have typed in the edit field
HRESULT hResult = pObj->GetProps (&sptServer, fMapiUnicode, &cValues, &pProp);
if (FAILED(hResult) || MAPI_W_ERRORS_RETURNED == hResult)
{
pfnMAPIFreeBuffer (pProp);
PrivateMessageBox (IDS_MSG_NEED_SERVER_NAME, hOwnerWnd);
return;
}
ASSERT (pProp->ulPropTag == PR_SMP_REMOTE_SERVER);
TCHAR szServer[MAX_STRING_SIZE+1];
lstrcpy (szServer, pProp->Value.LPSZ);
pfnMAPIFreeBuffer (pProp);
// Validate the server
if (!IsValidServerName (szServer))
{
MessageBeep (MB_ICONEXCLAMATION);
PrivateMessageBox (IDS_MSG_INVALID_SERVER_NAME, hOwnerWnd);
return;
}
if (!IsWINDSServerAvailable (szServer))
{
PrivateMessageBox (IDS_MSG_SERVER_NOT_FOUND, hOwnerWnd);
return;
}
// Show the list of mailboxes in the server. If the user hit OK, process the selected entry.
Restart:
if (S_OK == ShowServerAccounts (hOwnerWnd,
hInstance,
szServer,
szMailboxName,
szDisplayName,
szStoredPassword,
&dwMailboxID))
{
// Set the selected mailbox properties in the property object
SPropValue spvProps[5] = { 0 };
spvProps[0].ulPropTag = PR_SMP_MAILBOX_NAME;
spvProps[0].Value.LPSZ = szMailboxName;
spvProps[1].ulPropTag = PR_SMP_USER_NAME;
spvProps[1].Value.LPSZ = szDisplayName;
spvProps[2].ulPropTag = PR_SMP_MAILBOX_PASSWORD;
spvProps[2].Value.LPSZ = szStoredPassword;
spvProps[3].ulPropTag = PR_SMP_MAILBOX_PASSWORD;
spvProps[3].Value.LPSZ = szEnterPassword;
spvProps[4].Value.b = TRUE; // Activate the "BROWSE" button on the dialog below
// Before continuing, the user must verify it's access to the mailbox by typing the correct password
int nAnswer = DialogBoxParam (hInstance,
MAKEINTRESOURCE(IDD_ENTER_PASSWORD),
hOwnerWnd,
EnterMBPasswordDlgProc,
(LPARAM)spvProps);
if (IDC_BROWSE_MB == nAnswer)
{
goto Restart;
}
if (TRUE == nAnswer)
{
// Access is verified, continue
spvProps[3].ulPropTag = PR_SMP_MAILBOX_ID;
spvProps[3].Value.l = dwMailboxID;
pObj->SetProps (4, spvProps, NULL);
// Now we must tell the property sheet handler to re-read the data for
// this field from the IMAPIProp object any of the DTCTL members with a key, for a notification on them.
for (ULONG iRow=0; ; iRow++)
{
LPSRow pRow;
LPSPropValue pControlID;
hResult = pObj->m_pTableData->HrEnumRow (iRow, &pRow);
if (hResult || !pRow)
{
TraceResult ("BrowseMailboxes: Traversing the display table", hResult);
return;
}
pControlID = PpropFindProp (pRow->lpProps, pRow->cValues, PR_CONTROL_ID);
if (pControlID->Value.bin.cb)
{
pObj->m_pTableData->HrNotify (0, 1, pControlID);
}
pfnMAPIFreeBuffer (pRow);
}
}
}
}

///////////////////////////////////////////////////////////////////////////////
// ConfigChangePassword()
//
// Parameters
// pObj Pointer to our IMAPIProp implementation (CUIMAPIProp)
// passed in to the DoConfidPropSheet() function
// hOwnerWnd The owner of any window we display
// hInstance The instance of this DLL
//
// Purpose
// This function get called by our implementation of
// IMAPIControl::Active() by a user hitting a "Change Mailbox Password"
// on the provider configuration property sheet.
// Display a dialog box where the user can change the password of the
// mailbox.
//
// Return Value
// None
//
void STDAPICALLTYPE ConfigChangePassword (CUIMAPIProp * pObj, HWND hOwnerWnd, HINSTANCE hInstance)
{
const static SizedSPropTagArray(3, sptServerAndPass) =
{
3,
{
PR_SMP_REMOTE_SERVER,
PR_SMP_MAILBOX_NAME,
PR_SMP_MAILBOX_PASSWORD
}
};
TCHAR szOldPassword[MAX_PASSWORD_SIZE+1], szNewPassword[MAX_PASSWORD_SIZE+1];
TCHAR szServer[MAX_STRING_SIZE+1], szMBName[MAX_STRING_SIZE+1];
LPTSTR aszPasswords[2] = { 0 };
ULONG cValues;
LPSPropValue pProp = NULL;
SPropValue spvNewPassword = { 0 };
// Get the server and mailbox information for the property object
HRESULT hResult = pObj->GetProps ((LPSPropTagArray)&sptServerAndPass, fMapiUnicode, &cValues, &pProp);
if (FAILED(hResult) || MAPI_W_ERRORS_RETURNED == hResult)
{
pfnMAPIFreeBuffer (pProp);
PrivateMessageBox (IDS_MSG_NEED_SERVER_NAME, hOwnerWnd);
return;
}
ASSERTMSG (pProp[0].ulPropTag == PR_SMP_REMOTE_SERVER, "Where is PR_SMP_REMOTE_SERVER?!?!");
ASSERTMSG (pProp[1].ulPropTag == PR_SMP_MAILBOX_NAME, "Where is PR_SMP_MAILBOX_NAME?!?!");
ASSERTMSG (pProp[2].ulPropTag == PR_SMP_MAILBOX_PASSWORD, "Where is PR_SMP_MAILBOX_PASSWORD?!?!");
lstrcpy (szServer, pProp[0].Value.LPSZ);
lstrcpy (szMBName, pProp[1].Value.LPSZ);
lstrcpy (szOldPassword, pProp[2].Value.LPSZ);
pfnMAPIFreeBuffer (pProp);
// Validate the server name and availability
if (!IsValidServerName (szServer))
{
MessageBeep (MB_ICONEXCLAMATION);
PrivateMessageBox (IDS_MSG_INVALID_SERVER_NAME, hOwnerWnd);
return;
}
if (!IsWINDSServerAvailable (szServer))
{
PrivateMessageBox (IDS_MSG_SERVER_NOT_FOUND, hOwnerWnd);
return;
}
aszPasswords[0] = szNewPassword;
aszPasswords[1] = szOldPassword;

// Show the dialog where the user can change the information
if (TRUE == DialogBoxParam (hInstance,
MAKEINTRESOURCE(IDD_NEW_PASSWORD),
hOwnerWnd,
PasswordDlgProc,
(LPARAM)&aszPasswords))
{
// If the user is ok call the server
if (S_OK == ChangeMBServerPassword (szServer, szMBName, szOldPassword, szNewPassword))
{
// If the change was successfull, save the new password in the property object.
spvNewPassword.ulPropTag = PR_SMP_MAILBOX_PASSWORD;
spvNewPassword.Value.LPSZ = szNewPassword;
pObj->SetProps (1, &spvNewPassword, NULL);
}
}
}

///////////////////////////////////////////////////////////////////////////////
// PingRemoteServer()
//
// Parameters
// hOwnerWnd Handle to a windows that owns any UI done by
// this provider
// pProps An array of SPropValue structures with the logon
// properties of the service. The first 5 properties
// must be the standard properties for a WINDS service
// and they must be in the standard order (see COMWINDS.H)
//
// Purpose
// Make a quick connection to the server verifying a mailbox access
// with the current password and name.
//
// Return Value
// TRUE if the connection was successful, or the user does not care that
// the server is offline.
// FALSE if the user wants to change the configuration properties again.
//
BOOL WINAPI PingRemoteServer (HWND hOwnerWnd, LPSPropValue pProps)
{
BOOL fPingedOK = TRUE;
DWORD dwMsgIDS = 0, dwMailboxID;
TCHAR szServerUserFullName[MAX_STRING_SIZE+1];
HRESULT hLogonError;
CharUpper (pProps[SERVER_NAME].Value.LPSZ);
// Try to connect to the server and see if it is around
if (IsWINDSServerAvailable (pProps[SERVER_NAME].Value.LPSZ))
{
hLogonError = LogonServerMailbox (pProps[SERVER_NAME].Value.LPSZ,
pProps[MAILBOX_NAME].Value.LPSZ,
szServerUserFullName,
pProps[PASSWORD].Value.LPSZ,
&dwMailboxID);
if (hLogonError)
{
switch (hLogonError)
{
case HRESULT_FROM_WIN32 (ERROR_NO_SUCH_USER) :
dwMsgIDS = IDS_MSG_CONFIG_INVALID_USER;
break;
case HRESULT_FROM_WIN32 (ERROR_BAD_USERNAME) :
dwMsgIDS = IDS_MSG_CONFIG_INVALID_USER_NAME;
break;
case HRESULT_FROM_WIN32 (ERROR_INVALID_PASSWORD) :
dwMsgIDS = IDS_MSG_INVALID_MB_PASSWORD;
break;
default :
dwMsgIDS = IDS_MSG_CONFIG_NO_CONNECT;
break;
}
PrivateMessageBox (dwMsgIDS, hOwnerWnd);
fPingedOK = FALSE;
}
}
else
{
if (IDNO == PrivateMessageBox (IDS_MSG_NO_SERVER_GO_OFFLINE, hOwnerWnd, MB_YESNO | MB_ICONSTOP))
{
// The user wants to re-enter the name of the remote server
fPingedOK = FALSE;
}
}
return fPingedOK;
}

///////////////////////////////////////////////////////////////////////////////
// DoServerLogon()
//
// Parameters
// pMBInfo Pointer to the mailbox info structure where this
// function returns the mailbox information of the
// user logging in.
// pProps An array of SPropValue structures with the logon
// properties of the service. The first 5 properties
// must be the standard properties for a WINDS
// service and they must be in the standard order
// (see COMWINDS.H)
// pProfileObj Profile object to which this function write
// changes, if any are required based on the latest
// information comming down from the server or
// entered by the user in the configuration dialog.
// fUIAllowed Weather or not the function is allowed to display
// any UI of information or request input from
// the user.
// hOwnerWnd Handle to the window that owns any UI displayed.
// fSetNotification Weather or not to set notifications with the
// remote server
// dwNotifMask Mask of events this provider is intersted in
// receiving.
// pdwConnectID Where I return the connection ID returned by
// the server
// fOffLineOK Flag that indicates that the caller does not
// want to be bother with a "server offline"
// notification/UI and that we should return success
// even if the server could not be reached.
//
// Purpose
// This function does a complete logon to the server with the
// information passed in the pProps arguments. The function makes a
// remote call to the server to request access to a mailbox. If
// access is not granted we display messages and if needed, display the
// appropiate dialog boxes for reconfiguration or change of password.
// If the server was off-line, but the user does not mind, we return
// MAPI_W_NO_SERVICE.
// If the server is off-line, but no UI is allowed we return
// MAPI_E_NETWORK_ERROR.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI DoServerLogon (PMAILBOX_INFO pMBInfo,
LPSPropValue pProps,
LPPROFSECT pProfileObj,
BOOL fUIAllowed,
HWND hOwnerWnd,
BOOL fSetNotification,
DWORD dwNotifMask,
DWORD * pdwConnectID,
BOOL fOffLineOK)
{
ASSERT (PR_SMP_REMOTE_SERVER == pProps[SERVER_NAME].ulPropTag);
ASSERT (PR_SMP_MAILBOX_NAME == pProps[MAILBOX_NAME].ulPropTag);
ASSERT (PR_SMP_MAILBOX_ID == pProps[MAILBOX_ID].ulPropTag);
ASSERT (PR_SMP_USER_NAME == pProps[USER_NAME].ulPropTag);
ASSERT (PR_SMP_MAILBOX_PASSWORD == pProps[PASSWORD].ulPropTag);

pMBInfo->dwObjID = pProps[MAILBOX_ID].Value.l;
lstrcpy (pMBInfo->szMailboxName, pProps[MAILBOX_NAME].Value.LPSZ);
lstrcpy (pMBInfo->szFullName, pProps[USER_NAME].Value.LPSZ);
lstrcpy (pMBInfo->szPassword, pProps[PASSWORD].Value.LPSZ);

SPropValue spvProps[5] = { 0 };
DWORD dwMsgIDS = 0, dwStyle = MB_YESNO | MB_ICONSTOP, dwMailboxID;
HRESULT hLogonError;
long nResponse;

// Try to connect to the server and see if it is around
if (IsWINDSServerAvailable (pProps[SERVER_NAME].Value.LPSZ))
{
RestartMailboxLogon:
if (fSetNotification)
{
hLogonError = LogonServerMailboxAndSetNotif (pProps[SERVER_NAME].Value.LPSZ,
pMBInfo->szMailboxName,
pMBInfo->szFullName,
pMBInfo->szPassword,
&dwMailboxID,
dwNotifMask,
*pdwConnectID);
}
else
{
hLogonError = LogonServerMailbox (pProps[SERVER_NAME].Value.LPSZ,
pMBInfo->szMailboxName,
pMBInfo->szFullName,
pMBInfo->szPassword,
&dwMailboxID);
}
if (hLogonError)
{
if (fUIAllowed)
{
switch (hLogonError)
{
case HRESULT_FROM_WIN32 (ERROR_NO_SUCH_USER) :
dwMsgIDS = IDS_MSG_LOGON_INVALID_USER;
break;
case HRESULT_FROM_WIN32 (ERROR_BAD_USERNAME) :
dwMsgIDS = IDS_MSG_LOGON_INVALID_USER_NAME;
break;
case HRESULT_FROM_WIN32 (ERROR_INVALID_PASSWORD) :
dwMsgIDS = IDS_MSG_INVALID_MB_PASSWORD;
dwStyle = MB_OK | MB_ICONSTOP;
break;
default :
dwMsgIDS = IDS_MSG_LOGON_NO_CONNECT;
break;
}
if (dwMsgIDS)
{
PrivInitialize3DCtl (ghInstance);
nResponse = PrivateMessageBox (dwMsgIDS, hOwnerWnd, dwStyle);
if (IDYES == nResponse && hLogonError != HRESULT_FROM_WIN32 (ERROR_INVALID_PASSWORD))
{
return S_FALSE;
}
if (hLogonError == HRESULT_FROM_WIN32 (ERROR_INVALID_PASSWORD))
{
spvProps[0].ulPropTag = PR_SMP_MAILBOX_NAME;
spvProps[0].Value.LPSZ = pMBInfo->szMailboxName;
spvProps[1].ulPropTag = PR_SMP_USER_NAME;
spvProps[1].Value.LPSZ = pMBInfo->szFullName;
spvProps[2].ulPropTag = PR_SMP_MAILBOX_PASSWORD;
spvProps[2].Value.LPSZ = NULL;
spvProps[3].ulPropTag = PR_SMP_MAILBOX_PASSWORD;
spvProps[3].Value.LPSZ = pMBInfo->szPassword;
spvProps[4].Value.b = FALSE; // De-activate the "BROWSE" button on the dialog below
ASSERT (NULL != ghInstance);
nResponse = DialogBoxParam (ghInstance,
MAKEINTRESOURCE(IDD_ENTER_PASSWORD),
hOwnerWnd,
EnterMBPasswordDlgProc,
(LPARAM)spvProps);
if (FALSE == nResponse)
{
return MAPI_E_EXTENDED_ERROR;
}
else
{
goto RestartMailboxLogon;
}
}
}
}
else
{
return hLogonError;
}
}
else
{
ULONG ulProps = 0;
// If any of this properties that came from the server is different to
// what we have stored on the profile, then set them back for the next session.
if (lstrcmp (pProps[USER_NAME].Value.LPSZ, pMBInfo->szFullName))
{
spvProps[ulProps].ulPropTag = PR_SMP_USER_NAME;
spvProps[ulProps++].Value.LPSZ = pMBInfo->szFullName;
}
if (lstrcmp (pProps[PASSWORD].Value.LPSZ, pMBInfo->szPassword))
{
spvProps[ulProps].ulPropTag = PR_SMP_MAILBOX_PASSWORD;
spvProps[ulProps++].Value.LPSZ = pMBInfo->szPassword;
}
if (dwMailboxID != pProps[MAILBOX_ID].Value.ul)
{
spvProps[ulProps].ulPropTag = PR_SMP_MAILBOX_ID;
spvProps[ulProps++].Value.l = dwMailboxID;
}
if (ulProps)
{
HRESULT hResult = pProfileObj->SetProps (ulProps, spvProps, NULL);
TraceResult ("DoServerLogon: Could not set last-minute props", hResult);
}
}
}
else
{
// If the caller says that is OK to be offline, then return.
if (fOffLineOK)
{
return S_OK;
}
if (fUIAllowed)
{
PrivInitialize3DCtl (ghInstance);
if (IDYES == PrivateMessageBox (IDS_MSG_NO_SERVER_ONLINE, hOwnerWnd, MB_YESNO))
{
// The user wants to re-enter the name of the remote server
return MAPI_W_NO_SERVICE;
}
}
else
{
return MAPI_E_NETWORK_ERROR;
}
}
return S_OK;
}

///////////////////////////////////////////////////////////////////////////////
// WizardEntry()
//
// Parameters
// { Refer to MAPI Documentation on this method }
//
// Purpose
// Returns the name of the resource where the controls for the wizard
// pages are defined and outlined. The Wizard gives us a pointer to an
// IMAPIProp object. We will release this object after we are finished
// in the dialog procedure of our configuration pages.
//
// Return Value
// S_OK always.
//
ULONG STDAPICALLTYPE WizardEntry (HINSTANCE hProviderDLLInstance,
LPTSTR * ppcsResourceName,
DLGPROC * ppDlgProc,
LPMAPIPROP pMapiProp,
LPVOID pSupObj)
{
InfoTrace ("WizardEntry function called");
// Quick sanity check on the input parameters
ASSERT (ppcsResourceName);
ASSERT (pMapiProp);
ASSERT (ppDlgProc);
ASSERT (hProviderDLLInstance);
// The resource name needs to be an actual text string not
// something generated with the MAKEINTRESOURCE() macro
const static TCHAR szTemplate[] = TEXT("WIZARD_PAGES");
*ppcsResourceName = (LPTSTR)szTemplate;
*ppDlgProc = (DLGPROC)WizardDlgProc;
pPropObj = pMapiProp;
pPropObj->AddRef();
ghInstance = hProviderDLLInstance;

fInitalizeControls = fDownloadMBList = TRUE;
return S_OK;
}

///////////////////////////////////////////////////////////////////////////////
// WizardDlgProc()
//
// Parameters
// { Refer to MAPI and Win32 SDK Documentation on this method }
//
// Purpose
// This is the function that the profile wizard will call while
// interacting with our configuration pages.
//
// Return Value
// TRUE if we handle a message, FALSE if we don't or there was an error
// in the data
//
BOOL STDAPICALLTYPE WizardDlgProc (HWND hDlg,
UINT message,
WPARAM wParam,
LPARAM lParam)
{
static SPropValue spvWizardProps[WIZARD_PROPERTIES] = { 0 };
static TCHAR szDisplayName[MAX_STRING_SIZE+1];
static TCHAR szServerName[MAX_STRING_SIZE+1];
static TCHAR szMailboxName[MAX_ALIAS_SIZE+1];
static TCHAR szStoredPassword[MAX_PASSWORD_SIZE+1];
static TCHAR szEnterPassword[MAX_PASSWORD_SIZE+1];
static DWORD dwMailboxID;
static UINT iPageNum;
switch (message)
{
case WM_INITDIALOG:
// If the control have not been initialized do so
if (fInitalizeControls)
{
// Send output to a console window BUT NOT to the COM1
InitTraces (TRACES_CONSOLE | TRACES_NO_COM_OUTPUT);
dwMailboxID = 0;
// Set the flag to avoid re-initialization
fInitalizeControls = FALSE;
// Limit the maximum number of character users can enter for the mailbox PASSWORD
Edit_LimitText (GetDlgItem (hDlg, IDC_PASSWORD), MAX_PASSWORD_SIZE);
PrivInitialize3DCtl (ghInstance);
iPageNum = 0;
}
return TRUE;

case WIZ_QUERYNUMPAGES :
// Return the number of pages the our provider needs to display
return (BOOL)2;

case WM_CLOSE :
pPropObj->Release();
pPropObj = NULL;
PrivUninitialize3DCtl (ghInstance);
// Close down the log file/com port/console window/etc.
UnInitTraces();
return TRUE;

case WM_COMMAND :
switch (LOWORD(wParam))
{
case IDC_BROWSE_MB :
if (S_OK == ShowServerAccounts (hDlg,
ghInstance,
szServerName,
szMailboxName,

szDisplayName, 
szStoredPassword,
&dwMailboxID))
{
SetWindowText (GetDlgItem (hDlg, IDC_MAILBOXNAME), szMailboxName);
SetWindowText (GetDlgItem (hDlg, IDC_USER_NAME), szDisplayName);
}
return TRUE;

case WIZ_NEXT:
switch (iPageNum)
{
// We are about to leave a page in each of the
// following cases. Here we should get the data from
// the controls in that page, validate it if necessary
// and copy the validated data into the property array
case 0:
break;

case 1:
if (!GetWindowText (GetDlgItem (hDlg, IDC_SERVERNAME),
szServerName,
sizeof(szServerName)))
{
MessageBeep (MB_ICONEXCLAMATION);
PrivateMessageBox (IDS_MSG_NEED_SERVER_NAME, hDlg);
return FALSE;
}
if (!IsValidServerName (szServerName))
{
MessageBeep (MB_ICONEXCLAMATION);
PrivateMessageBox (IDS_MSG_INVALID_SERVER_NAME, hDlg);
return FALSE;
}
if (!IsWINDSServerAvailable (szServerName))
{
PrivateMessageBox (IDS_MSG_SERVER_NOT_FOUND, hDlg);
return FALSE;
}
if (fDownloadMBList)
{
if (S_OK == ShowServerAccounts (hDlg,
ghInstance,
szServerName,
szMailboxName,
szDisplayName,
szStoredPassword,
&dwMailboxID))
{
SetWindowText (GetDlgItem (hDlg, IDC_MAILBOXNAME), szMailboxName);
SetWindowText (GetDlgItem (hDlg, IDC_USER_NAME), szDisplayName);
fDownloadMBList = FALSE;
}
else
{
return FALSE;
}
}
break;

case 2:
if (!GetWindowTextLength (GetDlgItem (hDlg, IDC_PASSWORD)))
{
MessageBeep (MB_ICONEXCLAMATION);
PrivateMessageBox (IDS_MSG_SELECT_MB_NAME, hDlg);
SetFocus (GetDlgItem (hDlg, IDC_BROWSE_MB));
return FALSE;
}
if (!GetWindowText (GetDlgItem (hDlg, IDC_PASSWORD), szEnterPassword, sizeof(szEnterPassword)))
{
MessageBeep (MB_ICONEXCLAMATION);
PrivateMessageBox (IDS_MSG_NEED_PASSWORD, hDlg);
SetFocus (GetDlgItem (hDlg, IDC_PASSWORD));
return FALSE;
}
if (lstrcmp (szEnterPassword, szStoredPassword))
{
MessageBeep (MB_ICONEXCLAMATION);
PrivateMessageBox (IDS_MSG_INVALID_MB_PASSWORD, hDlg);
SetFocus (GetDlgItem (hDlg, IDC_PASSWORD));
return FALSE;
}
spvWizardProps[SERVER_NAME].ulPropTag = PR_SMP_REMOTE_SERVER;
spvWizardProps[SERVER_NAME].Value.LPSZ = szServerName;
spvWizardProps[MAILBOX_NAME].ulPropTag = PR_SMP_MAILBOX_NAME;
spvWizardProps[MAILBOX_NAME].Value.LPSZ = szMailboxName;
spvWizardProps[MAILBOX_ID].ulPropTag = PR_SMP_MAILBOX_ID;
spvWizardProps[MAILBOX_ID].Value.l = dwMailboxID;
spvWizardProps[USER_NAME].ulPropTag = PR_SMP_USER_NAME;
spvWizardProps[USER_NAME].Value.LPSZ = szDisplayName;
spvWizardProps[PASSWORD].ulPropTag = PR_SMP_MAILBOX_PASSWORD;
spvWizardProps[PASSWORD].Value.LPSZ = szStoredPassword;
// Since this is the last page in our configuration
// we must save the obtained data into the
// IMAPIProp object that the wizard gave us. In
// turn this data will be saved in the profile
// section of this provider
ASSERT (pPropObj);
if (pPropObj)
{
HRESULT hResult = pPropObj->SetProps (WIZARD_PROPERTIES, spvWizardProps, NULL);
if (hResult)
{
// Something went wrong
TraceResult ("WizardDlgPrc: Failed to set props", hResult);
return FALSE;
}
}
break;

default:
// We should not get here. No pages after three
ASSERT (FALSE);
break;
}
// Disable the page we were in and enable the next one
// before it is display by the wizard
TogglePage (hDlg, iPageNum, FALSE);
TogglePage (hDlg, ++iPageNum, TRUE);
return TRUE;

case WIZ_PREV:
// Disable the page we were in and enable the next one
// before it is display by the wizard
TogglePage (hDlg, iPageNum, FALSE);
TogglePage (hDlg, --iPageNum, TRUE);
return TRUE;
}
break;
}
return FALSE;
}

///////////////////////////////////////////////////////////////////////////////
// TogglePage()
//
// Parameters
// hDlg Handle to the dialogs where the controls are located
// iPage Number of the page we are going to toggle
// fState State of the controls: TRUE shows them, FALSE hides them
//
// Purpose
// This function will hide or show the controls for the page number
// specified in the iPage parameter.
//
// Return Value
// None
//
void WINAPI TogglePage (HWND hDlg, UINT iPage, BOOL fState)
{
// What page is it?
HWND hEditCtl = NULL;
switch (iPage)
{
// Toggle the controls that should be displayed for a particular page
case 1 :
EnableWindow (GetDlgItem (hDlg, IDC_STATIC1), fState);
ShowWindow (GetDlgItem (hDlg, IDC_STATIC1), fState ? SW_SHOW : SW_HIDE);
EnableWindow (GetDlgItem (hDlg, IDC_INFO1), fState);
ShowWindow (GetDlgItem (hDlg, IDC_INFO1), fState ? SW_SHOW : SW_HIDE);
hEditCtl = GetDlgItem (hDlg, IDC_SERVERNAME);
break;

case 2 :
EnableWindow (GetDlgItem (hDlg, IDC_STATIC2), fState);
ShowWindow (GetDlgItem (hDlg, IDC_STATIC2), fState ? SW_SHOW : SW_HIDE);
EnableWindow (GetDlgItem (hDlg, IDC_STATIC3), fState);
ShowWindow (GetDlgItem (hDlg, IDC_STATIC3), fState ? SW_SHOW : SW_HIDE);
EnableWindow (GetDlgItem (hDlg, IDC_STATIC4), fState);
ShowWindow (GetDlgItem (hDlg, IDC_STATIC4), fState ? SW_SHOW : SW_HIDE);
EnableWindow (GetDlgItem (hDlg, IDC_INFO2), fState);
ShowWindow (GetDlgItem (hDlg, IDC_INFO2), fState ? SW_SHOW : SW_HIDE);
EnableWindow (GetDlgItem (hDlg, IDC_MAILBOXNAME), fState);
ShowWindow (GetDlgItem (hDlg, IDC_MAILBOXNAME), fState ? SW_SHOW : SW_HIDE);
EnableWindow (GetDlgItem (hDlg, IDC_USER_NAME), fState);
ShowWindow (GetDlgItem (hDlg, IDC_USER_NAME), fState ? SW_SHOW : SW_HIDE);
EnableWindow (GetDlgItem (hDlg, IDC_BROWSE_MB), fState);
ShowWindow (GetDlgItem (hDlg, IDC_BROWSE_MB), fState ? SW_SHOW : SW_HIDE);
hEditCtl = GetDlgItem (hDlg, IDC_PASSWORD); // We want the button to have the focus by default
break;
}
if (hEditCtl)
{
EnableWindow (hEditCtl, fState);
ShowWindow (hEditCtl, fState ? SW_SHOW : SW_HIDE);
if (fState)
{
SetFocus (hEditCtl);
}
}
}

///////////////////////////////////////////////////////////////////////////////
// MergeConfigProps()
//
// Parameters
// ulCfgProps Number of properties for configuration
// pCfgProps Array of properties to configure the provider
// pLogonProps Array of properties found in the profile section of
// this service provider
//
// Purpose
// This function merges a property array that the user (or configuration
// application) passed into ServiceEntry with the property array of
// the provider, stored in the profile. This merged array is what
// either gets passed into the configuration dialog (if UI is allowed)
// and gets written out to the profile section for the service provider.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI MergeConfigProps (ULONG ulCfgProps,
LPSPropValue pCfgProps,
LPSPropValue pLogonProps)
{
while (ulCfgProps--)
{
// For the particular property found, set the proptag (in case
// the one in the profile was not valid), and the value. The
// value will be the value passed in the configuration prop array.
switch (pCfgProps[ulCfgProps].ulPropTag)
{
case PR_SMP_REMOTE_SERVER :
if (FALSE == IsValidServerName (pCfgProps[ulCfgProps].Value.LPSZ))
{
return E_INVALIDARG;
}
pLogonProps[SERVER_NAME] = pCfgProps[ulCfgProps];
break;
case PR_SMP_USER_NAME :
pLogonProps[USER_NAME] = pCfgProps[ulCfgProps];
break;
case PR_SMP_MAILBOX_NAME :
pLogonProps[MAILBOX_NAME] = pCfgProps[ulCfgProps];
break;
case PR_SMP_MAILBOX_ID :
pLogonProps[MAILBOX_ID] = pCfgProps[ulCfgProps];
break;
case PR_SMP_MAILBOX_PASSWORD :
pLogonProps[PASSWORD] = pCfgProps[ulCfgProps];
break;
}
}
return S_OK;
}

///////////////////////////////////////////////////////////////////////////////
// OpenServiceProfileSection()
//
// Parameters
// pSupObj Pointer to the provider support object
// ppProfSectObj Where we return a pointer to the service profile
// section of the provider
// pfnFreeBuffer MAPI memory allocation function
//
// Purpose
// This function opens the profile section of this service, where the
// properties of a WINDS provider (AB, MS, or XP) are stored.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI OpenServiceProfileSection (LPMAPISUP pSupObj,
LPPROFSECT * ppProfSectObj,
LPFREEBUFFER pfnFreeBuffer)
{
SPropTagArray sptService = { 1, { PR_SERVICE_UID } };
LPPROFSECT pProvProfSectObj;
ULONG cValues;
LPSPropValue pProp;
// Get the PROVIDER profile section
HRESULT hResult = pSupObj->OpenProfileSection (NULL,
MAPI_MODIFY,
&pProvProfSectObj);
if (!hResult)
{
// Get the UID of the profile section of the service where this provider is installed
hResult = pProvProfSectObj->GetProps (&sptService, fMapiUnicode, &cValues, &pProp);
if (SUCCEEDED(hResult))
{
if (S_OK == hResult)
{
// Now, with the obtained UID, open the profile section of the service
ASSERTMSG (PR_SERVICE_UID == pProp->ulPropTag, "Where is PR_SERVICE_UID");
hResult = pSupObj->OpenProfileSection ((LPMAPIUID)pProp->Value.bin.lpb,
MAPI_MODIFY,
ppProfSectObj);
}
else
{
hResult = E_FAIL;
}
pfnFreeBuffer (pProp);
}
pProvProfSectObj->Release();
}
TraceResult ("OpenServiceProfileSection", hResult);
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// PrivInitialize3DCtl()
//
// Parameters
// hInstance Handle to the instance the control 3d library will
// subclass
//
// Purpose
// This function dynamically binds to the CTL3D library for UI apperance
// on Windows NT. On Windows 95 the library may or may not be on the
// system. We do this to have a single binary file that works on
// Windows NT and Windows 95 and ensure that the WINDS service DLL loads
// correctly in both platforms.
// The CTL3D provider a less disparate user interface between the two OS's
//
// Return Value
// None
//
void WINAPI PrivInitialize3DCtl (HINSTANCE hInstance)
{
if (NULL == ghUIControl)
{
ghUIControl = LoadLibrary (TEXT("CTL3D32.DLL"));
if (ghUIControl)
{
pfn3DRegister = (LPCTL3DFUNCTION)GetProcAddress (ghUIControl, TEXT("Ctl3dRegister"));
pfn3DUnregister = (LPCTL3DFUNCTION)GetProcAddress (ghUIControl, TEXT("Ctl3dUnregister"));
pfn3DAutoSubclass = (LPCTL3DFUNCTION)GetProcAddress (ghUIControl, TEXT("Ctl3dAutoSubclass"));
pfnDlgSubclassEx = (LPCTL3DSUBCLASS)GetProcAddress (ghUIControl, TEXT("Ctl3dSubclassDlgEx"));

if (pfn3DRegister &&
pfn3DUnregister &&
pfn3DAutoSubclass &&
pfnDlgSubclassEx)
{
pfn3DRegister (hInstance);
pfn3DAutoSubclass (hInstance);
}
else
{
PrivUninitialize3DCtl (hInstance);
}
}
}
}

///////////////////////////////////////////////////////////////////////////////
// PrivUninitialize3DCtl()
//
// Parameters
// hInstance Handle to the instance the control 3d library will
// de-attach from.
//
// Purpose
// Unregister the 3D UI control stuff and unload the library of the
// 3D controls.
//
// Return Value
// None
//
void WINAPI PrivUninitialize3DCtl (HINSTANCE hInstance)
{
if (ghUIControl)
{
if (pfn3DUnregister)
{
pfn3DUnregister (hInstance);
}
FreeLibrary (ghUIControl);
ghUIControl = NULL;
pfn3DRegister = NULL;
pfn3DUnregister = NULL;
pfn3DAutoSubclass = NULL;
pfnDlgSubclassEx = NULL;
}
}

///////////////////////////////////////////////////////////////////////////////
// CheckForPendingMessages()
//
// Parameters
// szServerName Name of the server we are going to connect
// szMailboxName Name of the mailbox we are going to check
// pulMsgWaiting Number of messages waiting for download
//
// Purpose
// This function queries the remote server for how many messages are
// waiting in the specified mailbox.
// If there are not messages waiting, the function return S_FALSE.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI CheckForPendingMessages (LPTSTR szServerName,
LPTSTR szMailboxName,
ULONG * pulMsgWaiting)
{
HRESULT hResult = BindToServer (szServerName);
if (hResult)
{
return hResult;
}
RpcTryExcept
{
hResult = RemoteCheckNewMail ((WINDS_RPC_STRING)szMailboxName, pulMsgWaiting);
}
RpcExcept(1)
{
// If we got here is because there was an error while call was made
// or when it was about to be made.
hResult = RpcExceptionCode();
if (RPC_S_SERVER_UNAVAILABLE == hResult)
{
hResult = HRESULT_FROM_WIN32(ERROR_HOST_UNREACHABLE);
}
else
{
hResult = MAKE_HRESULT(1, FACILITY_RPC, hResult);
}
}
RpcEndExcept
#ifdef _DEBUG
if (hResult && S_FALSE != hResult)
{
TraceResult ("CheckForPendingMessages", hResult);
}
#endif // _DEBUG
return hResult;
}

///////////////////////////////////////////////////////////////////////////////
// GetNextMailboxMsg()
//
// Parameters
// szServerName Name of the server we are going to connect
// szMailboxName Name of the mailbox we are going to get the
// messages from
// szLocalMsgFile Name of the local file where the message
// should be placed.
//
// Purpose
// This function connect to the server an request the next message to
// be downloaded for the mailbox specified in call. If there are no
// more messages to download, we return S_FALSE.
//
// Return Value
// An HRESULT
//
HRESULT WINAPI GetNextMailboxMsg (LPTSTR szServerName,
LPTSTR szMailboxName,
LPTSTR szLocalMsgFile)
{
HRESULT hResult = BindToServer (szServerName);
if (hResult)
{
return hResult;
}
long lPipeNumber;
HANDLE hPipe, hFile;
TCHAR szPipeName[64];
BYTE abBuffer[IO_BUFFERSIZE];
DWORD dwBytesRead, dwBytesWritten;
RpcTryExcept
{
hResult = RemoteOpenOneMsgDownloadPipe ((WINDS_RPC_STRING)szMailboxName, &lPipeNumber);
if (!hResult)
{
wsprintf (szPipeName, PIPE_NAME_FORMAT, szServerName, lPipeNumber);
hPipe = CreateFile (szPipeName,
GENERIC_READ,
0,
NULL,
OPEN_EXISTING,
0,
NULL);
if (INVALID_HANDLE_VALUE == hPipe)
{
hResult = HRESULT_FROM_WIN32(GetLastError());
TraceResult ("GetHeadersFromServer: Failed to open pipe to server", hResult);
}
else
{
hFile = CreateFile (szLocalMsgFile,
GENERIC_WRITE,
0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,
NULL);
if (INVALID_HANDLE_VALUE == hFile)
{
hResult = HRESULT_FROM_WIN32(GetLastError());
TraceResult ("GetNextMailboxMsg: Failed to open local headers file", hResult);
}
else
{
do
{
// Read the pipe handle.
if (!ReadFile (hPipe, abBuffer, IO_BUFFERSIZE, &dwBytesRead, NULL))
{
hResult = HRESULT_FROM_WIN32(GetLastError());
if (HRESULT_FROM_WIN32(ERROR_BROKEN_PIPE) != hResult && // For Windows NT
HRESULT_FROM_WIN32(ERROR_ACCESS_DENIED) != hResult) // For Windows 95
{
// There was an error and we can't continue
TraceResult ("GetNextMailboxMsg: Failed to read from the pipe", hResult);
}
else
{
// If the pipe was broken, it means the server finished writing
// to the it, so we are finished reading from it.
hResult = S_OK;
}
}
if (dwBytesRead)
{
if (!WriteFile (hFile, abBuffer, dwBytesRead, &dwBytesWritten, NULL))
{
hResult = HRESULT_FROM_WIN32(GetLastError());
TraceResult ("GetNextMailboxMsg: Failed to write to local header file", hResult);
}
}
} while (dwBytesRead && !hResult);
CloseHandle (hFile);
}
CloseHandle (hPipe);
}
}
}
RpcExcept(1)
{
// If we got here is because there was an error while call was made
// or when it was about to be made.
hResult = RpcExceptionCode();
if (RPC_S_SERVER_UNAVAILABLE == hResult)
{
hResult = HRESULT_FROM_WIN32(ERROR_HOST_UNREACHABLE);
}
else
{
hResult = MAKE_HRESULT(1, FACILITY_RPC, hResult);
}
}
RpcEndExcept
#ifdef _DEBUG
if (hResult && S_FALSE != hResult)
{
TraceResult ("GetNextMailboxMsg", hResult);
}
#endif // _DEBUG
return hResult;
}

// End of file for COMWINDS.CPP