You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
2229 lines
80 KiB
2229 lines
80 KiB
/*
|
|
* LDIF.C
|
|
*
|
|
* Migrate LDIF <-> WAB
|
|
*
|
|
* Copyright 1997 Microsoft Corporation. All Rights Reserved.
|
|
*
|
|
* To Do:
|
|
* ObjectClass recognition
|
|
* Attribute mapping
|
|
* Groups
|
|
* Base64
|
|
* URLs
|
|
* Reject Change List LDIF
|
|
*
|
|
*/
|
|
|
|
#include "_comctl.h"
|
|
#include <windows.h>
|
|
#include <commctrl.h>
|
|
#include <mapix.h>
|
|
#include <wab.h>
|
|
#include <wabguid.h>
|
|
#include <wabdbg.h>
|
|
#include <wabmig.h>
|
|
#include <emsabtag.h>
|
|
#include "wabimp.h"
|
|
#include "..\..\wab32res\resrc2.h"
|
|
#include "dbgutil.h"
|
|
#include "initguid.h"
|
|
#include <shlwapi.h>
|
|
|
|
#define CR_CHAR 0x0d
|
|
#define LF_CHAR 0x0a
|
|
#define CCH_READ_BUFFER 1024
|
|
#define NUM_ITEM_SLOTS 32
|
|
|
|
BOOL decodeBase64(char * bufcoded, char * pbuffdecoded, DWORD * pcbDecoded);
|
|
|
|
// for conferencing stuff
|
|
#define CHANGE_PROP_TYPE(ulPropTag, ulPropType) \
|
|
(((ULONG)0xFFFF0000 & ulPropTag) | ulPropType)
|
|
|
|
HRESULT HrLoadPrivateWABProps(LPADRBOOK );
|
|
/*
|
|
- The following IDs and tags are for the conferencing named properties
|
|
-
|
|
- The GUID for these props is PS_Conferencing
|
|
*/
|
|
|
|
DEFINE_OLEGUID(PS_Conferencing, 0x00062004, 0, 0);
|
|
|
|
enum _ConferencingTags
|
|
{
|
|
prWABConfServers = 0,
|
|
prWABConfMax
|
|
};
|
|
|
|
#define CONF_SERVERS 0x8056
|
|
|
|
#define OLK_NAMEDPROPS_START CONF_SERVERS
|
|
|
|
ULONG PR_SERVERS;
|
|
|
|
SizedSPropTagArray(prWABConfMax, ptaUIDetlsPropsConferencing);
|
|
// end conferencing duplication
|
|
|
|
// Index into LDIF_ATTR_TABLE
|
|
//
|
|
// IMPORTANT: This is an intentionally ordered list!
|
|
// Within synonyms, the earlier attributes listed take precedence over those that follow. For
|
|
// example, if the record contains both "co" and "o" attributes, the value in the "co" attribute
|
|
// will be used for PR_COMPANY_NAME.
|
|
typedef enum _LDIF_ATTRIBUTES {
|
|
// PR_OBJECT_TYPE
|
|
ela_objectclass = 0, // object class (required)
|
|
|
|
// PR_COUNTRY
|
|
ela_c, // country
|
|
ela_countryname,
|
|
|
|
// PR_DISPLAY_NAME
|
|
ela_display_name, // (Microsoft servers use this)
|
|
ela_cn, // common name (display name)
|
|
ela_commonName, // (display name)
|
|
|
|
// PR_COMPANY_NAME
|
|
ela_co, // company
|
|
ela_organizationName, // (company)
|
|
ela_o, // organization (company)
|
|
|
|
// PR_MIDDLE_NAME
|
|
ela_initials,
|
|
|
|
// PR_SURNAME
|
|
ela_sn, // surname
|
|
ela_surname,
|
|
|
|
// PR_GIVEN_NAME
|
|
ela_givenname,
|
|
ela_uid, // (given name) ?
|
|
|
|
// PR_DEPARTMENT_NAME
|
|
ela_department,
|
|
ela_ou, // organizational unit (department)
|
|
ela_organizationalUnitName, // (department)
|
|
|
|
// PR_COMMENT
|
|
ela_comment,
|
|
ela_description, // description
|
|
ela_info, // info
|
|
|
|
// PR_LOCALITY
|
|
ela_l, // locality (city)
|
|
ela_locality, // locality (city)
|
|
|
|
// no mapping
|
|
ela_dn, // distinguished name
|
|
|
|
// PR_NICKNAME
|
|
ela_xmozillanickname, // Netscape nickname
|
|
|
|
// no mapping
|
|
ela_conferenceInformation, // conference server
|
|
ela_xmozillaconference, // Netscape conference server
|
|
|
|
// PR_HOME_FAX_NUMBER
|
|
ela_facsimiletelephonenumber, // home fax number
|
|
|
|
// PR_BUSINESS_FAX_NUMBER
|
|
ela_OfficeFax,
|
|
|
|
// PR_BUSINESS_TELEPHONE_NUMBER
|
|
ela_telephonenumber,
|
|
|
|
// PR_HOME_TELEPHONE_NUMBER
|
|
ela_homephonenumber,
|
|
|
|
// PR_MOBILE_TELEPHONE_NUMBER
|
|
ela_mobile, // cellular phone number
|
|
|
|
// PR_PAGER_TELEPHONE_NUMBER
|
|
ela_OfficePager,
|
|
ela_pager,
|
|
|
|
// PR_OFFICE_LOCATION
|
|
ela_physicalDeliveryOfficeName, // office location
|
|
|
|
// PR_HOME_ADDRESS_STREET
|
|
ela_homePostalAddress,
|
|
|
|
// PR_STREET_ADDRESS
|
|
ela_streetAddress, // business street address
|
|
ela_street, // business street address
|
|
ela_postalAddress, // business street address
|
|
|
|
// PR_STATE_OR_PROVINCE
|
|
ela_st, // business address state
|
|
|
|
// PR_POST_OFFICE_BOX
|
|
ela_postOfficeBox, // business PO Box
|
|
|
|
// PR_POSTAL_CODE
|
|
ela_postalcode, // business address zip code
|
|
|
|
// PR_PERSONAL_HOME_PAGE
|
|
ela_homepage, // personal home page
|
|
|
|
// PR_BUSINESS_HOME_PAGE
|
|
ela_URL, // business home page
|
|
|
|
// PR_EMAIL_ADDRESS
|
|
ela_mail, // email address
|
|
|
|
// PR_CONTACT_EMAIL_ADDRESSES
|
|
ela_otherMailbox, // secondary email addresses
|
|
|
|
// PR_TITLE
|
|
ela_title, // title
|
|
|
|
// no mapping
|
|
ela_member, // DL member
|
|
|
|
// no mapping
|
|
ela_userCertificate, // certificate
|
|
|
|
// no mapping
|
|
ela_labeledURI, // labelled URI URL
|
|
|
|
// no mapping
|
|
ela_xmozillauseconferenceserver, // Netscape conference info
|
|
|
|
// no mapping
|
|
ela_xmozillausehtmlmail, // Netscape HTML mail flag
|
|
|
|
ela_Max,
|
|
} LDIF_ATTRIBUTES, *LPLDIF_ATTRIBUTES;
|
|
|
|
typedef struct _LDIF_ATTR_TABLE {
|
|
const BYTE * lpName; // LDIF attribute name
|
|
ULONG index; // attribute index within LDIF record
|
|
ULONG ulPropTag; // prop tag mapping
|
|
ULONG ulPropIndex; // index in prop array
|
|
} LDIF_ATTR_TABLE, *LPLDIF_ATTR_TABLE;
|
|
|
|
|
|
typedef enum _LDIF_PROPERTIES {
|
|
elp_OBJECT_TYPE,
|
|
elp_DISPLAY_NAME,
|
|
elp_EMAIL_ADDRESS,
|
|
elp_SURNAME,
|
|
elp_GIVEN_NAME,
|
|
elp_TITLE,
|
|
elp_COMPANY_NAME,
|
|
elp_OFFICE_LOCATION,
|
|
elp_HOME_ADDRESS_STREET,
|
|
elp_STREET_ADDRESS,
|
|
elp_STATE_OR_PROVINCE,
|
|
elp_POST_OFFICE_BOX,
|
|
elp_POSTAL_CODE,
|
|
elp_LOCALITY,
|
|
elp_COUNTRY,
|
|
elp_MIDDLE_NAME,
|
|
elp_DEPARTMENT_NAME,
|
|
elp_COMMENT,
|
|
elp_NICKNAME,
|
|
elp_HOME_FAX_NUMBER,
|
|
elp_BUSINESS_FAX_NUMBER,
|
|
elp_BUSINESS_TELEPHONE_NUMBER,
|
|
elp_HOME_TELEPHONE_NUMBER,
|
|
elp_MOBILE_TELEPHONE_NUMBER,
|
|
elp_PAGER_TELEPHONE_NUMBER,
|
|
elp_PERSONAL_HOME_PAGE,
|
|
elp_BUSINESS_HOME_PAGE,
|
|
elp_CONTACT_EMAIL_ADDRESSES,
|
|
elp_CONFERENCE_SERVERS,
|
|
elp_Max
|
|
} LDIF_ATTRIBUTES, *LPLDIF_ATTRIBUTES;
|
|
|
|
|
|
// Must have
|
|
// PR_DISPLAY_NAME
|
|
|
|
#define NUM_MUST_HAVE_PROPS 1
|
|
|
|
typedef enum _LDIF_DATA_TYPE {
|
|
LDIF_ASCII,
|
|
LDIF_BASE64,
|
|
LDIF_URL
|
|
} LDIF_DATA_TYPE, *LPLDIF_DATA_TYPE;
|
|
|
|
typedef struct _LDIF_RECORD_ATTRIBUTE {
|
|
LPBYTE lpName;
|
|
LPBYTE lpData;
|
|
ULONG cbData;
|
|
LDIF_DATA_TYPE Type;
|
|
} LDIF_RECORD_ATTRIBUTE, * LPLDIF_RECORD_ATTRIBUTE;
|
|
|
|
const TCHAR szLDIFFilter[] = "*.ldf;*.ldif";
|
|
const TCHAR szLDIFExt[] = "ldf";
|
|
|
|
|
|
// LDAP attribute names
|
|
const BYTE sz_c[] = "c";
|
|
const BYTE sz_cn[] = "cn";
|
|
const BYTE sz_co[] = "co";
|
|
const BYTE sz_comment[] = "comment";
|
|
const BYTE sz_commonName[] = "commonName";
|
|
const BYTE sz_conferenceInformation[] = "conferenceInformation";
|
|
const BYTE sz_countryname[] = "countryname";
|
|
const BYTE sz_department[] = "department";
|
|
const BYTE sz_description[] = "description";
|
|
const BYTE sz_display_name[] = "display-name";
|
|
const BYTE sz_dn[] = "dn";
|
|
const BYTE sz_facsimiletelephonenumber[] = "facsimiletelephonenumber";
|
|
const BYTE sz_givenname[] = "givenname";
|
|
const BYTE sz_homePostalAddress[] = "homePostalAddress";
|
|
const BYTE sz_homepage[] = "homepage";
|
|
const BYTE sz_info[] = "info";
|
|
const BYTE sz_initials[] = "initials";
|
|
const BYTE sz_l[] = "l";
|
|
const BYTE sz_labeledURI[] = "labeledURI";
|
|
const BYTE sz_locality[] = "locality";
|
|
const BYTE sz_mail[] = "mail";
|
|
const BYTE sz_member[] = "member";
|
|
const BYTE sz_mobile[] = "mobile";
|
|
const BYTE sz_o[] = "o";
|
|
const BYTE sz_objectclass[] = "objectclass";
|
|
const BYTE sz_OfficeFax[] = "OfficeFax";
|
|
const BYTE sz_OfficePager[] = "OfficePager";
|
|
const BYTE sz_organizationName[] = "organizationName";
|
|
const BYTE sz_organizationalUnitName[] = "organizationalUnitName";
|
|
const BYTE sz_otherMailbox[] = "otherMailbox";
|
|
const BYTE sz_ou[] = "ou";
|
|
const BYTE sz_pager[] = "pager";
|
|
const BYTE sz_physicalDeliveryOfficeName[] = "physicalDeliveryOfficeName";
|
|
const BYTE sz_postOfficeBox[] = "postOfficeBox";
|
|
const BYTE sz_postalAddress[] = "postalAddress";
|
|
const BYTE sz_postalcode[] = "postalcode";
|
|
const BYTE sz_sn[] = "sn";
|
|
const BYTE sz_st[] = "st";
|
|
const BYTE sz_streetAddress[] = "streetAddress";
|
|
const BYTE sz_street[] = "street";
|
|
const BYTE sz_surname[] = "surname";
|
|
const BYTE sz_telephonenumber[] = "telephonenumber";
|
|
const BYTE sz_homephonenumber[] = "homephone";
|
|
const BYTE sz_title[] = "title";
|
|
const BYTE sz_uid[] = "uid";
|
|
const BYTE sz_URL[] = "URL";
|
|
const BYTE sz_userCertificate[] = "userCertificate";
|
|
const BYTE sz_xmozillaconference[] = "xmozillaconference";
|
|
const BYTE sz_xmozillanickname[] = "xmozillanickname";
|
|
const BYTE sz_xmozillauseconferenceserver[] = "xmozillauseconferenceserver";
|
|
const BYTE sz_xmozillausehtmlmail[] = "xmozillausehtmlmail";
|
|
|
|
|
|
// LDAP objectclass values
|
|
const BYTE sz_groupOfNames[] = "groupOfNames";
|
|
const BYTE sz_person[] = "person";
|
|
const BYTE sz_organizationalPerson[] = "organizationalPerson";
|
|
|
|
// since defs aren't shared -- these are also defined in ui_detls.c
|
|
const LPTSTR szCallto = TEXT("callto://");
|
|
const LPTSTR szFwdSlash = "/";
|
|
|
|
BOOL HandleImportError(HWND hwnd, ULONG ids, HRESULT hResult, LPTSTR lpDisplayName,
|
|
LPTSTR lpEmailAddress, LPWAB_IMPORT_OPTIONS lpImportOptions);
|
|
BOOL HandleExportError(HWND hwnd, ULONG ids, HRESULT hResult, LPTSTR lpDisplayName,
|
|
LPTSTR lpEmailAddress, LPWAB_EXPORT_OPTIONS lpExportOptions);
|
|
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : FreeLDIFRecord
|
|
|
|
Purpose : Frees an LDIF record structure
|
|
|
|
Parameters: lpLDIFRecord -> record to clean up
|
|
ulAttributes = number of attributes in lpLDIFRecord
|
|
|
|
Returns : none
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
void FreeLDIFRecord(LPLDIF_RECORD_ATTRIBUTE lpLDIFRecord, ULONG ulAttributes) {
|
|
ULONG i;
|
|
|
|
if (lpLDIFRecord) {
|
|
for (i = 0; i < ulAttributes; i++) {
|
|
if (lpLDIFRecord[i].lpName) {
|
|
LocalFree(lpLDIFRecord[i].lpName);
|
|
lpLDIFRecord[i].lpName = NULL;
|
|
}
|
|
if (lpLDIFRecord[i].lpData) {
|
|
LocalFree(lpLDIFRecord[i].lpData);
|
|
lpLDIFRecord[i].lpData = NULL;
|
|
}
|
|
}
|
|
LocalFree(lpLDIFRecord);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : OpenLDIFFile
|
|
|
|
Purpose : Opens a LDIF file for import
|
|
|
|
Parameters: hwnd = main dialog window
|
|
lpFileName = filename to create
|
|
lphFile -> returned file handle
|
|
|
|
Returns : HRESULT
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
HRESULT OpenLDIFFile(HWND hwnd, LPTSTR lpFileName, LPHANDLE lphFile) {
|
|
LPTSTR lpFilter;
|
|
TCHAR szFileName[MAX_PATH + 1] = "";
|
|
OPENFILENAME ofn;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
HRESULT hResult = hrSuccess;
|
|
DWORD ec;
|
|
|
|
|
|
if (INVALID_HANDLE_VALUE == (hFile = CreateFile(lpFileName,
|
|
GENERIC_READ,
|
|
0, // sharing
|
|
NULL,
|
|
CREATE_NEW,
|
|
FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL))) {
|
|
ec = GetLastError();
|
|
DebugTrace("CreateFile(%s) -> %u\n", lpFileName, ec);
|
|
switch (ec) {
|
|
case ERROR_FILE_NOT_FOUND:
|
|
case ERROR_PATH_NOT_FOUND:
|
|
default:
|
|
ShowMessageBoxParam(hwnd, IDE_LDIF_IMPORT_FILE_ERROR, MB_ICONERROR, lpFileName);
|
|
hResult = ResultFromScode(MAPI_E_NOT_FOUND);
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (! hResult) {
|
|
*lphFile = hFile;
|
|
}
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : ReadLDIFLine
|
|
|
|
Purpose : Reads a line from and LDIF file
|
|
|
|
Parameters: hFile = File handle
|
|
lppBuffer -> In/Out start of read buffer (return line data here)
|
|
lpcbBuffer = In/Out size of buffer
|
|
|
|
Returns : number of bytes read from file
|
|
|
|
Comment :
|
|
|
|
***************************************************************************/
|
|
ULONG ReadLDIFLine(HANDLE hFile, LPBYTE * lppBuffer, LPULONG lpcbBuffer) {
|
|
ULONG cbRead = 0;
|
|
ULONG cbReadFile = 0;
|
|
BOOL fDone = FALSE;
|
|
BOOL fColumn1 = TRUE;
|
|
BOOL fComment = FALSE;
|
|
BOOL fComent = FALSE;
|
|
ULONG ulSavePosition = 0;
|
|
LPBYTE lpRead = *lppBuffer; // current read pointer
|
|
LPBYTE lpT;
|
|
|
|
while (! fDone) {
|
|
if (cbRead >= (*lpcbBuffer - 1)) { // leave room for null
|
|
ULONG cbOffset = (ULONG) (lpRead - *lppBuffer);
|
|
|
|
// Buffer is too small. Reallocate!
|
|
*lpcbBuffer += CCH_READ_BUFFER;
|
|
if (! (lpT = LocalReAlloc(*lppBuffer, *lpcbBuffer, LMEM_MOVEABLE | LMEM_ZEROINIT))) {
|
|
DebugTrace("LocalReAlloc(%u) -> %u\n", *lpcbBuffer, GetLastError());
|
|
break;
|
|
}
|
|
*lppBuffer = lpT;
|
|
lpRead = *lppBuffer + cbOffset;
|
|
}
|
|
|
|
if ((! ReadFile(hFile,
|
|
lpRead,
|
|
1, // 1 character at a time
|
|
&cbReadFile,
|
|
NULL)) || cbReadFile == 0) {
|
|
DebugTrace("ReadFile -> EOF\n");
|
|
fDone = TRUE;
|
|
} else {
|
|
cbReadFile++;
|
|
|
|
// Got a character
|
|
// Is it interesting?
|
|
switch (*lpRead) {
|
|
case '#': // Comment line
|
|
if (fColumn1) {
|
|
// This is a comment line. Dump the whole line
|
|
fComment = TRUE;
|
|
} else {
|
|
cbRead++;
|
|
lpRead++;
|
|
}
|
|
fColumn1 = FALSE;
|
|
break;
|
|
|
|
case ' ':
|
|
if (fColumn1 || fComment) {
|
|
// This is a continuation or a comment, eat this space.
|
|
} else {
|
|
cbRead++;
|
|
lpRead++;
|
|
}
|
|
fColumn1 = FALSE;
|
|
break;
|
|
|
|
case '\n': // LDIF SEP character
|
|
if (fColumn1) {
|
|
// This is not a continuation, we've gone too far. Back up!
|
|
if (ulSavePosition) {
|
|
if (0xFFFFFFFF == (SetFilePointer(hFile, ulSavePosition, NULL, FILE_BEGIN))) {
|
|
DebugTrace("CountCSVRows SetFilePointer -> %u\n", GetLastError());
|
|
return(ResultFromScode(MAPI_E_CALL_FAILED));
|
|
}
|
|
}
|
|
fDone = TRUE;
|
|
} else {
|
|
fColumn1 = TRUE;
|
|
fComment = FALSE;
|
|
// Should check if next line starts with continuation character (space)
|
|
// Save the current position in case it isn't.
|
|
if (0xFFFFFFFF == (ulSavePosition = SetFilePointer(hFile, 0, NULL, FILE_CURRENT))) {
|
|
DebugTrace("CountCSVRows SetFilePointer -> %u\n", GetLastError());
|
|
}
|
|
}
|
|
break;
|
|
|
|
case '\r': // Eat the Carriage Return character
|
|
break;
|
|
|
|
default:
|
|
if (! fComment) {
|
|
if (cbRead && fColumn1) {
|
|
// This is not a continuation, we've gone too far. Back up!
|
|
Assert(ulSavePosition);
|
|
if (ulSavePosition) {
|
|
if (0xFFFFFFFF == (SetFilePointer(hFile, ulSavePosition, NULL, FILE_BEGIN))) {
|
|
DebugTrace("CountCSVRows SetFilePointer -> %u\n", GetLastError());
|
|
return(ResultFromScode(MAPI_E_CALL_FAILED));
|
|
}
|
|
}
|
|
fDone = TRUE;
|
|
} else {
|
|
cbRead++;
|
|
lpRead++;
|
|
}
|
|
}
|
|
fColumn1 = FALSE;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
*lpRead = '\0'; // Terminate the string
|
|
//DebugTrace("LDIF Line: %s\n", *lppBuffer);
|
|
return(cbReadFile);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : ParseLDIFLine
|
|
|
|
Purpose : Parse the LDIF input line into Name and Data
|
|
|
|
Parameters: lpBuffer -> input buffer
|
|
lppName -> returned name pointer (pointer into lpBuffer)
|
|
lppData -> returned data pointer (pointer into lpBuffer)
|
|
lpcbData -> returned data size
|
|
lpType -> returned LDIF data type
|
|
|
|
Returns : HRESULT
|
|
|
|
Comment : Caller should not free the *lppName and *lppData pointers
|
|
since they are just pointers into the input buffer.
|
|
|
|
Assume that lpBuffer is NULL terminated.
|
|
|
|
LDIF attrval is formed like this:
|
|
attrname ((":") / (":" *SPACE value) /
|
|
("::" *SPACE base64-value) /
|
|
(":<" *SPACE url))
|
|
|
|
***************************************************************************/
|
|
HRESULT ParseLDIFLine(LPBYTE lpBuffer, PUCHAR * lppName, PUCHAR * lppData,
|
|
LPULONG lpcbData, LPLDIF_DATA_TYPE lpType) {
|
|
HRESULT hResult = hrSuccess;
|
|
LPBYTE lpTemp = lpBuffer;
|
|
|
|
// Strip of leading white space
|
|
while (*lpTemp == ' ' || *lpTemp == '\r' || *lpTemp == '\n') {
|
|
lpTemp++;
|
|
}
|
|
|
|
if (*lpTemp) {
|
|
*lppName = lpTemp;
|
|
|
|
// Look for the end of the name
|
|
while (lpTemp && *lpTemp && *lpTemp != ':') {
|
|
lpTemp++;
|
|
}
|
|
|
|
if (*lpTemp != ':') {
|
|
// Hmm, this isn't very good LDIF. Error out.
|
|
hResult = ResultFromScode(MAPI_E_BAD_VALUE);
|
|
goto exit;
|
|
}
|
|
|
|
// now pointing to the ':', put a NULL there to terminate the name
|
|
*lpTemp = '\0';
|
|
|
|
// What type of encoding is it?
|
|
lpTemp++;
|
|
|
|
switch (*lpTemp) {
|
|
case ':':
|
|
*lpType = LDIF_BASE64;
|
|
lpTemp++;
|
|
break;
|
|
|
|
case '<':
|
|
*lpType = LDIF_URL;
|
|
lpTemp++;
|
|
break;
|
|
|
|
case '\0':
|
|
// No data. This is legitimate.
|
|
// Fall through to default.
|
|
|
|
default: // anything else implies ASCII value
|
|
*lpType = LDIF_ASCII;
|
|
break;
|
|
}
|
|
|
|
// Strip of spaces leading the data
|
|
while (*lpTemp == ' ') {
|
|
lpTemp++;
|
|
}
|
|
|
|
// Now pointing at data
|
|
*lppData = lpTemp;
|
|
|
|
// Count bytes of data
|
|
*lpcbData = lstrlen(lpTemp) + 1;
|
|
}
|
|
|
|
exit:
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : ReadLDIFRecord
|
|
|
|
Purpose : Reads a record from an LDIF file with fixups for special characters
|
|
|
|
Parameters: hFile = file handle
|
|
lpcItems -> Returned number of items
|
|
lprgItems -> Returned array of item strings. Caller is
|
|
responsible for LocalFree'ing each string pointer and
|
|
this array pointer.
|
|
|
|
Returns : HRESULT
|
|
|
|
Comment : LDIF special characters are '#', ' ', CR and LF.
|
|
Rules:
|
|
1) A line which starts with '#' is a comment
|
|
2) A line which starts with a ' ' is a continuation
|
|
|
|
***************************************************************************/
|
|
HRESULT ReadLDIFRecord(HANDLE hFile, ULONG * lpcItems, LPLDIF_RECORD_ATTRIBUTE * lppLDIFRecord) {
|
|
HRESULT hResult = hrSuccess;
|
|
PUCHAR lpBuffer = NULL;
|
|
ULONG cbBuffer = 0;
|
|
ULONG cbReadFile = 1;
|
|
ULONG iItem = 0;
|
|
ULONG cAttributes = 0;
|
|
BOOL fEOR = FALSE;
|
|
LPLDIF_RECORD_ATTRIBUTE lpLDIFRecord = NULL;
|
|
LDIF_DATA_TYPE Type;
|
|
LPBYTE lpData = NULL;
|
|
LPTSTR lpName = NULL;
|
|
ULONG cbData = 0;
|
|
TCHAR szTemp[2048]; // 2k limit
|
|
LPLDIF_RECORD_ATTRIBUTE lpLDIFRecordT;
|
|
|
|
|
|
|
|
// Start out with 1024 character buffer. Realloc as necesary.
|
|
cbBuffer = CCH_READ_BUFFER;
|
|
if (! (lpBuffer = LocalAlloc(LPTR, cbBuffer))) {
|
|
DebugTrace("LocalAlloc(%u) -> %u\n", cbBuffer, GetLastError());
|
|
hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
// Start out with 32 item slots. Realloc as necesary.
|
|
cAttributes = NUM_ITEM_SLOTS;
|
|
if (! (lpLDIFRecord = LocalAlloc(LPTR, cAttributes * sizeof(LDIF_RECORD_ATTRIBUTE)))) {
|
|
DebugTrace("LocalAlloc(%u) -> %u\n", cAttributes * sizeof(PUCHAR), GetLastError());
|
|
LocalFree(lpBuffer);
|
|
hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
|
|
goto exit;
|
|
}
|
|
|
|
// Read attributes lines until you get end of record or EOF
|
|
while (! fEOR) {
|
|
// Read the next line (merges continuation)
|
|
if (cbReadFile = ReadLDIFLine(hFile, &lpBuffer, &cbBuffer))
|
|
{
|
|
ULONG cchSize = 0;
|
|
|
|
// Got another attribute, parse it
|
|
if (hResult = ParseLDIFLine(lpBuffer, &lpName, &lpData, &cbData, &Type)) {
|
|
goto exit;
|
|
}
|
|
|
|
// End of record?
|
|
if (! lpName || ! lstrlen(lpName)) {
|
|
fEOR = TRUE;
|
|
break;
|
|
}
|
|
|
|
// Make sure there's room in the returned table for this attribute
|
|
if (iItem >= cAttributes) {
|
|
// Array is too small. Reallocate!
|
|
cAttributes += 1; // NUM_ITEM_SLOTS; // Allocate another batch
|
|
if (! (lpLDIFRecordT = LocalReAlloc(lpLDIFRecord, cAttributes * sizeof(LDIF_RECORD_ATTRIBUTE), LMEM_MOVEABLE | LMEM_ZEROINIT)))
|
|
{
|
|
DebugTrace("LocalReAlloc(%u) -> %u\n", cAttributes * sizeof(PUCHAR), GetLastError());
|
|
hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
|
|
goto exit;
|
|
}
|
|
lpLDIFRecord = lpLDIFRecordT;
|
|
}
|
|
|
|
// Fill in the attribute in the structure
|
|
|
|
// BUGBUG: Here's where we should decode BASE64
|
|
|
|
if(Type == LDIF_BASE64)
|
|
{
|
|
ULONG cb = sizeof(szTemp);
|
|
*szTemp = '\0';
|
|
decodeBase64( lpData, szTemp, &cb);
|
|
if(szTemp && lstrlen(szTemp))
|
|
{
|
|
lpData = szTemp;
|
|
cbData = cb;
|
|
szTemp[cb] = '\0';
|
|
}
|
|
}
|
|
|
|
lpLDIFRecord[iItem].Type = Type;
|
|
lpLDIFRecord[iItem].cbData = cbData;
|
|
|
|
if (! (lpLDIFRecord[iItem].lpData = LocalAlloc(LPTR, cbData)))
|
|
{
|
|
DebugTrace("LocalAlloc(%u) -> %u\n", cbData, GetLastError());
|
|
hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
|
|
goto exit;
|
|
}
|
|
memcpy(lpLDIFRecord[iItem].lpData, lpData, cbData);
|
|
|
|
cchSize = lstrlen(lpName) + 1;
|
|
if (! (lpLDIFRecord[iItem].lpName = LocalAlloc(LPTR, cchSize)))
|
|
{
|
|
DebugTrace("LocalAlloc(%u) -> %u\n", cchSize, GetLastError());
|
|
hResult = ResultFromScode(MAPI_E_NOT_ENOUGH_MEMORY);
|
|
goto exit;
|
|
}
|
|
StrCpyN(lpLDIFRecord[iItem].lpName, lpName, cchSize);
|
|
} else {
|
|
fEOR = TRUE;
|
|
hResult = ResultFromScode(WAB_W_END_OF_FILE);
|
|
}
|
|
|
|
iItem++;
|
|
}
|
|
|
|
exit:
|
|
if (lpBuffer) {
|
|
LocalFree(lpBuffer);
|
|
}
|
|
|
|
if (hResult) {
|
|
if (lpLDIFRecord) {
|
|
FreeLDIFRecord(lpLDIFRecord, iItem);
|
|
lpLDIFRecord = NULL;
|
|
}
|
|
}
|
|
|
|
*lppLDIFRecord = lpLDIFRecord;
|
|
*lpcItems = iItem;
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : CountLDIFRows
|
|
|
|
Purpose : Counts the rows in the LDIF file
|
|
|
|
Parameters: hFile = open LDIF file
|
|
lpulcEntries -> returned count of rows
|
|
|
|
Returns : HRESULT
|
|
|
|
Comment : File pointer should be positioned past the version string prior
|
|
to calling this function. This function leaves the file
|
|
pointer where it found it.
|
|
|
|
***************************************************************************/
|
|
HRESULT CountLDIFRecords(HANDLE hFile, LPULONG lpulcEntries) {
|
|
HRESULT hResult = hrSuccess;
|
|
PUCHAR * rgItems = NULL;
|
|
ULONG ulStart;
|
|
ULONG cProps, i;
|
|
LPLDIF_RECORD_ATTRIBUTE lpLDIFRecord = NULL;
|
|
|
|
*lpulcEntries = 0;
|
|
|
|
Assert(hFile != INVALID_HANDLE_VALUE);
|
|
|
|
if (0xFFFFFFFF == (ulStart = SetFilePointer(hFile, 0, NULL, FILE_CURRENT))) {
|
|
DebugTrace("CountCSVRows SetFilePointer -> %u\n", GetLastError());
|
|
return(ResultFromScode(MAPI_E_CALL_FAILED));
|
|
}
|
|
|
|
|
|
while (hResult == hrSuccess) {
|
|
// Read the line
|
|
if (ReadLDIFRecord(hFile, &cProps, &lpLDIFRecord)) {
|
|
// End of file
|
|
break;
|
|
}
|
|
|
|
(*lpulcEntries)++;
|
|
|
|
if (lpLDIFRecord) {
|
|
FreeLDIFRecord(lpLDIFRecord, cProps);
|
|
lpLDIFRecord = NULL;
|
|
}
|
|
}
|
|
if (0xFFFFFFFF == SetFilePointer(hFile, ulStart, NULL, FILE_BEGIN)) {
|
|
DebugTrace("CountCSVRows SetFilePointer -> %u\n", GetLastError());
|
|
}
|
|
|
|
DebugTrace("LDIF file contains %u entries\n", ulcEntries);
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : InitLDIFAttrTable
|
|
|
|
Purpose : Initialize the LDIF attribute table
|
|
|
|
Parameters: LDIFAttrTable = table of attribute mappings
|
|
|
|
Returns : none
|
|
|
|
***************************************************************************/
|
|
void InitLDIFAttrTable(LPLDIF_ATTR_TABLE LDIFAttrTable) {
|
|
ULONG i;
|
|
|
|
for (i = 0; i < ela_Max; i++) {
|
|
LDIFAttrTable[i].index = NOT_FOUND;
|
|
LDIFAttrTable[i].ulPropTag = PR_NULL;
|
|
}
|
|
LDIFAttrTable[ela_c].lpName = sz_c;
|
|
LDIFAttrTable[ela_cn].lpName = sz_cn;
|
|
LDIFAttrTable[ela_co].lpName = sz_co;
|
|
LDIFAttrTable[ela_comment].lpName = sz_comment;
|
|
LDIFAttrTable[ela_commonName].lpName = sz_commonName;
|
|
LDIFAttrTable[ela_conferenceInformation].lpName = sz_conferenceInformation;
|
|
LDIFAttrTable[ela_countryname].lpName = sz_countryname;
|
|
LDIFAttrTable[ela_department].lpName = sz_department;
|
|
LDIFAttrTable[ela_description].lpName = sz_description;
|
|
LDIFAttrTable[ela_display_name].lpName = sz_display_name;
|
|
LDIFAttrTable[ela_dn].lpName = sz_dn;
|
|
LDIFAttrTable[ela_facsimiletelephonenumber].lpName = sz_facsimiletelephonenumber;
|
|
LDIFAttrTable[ela_givenname].lpName = sz_givenname;
|
|
LDIFAttrTable[ela_homePostalAddress].lpName = sz_homePostalAddress;
|
|
LDIFAttrTable[ela_homepage].lpName = sz_homepage;
|
|
LDIFAttrTable[ela_info].lpName = sz_info;
|
|
LDIFAttrTable[ela_initials].lpName = sz_initials;
|
|
LDIFAttrTable[ela_l].lpName = sz_l;
|
|
LDIFAttrTable[ela_labeledURI].lpName = sz_labeledURI;
|
|
LDIFAttrTable[ela_locality].lpName = sz_locality;
|
|
LDIFAttrTable[ela_mail].lpName = sz_mail;
|
|
LDIFAttrTable[ela_member].lpName = sz_member;
|
|
LDIFAttrTable[ela_mobile].lpName = sz_mobile;
|
|
LDIFAttrTable[ela_o].lpName = sz_o;
|
|
LDIFAttrTable[ela_objectclass].lpName = sz_objectclass;
|
|
LDIFAttrTable[ela_OfficeFax].lpName = sz_OfficeFax;
|
|
LDIFAttrTable[ela_OfficePager].lpName = sz_OfficePager;
|
|
LDIFAttrTable[ela_organizationName].lpName = sz_organizationName;
|
|
LDIFAttrTable[ela_organizationalUnitName].lpName = sz_organizationalUnitName;
|
|
LDIFAttrTable[ela_otherMailbox].lpName = sz_otherMailbox;
|
|
LDIFAttrTable[ela_ou].lpName = sz_ou;
|
|
LDIFAttrTable[ela_pager].lpName = sz_pager;
|
|
LDIFAttrTable[ela_physicalDeliveryOfficeName].lpName = sz_physicalDeliveryOfficeName;
|
|
LDIFAttrTable[ela_postOfficeBox].lpName = sz_postOfficeBox;
|
|
LDIFAttrTable[ela_postalAddress].lpName = sz_postalAddress;
|
|
LDIFAttrTable[ela_postalcode].lpName = sz_postalcode;
|
|
LDIFAttrTable[ela_sn].lpName = sz_sn;
|
|
LDIFAttrTable[ela_st].lpName = sz_st;
|
|
LDIFAttrTable[ela_streetAddress].lpName = sz_streetAddress;
|
|
LDIFAttrTable[ela_street].lpName = sz_street;
|
|
LDIFAttrTable[ela_surname].lpName = sz_surname;
|
|
LDIFAttrTable[ela_telephonenumber].lpName = sz_telephonenumber;
|
|
LDIFAttrTable[ela_homephonenumber].lpName = sz_homephonenumber;
|
|
LDIFAttrTable[ela_title].lpName = sz_title;
|
|
LDIFAttrTable[ela_uid].lpName = sz_uid;
|
|
LDIFAttrTable[ela_URL].lpName = sz_URL;
|
|
LDIFAttrTable[ela_userCertificate].lpName = sz_userCertificate;
|
|
LDIFAttrTable[ela_xmozillaconference].lpName = sz_xmozillaconference;
|
|
LDIFAttrTable[ela_xmozillanickname].lpName = sz_xmozillanickname;
|
|
LDIFAttrTable[ela_xmozillauseconferenceserver].lpName = sz_xmozillauseconferenceserver;
|
|
LDIFAttrTable[ela_xmozillausehtmlmail].lpName = sz_xmozillausehtmlmail;
|
|
|
|
|
|
LDIFAttrTable[ela_c].ulPropTag = PR_COUNTRY;
|
|
LDIFAttrTable[ela_c].ulPropIndex = elp_COUNTRY;
|
|
LDIFAttrTable[ela_cn].ulPropTag = PR_DISPLAY_NAME;
|
|
LDIFAttrTable[ela_cn].ulPropIndex = elp_DISPLAY_NAME;
|
|
LDIFAttrTable[ela_co].ulPropTag = PR_COMPANY_NAME;
|
|
LDIFAttrTable[ela_co].ulPropIndex = elp_COMPANY_NAME;
|
|
LDIFAttrTable[ela_comment].ulPropTag = PR_COMMENT;
|
|
LDIFAttrTable[ela_comment].ulPropIndex = elp_COMMENT;
|
|
LDIFAttrTable[ela_commonName].ulPropTag = PR_DISPLAY_NAME;
|
|
LDIFAttrTable[ela_commonName].ulPropIndex = elp_DISPLAY_NAME;
|
|
LDIFAttrTable[ela_conferenceInformation].ulPropTag = PR_NULL; // bugbug?
|
|
LDIFAttrTable[ela_conferenceInformation].ulPropIndex = NOT_FOUND;
|
|
LDIFAttrTable[ela_countryname].ulPropTag = PR_COUNTRY;
|
|
LDIFAttrTable[ela_countryname].ulPropIndex = elp_COUNTRY;
|
|
LDIFAttrTable[ela_department].ulPropTag = PR_DEPARTMENT_NAME;
|
|
LDIFAttrTable[ela_department].ulPropIndex = elp_DEPARTMENT_NAME;
|
|
LDIFAttrTable[ela_description].ulPropTag = PR_COMMENT;
|
|
LDIFAttrTable[ela_description].ulPropIndex = elp_COMMENT;
|
|
LDIFAttrTable[ela_display_name].ulPropTag = PR_DISPLAY_NAME;
|
|
LDIFAttrTable[ela_display_name].ulPropIndex = elp_DISPLAY_NAME;
|
|
LDIFAttrTable[ela_dn].ulPropTag = PR_DISPLAY_NAME;
|
|
LDIFAttrTable[ela_dn].ulPropIndex = elp_DISPLAY_NAME;
|
|
LDIFAttrTable[ela_facsimiletelephonenumber].ulPropTag = PR_HOME_FAX_NUMBER;
|
|
LDIFAttrTable[ela_facsimiletelephonenumber].ulPropIndex = elp_HOME_FAX_NUMBER;
|
|
LDIFAttrTable[ela_givenname].ulPropTag = PR_GIVEN_NAME;
|
|
LDIFAttrTable[ela_givenname].ulPropIndex = elp_GIVEN_NAME;
|
|
LDIFAttrTable[ela_homePostalAddress].ulPropTag = PR_HOME_ADDRESS_STREET;
|
|
LDIFAttrTable[ela_homePostalAddress].ulPropIndex = elp_HOME_ADDRESS_STREET;
|
|
LDIFAttrTable[ela_homepage].ulPropTag = PR_PERSONAL_HOME_PAGE;
|
|
LDIFAttrTable[ela_homepage].ulPropIndex = elp_PERSONAL_HOME_PAGE;
|
|
LDIFAttrTable[ela_info].ulPropTag = PR_COMMENT;
|
|
LDIFAttrTable[ela_info].ulPropIndex = elp_COMMENT;
|
|
LDIFAttrTable[ela_initials].ulPropTag = PR_MIDDLE_NAME;
|
|
LDIFAttrTable[ela_initials].ulPropIndex = elp_MIDDLE_NAME;
|
|
LDIFAttrTable[ela_l].ulPropTag = PR_LOCALITY;
|
|
LDIFAttrTable[ela_l].ulPropIndex = elp_LOCALITY;
|
|
LDIFAttrTable[ela_labeledURI].ulPropTag = PR_NULL; // Labeled URI. Don't save now.
|
|
LDIFAttrTable[ela_labeledURI].ulPropIndex = NOT_FOUND;
|
|
LDIFAttrTable[ela_locality].ulPropTag = PR_LOCALITY;
|
|
LDIFAttrTable[ela_locality].ulPropIndex = elp_LOCALITY;
|
|
LDIFAttrTable[ela_mail].ulPropTag = PR_EMAIL_ADDRESS;
|
|
LDIFAttrTable[ela_mail].ulPropIndex = elp_EMAIL_ADDRESS;
|
|
LDIFAttrTable[ela_member].ulPropTag = PR_NULL; // member of DL
|
|
LDIFAttrTable[ela_member].ulPropIndex = NOT_FOUND;
|
|
LDIFAttrTable[ela_mobile].ulPropTag = PR_MOBILE_TELEPHONE_NUMBER;
|
|
LDIFAttrTable[ela_mobile].ulPropIndex = elp_MOBILE_TELEPHONE_NUMBER;
|
|
LDIFAttrTable[ela_o].ulPropTag = PR_COMPANY_NAME;
|
|
LDIFAttrTable[ela_o].ulPropIndex = elp_COMPANY_NAME;
|
|
LDIFAttrTable[ela_objectclass].ulPropTag = PR_NULL; // special case object class
|
|
LDIFAttrTable[ela_objectclass].ulPropIndex = NOT_FOUND;
|
|
LDIFAttrTable[ela_OfficeFax].ulPropTag = PR_BUSINESS_FAX_NUMBER;
|
|
LDIFAttrTable[ela_OfficeFax].ulPropIndex = elp_BUSINESS_FAX_NUMBER;
|
|
LDIFAttrTable[ela_OfficePager].ulPropTag = PR_PAGER_TELEPHONE_NUMBER;
|
|
LDIFAttrTable[ela_OfficePager].ulPropIndex = elp_PAGER_TELEPHONE_NUMBER;
|
|
LDIFAttrTable[ela_organizationName].ulPropTag = PR_COMPANY_NAME;
|
|
LDIFAttrTable[ela_organizationName].ulPropIndex = elp_COMPANY_NAME;
|
|
LDIFAttrTable[ela_organizationalUnitName].ulPropTag = PR_DEPARTMENT_NAME;
|
|
LDIFAttrTable[ela_organizationalUnitName].ulPropIndex = elp_DEPARTMENT_NAME;
|
|
LDIFAttrTable[ela_otherMailbox].ulPropTag = PR_NULL; // BUGBUG
|
|
LDIFAttrTable[ela_otherMailbox].ulPropIndex = NOT_FOUND;
|
|
LDIFAttrTable[ela_ou].ulPropTag = PR_DEPARTMENT_NAME;
|
|
LDIFAttrTable[ela_ou].ulPropIndex = elp_DEPARTMENT_NAME;
|
|
LDIFAttrTable[ela_pager].ulPropTag = PR_PAGER_TELEPHONE_NUMBER;
|
|
LDIFAttrTable[ela_pager].ulPropIndex = elp_PAGER_TELEPHONE_NUMBER;
|
|
LDIFAttrTable[ela_physicalDeliveryOfficeName].ulPropTag = PR_OFFICE_LOCATION;
|
|
LDIFAttrTable[ela_physicalDeliveryOfficeName].ulPropIndex = elp_OFFICE_LOCATION;
|
|
LDIFAttrTable[ela_postOfficeBox].ulPropTag = PR_POST_OFFICE_BOX;
|
|
LDIFAttrTable[ela_postOfficeBox].ulPropIndex = elp_POST_OFFICE_BOX;
|
|
LDIFAttrTable[ela_postalAddress].ulPropTag = PR_STREET_ADDRESS;
|
|
LDIFAttrTable[ela_postalAddress].ulPropIndex = elp_STREET_ADDRESS;
|
|
LDIFAttrTable[ela_postalcode].ulPropTag = PR_POSTAL_CODE;
|
|
LDIFAttrTable[ela_postalcode].ulPropIndex = elp_POSTAL_CODE;
|
|
LDIFAttrTable[ela_sn].ulPropTag = PR_SURNAME;
|
|
LDIFAttrTable[ela_sn].ulPropIndex = elp_SURNAME;
|
|
LDIFAttrTable[ela_st].ulPropTag = PR_STATE_OR_PROVINCE;
|
|
LDIFAttrTable[ela_st].ulPropIndex = elp_STATE_OR_PROVINCE;
|
|
LDIFAttrTable[ela_streetAddress].ulPropTag = PR_STREET_ADDRESS;
|
|
LDIFAttrTable[ela_streetAddress].ulPropIndex = elp_STREET_ADDRESS;
|
|
LDIFAttrTable[ela_street].ulPropTag = PR_STREET_ADDRESS;
|
|
LDIFAttrTable[ela_street].ulPropIndex = elp_STREET_ADDRESS;
|
|
LDIFAttrTable[ela_surname].ulPropTag = PR_SURNAME;
|
|
LDIFAttrTable[ela_surname].ulPropIndex = elp_SURNAME;
|
|
LDIFAttrTable[ela_telephonenumber].ulPropTag = PR_BUSINESS_TELEPHONE_NUMBER;
|
|
LDIFAttrTable[ela_telephonenumber].ulPropIndex = elp_BUSINESS_TELEPHONE_NUMBER;
|
|
LDIFAttrTable[ela_homephonenumber].ulPropTag = PR_HOME_TELEPHONE_NUMBER;
|
|
LDIFAttrTable[ela_homephonenumber].ulPropIndex = elp_HOME_TELEPHONE_NUMBER;
|
|
LDIFAttrTable[ela_title].ulPropTag = PR_TITLE;
|
|
LDIFAttrTable[ela_title].ulPropIndex = elp_TITLE;
|
|
LDIFAttrTable[ela_uid].ulPropTag = PR_GIVEN_NAME; // ?? Matches in LDIF spec
|
|
LDIFAttrTable[ela_uid].ulPropIndex = elp_GIVEN_NAME;
|
|
LDIFAttrTable[ela_URL].ulPropTag = PR_BUSINESS_HOME_PAGE;
|
|
LDIFAttrTable[ela_URL].ulPropIndex = elp_BUSINESS_HOME_PAGE;
|
|
LDIFAttrTable[ela_userCertificate].ulPropTag = PR_NULL; // BUGBUG
|
|
LDIFAttrTable[ela_userCertificate].ulPropIndex = NOT_FOUND;
|
|
LDIFAttrTable[ela_xmozillaconference].ulPropTag = PR_SERVERS; //PR_NULL; // BUGBUG?
|
|
LDIFAttrTable[ela_xmozillaconference].ulPropIndex = elp_CONFERENCE_SERVERS;
|
|
LDIFAttrTable[ela_xmozillanickname].ulPropTag = PR_NICKNAME;
|
|
LDIFAttrTable[ela_xmozillanickname].ulPropIndex = elp_NICKNAME;
|
|
LDIFAttrTable[ela_xmozillauseconferenceserver].ulPropTag = PR_NULL; // BUGBUG
|
|
LDIFAttrTable[ela_xmozillauseconferenceserver].ulPropIndex = NOT_FOUND;
|
|
LDIFAttrTable[ela_xmozillausehtmlmail].ulPropTag = PR_NULL; // BUGBUG
|
|
LDIFAttrTable[ela_xmozillausehtmlmail].ulPropIndex = NOT_FOUND;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : FindAttributeName
|
|
|
|
Purpose : Find the attribute mapping in the LDIF attribute table
|
|
|
|
Parameters: lpName = name of attribute to find
|
|
LDIFAttrTable = table of LDIF attribute mappings
|
|
|
|
Returns : index in LDIFAttrTable (or NOT_FOUND)
|
|
|
|
Comment : Could perhaps benefit from a binary search algorithm.
|
|
|
|
***************************************************************************/
|
|
ULONG FindAttributeName(LPBYTE lpName, LPLDIF_ATTR_TABLE LDIFAttrTable) {
|
|
ULONG i;
|
|
ULONG ulIndex = NOT_FOUND;
|
|
|
|
for (i = 0; i < ela_Max; i++) {
|
|
if (lpName && LDIFAttrTable[i].lpName && ! lstrcmpi(lpName, LDIFAttrTable[i].lpName)) {
|
|
ulIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
return(ulIndex);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
Name : MapLDIFtoProps
|
|
|
|
Purpose : Map the LDIF record attributes to WAB properties
|
|
|
|
Parameters: lpLDIFRecord -> LDIF record
|
|
cAttributes = number of attributes in LDIF record
|
|
lpspv -> prop value array (pre-allocated)
|
|
lpcProps -> returned number of properties
|
|
lppDisplayName -> returned display name
|
|
lppEmailAddress -> returned email address (or NULL)
|
|
|
|
Returns : HRESULT
|
|
|
|
***************************************************************************/
|
|
HRESULT MapLDIFtoProps(LPLDIF_RECORD_ATTRIBUTE lpLDIFRecord, ULONG cAttributes,
|
|
LPSPropValue * lppspv, LPULONG lpcProps, LPTSTR * lppDisplayName, LPTSTR *lppEmailAddress,
|
|
ULONG * lpulObjType) {
|
|
HRESULT hResult = hrSuccess;
|
|
ULONG cPropVals = cPropVals = cAttributes + NUM_MUST_HAVE_PROPS;
|
|
ULONG iProp = 0;
|
|
ULONG i;
|
|
LDIF_ATTR_TABLE LDIFAttrTable[ela_Max];
|
|
ULONG iTable;
|
|
ULONG cProps = elp_Max;
|
|
SCODE sc;
|
|
LONG iEmailAddr = -1;
|
|
LONG iServers = -1;
|
|
LPSPropValue lpspv = NULL;
|
|
ULONG ulIndex = 0;
|
|
|
|
*lpulObjType = MAPI_MAILUSER;
|
|
|
|
// Allocate prop value array
|
|
if (hResult = ResultFromScode(WABAllocateBuffer(cProps * sizeof(SPropValue), &lpspv))) {
|
|
DebugTrace("WABAllocateBuffer -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
// Fill with PR_NULL
|
|
for (i = 0; i < cProps; i++) {
|
|
lpspv[i].ulPropTag = PR_NULL;
|
|
}
|
|
|
|
InitLDIFAttrTable(LDIFAttrTable);
|
|
|
|
// Loop through attributes, looking for interesting stuff
|
|
for (i = 0; i < cAttributes; i++) {
|
|
iTable = NOT_FOUND;
|
|
if ((iTable = FindAttributeName(lpLDIFRecord[i].lpName, LDIFAttrTable)) != NOT_FOUND) {
|
|
// Found the attribute name
|
|
// mark the data index in the table
|
|
LDIFAttrTable[iTable].index = i;
|
|
}
|
|
|
|
// Some special cases need to be examined now.
|
|
switch (iTable) {
|
|
case ela_cn:
|
|
case ela_dn:
|
|
// if we have both cn and dn, cn takes precedence
|
|
if(LDIFAttrTable[ela_cn].index != NOT_FOUND && LDIFAttrTable[ela_dn].index != NOT_FOUND)
|
|
LDIFAttrTable[ela_dn].index = NOT_FOUND;
|
|
break;
|
|
|
|
case ela_objectclass:
|
|
// objectclass may appear multiple times. It is up to us to decide which
|
|
// one is meaningful.
|
|
// We recognize several different types:
|
|
// objectclass: person
|
|
// objectclass: organizationalPerson
|
|
// objectclass: groupofnames
|
|
// What objectclass is it?
|
|
if(lpLDIFRecord[i].lpData)
|
|
{
|
|
if (! lstrcmpi(lpLDIFRecord[i].lpData, sz_person) ||
|
|
! lstrcmpi(lpLDIFRecord[i].lpData, sz_organizationalPerson)) {
|
|
*lpulObjType = MAPI_MAILUSER;
|
|
} else if (! lstrcmpi(lpLDIFRecord[i].lpData, sz_groupOfNames)) {
|
|
*lpulObjType = MAPI_DISTLIST;
|
|
} else {
|
|
// Ignore this objectclass
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ela_member: // DL member name or address
|
|
Assert(*lpulObjType == MAPI_DISTLIST);
|
|
// BUGBUG: NYI
|
|
break;
|
|
}
|
|
}
|
|
|
|
// look through the attr table for props to use
|
|
for (i = 0; i < ela_Max; i++)
|
|
{
|
|
if (LDIFAttrTable[i].ulPropTag != PR_NULL &&
|
|
lpspv[ulIndex].ulPropTag == PR_NULL &&
|
|
LDIFAttrTable[i].index != NOT_FOUND)
|
|
{
|
|
|
|
if( LDIFAttrTable[i].ulPropTag == PR_SERVERS )
|
|
{
|
|
ULONG cchData;
|
|
ULONG cStrToAdd = 2;
|
|
LPTSTR * lppszServers;
|
|
ULONG index = (iServers >= 0 ? iServers : ulIndex); //LDIFAttrTable[i].ulPropIndex;
|
|
LONG cCurrentStrs = (iServers >= 0 ? lpspv[index].Value.MVSZ.cValues : 0);
|
|
LPTSTR lpEmailAddress = NULL;
|
|
lpspv[index].ulPropTag = PR_SERVERS;
|
|
|
|
if( cCurrentStrs >= (LONG)cStrToAdd )
|
|
{
|
|
// will not handle more than 2 netmtgs addresses
|
|
lpspv[index].ulPropTag = PR_NULL;
|
|
}
|
|
else
|
|
{
|
|
if( cCurrentStrs <= 0 )
|
|
{
|
|
sc = WABAllocateMore(sizeof(LPTSTR), lpspv,
|
|
(LPVOID *)&(lpspv[index].Value.MVSZ.LPPSZ));
|
|
|
|
if (sc)
|
|
{
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
|
|
cCurrentStrs = 0;
|
|
}
|
|
cchData = 2 + lstrlen(szCallto) + lstrlen( lpLDIFRecord[LDIFAttrTable[i].index].lpData );
|
|
if ( iEmailAddr >= 0 ){
|
|
lpEmailAddress = lpspv[iEmailAddr].Value.LPSZ;
|
|
cchData += lstrlen( lpEmailAddress) + 2;
|
|
}
|
|
|
|
// allocate enough space for two Server names
|
|
lppszServers = lpspv[index].Value.MVSZ.LPPSZ;
|
|
|
|
// Allocate more space for the email address and copy it.
|
|
sc = WABAllocateMore( sizeof(TCHAR) * cchData, lpspv,
|
|
(LPVOID *)&(lppszServers[cCurrentStrs]));
|
|
if( sc )
|
|
{
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
StrCpyN(lppszServers[cCurrentStrs], szCallto, cchData);
|
|
StrCatBuff(lppszServers[cCurrentStrs], lpLDIFRecord[LDIFAttrTable[i].index].lpData, cchData);
|
|
|
|
// now we need to check if email address has already been set
|
|
if ( iEmailAddr >= 0 )
|
|
{
|
|
StrCatBuff(lppszServers[cCurrentStrs], szFwdSlash, cchData);
|
|
StrCatBuff(lppszServers[cCurrentStrs], lpEmailAddress, cchData);
|
|
}
|
|
else
|
|
iServers = index;
|
|
|
|
lpspv[index].Value.MVSZ.cValues = ++cCurrentStrs;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
int index = LDIFAttrTable[i].index;
|
|
LPTSTR lp = lpLDIFRecord[index].lpData;
|
|
if(lp && lstrlen(lp))
|
|
{
|
|
lpspv[ulIndex].ulPropTag = LDIFAttrTable[i].ulPropTag;
|
|
// BUGBUG: assumes string data
|
|
// Allocate more space for the email address and copy it.
|
|
sc = WABAllocateMore( sizeof(TCHAR)*(lstrlen(lp)+1), lpspv, (LPVOID *)&(lpspv[ulIndex].Value.LPSZ));
|
|
if( sc )
|
|
{
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
StrCpyN(lpspv[ulIndex].Value.LPSZ, lp, lstrlen(lp)+1);
|
|
}
|
|
}
|
|
// Get the special display strings to return
|
|
switch (LDIFAttrTable[i].ulPropTag) {
|
|
case PR_DISPLAY_NAME:
|
|
*lppDisplayName = lpspv[ulIndex].Value.LPSZ;
|
|
break;
|
|
case PR_EMAIL_ADDRESS:
|
|
{
|
|
LPTSTR * lppszServerStr, lpszOldServerStr;
|
|
LONG cNumStrs;
|
|
ULONG cchData;
|
|
*lppEmailAddress = lpspv[ulIndex].Value.LPSZ;
|
|
// if servers has has already been set, append email address
|
|
if ( iServers >= 0 )
|
|
{
|
|
if( lpspv[iServers].ulPropTag != PR_SERVERS )
|
|
break;
|
|
|
|
cNumStrs = lpspv[iServers].Value.MVSZ.cValues - 1;
|
|
|
|
if( cNumStrs >= 0 && cNumStrs < 3)
|
|
{
|
|
lppszServerStr = lpspv[iServers].Value.MVSZ.LPPSZ;
|
|
lpszOldServerStr = lppszServerStr[cNumStrs];
|
|
cchData = lstrlen(*lppszServerStr) + lstrlen(*lppEmailAddress) + 2;
|
|
sc = WABAllocateMore( sizeof(TCHAR) * cchData, lpspv,
|
|
(LPVOID *)&(lppszServerStr[cNumStrs]));
|
|
|
|
if( sc )
|
|
{
|
|
hResult = ResultFromScode(sc);
|
|
goto exit;
|
|
}
|
|
StrCpyN(lppszServerStr[cNumStrs],lpszOldServerStr, cchData);
|
|
StrCatBuff(lppszServerStr[cNumStrs], szFwdSlash, cchData);
|
|
StrCatBuff(lppszServerStr[cNumStrs], *lppEmailAddress, cchData);
|
|
}
|
|
}
|
|
else
|
|
iEmailAddr = ulIndex;
|
|
}
|
|
break;
|
|
}
|
|
ulIndex++;
|
|
}
|
|
}
|
|
/*
|
|
// Get rid of PR_NULL props
|
|
for (i = 0; i < cProps; i++) {
|
|
if (lpspv[i].ulPropTag == PR_NULL) {
|
|
// Slide the props down.
|
|
if (i + 1 < cProps) { // Are there any higher props to copy?
|
|
CopyMemory(&(lpspv[i]),
|
|
&(lpspv[i + 1]),
|
|
((cProps - i) - 1) * sizeof(*lppspv[i]));
|
|
}
|
|
// decrement count
|
|
cProps--;
|
|
i--; // You overwrote the current propval. Look at it again.
|
|
}
|
|
}
|
|
*/
|
|
*lpcProps = ulIndex;
|
|
*lppspv = lpspv;
|
|
exit:
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
/*********************************************************
|
|
|
|
HraddLDIFMailUser - adds a mailuser to the WAB
|
|
|
|
**********************************************************/
|
|
HRESULT HrAddLDIFMailUser(HWND hWnd,
|
|
LPABCONT lpContainer,
|
|
LPTSTR lpDisplayName,
|
|
LPTSTR lpEmailAddress,
|
|
ULONG cProps,
|
|
LPSPropValue lpspv,
|
|
LPWAB_PROGRESS_CALLBACK lpProgressCB,
|
|
LPWAB_EXPORT_OPTIONS lpOptions)
|
|
{
|
|
HRESULT hResult = S_OK;
|
|
LPMAPIPROP lpMailUserWAB = NULL;
|
|
ULONG ulCreateFlags = CREATE_CHECK_DUP_STRICT;
|
|
REPLACE_INFO RI;
|
|
|
|
if (lpOptions->ReplaceOption == WAB_REPLACE_ALWAYS)
|
|
{
|
|
ulCreateFlags |= CREATE_REPLACE;
|
|
}
|
|
|
|
|
|
retry:
|
|
|
|
// Create a new wab mailuser
|
|
if (HR_FAILED(hResult = lpContainer->lpVtbl->CreateEntry(
|
|
lpContainer,
|
|
lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.cb,
|
|
(LPENTRYID) lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.lpb,
|
|
ulCreateFlags,
|
|
&lpMailUserWAB)))
|
|
{
|
|
DebugTrace("CreateEntry(WAB MailUser) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
{
|
|
ULONG i,k;
|
|
for(i=0;i<cProps;i++)
|
|
{
|
|
if(PROP_TYPE(lpspv[i].ulPropTag)==PT_MV_TSTRING)
|
|
{
|
|
DebugTrace("\t0x%.8x = %d\n",lpspv[i].ulPropTag, lpspv[i].Value.MVSZ.cValues);
|
|
for(k=0;k<lpspv[i].Value.MVSZ.cValues;k++)
|
|
DebugTrace("\t%s\n",lpspv[i].Value.MVSZ.LPPSZ[k]);
|
|
}
|
|
else
|
|
DebugTrace("0x%.8x = %s\n",lpspv[i].ulPropTag,lpspv[i].Value.LPSZ);
|
|
}
|
|
}
|
|
// Set the properties on the new WAB entry
|
|
if (HR_FAILED(hResult = lpMailUserWAB->lpVtbl->SetProps( lpMailUserWAB,
|
|
cProps, // cValues
|
|
lpspv, // property array
|
|
NULL))) // problems array
|
|
{
|
|
DebugTrace("LDIFImport:SetProps(WAB) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
// Save the new wab mailuser or distlist
|
|
if (HR_FAILED(hResult = lpMailUserWAB->lpVtbl->SaveChanges(lpMailUserWAB,
|
|
KEEP_OPEN_READONLY | FORCE_SAVE)))
|
|
{
|
|
if (GetScode(hResult) == MAPI_E_COLLISION)
|
|
{
|
|
// Find the display name
|
|
Assert(lpDisplayName);
|
|
|
|
if (! lpDisplayName)
|
|
{
|
|
DebugTrace("Collision, but can't find PR_DISPLAY_NAME in entry\n");
|
|
goto exit;
|
|
}
|
|
|
|
// Do we need to prompt?
|
|
if (lpOptions->ReplaceOption == WAB_REPLACE_PROMPT)
|
|
{
|
|
// Prompt user with dialog. If they say YES, we should try again
|
|
|
|
|
|
RI.lpszDisplayName = lpDisplayName;
|
|
RI.lpszEmailAddress = lpEmailAddress;
|
|
RI.ConfirmResult = CONFIRM_ERROR;
|
|
RI.lpImportOptions = lpOptions;
|
|
|
|
DialogBoxParam(hInst,
|
|
MAKEINTRESOURCE(IDD_ImportReplace),
|
|
hWnd,
|
|
ReplaceDialogProc,
|
|
(LPARAM)&RI);
|
|
|
|
switch (RI.ConfirmResult)
|
|
{
|
|
case CONFIRM_YES:
|
|
case CONFIRM_YES_TO_ALL:
|
|
// YES
|
|
// NOTE: recursive Migrate will fill in the SeenList entry
|
|
// go try again!
|
|
lpMailUserWAB->lpVtbl->Release(lpMailUserWAB);
|
|
lpMailUserWAB = NULL;
|
|
|
|
ulCreateFlags |= CREATE_REPLACE;
|
|
goto retry;
|
|
break;
|
|
|
|
case CONFIRM_ABORT:
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
goto exit;
|
|
|
|
default:
|
|
// NO
|
|
break;
|
|
}
|
|
}
|
|
hResult = hrSuccess;
|
|
|
|
} else
|
|
{
|
|
DebugTrace("SaveChanges(WAB MailUser) -> %x\n", GetScode(hResult));
|
|
}
|
|
}
|
|
|
|
exit:
|
|
if(lpMailUserWAB)
|
|
lpMailUserWAB->lpVtbl->Release(lpMailUserWAB);
|
|
|
|
return hResult;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*****************************************************************
|
|
|
|
HrCreateAdrListFromLDIFRecord
|
|
|
|
Scans an LDIF record and turns all the "members" into an
|
|
unresolved AdrList
|
|
|
|
******************************************************************/
|
|
HRESULT HrCreateAdrListFromLDIFRecord(ULONG cAttributes,
|
|
LPLDIF_RECORD_ATTRIBUTE lpLDIFRecord,
|
|
LPADRLIST * lppAdrList)
|
|
{
|
|
HRESULT hr = S_OK;
|
|
ULONG nMembers = 0, i;
|
|
LPADRLIST lpAdrList = NULL;
|
|
|
|
*lppAdrList = NULL;
|
|
|
|
// Count the members in this group
|
|
for(i=0;i<cAttributes;i++)
|
|
{
|
|
if(lpLDIFRecord[i].cbData && lpLDIFRecord[i].lpName && !lstrcmpi(lpLDIFRecord[i].lpName, sz_member))
|
|
{
|
|
nMembers++;
|
|
}
|
|
}
|
|
|
|
if(!nMembers)
|
|
goto exit;
|
|
|
|
// Now create a adrlist from these members
|
|
|
|
// Allocate prop value array
|
|
if (hr = ResultFromScode(WABAllocateBuffer(sizeof(ADRLIST) + nMembers * sizeof(ADRENTRY), &lpAdrList)))
|
|
goto exit;
|
|
|
|
lpAdrList->cEntries = nMembers;
|
|
|
|
nMembers = 0;
|
|
for(i=0;i<cAttributes;i++)
|
|
{
|
|
if(lpLDIFRecord[i].cbData && lpLDIFRecord[i].lpData
|
|
&& !lstrcmpi(lpLDIFRecord[i].lpName, sz_member))
|
|
{
|
|
// This is a member .. break out its lpData into
|
|
// Name and Email
|
|
LPTSTR lpName = NULL;
|
|
LPTSTR lpEmail = NULL;
|
|
|
|
lpName = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lpLDIFRecord[i].cbData + 1));
|
|
lpEmail = LocalAlloc(LMEM_ZEROINIT, sizeof(TCHAR)*(lpLDIFRecord[i].cbData + 1));
|
|
if(lpName && lpEmail)
|
|
{
|
|
LPTSTR lp = NULL;
|
|
StrCpyN(lpName, lpLDIFRecord[i].lpData, lpLDIFRecord[i].cbData + 1);
|
|
StrCpyN(lpEmail, lpName, lpLDIFRecord[i].cbData + 1);
|
|
|
|
lp = lpName;
|
|
|
|
// BUGBUG - we are looking for two pieces of data Name and Email
|
|
// this code is assuming it will get 'cn=' first and then 'mail='
|
|
// second .. this is all a poor hack assuming too many things
|
|
|
|
if(*lp == 'c' && *(lp+1) == 'n' && *(lp+2) == '=')
|
|
lp += 3;
|
|
StrCpyN(lpName, lp, lpLDIFRecord[i].cbData + 1);
|
|
|
|
while (lp && *lp && *lp!=',')
|
|
lp++;
|
|
|
|
if(!*lp) // there is a comma, sometimes there isnt
|
|
{
|
|
LocalFree(lpEmail);
|
|
lpEmail = NULL;
|
|
}
|
|
else
|
|
{
|
|
*lp = '\0';
|
|
lp++;
|
|
StrCpyN(lpEmail, lp, lpLDIFRecord[i].cbData + 1);
|
|
|
|
lp = lpEmail;
|
|
if(*lp == 'm' && *(lp+1) == 'a' && *(lp+2) == 'i' && *(lp+3) == 'l' && *(lp+4) == '=')
|
|
lp += 5;
|
|
StrCpyN(lpEmail, lp, lpLDIFRecord[i].cbData + 1);
|
|
while (lp && *lp && *lp!=',')
|
|
lp++;
|
|
if(*lp)
|
|
{
|
|
// terminate on this
|
|
*lp = '\0';
|
|
}
|
|
}
|
|
|
|
if(lpName)// && lpEmail)
|
|
{
|
|
LPSPropValue lpProp = NULL;
|
|
ULONG ulcProps = 2;
|
|
|
|
if (hr = ResultFromScode(WABAllocateBuffer(2 * sizeof(SPropValue), &lpProp)))
|
|
goto exit;
|
|
|
|
lpProp[0].ulPropTag = PR_DISPLAY_NAME;
|
|
|
|
if (hr = ResultFromScode(WABAllocateMore(lstrlen(lpName)+1, lpProp, &(lpProp[0].Value.lpszA))))
|
|
goto exit;
|
|
|
|
StrCpyN(lpProp[0].Value.lpszA, lpName, lstrlen(lpName)+1);
|
|
|
|
if(lpEmail)
|
|
{
|
|
lpProp[1].ulPropTag = PR_EMAIL_ADDRESS;
|
|
|
|
if (hr = ResultFromScode(WABAllocateMore(lstrlen(lpEmail)+1, lpProp, &(lpProp[1].Value.lpszA))))
|
|
goto exit;
|
|
|
|
StrCpyN(lpProp[1].Value.lpszA, lpEmail, lstrlen(lpEmail)+1);
|
|
}
|
|
lpAdrList->aEntries[nMembers].cValues = (lpEmail ? 2 : 1);
|
|
lpAdrList->aEntries[nMembers].rgPropVals = lpProp;
|
|
nMembers++;
|
|
|
|
}
|
|
|
|
if(lpName)
|
|
LocalFree(lpName);
|
|
if(lpEmail)
|
|
LocalFree(lpEmail);
|
|
|
|
}
|
|
|
|
|
|
}
|
|
}
|
|
|
|
*lppAdrList = lpAdrList;
|
|
|
|
exit:
|
|
|
|
if(HR_FAILED(hr) && lpAdrList)
|
|
WABFreePadrlist(lpAdrList);
|
|
|
|
return hr;
|
|
}
|
|
|
|
|
|
/*****************************************************************
|
|
|
|
HraddLDIFDistList - adds a distlist and its members to the WAB
|
|
|
|
Sequence of events will be:
|
|
|
|
- Create a DistList object
|
|
- Set the properties on the DistList object
|
|
- Scan the list of members for the given dist list object
|
|
- Add each member to the wab .. if member already exists,
|
|
prompt to replace etc ...if it doesnt exist, create new
|
|
|
|
|
|
******************************************************************/
|
|
HRESULT HrAddLDIFDistList(HWND hWnd,
|
|
LPABCONT lpContainer,
|
|
ULONG cAttributes,
|
|
LPLDIF_RECORD_ATTRIBUTE lpLDIFRecord,
|
|
LPTSTR lpDisplayName,
|
|
LPTSTR lpEmailAddress,
|
|
ULONG cProps,
|
|
LPSPropValue lpspv,
|
|
LPWAB_PROGRESS_CALLBACK lpProgressCB,
|
|
LPWAB_EXPORT_OPTIONS lpOptions)
|
|
{
|
|
HRESULT hResult = S_OK;
|
|
LPMAPIPROP lpDistListWAB = NULL;
|
|
LPDISTLIST lpDLWAB = NULL;
|
|
ULONG ulCreateFlags = CREATE_CHECK_DUP_STRICT;
|
|
REPLACE_INFO RI;
|
|
LPADRLIST lpAdrList = NULL;
|
|
LPFlagList lpfl = NULL;
|
|
ULONG ulcValues = 0;
|
|
LPSPropValue lpPropEID = NULL;
|
|
ULONG i, cbEIDNew;
|
|
LPENTRYID lpEIDNew;
|
|
ULONG ulObjectTypeOpen;
|
|
|
|
|
|
if (lpOptions->ReplaceOption == WAB_REPLACE_ALWAYS)
|
|
{
|
|
ulCreateFlags |= CREATE_REPLACE;
|
|
}
|
|
|
|
|
|
retry:
|
|
// Create a new wab distlist
|
|
if (HR_FAILED(hResult = lpContainer->lpVtbl->CreateEntry(
|
|
lpContainer,
|
|
lpCreateEIDsWAB[iconPR_DEF_CREATE_DL].Value.bin.cb,
|
|
(LPENTRYID) lpCreateEIDsWAB[iconPR_DEF_CREATE_DL].Value.bin.lpb,
|
|
ulCreateFlags,
|
|
(LPMAPIPROP *) &lpDistListWAB)))
|
|
{
|
|
DebugTrace("CreateEntry(WAB MailUser) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
// Set the properties on the new WAB entry
|
|
if (HR_FAILED(hResult = lpDistListWAB->lpVtbl->SetProps( lpDistListWAB,
|
|
cProps, // cValues
|
|
lpspv, // property array
|
|
NULL))) // problems array
|
|
{
|
|
DebugTrace("LDIFImport:SetProps(WAB) -> %x\n", GetScode(hResult));
|
|
goto exit;
|
|
}
|
|
|
|
|
|
// Save the new wab mailuser or distlist
|
|
if (HR_FAILED(hResult = lpDistListWAB->lpVtbl->SaveChanges(lpDistListWAB,
|
|
KEEP_OPEN_READWRITE | FORCE_SAVE)))
|
|
{
|
|
if (GetScode(hResult) == MAPI_E_COLLISION)
|
|
{
|
|
// Find the display name
|
|
Assert(lpDisplayName);
|
|
|
|
if (! lpDisplayName)
|
|
{
|
|
DebugTrace("Collision, but can't find PR_DISPLAY_NAME in entry\n");
|
|
goto exit;
|
|
}
|
|
|
|
// Do we need to prompt?
|
|
if (lpOptions->ReplaceOption == WAB_REPLACE_PROMPT)
|
|
{
|
|
// Prompt user with dialog. If they say YES, we should try again
|
|
|
|
|
|
RI.lpszDisplayName = lpDisplayName;
|
|
RI.lpszEmailAddress = NULL; //lpEmailAddress;
|
|
RI.ConfirmResult = CONFIRM_ERROR;
|
|
RI.lpImportOptions = lpOptions;
|
|
|
|
DialogBoxParam(hInst,
|
|
MAKEINTRESOURCE(IDD_ImportReplace),
|
|
hWnd,
|
|
ReplaceDialogProc,
|
|
(LPARAM)&RI);
|
|
|
|
switch (RI.ConfirmResult)
|
|
{
|
|
case CONFIRM_YES:
|
|
case CONFIRM_YES_TO_ALL:
|
|
// YES
|
|
// NOTE: recursive Migrate will fill in the SeenList entry
|
|
// go try again!
|
|
lpDistListWAB->lpVtbl->Release(lpDistListWAB);
|
|
lpDistListWAB = NULL;
|
|
|
|
ulCreateFlags |= CREATE_REPLACE;
|
|
goto retry;
|
|
break;
|
|
|
|
case CONFIRM_ABORT:
|
|
hResult = ResultFromScode(MAPI_E_USER_CANCEL);
|
|
goto exit;
|
|
|
|
default:
|
|
// NO
|
|
break;
|
|
}
|
|
}
|
|
hResult = hrSuccess;
|
|
|
|
} else
|
|
{
|
|
DebugTrace("SaveChanges(WAB MailUser) -> %x\n", GetScode(hResult));
|
|
}
|
|
}
|
|
|
|
|
|
// Now we've created the Distribution List object .. we need to add members to it ..
|
|
//
|
|
// What is the ENTRYID of our new entry?
|
|
if ((hResult = lpDistListWAB->lpVtbl->GetProps(lpDistListWAB,
|
|
(LPSPropTagArray)&ptaEid,
|
|
0,
|
|
&ulcValues,
|
|
&lpPropEID)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
cbEIDNew = lpPropEID->Value.bin.cb;
|
|
lpEIDNew = (LPENTRYID) lpPropEID->Value.bin.lpb;
|
|
|
|
if(!cbEIDNew || !lpEIDNew)
|
|
goto exit;
|
|
|
|
// Open the new WAB DL as a DISTLIST object
|
|
if (HR_FAILED(hResult = lpContainer->lpVtbl->OpenEntry(lpContainer,
|
|
cbEIDNew,
|
|
lpEIDNew,
|
|
(LPIID)&IID_IDistList,
|
|
MAPI_MODIFY,
|
|
&ulObjectTypeOpen,
|
|
(LPUNKNOWN*)&lpDLWAB)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
|
|
|
|
// First we create a lpAdrList with all the members of this dist list and try to resolve
|
|
// the members against the container .. entries that already exist in the WAB will come
|
|
// back as resolved .. entries that dont exist in the container will come back as unresolved
|
|
// We can then add the unresolved entries as fresh entries to the wab (since they are
|
|
// unresolved, there will be no collision) .. and then we can do another resolvenames to
|
|
// resolve everything and get a lpAdrList full of EntryIDs .. we can then take this list of
|
|
// entryids and call CreateEntry or CopyEntry on the DistList object to copy the entryid into
|
|
// the distlist ...
|
|
|
|
hResult = HrCreateAdrListFromLDIFRecord(cAttributes, lpLDIFRecord, &lpAdrList);
|
|
|
|
if(HR_FAILED(hResult))
|
|
goto exit;
|
|
|
|
if(!lpAdrList || !(lpAdrList->cEntries))
|
|
goto exit;
|
|
|
|
// Create a corresponding flaglist
|
|
lpfl = LocalAlloc(LMEM_ZEROINIT, sizeof(FlagList) + (lpAdrList->cEntries)*sizeof(ULONG));
|
|
if(!lpfl)
|
|
{
|
|
hResult = MAPI_E_NOT_ENOUGH_MEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
lpfl->cFlags = lpAdrList->cEntries;
|
|
|
|
// set all the flags to unresolved
|
|
for(i=0;i<lpAdrList->cEntries;i++)
|
|
lpfl->ulFlag[i] = MAPI_UNRESOLVED;
|
|
|
|
hResult = lpContainer->lpVtbl->ResolveNames(lpContainer, NULL, 0, lpAdrList, lpfl);
|
|
|
|
if(HR_FAILED(hResult))
|
|
goto exit;
|
|
|
|
// All the entries in the list that are resolved, already exist in the address book.
|
|
|
|
// The ones that are not resolved need to be added silently to the address book ..
|
|
for(i=0;i<lpAdrList->cEntries;i++)
|
|
{
|
|
if(lpfl->ulFlag[i] == MAPI_UNRESOLVED)
|
|
{
|
|
LPMAPIPROP lpMailUser = NULL;
|
|
|
|
if (HR_FAILED(hResult = lpContainer->lpVtbl->CreateEntry(
|
|
lpContainer,
|
|
lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.cb,
|
|
(LPENTRYID) lpCreateEIDsWAB[iconPR_DEF_CREATE_MAILUSER].Value.bin.lpb,
|
|
0,
|
|
&lpMailUser)))
|
|
{
|
|
continue;
|
|
//goto exit;
|
|
}
|
|
|
|
if(lpMailUser)
|
|
{
|
|
// Set the properties on the new WAB entry
|
|
if (HR_FAILED(hResult = lpMailUser->lpVtbl->SetProps(lpMailUser,
|
|
lpAdrList->aEntries[i].cValues,
|
|
lpAdrList->aEntries[i].rgPropVals,
|
|
NULL)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
// Save the new wab mailuser or distlist
|
|
if (HR_FAILED(hResult = lpMailUser->lpVtbl->SaveChanges(lpMailUser,
|
|
KEEP_OPEN_READONLY | FORCE_SAVE)))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
lpMailUser->lpVtbl->Release(lpMailUser);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
// now that we've added all the unresolved members to the WAB, we call ResolveNames
|
|
// again .. as a result, every member in this list will be resolved and we will
|
|
// have entryids for all of them
|
|
// We will then take these entryids and add them to the DistList object
|
|
|
|
hResult = lpContainer->lpVtbl->ResolveNames(lpContainer, NULL, 0, lpAdrList, lpfl);
|
|
|
|
if(HR_FAILED(hResult))
|
|
goto exit;
|
|
|
|
for(i=0;i<lpAdrList->cEntries;i++)
|
|
{
|
|
if(lpfl->ulFlag[i] == MAPI_RESOLVED)
|
|
{
|
|
ULONG j = 0;
|
|
LPSPropValue lpProp = lpAdrList->aEntries[i].rgPropVals;
|
|
|
|
for(j=0; j<lpAdrList->aEntries[i].cValues; j++)
|
|
{
|
|
if(lpProp[j].ulPropTag == PR_ENTRYID)
|
|
{
|
|
LPMAPIPROP lpMapiProp = NULL;
|
|
|
|
//ignore errors
|
|
lpDLWAB->lpVtbl->CreateEntry(lpDLWAB,
|
|
lpProp[j].Value.bin.cb,
|
|
(LPENTRYID) lpProp[j].Value.bin.lpb,
|
|
0,
|
|
&lpMapiProp);
|
|
|
|
if(lpMapiProp)
|
|
{
|
|
lpMapiProp->lpVtbl->SaveChanges(lpMapiProp, KEEP_OPEN_READWRITE | FORCE_SAVE);
|
|
lpMapiProp->lpVtbl->Release(lpMapiProp);
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
exit:
|
|
|
|
if (lpPropEID)
|
|
WABFreeBuffer(lpPropEID);
|
|
|
|
if (lpDLWAB)
|
|
lpDLWAB->lpVtbl->Release(lpDLWAB);
|
|
|
|
if(lpDistListWAB)
|
|
lpDistListWAB->lpVtbl->Release(lpDistListWAB);
|
|
|
|
if(lpAdrList)
|
|
WABFreePadrlist(lpAdrList);
|
|
|
|
if(lpfl)
|
|
LocalFree(lpfl);
|
|
|
|
return hResult;
|
|
}
|
|
|
|
HRESULT LDIFImport(HWND hWnd,
|
|
LPADRBOOK lpAdrBook,
|
|
LPWABOBJECT lpWABObject,
|
|
LPWAB_PROGRESS_CALLBACK lpProgressCB,
|
|
LPWAB_EXPORT_OPTIONS lpOptions) {
|
|
HRESULT hResult = hrSuccess;
|
|
TCHAR szFileName[MAX_PATH + 1] = "";
|
|
register ULONG i;
|
|
ULONG ulObjType;
|
|
ULONG index;
|
|
ULONG ulLastChosenProp = 0;
|
|
ULONG ulcFields = 0;
|
|
ULONG cAttributes = 0;
|
|
TCHAR szBuffer[MAX_RESOURCE_STRING + 1];
|
|
WAB_PROGRESS Progress;
|
|
LPABCONT lpContainer = NULL;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
LPLDIF_RECORD_ATTRIBUTE lpLDIFRecord = NULL;
|
|
LPSPropValue lpspv = NULL;
|
|
ULONG cProps;
|
|
BOOL fSkipSetProps;
|
|
LPTSTR lpDisplayName = NULL, lpEmailAddress = NULL;
|
|
BOOL fDoDistLists = FALSE;
|
|
|
|
SetGlobalBufferFunctions(lpWABObject);
|
|
|
|
// Get LDIF file name
|
|
OpenFileDialog(hWnd,
|
|
szFileName,
|
|
szLDIFFilter,
|
|
IDS_LDIF_FILE_SPEC,
|
|
szAllFilter,
|
|
IDS_ALL_FILE_SPEC,
|
|
NULL,
|
|
0,
|
|
szLDIFExt,
|
|
OFN_FILEMUSTEXIST | OFN_PATHMUSTEXIST,
|
|
hInst,
|
|
0, //idsTitle
|
|
0); // idsSaveButton
|
|
|
|
// Open the file
|
|
if ((hFile = CreateFile(szFileName,
|
|
GENERIC_READ,
|
|
FILE_SHARE_READ | FILE_SHARE_WRITE,
|
|
NULL,
|
|
OPEN_EXISTING,
|
|
FILE_FLAG_SEQUENTIAL_SCAN,
|
|
NULL)) == INVALID_HANDLE_VALUE) {
|
|
DebugTrace("Couldn't open file %s -> %u\n", szFileName, GetLastError());
|
|
return(ResultFromScode(MAPI_E_NOT_FOUND));
|
|
}
|
|
|
|
Assert(hFile != INVALID_HANDLE_VALUE);
|
|
|
|
// Read in the LDIF version if there is one
|
|
// BUGBUG: NYI
|
|
|
|
|
|
|
|
//
|
|
// Open the WAB's PAB container: fills global lpCreateEIDsWAB
|
|
//
|
|
if (hResult = LoadWABEIDs(lpAdrBook, &lpContainer)) {
|
|
goto exit;
|
|
}
|
|
|
|
if( HR_FAILED(hResult = HrLoadPrivateWABProps(lpAdrBook) ))
|
|
{
|
|
goto exit;
|
|
}
|
|
|
|
//
|
|
// All set... now loop through the records, adding each to the WAB
|
|
//
|
|
|
|
// How many records are there?
|
|
if (hResult = CountLDIFRecords(hFile, &ulcEntries)) {
|
|
goto exit;
|
|
}
|
|
|
|
// Initialize the Progress Bar
|
|
Progress.denominator = max(ulcEntries, 1);
|
|
Progress.numerator = 0;
|
|
if (LoadString(hInst, IDS_STATE_IMPORT_MU, szBuffer, sizeof(szBuffer))) {
|
|
DebugTrace("Status Message: %s\n", szBuffer);
|
|
Progress.lpText = szBuffer;
|
|
} else {
|
|
DebugTrace("Cannot load resource string %u\n", IDS_STATE_IMPORT_MU);
|
|
Progress.lpText = NULL;
|
|
}
|
|
lpProgressCB(hWnd, &Progress);
|
|
|
|
|
|
// We will make 2 passes over the file - in the first pass we will import all the
|
|
// contacts. In the second pass we will import all the distribution lists .. the
|
|
// advantage of doing 2 passes is that when importing contacts, we will prompt on
|
|
// conflict and then when importing distlists, we will assume all contacts in the
|
|
// WAB are correct and just point to the relevant ones
|
|
|
|
fDoDistLists = FALSE;
|
|
|
|
DoDistLists:
|
|
|
|
SetFilePointer(hFile, 0, NULL, FILE_BEGIN);
|
|
|
|
while (HR_SUCCEEDED(hResult))
|
|
{
|
|
lpDisplayName = NULL;
|
|
lpEmailAddress = NULL;
|
|
lpspv = NULL;
|
|
cAttributes = cProps = 0;
|
|
lpLDIFRecord = NULL;
|
|
|
|
// Read the LDIF attributes
|
|
if (hResult = ReadLDIFRecord(hFile, &cAttributes, &lpLDIFRecord)) {
|
|
DebugTrace("ReadLDIFRecord -> %x\n", GetScode(hResult));
|
|
if (GetScode(hResult) == MAPI_E_NOT_FOUND) {
|
|
// EOF
|
|
hResult = hrSuccess;
|
|
}
|
|
break; // nothing more to read
|
|
}
|
|
|
|
// Map the LDIF attributes to WAB properties
|
|
if (hResult = MapLDIFtoProps(lpLDIFRecord, cAttributes, &lpspv, &cProps,
|
|
&lpDisplayName, &lpEmailAddress, &ulObjType)) {
|
|
goto exit;
|
|
}
|
|
|
|
DebugTrace("..Importing..%s..%s..\n",lpDisplayName?lpDisplayName:"",lpEmailAddress?lpEmailAddress:"");
|
|
|
|
if(ulObjType == MAPI_MAILUSER && !fDoDistLists)
|
|
{
|
|
hResult = HrAddLDIFMailUser(hWnd, lpContainer,
|
|
lpDisplayName, lpEmailAddress,
|
|
cProps, lpspv,
|
|
lpProgressCB, lpOptions);
|
|
// Update progress bar
|
|
Progress.numerator++;
|
|
}
|
|
else if(ulObjType == MAPI_DISTLIST && fDoDistLists)
|
|
{
|
|
hResult = HrAddLDIFDistList(hWnd, lpContainer,
|
|
cAttributes, lpLDIFRecord,
|
|
lpDisplayName, lpEmailAddress,
|
|
cProps, lpspv,
|
|
lpProgressCB, lpOptions);
|
|
// Update progress bar
|
|
Progress.numerator++;
|
|
}
|
|
|
|
if(HR_FAILED(hResult))
|
|
goto exit;
|
|
|
|
// Clean up
|
|
if (lpLDIFRecord)
|
|
{
|
|
FreeLDIFRecord(lpLDIFRecord, cAttributes);
|
|
lpLDIFRecord = NULL;
|
|
}
|
|
|
|
Assert(Progress.numerator <= Progress.denominator);
|
|
|
|
if (lpspv)
|
|
{
|
|
WABFreeBuffer(lpspv);
|
|
lpspv = NULL;
|
|
}
|
|
|
|
lpProgressCB(hWnd, &Progress);
|
|
}
|
|
|
|
if(!fDoDistLists)
|
|
{
|
|
// Make a second pass doing only distlists this time
|
|
fDoDistLists = TRUE;
|
|
goto DoDistLists;
|
|
}
|
|
|
|
if (! HR_FAILED(hResult)) {
|
|
hResult = hrSuccess;
|
|
}
|
|
|
|
exit:
|
|
if (hFile) {
|
|
CloseHandle(hFile);
|
|
}
|
|
|
|
if (lpspv) {
|
|
WABFreeBuffer(lpspv);
|
|
lpspv = NULL;
|
|
}
|
|
|
|
if (lpLDIFRecord) {
|
|
FreeLDIFRecord(lpLDIFRecord, cAttributes);
|
|
lpLDIFRecord = NULL;
|
|
}
|
|
|
|
if (lpContainer) {
|
|
lpContainer->lpVtbl->Release(lpContainer);
|
|
lpContainer = NULL;
|
|
}
|
|
|
|
if (lpCreateEIDsWAB) {
|
|
WABFreeBuffer(lpCreateEIDsWAB);
|
|
lpCreateEIDsWAB = NULL;
|
|
}
|
|
|
|
|
|
return(hResult);
|
|
}
|
|
|
|
|
|
|
|
const int base642six[256]={
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,62,64,64,64,63,
|
|
52,53,54,55,56,57,58,59,60,61,64,64,64,64,64,64,64,0,1,2,3,4,5,6,7,8,9,
|
|
10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,64,64,64,64,64,64,26,27,
|
|
28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,
|
|
64,64,64,64,64,64,64,64,64,64,64,64,64
|
|
};
|
|
|
|
//-------------------------------------------------------------------------------------------
|
|
// Function: decode()
|
|
//-------------------------------------------------------------------------------------------
|
|
BOOL decodeBase64( char * bufcoded, // in
|
|
char * pbuffdecoded, // out
|
|
DWORD * pcbDecoded) // in out
|
|
{
|
|
int nbytesdecoded;
|
|
char *bufin;
|
|
unsigned char *bufout;
|
|
int nprbytes;
|
|
const int *rgiDict = base642six;
|
|
|
|
/* Strip leading whitespace. */
|
|
|
|
while(*bufcoded==' ' || *bufcoded == '\t') bufcoded++;
|
|
|
|
/* Figure out how many characters are in the input buffer.
|
|
* If this would decode into more bytes than would fit into
|
|
* the output buffer, adjust the number of input bytes downwards.
|
|
*/
|
|
bufin = bufcoded;
|
|
while(rgiDict[*(bufin++)] <= 63);
|
|
nprbytes = (int) (bufin - bufcoded - 1);
|
|
nbytesdecoded = ((nprbytes+3)/4) * 3;
|
|
|
|
if ( pcbDecoded )
|
|
*pcbDecoded = nbytesdecoded;
|
|
|
|
bufout = (unsigned char *)pbuffdecoded;
|
|
|
|
bufin = bufcoded;
|
|
|
|
while (nprbytes > 0) {
|
|
*(bufout++) =
|
|
(unsigned char) (rgiDict[*bufin] << 2 | rgiDict[bufin[1]] >> 4);
|
|
*(bufout++) =
|
|
(unsigned char) (rgiDict[bufin[1]] << 4 | rgiDict[bufin[2]] >> 2);
|
|
*(bufout++) =
|
|
(unsigned char) (rgiDict[bufin[2]] << 6 | rgiDict[bufin[3]]);
|
|
bufin += 4;
|
|
nprbytes -= 4;
|
|
}
|
|
|
|
if(nprbytes & 03) {
|
|
if(rgiDict[bufin[-2]] > 63)
|
|
nbytesdecoded -= 2;
|
|
else
|
|
nbytesdecoded -= 1;
|
|
}
|
|
|
|
((CHAR *)pbuffdecoded)[nbytesdecoded] = '\0';
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
- HrLoadPrivateWABProps
|
|
-
|
|
* Private function to load Conferencing Named properties
|
|
* as globals up front
|
|
*
|
|
*
|
|
*/
|
|
HRESULT HrLoadPrivateWABProps(LPADRBOOK lpIAB)
|
|
{
|
|
HRESULT hr = E_FAIL;
|
|
LPSPropTagArray lpta = NULL;
|
|
SCODE sc = 0;
|
|
ULONG i, uMax = prWABConfMax, nStartIndex = OLK_NAMEDPROPS_START;
|
|
LPMAPINAMEID *lppConfPropNames = NULL;
|
|
|
|
sc = WABAllocateBuffer(sizeof(LPMAPINAMEID) * uMax, (LPVOID *) &lppConfPropNames);
|
|
//sc = WABAllocateBuffer(sizeof(LPMAPINAMEID) * uMax, (LPVOID *) &lppConfPropNames);
|
|
if( (HR_FAILED(hr = ResultFromScode(sc))) )
|
|
goto err;
|
|
|
|
for(i=0;i< uMax;i++)
|
|
{
|
|
//sc = WABAllocateMore(sizeof(MAPINAMEID), lppConfPropNames, &(lppConfPropNames[i]));
|
|
sc = WABAllocateMore( sizeof(MAPINAMEID), lppConfPropNames, &(lppConfPropNames[i]));
|
|
if(sc)
|
|
{
|
|
hr = ResultFromScode(sc);
|
|
goto err;
|
|
}
|
|
lppConfPropNames[i]->lpguid = (LPGUID) &PS_Conferencing;
|
|
lppConfPropNames[i]->ulKind = MNID_ID;
|
|
lppConfPropNames[i]->Kind.lID = nStartIndex + i;
|
|
}
|
|
// Load the set of conferencing named props
|
|
//
|
|
if( HR_FAILED(hr = (lpIAB)->lpVtbl->GetIDsFromNames(lpIAB, uMax, lppConfPropNames,
|
|
MAPI_CREATE, &lpta) ))
|
|
goto err;
|
|
|
|
if(lpta)
|
|
// Set the property types on the returned props
|
|
PR_SERVERS = CHANGE_PROP_TYPE(lpta->aulPropTag[prWABConfServers], PT_MV_TSTRING);
|
|
rgPropNames[NUM_MORE_EXPORT_PROPS-1].ulPropTag = PR_SERVERS;
|
|
rgPropNames[NUM_MORE_EXPORT_PROPS-1].fChosen = FALSE;
|
|
rgPropNames[NUM_MORE_EXPORT_PROPS-1].ids = ids_ExportConfServer;
|
|
rgPropNames[NUM_MORE_EXPORT_PROPS-1].lpszName = NULL;
|
|
rgPropNames[NUM_MORE_EXPORT_PROPS-1].lpszCSVName = NULL;
|
|
|
|
err:
|
|
if(lpta)
|
|
WABFreeBuffer( lpta );
|
|
if( lppConfPropNames )
|
|
WABFreeBuffer( lppConfPropNames );
|
|
//WABFreeBuffer(lpta);
|
|
return hr;
|
|
}
|