|
|
/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
mapiutil.c
Abstract:
Utility functions for working with MAPI
Environment:
Windows NT fax driver user interface
Revision History:
09/18/96 -davidx- Created it.
mm/dd/yy -author- description
--*/
#include "faxui.h"
#define INITGUID
#define USES_IID_IMAPISession
#define USES_IID_IDistList
#include "mapiwrap.h"
//
// Global variables used for accessing MAPI services
//
static HINSTANCE hInstMapi = NULL; static INT mapiRefCount = 0;
ULONG lhMapiSession = 0; LPMAPISESSION lpMapiSession = NULL; LPMAPILOGON lpfnMAPILogon = NULL; LPMAPILOGOFF lpfnMAPILogoff = NULL; LPMAPIADDRESS lpfnMAPIAddress = NULL; LPMAPIFREEBUFFER lpfnMAPIFreeBuffer = NULL; LPSCMAPIXFROMSMAPI lpfnScMAPIXFromSMAPI = NULL;
//
// Function to insert a recipient into the recipient list view
//
BOOL InsertRecipientListItem( HWND hwndLV, PRECIPIENT pRecipient );
BOOL IsMapiAvailable( VOID )
/*++
Routine Description:
Determine whether MAPI is available
Arguments:
NONE
Return Value:
TRUE if MAPI is installed on the system, FALSE otherwise
--*/
{ return GetProfileInt(TEXT("MAIL"), TEXT("MAPI"), 0); }
BOOL DoMapiLogon( HWND hDlg )
/*++
Routine Description:
Logon MAPI to in order to access address book
Arguments:
hDlg - Handle to the send fax wizard window
Return Value:
TRUE if successful, FALSE if there is an error
!!!BUGBUG:
MAPI is not Unicoded enabled on NT. Must revisit this code once that's fixed.
--*/
#define MAX_PROFILE_NAME 256
{ LPTSTR profileName; CHAR ansiProfileName[MAX_PROFILE_NAME]; HKEY hRegKey; ULONG status;
//
// Retrieve the fax profile name stored in registry
//
profileName[0] = NUL;
if (hRegKey = GetUserInfoRegKey(REGKEY_FAX_SETUP, REG_READONLY)) {
profileName = GetRegistryString(hRegKey, REGVAL_FAX_PROFILE, TEXT("")); RegCloseKey(hRegKey);
if (!profileName || !*profileName) { return FALSE; } } else { return FALSE; }
Verbose(("Fax profile name: %ws\n", profileName));
//
// Attempt to logon to MAPI - We need to convert MAPI profile name to ANSI
// here because MAPI is not Unicode enabled.
//
if (! WideCharToMultiByte(CP_ACP, 0, profileName, -1, ansiProfileName, MAX_PROFILE_NAME, NULL, NULL)) { Error(("WideCharToMultiByte failed: %d\n", GetLastError())); MemFree(profileName); return FALSE; }
MemFree(profileName);
status = lpfnMAPILogon((ULONG) hDlg, ansiProfileName, NULL, MAPI_LOGON_UI, 0, &lhMapiSession);
//
// If a profile name is specified and logon failed,
// then try again without a profile.
//
if (status != SUCCESS_SUCCESS && !IsEmptyString(ansiProfileName)) {
ansiProfileName[0] = NUL;
status = lpfnMAPILogon((ULONG) hDlg, ansiProfileName, NULL, MAPI_LOGON_UI, 0, &lhMapiSession); }
if (status != SUCCESS_SUCCESS) {
Error(("MAPILogon failed: %d\n", status)); return FALSE; }
//
// Convert simple MAPI session handle to extended MAPI session pointer
//
if (FAILED(lpfnScMAPIXFromSMAPI(lhMapiSession, 0, &IID_IMAPISession, &lpMapiSession))) {
Error(("ScMAPIXFromSMAPI failed: %d\n", GetLastError())); lpfnMAPILogoff(lhMapiSession, 0, 0, 0); return FALSE; }
return TRUE; }
BOOL InitMapiService( HWND hDlg )
/*++
Routine Description:
Initialize Simple MAPI services if necessary
Arguments:
hDlg - Handle to the send fax wizard window
Return Value:
TRUE if successful, FALSE otherwise
NOTE:
Every successful call to this function must be balanced by a call to DeinitMapiService.
--*/
{ BOOL result;
EnterDrvSem();
//
// Load MAPI32.DLL into memory if necessary
//
if ((hInstMapi == NULL) && (hInstMapi = LoadLibrary(TEXT("MAPI32.DLL")))) { //
// Get pointers to various Simple MAPI functions
//
lpfnMAPILogon = (LPMAPILOGON) GetProcAddress(hInstMapi, "MAPILogon"); lpfnMAPILogoff = (LPMAPILOGOFF) GetProcAddress(hInstMapi, "MAPILogoff"); lpfnMAPIAddress = (LPMAPIADDRESS) GetProcAddress(hInstMapi, "MAPIAddress"); lpfnMAPIFreeBuffer = (LPMAPIFREEBUFFER) GetProcAddress(hInstMapi, "MAPIFreeBuffer"); lpfnScMAPIXFromSMAPI = (LPSCMAPIXFROMSMAPI) GetProcAddress(hInstMapi, "ScMAPIXFromSMAPI");
//
// Begins a simple MAPI session and obtain session handle and pointer
//
if (lpfnMAPILogon == NULL || lpfnMAPILogoff == NULL || lpfnMAPIAddress == NULL || lpfnMAPIFreeBuffer == NULL || lpfnScMAPIXFromSMAPI == NULL || !DoMapiLogon(hDlg)) { //
// Clean up properly in case of error
//
lhMapiSession = 0; lpMapiSession = NULL; FreeLibrary(hInstMapi); hInstMapi = NULL; } }
if (result = (hInstMapi != NULL)) mapiRefCount++; else Error(("InitMapiService failed: %d", GetLastError()));
LeaveDrvSem();
return result; }
VOID DeinitMapiService( VOID )
/*++
Routine Description:
Deinitialize Simple MAPI services if necessary
Arguments:
NONE
Return Value:
NONE
--*/
{ EnterDrvSem();
Assert(hInstMapi != NULL);
if (mapiRefCount > 0 && --mapiRefCount == 0 && hInstMapi != NULL) { if (lpMapiSession) MAPICALL(lpMapiSession)->Release(lpMapiSession);
if (lhMapiSession) lpfnMAPILogoff(lhMapiSession, 0, 0, 0);
lhMapiSession = 0; lpMapiSession = NULL; FreeLibrary(hInstMapi); hInstMapi = NULL; }
LeaveDrvSem(); }
LPSTR DupStringUnicodeToAnsi( LPWSTR pUnicodeStr )
/*++
Routine Description:
Convert a Unicode string to a multi-byte string
Arguments:
pUnicodeStr - Pointer to the Unicode string to be duplicated
Return Value:
Pointer to the duplicated multi-byte string
NOTE:
This is only need because MAPI is not Unicode enabled on NT.
--*/
{ INT nChar; LPSTR pAnsiStr;
//
// Figure out how much memory to allocate for the multi-byte string
//
if (! (nChar = WideCharToMultiByte(CP_ACP, 0, pUnicodeStr, -1, NULL, 0, NULL, NULL)) || ! (pAnsiStr = MemAlloc(nChar))) { return NULL; }
//
// Convert Unicode string to multi-byte string
//
WideCharToMultiByte(CP_ACP, 0, pUnicodeStr, -1, pAnsiStr, nChar, NULL, NULL); return pAnsiStr; }
BOOL CallMapiAddress( HWND hDlg, PUSERMEM pUserMem, PULONG pnRecips, lpMapiRecipDesc *ppRecips )
/*++
Routine Description:
Call MAPIAddress to display the address dialog
Arguments:
hDlg - Handle to the send fax wizard window pUserMem - Points to user mode memory structure pnRecips - Returns number of selected recipients ppRecips - Returns information about selected recipients
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{ lpMapiRecipDesc pRecips; PRECIPIENT pRecipient; ULONG nRecips, index; LONG status;
//
// Convert the recipient list to an array of MapiRecipDesc
//
nRecips = 0; pRecipient = pUserMem->pRecipients;
while (pRecipient) {
nRecips++; pRecipient = pRecipient->pNext; }
if (nRecips == 0) pRecips = NULL; else if (! (pRecips = MemAllocZ(nRecips * sizeof(MapiRecipDesc)))) return FALSE;
status = SUCCESS_SUCCESS; index = nRecips; pRecipient = pUserMem->pRecipients;
Verbose(("Recipients passed to MAPIAddress:\n"));
while (index-- > 0) {
Assert(pRecipient != NULL);
pRecips[index].ulRecipClass = MAPI_TO; pRecips[index].lpszName = DupStringUnicodeToAnsi(pRecipient->pName); pRecips[index].lpszAddress = DupStringUnicodeToAnsi(pRecipient->pAddress);
if (!pRecips[index].lpszName || !pRecips[index].lpszAddress) {
status = MAPI_E_INSUFFICIENT_MEMORY; break; }
Verbose((" %s, %s\n", pRecips[index].lpszName, pRecips[index].lpszAddress));
pRecipient = pRecipient->pNext; }
//
// Call MAPI to display the address book dialog
//
if (status == SUCCESS_SUCCESS) {
status = lpfnMAPIAddress(lhMapiSession, (ULONG) hDlg, NULL, 1, NULL, nRecips, pRecips, MAPI_LOGON_UI, 0, pnRecips, ppRecips); }
//
// Free the input recipient list after coming back from MAPI
//
for (index=0; index < nRecips; index++) {
MemFree(pRecips[index].lpszName); MemFree(pRecips[index].lpszAddress); }
MemFree(pRecips);
if (status != SUCCESS_SUCCESS) {
Error(("MAPIAddress failed: %d\n", status)); return FALSE; }
return TRUE; }
INT InterpretSimpleAddress( PUSERMEM pUserMem, HWND hwndLV, LPSTR pRecipName, LPSTR pRecipAddress )
/*++
Routine Description:
Process a simple address entry and insert it into the recipient list view
Arguments:
pUserMem - Points to user mode memory structure hwndLV - Handle to the recipient list view window pRecipName - Specifies the name of the recipient pRecipName - Specifies the recipient's address
Return Value:
-1 : if there is an error 0 : if the address entry is ignored 1 : if successful
--*/
{ LPTSTR pName, pAddress; INT nameLen, addrLen; PRECIPIENT pRecipient;
//
// Allocate memory to hold recipient information
//
if (pRecipName == NULL) {
Error(("Recipient name is NULL!\n")); return -1; }
nameLen = strlen(pRecipName) + 1; addrLen = strlen(pRecipAddress) + 1;
pRecipient = MemAllocZ(sizeof(RECIPIENT)); pName = MemAllocZ(nameLen * sizeof(TCHAR)); pAddress = MemAllocZ(addrLen * sizeof(TCHAR));
if (!pRecipient || !pName || !pAddress) {
Error(("Memory allocation failed\n")); MemFree(pRecipient); MemFree(pName); MemFree(pAddress); return -1; }
pRecipient->pName = pName; pRecipient->pAddress = pAddress;
//
// Convert name and address from Ansi string to Unicode string
//
MultiByteToWideChar(CP_ACP, 0, pRecipName, -1, pName, nameLen); MultiByteToWideChar(CP_ACP, 0, pRecipAddress, -1, pAddress, addrLen);
//
// Add this recipient to the recipient list
//
if (InsertRecipientListItem(hwndLV, pRecipient)) {
pRecipient->pNext = pUserMem->pRecipients; pUserMem->pRecipients = pRecipient; return 1;
} else {
FreeRecipient(pRecipient); return -1; } }
INT DetermineAddressType( LPSTR pAddress )
/*++
Routine Description:
Determine the type of an address
Arguments:
pAddress - Points to an address or address type string
Return Value:
One of the ADDRTYPE_* constants below
--*/
#define ADDRTYPE_NULL 0
#define ADDRTYPE_FAX 1
#define ADDRTYPE_MAPIPDL 2
#define ADDRTYPE_UNKNOWN 3
#define ADDRTYPESTR_FAX "FAX"
#define ADDRTYPESTR_MAPIPDL "MAPIPDL"
{ INT n; LPSTR p;
//
// Check if the input string is NULL
//
if (pAddress == NULL) return ADDRTYPE_NULL;
//
// Check if the address type is FAX
//
p = ADDRTYPESTR_FAX; n = strlen(p);
if ((_strnicmp(pAddress, p, n) == EQUAL_STRING) && (pAddress[n] == NUL || pAddress[n] == ':')) { return ADDRTYPE_FAX; }
//
// Check if the address type is MAPIPDL
//
p = ADDRTYPESTR_MAPIPDL; n = strlen(p);
if ((_strnicmp(pAddress, p, n) == EQUAL_STRING) && (pAddress[n] == NUL || pAddress[n] == ':')) { return ADDRTYPE_MAPIPDL; }
//
// Address type is something that we don't understand
//
return ADDRTYPE_UNKNOWN; }
LPSTR ConcatTypeWithAddress( LPSTR pType, LPSTR pAddress )
/*++
Routine Description:
Helper function to concatenate address type in front of the address
Arguments:
pType - Points to address type string pAddress - Points to address string
Return Value:
Pointer to concatenated address, NULL if there is an error
--*/
{ INT length; LPSTR p;
//
// Sanity check
//
if (pType == NULL || pAddress == NULL) return NULL;
//
// Calculate the length of the concatenated string
//
length = strlen(pType) + 1 + strlen(pAddress) + 1;
//
// Concatenate type with address, separated by a colon
//
if (p = MemAllocZ(length)) sprintf(p, "%s:%s", pType, pAddress);
return p; }
INT InterpretDistList( PUSERMEM pUserMem, HWND hwndLV, ULONG ulEIDSize, PVOID pEntryID )
/*++
Routine Description:
Expand a distribution list entry and insert the individual addresses into the recipient list view.
Arguments:
pUserMem - Points to user mode memory structure hwndLV - Handle to the recipient list view window ulEIDSize - Specifies the size of entry ID pEntryID - Points to entry ID data
Return Value:
> 0 : total number of useful address entries = 0 : no useful address entry found < 0 : if there is an error
--*/
#define EXIT_IF_FAILED(hr) { if (FAILED(hr)) goto ExitDistList; }
{ LPDISTLIST pDistList = NULL; LPMAPITABLE pMapiTable = NULL; LPSRowSet pRows = NULL; ULONG ulObjType, cRows; HRESULT hr; INT entriesUsed = 0;
static SizedSPropTagArray(4, sPropTags) = { 4, { PR_ENTRYID, PR_ADDRTYPE_A, PR_DISPLAY_NAME_A, PR_EMAIL_ADDRESS_A } };
//
// Deal with distribution lists
//
if (ulEIDSize == 0 || pEntryID == NULL) {
Error(("Unusable address entry\n")); return FALSE; }
//
// Open the recipient entry
//
hr = MAPICALL(lpMapiSession)->OpenEntry(lpMapiSession, ulEIDSize, pEntryID, &IID_IDistList, MAPI_DEFERRED_ERRORS, &ulObjType, (LPUNKNOWN *) &pDistList);
EXIT_IF_FAILED(hr);
//
// Get the contents table of the address entry
//
hr = MAPICALL(pDistList)->GetContentsTable(pDistList, MAPI_DEFERRED_ERRORS, &pMapiTable);
EXIT_IF_FAILED(hr);
//
// Limit the query to only the properties we're interested in
//
hr = MAPICALL(pMapiTable)->SetColumns(pMapiTable, (LPSPropTagArray) &sPropTags, 0);
EXIT_IF_FAILED(hr);
//
// Get the total number of rows
//
hr = MAPICALL(pMapiTable)->GetRowCount(pMapiTable, 0, &cRows);
EXIT_IF_FAILED(hr);
//
// Get the individual entries of the distribution list
//
hr = MAPICALL(pMapiTable)->SeekRow(pMapiTable, BOOKMARK_BEGINNING, 0, NULL);
EXIT_IF_FAILED(hr);
hr = MAPICALL(pMapiTable)->QueryRows(pMapiTable, cRows, 0, &pRows);
EXIT_IF_FAILED(hr);
hr = S_OK; entriesUsed = 0;
if (pRows && pRows->cRows) {
//
// Handle each entry of the distribution list in turn:
// for simple entries, call InterpretSimpleAddress
// for embedded distribution list, call this function recursively
//
for (cRows = 0; cRows < pRows->cRows; cRows++) {
LPSPropValue lpProps = pRows->aRow[cRows].lpProps; LPSTR pType, pName, pAddress; INT result;
pType = lpProps[1].Value.lpszA; pName = lpProps[2].Value.lpszA; pAddress = lpProps[3].Value.lpszA;
Verbose((" %s: %s", pType, pName));
switch (DetermineAddressType(pType)) {
case ADDRTYPE_FAX:
if ((pAddress != NULL) && (lpProps[3].ulPropTag == PR_EMAIL_ADDRESS_A) && (pAddress = ConcatTypeWithAddress(pType, pAddress))) { Verbose((", %s\n", pAddress));
result = InterpretSimpleAddress(pUserMem, hwndLV, pName, pAddress); MemFree(pAddress);
} else {
Verbose(("\nBad address.\n")); result = -1; } break;
case ADDRTYPE_MAPIPDL: case ADDRTYPE_NULL:
Verbose(("\n"));
result = InterpretDistList(pUserMem, hwndLV, lpProps[0].Value.bin.cb, lpProps[0].Value.bin.lpb); break;
default:
Verbose(("\nUnknown address type.\n")); result = 0; break; }
if (result < 0) hr = -1; else entriesUsed += result; } }
ExitDistList:
//
// Perform necessary clean up before returning to caller
//
if (pRows) {
for (cRows = 0; cRows < pRows->cRows; cRows++) lpfnMAPIFreeBuffer(pRows->aRow[cRows].lpProps);
lpfnMAPIFreeBuffer(pRows); }
if (pMapiTable) MAPICALL(pMapiTable)->Release(pMapiTable);
if (pDistList) MAPICALL(pDistList)->Release(pDistList);
if (FAILED(hr)) {
Error(("InterpretDistList failed: 0x%x\n", hr)); return -1;
} else return entriesUsed; }
BOOL InterpretSelectedAddresses( HWND hDlg, PUSERMEM pUserMem, HWND hwndLV, ULONG nRecips, lpMapiRecipDesc pRecips )
/*++
Routine Description:
Expand the selected addresses and insert them into the recipient list view
Arguments:
hDlg - Handle to the send fax wizard window pUserMem - Points to user mode memory structure hwndLV - Handle to the recipient list view window nRecips - Number of selected recipients pRecips - Information about selected recipients
Return Value:
TRUE if successful, FALSE if there is an error
--*/
{ INT discarded = 0;
//
// Remove all existing entries in the recipient list view
//
if (! ListView_DeleteAllItems(hwndLV)) return FALSE;
FreeRecipientList(pUserMem);
Verbose(("Recipients returned from MAPIAddress:\n"));
for ( ; nRecips--; pRecips++) {
INT result;
Verbose((" %s, %s\n", pRecips->lpszName, pRecips->lpszAddress));
switch (DetermineAddressType(pRecips->lpszAddress)) {
case ADDRTYPE_FAX:
result = InterpretSimpleAddress(pUserMem, hwndLV, pRecips->lpszName, pRecips->lpszAddress); break;
case ADDRTYPE_MAPIPDL: case ADDRTYPE_NULL:
result = InterpretDistList(pUserMem, hwndLV, pRecips->ulEIDSize, pRecips->lpEntryID); break;
default:
Verbose(("Unknown address type.\n")); result = 0; break; }
if (result <= 0) discarded++; }
if (discarded) DisplayMessageDialog(hDlg, 0, 0, IDS_BAD_ADDRESS_TYPE);
return TRUE; }
|