|
|
/*
=============================================================================== Module - edk.cpp System - EnterpriseAdministrator Creator - Steven Bailey Created - 2 Apr 97 Description - Exchange MAPI helper routines. Updates - Christy Boles - added more MAPI helper functions, and some DAPI helper functions. =============================================================================== */ #ifdef USE_STDAFX
# include "stdafx.h"
#else
# include <windows.h>
#endif
#include <mapiguid.h>
#include "edk2.hpp"
#include <edkcode.h>
#include <objbase.h>
#include <mapiutil.h>
#include <emsabtag.h>
#include <_ENTRYID.H>
extern LPMAPIALLOCATEBUFFER pMAPIAllocateBuffer; extern LPMAPIFREEBUFFER pMAPIFreeBuffer; extern LPMAPIINITIALIZE pMAPIInitialize; extern LPMAPIUNINITIALIZE pMAPIUninitialize; extern LPMAPILOGONEX pMAPILogonEx; extern LPMAPIADMINPROFILES pMAPIAdminProfiles; extern LPFREEPADRLIST pFreePadrlist; extern LPFREEPROWS pFreeProws; extern LPSCDUPPROPSET pScDupPropset; extern LPHRQUERYALLROWS pHrQueryAllRows; extern LPULRELEASE pUlRelease;
#define CHAR WCHAR
#define HR_LOG(x) x
// definition of the Exchange address type.
// from edk.h
#define EXCHANGE_ADDRTYPE L"EX"
#define CbNewFlagList(_cflag) \
(offsetof(FlagList,ulFlag) + (_cflag)*sizeof(ULONG))
//$--cbStrLen@------------------------------------------------
// Returns total number of bytes (including NULL) used by
// a string. Useful for string allocations...
// -----------------------------------------------------------
#define cbStrLenA(sz) ((lstrlenA((sz)) + 1) * sizeof(CHAR))
#if defined(_M_IX86)
#define cbStrLenW(sz) ((lstrlenW((sz)) + 1) * sizeof(WCHAR))
#else
// lstrlenW can return 0 for UNALIGNED UNICODE strings on non-IX86 platforms
__inline static size_t cbStrLenW( IN UNALIGNED const WCHAR *wsz) { size_t cbWsz = 0;
for(; *wsz; wsz++) cbWsz += sizeof( WCHAR);
return( cbWsz + sizeof( WCHAR)); } #endif
#ifdef UNICODE
#define cbStrLen cbStrLenW
#else
#define cbStrLen cbStrLenA
#endif
#define ULRELEASE(x) \
{ \ (*pUlRelease)((x)); \ (x) = NULL; \ }
#define MAPIFREEBUFFER(x) \
{ \ (*pMAPIFreeBuffer)((x)); \ (x) = NULL; \ }
#define FREEPADRLIST(x) \
{ \ (*pFreePadrlist)((x)); \ (x) = NULL; \ }
#define FREEPROWS(x) \
{ \ (*pFreeProws)((x)); \ (x) = NULL; \ }
// Definitions from ExchInst.c
#define MAX_CSV_LINE_SIZ 2048
#define MAX_WORD 0xFFFF
#define FILE_PREFIX L"EXCH"
#define NEW_LINE L"\r\n"
#define EXCHINST_DELIM L'\t'
#define EXCHINST_QUOTE L'"'
#define EXCHINST_MV_SEP L'%'
#define SZ_EXCHINST_DELIM L"\t"
#define SZ_EXCHINST_QUOTE L"\""
#define SZ_EXCHINST_MV_SEP L"%"
#define BEGIN_CSV_LINE(a,b) lstrcpy(a, b)
#define APPEND_CSV_LINE(a,b) \
{ \ lstrcat(a, SZ_EXCHINST_DELIM); \ lstrcat(a, b); \ }
#define DELETEFILE(_file) \
{ \ if((_file) != NULL && (_file)[0] != 0) \ { \ if(! DeleteFile ((_file))) \ { \ HRESULT _hr = HR_LOG(E_FAIL); \ } \ } \ (_file)[0] = 0; \ }
#define CLOSEHANDLE(h) \
{ \ if(((h) != NULL) && ((h) != INVALID_HANDLE_VALUE)) \ { \ if(CloseHandle((h)) == FALSE) \ { \ /* HRESULT _hr = HR_LOG(E_FAIL); \
*/ HR_LOG(E_FAIL); \ } \ (h) = NULL; \ } \ }
//
// Attribute Defines
//
#define OBJ_CLASS L"Obj-Class"
#define MODE L"Mode"
#define ADDR_SYNTAX L"Address-Syntax"
#define ADDR_ENTRY_DT L"Address-Entry-Display-Table"
#define ADDR_TYPE L"Address-Type"
#define ADMIN_DISPLAY_NAME L"Admin-Display-Name"
#define DISPLAY_NAME L"Display-Name"
#define COMMON_NAME L"Common-Name"
#define DELIVERY_MECHANISM L"Delivery-Mechanism"
#define DELIV_EXT_CONT_TYPES L"Deliv-Ext-Cont-Types"
#define EXTENSION_DATA L"Extension-Data"
#define EXTENSION_NAME L"Extension-Name"
#define HELP_FILE_NAME L"Help-File-Name"
#define COMPUTER_NAME L"Computer-Name"
#define GATEWAY_PROXY L"Gateway-Proxy"
#define HOME_SERVER L"Home-Server"
#define FILE_VERSION L"File-Version"
#define PER_MSG_DDT L"Per-Msg-Dialog-Display-Table"
#define PER_RECIP_DDT L"Per-Recip-Dialog-Display-Table"
#define PROXY_GENERATOR_DLL L"Proxy-Generator-DLL"
#define ROUTING_LIST L"Routing-List"
#define OBJ_DIST_NAME L"Obj-Dist-Name"
#define ORGANIZATION L"Organization"
#define ORGANIZATIONAL_UNIT L"Organizational-Unit"
#define CONTAINER L"Container"
#define HELP_DATA16 L"Help-Data16"
#define HELP_DATA32 L"Help-Data32"
#define OBJ_ADMIN L"Obj-Admins"
#define SITE_ADDRESSING L"Site-Addressing"
#define ADMIN_EXTENSION_DLL L"Admin-Extension-Dll"
#define CAN_PRESERVE_DNS L"Can-Preserve-DNs"
#define HEURISTICS L"Heuristics"
#define CONTAINER_INFO L"Container-Info"
//
// Attribute Value Defines
//
#define OBJ_CLASS_GW L"Mail-Gateway"
#define OBJ_CLASS_MB L"Mailbox-Agent"
#define OBJ_CLASS_SITE L"Site-Addressing"
#define OBJ_CLASS_ADDR_TYPE L"Addr-Type"
#define OBJ_CLASS_ADDR_TEMPLATE L"Address-Template"
#define OBJ_CLASS_ADMIN_EXTENSION L"Admin-Extension"
#define OBJ_CLASS_COMPUTER L"Computer"
#define OBJ_CLASS_CONTAINER L"Container"
//
// Container Information Defines
//
#define ADDRESS_TEMPLATE_CONTAINER_INFO L"256"
//
// Import Mode Defines
//
#define MODE_CREATE L"Create"
#define MODE_MODIFY L"Modify"
#define MODE_DELETE L"Delete"
#define DELIVERY_MECHANISM_GW L"2"
#define DELIVERY_MECHANISM_MB L"0"
#define CONTAINER_CONFIGURATION L"/cn=Configuration"
#define CONTAINER_GW L"/cn=Configuration/cn=Connections"
#define CONTAINER_ADDR_TYPE L"/cn=Configuration/cn=Addressing/cn=Address-Types"
#define CONTAINER_ADDR_TEMPLATE L"/cn=Configuration/cn=Addressing/cn=Address-Templates"
#define CONTAINER_SERVERS L"/cn=Configuration/cn=Servers"
#define CONTAINER_SITE_ADDR L"/cn=Configuration/cn=Site-Addressing"
#define CONTAINER_ADD_INS L"/cn=Configuration/cn=Add-Ins"
#define ACCOUNT_NAME L"Obj-Users"
//
// Common macros.
//
#define CREATEKEY(hkParent, pszName, hkOut, dwDisposition) \
RegCreateKeyEx(hkParent, pszName, 0, "", REG_OPTION_NON_VOLATILE, \ KEY_ALL_ACCESS, NULL, &hkOut, &dwDisposition)
#define SETSZVALUE(hk, pszName, pszValue) \
RegSetValueEx(hk, pszName, 0, REG_SZ, pszValue, lstrlen(pszValue)+1)
#define SETMULTISZVALUE(hk, pszName, pszValue) \
RegSetValueEx(hk, pszName, 0, REG_MULTI_SZ, pszValue, \ CbMultiSz(pszValue)+sizeof(CHAR))
#define FREEHKEY(hk) \
if(hk != INVALID_HANDLE_VALUE) \ RegCloseKey(hk);
static CHAR szExport[] = L"Export";
static CHAR szNull[] = L"(null)";
static CHAR szNullDisplayName[] = L"No Display Name!";
#define GLOBALFREE(x) { if((x) != NULL) {GlobalFree((void *)(x)); (x) = NULL;} }
//--HrMAPICreateSizedAddressList------------------------------------------------
// Create a sized address list.
// -----------------------------------------------------------------------------
HRESULT HrMAPICreateSizedAddressList( ULONG cEntries, // in - count of entries in address list
LPADRLIST * lppAdrList) // out- pointer to address list pointer
{ HRESULT hr = NOERROR; SCODE sc = 0; ULONG cBytes = 0;
*lppAdrList = NULL;
cBytes = CbNewADRLIST(cEntries);
sc = (*pMAPIAllocateBuffer)(cBytes, (void **)lppAdrList);
if(FAILED(sc)) { hr = HR_LOG(E_OUTOFMEMORY); goto cleanup; }
// Initialize ADRLIST structure
ZeroMemory(*lppAdrList, cBytes);
(*lppAdrList)->cEntries = cEntries;
cleanup:
return hr; }
//--HrMAPISetAddressList--------------------------------------------------------
// Set an address list.
// -----------------------------------------------------------------------------
HRESULT HrMAPISetAddressList( ULONG iEntry, // in - index of address list entry
ULONG cProps, // in - count of values in address list
// entry
LPSPropValue lpPropValues, // in - pointer to address list entry
LPADRLIST lpAdrList) // i/o - pointer to address list pointer
{ HRESULT hr = NOERROR; SCODE sc = 0; LPSPropValue lpNewPropValues = NULL; // ULONG cBytes = 0;
if(iEntry >= lpAdrList->cEntries) { hr = HR_LOG(E_FAIL); goto cleanup; }
sc = (*pScDupPropset)( cProps, lpPropValues, (*pMAPIAllocateBuffer), &lpNewPropValues);
if(FAILED(sc)) { hr = HR_LOG(E_FAIL); goto cleanup; }
if(lpAdrList->aEntries[iEntry].rgPropVals != NULL) { MAPIFREEBUFFER(lpAdrList->aEntries[iEntry].rgPropVals); }
lpAdrList->aEntries[iEntry].cValues = cProps; lpAdrList->aEntries[iEntry].rgPropVals = lpNewPropValues;
cleanup:
return hr; }
HRESULT HrGWResolveAddressW( LPABCONT lpGalABCont, // in - pointer to GAL container
LPCWSTR lpszAddress, // in - pointer to proxy address
BOOL * lpfMapiRecip, // out- MAPI recipient
ULONG * lpcbEntryID, // out- count of bytes in entry ID
LPENTRYID * lppEntryID) // out- pointer to entry ID
{ HRESULT hr = NOERROR; HRESULT hrT = 0; SCODE sc = 0; LPADRLIST lpAdrList = NULL; LPFlagList lpFlagList = NULL; SPropValue prop[2] = {0}; ULONG cbEntryID = 0; LPENTRYID lpEntryID = NULL;
static const SizedSPropTagArray(2, rgPropTags) = { 2, { PR_ENTRYID, PR_SEND_RICH_INFO } };
*lpfMapiRecip = FALSE; *lpcbEntryID = 0; *lppEntryID = NULL;
sc = (*pMAPIAllocateBuffer)( CbNewFlagList(1), (LPVOID*)&lpFlagList);
if(FAILED(sc)) { hr = HR_LOG(E_OUTOFMEMORY); goto cleanup; }
lpFlagList->cFlags = 1; lpFlagList->ulFlag[0] = MAPI_UNRESOLVED;
hr = HrMAPICreateSizedAddressList(1, &lpAdrList);
if(FAILED(hr)) { hr = HR_LOG(E_FAIL); goto cleanup; }
prop[0].ulPropTag = PR_DISPLAY_NAME_W; prop[0].Value.lpszW = (LPWSTR)lpszAddress; prop[1].ulPropTag = PR_RECIPIENT_TYPE; prop[1].Value.ul = MAPI_TO;
hr = HrMAPISetAddressList( 0, 2, prop, lpAdrList);
if(FAILED(hr)) { hr = HR_LOG(E_FAIL); goto cleanup; }
hrT = lpGalABCont->ResolveNames( (LPSPropTagArray)&rgPropTags, EMS_AB_ADDRESS_LOOKUP, lpAdrList, lpFlagList);
if(lpFlagList->ulFlag[0] != MAPI_RESOLVED) { if(lpFlagList->ulFlag[0] == MAPI_AMBIGUOUS) { hrT = MAPI_E_AMBIGUOUS_RECIP; } else { hrT = MAPI_E_NOT_FOUND; } }
if(FAILED(hrT)) { if(hrT == MAPI_E_NOT_FOUND) { hr = HR_LOG(EDK_E_NOT_FOUND); } else { hr = HR_LOG(E_FAIL); };
goto cleanup; }
cbEntryID = lpAdrList->aEntries[0].rgPropVals[0].Value.bin.cb; lpEntryID = (LPENTRYID)lpAdrList->aEntries[0].rgPropVals[0].Value.bin.lpb;
sc = (*pMAPIAllocateBuffer)( cbEntryID, (LPVOID*)lppEntryID);
if(FAILED(sc)) { hr = HR_LOG(E_OUTOFMEMORY); goto cleanup; }
CopyMemory(*lppEntryID, lpEntryID, cbEntryID); *lpcbEntryID = cbEntryID; *lpfMapiRecip = lpAdrList->aEntries[0].rgPropVals[1].Value.b;
cleanup:
MAPIFREEBUFFER(lpFlagList);
FREEPADRLIST(lpAdrList);
return hr; }
//--HrFindExchangeGlobalAddressList-------------------------------------------------
// Returns the entry ID of the global address list container in the address
// book.
// -----------------------------------------------------------------------------
// CAVEAT: If this function is successful, you must free the buffer returned in lppeid.
HRESULT HrFindExchangeGlobalAddressList( LPADRBOOK lpAdrBook, // in - address book pointer
ULONG * lpcbeid, // out- pointer to count of bytes in entry ID
LPENTRYID * lppeid) // out- pointer to entry ID pointer
{ HRESULT hr = NOERROR; ULONG ulObjType = 0; // ULONG i = 0;
LPMAPIPROP lpRootContainer = NULL; LPMAPIPROP lpContainer = NULL; LPMAPITABLE lpContainerTable = NULL; LPSRowSet lpRows = NULL; ULONG cbContainerEntryId = 0; LPENTRYID lpContainerEntryId = NULL; LPSPropValue lpCurrProp = NULL; SRestriction SRestrictAnd[2] = {0}; SRestriction SRestrictGAL = {0}; SPropValue SPropID = {0}; SPropValue SPropProvider = {0}; BYTE muid[] = MUIDEMSAB;
SizedSPropTagArray(1, rgPropTags) = { 1, { PR_ENTRYID, } };
*lpcbeid = 0; *lppeid = NULL;
// Open the root container of the address book
hr = lpAdrBook->OpenEntry( 0, NULL, NULL, MAPI_DEFERRED_ERRORS, &ulObjType, (LPUNKNOWN FAR *)&lpRootContainer);
if(FAILED(hr)) { goto cleanup; }
if(ulObjType != MAPI_ABCONT) { hr = E_FAIL; goto cleanup; }
// Get the hierarchy table of the root container
hr = ((LPABCONT)lpRootContainer)->GetHierarchyTable( MAPI_DEFERRED_ERRORS|CONVENIENT_DEPTH, &lpContainerTable);
if(FAILED(hr)) { goto cleanup; }
// Restrict the table to the global address list (GAL)
// ---------------------------------------------------
// Initialize provider restriction to only Exchange providers
SRestrictAnd[0].rt = RES_PROPERTY; SRestrictAnd[0].res.resProperty.relop = RELOP_EQ; SRestrictAnd[0].res.resProperty.ulPropTag = PR_AB_PROVIDER_ID; SPropProvider.ulPropTag = PR_AB_PROVIDER_ID;
SPropProvider.Value.bin.cb = 16; SPropProvider.Value.bin.lpb = (LPBYTE)muid; SRestrictAnd[0].res.resProperty.lpProp = &SPropProvider;
// Initialize container ID restriction to only GAL container
SRestrictAnd[1].rt = RES_PROPERTY; SRestrictAnd[1].res.resProperty.relop = RELOP_EQ; SRestrictAnd[1].res.resProperty.ulPropTag = PR_EMS_AB_CONTAINERID; SPropID.ulPropTag = PR_EMS_AB_CONTAINERID; SPropID.Value.l = 0; SRestrictAnd[1].res.resProperty.lpProp = &SPropID;
// Initialize AND restriction
SRestrictGAL.rt = RES_AND; SRestrictGAL.res.resAnd.cRes = 2; SRestrictGAL.res.resAnd.lpRes = &SRestrictAnd[0];
// Restrict the table to the GAL - only a single row should remain
// Get the row corresponding to the GAL
//
// Query all the rows
//
hr = (*pHrQueryAllRows)( lpContainerTable, (LPSPropTagArray)&rgPropTags, &SRestrictGAL, NULL, 0, &lpRows);
if(FAILED(hr) || (lpRows == NULL) || (lpRows->cRows != 1)) { hr = E_FAIL; goto cleanup; }
// Get the entry ID for the GAL
lpCurrProp = &(lpRows->aRow[0].lpProps[0]);
if(lpCurrProp->ulPropTag == PR_ENTRYID) { cbContainerEntryId = lpCurrProp->Value.bin.cb; lpContainerEntryId = (LPENTRYID)lpCurrProp->Value.bin.lpb; } else { hr = EDK_E_NOT_FOUND; goto cleanup; }
hr = (*pMAPIAllocateBuffer)(cbContainerEntryId, (LPVOID *)lppeid);
if(FAILED(hr)) { *lpcbeid = 0; *lppeid = NULL; } else { CopyMemory( *lppeid, lpContainerEntryId, cbContainerEntryId);
*lpcbeid = cbContainerEntryId; }
cleanup:
if (lpRootContainer) lpRootContainer->Release(); if (lpContainerTable) lpContainerTable->Release(); if (lpContainer) lpContainer->Release();
(*pFreeProws)(lpRows); if(FAILED(hr)) { (*pMAPIFreeBuffer)(*lppeid);
*lpcbeid = 0; *lppeid = NULL; } return hr; }
//--HrSearchGAL----------------------------------------------------------------
// Look for the entry ID by searching for the DN in the global address list.
//
// RETURNS: hr == NOERROR Found
// hr == EDK_E_NOT_FOUND DN Not Found
// hr == (anything else) Other Error
// -----------------------------------------------------------------------------
static HRESULT HrSearchGAL( LPADRBOOK lpAdrBook, // in - address book (directory) to look in
LPWSTR lpszDN, // in - object distinguished name
ULONG * lpcbEntryID, // out- count of bytes in entry ID
LPENTRYID * lppEntryID) // out- pointer to entry ID
{ HRESULT hr = NOERROR; LPWSTR lpszAddress = NULL; ULONG cbGALEntryID = 0; LPENTRYID lpGALEntryID = NULL; ULONG ulGALObjectType = 0; LPABCONT lpGAL = NULL; BOOL fMapiRecip = FALSE;
// Initially zero out the return variables.
*lpcbEntryID = 0; *lppEntryID = NULL;
// Create an address string consisting of "EX:" followed by the DN.
hr = (*pMAPIAllocateBuffer)( wcslen(EXCHANGE_ADDRTYPE L":") + wcslen(lpszDN) + 1, (void **)&lpszAddress); if (FAILED(hr)) goto cleanup;
wcscpy(lpszAddress, EXCHANGE_ADDRTYPE L":"); wcscat(lpszAddress, lpszDN);
// Open the global address list.
hr = HrFindExchangeGlobalAddressList( lpAdrBook, &cbGALEntryID, &lpGALEntryID); if (FAILED(hr)) goto cleanup; hr = lpAdrBook->OpenEntry( cbGALEntryID, lpGALEntryID, NULL, MAPI_BEST_ACCESS | MAPI_DEFERRED_ERRORS, &ulGALObjectType, (LPUNKNOWN *) &lpGAL); if (FAILED(hr)) goto cleanup;
// Make sure it's the right object type.
if (ulGALObjectType != MAPI_ABCONT) { //hr = HR_LOG(E_FAIL);
goto cleanup; }
// Resolve the address (returns EDK_E_NOT_FOUND if not found).
hr = HrGWResolveAddressW( lpGAL, lpszAddress, &fMapiRecip, lpcbEntryID, lppEntryID); if (FAILED(hr)) goto cleanup;
cleanup: ULRELEASE(lpGAL); MAPIFREEBUFFER(lpGALEntryID); MAPIFREEBUFFER(lpszAddress); return hr; }
//$--HrCreateDirEntryIdEx-------------------------------------------------------
// Create a directory entry ID given the address of the object
// in the directory.
// -----------------------------------------------------------------------------
HRESULT HrCreateDirEntryIdEx( // RETURNS: HRESULT
IN LPADRBOOK lpAdrBook, // address book (directory) to look in
IN LPWSTR lpszAddress, // object distinguished name
OUT ULONG * lpcbEntryID, // count of bytes in entry ID
OUT LPENTRYID * lppEntryID) // pointer to entry ID
{ HRESULT hr = NOERROR; // ULONG cbHierarchyEntryID = 0;
// LPENTRYID lpHierarchyEntryID = NULL;
ULONG ulEntryIDType = 0;
// Initially zero out the return variables.
*lpcbEntryID = 0; *lppEntryID = NULL;
// Look for the DN in the global address list.
hr = HrSearchGAL( lpAdrBook, lpszAddress, lpcbEntryID, lppEntryID); if (FAILED(hr)) goto cleanup;
// If the type was DT_AGENT or DT_ORGANIZATION, then we have to
// do a further lookup in the hierarchy table to determine the
// DN's real type.
ulEntryIDType = ((LPDIR_ENTRYID) *lppEntryID)->ulType;
cleanup: return hr; }
//$--CbMultiSz------------------------------------------------------------------
// Count of bytes in a REG_MULTI_SZ string (not including terminating NULL).
// -----------------------------------------------------------------------------
static DWORD CbMultiSz( // RETURNS: count of bytes
IN LPWSTR lpszRegMultiSz) // REG_MULTI_SZ string
{ // HRESULT hr = NOERROR;
DWORD cch = 0; DWORD cb = 0; LPWSTR lpsz = NULL;
if(lpszRegMultiSz == NULL) { goto cleanup; }
lpsz = lpszRegMultiSz;
while(*lpsz) { cch = lstrlenW(lpsz);
cch++;
cb += cch * sizeof(WCHAR);
lpsz += cch; }
cleanup:
return(cb); }
//$--HrGetRegistryValue---------------------------------------------------------
// Get a registry value - allocating memory to hold it.
// -----------------------------------------------------------------------------
static HRESULT HrGetRegistryValue( // RETURNS: return code
IN HKEY hk, // the key.
IN LPWSTR lpszValue, // value name in key.
OUT DWORD * lpType, // where to put type info.
OUT DWORD * lpcb, // where to put byte count info.
OUT LPVOID * lppData) // where to put the data.
{ HRESULT hr = E_FAIL; LONG lRet = 0;
*lppData = NULL;
//
// Get its size
//
lRet = RegQueryValueEx( hk, lpszValue, NULL, lpType, NULL, lpcb);
if(lRet != ERROR_SUCCESS) { hr = HR_LOG(HRESULT_FROM_WIN32(lRet)); goto cleanup; }
//
// Allocate memory for it
//
*lppData = (LPVOID)GlobalAlloc(GMEM_FIXED, *lpcb);
if(*lppData == NULL) { hr = HR_LOG(HRESULT_FROM_WIN32(GetLastError())); goto cleanup; }
//
// Get the current value
//
lRet = RegQueryValueEx(hk, lpszValue, NULL, lpType, (UCHAR*)*lppData, lpcb);
if(lRet != ERROR_SUCCESS) { hr = HR_LOG(HRESULT_FROM_WIN32(lRet)); goto cleanup; }
hr = NOERROR;
cleanup:
if(FAILED(hr)) { if(lppData != NULL) { GLOBALFREE(*lppData); } }
return hr; }
//--FCsvGetField---------------------------------------------------------------
// Given a record and a field separator and a field number, this routine
// will extract the field requested.
//------------------------------------------------------------------------------
static BOOL FCsvGetField( // RETURNS: TRUE/FALSE
IN WORD wLen, // maximum length of the field to extract
IN WORD wFieldNum, // field number we want from the record
IN CHAR cFieldSeparator, // character to use as a field separator
IN CHAR *lpszRecord, // record to extract the field from
OUT CHAR *lpszField) // field we have extracted
{ // HRESULT hr = NOERROR;
BOOL fRet = FALSE; // CHAR *lpszBeginField = lpszField;
while((wFieldNum > 0) && (*lpszRecord != 0)) { // If we found a field separator, increment current field
if(*lpszRecord == cFieldSeparator) { wFieldNum--; } // If we are at the desired field, copy the current character into it
else if(wFieldNum == 1 && wLen > 1) { *lpszField = *lpszRecord; lpszField++; wLen--; }
lpszRecord++; }
*lpszField = 0;
// If the requested field # existed, return True,
// otherwise we ran out of fields - return False
if(wFieldNum <= 1) { fRet = TRUE; } else { fRet = FALSE; }
return(fRet); }
//$--FCsvGetRecord--------------------------------------------------------------
// Given a buffer, the buffer's length and a file handle, this
// function fills the buffer with a single line read from the file.
// The NL & CR are NOT put into the buffer. No unprintable characters are
// placed in the buffer
// -----------------------------------------------------------------------------
BOOL FCsvGetRecord( // RETURNS: TRUE/FALSE
IN WORD wBufferLen, // length of the record buffer
IN HANDLE hFile, // file handle to read from
OUT CHAR *lpszBuffer) // record we have retrieved
{ // HRESULT hr = NOERROR;
DWORD dwBytesRead = 0; BOOL fReadData = FALSE;
while((ReadFile(hFile, (LPVOID)lpszBuffer, 1, &dwBytesRead, NULL) == TRUE) && (wBufferLen > 1) && (*lpszBuffer != '\n') && (dwBytesRead > 0)) { fReadData = TRUE;
// Only store character in buffer if it is printable!
if((isprint(*lpszBuffer)) || (*lpszBuffer == EXCHINST_DELIM)) { lpszBuffer++; wBufferLen--; } }
// If a given record is too long it is a problem!!!
if(wBufferLen <= 0) { fReadData = FALSE; }
*lpszBuffer = 0;
return(fReadData); }
//$--HrEDKExportObject----------------------------------------------------------
// This function will export an object from an Exchange server.
// -----------------------------------------------------------------------------
static HRESULT HrEDKExportObject( // RETURNS: return code
IN LPWSTR lpszServer, // server name
IN LPWSTR lpszBasePoint, // base point
IN DWORD dwControlFlags, // control flags
IN LPWSTR *rgpszClasses, // classes
IN LPWSTR lpszObjectAttributes, // list of attributes to export
OUT LPWSTR lpszTempName) // temporary file name
{ HRESULT hr = E_FAIL; ULONG cErrors = 0; HANDLE hTempFile = INVALID_HANDLE_VALUE; CHAR szTempPath[MAX_PATH+1] = {0}; DWORD dwNumberOfBytesWritten = 0; BEXPORT_PARMS BExportParms = {0}; BOOL fRet = FALSE;
// Get temporary directory path
if(!GetTempPath(MAX_PATH, szTempPath)) { hr = HR_LOG(HRESULT_FROM_WIN32(GetLastError())); goto cleanup; }
// Get temporary file name
if(!GetTempFileName(szTempPath, FILE_PREFIX, 0, lpszTempName)) { hr = HR_LOG(HRESULT_FROM_WIN32(GetLastError())); goto cleanup; }
// Create the temporary file
hTempFile = CreateFile(lpszTempName, GENERIC_WRITE, 0, (LPSECURITY_ATTRIBUTES)NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, (HANDLE)NULL);
// Check to see if temporary file was created...
if(hTempFile == INVALID_HANDLE_VALUE) { hr = HR_LOG(HRESULT_FROM_WIN32(GetLastError())); goto cleanup; }
// Write data to the temporary file & close it
fRet = WriteFile( hTempFile, lpszObjectAttributes, lstrlen(lpszObjectAttributes)*sizeof(CHAR), &dwNumberOfBytesWritten, NULL);
if(fRet == FALSE) { hr = HR_LOG(HRESULT_FROM_WIN32(GetLastError())); goto cleanup; }
fRet = WriteFile( hTempFile, NEW_LINE, lstrlen(NEW_LINE)*sizeof(CHAR), &dwNumberOfBytesWritten, NULL);
if(fRet == FALSE) { hr = HR_LOG(HRESULT_FROM_WIN32(GetLastError())); goto cleanup; }
CLOSEHANDLE(hTempFile);
//
// Batch Export
//
BExportParms.dwDAPISignature = DAPI_SIGNATURE; BExportParms.dwFlags = dwControlFlags | DAPI_MODIFY_REPLACE_PROPERTIES | DAPI_SUPPRESS_PROGRESS | DAPI_SUPPRESS_COMPLETION | DAPI_SUPPRESS_ARCHIVES | DAPI_IMPORT_NO_ERR_FILE; BExportParms.pszExportFile = lpszTempName; BExportParms.pszBasePoint = lpszBasePoint; BExportParms.pszDSAName = lpszServer; BExportParms.rgpszClasses = rgpszClasses; BExportParms.chColSep = EXCHINST_DELIM; BExportParms.chQuote = EXCHINST_QUOTE; BExportParms.chMVSep = EXCHINST_MV_SEP;
cErrors = (*pBatchExport)(&BExportParms);
if(cErrors == 0) { hr = NOERROR; } else { hr = HR_LOG(E_FAIL); } cleanup:
CLOSEHANDLE(hTempFile);
return hr; }
//$--HrEDKEnumDNs---------------------------------------------------------------
// Enumerates the distinguished name(s).
// -----------------------------------------------------------------------------
static HRESULT HrEDKEnumDNs( // RETURNS: return code
IN LPWSTR lpszRootDN, // distinguished name of DIT root
IN LPWSTR lpszServer, // server name
IN DWORD dwControlFlags, // control flags
IN LPWSTR *rgpszClasses, // classes
OUT LPWSTR *lppszDNs) // distinguished names
{ HRESULT hr = NOERROR; HANDLE hTempFile = INVALID_HANDLE_VALUE; CHAR szObjectAttributes[MAX_CSV_LINE_SIZ] = {0}; // CHAR szAttributeValues[MAX_CSV_LINE_SIZ] = {0};
// CHAR szCurRecord[MAX_CSV_LINE_SIZ] = {0};
CHAR szCurLine[MAX_CSV_LINE_SIZ] = {0}; CHAR szCurField[MAX_PATH+1] = {0}; CHAR szTempName[MAX_PATH+1] = {0}; WORD wAttribField = MAX_WORD; WORD wCurrField = 0; LPWSTR lpsz = NULL; ULONG ulCurrOffset = 0;
*lppszDNs = NULL;
BEGIN_CSV_LINE (szObjectAttributes, OBJ_CLASS); APPEND_CSV_LINE (szObjectAttributes, OBJ_DIST_NAME);
hr = HrEDKExportObject( lpszServer, lpszRootDN, dwControlFlags, rgpszClasses, szObjectAttributes, szTempName);
if(SUCCEEDED(hr)) { // Open the temporary file
hTempFile = CreateFile( szTempName, GENERIC_READ, 0, (LPSECURITY_ATTRIBUTES)NULL, OPEN_EXISTING, FILE_FLAG_DELETE_ON_CLOSE, (HANDLE)NULL);
if(hTempFile == INVALID_HANDLE_VALUE) { hr = HR_LOG(E_FAIL); goto cleanup; }
//
// The first line contains the list of fields - find which field has
// the attribute we are looking for.
//
FCsvGetRecord(MAX_CSV_LINE_SIZ, hTempFile, szCurLine);
for( wCurrField = 1;
FCsvGetField( MAX_PATH, wCurrField, EXCHINST_DELIM, szCurLine, szCurField);
wCurrField++) { if(wcscmp(szCurField, OBJ_DIST_NAME) == 0) { wAttribField = wCurrField; break; } }
// Was the field exported & found above?
if(wAttribField == MAX_WORD) { hr = HR_LOG(E_FAIL); goto cleanup; }
ulCurrOffset = 0;
while(FCsvGetRecord (MAX_CSV_LINE_SIZ, hTempFile, szCurLine)) { FCsvGetField( MAX_PATH, wAttribField, EXCHINST_DELIM, szCurLine, szCurField);
if( *szCurField) { if(lpsz == NULL) { lpsz = (LPWSTR)GlobalAlloc( GMEM_FIXED, cbStrLen(szCurField) + sizeof(CHAR)); } else { lpsz = (LPWSTR)GlobalReAlloc( lpsz, GlobalSize(lpsz) + cbStrLen(szCurField), GMEM_MOVEABLE); }
if(lpsz == NULL) { hr = HR_LOG(HRESULT_FROM_WIN32(GetLastError())); goto cleanup; }
lstrcpy(&lpsz[ulCurrOffset], szCurField);
ulCurrOffset += cbStrLen(szCurField);
lpsz[ulCurrOffset] = 0; } } } *lppszDNs = lpsz;
cleanup:
CLOSEHANDLE(hTempFile);
if(FAILED(hr)) { GLOBALFREE(*lppszDNs); }
return hr; }
//$--HrEnumOrganizations-----------------------------------------------------
// Enumerates the organization name(s).
// -----------------------------------------------------------------------------
HRESULT HrEnumOrganizations( // RETURNS: return code
IN LPWSTR lpszRootDN, // distinguished name of DIT root
IN LPWSTR lpszServer, // server name
OUT LPWSTR *lppszOrganizations) // organizations
{ HRESULT hr = NOERROR; LPWSTR rgpszClasses[2] = {0};
rgpszClasses[0] = ORGANIZATION; rgpszClasses[1] = NULL;
hr = HrEDKEnumDNs( lpszRootDN, lpszServer, DAPI_EXPORT_SUBTREE, rgpszClasses, lppszOrganizations);
return hr; }
//$--HrEnumSites-------------------------------------------------------------
// Enumerates the site name(s).
// -----------------------------------------------------------------------------
HRESULT HrEnumSites( // RETURNS: return code
IN LPWSTR lpszServer, // server name
IN LPWSTR lpszOrganizationDN, // distinguished name of organization
OUT LPWSTR *lppszSites) // sites
{ HRESULT hr = NOERROR; LPWSTR rgpszClasses[2] = {0};
rgpszClasses[0] = ORGANIZATIONAL_UNIT; rgpszClasses[1] = NULL;
hr = HrEDKEnumDNs( lpszOrganizationDN, lpszServer, 0, rgpszClasses, lppszSites);
return hr; }
//$--HrEnumContainers--------------------------------------------------------
// Enumerates the container name(s).
// -----------------------------------------------------------------------------
HRESULT HrEnumContainers( // RETURNS: return code
IN LPWSTR lpszServer, // server name
IN LPWSTR lpszSiteDN, // distinguished name of site
IN BOOL fSubtree, // sub-tree?
OUT LPWSTR *lppszContainers) // containers
{ HRESULT hr = NOERROR; LPWSTR rgpszClasses[2] = {0}; DWORD dwControlFlags = 0;
rgpszClasses[0] = CONTAINER; rgpszClasses[1] = NULL;
if(fSubtree == TRUE) { dwControlFlags = DAPI_EXPORT_SUBTREE; }
hr = HrEDKEnumDNs( lpszSiteDN, lpszServer, dwControlFlags, rgpszClasses, lppszContainers);
return hr; }
/**/
|