/* * Messengr.C * * Migrate Communicator Messenger NAB <-> WAB * * Copyright 1997 Microsoft Corporation. All Rights Reserved. * * To Do: * ObjectClass recognition * Attribute mapping * Groups * Base64 * URLs * Reject Change List MESS * */ #include "_comctl.h" #include #include #include #include #include #include #include #include #include "wabimp.h" #include "..\..\wab32res\resrc2.h" #include "dbgutil.h" #include #define CR_CHAR 0x0d #define LF_CHAR 0x0a #define CCH_READ_BUFFER 1024 #define NUM_ITEM_SLOTS 32 /* Messenger address header 8-Display Name. 8-Nickname. 2-? 8-First Name. 8-? 8-last Name 8-Organization 8- City 8-State 8-e-mail 8- Notes 1- FF 8-Title 8-Address1 8-Zip 8-Work Phone 8-Fax 8- House phone. 18-? 8-Address 8-Country. */ typedef enum _MESS_ATTRIBUTES { // PR_DISPLAY_NAME m_DisplayName, // PR_NICKNAME m_Nickname, // Netscape nickname //PR_GIVEN_NAME m_FirstName, //PR_SURNAME m_LastName, //PR_COMPANY_NAME m_Organization, // PR_LOCALITY m_City, // locality (city) // PR_STATE_OR_PROVINCE m_State, // business address state // PR_EMAIL_ADDRESS m_Email, // email address // PR_COMMENT m_Notes, //PR_TITLE, m_Title, // PR_STREET_ADDRESS m_StreetAddress2, // PR_POSTAL_CODE m_Zip, // business address zip code // PR_BUSINESS_TELEPHONE_NUMBER m_WorkPhone, // PR_BUSINESS_FAX_NUMBER m_Fax, // PR_HOME_TELEPHONE_NUMBER m_HomePhone, // PR_STREET_ADDRESS m_StreetAddress1, // PR_COUNTRY m_Country, // country m_Max, } MESS_ATTRIBUTES, *LPMESS_ATTRIBUTES; ULONG ulDefPropTags[] = { PR_DISPLAY_NAME, PR_NICKNAME, PR_GIVEN_NAME, PR_SURNAME, PR_COMPANY_NAME, PR_LOCALITY, PR_STATE_OR_PROVINCE, PR_EMAIL_ADDRESS, PR_COMMENT, PR_TITLE, PR_STREET_ADDRESS, PR_POSTAL_CODE, PR_BUSINESS_TELEPHONE_NUMBER, PR_BUSINESS_FAX_NUMBER, PR_HOME_TELEPHONE_NUMBER, PR_STREET_ADDRESS, PR_COUNTRY, }; // All props are string props typedef struct _MESS_RECORD { LPTSTR lpData[m_Max]; ULONG ulObjectType; } MESS_RECORD, *LPMESS_RECORD; typedef struct _MESS_HEADER_ATTRIBUTES { ULONG ulOffSet; ULONG ulSize; } MH_ATTR, * LPMH_ATTR; typedef struct _MESS_BASIC_PROPS { LPTSTR lpName; LPTSTR lpEmail; LPTSTR lpComment; } MP_BASIC, * LPMP_BASIC; typedef struct _MESS_STUFF { ULONG ulOffSet; ULONG ulNum; MP_BASIC bp; } MH_STUFF, * LPMH_STUFF; typedef struct _MESS_ADDRESS_HEADER { MH_ATTR prop[m_Max]; } MESS_HEADER, * LPMESS_HEADER; // Must have // PR_DISPLAY_NAME #define NUM_MUST_HAVE_PROPS 1 const TCHAR szMESSFilter[] = "*.nab"; const TCHAR szMESSExt[] = "nab"; /***************************************************************** HrCreateAdrListFromMESSRecord Scans an MESS record and turns all the "members" into an unresolved AdrList ******************************************************************/ HRESULT HrCreateAdrListFromMESSRecord(ULONG nMembers, LPMP_BASIC lpmp, LPADRLIST * lppAdrList) { HRESULT hr = S_OK; ULONG i; LPADRLIST lpAdrList = NULL; ULONG ulCount = 0; *lppAdrList = NULL; 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; ulCount = nMembers; nMembers = 0; for(i=0;iaEntries[nMembers].cValues = (lpEmail ? 2 : 1); lpAdrList->aEntries[nMembers].rgPropVals = lpProp; nMembers++; } } lpAdrList->cEntries = nMembers; *lppAdrList = lpAdrList; exit: if(HR_FAILED(hr) && lpAdrList) WABFreePadrlist(lpAdrList); return hr; } /***************************************************************** HraddMESSDistList - 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 HrAddMESSDistList(HWND hWnd, LPABCONT lpContainer, MH_STUFF HeadDL, ULONG ulcNumDLMembers, LPMP_BASIC lpmp, 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; SPropValue Prop[3]; ULONG cProps = 0; LPTSTR lpDisplayName = HeadDL.bp.lpName; Prop[cProps].ulPropTag = PR_DISPLAY_NAME; Prop[cProps].Value.LPSZ = HeadDL.bp.lpName; if(!HeadDL.bp.lpName) return MAPI_E_INVALID_PARAMETER; cProps++; Prop[cProps].ulPropTag = PR_OBJECT_TYPE; Prop[cProps].Value.l = MAPI_DISTLIST; cProps++; if(HeadDL.bp.lpComment) { Prop[cProps].ulPropTag = PR_COMMENT; Prop[cProps].Value.LPSZ = HeadDL.bp.lpComment; cProps++; } //if (lpOptions->ReplaceOption == WAB_REPLACE_ALWAYS) // Force a replace - collision will only be for groups and we dont care really { 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 (LPSPropValue) &Prop, // property array NULL))) // problems array { 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; } if(!ulcNumDLMembers) { hResult = S_OK; 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 = HrCreateAdrListFromMESSRecord(ulcNumDLMembers, lpmp, &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;icEntries;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;icEntries;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(hResult==MAPI_E_AMBIGUOUS_RECIP) hResult = S_OK; if(HR_FAILED(hResult)) goto exit; for(i=0;icEntries;i++) { if(lpfl->ulFlag[i] == MAPI_RESOLVED) { ULONG j = 0; LPSPropValue lpProp = lpAdrList->aEntries[i].rgPropVals; for(j=0; jaEntries[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; } /********************************************************* HraddMESSMailUser - adds a mailuser to the WAB **********************************************************/ HRESULT HrAddMESSMailUser(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; } // Set the properties on the new WAB entry if (HR_FAILED(hResult = lpMailUserWAB->lpVtbl->SetProps( lpMailUserWAB, cProps, // cValues lpspv, // property array NULL))) // problems array { 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; } /*************************************************************************** Name : MapMESSRecordtoProps Purpose : Map the MESS record attributes to WAB properties Parameters: lpMESSRecord -> MESS 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 MapMESSRecordtoProps( LPMESS_RECORD lpMESSRecord, LPSPropValue * lppspv, LPULONG lpcProps, LPTSTR * lppDisplayName, LPTSTR *lppEmailAddress) { HRESULT hResult = hrSuccess; ULONG cPropVals = m_Max + 1; // PR_OBJECT_TYPE ULONG iProp = 0; ULONG i; ULONG iTable; ULONG cProps = cPropVals; // Allocate prop value array if (hResult = ResultFromScode(WABAllocateBuffer(cProps * sizeof(SPropValue), lppspv))) { DebugTrace("WABAllocateBuffer -> %x\n", GetScode(hResult)); goto exit; } // Fill with PR_NULL for (i = 0; i < cProps; i++) { (*lppspv)[i].ulPropTag = PR_NULL; } iProp = 0; for(i=0; ilpData[i] && lstrlen(lpMESSRecord->lpData[i])) { (*lppspv)[iProp].ulPropTag = ulDefPropTags[i]; (*lppspv)[iProp].Value.LPSZ = lpMESSRecord->lpData[i]; switch((*lppspv)[iProp].ulPropTag) { case PR_DISPLAY_NAME: *lppDisplayName = (*lppspv)[iProp].Value.LPSZ; break; case PR_EMAIL_ADDRESS: *lppEmailAddress = (*lppspv)[iProp].Value.LPSZ; break; } iProp++; } } (*lppspv)[iProp].ulPropTag = PR_OBJECT_TYPE; (*lppspv)[iProp].Value.l = lpMESSRecord->ulObjectType; *lpcProps = iProp; exit: return(hResult); } /*************************************************************************** Name : FreeMESSRecord Purpose : Frees an MESS record structure Parameters: lpMESSRecord -> record to clean up ulAttributes = number of attributes in lpMESSRecord Returns : none Comment : ***************************************************************************/ void FreeMESSRecord(LPMESS_RECORD lpMESSRecord) { ULONG i; if (lpMESSRecord) { for (i = 0; i < m_Max; i++) { if (lpMESSRecord->lpData[i]) LocalFree(lpMESSRecord->lpData[i]); } LocalFree(lpMESSRecord); } } /*************************************************************************** FunctionName: GetOffSet Purpose : Gets 4 bytes from the offset specified. Parameters : hFile -pointer to the file Offset-Offset of the OffSetValue -the returned 4 bytes. Returns : Note : ***************************************************************************/ BOOL GetOffSet(HANDLE hFile, DWORD Offset, ULONG* lpOffSetValue) { BYTE Value[4]; DWORD dwRead = 0; SetFilePointer(hFile, Offset, NULL, FILE_BEGIN); ReadFile(hFile, Value, 4, &dwRead, NULL); *(lpOffSetValue)= (ULONG)Value[0]*16777216 + (ULONG)Value[1]*65536 + (ULONG)Value[2]*256 + (ULONG)Value[3]; return TRUE; } /****************************************************************************** * FUNCTION NAME:GetMESSFileName * * PURPOSE: Gets the Messenger Address book file name * * PARAMETERS: szFileName = buffer containing the installation path // Messenger abook is generally abook.nab // Location can be found under // HKLM\Software\Netscape\Netscape Navigator\Users\defaultuser // Look for "DirRoot" * * RETURNS: HRESULT ******************************************************************************/ HRESULT GetNABPath(LPTSTR szFileName, DWORD cbFileName) { HKEY phkResult = NULL; LONG Registry; BOOL bResult; TCHAR *lpData = NULL, *RegPath = NULL, *path = NULL; DWORD dwSize = cbFileName; LPTSTR lpRegMess = TEXT("Software\\Netscape\\Netscape Navigator\\Users"); LPTSTR lpRegUser = TEXT("CurrentUser"); LPTSTR lpRegKey = TEXT("DirRoot"); LPTSTR lpNABFile = TEXT("\\abook.nab"); HRESULT hResult = S_OK; TCHAR szUser[MAX_PATH]; TCHAR szUserPath[2*MAX_PATH]; *szFileName = '\0'; *szUser ='\0'; // Open the Netscape..Users key Registry = RegOpenKeyEx(HKEY_LOCAL_MACHINE, lpRegMess, 0, KEY_QUERY_VALUE, &phkResult); if (Registry != ERROR_SUCCESS) { hResult = E_FAIL; goto error; } // Look for the CurrentUser dwSize = sizeof(szUser); Registry = RegQueryValueEx(phkResult, lpRegUser, NULL, NULL, (LPBYTE)szUser, &dwSize); if (Registry != ERROR_SUCCESS) { hResult = E_FAIL; goto error; } if(!lstrlen(szUser)) { hResult = E_FAIL; goto error; } if (phkResult) { RegCloseKey(phkResult); } //Now concatenate the currentuser to the end of the Netscape key and reopen StrCpyN(szUserPath, lpRegMess, ARRAYSIZE(szUserPath)); StrCatBuff(szUserPath, TEXT("\\"), ARRAYSIZE(szUserPath)); StrCatBuff(szUserPath, szUser, ARRAYSIZE(szUserPath)); // Open the Netscape..Users key Registry = RegOpenKeyEx(HKEY_LOCAL_MACHINE, szUserPath, 0, KEY_QUERY_VALUE, &phkResult); if (Registry != ERROR_SUCCESS) { hResult = E_FAIL; goto error; } dwSize = cbFileName; Registry = RegQueryValueEx(phkResult, lpRegKey, NULL, NULL, (LPBYTE)szFileName, &dwSize); if (Registry != ERROR_SUCCESS) { hResult = E_FAIL; goto error; } // concatenate the file name to this directory path StrCatBuff(szFileName,lpNABFile, cbFileName/sizeof(szFileName[0])); error: if (phkResult) { RegCloseKey(phkResult); } return(hResult); } HRESULT ReadMESSHeader(HANDLE hFile, LPMESS_HEADER lpmh, ULONG ulOffSet) { ULONG ulMagicNumber = 0; HRESULT hr = E_FAIL; DWORD dwRead; ULONG i = 0; // Skip 2 bytes SetFilePointer(hFile, 2, NULL, FILE_CURRENT); ulOffSet += 2; GetOffSet(hFile, ulOffSet, &ulMagicNumber); if(ulMagicNumber != 0x00000001 ) goto exit; ulOffSet += 4; for(i=0;iprop[i].ulOffSet)); ulOffSet += 4; GetOffSet(hFile, ulOffSet, &(lpmh->prop[i].ulSize)); ulOffSet += 4; } hr = S_OK; exit: return hr; } /*************************************************************************** FunctionName: GetHeaders Purpose :Reads the binary trees ( address binary tree or Dls binary tree) into an array. Parameters : nLayer= Number of layers in the binary tree. Offset= Primary offset of the binary tree. pHeaders= Array in which the Address entry header offsets and their numbers are to be stored. bflag = 1 should be passed when this recursive function is called for the first time. Returns : Note : //This function is a recursive function which reads the binary tree and stores the Offset values and the address numbers in a Array. ***************************************************************************/ BOOL GetHeaders(HANDLE pFile, int nLayer, ULONG Offset, LPMH_STUFF pHeaders, BOOL bflag) { static ULONG ulCount =0; //keeps trecat of the number of element ULONG nLoops =0; ULONG ulNewOffset =0; ULONG ulElement = 0; if(bflag==1) ulCount =0; //get the number of elements in this header if(Offset==0) nLoops=32; else { GetOffSet( pFile, Offset+4,&nLoops); nLoops &= 0x0000FFFF; } for(ulElement = 0; ulElement < nLoops; ulElement++) { if(nLayer > 0) { ulNewOffset=0; if(Offset!=0) { GetOffSet(pFile, Offset+8+(ulElement*4), &ulNewOffset); { ULONG ulMagicNumber=0; GetOffSet(pFile,ulNewOffset+2,&ulMagicNumber); if(ulMagicNumber != 1) ulNewOffset = 0; } } //call this function recursively GetHeaders( pFile, nLayer-1, ulNewOffset, pHeaders, 0); } else { //fill the array here (offset) pHeaders[ulCount].ulOffSet=pHeaders[ulCount].ulNum=0; if(Offset!=0) { GetOffSet(pFile, Offset+8+(ulElement*8),& (pHeaders[ulCount].ulOffSet)); //fill the array element here (address number in case of addresses and size in case of messages) if(!GetOffSet(pFile, Offset+12+(ulElement*8), &(pHeaders[ulCount].ulNum))) { pHeaders[ulCount].ulNum=0; } } ulCount++; //increment the count } } return TRUE; } /*************************************************************************** Name : ReadMESSRecord Purpose : Reads a record from an MESS file with fixups for special characters Parameters: hFile = file handle Returns : HRESULT ***************************************************************************/ HRESULT ReadMESSRecord(HANDLE hFile, LPMESS_RECORD * lppMESSRecord, ULONG ulContactOffset) { HRESULT hResult = hrSuccess; PUCHAR lpBuffer = NULL; ULONG cbBuffer = 0; ULONG cbReadFile = 1; ULONG iItem = 0; ULONG cAttributes = 0; BOOL fEOR = FALSE; LPMESS_RECORD lpMESSRecord = NULL; LPBYTE lpData = NULL; LPTSTR lpName = NULL; ULONG cbData; TCHAR szTemp[2048]; // 2k limit ULONG i = 0; DWORD dwRead = 0; ULONG cchSize = 0; MESS_HEADER mh = {0}; // The Contact Offset gives us the offset of the header for this record - the // header contains the offset and the size of each property for that address if(hResult = ReadMESSHeader(hFile, &mh, ulContactOffset)) goto exit; lpMESSRecord = LocalAlloc(LMEM_ZEROINIT, sizeof(MESS_RECORD)); if(!lpMESSRecord) { hResult = MAPI_E_NOT_ENOUGH_MEMORY; goto exit; } lpMESSRecord->ulObjectType = MAPI_MAILUSER; for(i=0;ilpData[i] = LocalAlloc(LMEM_ZEROINIT, cchSize); } else lpMESSRecord->lpData[i] = LocalAlloc(LMEM_ZEROINIT, mh.prop[i].ulSize); if(lpMESSRecord->lpData[i]) { SetFilePointer(hFile, mh.prop[i].ulOffSet, NULL, FILE_BEGIN); ReadFile(hFile, (LPVOID) lpMESSRecord->lpData[i], mh.prop[i].ulSize, &dwRead, NULL); lpMESSRecord->lpData[i][mh.prop[i].ulSize-1] = '\0'; } } } //Fix the fact that the street address is split into street1 and street2 if(lpMESSRecord->lpData[m_StreetAddress1] && lpMESSRecord->lpData[m_StreetAddress2] && lstrlen(lpMESSRecord->lpData[m_StreetAddress1]) && lstrlen(lpMESSRecord->lpData[m_StreetAddress2])) { StrCatBuff(lpMESSRecord->lpData[m_StreetAddress1], TEXT("\r\n"), cchSize); StrCatBuff(lpMESSRecord->lpData[m_StreetAddress1], lpMESSRecord->lpData[m_StreetAddress2], cchSize); LocalFree(lpMESSRecord->lpData[m_StreetAddress2]); lpMESSRecord->lpData[m_StreetAddress2] = NULL; } *lppMESSRecord = lpMESSRecord; exit: return(hResult); } /*************************************************************************** GetAllDLNames Purpose : Gets the Names of all the DLs. Note : ***************************************************************************/ BOOL GetAllDLNames(HANDLE pFile, ULONG nDLs, LPMH_STUFF pHeadersDL) { ULONG i = 0; for(i=0;i 0) { ulNewOffset=0; if(POffset!=0) GetOffSet(pFile, POffset+8+(ulElement*4), &ulNewOffset); //call this function recursively GetDLEntryNumbers(pFile,nLayer-1, ulNewOffset,ulNumOfEntries,pEntryNumbers,0); } else { //fill the array here (offset) pEntryNumbers[ulCount]=0; if(POffset!=0) GetOffSet(pFile, POffset+8+(ulElement*4),&(pEntryNumbers[ulCount])); ulCount++; //increment the count if(ulCount>(*ulNumOfEntries)) { *ulNumOfEntries=ulCount; return TRUE; } } } return TRUE; } /*************************************************************************** FunctionName: GetDLEntries Purpose : Gets the entries of a DL. Note : ***************************************************************************/ BOOL GetDLEntries(HANDLE pFile, LPMH_STUFF pHeadAdd, ULONG ulAddCount, LPMH_STUFF pHeadDL, ULONG ulDLCount, ULONG ulDLOffset, ULONG nIndex, ULONG * lpulDLNum, LPMP_BASIC * lppmp) { ULONG ulDLEntHeaderOffSet=0;//offset of the header of DL entries(Header which has the entry numbers ULONG ulDLEntriesCount=0; ULONG ulDLEntryOffSet=0; //offset of the Dl entry ULONG ulDLEntryNumber=0; //Number of DL entry ULONG ulDLEntryNameOffSet=0; ULONG ulDLEntryNameSize=0; ULONG * lpulDLEntryNumbers = NULL; int nLevelCount=0; int utemp=32; DWORD dwRead = 0; ULONG i, j; LPMP_BASIC lpmp = NULL; if(FALSE==GetOffSet(pFile,ulDLOffset+24,&ulDLEntriesCount)) return FALSE; if(!ulDLEntriesCount) // no members return TRUE; *lpulDLNum = ulDLEntriesCount; //alocate the array of string pointers which hold the names of the DL entries. lpmp = LocalAlloc(LMEM_ZEROINIT, sizeof(MP_BASIC) * ulDLEntriesCount); //get the entries here //first get the offset of the header which has the DL entry numbers. if(FALSE==GetOffSet(pFile,ulDLOffset+28,&ulDLEntHeaderOffSet)) return FALSE; lpulDLEntryNumbers = LocalAlloc(LMEM_ZEROINIT, sizeof(ULONG) * ulDLEntriesCount); if(!lpulDLEntryNumbers) return FALSE; nLevelCount=0; utemp=32; while(utemp <(int) ulDLEntriesCount) { utemp *= 32; nLevelCount++; } if(!(GetDLEntryNumbers(pFile, nLevelCount, ulDLEntHeaderOffSet, &ulDLEntriesCount, lpulDLEntryNumbers, 1))) { return FALSE; } for(i=0;i %u\n", szFileName, err); // BEGIN DELTA for BUG 1804 // if the file is locked (e.g. netscape AB in use) if( err == ERROR_SHARING_VIOLATION ) return(ResultFromScode(MAPI_E_BUSY)); // else return a generic error for generic msg return(ResultFromScode(MAPI_E_NOT_FOUND)); // END DELTA for BUG 1804 } Assert(hFile != INVALID_HANDLE_VALUE); // // Open the WAB's PAB container: fills global lpCreateEIDsWAB // if (hResult = LoadWABEIDs(lpAdrBook, &lpContainer)) { goto exit; } // // All set... now loop through the records, adding each to the WAB // GetOffSet(hFile,0x185,&nEntries); GetOffSet(hFile,0x1d8,&nDLs); GetOffSet(hFile,0x195,&nContactOffset); GetOffSet(hFile,0x1e8,&nDLOffset); ulcEntries = nEntries + nDLs; if(!ulcEntries) { hResult = S_OK; 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 if(nEntries) { SetFilePointer(hFile, 0, NULL, FILE_BEGIN); pHeadersAdd = LocalAlloc(LMEM_ZEROINIT, nEntries * sizeof(MH_STUFF)); if(!pHeadersAdd) { hResult = MAPI_E_NOT_ENOUGH_MEMORY; goto exit; } utemp = 32; nLevelCountAdd = 0; while(utemp <(int) nEntries) { utemp *= 32; nLevelCountAdd++; } if(!GetHeaders(hFile ,nLevelCountAdd, nContactOffset, pHeadersAdd, 1)) { goto exit; } for(i=0;i %x\n", GetScode(hResult)); continue; } if (hResult = MapMESSRecordtoProps( lpMESSRecord, &lpspv, &cProps, &lpDisplayName, &lpEmailAddress)) { DebugTrace("MapMESSRecordtoProps -> %x\n", GetScode(hResult)); continue; } hResult = HrAddMESSMailUser(hWnd, lpContainer, lpDisplayName, lpEmailAddress, cProps, lpspv, lpProgressCB, lpOptions); //if(HR_FAILED(hResult)) if(hResult == MAPI_E_USER_CANCEL) goto exit; // Update progress bar Progress.numerator++; Assert(Progress.numerator <= Progress.denominator); if(lpDisplayName && lstrlen(lpDisplayName)) { pHeadersAdd[i].bp.lpName = LocalAlloc(LMEM_ZEROINIT, lstrlen(lpDisplayName)+1); if(pHeadersAdd[i].bp.lpName) StrCpyN(pHeadersAdd[i].bp.lpName, lpDisplayName, lstrlen(lpDisplayName)+1); } if(lpEmailAddress && lstrlen(lpEmailAddress)) { pHeadersAdd[i].bp.lpEmail = LocalAlloc(LMEM_ZEROINIT, lstrlen(lpEmailAddress)+1); if(pHeadersAdd[i].bp.lpEmail) StrCpyN(pHeadersAdd[i].bp.lpEmail, lpEmailAddress, lstrlen(lpEmailAddress)+1); } if (lpMESSRecord) { FreeMESSRecord(lpMESSRecord); lpMESSRecord = NULL; } if (lpspv) { int j; for(j=0;jlpVtbl->Release(lpContainer); lpContainer = NULL; } if (lpCreateEIDsWAB) { WABFreeBuffer(lpCreateEIDsWAB); lpCreateEIDsWAB = NULL; } return(hResult); }