/* ---------------------------------------------------------------------- Module: ULS.DLL (Service Provider) File: spnotify.cpp Content: This file contains the notification handlers. History: 10/15/96 Chu, Lon-Chan [lonchanc] Created. Copyright (c) Microsoft Corporation 1996-1997 ---------------------------------------------------------------------- */ #include "ulsp.h" #include "spinc.h" typedef struct { TCHAR *pszName; TCHAR *pszValue; } ATTR_PAIR; typedef struct { ULONG cMaxAttrs; ULONG cCurrAttrs; ATTR_PAIR aPairs[1]; } ATTR_PAIRS; typedef struct { CLIENT_INFO ClientInfo; ATTR_PAIRS Attrs; } CLIENT_INFO_ATTRS; #ifdef ENABLE_MEETING_PLACE typedef struct { MTG_INFO MtgInfo; ATTR_PAIRS Attrs; } MTG_INFO_ATTRS; #endif ULONG GetUniqueNotifyID ( VOID ) { // Always positive number // if (g_uRespID & 0x80000000UL) g_uRespID = 1; return g_uRespID++; } BOOL NotifyGeneric ( HRESULT hrServer, SP_CResponse *pItem ) { MyAssert (pItem != NULL); // Get the pending info // RESP_INFO *pInfo = pItem->GetRespInfo (); MyAssert (pInfo != NULL); // Do not use the result (pLdapMsg) // // Check dependency such as modify/modrdn // if (pInfo->uMsgID[0] != INVALID_MSG_ID) { // Do we wait for the second result? // If so, remember the hr from the first result. // if (pInfo->uMsgID[1] != INVALID_MSG_ID) { // We need two results; the first one just comes in. // We still need to wait for the second one // pInfo->uMsgID[0] = INVALID_MSG_ID; pInfo->hrDependency = hrServer; // Don't destroy this item // return FALSE; } } else { // This is the second result // MyAssert (pInfo->uMsgID[1] != INVALID_MSG_ID); // Propagate the hr from the first result if needed // if (pInfo->hrDependency != S_OK) hrServer = pInfo->hrDependency; } // Post the result to the com layer // PostMessage (g_hWndNotify, pInfo->uNotifyMsg, pInfo->uRespID, hrServer); // Destroy this pending item // return TRUE; } BOOL NotifyRegister ( HRESULT hrServer, SP_CResponse *pItem ) { MyAssert (pItem != NULL); // Get pending info // RESP_INFO *pInfo = pItem->GetRespInfo (); MyAssert (pInfo != NULL); // Get the object of user/app/prot/mtg // HANDLE hObject = pInfo->hObject; MyAssert (hObject != NULL); // Do not use the result (pLdapMsg) // // Check dependency such as modify/modrdn // if (pInfo->uMsgID[0] != INVALID_MSG_ID) { // Do we wait for the second result? // If so, remember the hr from the first result. // if (pInfo->uMsgID[1] != INVALID_MSG_ID) { // We need two results; the first one just comes in. // We still need to wait for the second one // pInfo->uMsgID[0] = INVALID_MSG_ID; pInfo->hrDependency = hrServer; // Don't destroy this item // return FALSE; } } else { // This is the second result // MyAssert (pInfo->uMsgID[1] != INVALID_MSG_ID); // Propagate the hr from the first result if needed // if (pInfo->hrDependency != S_OK) hrServer = pInfo->hrDependency; } // Notify the object of success/failure // SP_CClient *pClient; SP_CProtocol *pProt; #ifdef ENABLE_MEETING_PLACE SP_CMeeting *pMtg; #endif if (hrServer != S_OK) { // Release the object when failure // switch (pInfo->uNotifyMsg) { case WM_ILS_REGISTER_CLIENT: pClient = (SP_CClient *) hObject; if (pClient->IsValidObject ()) { pClient->Release (); } break; case WM_ILS_REGISTER_PROTOCOL: pProt = (SP_CProtocol *) hObject; if (pProt->IsValidObject ()) { pProt->Release (); } break; #ifdef ENABLE_MEETING_PLACE case WM_ILS_REGISTER_MEETING: pMtg = (SP_CMeeting *) hObject; if (pMtg->IsValidObject ()) { pMtg->Release (); } break; #endif default: MyAssert (FALSE); break; } } else { // Set as successful registration when success // switch (pInfo->uNotifyMsg) { case WM_ILS_REGISTER_CLIENT: pClient = (SP_CClient *) hObject; if (pClient->IsValidObject ()) { pClient->SetRegRemotely (); if (g_pRefreshScheduler != NULL) { g_pRefreshScheduler->EnterClientObject (pClient); } else { MyAssert (FALSE); } } break; case WM_ILS_REGISTER_PROTOCOL: pProt = (SP_CProtocol *) hObject; if (pProt->IsValidObject ()) { pProt->SetRegRemotely (); } break; #ifdef ENABLE_MEETING_PLACE case WM_ILS_REGISTER_MEETING: pMtg = (SP_CMeeting *) hObject; if (pMtg->IsValidObject ()) { pMtg->SetRegRemotely (); if (g_pRefreshScheduler != NULL) { g_pRefreshScheduler->EnterMtgObject (pMtg); } else { MyAssert (FALSE); } } break; #endif default: MyAssert (FALSE); break; } } // Post the result to the com layer // PostMessage (g_hWndNotify, pInfo->uNotifyMsg, pInfo->uRespID, (LPARAM) hrServer); // Destroy this pending item // return TRUE; } /* =========== ENUMERATION ============ */ typedef struct { ULONG uEnumUsers; // WM_ILS_ENUM_USERS, WM_ILS_ENUM_USERINFOS, or 0 ULONG cItems; ULONG cbEntrySize; BYTE bData[8]; // data starting from here } ENUM_LIST; extern HRESULT CacheEnumInfos ( ULONG uNotifyMsg, LDAP *ld, LDAPMessage *pEntry, VOID *p ); extern VOID BuildEnumObjectNames ( LDAP_ENUM *pEnum, ENUM_LIST *pEnumList ); extern VOID BuildEnumClientInfos ( LDAP_ENUM *pEnum, ENUM_LIST *pEnumList ); extern VOID SizeEnumClientInfos ( ULONG *pcbTotalSize, CLIENT_INFO_ATTRS *pcia ); extern VOID TotalSizeEnumObjectNames ( ULONG *pcbTotalSize, ULONG cEntries, TCHAR **appszObjectNames[] ); extern VOID FreeStdAttrCache ( TCHAR *apszStdAttrValues[], ULONG cStdAttrs ); extern VOID FreeAttrPairArrayCache ( ATTR_PAIR aAttrPair[], ULONG cPairs ); extern VOID CacheAnyAttrNamesInAttrPairs ( ULONG cNames, TCHAR *pszSrcNameList, ATTR_PAIR aAttrPairs[] ); #ifdef ENABLE_MEETING_PLACE extern VOID BuildEnumMtgInfos ( LDAP_ENUM *pEnum, ENUM_LIST *pEnumList ); extern VOID SizeEnumMtgInfos ( ULONG *pcbTotalSize, MTG_INFO_ATTRS *pmia ); #endif BOOL NotifyEnumX ( ULONG uEnumType, HRESULT hrServer, SP_CResponse *pItem, TCHAR *pszRetAttrName ) // returned attribute's name { MyAssert (pItem != NULL); #if defined (DEBUG) || defined (_DEBUG) // Consistency checks // switch (uEnumType) { case WM_ILS_ENUM_CLIENTS: #ifdef ENABLE_MEETING_PLACE case WM_ILS_ENUM_MEETINGS: #endif MyAssert (pszRetAttrName != NULL && *pszRetAttrName != TEXT ('\0')); break; case WM_ILS_ENUM_CLIENTINFOS: #ifdef ENABLE_MEETING_PLACE case WM_ILS_ENUM_MEETINGINFOS: #endif MyAssert (pszRetAttrName == NULL); break; default: MyAssert (FALSE); break; } #endif // Get pending info // RESP_INFO *pInfo = pItem->GetRespInfo (); MyAssert (pInfo != NULL); // Initialize minimal info // LDAP_ENUM *pEnum = NULL; ENUM_LIST *pEnumList = NULL; // If error, simply report the error // if (hrServer != S_OK) goto MyExit; // Get the ldap result // LDAPMessage *pLdapMsg; pLdapMsg = pItem->GetResult (); if (pLdapMsg == NULL) { MyAssert (FALSE); hrServer = ILS_E_POINTER; goto MyExit; } // Get ld // LDAP *ld; ld = pItem->GetLd (); if (ld == NULL) { MyAssert (FALSE); hrServer = ILS_E_HANDLE; goto MyExit; } // Initialize the total size of LDAP_ENUM // ULONG cbTotalSize; cbTotalSize = sizeof (LDAP_ENUM) + // the minimal info sizeof (TCHAR); // the last null terminator // Let's get the count of entries in this result set // ULONG cEntries, i; cEntries = ldap_count_entries (ld, pLdapMsg); // Return now if there is nothing to handle // if (cEntries <= 0) { // I want to make sure this case happens or not // MyAssert (cEntries == 0); // Simply return without deleting this pending item // return FALSE; } // In the following, we only deal with the case (cEntries > 0) // // Calculate enum list size // ULONG cbEntrySize , cbSizeEnumList; switch (uEnumType) { case WM_ILS_ENUM_CLIENTINFOS: cbEntrySize = sizeof (CLIENT_INFO_ATTRS) + pInfo->cAnyAttrs * sizeof (ATTR_PAIR); break; #ifdef ENABLE_MEETING_PLACE case WM_ILS_ENUM_MEETINGINFOS: cbEntrySize = sizeof (MTG_INFO_ATTRS) + pInfo->cAnyAttrs * sizeof (ATTR_PAIR); break; #endif default: cbEntrySize = sizeof (TCHAR **); break; } cbSizeEnumList = sizeof (ENUM_LIST) + cEntries * cbEntrySize; // Allocate the enum list that is a temporary cache // for all attributes from wldap32.dll // pEnumList = (ENUM_LIST *) MemAlloc (cbSizeEnumList); if (pEnumList == NULL) { // Fails probably due to insane cbSizeEnumList // MyAssert (FALSE); hrServer = ILS_E_MEMORY; goto MyExit; } // Fill in enum list // pEnumList->uEnumUsers = uEnumType; pEnumList->cItems = cEntries; pEnumList->cbEntrySize = cbEntrySize; // Fill in names of extended attributes if needed // if (pInfo->cAnyAttrs > 0) { switch (uEnumType) { case WM_ILS_ENUM_CLIENTINFOS: for (i = 0; i < cEntries; i++) { CLIENT_INFO_ATTRS *p = (CLIENT_INFO_ATTRS *) (&(pEnumList->bData[0]) + i * cbEntrySize); p->Attrs.cMaxAttrs = pInfo->cAnyAttrs; CacheAnyAttrNamesInAttrPairs ( pInfo->cAnyAttrs, pInfo->pszAnyAttrNameList, &(p->Attrs.aPairs[0])); } break; #ifdef ENABLE_MEETING_PLACE case WM_ILS_ENUM_MEETINGINFOS: for (i = 0; i < cEntries; i++) { MTG_INFO_ATTRS *p = (MTG_INFO_ATTRS *) (&(pEnumList->bData[0]) + i * cbEntrySize); p->Attrs.cMaxAttrs = pInfo->cAnyAttrs; CacheAnyAttrNamesInAttrPairs ( pInfo->cAnyAttrs, pInfo->pszAnyAttrNameList, &(p->Attrs.aPairs[0])); } break; #endif default: break; } } // Get the first entry // LDAPMessage *pEntry; pEntry = ldap_first_entry (ld, pLdapMsg); if (pEntry == NULL) { MyAssert (FALSE); hrServer = ILS_E_MEMORY; goto MyExit; } // Cache the attributes in the first entry // TCHAR ***appszObjectNames; switch (uEnumType) { case WM_ILS_ENUM_CLIENTINFOS: #ifdef ENABLE_MEETING_PLACE case WM_ILS_ENUM_MEETINGINFOS: #endif hrServer = CacheEnumInfos (uEnumType, ld, pEntry, (VOID *) &(pEnumList->bData[0])); if (hrServer != S_OK) { MyAssert (FALSE); goto MyExit; } break; default: appszObjectNames = (TCHAR ***) &(pEnumList->bData[0]); appszObjectNames[0] = my_ldap_get_values (ld, pEntry, pszRetAttrName); if (appszObjectNames[0] == NULL) { MyAssert (FALSE); hrServer = ILS_E_MEMORY; goto MyExit; } break; } // switch (uEnumType) // Loop through the other entries // for (i = 1; i < cEntries; i++) { // Next entry, please // pEntry = ldap_next_entry (ld, pEntry); if (pEntry == NULL) { MyAssert (FALSE); // Failed, adjust the count to return partial result // pEnumList->cItems = cEntries = i; break; } // Cache the attributes in the subsequent entries // switch (uEnumType) { case WM_ILS_ENUM_CLIENTINFOS: #ifdef ENABLE_MEETING_PLACE case WM_ILS_ENUM_MEETINGINFOS: #endif hrServer = CacheEnumInfos (uEnumType, ld, pEntry, (CLIENT_INFO_ATTRS *) (&(pEnumList->bData[0]) + i * cbEntrySize)); if (hrServer != S_OK) { MyAssert (FALSE); goto MyExit; } break; default: appszObjectNames[i] = my_ldap_get_values (ld, pEntry, pszRetAttrName); if (appszObjectNames[i] == NULL) { MyAssert (FALSE); hrServer = ILS_E_MEMORY; goto MyExit; } break; } // switch (uEnumType) } // for (i = 1; i < cEntries; i++) // We just cache all the attribute names and values. // Now, we need to calculate the total size of the return buffer. // // Calculate the total size of the LDAP_ENUM structure... // switch (uEnumType) { case WM_ILS_ENUM_CLIENTINFOS: for (i = 0; i < cEntries; i++) { SizeEnumClientInfos (&cbTotalSize, (CLIENT_INFO_ATTRS *) (&(pEnumList->bData[0]) + i * cbEntrySize)); } break; #ifdef ENABLE_MEETING_PLACE case WM_ILS_ENUM_MEETINGINFOS: for (i = 0; i < cEntries; i++) { SizeEnumMtgInfos (&cbTotalSize, (MTG_INFO_ATTRS *) (&(pEnumList->bData[0]) + i * cbEntrySize)); } break; #endif default: TotalSizeEnumObjectNames (&cbTotalSize, cEntries, &(appszObjectNames[0])); break; } // switch (uEnumType) // Allocate the returned LDAP_ENUM structure // pEnum = (LDAP_ENUM *) MemAlloc (cbTotalSize); if (pEnum == NULL) { // Fails probably due to insane cbTotalSize // MyAssert (FALSE); hrServer = ILS_E_MEMORY; goto MyExit; } // Fill in LDAP_ENUM common fields // pEnum->uSize = sizeof (*pEnum); pEnum->hResult = hrServer; pEnum->cItems = cEntries; pEnum->uOffsetItems = sizeof (*pEnum); // Fill in LDAP_ENUM items // switch (uEnumType) { case WM_ILS_ENUM_CLIENTINFOS: BuildEnumClientInfos (pEnum, pEnumList); break; #ifdef ENABLE_MEETING_PLACE case WM_ILS_ENUM_MEETINGINFOS: BuildEnumMtgInfos (pEnum, pEnumList); break; #endif default: BuildEnumObjectNames (pEnum, pEnumList); break; } MyAssert (hrServer == S_OK); MyExit: // Free the temporary cache // if (pEnumList != NULL) { switch (uEnumType) { case WM_ILS_ENUM_CLIENTINFOS: for (i = 0; i < pEnumList->cItems; i++) { CLIENT_INFO_ATTRS *p = (CLIENT_INFO_ATTRS *) (&(pEnumList->bData[0]) + i * cbEntrySize); // Free standard attributes // FreeStdAttrCache (&(p->ClientInfo.apszStdAttrValues[0]), COUNT_ENUM_DIR_CLIENT_INFO); // Free extended attributes // FreeAttrPairArrayCache (&(p->Attrs.aPairs[0]), pInfo->cAnyAttrs); } break; #ifdef ENABLE_MEETING_PLACE case WM_ILS_ENUM_MEETINGINFOS: for (i = 0; i < pEnumList->cItems; i++) { MTG_INFO_ATTRS *p = (MTG_INFO_ATTRS *) (&(pEnumList->bData[0]) + i * cbEntrySize); // Free standard attributes // FreeStdAttrCache (&(p->MtgInfo.apszStdAttrValues[0]), COUNT_ENUM_DIRMTGINFO); // Free extended attributes // FreeAttrPairArrayCache (&(p->Attrs.aPairs[0]), pInfo->cAnyAttrs); } break; #endif default: for (i = 0; i < pEnumList->cItems; i++) { if (appszObjectNames[i] != NULL) ldap_value_free (appszObjectNames[i]); } break; } MemFree (pEnumList); } // if // Clean up if failure // if (hrServer != S_OK) { // Special treatment of enum termination for wldap32.dll // if (hrServer == ILS_E_PARAMETER) { MemFree (pEnum); pEnum = NULL; // enum termination } else { // Make sure we have at least LDAP_ENUM buffer to return // if (pEnum != NULL) ZeroMemory (pEnum, sizeof (*pEnum)); else pEnum = (LDAP_ENUM *) MemAlloc (sizeof (LDAP_ENUM)); // Set up the LDAP_ENUM info // if (pEnum != NULL) { pEnum->uSize = sizeof (*pEnum); pEnum->hResult = hrServer; } } // Force to delete this pending item // cEntries = 0; } // Post a message to the com layer of this enum result // PostMessage (g_hWndNotify, pInfo->uNotifyMsg, pInfo->uRespID, (LPARAM) pEnum); return (cEntries == 0); } BOOL NotifyEnumClients ( HRESULT hrServer, SP_CResponse *pItem ) { return NotifyEnumX (WM_ILS_ENUM_CLIENTS, hrServer, pItem, STR_CLIENT_CN); } BOOL NotifyEnumClientInfos ( HRESULT hrServer, SP_CResponse *pItem ) { return NotifyEnumX (WM_ILS_ENUM_CLIENTINFOS, hrServer, pItem, NULL); } BOOL NotifyEnumProts ( HRESULT hrServer, SP_CResponse *pItem ) { MyAssert (pItem != NULL); // Clean up locals // LDAP_ENUM *pEnum = NULL; TCHAR **apszProtNames = NULL; // Get the pending info // RESP_INFO *pInfo = pItem->GetRespInfo (); MyAssert (pInfo != NULL); // If error, simply report the error // if (hrServer != S_OK) goto MyExit; // Get the ldap result // LDAPMessage *pLdapMsg; pLdapMsg = pItem->GetResult (); MyAssert (pLdapMsg != NULL); if (pLdapMsg == NULL) { MyAssert (FALSE); hrServer = ILS_E_POINTER; goto MyExit; } // Get ld // LDAP *ld; ld = pItem->GetLd (); if (ld == NULL) { MyAssert (FALSE); hrServer = ILS_E_HANDLE; goto MyExit; } // Get the array // apszProtNames = my_ldap_get_values (ld, pLdapMsg, STR_PROT_NAME); if (apszProtNames == NULL) { hrServer = ILS_E_NO_SUCH_OBJECT; goto MyExit; } // Initialize minimal info size // ULONG cbEnumList; cbEnumList = sizeof (LDAP_ENUM) + // the minimal info sizeof (TCHAR); // the last null terminator // Let's see how many strings in the array // ULONG cNames; for (cNames = 0; apszProtNames[cNames] != NULL; cNames++) { cbEnumList += (lstrlen (apszProtNames[cNames]) + 1) * sizeof (TCHAR); } // Allocate the enum structure // pEnum = (LDAP_ENUM *) MemAlloc (cbEnumList); if (pEnum == NULL) { hrServer = ILS_E_MEMORY; goto MyExit; } // Fill in header // pEnum->uSize = sizeof (*pEnum); pEnum->hResult = hrServer; pEnum->cItems = cNames; pEnum->uOffsetItems = sizeof (*pEnum); // Fill in name strings // ULONG i; TCHAR *pszName; pszName = (TCHAR *) (pEnum + 1); for (i = 0; i < cNames; i++) { My_lstrcpy (pszName, apszProtNames[i]); pszName += lstrlen (pszName) + 1; } MyAssert (hrServer == S_OK); MyExit: // Free the array if allocated // if (apszProtNames != NULL) ldap_value_free (apszProtNames); // Post messages back to the COM layer // if (hrServer != S_OK) { // Make sure we have at least LDAP_ENUM buffer to return // if (pEnum != NULL) ZeroMemory (pEnum, sizeof (*pEnum)); else pEnum = (LDAP_ENUM *) MemAlloc (sizeof (LDAP_ENUM)); // Set up the LDAP_ENUM info // if (pEnum != NULL) { pEnum->uSize = sizeof (*pEnum); pEnum->hResult = hrServer; } } // Post a message to the com layer of this enum result // PostMessage (g_hWndNotify, pInfo->uNotifyMsg, pInfo->uRespID, (LPARAM) pEnum); // Terminate enumeration if success // if (hrServer == S_OK) { PostMessage (g_hWndNotify, pInfo->uNotifyMsg, pInfo->uRespID, (LPARAM) NULL); } // Destroy this pending item // return TRUE; } #ifdef ENABLE_MEETING_PLACE BOOL NotifyEnumMtgs ( HRESULT hrServer, SP_CResponse *pItem ) { return NotifyEnumX (WM_ILS_ENUM_MEETINGS, hrServer, pItem, STR_MTG_NAME); } #endif #ifdef ENABLE_MEETING_PLACE BOOL NotifyEnumMtgInfos ( HRESULT hrServer, SP_CResponse *pItem ) { return NotifyEnumX (WM_ILS_ENUM_MEETINGINFOS, hrServer, pItem, NULL); } #endif #ifdef ENABLE_MEETING_PLACE BOOL NotifyEnumAttendees ( HRESULT hrServer, SP_CResponse *pItem ) { MyAssert (pItem != NULL); // Get pending info // RESP_INFO *pInfo = pItem->GetRespInfo (); MyAssert (pInfo != NULL); // Initialize minimal info // LDAP_ENUM *pEnum = NULL; // If error, simply report the error // if (hrServer != S_OK) goto MyExit; // Get the ldap result // LDAPMessage *pLdapMsg; pLdapMsg = pItem->GetResult (); if (pLdapMsg == NULL) { MyAssert (FALSE); hrServer = ILS_E_POINTER; goto MyExit; } // Get ld // LDAP *ld; ld = pItem->GetLd (); if (ld == NULL) { MyAssert (FALSE); hrServer = ILS_E_HANDLE; goto MyExit; } // Initialize the total size of LDAP_ENUM // ULONG cbTotalSize; cbTotalSize = sizeof (LDAP_ENUM) + // the minimal info sizeof (TCHAR); // the last null terminator // Get the first entry that we care about // LDAPMessage *pEntry; pEntry = ldap_first_entry (ld, pLdapMsg); if (pEntry == NULL) { MyAssert (FALSE); hrServer = ILS_E_MEMORY; goto MyExit; } // Get the Members attribute // ULONG cItems; cItems = 0; TCHAR **apszMembers; apszMembers = my_ldap_get_values (ld, pEntry, STR_MTG_MEMBERS); if (apszMembers != NULL) { // Find out how many attendees // for (TCHAR **ppsz = apszMembers; *ppsz != NULL; ppsz++) { cItems++; cbTotalSize += (lstrlen (*ppsz) + 1) * sizeof (TCHAR); } } // Allocate the returned LDAP_ENUM structure // pEnum = (LDAP_ENUM *) MemAlloc (cbTotalSize); if (pEnum == NULL) { // Fails probably due to insane cbTotalSize // MyAssert (FALSE); hrServer = ILS_E_MEMORY; goto MyExit; } // Fill in LDAP_ENUM common fields // pEnum->uSize = sizeof (*pEnum); pEnum->hResult = hrServer; pEnum->cItems = cItems; pEnum->uOffsetItems = sizeof (*pEnum); // Fill in LDAP_ENUM items // TCHAR *pszDst; ULONG i; pszDst = (TCHAR *) (pEnum + 1); for (i = 0; i < cItems; i++) { lstrcpy (pszDst, apszMembers[i]); pszDst += lstrlen (pszDst) + 1; } MyAssert (hrServer == S_OK); MyExit: // Clean up if failure // if (hrServer != S_OK) { // Make sure we have at least LDAP_ENUM buffer to return // if (pEnum != NULL) ZeroMemory (pEnum, sizeof (*pEnum)); else pEnum = (LDAP_ENUM *) MemAlloc (sizeof (LDAP_ENUM)); // Fill in the minimal info // if (pEnum != NULL) { pEnum->uSize = sizeof (*pEnum); pEnum->hResult = hrServer; } } // Post a message to the com layer of this enum result // PostMessage (g_hWndNotify, pInfo->uNotifyMsg, pInfo->uRespID, (LPARAM) pEnum); // Delete this pending item // return TRUE; } #endif // ENABLE_MEETING_PLACE VOID CacheEnumClientInfoAttr ( CLIENT_INFO_ATTRS *puia, TCHAR *pszAttrName, TCHAR **ppszAttrValue ) { ULONG i; // See if this attribute is arbitrary? // if (IlsIsAnyAttrName (pszAttrName) != NULL) { // Deal with extended attributes // for (i = 0; i < puia->Attrs.cMaxAttrs; i++) { if (My_lstrcmpi (pszAttrName, puia->Attrs.aPairs[i].pszName) == 0) { puia->Attrs.aPairs[i].pszValue = (TCHAR *) ppszAttrValue; break; } } } else { // Deal with standard attributes // for (i = 0; i < COUNT_ENUM_DIR_CLIENT_INFO; i++) { if (My_lstrcmpi (pszAttrName, c_apszClientStdAttrNames[i]) == 0) { puia->ClientInfo.apszStdAttrValues[i] = (TCHAR *) ppszAttrValue; break; } } } } #ifdef ENABLE_MEETING_PLACE VOID CacheEnumMtgInfoAttr ( MTG_INFO_ATTRS *pmia, TCHAR *pszAttrName, TCHAR **ppszAttrValue ) { ULONG i; // See if this attribute is arbitrary? // if (IlsIsAnyAttrName (pszAttrName) != NULL) { // Deal with extended attributes // for (i = 0; i < pmia->Attrs.cMaxAttrs; i++) { if (My_lstrcmpi (pszAttrName, pmia->Attrs.aPairs[i].pszName) == 0) { pmia->Attrs.aPairs[i].pszValue = (TCHAR *) ppszAttrValue; break; } } } else { // Deal with standard attributes // for (i = 0; i < COUNT_ENUM_DIRMTGINFO; i++) { if (My_lstrcmpi (pszAttrName, c_apszMtgStdAttrNames[i]) == 0) { pmia->MtgInfo.apszStdAttrValues[i] = (TCHAR *) ppszAttrValue; break; } } } } #endif // ENABLE_MEETING_PLACE HRESULT CacheEnumInfos ( ULONG uNotifyMsg, LDAP *ld, LDAPMessage *pEntry, VOID *p ) { MyAssert (ld != NULL); MyAssert (pEntry != NULL); MyAssert (p != NULL); struct berelement *pContext = NULL; // Examine the first attribute // TCHAR *pszAttrName = ldap_first_attribute (ld, pEntry, &pContext); TCHAR **ppszAttrValue = ldap_get_values (ld, pEntry, pszAttrName); if (ppszAttrValue == NULL) return ILS_E_MEMORY; // Cache the first attribute // switch (uNotifyMsg) { case WM_ILS_ENUM_CLIENTINFOS: CacheEnumClientInfoAttr ( (CLIENT_INFO_ATTRS *) p, pszAttrName, ppszAttrValue); break; #ifdef ENABLE_MEETING_PLACE case WM_ILS_ENUM_MEETINGINFOS: CacheEnumMtgInfoAttr ( (MTG_INFO_ATTRS *) p, pszAttrName, ppszAttrValue); break; #endif default: MyAssert (FALSE); break; } // Step through the others // while ((pszAttrName = ldap_next_attribute (ld, pEntry, pContext)) != NULL) { // Examine the other attributes one by one // ppszAttrValue = ldap_get_values (ld, pEntry, pszAttrName); if (ppszAttrValue == NULL) return ILS_E_MEMORY; // Cache the other attributes one by one // switch (uNotifyMsg) { case WM_ILS_ENUM_CLIENTINFOS: CacheEnumClientInfoAttr ( (CLIENT_INFO_ATTRS *) p, pszAttrName, ppszAttrValue); break; #ifdef ENABLE_MEETING_PLACE case WM_ILS_ENUM_MEETINGINFOS: CacheEnumMtgInfoAttr ( (MTG_INFO_ATTRS *) p, pszAttrName, ppszAttrValue); break; #endif default: MyAssert (FALSE); break; } } return S_OK; } VOID BuildEnumObjectNames ( LDAP_ENUM *pEnum, ENUM_LIST *pEnumList ) { MyAssert (pEnum != NULL); MyAssert (pEnumList != NULL); ULONG cEntries = pEnum->cItems; // appszObjectNames are an array of names from server // TCHAR *pszName = (TCHAR *) (pEnum + 1); TCHAR ***appszObjectNames = (TCHAR ***) &(pEnumList->bData[0]); for (ULONG i = 0; i < cEntries; i++) { TCHAR **ppsz = appszObjectNames[i]; if (ppsz != NULL && *ppsz != NULL) { My_lstrcpy (pszName, *ppsz); pszName += lstrlen (pszName) + 1; } else { *pszName++ = TEXT ('\0'); // empty strings } } } VOID BuildEnumClientInfos ( LDAP_ENUM *pEnum, ENUM_LIST *pEnumList ) { MyAssert (pEnum != NULL); MyAssert (pEnumList != NULL); ULONG i, j; ULONG cEntries = pEnumList->cItems; ULONG cbEntrySize = pEnumList->cbEntrySize; LDAP_CLIENTINFO *plci = (LDAP_CLIENTINFO *) (pEnum + 1); TCHAR *pszStringBuffer = (TCHAR *) (plci + cEntries); TCHAR **ppsz; CLIENT_INFO_ATTRS *p; ULONG cAttrs; // Loop through all entries // for (i = 0; i < cEntries; i++, plci++) { // Get to cached structure // p = (CLIENT_INFO_ATTRS *) (&(pEnumList->bData[0]) + i * cbEntrySize); // Set the size of LDAP_USERINFO // plci->uSize = sizeof (*plci); // Copy the User Name if needed // ppsz = (TCHAR **) p->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_CN]; if (ppsz != NULL) { plci->uOffsetCN = (ULONG)((ULONG_PTR) pszStringBuffer - (ULONG_PTR) plci); My_lstrcpy (pszStringBuffer, *ppsz); pszStringBuffer += lstrlen (pszStringBuffer) + 1; } // Copy the First Name if needed // ppsz = (TCHAR **) p->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_FIRST_NAME]; if (ppsz != NULL) { plci->uOffsetFirstName = (ULONG)((ULONG_PTR) pszStringBuffer - (ULONG_PTR) plci); My_lstrcpy (pszStringBuffer, *ppsz); pszStringBuffer += lstrlen (pszStringBuffer) + 1; } // Copy the Last Name if needed // ppsz = (TCHAR **) p->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_LAST_NAME]; if (ppsz != NULL) { plci->uOffsetLastName = (ULONG)((ULONG_PTR) pszStringBuffer - (ULONG_PTR) plci); My_lstrcpy (pszStringBuffer, *ppsz); pszStringBuffer += lstrlen (pszStringBuffer) + 1; } // Copy the Email Name if needed // ppsz = (TCHAR **) p->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_EMAIL_NAME]; if (ppsz != NULL) { plci->uOffsetEMailName = (ULONG)((ULONG_PTR) pszStringBuffer - (ULONG_PTR) plci); My_lstrcpy (pszStringBuffer, *ppsz); pszStringBuffer += lstrlen (pszStringBuffer) + 1; } // Copy the City Name if needed // ppsz = (TCHAR **) p->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_CITY_NAME]; if (ppsz != NULL) { plci->uOffsetCityName = (ULONG)((ULONG_PTR) pszStringBuffer - (ULONG_PTR) plci); My_lstrcpy (pszStringBuffer, *ppsz); pszStringBuffer += lstrlen (pszStringBuffer) + 1; } // Copy the Country Name if needed // ppsz = (TCHAR **) p->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_C]; if (ppsz != NULL) { plci->uOffsetCountryName = (ULONG)((ULONG_PTR) pszStringBuffer - (ULONG_PTR) plci); My_lstrcpy (pszStringBuffer, *ppsz); pszStringBuffer += lstrlen (pszStringBuffer) + 1; } // Copy the Comment Name if needed // ppsz = (TCHAR **) p->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_COMMENT]; if (ppsz != NULL) { plci->uOffsetComment = (ULONG)((ULONG_PTR) pszStringBuffer - (ULONG_PTR) plci); My_lstrcpy (pszStringBuffer, *ppsz); pszStringBuffer += lstrlen (pszStringBuffer) + 1; } // Copy the IP Address if needed // ppsz = (TCHAR **) p->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_IP_ADDRESS]; if (ppsz != NULL) { plci->uOffsetIPAddress = (ULONG)((ULONG_PTR) pszStringBuffer - (ULONG_PTR) plci); GetIPAddressString (pszStringBuffer, GetStringLong (*ppsz)); pszStringBuffer += lstrlen (pszStringBuffer) + 1; } // Copy the Flags if needed // ppsz = (TCHAR **) p->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_FLAGS]; if (ppsz != NULL) { plci->dwFlags = (*ppsz != NULL) ? GetStringLong (*ppsz) : INVALID_USER_FLAGS; } // Copy extended attributes if needed // plci->cAttrsReturned = cAttrs = p->Attrs.cMaxAttrs; plci->uOffsetAttrsReturned = (ULONG)((ULONG_PTR) pszStringBuffer - (ULONG_PTR) plci); for (j = 0; j < cAttrs; j++) { // Extended attribute name // My_lstrcpy (pszStringBuffer, IlsSkipAnyAttrNamePrefix ( (const TCHAR *) p->Attrs.aPairs[j].pszName)); pszStringBuffer += lstrlen (pszStringBuffer) + 1; // Extended attribute value // ppsz = (TCHAR **) p->Attrs.aPairs[j].pszValue; if (ppsz != NULL) { My_lstrcpy (pszStringBuffer, *ppsz); } else { ASSERT(FALSE); } pszStringBuffer += lstrlen (pszStringBuffer) + 1; } // for j } // for i } #ifdef ENABLE_MEETING_PLACE VOID BuildEnumMtgInfos ( LDAP_ENUM *pEnum, ENUM_LIST *pEnumList ) { MyAssert (pEnum != NULL); MyAssert (pEnumList != NULL); ULONG i, j; ULONG cEntries = pEnumList->cItems; ULONG cbEntrySize = pEnumList->cbEntrySize; LDAP_MEETINFO *plmi = (LDAP_MEETINFO *) (pEnum + 1); TCHAR *pszStringBuffer = (TCHAR *) (plmi + cEntries); TCHAR **ppsz; MTG_INFO_ATTRS *p; ULONG cAttrs; // Loop through all entries // for (i = 0; i < cEntries; i++, plmi++) { // Get to the cache structure // p = (MTG_INFO_ATTRS *) (&(pEnumList->bData[0]) + i * cbEntrySize); // Set the size of LDAP_MEETINFO // plmi->uSize = sizeof (*plmi); // Copy the Meeting Name if needed // ppsz = (TCHAR **) p->MtgInfo.apszStdAttrValues[ENUM_MTGATTR_CN]; if (ppsz != NULL) { plmi->uOffsetMeetingPlaceID = (ULONG) pszStringBuffer - (ULONG) plmi; My_lstrcpy (pszStringBuffer, *ppsz); pszStringBuffer += lstrlen (pszStringBuffer) + 1; } // Copy the Meeting Type if needed // ppsz = (TCHAR **) p->MtgInfo.apszStdAttrValues[ENUM_MTGATTR_MTG_TYPE]; if (ppsz != NULL) { plmi->lMeetingPlaceType = (*ppsz != NULL) ? GetStringLong (*ppsz) : INVALID_MEETING_TYPE; } // Copy the Attendee Type if needed // ppsz = (TCHAR **) p->MtgInfo.apszStdAttrValues[ENUM_MTGATTR_MEMBER_TYPE]; if (ppsz != NULL) { plmi->lAttendeeType = (*ppsz != NULL) ? GetStringLong (*ppsz) : INVALID_ATTENDEE_TYPE; } // Copy the Description if needed // ppsz = (TCHAR **) p->MtgInfo.apszStdAttrValues[ENUM_MTGATTR_DESCRIPTION]; if (ppsz != NULL) { plmi->uOffsetDescription = (ULONG) pszStringBuffer - (ULONG) plmi; My_lstrcpy (pszStringBuffer, *ppsz); pszStringBuffer += lstrlen (pszStringBuffer) + 1; } // Copy the Host Name if needed // ppsz = (TCHAR **) p->MtgInfo.apszStdAttrValues[ENUM_MTGATTR_HOST_NAME]; if (ppsz != NULL) { plmi->uOffsetHostName = (ULONG) pszStringBuffer - (ULONG) plmi; My_lstrcpy (pszStringBuffer, *ppsz); pszStringBuffer += lstrlen (pszStringBuffer) + 1; } // Copy the Host IP Address if needed // ppsz = (TCHAR **) p->MtgInfo.apszStdAttrValues[ENUM_MTGATTR_IP_ADDRESS]; if (ppsz != NULL) { plmi->uOffsetHostIPAddress = (ULONG) pszStringBuffer - (ULONG) plmi; GetIPAddressString (pszStringBuffer, GetStringLong (*ppsz)); pszStringBuffer += lstrlen (pszStringBuffer) + 1; } // Copy extended attributes if needed // plmi->cAttrsReturned = cAttrs = p->Attrs.cMaxAttrs; plmi->uOffsetAttrsReturned = (ULONG) pszStringBuffer - (ULONG) plmi; for (j = 0; j < cAttrs; j++) { // Extended attribute name // My_lstrcpy (pszStringBuffer, IlsSkipAnyAttrNamePrefix ( (const TCHAR *) p->Attrs.aPairs[j].pszName)); pszStringBuffer += lstrlen (pszStringBuffer) + 1; // Extended attribute value // ppsz = (TCHAR **) p->Attrs.aPairs[j].pszValue; My_lstrcpy (pszStringBuffer, *ppsz); pszStringBuffer += lstrlen (pszStringBuffer) + 1; } // for j } // for i } #endif // ENABLE_MEETING_PLACE VOID TotalSizeEnumObjectNames ( ULONG *pcbTotalSize, ULONG cEntries, TCHAR **appszObjectNames[] ) { ULONG i, cbThisSize; TCHAR **ppsz; // Loop through all the entries and compute the total size // for (i = 0; i < cEntries; i++) { ppsz = appszObjectNames[i]; // Calcualte the attribute string length // cbThisSize = 1; if (ppsz != NULL && *ppsz != NULL) cbThisSize += My_lstrlen (*ppsz); // Convert string length to string size // cbThisSize *= sizeof (TCHAR); // Add up this entry size // // lonchanc: BUGS BUGS the size is wrong. need to figure out the exact size *pcbTotalSize += sizeof (LDAP_CLIENTINFO) + cbThisSize; } } VOID SizeEnumClientInfos ( ULONG *pcbTotalSize, CLIENT_INFO_ATTRS *pcia ) { ULONG i, cbThisSize; TCHAR **ppsz; // Add up user info header // *pcbTotalSize += sizeof (LDAP_CLIENTINFO); // Add up the total size for standard attributes // for (i = 0; i < COUNT_ENUM_DIR_CLIENT_INFO; i++) { // Get the attribute value // ppsz = (TCHAR **) pcia->ClientInfo.apszStdAttrValues[i]; // Calcualte the attribute string length // cbThisSize = 1; if (ppsz != NULL && *ppsz != NULL) cbThisSize += My_lstrlen (*ppsz); // Compensate the string length if it is ip address // if (i == ENUM_CLIENTATTR_IP_ADDRESS) cbThisSize += 16; // Convert string length to string size // cbThisSize *= sizeof (TCHAR); // Add up this entry size // *pcbTotalSize += cbThisSize; } // Add up the total size for extended attributes // for (i = 0; i < pcia->Attrs.cMaxAttrs; i++) { // Get the extended attribute value // ppsz = (TCHAR **) pcia->Attrs.aPairs[i].pszValue; // Calcualte the attribute string length // cbThisSize = 1; if (ppsz != NULL && *ppsz != NULL) cbThisSize += My_lstrlen (*ppsz); // Get the extended attribute name // cbThisSize += lstrlen (IlsSkipAnyAttrNamePrefix ((const TCHAR *) pcia->Attrs.aPairs[i].pszName)) + 1; // Convert string length to string size // cbThisSize *= sizeof (TCHAR); // Add up this entry size // *pcbTotalSize += cbThisSize; } } #ifdef ENABLE_MEETING_PLACE VOID SizeEnumMtgInfos ( ULONG *pcbTotalSize, MTG_INFO_ATTRS *pmia ) { ULONG i, cbThisSize; TCHAR **ppsz; // Add up meeting info header // *pcbTotalSize += sizeof (LDAP_MEETINFO); // Add up the total size for standard attributes // for (i = 0; i < COUNT_ENUM_DIRMTGINFO; i++) { // Get the standard attribute value // ppsz = (TCHAR **) pmia->MtgInfo.apszStdAttrValues[i]; // Calcualte the attribute string length // cbThisSize = 1; if (ppsz != NULL && *ppsz != NULL) cbThisSize += My_lstrlen (*ppsz); // Compensate the string length if it is ip address // if (i == ENUM_MTGATTR_IP_ADDRESS) cbThisSize += 16; // Convert string length to string size // cbThisSize *= sizeof (TCHAR); // Add up this entry size // *pcbTotalSize += cbThisSize; } // Add up the total size for extended attributes // for (i = 0; i < pmia->Attrs.cMaxAttrs; i++) { // Get the extended attribute value // ppsz = (TCHAR **) pmia->Attrs.aPairs[i].pszValue; // Calcualte the attribute string length // cbThisSize = 1; if (ppsz != NULL && *ppsz != NULL) cbThisSize += My_lstrlen (*ppsz); // Get the extended attribute name // cbThisSize += lstrlen (IlsSkipAnyAttrNamePrefix ((const TCHAR *) pmia->Attrs.aPairs[i].pszName)) + 1; // Convert string length to string size // cbThisSize *= sizeof (TCHAR); // Add up this entry size // *pcbTotalSize += cbThisSize; } } #endif // ENABLE_MEETING_PLACE /* =========== RESOLVE ============ */ typedef HRESULT (INFO_HANDLER) ( VOID *, const TCHAR *, const TCHAR ** ); extern HRESULT CacheResolveClientInfoAttr ( VOID *, const TCHAR *, const TCHAR ** ); extern HRESULT CacheResolveProtInfoAttr ( VOID *, const TCHAR *, const TCHAR ** ); extern HRESULT CacheResolveMtgInfoAttr ( VOID *, const TCHAR *, const TCHAR ** ); BOOL NotifyResolveX ( HRESULT hrServer, SP_CResponse *pItem, VOID *pInfo, INFO_HANDLER *pHandler ) { MyAssert (pItem != NULL); MyAssert (pInfo != NULL); MyAssert (pHandler != NULL); // Get the ldap result // LDAPMessage *pLdapMsg = pItem->GetResult (); MyAssert (pLdapMsg != NULL); if (pLdapMsg == NULL) { MyAssert (FALSE); hrServer = ILS_E_POINTER; goto MyExit; } // Get ld // LDAP *ld; ld = pItem->GetLd (); if (ld == NULL) { MyAssert (FALSE); hrServer = ILS_E_HANDLE; goto MyExit; } // Get the first entry that we care only // LDAPMessage *pEntry; pEntry = ldap_first_entry (ld, pLdapMsg); if (pEntry == NULL) { MyAssert (FALSE); hrServer = ILS_E_MEMORY; goto MyExit; } // Initialize wldap32.dll context // struct berelement *pContext; pContext = NULL; // Examine the first attribute // TCHAR *pszAttrName; pszAttrName = ldap_first_attribute (ld, pEntry, &pContext); if (pszAttrName == NULL) { MyAssert (FALSE); hrServer = ILS_E_MEMORY; goto MyExit; } TCHAR **ppszAttrVal; ppszAttrVal = ldap_get_values (ld, pEntry, pszAttrName); if (ppszAttrVal == NULL) { MyAssert (FALSE); hrServer = ILS_E_MEMORY; goto MyExit; } // Cache this attribute name (if needed) and value // HRESULT hr; hr = (*pHandler) (pInfo, pszAttrName,(const TCHAR **) ppszAttrVal); ldap_value_free (ppszAttrVal); if (hr != S_OK) { hrServer = hr; goto MyExit; } // Step through the other attributes // while ((pszAttrName = ldap_next_attribute (ld, pEntry, pContext)) != NULL) { ppszAttrVal = ldap_get_values (ld, pEntry, pszAttrName); if (ppszAttrVal == NULL) { MyAssert (FALSE); hrServer = ILS_E_MEMORY; goto MyExit; } // Cache the other attribute names (if needed) and values // hr = (*pHandler) (pInfo, pszAttrName, (const TCHAR **) ppszAttrVal); ldap_value_free (ppszAttrVal); if (hr != S_OK) { hrServer = hr; goto MyExit; } } MyAssert (hrServer == S_OK); MyExit: return hrServer; } BOOL NotifyResolveClient ( HRESULT hrServer, SP_CResponse *pItem ) { MyAssert (pItem != NULL); ULONG i; // Get the pending info // RESP_INFO *pInfo = pItem->GetRespInfo (); MyAssert (pInfo != NULL); // Initialize minimal info // LDAP_CLIENTINFO_RES *pClientRes = NULL; CLIENT_INFO_ATTRS *pcia = NULL; // If error, simply report the error // if (hrServer != S_OK) goto MyExit; // Get the ldap result // LDAPMessage *pLdapMsg; pLdapMsg = pItem->GetResult (); if (pLdapMsg == NULL) { MyAssert (FALSE); goto MyExit; } // Get ld // LDAP *ld; ld = pItem->GetLd (); if (ld == NULL) { MyAssert (FALSE); hrServer = ILS_E_HANDLE; goto MyExit; } // Get the count of attributes // ULONG cAttrs; cAttrs = my_ldap_count_1st_entry_attributes (ld, pLdapMsg); if (cAttrs == 0) { hrServer = ILS_E_NO_MORE; goto MyExit; } // Allocate result set holder // pcia = (CLIENT_INFO_ATTRS *) MemAlloc ( sizeof (CLIENT_INFO_ATTRS) + cAttrs * sizeof (ATTR_PAIR)); if (pcia == NULL) { hrServer = ILS_E_MEMORY; goto MyExit; } // Initialize result set holder // pcia->Attrs.cMaxAttrs = cAttrs; // Cache resolve set // hrServer = NotifyResolveX ( hrServer, pItem, pcia, CacheResolveClientInfoAttr); if (hrServer != S_OK) { goto MyExit; } // Initialize the total size // ULONG cbTotalSize, cbThisSize; cbTotalSize = sizeof (LDAP_CLIENTINFO_RES); // Loop through all attributes in order to compute the total size // for (i = 0; i < COUNT_ENUM_RES_CLIENT_INFO; i++) { if (pcia->ClientInfo.apszStdAttrValues[i] != NULL) { // Get the string length // cbThisSize = My_lstrlen (pcia->ClientInfo.apszStdAttrValues[i]) + 1; // Compensate for the ip address // if (i == ENUM_CLIENTATTR_IP_ADDRESS) cbThisSize += 16; // Convert string length to string size // cbThisSize *= sizeof (TCHAR); // Add up to the total size // cbTotalSize += cbThisSize; } } // Loop through extended attributes // for (i = 0; i < pcia->Attrs.cCurrAttrs; i++) { cbThisSize = My_lstrlen (pcia->Attrs.aPairs[i].pszName) + 1; cbThisSize += My_lstrlen (pcia->Attrs.aPairs[i].pszValue) + 1; cbThisSize *= sizeof (TCHAR); cbTotalSize += cbThisSize; } // Allocate LDAP_USERINFO_RES structure // pClientRes = (LDAP_CLIENTINFO_RES *) MemAlloc (cbTotalSize); if (pClientRes == NULL) { MyAssert (FALSE); // we are in deep trouble here hrServer = ILS_E_MEMORY; goto MyExit; } // Fill in common fields // pClientRes->uSize = sizeof (*pClientRes); pClientRes->hResult = hrServer; pClientRes->lci.uSize = sizeof (pClientRes->lci); // Prepare to copy strings // TCHAR *pszDst, *pszSrc; pszDst = (TCHAR *) (pClientRes + 1); // Copy user object's standard attributes // pszSrc = pcia->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_CN]; if (pszSrc != NULL) { pClientRes->lci.uOffsetCN = (ULONG)((ULONG_PTR) pszDst - (ULONG_PTR) &(pClientRes->lci)); My_lstrcpy (pszDst, pszSrc); pszDst += lstrlen (pszDst) + 1; } pszSrc = pcia->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_FIRST_NAME]; if (pszSrc != NULL) { pClientRes->lci.uOffsetFirstName = (ULONG)((ULONG_PTR) pszDst - (ULONG_PTR) &(pClientRes->lci)); My_lstrcpy (pszDst, pszSrc); pszDst += lstrlen (pszDst) + 1; } pszSrc = pcia->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_LAST_NAME]; if (pszSrc != NULL) { pClientRes->lci.uOffsetLastName = (ULONG)((ULONG_PTR) pszDst - (ULONG_PTR) &(pClientRes->lci)); My_lstrcpy (pszDst, pszSrc); pszDst += lstrlen (pszDst) + 1; } pszSrc = pcia->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_EMAIL_NAME]; if (pszSrc != NULL) { pClientRes->lci.uOffsetEMailName = (ULONG)((ULONG_PTR) pszDst - (ULONG_PTR) &(pClientRes->lci)); My_lstrcpy (pszDst, pszSrc); pszDst += lstrlen (pszDst) + 1; } pszSrc = pcia->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_CITY_NAME]; if (pszSrc != NULL) { pClientRes->lci.uOffsetCityName = (ULONG)((ULONG_PTR) pszDst - (ULONG_PTR) &(pClientRes->lci)); My_lstrcpy (pszDst, pszSrc); pszDst += lstrlen (pszDst) + 1; } pszSrc = pcia->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_C]; if (pszSrc != NULL) { pClientRes->lci.uOffsetCountryName = (ULONG)((ULONG_PTR) pszDst - (ULONG_PTR) &(pClientRes->lci)); My_lstrcpy (pszDst, pszSrc); pszDst += lstrlen (pszDst) + 1; } pszSrc = pcia->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_COMMENT]; if (pszSrc != NULL) { pClientRes->lci.uOffsetComment = (ULONG)((ULONG_PTR) pszDst - (ULONG_PTR) &(pClientRes->lci)); My_lstrcpy (pszDst, pszSrc); pszDst += lstrlen (pszDst) + 1; } pszSrc = pcia->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_IP_ADDRESS]; if (pszSrc != NULL) { pClientRes->lci.uOffsetIPAddress = (ULONG)((ULONG_PTR) pszDst - (ULONG_PTR) &(pClientRes->lci)); GetIPAddressString (pszDst, GetStringLong (pszSrc)); pszDst += lstrlen (pszDst) + 1; } pszSrc = pcia->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_FLAGS]; if (pszSrc != NULL) { pClientRes->lci.dwFlags = (pszSrc != NULL)? GetStringLong (pszSrc) : INVALID_USER_FLAGS; } // Copy app object's standard attributes // pszSrc = pcia->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_APP_NAME]; if (pszSrc != NULL) { pClientRes->lci.uOffsetAppName = (ULONG)((ULONG_PTR) pszDst - (ULONG_PTR) &(pClientRes->lci)); My_lstrcpy (pszDst, pszSrc); pszDst += lstrlen (pszDst) + 1; } pszSrc = pcia->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_APP_MIME_TYPE]; if (pszSrc != NULL) { pClientRes->lci.uOffsetAppMimeType = (ULONG)((ULONG_PTR) pszDst - (ULONG_PTR) &(pClientRes->lci)); My_lstrcpy (pszDst, pszSrc); pszDst += lstrlen (pszDst) + 1; } pszSrc = pcia->ClientInfo.apszStdAttrValues[ENUM_CLIENTATTR_APP_GUID]; if (MyIsGoodString (pszSrc)) { GetStringGuid (pszSrc, &(pClientRes->lci.AppGuid)); } else { ZeroMemory (&(pClientRes->lci.AppGuid), sizeof (pClientRes->lci.AppGuid)); } // Copy app object's extended attributes // pClientRes->lci.cAttrsReturned = pcia->Attrs.cCurrAttrs; if (pClientRes->lci.cAttrsReturned > 0) { pClientRes->lci.uOffsetAttrsReturned = (ULONG)((ULONG_PTR) pszDst - (ULONG_PTR) &(pClientRes->lci)); for (i = 0; i < pcia->Attrs.cCurrAttrs; i++) { My_lstrcpy (pszDst, pcia->Attrs.aPairs[i].pszName); pszDst += lstrlen (pszDst) + 1; My_lstrcpy (pszDst, pcia->Attrs.aPairs[i].pszValue); pszDst += lstrlen (pszDst) + 1; } } MyAssert (hrServer == S_OK); MyExit: // Free temporary result set holder // if (pcia != NULL) { // Free standard attributes // for (INT i = 0; i < COUNT_ENUM_CLIENT_INFO; i++) { MemFree (pcia->ClientInfo.apszStdAttrValues[i]); } // Free arbitrary attributes // for (ULONG j = 0; j < pcia->Attrs.cCurrAttrs; j++) { MemFree (pcia->Attrs.aPairs[j].pszName); MemFree (pcia->Attrs.aPairs[j].pszValue); } // Free the holder itself // MemFree (pcia); } // Clean up the return structure if failure // if (hrServer != S_OK) { // Make sure we have a return structure // if (pClientRes != NULL) ZeroMemory (pClientRes, sizeof (*pClientRes)); else pClientRes = (LDAP_CLIENTINFO_RES *) MemAlloc (sizeof (LDAP_CLIENTINFO_RES)); // Fill in the minimal info // if (pClientRes != NULL) { pClientRes->uSize = sizeof (*pClientRes); pClientRes->hResult = hrServer; } } // Post a message to the com layer // PostMessage (g_hWndNotify, pInfo->uNotifyMsg, pInfo->uRespID, (LPARAM) pClientRes); // Delete this pending item // return TRUE; } HRESULT CacheResolveClientInfoAttr ( VOID *pInfo, const TCHAR *pszAttrName, const TCHAR **ppszAttrVal ) { MyAssert (pInfo != NULL); MyAssert (pszAttrName != NULL); // Shorthand meeting info pointer // CLIENT_INFO_ATTRS *pcia = (CLIENT_INFO_ATTRS *) pInfo; // See if this attribute is arbitrary? // const TCHAR *pszRealAnyName = IlsIsAnyAttrName (pszAttrName); if (pszRealAnyName != NULL) { MyAssert (pcia->Attrs.cCurrAttrs < pcia->Attrs.cMaxAttrs); // Duplicate the name // pcia->Attrs.aPairs[pcia->Attrs.cCurrAttrs].pszName = My_strdup (pszRealAnyName); // Duplicate the value // BUGS: we should avoid duplicate the string here (cf. enum-user-infos) // if (ppszAttrVal != NULL) { pcia->Attrs.aPairs[pcia->Attrs.cCurrAttrs++].pszValue = My_strdup (*ppszAttrVal); } else { // ILS server bug or wldap32.dll bug // MyAssert (FALSE); } } else { // Loop through all standard attributes // for (INT i = 0; i < COUNT_ENUM_RES_CLIENT_INFO; i++) { // Figure out what attribute it is // if (My_lstrcmpi (c_apszClientStdAttrNames[i], pszAttrName) == 0) { // Free the previously allocated value if any // MemFree (pcia->ClientInfo.apszStdAttrValues[i]); // Duplicate the value // BUGS: we should avoid duplicate the string here (cf. enum-user-infos) // if (ppszAttrVal != NULL) { pcia->ClientInfo.apszStdAttrValues[i] = DuplicateGoodString (*ppszAttrVal); } else { // ILS server bug or wldap32.dll bug // MyAssert (FALSE); } break; } } } return S_OK; } typedef struct { PROT_INFO ProtInfo; TCHAR *pszProtNameToResolve; BOOL fFindIndex; LONG nIndex; } PROT_INFO_EX; enum { INVALID_INDEX = -1 }; BOOL NotifyResolveProt ( HRESULT hrServer, SP_CResponse *pItem ) { MyAssert (pItem != NULL); // Get the pending info // RESP_INFO *pInfo = pItem->GetRespInfo (); MyAssert (pInfo != NULL); // Initialize minimal info // LDAP_PROTINFO_RES *pProtRes = NULL; PROT_INFO_EX *ppi = NULL; // If error, simply report the error // if (hrServer != S_OK) goto MyExit; // Allocate result holder // ppi = (PROT_INFO_EX *) MemAlloc (sizeof (PROT_INFO_EX)); if (ppi == NULL) { hrServer = ILS_E_MEMORY; goto MyExit; } // Cache the protocol name to resolve // MyAssert (pInfo->pszProtNameToResolve != NULL); ppi->pszProtNameToResolve = pInfo->pszProtNameToResolve; ppi->nIndex = INVALID_INDEX; // Call the common routine to find the index // ppi->fFindIndex = TRUE; hrServer = NotifyResolveX (hrServer, pItem, ppi, CacheResolveProtInfoAttr); if (hrServer != S_OK) goto MyExit; // Check to see if we found the index // if (ppi->nIndex == INVALID_INDEX) { hrServer = ILS_E_NO_SUCH_OBJECT; goto MyExit; } // Call the common routine AGAIN to save attribute values // ppi->fFindIndex = FALSE; hrServer = NotifyResolveX (hrServer, pItem, ppi, CacheResolveProtInfoAttr); if (hrServer != S_OK) goto MyExit; // Initialize the size // ULONG cbTotalSize, cbThisSize; cbTotalSize = sizeof (LDAP_PROTINFO_RES); // Loop through standard attrs // ULONG i; for (i = 0; i < COUNT_ENUM_PROTATTR; i++) { if (ppi->ProtInfo.apszStdAttrValues[i] != NULL) { cbThisSize = My_lstrlen (ppi->ProtInfo.apszStdAttrValues[i]) + 1; cbThisSize *= sizeof (TCHAR); cbTotalSize += cbThisSize; } } // Allocate LDAP_PROTINFO_RES structure // pProtRes = (LDAP_PROTINFO_RES *) MemAlloc (cbTotalSize); if (pProtRes == NULL) { MyAssert (FALSE); // we are in deep trouble here hrServer = ILS_E_MEMORY; goto MyExit; } // Fill in fields // pProtRes->uSize = sizeof (*pProtRes); pProtRes->hResult = hrServer; pProtRes->lpi.uSize = sizeof (pProtRes->lpi); TCHAR *pszSrc, *pszDst; pszDst = (TCHAR *) (pProtRes + 1); // Copy protocol name // pszSrc = ppi->ProtInfo.apszStdAttrValues[ENUM_PROTATTR_NAME]; if (pszSrc != NULL) { pProtRes->lpi.uOffsetName = (ULONG)((ULONG_PTR) pszDst - (ULONG_PTR) &(pProtRes->lpi)); My_lstrcpy (pszDst, pszSrc); pszDst += lstrlen (pszDst) + 1; } // Copy protocol mime type // pszSrc = ppi->ProtInfo.apszStdAttrValues[ENUM_PROTATTR_MIME_TYPE]; if (pszSrc != NULL) { pProtRes->lpi.uOffsetMimeType = (ULONG)((ULONG_PTR) pszDst - (ULONG_PTR) &(pProtRes->lpi)); My_lstrcpy (pszDst, pszSrc); pszDst += lstrlen (pszDst) + 1; } // Copy protocol prot number // pszSrc = ppi->ProtInfo.apszStdAttrValues[ENUM_PROTATTR_PORT_NUMBER]; if (pszSrc != NULL) { pProtRes->lpi.uPortNumber = GetStringLong (pszSrc); } MyAssert (hrServer == S_OK); MyExit: // Free temporary app result holder // if (ppi != NULL) { for (INT i = 0; i < COUNT_ENUM_PROTATTR; i++) { MemFree (ppi->ProtInfo.apszStdAttrValues[i]); } MemFree (ppi); } // Clean up the return structure if failure // if (hrServer != S_OK) { // Make sure we have a valid returned structure // if (pProtRes != NULL) ZeroMemory (pProtRes, sizeof (*pProtRes)); else pProtRes = (LDAP_PROTINFO_RES *) MemAlloc (sizeof (LDAP_PROTINFO_RES)); // Fill in the minimal info // if (pProtRes != NULL) { pProtRes->uSize = sizeof (*pProtRes); pProtRes->hResult = hrServer; } } // Post the result to the com layer // PostMessage (g_hWndNotify, pInfo->uNotifyMsg, pInfo->uRespID, (LPARAM) pProtRes); // Destroy this pending item // return TRUE; } HRESULT CacheResolveProtInfoAttr ( VOID *pInfo, const TCHAR *pszAttrName, const TCHAR **ppszAttrVal ) { MyAssert (pInfo != NULL); MyAssert (pszAttrName != NULL); // Shorthand prot info pointer // PROT_INFO_EX *ppi = (PROT_INFO_EX *) pInfo; // Are we trying to find the index of the protocol to resolve? // if (ppi->fFindIndex) { // If we already located the index, then simply return // if (ppi->nIndex == INVALID_INDEX) { // Looking for "sprotid" // if (My_lstrcmpi (STR_PROT_NAME, pszAttrName) == 0) { // Get to the protocol name attribute // if (ppszAttrVal != NULL) { TCHAR *pszVal; for (LONG nIndex = 0; (pszVal = (TCHAR *) ppszAttrVal[nIndex]) != NULL; nIndex++) { if (My_lstrcmpi (ppi->pszProtNameToResolve, pszVal) == 0) { // Locate the same protocol name, remember the index // ppi->nIndex = nIndex; break; // return S_OK; // we should be able to return from here } } } else { // ILS server bug or wldap32.dll bug // MyAssert (FALSE); } } } } else { // Loop through all standard attributes // for (INT i = 0; i < COUNT_ENUM_PROTATTR; i++) { // Figure out what attribute it is // if (My_lstrcmpi (c_apszProtStdAttrNames[i], pszAttrName) == 0) { // Free the previously allocated value if any // MemFree (ppi->ProtInfo.apszStdAttrValues[i]); // Duplicate the value // BUGS: we should avoid duplicate the string here (cf. enum-user-infos) // if (ppszAttrVal != NULL) { // Make sure that we do not fault when the ILS server or wldap32.dll has a bug // for (LONG nIndex = 0; nIndex <= ppi->nIndex; nIndex++) { if (ppszAttrVal[nIndex] == NULL) { // ILS server bug // MyAssert (FALSE); return S_OK; } } // Duplicate the attribute value // ppi->ProtInfo.apszStdAttrValues[i] = My_strdup (ppszAttrVal[ppi->nIndex]); } else { // ILS server bug or wldap32.dll bug // MyAssert (FALSE); } break; } } } return S_OK; } #ifdef ENABLE_MEETING_PLACE BOOL NotifyResolveMtg ( HRESULT hrServer, SP_CResponse *pItem ) { MyAssert (pItem != NULL); // Get pending info // RESP_INFO *pInfo = pItem->GetRespInfo (); MyAssert (pInfo != NULL); // Initialize minimal return info // LDAP_MEETINFO_RES *pMtgRes = NULL; MTG_INFO_ATTRS *pmia = NULL; // If error, simply report the error // if (hrServer != S_OK) goto MyExit; // Get the ldap result // LDAPMessage *pLdapMsg; pLdapMsg = pItem->GetResult (); if (pLdapMsg == NULL) { MyAssert (FALSE); goto MyExit; } // Get ld // LDAP *ld; ld = pItem->GetLd (); if (ld == NULL) { MyAssert (FALSE); hrServer = ILS_E_HANDLE; goto MyExit; } // Get the count of attributes // ULONG cAttrs; cAttrs = my_ldap_count_1st_entry_attributes (ld, pLdapMsg); if (cAttrs == 0) { hrServer = ILS_E_NO_MORE; goto MyExit; } // Allocate result set holder // pmia = (MTG_INFO_ATTRS *) MemAlloc ( sizeof (MTG_INFO_ATTRS) + cAttrs * sizeof (ATTR_PAIR)); if (pmia == NULL) { hrServer = ILS_E_MEMORY; goto MyExit; } // Initialize result set holder // pmia->Attrs.cMaxAttrs = cAttrs; // Cache resolve set // hrServer = NotifyResolveX ( hrServer, pItem, pmia, CacheResolveMtgInfoAttr); if (hrServer != S_OK) goto MyExit; // Initialize the size // ULONG cbTotalSize, cbThisSize; cbTotalSize = sizeof (LDAP_MEETINFO_RES); // Loop through standard attrs to calculate the total size // ULONG i; for (i = 0; i < COUNT_ENUM_MTGATTR; i++) { if (pmia->MtgInfo.apszStdAttrValues[i] != NULL) { // Compute the string length // cbThisSize = My_lstrlen (pmia->MtgInfo.apszStdAttrValues[i]) + 1; // Compensate the string length if it is ip address // if (i == ENUM_MTGATTR_IP_ADDRESS) cbThisSize += 16; // Convert the string length to string size // cbThisSize *= sizeof (TCHAR); // Add up to the total size // cbTotalSize += cbThisSize; } } // Loop through arbitrary attrs to calculate the total size // for (i = 0; i < pmia->Attrs.cCurrAttrs; i++) { cbThisSize = My_lstrlen (pmia->Attrs.aPairs[i].pszName) + 1; cbThisSize += My_lstrlen (pmia->Attrs.aPairs[i].pszValue) + 1; cbThisSize *= sizeof (TCHAR); cbTotalSize += cbThisSize; } // Allocate LDAP_MTGINFO_RES structure // pMtgRes = (LDAP_MEETINFO_RES *) MemAlloc (cbTotalSize); if (pMtgRes == NULL) { MyAssert (FALSE); // we are in deep trouble here hrServer = ILS_E_MEMORY; goto MyExit; } // Fill in common fields // pMtgRes->uSize = sizeof (*pMtgRes); pMtgRes->hResult = hrServer; pMtgRes->lmi.uSize = sizeof (pMtgRes->lmi); TCHAR *pszSrc, *pszDst; pszDst = (TCHAR *) (pMtgRes + 1); // Copy Meeting Name if needed // pszSrc = pmia->MtgInfo.apszStdAttrValues[ENUM_MTGATTR_CN]; if (pszSrc != NULL) { pMtgRes->lmi.uOffsetMeetingPlaceID = (ULONG) pszDst - (ULONG) &(pMtgRes->lmi); My_lstrcpy (pszDst, pszSrc); pszDst += lstrlen (pszDst) + 1; } // Copy Meeting Type if needed // pszSrc = pmia->MtgInfo.apszStdAttrValues[ENUM_MTGATTR_MTG_TYPE]; if (pszSrc != NULL) { pMtgRes->lmi.lMeetingPlaceType = (pszSrc != NULL) ? GetStringLong (pszSrc) : INVALID_MEETING_TYPE; } // Copy Attendee Type if needed // pszSrc = pmia->MtgInfo.apszStdAttrValues[ENUM_MTGATTR_MEMBER_TYPE]; if (pszSrc != NULL) { pMtgRes->lmi.lAttendeeType = (pszSrc != NULL) ? GetStringLong (pszSrc) : INVALID_ATTENDEE_TYPE; } // Copy Description if needed // pszSrc = pmia->MtgInfo.apszStdAttrValues[ENUM_MTGATTR_DESCRIPTION]; if (pszSrc != NULL) { pMtgRes->lmi.uOffsetDescription = (ULONG) pszDst - (ULONG) &(pMtgRes->lmi); My_lstrcpy (pszDst, pszSrc); pszDst += lstrlen (pszDst) + 1; } // Copy Host Name if needed // pszSrc = pmia->MtgInfo.apszStdAttrValues[ENUM_MTGATTR_HOST_NAME]; if (pszSrc != NULL) { pMtgRes->lmi.uOffsetHostName = (ULONG) pszDst - (ULONG) &(pMtgRes->lmi); My_lstrcpy (pszDst, pszSrc); pszDst += lstrlen (pszDst) + 1; } // Copy Host IP Address if needed // pszSrc = pmia->MtgInfo.apszStdAttrValues[ENUM_MTGATTR_IP_ADDRESS]; if (pszSrc != NULL) { pMtgRes->lmi.uOffsetHostIPAddress = (ULONG) pszDst - (ULONG) &(pMtgRes->lmi); GetIPAddressString (pszDst, GetStringLong (pszSrc)); pszDst += lstrlen (pszDst) + 1; } // Copy extended attributes // pMtgRes->lmi.cAttrsReturned = pmia->Attrs.cCurrAttrs; if (pMtgRes->lmi.cAttrsReturned > 0) { pMtgRes->lmi.uOffsetAttrsReturned = (ULONG) pszDst - (ULONG) &(pMtgRes->lmi); for (i = 0; i < pmia->Attrs.cCurrAttrs; i++) { My_lstrcpy (pszDst, pmia->Attrs.aPairs[i].pszName); pszDst += lstrlen (pszDst) + 1; My_lstrcpy (pszDst, pmia->Attrs.aPairs[i].pszValue); pszDst += lstrlen (pszDst) + 1; } } MyAssert (hrServer == S_OK); MyExit: // Free temporary result set holder // if (pmia != NULL) { // Free standard attributes // for (INT i = 0; i < COUNT_ENUM_MTGATTR; i++) { MemFree (pmia->MtgInfo.apszStdAttrValues[i]); } // Free arbitrary attributes // for (ULONG j = 0; j < pmia->Attrs.cCurrAttrs; j++) { MemFree (pmia->Attrs.aPairs[j].pszName); MemFree (pmia->Attrs.aPairs[j].pszValue); } // Free the holder itself // MemFree (pmia); } // Clean up the return structure if failure // if (hrServer != S_OK) { // Make sure we have a return structure // if (pMtgRes != NULL) ZeroMemory (pMtgRes, sizeof (*pMtgRes)); else pMtgRes = (LDAP_MEETINFO_RES *) MemAlloc (sizeof (LDAP_MEETINFO_RES)); // Fill in the minimal info // if (pMtgRes != NULL) { pMtgRes->uSize = sizeof (*pMtgRes); pMtgRes->hResult = hrServer; } } // Post a message to the com layer // PostMessage (g_hWndNotify, pInfo->uNotifyMsg, pInfo->uRespID, (LPARAM) pMtgRes); // Delete this pending item // return TRUE; } #endif // ENABLE_MEETING_PLACE #ifdef ENABLE_MEETING_PLACE HRESULT CacheResolveMtgInfoAttr ( VOID *pInfo, const TCHAR *pszAttrName, const TCHAR **ppszAttrVal ) { MyAssert (pInfo != NULL); MyAssert (pszAttrName != NULL); // Shorthand meeting info pointer // MTG_INFO_ATTRS *pmia = (MTG_INFO_ATTRS *) pInfo; // See if this attribute is arbitrary? // const TCHAR *pszRealAnyName = IlsIsAnyAttrName (pszAttrName); if (pszRealAnyName != NULL) { MyAssert (pmia->Attrs.cCurrAttrs < pmia->Attrs.cMaxAttrs); // Duplicate the name // pmia->Attrs.aPairs[pmia->Attrs.cCurrAttrs].pszName = My_strdup (pszRealAnyName); // Duplicate the value // BUGS: we should avoid duplicate the string here (cf. enum-user-infos) // if (ppszAttrVal != NULL) { pmia->Attrs.aPairs[pmia->Attrs.cCurrAttrs++].pszValue = My_strdup (*ppszAttrVal); } else { // ILS server bug or wldap32.dll bug // MyAssert (FALSE); } } else { // Loop through all standard attributes // for (INT i = 0; i < COUNT_ENUM_RESMTGINFO; i++) { // Figure out what attribute it is // if (My_lstrcmpi (c_apszMtgStdAttrNames[i], pszAttrName) == 0) { // Free the previously allocated value if any // MemFree (pmia->MtgInfo.apszStdAttrValues[i]); // Duplicate the value // BUGS: we should avoid duplicate the string here (cf. enum-user-infos) // if (ppszAttrVal != NULL) { pmia->MtgInfo.apszStdAttrValues[i] = My_strdup (*ppszAttrVal); } else { // ILS server bug or wldap32.dll bug // MyAssert (FALSE); } break; } } } return S_OK; } #endif // ENABLE_MEETING_PLACE VOID FreeStdAttrCache ( TCHAR *apszStdAttrValues[], ULONG cStdAttrs ) { for (ULONG i = 0; i < cStdAttrs; i++) { if (apszStdAttrValues[i] != NULL) { ldap_value_free ((TCHAR **) apszStdAttrValues[i]); } } } VOID FreeAttrPairArrayCache ( ATTR_PAIR aAttrPair[], ULONG cPairs ) { if (aAttrPair != NULL) { for (ULONG j = 0; j < cPairs; j++) { if (aAttrPair[j].pszValue != NULL) { ldap_value_free ((TCHAR **) aAttrPair[j].pszValue); } } } } VOID CacheAnyAttrNamesInAttrPairs ( ULONG cNames, TCHAR *pszSrcNameList, ATTR_PAIR aPairs[] ) { MyAssert (cNames != 0); MyAssert (pszSrcNameList != NULL); MyAssert (aPairs != NULL); // Note that all these extended attribute names are already PREFIXED // for (ULONG i = 0; i < cNames; i++) { aPairs[i].pszName = pszSrcNameList; pszSrcNameList += lstrlen (pszSrcNameList) + 1; } }