[CalendarServer-changes] [3308] PyOpenDirectory/trunk

source_changes at macosforge.org source_changes at macosforge.org
Mon Nov 3 07:34:05 PST 2008


Revision: 3308
          http://trac.macosforge.org/projects/calendarserver/changeset/3308
Author:   cdaboo at apple.com
Date:     2008-11-03 07:34:04 -0800 (Mon, 03 Nov 2008)
Log Message:
-----------
recordType argument can now be a tuple or list in addition to a string so that more than one
recordType can be queried at a time.

Modified Paths:
--------------
    PyOpenDirectory/trunk/pysrc/opendirectory.py
    PyOpenDirectory/trunk/src/CDirectoryService.cpp
    PyOpenDirectory/trunk/src/CDirectoryService.h
    PyOpenDirectory/trunk/src/PythonWrapper.cpp
    PyOpenDirectory/trunk/test.py

Modified: PyOpenDirectory/trunk/pysrc/opendirectory.py
===================================================================
--- PyOpenDirectory/trunk/pysrc/opendirectory.py	2008-11-01 00:06:48 UTC (rev 3307)
+++ PyOpenDirectory/trunk/pysrc/opendirectory.py	2008-11-03 15:34:04 UTC (rev 3308)
@@ -34,7 +34,7 @@
     is the attribute name, and the second C{str} is an encoding type, either "str" or "base64".
     
     @param obj: C{object} the object obtained from an odInit call.
-    @param recordType: C{str} containing the OD record type to lookup.
+    @param recordType: C{str}, C{tuple} or C{list} containing the OD record types to lookup.
     @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
     @return: C{dict} containing a C{dict} of attributes for each record found,  
         or C{None} otherwise.
@@ -51,7 +51,7 @@
     @param value: C{str} containing the value to search for.
     @param matchType: C{int} DS match type to use when searching.
     @param casei: C{True} to do case-insenstive match, C{False} otherwise.
-    @param recordType: C{str} containing the OD record type to lookup.
+    @param recordType: C{str}, C{tuple} or C{list} containing the OD record types to lookup.
     @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
     @return: C{dict} containing a C{dict} of attributes for each record found,  
         or C{None} otherwise.
@@ -66,7 +66,7 @@
     @param obj: C{object} the object obtained from an odInit call.
     @param compound: C{str} containing the compound search query to use.
     @param casei: C{True} to do case-insenstive match, C{False} otherwise.
-    @param recordType: C{str} containing the OD record type to lookup.
+    @param recordType: C{str}, C{tuple} or C{list} containing the OD record types to lookup.
     @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
     @return: C{dict} containing a C{dict} of attributes for each record found,  
         or C{None} otherwise.
@@ -79,7 +79,7 @@
     is the attribute name, and the second C{str} is an encoding type, either "str" or "base64".
     
     @param obj: C{object} the object obtained from an odInit call.
-    @param recordType: C{str} containing the OD record type to lookup.
+    @param recordType: C{str}, C{tuple} or C{list} containing the OD record types to lookup.
     @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
     @return: C{list} containing a C{list} of C{str} (record name) and C{dict} attributes 
         for each record found, or C{None} otherwise.
@@ -96,7 +96,7 @@
     @param value: C{str} containing the value to search for.
     @param matchType: C{int} DS match type to use when searching.
     @param casei: C{True} to do case-insenstive match, C{False} otherwise.
-    @param recordType: C{str} containing the OD record type to lookup.
+    @param recordType: C{str}, C{tuple} or C{list} containing the OD record types to lookup.
     @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
     @return: C{list} containing a C{list} of C{str} (record name) and C{dict} attributes 
         for each record found, or C{None} otherwise.
@@ -111,7 +111,7 @@
     @param obj: C{object} the object obtained from an odInit call.
     @param compound: C{str} containing the compound search query to use.
     @param casei: C{True} to do case-insenstive match, C{False} otherwise.
-    @param recordType: C{str} containing the OD record type to lookup.
+    @param recordType: C{str}, C{tuple} or C{list} containing the OD record types to lookup.
     @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
     @return: C{list} containing a C{list} of C{str} (record name) and C{dict} attributes 
         for each record found, or C{None} otherwise.

Modified: PyOpenDirectory/trunk/src/CDirectoryService.cpp
===================================================================
--- PyOpenDirectory/trunk/src/CDirectoryService.cpp	2008-11-01 00:06:48 UTC (rev 3307)
+++ PyOpenDirectory/trunk/src/CDirectoryService.cpp	2008-11-03 15:34:04 UTC (rev 3308)
@@ -81,21 +81,21 @@
 //
 // Get specific attributes for one or more user records in the directory.
 //
-// @param recordType: the record type to list.
+// @param recordTypes: the record types to list.
 // @param attributes: CFArray of CFString listing the attributes to return for each record.
 // @return: CFMutableArrayRef composed of CFMutableArrayRef with a CFStringRef/CFMutableDictionaryRef tuple for
 //          each record, where the CFStringRef is the record name and CFMutableDictionaryRef of CFStringRef key
 //            and value entries for each attribute/value requested in the record indexed by uid,
 //            or NULL if it fails.
 //
-CFMutableArrayRef CDirectoryService::ListAllRecordsWithAttributes(const char* recordType, CFDictionaryRef attributes, bool using_python)
+CFMutableArrayRef CDirectoryService::ListAllRecordsWithAttributes(CFArrayRef recordTypes, CFDictionaryRef attributes, bool using_python)
 {
     try
     {
         StPythonThreadState threading(using_python);
 
         // Get attribute map
-        return _ListAllRecordsWithAttributes(recordType, NULL, attributes);
+        return _ListAllRecordsWithAttributes(recordTypes, NULL, attributes);
     }
     catch(CDirectoryServiceException& dserror)
     {
@@ -118,21 +118,21 @@
 // @param value: the value to query.
 // @param matchType: the match type to use.
 // @param casei: true if case-insensitive match is to be used, false otherwise.
-// @param recordType: the record type to list.
+// @param recordTypes: the record types to list.
 // @param attributes: CFArray of CFString listing the attributes to return for each record.
 // @return: CFMutableArrayRef composed of CFMutableArrayRef with a CFStringRef/CFMutableDictionaryRef tuple for
 //          each record, where the CFStringRef is the record name and CFMutableDictionaryRef of CFStringRef key
 //          and value entries for each attribute/value requested in the record indexed by uid,
 //          or NULL if it fails.
 //
-CFMutableArrayRef CDirectoryService::QueryRecordsWithAttribute(const char* attr, const char* value, int matchType, bool casei, const char* recordType, CFDictionaryRef attributes, bool using_python)
+CFMutableArrayRef CDirectoryService::QueryRecordsWithAttribute(const char* attr, const char* value, int matchType, bool casei, CFArrayRef recordTypes, CFDictionaryRef attributes, bool using_python)
 {
     try
     {
         StPythonThreadState threading(using_python);
 
         // Get attribute map
-        return _QueryRecordsWithAttributes(attr, value, matchType, NULL, casei, recordType, attributes);
+        return _QueryRecordsWithAttributes(attr, value, matchType, NULL, casei, recordTypes, attributes);
     }
     catch(CDirectoryServiceException& dserror)
     {
@@ -153,21 +153,21 @@
 //
 // @param query: the compund query string to use.
 // @param casei: true if case-insensitive match is to be used, false otherwise.
-// @param recordType: the record type to list.
+// @param recordTypes: the record types to list.
 // @param attributes: CFArray of CFString listing the attributes to return for each record.
 // @return: CFMutableArrayRef composed of CFMutableArrayRef with a CFStringRef/CFMutableDictionaryRef tuple for
 //          each record, where the CFStringRef is the record name and CFMutableDictionaryRef of CFStringRef key
 //          and value entries for each attribute/value requested in the record indexed by uid,
 //          or NULL if it fails.
 //
-CFMutableArrayRef CDirectoryService::QueryRecordsWithAttributes(const char* query, bool casei, const char* recordType, CFDictionaryRef attributes, bool using_python)
+CFMutableArrayRef CDirectoryService::QueryRecordsWithAttributes(const char* query, bool casei, CFArrayRef recordTypes, CFDictionaryRef attributes, bool using_python)
 {
     try
     {
         StPythonThreadState threading(using_python);
 
         // Get attribute map
-        return _QueryRecordsWithAttributes(NULL, NULL, 0, query, casei, recordType, attributes);
+        return _QueryRecordsWithAttributes(NULL, NULL, 0, query, casei, recordTypes, attributes);
     }
     catch(CDirectoryServiceException& dserror)
     {
@@ -258,7 +258,7 @@
 //          and value entries for each attribute/value requested in the record indexed by uid,
 //          or NULL if it fails.
 //
-CFMutableArrayRef CDirectoryService::_ListAllRecordsWithAttributes(const char* type, CFArrayRef names, CFDictionaryRef attributes)
+CFMutableArrayRef CDirectoryService::_ListAllRecordsWithAttributes(CFArrayRef recordTypes, CFArrayRef names, CFDictionaryRef attributes)
 {
     CFMutableArrayRef result = NULL;
     CFMutableArrayRef record_tuple = NULL;
@@ -297,7 +297,7 @@
         // Build data list of types
         recTypes = ::dsDataListAllocate(mDir);
         ThrowIfNULL(recTypes);
-        ThrowIfDSErr(::dsBuildListFromStringsAlloc(mDir, recTypes,  type, NULL));
+        BuildStringDataList(recordTypes, recTypes);
 
         // Build data list of attributes
         attrTypes = ::dsDataListAllocate(mDir);
@@ -499,14 +499,14 @@
 // @param matchType: the match type to use (0 if compound is being used).
 // @param attr: the compound query to use rather than single attribute/value (NULL if compound is not being used).
 // @param casei: true if case-insensitive match is to be used, false otherwise.
-// @param type: the record type to check.
+// @param recordTypes: the record type to check.
 // @param attributes: a list of attributes to return.
 // @return: CFMutableArrayRef composed of CFMutableArrayRef with a CFStringRef/CFMutableDictionaryRef tuple for
 //          each record, where the CFStringRef is the record name and CFMutableDictionaryRef of CFStringRef key
 //          and value entries for each attribute/value requested in the record indexed by uid,
 //          or NULL if it fails.
 //
-CFMutableArrayRef CDirectoryService::_QueryRecordsWithAttributes(const char* attr, const char* value, int matchType, const char* compound, bool casei, const char* type, CFDictionaryRef attributes)
+CFMutableArrayRef CDirectoryService::_QueryRecordsWithAttributes(const char* attr, const char* value, int matchType, const char* compound, bool casei, CFArrayRef recordTypes, CFDictionaryRef attributes)
 {
     CFMutableArrayRef result = NULL;
     CFMutableArrayRef record_tuple = NULL;
@@ -563,7 +563,7 @@
         // Build data list of types
         recTypes = ::dsDataListAllocate(mDir);
         ThrowIfNULL(recTypes);
-        ThrowIfDSErr(::dsBuildListFromStringsAlloc(mDir, recTypes,  type, NULL));
+        BuildStringDataList(recordTypes, recTypes);
 
         // Build data list of attributes
         attrTypes = ::dsDataListAllocate(mDir);

Modified: PyOpenDirectory/trunk/src/CDirectoryService.h
===================================================================
--- PyOpenDirectory/trunk/src/CDirectoryService.h	2008-11-01 00:06:48 UTC (rev 3307)
+++ PyOpenDirectory/trunk/src/CDirectoryService.h	2008-11-03 15:34:04 UTC (rev 3308)
@@ -31,9 +31,9 @@
     CDirectoryService(const char* nodename);
     ~CDirectoryService();
 
-    CFMutableArrayRef ListAllRecordsWithAttributes(const char* recordType, CFDictionaryRef attributes, bool using_python=true);
-    CFMutableArrayRef QueryRecordsWithAttribute(const char* attr, const char* value, int matchType, bool casei, const char* recordType, CFDictionaryRef attributes, bool using_python=true);
-    CFMutableArrayRef QueryRecordsWithAttributes(const char* query, bool casei, const char* recordType, CFDictionaryRef attributes, bool using_python=true);
+    CFMutableArrayRef ListAllRecordsWithAttributes(CFArrayRef recordTypes, CFDictionaryRef attributes, bool using_python=true);
+    CFMutableArrayRef QueryRecordsWithAttribute(const char* attr, const char* value, int matchType, bool casei, CFArrayRef recordTypes, CFDictionaryRef attributes, bool using_python=true);
+    CFMutableArrayRef QueryRecordsWithAttributes(const char* query, bool casei, CFArrayRef recordTypes, CFDictionaryRef attributes, bool using_python=true);
 
     bool AuthenticateUserBasic(const char* nodename, const char* user, const char* pswd, bool& result, bool using_python=true);
     bool AuthenticateUserDigest(const char* nodename, const char* user, const char* challenge, const char* response, const char* method, bool& result, bool using_python=true);
@@ -67,8 +67,8 @@
     tDataBufferPtr        mData;
     UInt32                mDataSize;
 
-    CFMutableArrayRef _ListAllRecordsWithAttributes(const char* type, CFArrayRef names, CFDictionaryRef attrs);
-    CFMutableArrayRef _QueryRecordsWithAttributes(const char* attr, const char* value, int matchType, const char* compound, bool casei, const char* recordType, CFDictionaryRef attrs);
+    CFMutableArrayRef _ListAllRecordsWithAttributes(CFArrayRef recordTypes, CFArrayRef names, CFDictionaryRef attrs);
+    CFMutableArrayRef _QueryRecordsWithAttributes(const char* attr, const char* value, int matchType, const char* compound, bool casei, CFArrayRef recordTypes, CFDictionaryRef attrs);
 
     bool NativeAuthenticationBasicToNode(const char* nodename, const char* user, const char* pswd);
     bool NativeAuthenticationDigestToNode(const char* nodename, const char* user, const char* challenge, const char* response, const char* method);

Modified: PyOpenDirectory/trunk/src/PythonWrapper.cpp
===================================================================
--- PyOpenDirectory/trunk/src/PythonWrapper.cpp	2008-11-01 00:06:48 UTC (rev 3307)
+++ PyOpenDirectory/trunk/src/PythonWrapper.cpp	2008-11-03 15:34:04 UTC (rev 3308)
@@ -127,6 +127,53 @@
 }
 
 // Utility function - not exposed to Python
+static CFArrayRef PyStringTupleOrListToCFArray(PyObject* item)
+{
+	if (PyTuple_Check(item) || PyList_Check(item))
+	{
+		PyTupleOrList pyitem(item);
+		CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorDefault, pyitem.getSize(), &kCFTypeArrayCallBacks);
+		for(int i = 0; i < pyitem.getSize(); i++)
+		{
+			PyObject* str = pyitem.get(i);
+			if ((str == NULL) || !PyString_Check(str))
+			{
+				CFRelease(result);
+				throw PyObjectException("Expecting a str type in 'PyStringTupleOrListToCFArray'.");
+			}
+			const char* cstr = PyString_AsString(str);
+			if (cstr == NULL)
+			{
+				CFRelease(result);
+				throw PyObjectException("Could not extract string in 'PyStringTupleOrListToCFArray'.");
+			}
+			CFStringUtil cfstr(cstr);
+			CFArrayAppendValue(result, cfstr.get());
+		}
+
+		return result;
+	}
+	else if (PyString_Check(item))
+	{
+		CFMutableArrayRef result = CFArrayCreateMutable(kCFAllocatorDefault, 1, &kCFTypeArrayCallBacks);
+		const char* cstr = PyString_AsString(item);
+		if (cstr == NULL)
+		{
+			CFRelease(result);
+			throw PyObjectException("Could not extract string in 'PyStringTupleOrListToCFArray'.");
+		}
+		CFStringUtil cfstr(cstr);
+		CFArrayAppendValue(result, cfstr.get());
+
+		return result;
+	}
+	else
+	{
+		throw PyObjectException("Could not extract string, tuple or list in 'PyStringTupleOrListToCFArray'.");
+	}
+}
+
+// Utility function - not exposed to Python
 static CFArrayRef PyTupleOrListToCFArray(PyObject* item)
 {
 	PyTupleOrList pyitem(item);
@@ -334,68 +381,33 @@
 PyObject* ODException_class = NULL;
 
 /*
- This is an automatic destructor for the object obtained by odInit. It is not directly
- exposed to Python, instead Python calls it automatically when reclaiming the object.
+    Internal method.
  */
-extern "C" void odDestroy(void* obj)
+static PyObject *_listAllRecordsWithAttributes(PyObject *self, PyObject *args, bool list)
 {
-    CDirectoryServiceManager* dsmgr = static_cast<CDirectoryServiceManager*>(obj);
-    delete dsmgr;
-}
-
-/*
- def odInit(nodename):
-    """
-    Create an Open Directory object to operate on the specified directory service node name.
-
-    @param nodename: C{str} containing the node name.
-    @return: C{object} an object to be passed to all subsequent functions on success,
-        C{None} on failure.
-    """
- */
-extern "C" PyObject* odInit(PyObject* self, PyObject* args)
-{
-    const char* nodename;
-    if (!PyArg_ParseTuple(args, "s", &nodename))
-    {
-        PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices odInit: could not parse arguments", 0));
-        return NULL;
-    }
-
-    CDirectoryServiceManager* dsmgr = new CDirectoryServiceManager(nodename);
-    if (dsmgr != NULL)
-    {
-        return PyCObject_FromVoidPtr(dsmgr, odDestroy);
-    }
-
-    PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices odInit: could not initialize directory service", 0));
-    return NULL;
-}
-
-/*
-def listAllRecordsWithAttributes(obj, recordType, attributes):
-    """
-    List records in Open Directory, and return key attributes for each one. The attributes
-    can be a C{str} for the attribute name, or a C{tuple} or C{list} where the first C{str}
-    is the attribute name, and the second C{str} is an encoding type, either "str" or "base64".
-
-    @param obj: C{object} the object obtained from an odInit call.
-    @param recordType: C{str} containing the OD record type to lookup.
-    @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
-    @return: C{dict} containing a C{dict} of attributes for each record found,
-        or C{None} otherwise.
- */
-extern "C" PyObject *listAllRecordsWithAttributes(PyObject *self, PyObject *args)
-{
     PyObject* pyds;
-    const char* recordType;
+    PyObject* recordType;
     PyObject* attributes;
-    if (!PyArg_ParseTuple(args, "OsO", &pyds, &recordType, &attributes) || !PyCObject_Check(pyds) || !PyTupleOrList::typeOK(attributes))
+    if (!PyArg_ParseTuple(args, "OOO", &pyds, &recordType, &attributes) || !PyCObject_Check(pyds) || !PyTupleOrList::typeOK(attributes))
     {
         PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices listAllRecordsWithAttributes: could not parse arguments", 0));
         return NULL;
     }
 
+	// Convert string/tuple/list to CFArray
+    CFArrayRef cfrecordtypes = NULL;
+    try
+    {
+    	cfrecordtypes = PyStringTupleOrListToCFArray(recordType);
+    }
+	catch(PyObjectException& ex)
+	{
+		std::string msg("DirectoryServices listAllRecordsWithAttributes: could not parse recordTypes: ");
+		msg += ex.what();
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", msg.c_str(), 0));
+		return NULL;
+	}
+
     // Convert list to CFArray of CFString
     CFDictionaryRef cfattributes = NULL;
 	try
@@ -407,6 +419,7 @@
 		std::string msg("DirectoryServices listAllRecordsWithAttributes: could not parse attributes list: ");
 		msg += ex.what();
 		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", msg.c_str(), 0));
+        CFRelease(cfrecordtypes);
 		return NULL;
 	}
 
@@ -414,13 +427,14 @@
     if (dsmgr != NULL)
     {
         std::auto_ptr<CDirectoryService> ds(dsmgr->GetService());
-        CFMutableArrayRef list = NULL;
-        list = ds->ListAllRecordsWithAttributes(recordType, cfattributes);
-        if (list != NULL)
+        CFMutableArrayRef results = NULL;
+        results = ds->ListAllRecordsWithAttributes(cfrecordtypes, cfattributes);
+        if (results != NULL)
         {
-            PyObject* result = CFArrayArrayDictionaryToPyDict(list);
-            CFRelease(list);
+            PyObject* result = list ? CFArrayArrayDictionaryToPyList(results) : CFArrayArrayDictionaryToPyDict(results);
+            CFRelease(results);
             CFRelease(cfattributes);
+            CFRelease(cfrecordtypes);
 
             return result;
         }
@@ -429,28 +443,11 @@
         PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices listAllRecordsWithAttributes: invalid directory service argument", 0));
 
     CFRelease(cfattributes);
+    CFRelease(cfrecordtypes);
     return NULL;
 }
 
-/*
-def queryRecordsWithAttribute(obj, attr, value, matchType, casei, recordType, attributes):
-    """
-    List records in Open Directory matching specified attribute and value, and return key attributes for each one.
-    The attributes can be a C{str} for the attribute name, or a C{tuple} or C{list} where the first C{str}
-    is the attribute name, and the second C{str} is an encoding type, either "str" or "base64".
-
-    @param obj: C{object} the object obtained from an odInit call.
-    @param attr: C{str} for the attribute to query.
-    @param value: C{str} for the attribute value to query.
-    @param matchType: C{int} DS match type to use when searching.
-    @param casei: C{True} to do case-insenstive match, C{False} otherwise.
-    @param recordType: C{str} containing the OD record type to lookup.
-    @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
-    @return: C{dict} containing a C{dict} of attributes for each record found,
-        or C{None} otherwise.
-    """
- */
-extern "C" PyObject *queryRecordsWithAttribute(PyObject *self, PyObject *args)
+static PyObject *_queryRecordsWithAttribute(PyObject *self, PyObject *args, bool list)
 {
     PyObject* pyds;
     const char* attr;
@@ -458,9 +455,9 @@
     int matchType;
     PyObject* caseio;
     bool casei;
-    const char* recordType;
+    PyObject* recordType;
     PyObject* attributes;
-    if (!PyArg_ParseTuple(args, "OssiOsO", &pyds, &attr, &value, &matchType, &caseio, &recordType, &attributes) ||
+    if (!PyArg_ParseTuple(args, "OssiOOO", &pyds, &attr, &value, &matchType, &caseio, &recordType, &attributes) ||
         !PyCObject_Check(pyds) || !PyBool_Check(caseio) || !PyTupleOrList::typeOK(attributes))
     {
         PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices queryRecordsWithAttribute: could not parse arguments", 0));
@@ -469,6 +466,20 @@
 
     casei = (caseio == Py_True);
 
+	// Convert string/tuple/list to CFArray
+    CFArrayRef cfrecordtypes = NULL;
+    try
+    {
+    	cfrecordtypes = PyStringTupleOrListToCFArray(recordType);
+    }
+	catch(PyObjectException& ex)
+	{
+		std::string msg("DirectoryServices listAllRecordsWithAttributes: could not parse recordTypes: ");
+		msg += ex.what();
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", msg.c_str(), 0));
+		return NULL;
+	}
+
     // Convert list to CFArray of CFString
     CFDictionaryRef cfattributes = NULL;
 	try
@@ -480,6 +491,7 @@
 		std::string msg("DirectoryServices queryRecordsWithAttribute: could not parse attributes list: ");
 		msg += ex.what();
 		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", msg.c_str(), 0));
+        CFRelease(cfrecordtypes);
 		return NULL;
 	}
 
@@ -487,13 +499,14 @@
     if (dsmgr != NULL)
     {
         std::auto_ptr<CDirectoryService> ds(dsmgr->GetService());
-        CFMutableArrayRef list = NULL;
-        list = ds->QueryRecordsWithAttribute(attr, value, matchType, casei, recordType, cfattributes);
-        if (list != NULL)
+        CFMutableArrayRef results = NULL;
+        results = ds->QueryRecordsWithAttribute(attr, value, matchType, casei, cfrecordtypes, cfattributes);
+        if (results != NULL)
         {
-            PyObject* result = CFArrayArrayDictionaryToPyDict(list);
-            CFRelease(list);
+            PyObject* result = list ? CFArrayArrayDictionaryToPyList(results) : CFArrayArrayDictionaryToPyDict(results);
+            CFRelease(results);
             CFRelease(cfattributes);
+            CFRelease(cfrecordtypes);
 
             return result;
         }
@@ -502,34 +515,19 @@
         PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices queryRecordsWithAttribute: invalid directory service argument", 0));
 
     CFRelease(cfattributes);
+    CFRelease(cfrecordtypes);
     return NULL;
 }
 
-/*
-def queryRecordsWithAttributes(obj, query, casei, recordType, attributes):
-    """
-    List records in Open Directory matching specified compound query, and return key attributes for each one.
-    The attributes can be a C{str} for the attribute name, or a C{tuple} or C{list} where the first C{str}
-    is the attribute name, and the second C{str} is an encoding type, either "str" or "base64".
-
-    @param obj: C{object} the object obtained from an odInit call.
-    @param query: C{str} the compound query string.
-    @param casei: C{True} to do case-insenstive match, C{False} otherwise.
-    @param recordType: C{str} containing the OD record type to lookup.
-    @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
-    @return: C{dict} containing a C{dict} of attributes for each record found,
-        or C{None} otherwise.
-    """
- */
-extern "C" PyObject *queryRecordsWithAttributes(PyObject *self, PyObject *args)
+static PyObject *_queryRecordsWithAttributes(PyObject *self, PyObject *args, bool list)
 {
     PyObject* pyds;
     const char* query;
     PyObject* caseio;
     bool casei;
-    const char* recordType;
+    PyObject* recordType;
     PyObject* attributes;
-    if (!PyArg_ParseTuple(args, "OsOsO", &pyds, &query, &caseio, &recordType, &attributes) ||
+    if (!PyArg_ParseTuple(args, "OsOOO", &pyds, &query, &caseio, &recordType, &attributes) ||
         !PyCObject_Check(pyds) || !PyBool_Check(caseio) || !PyTupleOrList::typeOK(attributes))
     {
         PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices queryRecordsWithAttributes: could not parse arguments", 0));
@@ -538,6 +536,20 @@
 
     casei = (caseio == Py_True);
 
+	// Convert string/tuple/list to CFArray
+    CFArrayRef cfrecordtypes = NULL;
+    try
+    {
+    	cfrecordtypes = PyStringTupleOrListToCFArray(recordType);
+    }
+	catch(PyObjectException& ex)
+	{
+		std::string msg("DirectoryServices listAllRecordsWithAttributes: could not parse recordTypes: ");
+		msg += ex.what();
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", msg.c_str(), 0));
+		return NULL;
+	}
+
     // Convert list to CFArray of CFString
     CFDictionaryRef cfattributes = NULL;
 	try
@@ -549,6 +561,7 @@
 		std::string msg("DirectoryServices queryRecordsWithAttributes: could not parse attributes list: ");
 		msg += ex.what();
 		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", msg.c_str(), 0));
+        CFRelease(cfrecordtypes);
 		return NULL;
 	}
 
@@ -556,13 +569,14 @@
     if (dsmgr != NULL)
     {
         std::auto_ptr<CDirectoryService> ds(dsmgr->GetService());
-        CFMutableArrayRef list = NULL;
-        list = ds->QueryRecordsWithAttributes(query, casei, recordType, cfattributes);
-        if (list != NULL)
+        CFMutableArrayRef results = NULL;
+        results = ds->QueryRecordsWithAttributes(query, casei, cfrecordtypes, cfattributes);
+        if (results != NULL)
         {
-            PyObject* result = CFArrayArrayDictionaryToPyDict(list);
-            CFRelease(list);
+            PyObject* result = list ? CFArrayArrayDictionaryToPyList(results) : CFArrayArrayDictionaryToPyDict(results);
+            CFRelease(results);
             CFRelease(cfattributes);
+            CFRelease(cfrecordtypes);
 
             return result;
         }
@@ -571,73 +585,70 @@
         PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices queryRecordsWithAttributes: invalid directory service argument", 0));
 
     CFRelease(cfattributes);
+    CFRelease(cfrecordtypes);
     return NULL;
 }
 
 /*
-def listAllRecordsWithAttributes_list(obj, recordType, attributes):
+ This is an automatic destructor for the object obtained by odInit. It is not directly
+ exposed to Python, instead Python calls it automatically when reclaiming the object.
+ */
+extern "C" void odDestroy(void* obj)
+{
+    CDirectoryServiceManager* dsmgr = static_cast<CDirectoryServiceManager*>(obj);
+    delete dsmgr;
+}
+
+/*
+ def odInit(nodename):
     """
-    List records in Open Directory, and return key attributes for each one.
-    The attributes can be a C{str} for the attribute name, or a C{tuple} or C{list} where the first C{str}
-    is the attribute name, and the second C{str} is an encoding type, either "str" or "base64".
+    Create an Open Directory object to operate on the specified directory service node name.
 
-    @param obj: C{object} the object obtained from an odInit call.
-    @param recordType: C{str} containing the OD record type to lookup.
-    @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
-    @return: C{list} containing a C{list} of C{str} (record name) and C{dict} attributes
-         for each record found, or C{None} otherwise.
+    @param nodename: C{str} containing the node name.
+    @return: C{object} an object to be passed to all subsequent functions on success,
+        C{None} on failure.
     """
  */
-extern "C" PyObject *listAllRecordsWithAttributes_list(PyObject *self, PyObject *args)
+extern "C" PyObject* odInit(PyObject* self, PyObject* args)
 {
-    PyObject* pyds;
-    const char* recordType;
-    PyObject* attributes;
-    if (!PyArg_ParseTuple(args, "OsO", &pyds, &recordType, &attributes) || !PyCObject_Check(pyds) || !PyTupleOrList::typeOK(attributes))
+    const char* nodename;
+    if (!PyArg_ParseTuple(args, "s", &nodename))
     {
-        PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices listAllRecordsWithAttributes_list: could not parse arguments", 0));
+        PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices odInit: could not parse arguments", 0));
         return NULL;
     }
 
-    // Convert list to CFArray of CFString
-    CFDictionaryRef cfattributes = NULL;
-	try
-	{
-		cfattributes = AttributesToCFDictionary(attributes);
-	}
-	catch(PyObjectException& ex)
-	{
-		std::string msg("DirectoryServices listAllRecordsWithAttributes_list: could not parse attributes list: ");
-		msg += ex.what();
-		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", msg.c_str(), 0));
-		return NULL;
-	}
-
-    CDirectoryServiceManager* dsmgr = static_cast<CDirectoryServiceManager*>(PyCObject_AsVoidPtr(pyds));
+    CDirectoryServiceManager* dsmgr = new CDirectoryServiceManager(nodename);
     if (dsmgr != NULL)
     {
-        std::auto_ptr<CDirectoryService> ds(dsmgr->GetService());
-        CFMutableArrayRef list = NULL;
-        list = ds->ListAllRecordsWithAttributes(recordType, cfattributes);
-        if (list != NULL)
-        {
-            PyObject* result = CFArrayArrayDictionaryToPyList(list);
-            CFRelease(list);
-            CFRelease(cfattributes);
-
-            return result;
-        }
+        return PyCObject_FromVoidPtr(dsmgr, odDestroy);
     }
-    else
-        PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices listAllRecordsWithAttributes_list: invalid directory service argument", 0));
 
-    CFRelease(cfattributes);
+    PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices odInit: could not initialize directory service", 0));
     return NULL;
 }
 
 /*
-def queryRecordsWithAttribute_list(obj, attr, value, matchType, casei, recordType, attributes):
+def listAllRecordsWithAttributes(obj, recordType, attributes):
     """
+    List records in Open Directory, and return key attributes for each one. The attributes
+    can be a C{str} for the attribute name, or a C{tuple} or C{list} where the first C{str}
+    is the attribute name, and the second C{str} is an encoding type, either "str" or "base64".
+
+    @param obj: C{object} the object obtained from an odInit call.
+    @param recordType: C{str}, C{tuple} or C{list} containing the OD record types to lookup.
+    @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
+    @return: C{dict} containing a C{dict} of attributes for each record found,
+        or C{None} otherwise.
+ */
+extern "C" PyObject *listAllRecordsWithAttributes(PyObject *self, PyObject *args)
+{
+	return _listAllRecordsWithAttributes(self, args, false);
+}
+
+/*
+def queryRecordsWithAttribute(obj, attr, value, matchType, casei, recordType, attributes):
+    """
     List records in Open Directory matching specified attribute and value, and return key attributes for each one.
     The attributes can be a C{str} for the attribute name, or a C{tuple} or C{list} where the first C{str}
     is the attribute name, and the second C{str} is an encoding type, either "str" or "base64".
@@ -647,65 +658,78 @@
     @param value: C{str} for the attribute value to query.
     @param matchType: C{int} DS match type to use when searching.
     @param casei: C{True} to do case-insenstive match, C{False} otherwise.
-    @param recordType: C{str} containing the OD record type to lookup.
+    @param recordType: C{str}, C{tuple} or C{list} containing the OD record types to lookup.
     @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
-    @return: C{list} containing a C{list} of C{str} (record name) and C{dict} attributes
-         for each record found, or C{None} otherwise.
+    @return: C{dict} containing a C{dict} of attributes for each record found,
+        or C{None} otherwise.
     """
  */
-extern "C" PyObject *queryRecordsWithAttribute_list(PyObject *self, PyObject *args)
+extern "C" PyObject *queryRecordsWithAttribute(PyObject *self, PyObject *args)
 {
-    PyObject* pyds;
-    const char* attr;
-    const char* value;
-    int matchType;
-    PyObject* caseio;
-    bool casei;
-    const char* recordType;
-    PyObject* attributes;
-    if (!PyArg_ParseTuple(args, "OssiOsO", &pyds, &attr, &value, &matchType, &caseio, &recordType, &attributes) ||
-        !PyCObject_Check(pyds) || !PyBool_Check(caseio) || !PyTupleOrList::typeOK(attributes))
-    {
-        PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices queryRecordsWithAttribute_list: could not parse arguments", 0));
-        return NULL;
-    }
+	return _queryRecordsWithAttribute(self, args, false);
+}
 
-    casei = (caseio == Py_True);
+/*
+def queryRecordsWithAttributes(obj, query, casei, recordType, attributes):
+    """
+    List records in Open Directory matching specified compound query, and return key attributes for each one.
+    The attributes can be a C{str} for the attribute name, or a C{tuple} or C{list} where the first C{str}
+    is the attribute name, and the second C{str} is an encoding type, either "str" or "base64".
 
-    // Convert list to CFArray of CFString
-    CFDictionaryRef cfattributes = NULL;
-	try
-	{
-		cfattributes = AttributesToCFDictionary(attributes);
-	}
-	catch(PyObjectException& ex)
-	{
-		std::string msg("DirectoryServices queryRecordsWithAttribute_list: could not parse attributes list: ");
-		msg += ex.what();
-		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", msg.c_str(), 0));
-		return NULL;
-	}
+    @param obj: C{object} the object obtained from an odInit call.
+    @param query: C{str} the compound query string.
+    @param casei: C{True} to do case-insenstive match, C{False} otherwise.
+    @param recordType: C{str}, C{tuple} or C{list} containing the OD record types to lookup.
+    @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
+    @return: C{dict} containing a C{dict} of attributes for each record found,
+        or C{None} otherwise.
+    """
+ */
+extern "C" PyObject *queryRecordsWithAttributes(PyObject *self, PyObject *args)
+{
+	return _queryRecordsWithAttributes(self, args, false);
+}
 
-    CDirectoryServiceManager* dsmgr = static_cast<CDirectoryServiceManager*>(PyCObject_AsVoidPtr(pyds));
-    if (dsmgr != NULL)
-    {
-        std::auto_ptr<CDirectoryService> ds(dsmgr->GetService());
-        CFMutableArrayRef list = NULL;
-        list = ds->QueryRecordsWithAttribute(attr, value, matchType, casei, recordType, cfattributes);
-        if (list != NULL)
-        {
-            PyObject* result = CFArrayArrayDictionaryToPyList(list);
-            CFRelease(list);
-            CFRelease(cfattributes);
+/*
+def listAllRecordsWithAttributes_list(obj, recordType, attributes):
+    """
+    List records in Open Directory, and return key attributes for each one.
+    The attributes can be a C{str} for the attribute name, or a C{tuple} or C{list} where the first C{str}
+    is the attribute name, and the second C{str} is an encoding type, either "str" or "base64".
 
-            return result;
-        }
-    }
-    else
-        PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices queryRecordsWithAttribute_list: invalid directory service argument", 0));
+    @param obj: C{object} the object obtained from an odInit call.
+    @param recordType: C{str}, C{tuple} or C{list} containing the OD record types to lookup.
+    @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
+    @return: C{list} containing a C{list} of C{str} (record name) and C{dict} attributes
+         for each record found, or C{None} otherwise.
+    """
+ */
+extern "C" PyObject *listAllRecordsWithAttributes_list(PyObject *self, PyObject *args)
+{
+	return _listAllRecordsWithAttributes(self, args, true);
+}
 
-    CFRelease(cfattributes);
-    return NULL;
+/*
+def queryRecordsWithAttribute_list(obj, attr, value, matchType, casei, recordType, attributes):
+    """
+    List records in Open Directory matching specified attribute and value, and return key attributes for each one.
+    The attributes can be a C{str} for the attribute name, or a C{tuple} or C{list} where the first C{str}
+    is the attribute name, and the second C{str} is an encoding type, either "str" or "base64".
+
+    @param obj: C{object} the object obtained from an odInit call.
+    @param attr: C{str} for the attribute to query.
+    @param value: C{str} for the attribute value to query.
+    @param matchType: C{int} DS match type to use when searching.
+    @param casei: C{True} to do case-insenstive match, C{False} otherwise.
+    @param recordType: C{str}, C{tuple} or C{list} containing the OD record types to lookup.
+    @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
+    @return: C{list} containing a C{list} of C{str} (record name) and C{dict} attributes
+         for each record found, or C{None} otherwise.
+    """
+ */
+extern "C" PyObject *queryRecordsWithAttribute_list(PyObject *self, PyObject *args)
+{
+	return _queryRecordsWithAttribute(self, args, true);
 }
 
 /*
@@ -718,7 +742,7 @@
     @param obj: C{object} the object obtained from an odInit call.
     @param query: C{str} the compound query string.
     @param casei: C{True} to do case-insenstive match, C{False} otherwise.
-    @param recordType: C{str} containing the OD record type to lookup.
+    @param recordType: C{str}, C{tuple} or C{list} containing the OD record types to lookup.
     @param attributes: C{list} or C{tuple} containing the attributes to return for each record.
     @return: C{list} containing a C{list} of C{str} (record name) and C{dict} attributes
          for each record found, or C{None} otherwise.
@@ -726,55 +750,7 @@
  */
 extern "C" PyObject *queryRecordsWithAttributes_list(PyObject *self, PyObject *args)
 {
-    PyObject* pyds;
-    const char* query;
-    PyObject* caseio;
-    bool casei;
-    const char* recordType;
-    PyObject* attributes;
-    if (!PyArg_ParseTuple(args, "OsOsO", &pyds, &query, &caseio, &recordType, &attributes) ||
-        !PyCObject_Check(pyds) || !PyBool_Check(caseio) || !PyTupleOrList::typeOK(attributes))
-    {
-        PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices queryRecordsWithAttributes_list: could not parse arguments", 0));
-        return NULL;
-    }
-
-    casei = (caseio == Py_True);
-
-    // Convert list to CFArray of CFString
-    CFDictionaryRef cfattributes = NULL;
-	try
-	{
-		cfattributes = AttributesToCFDictionary(attributes);
-	}
-	catch(PyObjectException& ex)
-	{
-		std::string msg("DirectoryServices queryRecordsWithAttributes_list: could not parse attributes list: ");
-		msg += ex.what();
-		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", msg.c_str(), 0));
-		return NULL;
-	}
-
-    CDirectoryServiceManager* dsmgr = static_cast<CDirectoryServiceManager*>(PyCObject_AsVoidPtr(pyds));
-    if (dsmgr != NULL)
-    {
-        std::auto_ptr<CDirectoryService> ds(dsmgr->GetService());
-        CFMutableArrayRef list = NULL;
-        list = ds->QueryRecordsWithAttributes(query, casei, recordType, cfattributes);
-        if (list != NULL)
-        {
-            PyObject* result = CFArrayArrayDictionaryToPyList(list);
-            CFRelease(list);
-            CFRelease(cfattributes);
-
-            return result;
-        }
-    }
-    else
-        PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices queryRecordsWithAttributes_list: invalid directory service argument", 0));
-
-    CFRelease(cfattributes);
-    return NULL;
+	return _queryRecordsWithAttributes(self, args, true);
 }
 
 /*

Modified: PyOpenDirectory/trunk/test.py
===================================================================
--- PyOpenDirectory/trunk/test.py	2008-11-01 00:06:48 UTC (rev 3307)
+++ PyOpenDirectory/trunk/test.py	2008-11-03 15:34:04 UTC (rev 3308)
@@ -266,26 +266,68 @@
 			[dsattributes.kDS1AttrGeneratedUID, dsattributes.kDS1AttrDistinguishedName,]
 		)
 		
+	def listResourcesPlaces_list():
+		d = opendirectory.listAllRecordsWithAttributes_list(
+			ref,
+		    (dsattributes.kDSStdRecordTypeResources, dsattributes.kDSStdRecordTypePlaces,),
+			[dsattributes.kDSNAttrRecordType, dsattributes.kDS1AttrGeneratedUID, dsattributes.kDS1AttrDistinguishedName,]
+		)
+		if d is None:
+			print "Failed to list resources/places"
+		else:
+			d.sort(cmp=lambda x, y: x[0] < y[0])
+			print "\nlistResourcesPlaces_list number of results = %d" % (len(d),)
+			for name, record in d:
+				print "Name: %s" % name
+				print "dict: %s" % str(record)
+	
+	def queryUsersGroups_list():
+		querySimple_list(
+			"queryUsersGroups_list",
+		    dsattributes.kDS1AttrDistinguishedName,
+		    "burns",
+		    dsattributes.eDSContains,
+		    True,
+			(dsattributes.kDSStdRecordTypeUsers, dsattributes.kDSStdRecordTypeGroups,),
+			[dsattributes.kDS1AttrGeneratedUID, dsattributes.kDS1AttrDistinguishedName,]
+		)
+		
+	def queryUsersGroupsPlaces_list():
+		querySimple_list(
+			"queryUsersGroupsPlaces_list",
+		    dsattributes.kDS1AttrDistinguishedName,
+		    "tom",
+		    dsattributes.eDSContains,
+		    True,
+			(dsattributes.kDSStdRecordTypeUsers, dsattributes.kDSStdRecordTypeGroups, dsattributes.kDSStdRecordTypePlaces,),
+			[dsattributes.kDS1AttrGeneratedUID, dsattributes.kDS1AttrDistinguishedName,]
+		)
+		
 	def authentciateBasic():
 		if opendirectory.authenticateUserBasic(ref, "gooeyed", "test", "test"):
 			print "Authenticated user"
 		else:
 			print "Failed to authenticate user"
 	
-	listUsers()
-	listGroups()
-	listComputers()
-	queryUsers()
-	queryUsersCompoundOr()
-	queryUsersCompoundOrExact()
-	queryUsersCompoundAnd()
-	listUsers_list()
-	listGroups_list()
-	listComputers_list()
-	queryUsers_list()
-	queryUsersCompoundOr_list()
-	queryUsersCompoundOrExact_list()
-	queryUsersCompoundAnd_list()
+	#listUsers()
+	#listGroups()
+	#listComputers()
+	#queryUsers()
+	#queryUsersCompoundOr()
+	#queryUsersCompoundOrExact()
+	#queryUsersCompoundAnd()
+	#listUsers_list()
+	#listGroups_list()
+	#listComputers_list()
+	#queryUsers_list()
+	#queryUsersCompoundOr_list()
+	#queryUsersCompoundOrExact_list()
+	#queryUsersCompoundAnd_list()
+
+	listResourcesPlaces_list()
+	queryUsersGroups_list()
+	queryUsersGroupsPlaces_list()
+
 	#authentciateBasic()
 
 	ref = None
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20081103/4099dcea/attachment-0001.html>


More information about the calendarserver-changes mailing list