Esempio n. 1
0
STDMETHODIMP CLDAPQuery::nextResults(
	/* [in] */ LONG results_id,
	/* [in] */ ULONG num_results,
	/* [retval][out] */ SAFEARRAY** result)
{
	CComSafeArray<VARIANT> dnList(0UL);

	ÑConnectInfo *cinfo = NULL;
	ÑResultsInfo *presinfo = NULL;
	m_errorCode = 0L;
	for(int i = 0; i < m_connections.GetSize(); i++)
	{
		ÑConnectInfo * const currentConnectInfo = m_connections.GetValueAt(i);
		if(currentConnectInfo)
		{
			ÑResultsInfo * const resInfo = currentConnectInfo->findResult(results_id);
			if(resInfo)
			{
				cinfo = currentConnectInfo;
				presinfo = resInfo;
				break;
			}
		}
	}
	if(cinfo && presinfo && presinfo->pages())
	{
		const PLDAP ld = cinfo->ld();
		const PLDAPSearch pPages = presinfo->pages();
		PLDAPMessage pMsg = NULL;
		const BOOL allResults = (num_results == 0UL);
		while((allResults || num_results > 0UL) &&
			(m_errorCode = ldap_get_next_page_s(ld, pPages, NULL, (num_results < 1000UL && num_results > 0UL ? num_results : 1000UL), NULL, &pMsg)) == LDAP_SUCCESS) //not more the 1k results per query
		{
			if(pMsg)
			{
				for(PLDAPMessage entry = ldap_first_entry(ld, pMsg); entry != NULL && (allResults || num_results-- > 0UL); entry = ldap_next_entry(ld, entry))
				{
					CComObject<CAssocObject> *obj;
					CComObject<CAssocObject>::CreateInstance(&obj);

					const PTCHAR dn = ldap_get_dn(ld, entry);
					obj->AddValue(_T("dn"), CComVariant(dn));

					PTCHAR attr;
					BerElement* berElem = NULL;
					for(attr = ldap_first_attribute(ld, entry, &berElem); attr != NULL; attr = ldap_next_attribute(ld, entry, berElem))
					{
						bool single = false;
						const AttrSchema* const schema = cinfo->attrSchemaLookup(attr);
						if(schema)
						{
							single = schema->single;
							if(schema->type == OctetString) //we need to work different only with binary data
							{
								PBERVAL *vals;
								if((vals = ldap_get_values_len(ld, entry, attr)) != NULL)
								{
									if(!single)
									{
										CComSafeArray<VARIANT> attrValues(ldap_count_values_len(vals));
										for(LONG i = 0L; vals[i] != NULL; i++)
										{
											attrValues[i] = CAttributesSchema::getAttributeVariant(vals[i], schema->type);
										}
										obj->AddValue(attr, CComVariant(attrValues));
									}
									else
									{
										obj->AddValue(attr, CAttributesSchema::getAttributeVariant(vals[0], schema->type));
									}
									ldap_value_free_len(vals);
								}
								ldap_memfree(attr);
								continue;
							}
						}
						PTCHAR *vals;
						if((vals = ldap_get_values(ld, entry, attr)) != NULL && ldap_count_values(vals) > 0UL)
						{
							if(!single)
							{
								CComSafeArray<VARIANT> attrValues(ldap_count_values(vals));
								for(LONG i = 0L; vals[i] != NULL; i++)
								{
									attrValues[i] = CComVariant(vals[i]);
								}
								obj->AddValue(attr, CComVariant(attrValues));
							}
							else
							{
								obj->AddValue(attr, CComVariant(vals[0]));
							}
							ldap_value_free(vals);
						}
						else
						{
							BOOL last = FALSE;
							LONG start = 0L;
							CComSafeArray<VARIANT> attrValues(0UL);
							do
							{
								CString attrWithRange;
								if(last)
									attrWithRange.Format(_T("%s;range=%ld-*"), attr, start);
								else
									attrWithRange.Format(_T("%s;range=%ld-%ld"), attr, start, start+999L);
								CSimpleArray<PTCHAR> a;
								a.Add(attrWithRange.GetBuffer());
								a.Add(NULL);
								PLDAPMessage pItemMsg = NULL;
								if(ldap_search_s(ld, dn, LDAP_SCOPE_BASE, _T("(objectClass=*)"), a.GetData(), 0, &pItemMsg) == LDAP_SUCCESS)
								{
									PLDAPMessage const itemEntry = ldap_first_entry(ld, pItemMsg);
									if(itemEntry)
									{
										if((vals = ldap_get_values(ld, itemEntry, attrWithRange.GetBuffer())) != NULL)
										{
											if(ldap_count_values(vals) == 0)
											{
												if(last) start = -1L; //leave loop if already last
												last = TRUE;
											}
											else
											{
												for(LONG i = 0L; vals[i] != NULL; i++)
												{
													attrValues.Add(CComVariant(vals[i]));
												}
												if(last) start = -1L; //leave loop
												else start += 1000L; //next results
											}
											ldap_value_free(vals);
										}
										else
										{
											if(last) start = -1L; //leave loop if already last
											last = TRUE;
										}
									}
									else
									{
										start = -1L; //leave loop
									}
									ldap_msgfree(pItemMsg);
								}
								else
								{
									start = -1L; //leave loop
								}
							} while (start >= 0L);
							obj->AddValue(attr, CComVariant(attrValues));
						}
						ldap_memfree(attr);
					}
					dnList.Add(CComVariant(obj));
					ldap_memfree(dn);
				}
				ldap_msgfree(pMsg);
			}
		}
		if(m_errorCode != LDAP_SUCCESS && m_errorCode != LDAP_SIZELIMIT_EXCEEDED)
		{
			cinfo->removeResult(results_id);
		}
		if(m_errorCode == LDAP_NO_RESULTS_RETURNED || m_errorCode == LDAP_MORE_RESULTS_TO_RETURN || m_errorCode == LDAP_SIZELIMIT_EXCEEDED)
			m_errorCode = LDAP_SUCCESS;
	}
	*result = dnList.Detach();
	return S_OK;
}