windows-nt/Source/XPSP1/NT/printscan/fax/print/faxprint/faxui/mapiutil.c
2020-09-26 16:20:57 +08:00

1018 lines
21 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}