Signed-off-by: Dmitry Timoshkov <dmitry(a)baikal.ru>
---
dlls/adsldp/adsldp.c | 142 ++++++++++++++++++++++++++++++++++-
dlls/adsldp/adsldp_private.h | 10 +++
2 files changed, 149 insertions(+), 3 deletions(-)
diff --git a/dlls/adsldp/adsldp.c b/dlls/adsldp/adsldp.c
index 58db41a094..942c471dfb 100644
--- a/dlls/adsldp/adsldp.c
+++ b/dlls/adsldp/adsldp.c
@@ -40,7 +40,6 @@
#include "adsldp_private.h"
-#include "wine/heap.h"
#include "wine/debug.h"
WINE_DEFAULT_DEBUG_CHANNEL(adsldp);
@@ -372,6 +371,12 @@ static HRESULT ADSystemInfo_create(REFIID riid, void **obj)
return hr;
}
+struct ldap_attribute
+{
+ WCHAR *name;
+ WCHAR **values;
+};
+
typedef struct
{
IADs IADs_iface;
@@ -381,6 +386,8 @@ typedef struct
BSTR host;
BSTR object;
ULONG port;
+ ULONG attrs_count, attrs_count_allocated;
+ struct ldap_attribute *attrs;
} LDAP_namespace;
static inline LDAP_namespace *impl_from_IADs(IADs *iface)
@@ -422,6 +429,23 @@ static ULONG WINAPI ldapns_AddRef(IADs *iface)
return InterlockedIncrement(&ldap->ref);
}
+static void free_attributes(LDAP_namespace *ldap)
+{
+ ULONG i;
+
+ if (!ldap->attrs) return;
+
+ for (i = 0; i < ldap->attrs_count; i++)
+ {
+ ldap_memfreeW(ldap->attrs[i].name);
+ ldap_value_freeW(ldap->attrs[i].values);
+ }
+
+ heap_free(ldap->attrs);
+ ldap->attrs = NULL;
+ ldap->attrs_count = 0;
+}
+
static ULONG WINAPI ldapns_Release(IADs *iface)
{
LDAP_namespace *ldap = impl_from_IADs(iface);
@@ -433,6 +457,7 @@ static ULONG WINAPI ldapns_Release(IADs *iface)
if (ldap->ld) ldap_unbind(ldap->ld);
SysFreeString(ldap->host);
SysFreeString(ldap->object);
+ free_attributes(ldap);
heap_free(ldap);
}
@@ -548,10 +573,118 @@ static HRESULT WINAPI ldapns_PutEx(IADs *iface, LONG code, BSTR name, VARIANT pr
return E_NOTIMPL;
}
+static HRESULT add_attribute(LDAP_namespace *ldap, WCHAR *name, WCHAR **values)
+{
+ struct ldap_attribute *new_attrs;
+
+ if (!ldap->attrs)
+ {
+ ldap->attrs = heap_alloc(256 * sizeof(ldap->attrs[0]));
+ if (!ldap->attrs) return E_OUTOFMEMORY;
+ ldap->attrs_count_allocated = 256;
+ }
+ else if (ldap->attrs_count_allocated < ldap->attrs_count + 1)
+ {
+ new_attrs = heap_realloc(ldap->attrs, (ldap->attrs_count_allocated * 2) * sizeof(*new_attrs));
+ if (!new_attrs) return E_OUTOFMEMORY;
+
+ ldap->attrs_count_allocated *= 2;
+ ldap->attrs = new_attrs;
+ }
+
+ ldap->attrs[ldap->attrs_count].name = name;
+ ldap->attrs[ldap->attrs_count].values = values;
+ ldap->attrs_count++;
+
+ return S_OK;
+}
+
static HRESULT WINAPI ldapns_GetInfoEx(IADs *iface, VARIANT prop, LONG reserved)
{
- FIXME("%p,%s,%d: stub\n", iface, wine_dbgstr_variant(&prop), reserved);
- return E_NOTIMPL;
+ LDAP_namespace *ldap = impl_from_IADs(iface);
+ HRESULT hr;
+ SAFEARRAY *sa;
+ VARIANT *item;
+ WCHAR **props = NULL, *attr, **values;
+ DWORD i, count, err;
+ LDAPMessage *res = NULL, *entry;
+ BerElement *ber;
+
+ TRACE("%p,%s,%d\n", iface, wine_dbgstr_variant(&prop), reserved);
+
+ free_attributes(ldap);
+
+ if (!ldap->ld) return E_NOTIMPL;
+
+ if (V_VT(&prop) != (VT_ARRAY | VT_VARIANT))
+ return E_ADS_BAD_PARAMETER;
+
+ sa = V_ARRAY(&prop);
+ if (sa->cDims != 1)
+ return E_ADS_BAD_PARAMETER;
+
+ hr = SafeArrayAccessData(sa, (void *)&item);
+ if (hr != S_OK) return hr;
+
+ count = sa->rgsabound[0].cElements;
+ if (count)
+ {
+ props = heap_alloc((count + 1) * sizeof(props[0]));
+ if (!props)
+ {
+ hr = E_OUTOFMEMORY;
+ goto exit;
+ }
+
+ for (i = 0; i < count; i++)
+ {
+ if (V_VT(&item[i]) != VT_BSTR)
+ {
+ hr = E_ADS_BAD_PARAMETER;
+ goto exit;
+ }
+ props[i] = V_BSTR(&item[i]);
+ }
+ props[sa->rgsabound[0].cElements] = NULL;
+ }
+
+ err = ldap_search_sW(ldap->ld, NULL, LDAP_SCOPE_BASE, (WCHAR *)L"(objectClass=*)", props, FALSE, &res);
+ if (err != LDAP_SUCCESS)
+ {
+ TRACE("ldap_search_sW error %#x\n", err);
+ hr = HRESULT_FROM_WIN32(map_ldap_error(err));
+ goto exit;
+ }
+
+ entry = ldap_first_entry(ldap->ld, res);
+ while (entry)
+ {
+ attr = ldap_first_attributeW(ldap->ld, entry, &ber);
+ while (attr)
+ {
+ TRACE("attr: %s\n", debugstr_w(attr));
+
+ values = ldap_get_valuesW(ldap->ld, entry, attr);
+
+ hr = add_attribute(ldap, attr, values);
+ if (hr != S_OK)
+ {
+ ldap_value_freeW(values);
+ ldap_memfreeW(attr);
+ goto exit;
+ }
+
+ attr = ldap_next_attributeW(ldap->ld, entry, ber);
+ }
+
+ entry = ldap_next_entry(ldap->ld, res);
+ }
+
+exit:
+ if (res) ldap_msgfree(res);
+ heap_free(props);
+ SafeArrayUnaccessData(sa);
+ return hr;
}
static const IADsVtbl IADs_vtbl =
@@ -867,6 +1000,9 @@ static HRESULT LDAPNamespace_create(REFIID riid, void **obj)
ldap->ld = NULL;
ldap->host = NULL;
ldap->object = NULL;
+ ldap->attrs_count = 0;
+ ldap->attrs_count_allocated = 0;
+ ldap->attrs = NULL;
hr = IADs_QueryInterface(&ldap->IADs_iface, riid, obj);
IADs_Release(&ldap->IADs_iface);
diff --git a/dlls/adsldp/adsldp_private.h b/dlls/adsldp/adsldp_private.h
index 8748d0496d..0443ffbf6e 100644
--- a/dlls/adsldp/adsldp_private.h
+++ b/dlls/adsldp/adsldp_private.h
@@ -19,6 +19,16 @@
#ifndef _ADSLDP_PRIVATE_H
#define _ADSLDP_PRIVATE_H
+#include "wine/heap.h"
+
+static inline WCHAR *strdupW(const WCHAR *src)
+{
+ WCHAR *dst;
+ if (!src) return NULL;
+ if ((dst = heap_alloc((wcslen(src) + 1) * sizeof(WCHAR)))) wcscpy(dst, src);
+ return dst;
+}
+
DWORD map_ldap_error(DWORD) DECLSPEC_HIDDEN;
#endif
--
2.25.1