/* * ABROOT.C * * IMAPIContainer implementation for the address book's root * container. */ #include "_apipch.h" extern SPropTagArray sosPR_ROWID; /* * Root jump table is defined here... */ ROOT_Vtbl vtblROOT = { VTABLE_FILL (ROOT_QueryInterface_METHOD *) CONTAINER_QueryInterface, (ROOT_AddRef_METHOD *) WRAP_AddRef, (ROOT_Release_METHOD *) CONTAINER_Release, (ROOT_GetLastError_METHOD *) IAB_GetLastError, (ROOT_SaveChanges_METHOD *) WRAP_SaveChanges, (ROOT_GetProps_METHOD *) WRAP_GetProps, (ROOT_GetPropList_METHOD *) WRAP_GetPropList, (ROOT_OpenProperty_METHOD *) CONTAINER_OpenProperty, (ROOT_SetProps_METHOD *) WRAP_SetProps, (ROOT_DeleteProps_METHOD *) WRAP_DeleteProps, (ROOT_CopyTo_METHOD *) WRAP_CopyTo, (ROOT_CopyProps_METHOD *) WRAP_CopyProps, (ROOT_GetNamesFromIDs_METHOD *) WRAP_GetNamesFromIDs, (ROOT_GetIDsFromNames_METHOD *) WRAP_GetIDsFromNames, ROOT_GetContentsTable, ROOT_GetHierarchyTable, ROOT_OpenEntry, ROOT_SetSearchCriteria, ROOT_GetSearchCriteria, ROOT_CreateEntry, ROOT_CopyEntries, ROOT_DeleteEntries, ROOT_ResolveNames }; // // Interfaces supported by this object // #define ROOT_cInterfaces 3 LPIID ROOT_LPIID[ROOT_cInterfaces] = { (LPIID)&IID_IABContainer, (LPIID)&IID_IMAPIContainer, (LPIID)&IID_IMAPIProp }; // Registry strings const LPTSTR szWABKey = TEXT("Software\\Microsoft\\WAB"); // PR_AB_PROVIDER_ID for Outlook static const MAPIUID muidCAB = {0xfd,0x42,0xaa,0x0a,0x18,0xc7,0x1a,0x10,0xe8,0x85,0x0B,0x65,0x1C,0x24,0x00,0x00}; /* - - SetContainerlpProps * * The ROOT container will have a bunch of entries with props for each entry * The props are set in one place here * lpProps - LPSPropValue array in which we are storing the props lpszName - Container name iRow - Row of this entry in the table (?) cb, lpb - entryid of the container lpEID - alternat way of passing in the EID ulContainerFlags - any flags we want to cache on the container ulDepth ? bProviderID ? bLDAP - identifies LDAP containers which need some extra props fLDAPResolve - whether the LDAP container is used for name resolution or not */ void SetContainerlpProps(LPSPropValue lpProps, LPTSTR lpszName, ULONG iRow, ULONG cb, LPBYTE lpb, LPSBinary lpEID, ULONG ulContainerFlags, ULONG ulDepth, BOOL bProviderID, ULONG ulFlags, BOOL bLDAP, BOOL fLDAPResolve) { LPSTR lpszNameA = NULL; if(!(ulFlags & MAPI_UNICODE)) // this assumes UNICODE is defined ScWCToAnsiMore((LPALLOCATEMORE) (&MAPIAllocateMore), lpProps, lpszName, &lpszNameA); DebugTrace(TEXT("Adding root-table container:%s\n"),lpszName); lpProps[ircPR_DISPLAY_TYPE].ulPropTag = PR_DISPLAY_TYPE; lpProps[ircPR_DISPLAY_TYPE].Value.l = DT_LOCAL; lpProps[ircPR_OBJECT_TYPE].ulPropTag = PR_OBJECT_TYPE; lpProps[ircPR_OBJECT_TYPE].Value.l = MAPI_ABCONT; lpProps[ircPR_ROWID].ulPropTag = PR_ROWID; lpProps[ircPR_ROWID].Value.l = iRow; lpProps[ircPR_DEPTH].ulPropTag = PR_DEPTH; lpProps[ircPR_DEPTH].Value.l = ulDepth; lpProps[ircPR_CONTAINER_FLAGS].ulPropTag = PR_CONTAINER_FLAGS; lpProps[ircPR_CONTAINER_FLAGS].Value.l = ulContainerFlags; if(bLDAP) { if(ulFlags & MAPI_UNICODE) // this assumes UNICODE is defined { lpProps[ircPR_WAB_LDAP_SERVER].ulPropTag = PR_WAB_LDAP_SERVER; lpProps[ircPR_WAB_LDAP_SERVER].Value.lpszW = lpszName; } else { lpProps[ircPR_WAB_LDAP_SERVER].ulPropTag = CHANGE_PROP_TYPE( PR_WAB_LDAP_SERVER, PT_STRING8); lpProps[ircPR_WAB_LDAP_SERVER].Value.lpszA = lpszNameA; } lpProps[ircPR_WAB_RESOLVE_FLAG].ulPropTag = PR_WAB_RESOLVE_FLAG; lpProps[ircPR_WAB_RESOLVE_FLAG].Value.b = (USHORT) !!fLDAPResolve; } else { lpProps[ircPR_WAB_LDAP_SERVER].ulPropTag = PR_NULL; lpProps[ircPR_WAB_RESOLVE_FLAG].ulPropTag = PR_NULL; } if(ulFlags & MAPI_UNICODE) // this assumes UNICODE is defined { lpProps[ircPR_DISPLAY_NAME].ulPropTag = PR_DISPLAY_NAME; lpProps[ircPR_DISPLAY_NAME].Value.lpszW = lpszName; } else { lpProps[ircPR_DISPLAY_NAME].ulPropTag = CHANGE_PROP_TYPE( PR_DISPLAY_NAME, PT_STRING8); lpProps[ircPR_DISPLAY_NAME].Value.lpszA = lpszNameA; } if(bProviderID) { lpProps[ircPR_AB_PROVIDER_ID].ulPropTag = PR_AB_PROVIDER_ID; lpProps[ircPR_AB_PROVIDER_ID].Value.bin.cb = sizeof(MAPIUID); lpProps[ircPR_AB_PROVIDER_ID].Value.bin.lpb = (LPBYTE)&muidCAB; } else { lpProps[ircPR_AB_PROVIDER_ID].ulPropTag = PR_NULL; } lpProps[ircPR_ENTRYID].ulPropTag = PR_ENTRYID; if(lpEID) lpProps[ircPR_ENTRYID].Value.bin = *lpEID; else { lpProps[ircPR_ENTRYID].Value.bin.cb = cb; lpProps[ircPR_ENTRYID].Value.bin.lpb = lpb; } // Make certain we have proper indicies. // For now, we will equate PR_INSTANCE_KEY and PR_RECORD_KEY to PR_ENTRYID. lpProps[ircPR_INSTANCE_KEY].ulPropTag = PR_INSTANCE_KEY; lpProps[ircPR_INSTANCE_KEY].Value.bin.cb = lpProps[ircPR_ENTRYID].Value.bin.cb; lpProps[ircPR_INSTANCE_KEY].Value.bin.lpb = lpProps[ircPR_ENTRYID].Value.bin.lpb; lpProps[ircPR_RECORD_KEY].ulPropTag = PR_RECORD_KEY; lpProps[ircPR_RECORD_KEY].Value.bin.cb = lpProps[ircPR_ENTRYID].Value.bin.cb; lpProps[ircPR_RECORD_KEY].Value.bin.lpb = lpProps[ircPR_ENTRYID].Value.bin.lpb; } /* - bIsDupeContainerName - * The Root_GetContentsTable fails badly if there are multiple containers * with the same index name because the Table methods can't handle it .. * * Therefore, to prevent such problems, we double-check if a container name * is duplicated before adding it to the container list. * */ BOOL bIsDupeContainerName(LPSRowSet lpsrs, LPTSTR lpszName) { ULONG i = 0; BOOL bRet = FALSE; // walk through the rows one by one for(i=0;icRows;i++) { LPSPropValue lpProps = lpsrs->aRow[i].lpProps; if(!lpProps || !lpsrs->aRow[i].cValues) continue; if( lpProps[ircPR_DISPLAY_NAME].ulPropTag == PR_DISPLAY_NAME && !lstrcmpi(lpProps[ircPR_DISPLAY_NAME].Value.LPSZ, lpszName)) { DebugTrace(TEXT("Found dupe container name .. skipping ...\n")); bRet = TRUE; break; } } return bRet; } /*************************************************** * * The actual ABContainer methods */ /* --------- * IMAPIContainer */ /************************************************************************* * * - ROOT_GetContentsTable - * * ulFlags - WAB_LOCAL_CONTAINERS means don't add the LDAP containers to this table * Just do the local WAB containers * WAB_NO_PROFILE_CONTAINERS means don't add the profile containers * Just add a single local container that will have all the contents * */ STDMETHODIMP ROOT_GetContentsTable(LPROOT lpROOT, ULONG ulFlags, LPMAPITABLE * lppTable) { LPTABLEDATA lpTableData = NULL; HRESULT hResult = hrSuccess; SCODE sc; LPSRowSet lpSRowSet = NULL; LPSPropValue lpProps = NULL; ULONG i; ULONG iRow; ULONG cProps, cRows, colkci = 0, cwabci = 0; ULONG cLDAPContainers = 0; TCHAR szBuffer[MAX_PATH]; IImnAccountManager2 * lpAccountManager = NULL; LPSERVER_NAME lpServerNames = NULL, lpNextServer; OlkContInfo *rgolkci, *rgwabci; LPPTGDATA lpPTGData=GetThreadStoragePointer(); BOOL bUserProfileContainersOnly = FALSE; BOOL bAllContactsContainerOnly = FALSE; // BUGBUG: This routine actually returns the Hierarchy table, not the // contents table, but too much code depends on this to change it right // now. #ifdef PARAMETER_VALIDATION // Check to see if it has a jump table if (IsBadReadPtr(lpROOT, sizeof(LPVOID))) { // No jump table found return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } // Check to see that it's ROOTs jump table if (lpROOT->lpVtbl != &vtblROOT) { // Not my jump table return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } if (ulFlags & ~(MAPI_DEFERRED_ERRORS|MAPI_UNICODE|WAB_LOCAL_CONTAINERS|WAB_NO_PROFILE_CONTAINERS)) { DebugTraceArg(ROOT_GetContentsTable, TEXT("Unknown flags")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS)); } if (IsBadWritePtr(lppTable, sizeof(LPMAPITABLE))) { DebugTraceArg(ROOT_GetContentsTable, TEXT("Invalid Table parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } #endif // PARAMETER_VALIDATION EnterCriticalSection(&lpROOT->lpIAB->cs); // Create a table object // [PaulHi] 4/5/99 Use the Internal CreateTableData() function that takes // the ulFlags and will deal with ANSI/UNICODE requests correctly sc = CreateTableData( NULL, (ALLOCATEBUFFER FAR * ) MAPIAllocateBuffer, (ALLOCATEMORE FAR *) MAPIAllocateMore, MAPIFreeBuffer, NULL, TBLTYPE_DYNAMIC, PR_RECORD_KEY, (LPSPropTagArray)&ITableColumnsRoot, NULL, 0, NULL, ulFlags, &lpTableData); if ( FAILED(sc) ) { DebugTrace(TEXT("CreateTableData() failed %x\n"), sc); hResult = ResultFromScode(sc); goto exit; } Assert(lpTableData); if(ulFlags & WAB_NO_PROFILE_CONTAINERS) bAllContactsContainerOnly = TRUE; if(ulFlags & MAPI_UNICODE) ((TAD *)lpTableData)->bMAPIUnicodeTable = TRUE; // Enumerate the LDAP accounts if(!(ulFlags & WAB_LOCAL_CONTAINERS)) { cLDAPContainers = 0; if (! HR_FAILED(hResult = InitAccountManager(lpROOT->lpIAB, &lpAccountManager, NULL))) { // Count and enumerate LDAP servers to ServerList if (hResult = EnumerateLDAPtoServerList(lpAccountManager, &lpServerNames, &cLDAPContainers)) { DebugTrace(TEXT("EnumerateLDAPtoServerList -> %x\n"), GetScode(hResult)); hResult = hrSuccess; // not fatal } } else { DebugTrace(TEXT("InitAccountManager -> %x\n"), GetScode(hResult)); hResult = hrSuccess; } } // If this is an outlook session then use the outlook's list of containers // as provided by outlook... if (pt_bIsWABOpenExSession) { colkci = lpROOT->lpIAB->lpPropertyStore->colkci; Assert(colkci); rgolkci = lpROOT->lpIAB->lpPropertyStore->rgolkci; Assert(rgolkci); } else colkci = 1; // If we have a user profile active, then dont return the virtual PAB folder // as part of this table .. only return the actual folders in the user's view // The test for this is that (1) Have Profiles enabled (2) Have a current user // and (3) The NO_PROFILE_CONTAINERS should not have been specified bUserProfileContainersOnly = ( bAreWABAPIProfileAware(lpROOT->lpIAB) && bIsThereACurrentUser(lpROOT->lpIAB) && !bAllContactsContainerOnly); // If we have Profile awareness and no NO_PROFILE flag, // use the wab's list of folder if (bAreWABAPIProfileAware(lpROOT->lpIAB) && !bAllContactsContainerOnly) { cwabci = lpROOT->lpIAB->cwabci; Assert(cwabci); rgwabci = lpROOT->lpIAB->rgwabci; Assert(rgwabci); } else cwabci = 1; // Since outlook and identity_profiles are mutually exclusive, we can // do '-1' here to remove whatever container we don't need // and if we don't want ldap containers, we can do another -1 cRows = cwabci + colkci + cLDAPContainers - 1 - (bUserProfileContainersOnly?1:0); // Outlook and Profiles are mutually exclusive iRow = 0; // current row // Allocate the SRowSet if (FAILED(sc = MAPIAllocateBuffer(sizeof(SRowSet) + cRows * sizeof(SRow), &lpSRowSet))) { DebugTrace(TEXT("Allocation of SRowSet -> %x\n"), sc); hResult = ResultFromScode(sc); goto exit; } MAPISetBufferName(lpSRowSet, TEXT("Root_ContentsTable SRowSet")); // Set each LPSRow to NULL so we can easily free on error ZeroMemory( lpSRowSet, (UINT) (sizeof(SRowSet) + cRows * sizeof(SRow))); lpSRowSet->cRows = cRows; cProps = ircMax; if (FAILED(sc = MAPIAllocateBuffer(ircMax * sizeof(SPropValue), &lpProps))) { DebugTrace(TEXT("ROOT_GetContentsTable: Allocation of props -> %x\n"), sc); hResult = ResultFromScode(sc); goto exit; } // // Add our PAB container // if(!bUserProfileContainersOnly) { // Load the display name from resource string if (!LoadString(hinstMapiX, IDS_ADDRBK_CAPTION, szBuffer, ARRAYSIZE(szBuffer))) StrCpyN(szBuffer, szEmpty, ARRAYSIZE(szBuffer)); { ULONG cb = 0; LPENTRYID lpb = NULL; if (HR_FAILED(hResult = CreateWABEntryID(WAB_PAB, NULL, NULL, NULL, 0, 0, lpProps, &cb, &lpb))) goto exit; // Set props for the pab object SetContainerlpProps(lpProps, pt_bIsWABOpenExSession ? lpROOT->lpIAB->lpPropertyStore->rgolkci->lpszName : szBuffer, iRow, cb, (LPBYTE)lpb, NULL, AB_MODIFIABLE | AB_RECIPIENTS, pt_bIsWABOpenExSession ? 1 : 0, pt_bIsWABOpenExSession ? TRUE : FALSE, ulFlags, FALSE, FALSE); } // Attach the props to the SRowSet lpSRowSet->aRow[iRow].lpProps = lpProps; lpSRowSet->aRow[iRow].cValues = cProps; lpSRowSet->aRow[iRow].ulAdrEntryPad = 0; iRow++; } // // Next, add any additional containers // for (i = 1; i < colkci; i++) { if (FAILED(sc = MAPIAllocateBuffer(ircMax * sizeof(SPropValue), &lpProps))) { DebugTrace(TEXT("ROOT_GetContentsTable: Allocation of props -> %x\n"), sc); hResult = ResultFromScode(sc); goto exit; } SetContainerlpProps(lpProps, rgolkci[i].lpszName, iRow, 0, NULL, rgolkci[i].lpEntryID, AB_MODIFIABLE | AB_RECIPIENTS, 1, TRUE, ulFlags, FALSE, FALSE); // Attach the props to the SRowSet lpSRowSet->aRow[iRow].lpProps = lpProps; lpSRowSet->aRow[iRow].cValues = cProps; lpSRowSet->aRow[iRow].ulAdrEntryPad = 0; iRow++; } for (i = 1; i < cwabci; i++) { if (FAILED(sc = MAPIAllocateBuffer(ircMax * sizeof(SPropValue), &lpProps))) { DebugTrace(TEXT("ROOT_GetContentsTable: Allocation of props -> %x\n"), sc); hResult = ResultFromScode(sc); goto exit; } SetContainerlpProps(lpProps, rgwabci[i].lpszName, iRow, 0, NULL, rgwabci[i].lpEntryID, AB_MODIFIABLE | AB_RECIPIENTS, 1, TRUE, ulFlags, FALSE, FALSE); // Attach the props to the SRowSet lpSRowSet->aRow[iRow].lpProps = lpProps; lpSRowSet->aRow[iRow].cValues = cProps; lpSRowSet->aRow[iRow].ulAdrEntryPad = 0; iRow++; } // // Now, add the LDAP objects // lpNextServer = lpServerNames; for (i = 0; i < cLDAPContainers && lpNextServer; i++) { UNALIGNED WCHAR *lpName = lpNextServer->lpszName; if (lpName) { LDAPSERVERPARAMS sParams; if(bIsDupeContainerName(lpSRowSet, (LPTSTR) lpName)) { lpSRowSet->cRows--; goto endloop; } //DebugTrace(TEXT("LDAP Server: %s\n"), lpNextServer->lpszName); cProps = ircMax; if (FAILED(sc = MAPIAllocateBuffer(ircMax * sizeof(SPropValue), &lpProps))) { DebugTrace(TEXT("ROOT_GetContentsTable: Allocation of props -> %x\n"), sc); hResult = ResultFromScode(sc); goto exit; } GetLDAPServerParams(lpNextServer->lpszName, &sParams); { ULONG cb = 0; LPENTRYID lpb = NULL; LPVOID pv = lpName; if (HR_FAILED(hResult = CreateWABEntryID(WAB_LDAP_CONTAINER, pv, // server name NULL, NULL, 0, 0, lpProps, &cb, &lpb))) { goto exit; } SetContainerlpProps(lpProps, (LPTSTR) lpName, iRow, cb, (LPBYTE)lpb, NULL, AB_FIND_ON_OPEN | AB_UNMODIFIABLE, 0, FALSE, ulFlags, TRUE, sParams.fResolve); } FreeLDAPServerParams(sParams); // Attach the props to the SRowSet lpSRowSet->aRow[iRow].lpProps = lpProps; lpSRowSet->aRow[iRow].cValues = cProps; lpSRowSet->aRow[iRow].ulAdrEntryPad = 0; iRow++; } endloop: lpNextServer = lpNextServer->lpNext; } // Add all this data we just created to the the Table. if (hResult = lpTableData->lpVtbl->HrModifyRows(lpTableData, 0, // ulFlags lpSRowSet)) { DebugTraceResult( TEXT("ROOT_GetContentsTable:HrModifyRows"), hResult); goto exit; } hResult = lpTableData->lpVtbl->HrGetView(lpTableData, NULL, // LPSSortOrderSet lpsos, ContentsViewGone, // CALLERRELEASE FAR * lpfReleaseCallback, 0, // ULONG ulReleaseData, lppTable); // LPMAPITABLE FAR * lplpmt) exit: while(lpServerNames) { lpNextServer = lpServerNames; lpServerNames = lpServerNames->lpNext; LocalFreeAndNull(&lpNextServer->lpszName); LocalFreeAndNull(&lpNextServer); } FreeProws(lpSRowSet); // Cleanup table if failure if (HR_FAILED(hResult)) { if (lpTableData) { UlRelease(lpTableData); } } LeaveCriticalSection(&lpROOT->lpIAB->cs); return(hResult); } /************************************************************************* * * - ROOT_GetHierarchyTable - * Returns the merge of all the root hierarchy tables * * * */ STDMETHODIMP ROOT_GetHierarchyTable (LPROOT lpROOT, ULONG ulFlags, LPMAPITABLE * lppTable) { LPTSTR lpszMessage = NULL; ULONG ulLowLevelError = 0; HRESULT hr = hrSuccess; #ifdef PARAMETER_VALIDATION // Validate parameters // Check to see if it has a jump table if (IsBadReadPtr(lpROOT, sizeof(LPVOID))) { // No jump table found return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } // Check to see that it's ROOTs jump table if (lpROOT->lpVtbl != &vtblROOT) { // Not my jump table return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } // See if I can set the return variable if (IsBadWritePtr (lppTable, sizeof (LPMAPITABLE))) { return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } // Check flags: // The only valid flags are CONVENIENT_DEPTH and MAPI_DEFERRED_ERRORS if (ulFlags & ~(CONVENIENT_DEPTH|MAPI_DEFERRED_ERRORS|MAPI_UNICODE)) { DebugTraceArg(ROOT_GetHierarchyTable, TEXT("Unknown flags used")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS)); } #endif // BUGBUG: We use the code which is incorrectly in GetContentsTable... hr = ROOT_GetContentsTable(lpROOT, ulFlags & ~CONVENIENT_DEPTH, lppTable); DebugTraceResult(ROOT_GetHierarchyTable, hr); return(hr); } /************************************************************************* * * - ROOT_OpenEntry - * Just call ABP_OpenEntry * * * */ STDMETHODIMP ROOT_OpenEntry(LPROOT lpROOT, ULONG cbEntryID, LPENTRYID lpEntryID, LPCIID lpInterface, ULONG ulFlags, ULONG * lpulObjType, LPUNKNOWN * lppUnk) { #ifdef PARAMETER_VALIDATION // Validate the object. if (BAD_STANDARD_OBJ(lpROOT, ROOT_, OpenEntry, lpVtbl)) { // jump table not large enough to support this method return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } // Check the entryid parameter. It needs to be big enough to hold an entryid. // Null entryids are valid /* if (lpEntryID) { if (cbEntryID < offsetof(ENTRYID, ab) || IsBadReadPtr((LPVOID) lpEntryID, (UINT)cbEntryID)) { DebugTraceArg(ROOT_OpenEntry, TEXT("lpEntryID fails address check")); return(ResultFromScode(MAPI_E_INVALID_ENTRYID)); } //NFAssertSz(FValidEntryIDFlags(lpEntryID->abFlags), // TEXT("Undefined bits set in EntryID flags\n")); } */ // Don't check the interface parameter unless the entry is something // MAPI itself handles. The provider should return an error if this // parameter is something that it doesn't understand. // At this point, we just make sure it's readable. if (lpInterface && IsBadReadPtr(lpInterface, sizeof(IID))) { DebugTraceArg(ROOT_OpenEntry, TEXT("lpInterface fails address check")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } if (ulFlags & ~(MAPI_MODIFY | MAPI_DEFERRED_ERRORS | MAPI_BEST_ACCESS)) { DebugTraceArg(ROOT_OpenEntry, TEXT("Unknown flags used")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS)); } if (IsBadWritePtr((LPVOID) lpulObjType, sizeof (ULONG))) { DebugTraceArg(ROOT_OpenEntry, TEXT("lpulObjType")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } if (IsBadWritePtr((LPVOID) lppUnk, sizeof (LPUNKNOWN))) { DebugTraceArg(ROOT_OpenEntry, TEXT("lppUnk")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } #endif // PARAMETER_VALIDATION // Should just call IAB::OpenEntry()... return(lpROOT->lpIAB->lpVtbl->OpenEntry(lpROOT->lpIAB, cbEntryID, lpEntryID, lpInterface, ulFlags, lpulObjType, lppUnk)); } STDMETHODIMP ROOT_SetSearchCriteria(LPROOT lpROOT, LPSRestriction lpRestriction, LPENTRYLIST lpContainerList, ULONG ulSearchFlags) { #ifdef PARAMETER_VALIDATION // Validate the object. if (BAD_STANDARD_OBJ(lpROOT, ROOT_, SetSearchCriteria, lpVtbl)) { // jump table not large enough to support this method DebugTraceArg(ROOT_SetSearchCriteria, TEXT("Bad object/vtble")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } // ensure we can read the restriction if (lpRestriction && IsBadReadPtr(lpRestriction, sizeof(SRestriction))) { DebugTraceArg(ROOT_SetSearchCriteria, TEXT("Bad Restriction parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } if (FBadEntryList(lpContainerList)) { DebugTraceArg(ROOT_SetSearchCriteria, TEXT("Bad ContainerList parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } if (ulSearchFlags & ~(STOP_SEARCH | RESTART_SEARCH | RECURSIVE_SEARCH | SHALLOW_SEARCH | FOREGROUND_SEARCH | BACKGROUND_SEARCH)) { DebugTraceArg(ROOT_GetSearchCriteria, TEXT("Unknown flags used")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS)); } #endif // PARAMETER_VALIDATION return(ResultFromScode(MAPI_E_NO_SUPPORT)); } STDMETHODIMP ROOT_GetSearchCriteria(LPROOT lpROOT, ULONG ulFlags, LPSRestriction FAR * lppRestriction, LPENTRYLIST FAR * lppContainerList, ULONG FAR * lpulSearchState) { #ifdef PARAMETER_VALIDATION // Validate the object. if (BAD_STANDARD_OBJ(lpROOT, ROOT_, GetSearchCriteria, lpVtbl)) { // jump table not large enough to support this method DebugTraceArg(ROOT_GetSearchCriteria, TEXT("Bad object/vtble")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } if (ulFlags & ~(MAPI_UNICODE)) { DebugTraceArg(ROOT_GetSearchCriteria, TEXT("Unknown Flags")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS)); } // ensure we can write the restriction if (lppRestriction && IsBadWritePtr(lppRestriction, sizeof(LPSRestriction))) { DebugTraceArg(ROOT_GetSearchCriteria, TEXT("Bad Restriction write parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } // ensure we can read the container list if (lppContainerList && IsBadWritePtr(lppContainerList, sizeof(LPENTRYLIST))) { DebugTraceArg(ROOT_GetSearchCriteria, TEXT("Bad ContainerList parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } if (lpulSearchState && IsBadWritePtr(lpulSearchState, sizeof(ULONG))) { DebugTraceArg(ROOT_GetSearchCriteria, TEXT("lpulSearchState fails address check")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } #endif // PARAMETER_VALIDATION return(ResultFromScode(MAPI_E_NO_SUPPORT)); } //---------------------------------------------------------------------------- // Synopsis: ROOT_CreateEntry() // // Description: // If called from a OneOff container a OneOff MAIL_USER object // is created via the use of any arbitrary template. // CreateEntry is not supported from a ROOT container. // // Parameters: // Returns: // Effects: // // Notes: OneOff EntryIDs contain MAPI_UNICODE flag information in // the ulDataType member. // // Revision: //---------------------------------------------------------------------------- STDMETHODIMP ROOT_CreateEntry(LPROOT lpROOT, ULONG cbEntryID, LPENTRYID lpEntryID, ULONG ulCreateFlags, LPMAPIPROP FAR * lppMAPIPropEntry) { BYTE bType; #ifdef PARAMETER_VALIDATION // Validate the object. if (BAD_STANDARD_OBJ(lpROOT, ROOT_, CreateEntry, lpVtbl)) { // jump table not large enough to support this method DebugTraceArg(ROOT_CreateEntry, TEXT("Bad object/Vtbl")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } // Check the entryid parameter. It needs to be big enough to hold an entryid. // Null entryid are bad /* if (lpEntryID) { if (cbEntryID < offsetof(ENTRYID, ab) || IsBadReadPtr((LPVOID) lpEntryID, (UINT)cbEntryID)) { DebugTraceArg(ROOT_CreateEntry, TEXT("lpEntryID fails address check")); return(ResultFromScode(MAPI_E_INVALID_ENTRYID)); } //NFAssertSz(FValidEntryIDFlags(lpEntryID->abFlags), // "Undefined bits set in EntryID flags\n"); } else { DebugTraceArg(ROOT_CreateEntry, TEXT("lpEntryID NULL")); return(ResultFromScode(MAPI_E_INVALID_ENTRYID)); } */ if (ulCreateFlags & ~(CREATE_CHECK_DUP_STRICT | CREATE_CHECK_DUP_LOOSE | CREATE_REPLACE | CREATE_MERGE)) { DebugTraceArg(ROOT_CreateEntry, TEXT("Unknown flags used")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS)); } if (IsBadWritePtr(lppMAPIPropEntry, sizeof(LPMAPIPROP))) { DebugTraceArg(ROOT_CreateEntry, TEXT("Bad MAPI Property write parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } #endif // PARAMETER_VALIDATION #ifdef NEVER if (lpROOT->ulType == AB_ROOT) return ResultFromScode(MAPI_E_NO_SUPPORT); #endif // NEVER // What kind of entry are we creating? // Default is MailUser bType = IsWABEntryID(cbEntryID, lpEntryID, NULL, NULL, NULL, NULL, NULL); if (bType == WAB_DEF_MAILUSER || cbEntryID == 0) { // // Create a new (in memory) entry and return it's mapiprop // return(HrNewMAILUSER(lpROOT->lpIAB, lpROOT->pmbinOlk, MAPI_MAILUSER, ulCreateFlags, lppMAPIPropEntry)); } else if (bType == WAB_DEF_DL) { // // Create a new (in memory) distribution list and return it's mapiprop? return(HrNewMAILUSER(lpROOT->lpIAB, lpROOT->pmbinOlk, MAPI_DISTLIST, ulCreateFlags, lppMAPIPropEntry)); } else { DebugTrace(TEXT("ROOT_CreateEntry got unknown template entryID\n")); return(ResultFromScode(MAPI_E_INVALID_ENTRYID)); } } /* - CopyEntries - * Copies a list of entries into this container... Since you can't * do that with this container we just return not supported. */ STDMETHODIMP ROOT_CopyEntries(LPROOT lpROOT, LPENTRYLIST lpEntries, ULONG_PTR ulUIParam, LPMAPIPROGRESS lpProgress, ULONG ulFlags) { #ifdef PARAMETER_VALIDATION if (BAD_STANDARD_OBJ(lpROOT, ROOT_, CopyEntries, lpVtbl)) { // jump table not large enough to support this method DebugTraceArg(ROOT_CopyEntries, TEXT("Bad object/vtbl")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } // ensure we can read the container list if (FBadEntryList(lpEntries)) { DebugTraceArg(ROOT_CopyEntries, TEXT("Bad Entrylist parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } if (ulUIParam && !IsWindow((HWND)ulUIParam)) { DebugTraceArg(ROOT_CopyEntries, TEXT("Invalid window handle")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } if (lpProgress && IsBadReadPtr(lpProgress, sizeof(IMAPIProgress))) { DebugTraceArg(ROOT_CopyEntries, TEXT("Bad MAPI Progress parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } if (ulFlags & ~(AB_NO_DIALOG | CREATE_CHECK_DUP_LOOSE)) { DebugTraceArg(ROOT_CreateEntry, TEXT("Unknown flags used")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS)); } #endif // PARAMETER_VALIDATION return(ResultFromScode(MAPI_E_NO_SUPPORT)); } /* - DeleteEntries - * * Deletes entries within this container... Funny that. There really * isn't a true container here. Do we just say "Sure, that worked just * fine" or "Sorry this operation not supported." I don't think it really * matters... For now it's the former. */ STDMETHODIMP ROOT_DeleteEntries (LPROOT lpROOT, LPENTRYLIST lpEntries, ULONG ulFlags) { ULONG i; HRESULT hResult = hrSuccess; ULONG cDeleted = 0; ULONG cToDelete; SCODE sc; #ifndef DONT_ADDREF_PROPSTORE if ((FAILED(sc = OpenAddRefPropertyStore(NULL, lpROOT->lpIAB->lpPropertyStore)))) { hResult = ResultFromScode(sc); goto exitNotAddRefed; } #endif #ifdef PARAMETER_VALIDATION if (BAD_STANDARD_OBJ(lpROOT, ROOT_, DeleteEntries, lpVtbl)) { // jump table not large enough to support this method DebugTraceArg(ROOT_DeleteEntries, TEXT("Bad object/vtbl")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } // ensure we can read the container list if (FBadEntryList(lpEntries)) { DebugTraceArg(ROOT_DeleteEntries, TEXT("Bad Entrylist parameter")); return(ResultFromScode(MAPI_E_INVALID_PARAMETER)); } if (ulFlags) { DebugTraceArg(ROOT_DeleteEntries, TEXT("Unknown flags used")); // return(ResultFromScode(MAPI_E_UNKNOWN_FLAGS)); } #endif // PARAMETER_VALIDATION // List of entryids is in lpEntries. This is a counted array of // entryid SBinary structs. cToDelete = lpEntries->cValues; // Delete each entry for (i = 0; i < cToDelete; i++) { if(0 != IsWABEntryID(lpEntries->lpbin[i].cb, (LPENTRYID) IntToPtr(lpEntries->lpbin[i].cb), NULL, NULL, NULL, NULL, NULL)) { DebugTrace(TEXT("CONTAINER_DeleteEntries got bad entryid of size %u\n"), lpEntries->lpbin[i].cb); continue; } hResult = DeleteCertStuff((LPADRBOOK)lpROOT->lpIAB, (LPENTRYID)lpEntries->lpbin[i].lpb, lpEntries->lpbin[i].cb); hResult = HrSaveHotmailSyncInfoOnDeletion((LPADRBOOK) lpROOT->lpIAB, &(lpEntries->lpbin[i])); if (HR_FAILED(hResult = DeleteRecord(lpROOT->lpIAB->lpPropertyStore->hPropertyStore, &(lpEntries->lpbin[i])))) { DebugTraceResult( TEXT("DeleteEntries: DeleteRecord"), hResult); continue; } cDeleted++; } if (! hResult) { if (cDeleted != cToDelete) { hResult = ResultFromScode(MAPI_W_PARTIAL_COMPLETION); DebugTrace(TEXT("DeleteEntries deleted %u of requested %u\n"), cDeleted, cToDelete); } } #ifndef DONT_ADDREF_PROPSTORE ReleasePropertyStore(lpROOT->lpIAB->lpPropertyStore); exitNotAddRefed: #endif return(hResult); } STDMETHODIMP ROOT_ResolveNames( LPROOT lpRoot, LPSPropTagArray lptagaColSet, ULONG ulFlags, LPADRLIST lpAdrList, LPFlagList lpFlagList) { return(ResultFromScode(MAPI_E_NO_SUPPORT)); }