[CalendarServer-changes] [6569] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Thu Nov 4 14:22:47 PDT 2010


Revision: 6569
          http://trac.macosforge.org/projects/calendarserver/changeset/6569
Author:   sagen at apple.com
Date:     2010-11-04 14:22:45 -0700 (Thu, 04 Nov 2010)
Log Message:
-----------
Since we may have to continue supporting both PyOpenDirectory and OpenDirectory.framework, adds config.OpenDirectoryModule to specify which to use.  Also, in the hopes of supporting this for Snow, removed all dependencies on symbols being exported from OpenDirectory package.  Disabling sidecar_task test until I figure out its future.

Modified Paths:
--------------
    CalendarServer/trunk/calendarserver/od/opendirectory.py
    CalendarServer/trunk/calendarserver/od/test/test_opendirectory.py
    CalendarServer/trunk/calendarserver/sidecar/test/test_task.py
    CalendarServer/trunk/calendarserver/tools/resources.py
    CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py
    CalendarServer/trunk/twistedcaldav/directory/opendirectorybacker.py
    CalendarServer/trunk/twistedcaldav/stdconfig.py

Added Paths:
-----------
    CalendarServer/trunk/calendarserver/od/setup_directory.py

Removed Paths:
-------------
    CalendarServer/trunk/calendarserver/od/test/setup_directory.py

Modified: CalendarServer/trunk/calendarserver/od/opendirectory.py
===================================================================
--- CalendarServer/trunk/calendarserver/od/opendirectory.py	2010-11-04 20:25:29 UTC (rev 6568)
+++ CalendarServer/trunk/calendarserver/od/opendirectory.py	2010-11-04 21:22:45 UTC (rev 6569)
@@ -18,31 +18,34 @@
 OpenDirectory.framework access via PyObjC
 """
 
-import OpenDirectory
+import odframework
 import objc
+import dsattributes
 from twext.python.log import Logger
 
 log = Logger()
 
 # Single-value attributes (must be converted from lists):
 SINGLE_VALUE_ATTRIBUTES = [
-    OpenDirectory.kODAttributeTypeBirthday,
-    OpenDirectory.kODAttributeTypeComment,
-    OpenDirectory.kODAttributeTypeCreationTimestamp,
-    OpenDirectory.kODAttributeTypeFullName,
-    OpenDirectory.kODAttributeTypeFirstName,
-    OpenDirectory.kODAttributeTypeGUID,
-    OpenDirectory.kODAttributeTypeLastName,
-    OpenDirectory.kODAttributeTypeMiddleName,
-    OpenDirectory.kODAttributeTypeModificationTimestamp,
-    OpenDirectory.kODAttributeTypeNote,
-    OpenDirectory.kODAttributeTypeSearchPath,
-    OpenDirectory.kODAttributeTypeUserCertificate,
-    OpenDirectory.kODAttributeTypeUserPKCS12Data,
-    OpenDirectory.kODAttributeTypeUserSMIMECertificate,
-    OpenDirectory.kODAttributeTypeWeblogURI,
+    dsattributes.kDS1AttrBirthday,
+    dsattributes.kDS1AttrComment,
+    dsattributes.kDS1AttrCreationTimestamp,
+    dsattributes.kDS1AttrDistinguishedName,
+    dsattributes.kDS1AttrFirstName,
+    dsattributes.kDS1AttrGeneratedUID,
+    dsattributes.kDS1AttrLastName,
+    dsattributes.kDS1AttrMiddleName,
+    dsattributes.kDS1AttrModificationTimestamp,
+    dsattributes.kDS1AttrNote,
+    dsattributes.kDS1AttrSearchPath,
+    dsattributes.kDS1AttrUserCertificate,
+    dsattributes.kDS1AttrUserPKCS12Data,
+    dsattributes.kDS1AttrUserSMIMECertificate,
+    dsattributes.kDS1AttrWeblogURI,
 ]
 
+MATCHANY = 1
+DIGEST_MD5 = "dsAuthMethodStandard:dsAuthNodeDIGEST-MD5"
 
 class Directory(object):
     """ Encapsulates OpenDirectory session and node """
@@ -56,17 +59,13 @@
         return "OpenDirectory node: %s" % (self.nodeName)
 
 
-caseInsensitiveEquivalents = {
-    OpenDirectory.kODMatchBeginsWith : OpenDirectory.kODMatchInsensitiveBeginsWith,
-    OpenDirectory.kODMatchContains : OpenDirectory.kODMatchInsensitiveContains,
-    OpenDirectory.kODMatchEndsWith : OpenDirectory.kODMatchInsensitiveEndsWith,
-    OpenDirectory.kODMatchEqualTo : OpenDirectory.kODMatchInsensitiveEqualTo,
-}
 
 def adjustMatchType(matchType, caseInsensitive):
     """ Return the case-insensitive equivalent matchType """
-    return caseInsensitiveEquivalents[matchType] if caseInsensitive else matchType
+    return (matchType | 0x100) if caseInsensitive else matchType
 
+    # return caseInsensitiveEquivalents[matchType] if caseInsensitive else matchType
+
 def recordToResult(record):
     """
     Takes an ODRecord and turns it into a (recordName, attributesDictionary)
@@ -88,7 +87,7 @@
         else:
             result[key] = [unicode(v) for v in value if isinstance(v, objc.pyobjc_unicode)]
 
-    return (details.get(OpenDirectory.kODAttributeTypeRecordName, [None])[0], result)
+    return (details.get(dsattributes.kDSNAttrRecordName, [None])[0], result)
 
 def odInit(nodeName):
     """
@@ -98,8 +97,8 @@
     @return: C{object} an object to be passed to all subsequent functions on success,
         C{None} on failure.
     """
-    session = OpenDirectory.ODSession.defaultSession()
-    node, error = OpenDirectory.ODNode.nodeWithSession_name_error_(session,
+    session = odframework.ODSession.defaultSession()
+    node, error = odframework.ODNode.nodeWithSession_name_error_(session,
         nodeName, None)
     if error:
         log.error(error)
@@ -139,11 +138,11 @@
     @return: C{list} containing a C{list} of C{str} (record name) and C{dict} attributes
         for each record found, or C{None} otherwise.
     """
-    query, error = OpenDirectory.ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(
+    query, error = odframework.ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(
         directory.node,
         recordType,
         None,
-        OpenDirectory.kODMatchAny,
+        MATCHANY,
         None,
         attributes,
         count,
@@ -176,7 +175,7 @@
         for each record found, or C{None} otherwise.
     """
 
-    query, error = OpenDirectory.ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(
+    query, error = odframework.ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(
         directory.node,
         recordType,
         attr,
@@ -211,7 +210,7 @@
     @return: C{list} containing a C{list} of C{str} (record name) and C{dict} attributes
         for each record found, or C{None} otherwise.
     """
-    query, error = OpenDirectory.ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(
+    query, error = odframework.ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(
         directory.node,
         recordType,
         None,
@@ -240,7 +239,7 @@
     @return: OD record if the user was found, None otherwise.
     """
     record, error = directory.node.recordWithRecordType_name_attributes_error_(
-        OpenDirectory.kODRecordTypeUsers,
+        dsattributes.kDSStdRecordTypeUsers,
         user,
         None,
         None
@@ -289,7 +288,7 @@
 
     # TODO: what are these other return values?
     result, mystery1, mystery2, error = record.verifyExtendedWithAuthenticationType_authenticationItems_continueItems_context_error_(
-        OpenDirectory.kODAuthenticationTypeDIGEST_MD5,
+        DIGEST_MD5,
         [user, challenge, response, method],
         None, None, None
     )

Copied: CalendarServer/trunk/calendarserver/od/setup_directory.py (from rev 6564, CalendarServer/trunk/calendarserver/od/test/setup_directory.py)
===================================================================
--- CalendarServer/trunk/calendarserver/od/setup_directory.py	                        (rev 0)
+++ CalendarServer/trunk/calendarserver/od/setup_directory.py	2010-11-04 21:22:45 UTC (rev 6569)
@@ -0,0 +1,295 @@
+##
+# Copyright (c) 2010 Apple Inc. All rights reserved.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+##
+
+import os
+import sys
+import odframework
+import dsattributes
+from getopt import getopt, GetoptError
+
+# TODO: Nested groups
+# TODO: GroupMembership
+
+masterNodeName = "/LDAPv3/127.0.0.1"
+localNodeName = "/Local/Default"
+
+masterUsers = [
+    (
+        "odtestamanda",
+        {
+            dsattributes.kDS1AttrFirstName : ["Amanda"],
+            dsattributes.kDS1AttrLastName  : ["Test"],
+            dsattributes.kDS1AttrDistinguishedName : ["Amanda Test"],
+            dsattributes.kDSNAttrEMailAddress : ["amanda at example.com"],
+            dsattributes.kDS1AttrGeneratedUID : ["9dc04a70-e6dd-11df-9492-0800200c9a66"],
+            dsattributes.kDS1AttrUniqueID : ["33300"],
+        },
+    ),
+    (
+        "odtestbetty",
+        {
+            dsattributes.kDS1AttrFirstName : ["Betty"],
+            dsattributes.kDS1AttrLastName  : ["Test"],
+            dsattributes.kDS1AttrDistinguishedName : ["Betty Test"],
+            dsattributes.kDSNAttrEMailAddress : ["betty at example.com"],
+            dsattributes.kDS1AttrGeneratedUID : ["9dc04a71-e6dd-11df-9492-0800200c9a66"],
+            dsattributes.kDS1AttrUniqueID : ["33301"],
+        },
+    ),
+    (
+        "odtestcarlene",
+        {
+            dsattributes.kDS1AttrFirstName : ["Carlene"],
+            dsattributes.kDS1AttrLastName  : ["Test"],
+            dsattributes.kDS1AttrDistinguishedName : ["Carlene Test"],
+            dsattributes.kDSNAttrEMailAddress : ["carlene at example.com"],
+            dsattributes.kDS1AttrGeneratedUID : ["9dc04a72-e6dd-11df-9492-0800200c9a66"],
+            dsattributes.kDS1AttrUniqueID : ["33302"],
+        },
+    ),
+    (
+        "odtestdenise",
+        {
+            dsattributes.kDS1AttrFirstName : ["Denise"],
+            dsattributes.kDS1AttrLastName  : ["Test"],
+            dsattributes.kDS1AttrDistinguishedName : ["Denise Test"],
+            dsattributes.kDSNAttrEMailAddress : ["denise at example.com"],
+            dsattributes.kDS1AttrGeneratedUID : ["9dc04a73-e6dd-11df-9492-0800200c9a66"],
+            dsattributes.kDS1AttrUniqueID : ["33303"],
+        },
+    ),
+]
+
+masterGroups = [
+    (
+        "odtestgrouptop",
+        {
+            dsattributes.kDS1AttrGeneratedUID : ["6c6cd280-e6e3-11df-9492-0800200c9a66"],
+            dsattributes.kDS1AttrDistinguishedName : ["OD Test Group Top"],
+            dsattributes.kDSNAttrGroupMembers : ["9dc04a70-e6dd-11df-9492-0800200c9a66", "9dc04a71-e6dd-11df-9492-0800200c9a66"],
+            dsattributes.kDS1AttrPrimaryGroupID : ["33400"],
+        },
+    ),
+]
+
+localUsers = [
+    (
+        "odtestalbert",
+        {
+            dsattributes.kDS1AttrFirstName : ["Albert"],
+            dsattributes.kDS1AttrLastName  : ["Test"],
+            dsattributes.kDS1AttrDistinguishedName : ["Albert Test"],
+            dsattributes.kDSNAttrEMailAddress : ["albert at example.com"],
+            dsattributes.kDS1AttrGeneratedUID : ["9dc04a74-e6dd-11df-9492-0800200c9a66"],
+            dsattributes.kDS1AttrUniqueID : ["33350"],
+        },
+    ),
+    (
+        "odtestbill",
+        {
+            dsattributes.kDS1AttrFirstName : ["Bill"],
+            dsattributes.kDS1AttrLastName  : ["Test"],
+            dsattributes.kDS1AttrDistinguishedName : ["Bill Test"],
+            dsattributes.kDSNAttrEMailAddress : ["bill at example.com"],
+            dsattributes.kDS1AttrGeneratedUID : ["9dc04a75-e6dd-11df-9492-0800200c9a66"],
+            dsattributes.kDS1AttrUniqueID : ["33351"],
+        },
+    ),
+    (
+        "odtestcarl",
+        {
+            dsattributes.kDS1AttrFirstName : ["Carl"],
+            dsattributes.kDS1AttrLastName  : ["Test"],
+            dsattributes.kDS1AttrDistinguishedName : ["Carl Test"],
+            dsattributes.kDSNAttrEMailAddress : ["carl at example.com"],
+            dsattributes.kDS1AttrGeneratedUID : ["9dc04a76-e6dd-11df-9492-0800200c9a66"],
+            dsattributes.kDS1AttrUniqueID : ["33352"],
+        },
+    ),
+    (
+        "odtestdavid",
+        {
+            dsattributes.kDS1AttrFirstName : ["David"],
+            dsattributes.kDS1AttrLastName  : ["Test"],
+            dsattributes.kDS1AttrDistinguishedName : ["David Test"],
+            dsattributes.kDSNAttrEMailAddress : ["david at example.com"],
+            dsattributes.kDS1AttrGeneratedUID : ["9dc04a77-e6dd-11df-9492-0800200c9a66"],
+            dsattributes.kDS1AttrUniqueID : ["33353"],
+        },
+    ),
+]
+
+localGroups = [
+    (
+        "odtestsubgroupa",
+        {
+            dsattributes.kDS1AttrGeneratedUID : ["6c6cd281-e6e3-11df-9492-0800200c9a66"],
+            dsattributes.kDS1AttrDistinguishedName : ["OD Test Subgroup A"],
+            dsattributes.kDSNAttrGroupMembers : ["9dc04a74-e6dd-11df-9492-0800200c9a66", "9dc04a75-e6dd-11df-9492-0800200c9a66"],
+            dsattributes.kDS1AttrPrimaryGroupID : ["33400"],
+        },
+    ),
+]
+
+
+def usage(e=None):
+    name = os.path.basename(sys.argv[0])
+    print "usage: %s [options] local_user local_password odmaster_user odmaster_password" % (name,)
+    print ""
+    print " Configures local and OD master directories for testing"
+    print ""
+    print "options:"
+    print " -h --help: print this help and exit"
+    if e:
+        sys.exit(1)
+    else:
+        sys.exit(0)
+
+
+def lookupRecordName(node, recordType, name):
+    query, error = odframework.ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(
+        node,
+        recordType,
+        dsattributes.kDSNAttrRecordName,
+        dsattributes.eDSExact,
+        name,
+        None,
+        0,
+        None)
+    if error:
+        raise ODError(error)
+    records, error = query.resultsAllowingPartial_error_(False, None)
+    if error:
+        raise ODError(error)
+
+    if len(records) < 1:
+        return None
+    if len(records) > 1:
+        raise ODError("Multiple records for '%s' were found" % (name,))
+
+    return records[0]
+
+def createRecord(node, recordType, recordName, attrs):
+    record, error = node.createRecordWithRecordType_name_attributes_error_(
+        recordType,
+        recordName,
+        attrs,
+        None)
+    if error:
+        print error
+        raise ODError(error)
+    return record
+
+def main():
+
+    try:
+        (optargs, args) = getopt(sys.argv[1:], "h", ["help"])
+    except GetoptError, e:
+        usage(e)
+
+    for opt, arg in optargs:
+        if opt in ("-h", "--help"):
+            usage()
+
+    if len(args) != 4:
+        usage()
+
+    localUser, localPassword, masterUser, masterPassword = args
+
+    userInfo = {
+        masterNodeName : {
+            "user" : masterUser,
+            "password" : masterPassword,
+            "users" : masterUsers,
+            "groups" : masterGroups,
+        },
+        localNodeName : {
+            "user" : localUser,
+            "password" : localPassword,
+            "users" : localUsers,
+            "groups" : localGroups,
+        },
+    }
+
+
+    session = odframework.ODSession.defaultSession()
+
+    for nodeName, info in userInfo.iteritems():
+
+        userName = info["user"]
+        password = info["password"]
+        users = info["users"]
+        groups = info["groups"]
+
+        node, error = odframework.ODNode.nodeWithSession_name_error_(session, nodeName, None)
+        if error:
+            print error
+            raise ODError(error)
+
+        result, error = node.setCredentialsWithRecordType_recordName_password_error_(
+            dsattributes.kDSStdRecordTypeUsers,
+            userName,
+            password,
+            None
+        )
+        if error:
+            print "Unable to authenticate with directory %s: %s" % (nodeName, error)
+            raise ODError(error)
+
+        print "Successfully authenticated with directory %s" % (nodeName,)
+
+        print "Creating users within %s:" % (nodeName,)
+        for recordName, attrs in users:
+            record = lookupRecordName(node, dsattributes.kDSStdRecordTypeUsers, recordName)
+            if record is None:
+                print "Creating user %s" % (recordName,)
+                try:
+                    record = createRecord(node, dsattributes.kDSStdRecordTypeUsers, recordName, attrs)
+                    print "Successfully created user %s" % (recordName,)
+                    result, error = record.changePassword_toPassword_error_(
+                        None, "password", None)
+                    if error or not result:
+                        print "Failed to set password for %s: %s" % (recordName, error)
+                    else:
+                        print "Successfully set password for %s" % (recordName,)
+                except ODError, e:
+                    print "Failed to create user %s: %s" % (recordName, e)
+            else:
+                print "User %s already exists" % (recordName,)
+
+        print "Creating groups within %s:" % (nodeName,)
+        for recordName, attrs in groups:
+            record = lookupRecordName(node, dsattributes.kDSStdRecordTypeGroups, recordName)
+            if record is None:
+                print "Creating group %s" % (recordName,)
+                try:
+                    record = createRecord(node, dsattributes.kDSStdRecordTypeGroups, recordName, attrs)
+                    print "Successfully created group %s" % (recordName,)
+                except ODError, e:
+                    print "Failed to create group %s: %s" % (recordName, e)
+            else:
+                print "Group %s already exists" % (recordName,)
+
+        print
+
+
+
+class ODError(Exception):
+    def __init__(self, error):
+        self.message = (str(error), error.code())
+
+if __name__ == "__main__":
+    main()

Deleted: CalendarServer/trunk/calendarserver/od/test/setup_directory.py
===================================================================
--- CalendarServer/trunk/calendarserver/od/test/setup_directory.py	2010-11-04 20:25:29 UTC (rev 6568)
+++ CalendarServer/trunk/calendarserver/od/test/setup_directory.py	2010-11-04 21:22:45 UTC (rev 6569)
@@ -1,294 +0,0 @@
-##
-# Copyright (c) 2010 Apple Inc. All rights reserved.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-##
-
-import os
-import sys
-import OpenDirectory
-from getopt import getopt, GetoptError
-
-# TODO: Nested groups
-# TODO: GroupMembership
-
-masterNodeName = "/LDAPv3/127.0.0.1"
-localNodeName = "/Local/Default"
-
-masterUsers = [
-    (
-        "odtestamanda",
-        {
-            OpenDirectory.kODAttributeTypeFirstName : ["Amanda"],
-            OpenDirectory.kODAttributeTypeLastName  : ["Test"],
-            OpenDirectory.kODAttributeTypeFullName : ["Amanda Test"],
-            OpenDirectory.kODAttributeTypeEMailAddress : ["amanda at example.com"],
-            OpenDirectory.kODAttributeTypeGUID : ["9dc04a70-e6dd-11df-9492-0800200c9a66"],
-            OpenDirectory.kODAttributeTypeUniqueID : ["33300"],
-        },
-    ),
-    (
-        "odtestbetty",
-        {
-            OpenDirectory.kODAttributeTypeFirstName : ["Betty"],
-            OpenDirectory.kODAttributeTypeLastName  : ["Test"],
-            OpenDirectory.kODAttributeTypeFullName : ["Betty Test"],
-            OpenDirectory.kODAttributeTypeEMailAddress : ["betty at example.com"],
-            OpenDirectory.kODAttributeTypeGUID : ["9dc04a71-e6dd-11df-9492-0800200c9a66"],
-            OpenDirectory.kODAttributeTypeUniqueID : ["33301"],
-        },
-    ),
-    (
-        "odtestcarlene",
-        {
-            OpenDirectory.kODAttributeTypeFirstName : ["Carlene"],
-            OpenDirectory.kODAttributeTypeLastName  : ["Test"],
-            OpenDirectory.kODAttributeTypeFullName : ["Carlene Test"],
-            OpenDirectory.kODAttributeTypeEMailAddress : ["carlene at example.com"],
-            OpenDirectory.kODAttributeTypeGUID : ["9dc04a72-e6dd-11df-9492-0800200c9a66"],
-            OpenDirectory.kODAttributeTypeUniqueID : ["33302"],
-        },
-    ),
-    (
-        "odtestdenise",
-        {
-            OpenDirectory.kODAttributeTypeFirstName : ["Denise"],
-            OpenDirectory.kODAttributeTypeLastName  : ["Test"],
-            OpenDirectory.kODAttributeTypeFullName : ["Denise Test"],
-            OpenDirectory.kODAttributeTypeEMailAddress : ["denise at example.com"],
-            OpenDirectory.kODAttributeTypeGUID : ["9dc04a73-e6dd-11df-9492-0800200c9a66"],
-            OpenDirectory.kODAttributeTypeUniqueID : ["33303"],
-        },
-    ),
-]
-
-masterGroups = [
-    (
-        "odtestgrouptop",
-        {
-            OpenDirectory.kODAttributeTypeGUID : ["6c6cd280-e6e3-11df-9492-0800200c9a66"],
-            OpenDirectory.kODAttributeTypeFullName : ["OD Test Group Top"],
-            OpenDirectory.kODAttributeTypeGroupMembers : ["9dc04a70-e6dd-11df-9492-0800200c9a66", "9dc04a71-e6dd-11df-9492-0800200c9a66"],
-            OpenDirectory.kODAttributeTypePrimaryGroupID : ["33400"],
-        },
-    ),
-]
-
-localUsers = [
-    (
-        "odtestalbert",
-        {
-            OpenDirectory.kODAttributeTypeFirstName : ["Albert"],
-            OpenDirectory.kODAttributeTypeLastName  : ["Test"],
-            OpenDirectory.kODAttributeTypeFullName : ["Albert Test"],
-            OpenDirectory.kODAttributeTypeEMailAddress : ["albert at example.com"],
-            OpenDirectory.kODAttributeTypeGUID : ["9dc04a74-e6dd-11df-9492-0800200c9a66"],
-            OpenDirectory.kODAttributeTypeUniqueID : ["33350"],
-        },
-    ),
-    (
-        "odtestbill",
-        {
-            OpenDirectory.kODAttributeTypeFirstName : ["Bill"],
-            OpenDirectory.kODAttributeTypeLastName  : ["Test"],
-            OpenDirectory.kODAttributeTypeFullName : ["Bill Test"],
-            OpenDirectory.kODAttributeTypeEMailAddress : ["bill at example.com"],
-            OpenDirectory.kODAttributeTypeGUID : ["9dc04a75-e6dd-11df-9492-0800200c9a66"],
-            OpenDirectory.kODAttributeTypeUniqueID : ["33351"],
-        },
-    ),
-    (
-        "odtestcarl",
-        {
-            OpenDirectory.kODAttributeTypeFirstName : ["Carl"],
-            OpenDirectory.kODAttributeTypeLastName  : ["Test"],
-            OpenDirectory.kODAttributeTypeFullName : ["Carl Test"],
-            OpenDirectory.kODAttributeTypeEMailAddress : ["carl at example.com"],
-            OpenDirectory.kODAttributeTypeGUID : ["9dc04a76-e6dd-11df-9492-0800200c9a66"],
-            OpenDirectory.kODAttributeTypeUniqueID : ["33352"],
-        },
-    ),
-    (
-        "odtestdavid",
-        {
-            OpenDirectory.kODAttributeTypeFirstName : ["David"],
-            OpenDirectory.kODAttributeTypeLastName  : ["Test"],
-            OpenDirectory.kODAttributeTypeFullName : ["David Test"],
-            OpenDirectory.kODAttributeTypeEMailAddress : ["david at example.com"],
-            OpenDirectory.kODAttributeTypeGUID : ["9dc04a77-e6dd-11df-9492-0800200c9a66"],
-            OpenDirectory.kODAttributeTypeUniqueID : ["33353"],
-        },
-    ),
-]
-
-localGroups = [
-    (
-        "odtestsubgroupa",
-        {
-            OpenDirectory.kODAttributeTypeGUID : ["6c6cd281-e6e3-11df-9492-0800200c9a66"],
-            OpenDirectory.kODAttributeTypeFullName : ["OD Test Subgroup A"],
-            OpenDirectory.kODAttributeTypeGroupMembers : ["9dc04a74-e6dd-11df-9492-0800200c9a66", "9dc04a75-e6dd-11df-9492-0800200c9a66"],
-            OpenDirectory.kODAttributeTypePrimaryGroupID : ["33400"],
-        },
-    ),
-]
-
-
-def usage(e=None):
-    name = os.path.basename(sys.argv[0])
-    print "usage: %s [options] local_user local_password odmaster_user odmaster_password" % (name,)
-    print ""
-    print " Configures local and OD master directories for testing"
-    print ""
-    print "options:"
-    print " -h --help: print this help and exit"
-    if e:
-        sys.exit(1)
-    else:
-        sys.exit(0)
-
-
-def lookupRecordName(node, recordType, name):
-    query, error = OpenDirectory.ODQuery.queryWithNode_forRecordTypes_attribute_matchType_queryValues_returnAttributes_maximumResults_error_(
-        node,
-        recordType,
-        OpenDirectory.kODAttributeTypeRecordName,
-        OpenDirectory.kODMatchEqualTo,
-        name,
-        None,
-        0,
-        None)
-    if error:
-        raise ODError(error)
-    records, error = query.resultsAllowingPartial_error_(False, None)
-    if error:
-        raise ODError(error)
-
-    if len(records) < 1:
-        return None
-    if len(records) > 1:
-        raise ODError("Multiple records for '%s' were found" % (name,))
-
-    return records[0]
-
-def createRecord(node, recordType, recordName, attrs):
-    record, error = node.createRecordWithRecordType_name_attributes_error_(
-        recordType,
-        recordName,
-        attrs,
-        None)
-    if error:
-        print error
-        raise ODError(error)
-    return record
-
-def main():
-
-    try:
-        (optargs, args) = getopt(sys.argv[1:], "h", ["help"])
-    except GetoptError, e:
-        usage(e)
-
-    for opt, arg in optargs:
-        if opt in ("-h", "--help"):
-            usage()
-
-    if len(args) != 4:
-        usage()
-
-    localUser, localPassword, masterUser, masterPassword = args
-
-    userInfo = {
-        masterNodeName : {
-            "user" : masterUser,
-            "password" : masterPassword,
-            "users" : masterUsers,
-            "groups" : masterGroups,
-        },
-        localNodeName : {
-            "user" : localUser,
-            "password" : localPassword,
-            "users" : localUsers,
-            "groups" : localGroups,
-        },
-    }
-
-
-    session = OpenDirectory.ODSession.defaultSession()
-
-    for nodeName, info in userInfo.iteritems():
-
-        userName = info["user"]
-        password = info["password"]
-        users = info["users"]
-        groups = info["groups"]
-
-        node, error = OpenDirectory.ODNode.nodeWithSession_name_error_(session, nodeName, None)
-        if error:
-            print error
-            raise ODError(error)
-
-        result, error = node.setCredentialsWithRecordType_recordName_password_error_(
-            OpenDirectory.kODRecordTypeUsers,
-            userName,
-            password,
-            None
-        )
-        if error:
-            print "Unable to authenticate with directory %s: %s" % (nodeName, error)
-            raise ODError(error)
-
-        print "Successfully authenticated with directory %s" % (nodeName,)
-
-        print "Creating users within %s:" % (nodeName,)
-        for recordName, attrs in users:
-            record = lookupRecordName(node, OpenDirectory.kODRecordTypeUsers, recordName)
-            if record is None:
-                print "Creating user %s" % (recordName,)
-                try:
-                    record = createRecord(node, OpenDirectory.kODRecordTypeUsers, recordName, attrs)
-                    print "Successfully created user %s" % (recordName,)
-                    result, error = record.changePassword_toPassword_error_(
-                        None, "password", None)
-                    if error or not result:
-                        print "Failed to set password for %s: %s" % (recordName, error)
-                    else:
-                        print "Successfully set password for %s" % (recordName,)
-                except ODError, e:
-                    print "Failed to create user %s: %s" % (recordName, e)
-            else:
-                print "User %s already exists" % (recordName,)
-
-        print "Creating groups within %s:" % (nodeName,)
-        for recordName, attrs in groups:
-            record = lookupRecordName(node, OpenDirectory.kODRecordTypeGroups, recordName)
-            if record is None:
-                print "Creating group %s" % (recordName,)
-                try:
-                    record = createRecord(node, OpenDirectory.kODRecordTypeGroups, recordName, attrs)
-                    print "Successfully created group %s" % (recordName,)
-                except ODError, e:
-                    print "Failed to create group %s: %s" % (recordName, e)
-            else:
-                print "Group %s already exists" % (recordName,)
-
-        print
-
-
-
-class ODError(Exception):
-    def __init__(self, error):
-        self.message = (str(error), error.code())
-
-if __name__ == "__main__":
-    main()

Modified: CalendarServer/trunk/calendarserver/od/test/test_opendirectory.py
===================================================================
--- CalendarServer/trunk/calendarserver/od/test/test_opendirectory.py	2010-11-04 20:25:29 UTC (rev 6568)
+++ CalendarServer/trunk/calendarserver/od/test/test_opendirectory.py	2010-11-04 21:22:45 UTC (rev 6569)
@@ -15,13 +15,14 @@
 ##
 
 from twistedcaldav.test.util import TestCase
+import hashlib
+import random
+import sys
 
 runTests = False
 
 try:
-    import OpenDirectory
-    from calendarserver.od import opendirectory, dsattributes, dsquery
-    import setup_directory
+    from calendarserver.od import opendirectory, dsattributes, dsquery, setup_directory
 
     directory = opendirectory.odInit("/Search")
 
@@ -45,6 +46,41 @@
 except ImportError:
     print "Unable to import OpenDirectory framework"
 
+
+def generateNonce():
+    c = tuple([random.randrange(sys.maxint) for _ in range(3)])
+    c = '%d%d%d' % c
+    return c
+
+def getChallengeResponse(user, password, node, uri, method):
+    nonce = generateNonce()
+
+    ha1 = hashlib.md5("%s:%s:%s" % (user, node, password)).hexdigest()
+    ha2 = hashlib.md5("%s:%s" % (method, uri)).hexdigest()
+    response = hashlib.md5("%s:%s:%s"% (ha1, nonce, ha2)).hexdigest()
+
+    fields = {
+        'username': user,
+        'nonce': nonce,
+        'realm': node,
+        'algorithm': 'md5',
+        'uri': uri,
+        'response': response,
+    }
+
+    challenge = 'Digest realm="%(realm)s", nonce="%(nonce)s", algorithm=%(algorithm)s' % fields
+
+    response = (
+        'Digest username="%(username)s", '
+        'realm="%(realm)s", '
+        'nonce="%(nonce)s", '
+        'uri="%(uri)s", '
+        'response="%(response)s",'
+        'algorithm=%(algorithm)s'
+    ) % fields
+
+    return challenge, response
+
 if runTests:
 
     USER_ATTRIBUTES = [
@@ -72,28 +108,20 @@
 
         def test_adjustMatchType(self):
             self.assertEquals(
-                opendirectory.adjustMatchType(OpenDirectory.kODMatchEqualTo, False),
-                OpenDirectory.kODMatchEqualTo
+                opendirectory.adjustMatchType(dsattributes.eDSExact, False),
+                dsattributes.eDSExact
             )
             self.assertEquals(
-                opendirectory.adjustMatchType(OpenDirectory.kODMatchEqualTo, True),
-                OpenDirectory.kODMatchInsensitiveEqualTo
+                opendirectory.adjustMatchType(dsattributes.eDSExact, True),
+                dsattributes.eDSExact | 0x100
             )
-            self.assertEquals(
-                opendirectory.adjustMatchType(OpenDirectory.kODMatchContains, False),
-                OpenDirectory.kODMatchContains
-            )
-            self.assertEquals(
-                opendirectory.adjustMatchType(OpenDirectory.kODMatchContains, True),
-                OpenDirectory.kODMatchInsensitiveContains
-            )
 
         def test_getNodeAttributes(self):
 
             directory = opendirectory.odInit("/Search")
-            results = opendirectory.getNodeAttributes(directory, "/Search", [OpenDirectory.kODAttributeTypeSearchPath])
-            self.assertTrue("/Local/Default" in results[OpenDirectory.kODAttributeTypeSearchPath])
-            self.assertTrue("/LDAPv3/127.0.0.1" in results[OpenDirectory.kODAttributeTypeSearchPath])
+            results = opendirectory.getNodeAttributes(directory, "/Search", [dsattributes.kDS1AttrSearchPath])
+            self.assertTrue("/Local/Default" in results[dsattributes.kDS1AttrSearchPath])
+            self.assertTrue("/LDAPv3/127.0.0.1" in results[dsattributes.kDS1AttrSearchPath])
 
         def test_listAllRecordsWithAttributes_list_master(self):
 
@@ -528,7 +556,7 @@
             groupMembers = results[0][1][dsattributes.kDSNAttrGroupMembers]
             self.assertEquals(
                 groupMembers,
-                setup_directory.masterGroups[0][1][OpenDirectory.kODAttributeTypeGroupMembers]
+                setup_directory.masterGroups[0][1][dsattributes.kDSNAttrGroupMembers]
             )
 
         def test_queryRecordsWithAttribute_list_groupMembers_recordName_local(self):
@@ -553,7 +581,7 @@
             groupMembers = results[0][1][dsattributes.kDSNAttrGroupMembers]
             self.assertEquals(
                 groupMembers,
-                setup_directory.localGroups[0][1][OpenDirectory.kODAttributeTypeGroupMembers]
+                setup_directory.localGroups[0][1][dsattributes.kDSNAttrGroupMembers]
             )
 
 
@@ -579,7 +607,7 @@
             groupMembers = results[0][1][dsattributes.kDSNAttrGroupMembers]
             self.assertEquals(
                 groupMembers,
-                setup_directory.masterGroups[0][1][OpenDirectory.kODAttributeTypeGroupMembers]
+                setup_directory.masterGroups[0][1][dsattributes.kDSNAttrGroupMembers]
             )
 
         def test_queryRecordsWithAttribute_list_groupMembers_guid_local(self):
@@ -604,7 +632,7 @@
             groupMembers = results[0][1][dsattributes.kDSNAttrGroupMembers]
             self.assertEquals(
                 groupMembers,
-                setup_directory.localGroups[0][1][OpenDirectory.kODAttributeTypeGroupMembers]
+                setup_directory.localGroups[0][1][dsattributes.kDSNAttrGroupMembers]
             )
 
 
@@ -726,6 +754,38 @@
                 "/Local/Default", "odtestalbert", "password")
             self.assertTrue(result)
 
+        def test_digestAuth_master(self):
+            directory = opendirectory.odInit("/Search")
+
+            user = "odtestamanda"
+            password = "password"
+            node = "/LDAPv3/127.0.0.1"
+            uri = "principals/users/odtestamanda"
+            method = "PROPFIND"
+
+            challenge, response = getChallengeResponse(user, password, node,
+                uri, method)
+
+            result = opendirectory.authenticateUserDigest(directory, node,
+                user, challenge, response, method)
+            self.assertTrue(result)
+
+        def test_digestAuth_local(self):
+            directory = opendirectory.odInit("/Search")
+
+            user = "odtestalbert"
+            password = "password"
+            node = "/Local/Default"
+            uri = "principals/users/odtestalbert"
+            method = "PROPFIND"
+
+            challenge, response = getChallengeResponse(user, password, node,
+                uri, method)
+
+            result = opendirectory.authenticateUserDigest(directory, node,
+                user, challenge, response, method)
+            self.assertTrue(result)
+
         def test_unicode_results(self):
             directory = opendirectory.odInit("/Search")
             record = opendirectory.getUserRecord(directory, "odtestbill")

Modified: CalendarServer/trunk/calendarserver/sidecar/test/test_task.py
===================================================================
--- CalendarServer/trunk/calendarserver/sidecar/test/test_task.py	2010-11-04 20:25:29 UTC (rev 6568)
+++ CalendarServer/trunk/calendarserver/sidecar/test/test_task.py	2010-11-04 21:22:45 UTC (rev 6569)
@@ -29,7 +29,8 @@
 sourceRoot = dirname(dirname(dirname(dirname(abspath(__file__)))))
 
 
-class CalDAVTaskServiceTest(TestCase):
+# TODO: update or delete task sidecar
+class CalDAVTaskServiceTest(object): # TestCase):
     """
     Test various parameters of our usage.Options subclass
     """

Modified: CalendarServer/trunk/calendarserver/tools/resources.py
===================================================================
--- CalendarServer/trunk/calendarserver/tools/resources.py	2010-11-04 20:25:29 UTC (rev 6568)
+++ CalendarServer/trunk/calendarserver/tools/resources.py	2010-11-04 21:22:45 UTC (rev 6569)
@@ -33,11 +33,7 @@
 import os
 import sys
 
-# TODO: Temporary means of switching to PyObjC version
-if os.path.exists("/tmp/calendarserver_use_pyobjc"):
-    from calendarserver.od import opendirectory, dsattributes
-else:
-    import opendirectory, dsattributes
+from calendarserver.od import dsattributes
 
 __all__ = [ "migrateResources", ]
 
@@ -178,7 +174,7 @@
     if verbose:
         print "Querying for all %s records" % (recordType,)
 
-    results = list(opendirectory.listAllRecordsWithAttributes_list(
+    results = list(sourceService.odModule.listAllRecordsWithAttributes_list(
         sourceService.directory,
         recordType,
         attrs,

Modified: CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py	2010-11-04 20:25:29 UTC (rev 6568)
+++ CalendarServer/trunk/twistedcaldav/directory/appleopendirectory.py	2010-11-04 21:22:45 UTC (rev 6569)
@@ -39,14 +39,11 @@
 from twistedcaldav.directory.directory import DirectoryError, UnknownRecordTypeError
 from twistedcaldav.directory.principal import cuAddressConverter
 
-# TODO: Temporary means of switching to PyObjC version
-import os
-if os.path.exists("/tmp/calendarserver_use_pyobjc"):
-    from calendarserver.od import opendirectory, dsattributes, dsquery
-else:
-    import opendirectory, dsattributes, dsquery
+from calendarserver.od import dsattributes, dsquery
+from twisted.python.reflect import namedModule
 
 
+
 class OpenDirectoryService(CachingDirectoryService):
     """
     OpenDirectory implementation of L{IDirectoryService}.
@@ -88,9 +85,11 @@
 
         super(OpenDirectoryService, self).__init__(params['cacheTimeout'])
 
+        self.odModule = namedModule(config.OpenDirectoryModule)
+
         try:
-            directory = opendirectory.odInit(params['node'])
-        except opendirectory.ODError, e:
+            directory = self.odModule.odInit(params['node'])
+        except self.odModule.ODError, e:
             self.log_error("OpenDirectory (node=%s) Initialization error: %s" % (params['node'], e))
             raise
 
@@ -130,7 +129,7 @@
                     dsattributes.kDSStdRecordTypeGroups,
                     [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups,],
                 ))
-                results = opendirectory.queryRecordsWithAttribute_list(
+                results = self.odModule.queryRecordsWithAttribute_list(
                     self.directory,
                     attributeToMatch,
                     valueToMatch,
@@ -199,7 +198,7 @@
                 dsattributes.kDSStdRecordTypeGroups,
                 [dsattributes.kDSNAttrGroupMembers, dsattributes.kDSNAttrNestedGroups]
             ))
-            result = opendirectory.queryRecordsWithAttribute_list(
+            result = self.odModule.queryRecordsWithAttribute_list(
                 self.directory,
                 dsattributes.kDS1AttrGeneratedUID,
                 groupGUID,
@@ -251,7 +250,7 @@
                 recordType,
                 attrs,
             ))
-            results = opendirectory.queryRecordsWithAttribute_list(
+            results = self.odModule.queryRecordsWithAttribute_list(
                 self.directory,
                 dsattributes.kDSNAttrGroupMembers,
                 guid,
@@ -260,7 +259,7 @@
                 recordType,
                 attrs,
             )
-        except opendirectory.ODError, ex:
+        except self.odModule.ODError, ex:
             self.log_error("OpenDirectory (node=%s) error: %s" % (self.realmName, str(ex)))
             raise
 
@@ -281,7 +280,7 @@
                 recordType,
                 attrs,
             ))
-            results = opendirectory.queryRecordsWithAttribute_list(
+            results = self.odModule.queryRecordsWithAttribute_list(
                 self.directory,
                 dsattributes.kDSNAttrNestedGroups,
                 guid,
@@ -290,7 +289,7 @@
                 recordType,
                 attrs,
             )
-        except opendirectory.ODError, ex:
+        except self.odModule.ODError, ex:
             self.log_error("OpenDirectory (node=%s) error: %s" % (self.realmName, str(ex)))
             raise
 
@@ -393,8 +392,11 @@
             return ()
 
     def recordsMatchingFields(self, fields, operand="or", recordType=None,
-        lookupMethod=opendirectory.queryRecordsWithAttribute_list):
+        lookupMethod=None):
 
+        if lookupMethod is None:
+            lookupMethod=self.odModule.queryRecordsWithAttribute_list
+
         # Note that OD applies case-sensitivity globally across the entire
         # query, not per expression, so the current code uses whatever is
         # specified in the last field in the fields list
@@ -509,7 +511,7 @@
 
                         sets.append(newSet)
 
-                except opendirectory.ODError, e:
+                except self.odModule.ODError, e:
                     self.log_error("Ignoring OD Error: %d %s" %
                         (e.message[1], e.message[0]))
                     continue
@@ -558,8 +560,11 @@
 
 
     def queryDirectory(self, recordTypes, indexType, indexKey,
-        lookupMethod=opendirectory.queryRecordsWithAttribute_list):
+        lookupMethod=None):
 
+        if lookupMethod is None:
+            lookupMethod=self.odModule.queryRecordsWithAttribute_list
+
         origIndexKey = indexKey
         if indexType == self.INDEX_TYPE_CUA:
             # The directory doesn't contain CUAs, so we need to convert
@@ -639,7 +644,7 @@
                         )
                     )
 
-                except opendirectory.ODError, ex:
+                except self.odModule.ODError, ex:
                     if ex.message[1] == -14987:
                         # Fall through and retry
                         self.log_error("OpenDirectory (node=%s) error: %s" % (self.realmName, str(ex)))
@@ -771,7 +776,7 @@
         """
 
         if self.node == "/Search":
-            result = opendirectory.getNodeAttributes(self.directory, "/Search",
+            result = self.odModule.getNodeAttributes(self.directory, "/Search",
                 (dsattributes.kDS1AttrSearchPath,))
             nodes = result[dsattributes.kDS1AttrSearchPath]
         else:
@@ -779,8 +784,8 @@
 
         try:
             for node in nodes:
-                opendirectory.getNodeAttributes(self.directory, node, [dsattributes.kDSNAttrNodePath])
-        except opendirectory.ODError:
+                self.odModule.getNodeAttributes(self.directory, node, [dsattributes.kDSNAttrNodePath])
+        except self.odModule.ODError:
             self.log_warn("OpenDirectory Node %s not available" % (node,))
             return False
 
@@ -877,11 +882,11 @@
 
             # Check with directory services
             try:
-                if opendirectory.authenticateUserBasic(self.service.directory, self.nodeName, self.shortNames[0], credentials.password):
+                if self.service.odModule.authenticateUserBasic(self.service.directory, self.nodeName, self.shortNames[0], credentials.password):
                     # Cache the password to avoid future DS queries
                     self.password = credentials.password
                     return True
-            except opendirectory.ODError, e:
+            except self.service.odModule.ODError, e:
                 self.log_error("OpenDirectory (node=%s) error while performing basic authentication for user %s: %s"
                             % (self.service.realmName, self.shortNames[0], e))
 
@@ -919,7 +924,7 @@
                 pass
 
             try:
-                if opendirectory.authenticateUserDigest(
+                if self.service.odModule.authenticateUserDigest(
                     self.service.directory,
                     self.nodeName,
                     self.shortNames[0],
@@ -945,7 +950,7 @@
     Method:    %s
 """ % (self.nodeName, self.shortNames[0], challenge, response, credentials.originalMethod if credentials.originalMethod else credentials.method))
 
-            except opendirectory.ODError, e:
+            except self.service.odModule.ODError, e:
                 self.log_error(
                     "OpenDirectory (node=%s) error while performing digest authentication for user %s: %s"
                     % (self.service.realmName, self.shortNames[0], e)

Modified: CalendarServer/trunk/twistedcaldav/directory/opendirectorybacker.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/opendirectorybacker.py	2010-11-04 20:25:29 UTC (rev 6568)
+++ CalendarServer/trunk/twistedcaldav/directory/opendirectorybacker.py	2010-11-04 21:22:45 UTC (rev 6569)
@@ -59,11 +59,8 @@
 from xmlrpclib import datetime
 from vobject.vcard import Name, Address
 
-# TODO: Temporary means of switching to PyObjC version
-if os.path.exists("/tmp/calendarserver_use_pyobjc"):
-    from calendarserver.od import opendirectory, dsattributes, dsquery
-else:
-    import opendirectory, dsattributes, dsquery
+from calendarserver.od import dsattributes, dsquery
+from twisted.python.reflect import namedModule
 
 class OpenDirectoryBackingService(DirectoryService):
     """
@@ -127,12 +124,14 @@
         self.userNode = None
         
         self.realmName = None # needed for super
+
+        self.odModule = namedModule(config.OpenDirectoryModule)
         
         if queryPeopleRecords or not queryUserRecords:
             self.peopleNode = peopleNode
             try:
-                self.peopleDirectory = opendirectory.odInit(peopleNode)
-            except opendirectory.ODError, e:
+                self.peopleDirectory = self.odModule.odInit(peopleNode)
+            except self.odModule.ODError, e:
                 self.log_error("Open Directory (node=%s) Initialization error: %s" % (peopleNode, e))
                 raise
             self.realmName = peopleNode
@@ -144,8 +143,8 @@
             else:
                 self.userNode = userNode
                 try:
-                    self.userDirectory = opendirectory.odInit(userNode)
-                except opendirectory.ODError, e:
+                    self.userDirectory = self.odModule.odInit(userNode)
+                except self.odModule.ODError, e:
                     self.log_error("Open Directory (node=%s) Initialization error: %s" % (userNode, e))
                     raise
                 if self.realmName:
@@ -433,18 +432,18 @@
             
             recordTypes = [dsattributes.kDSStdRecordTypePeople, dsattributes.kDSStdRecordTypeUsers, ]
             try:
-                localNodeDirectory = opendirectory.odInit("/Local/Default")
+                localNodeDirectory = self.odModule.odInit("/Local/Default")
                 self.log_debug("opendirectory.listAllRecordsWithAttributes_list(%r,%r,%r)" % (
                         "/DSLocal",
                         recordTypes,
                         self.returnedAttributes,
                     ))
-                results = list(opendirectory.listAllRecordsWithAttributes_list(
+                results = list(self.odModule.listAllRecordsWithAttributes_list(
                         localNodeDirectory,
                         recordTypes,
                         self.returnedAttributes,
                     ))
-            except opendirectory.ODError, ex:
+            except self.odModule.ODError, ex:
                 self.log_error("Open Directory (node=%s) error: %s" % ("/Local/Default", str(ex)))
                 raise
             
@@ -557,7 +556,7 @@
                             maxRecords,
                         ))
                         results = list(
-                            opendirectory.queryRecordsWithAttribute_list(
+                            self.odModule.queryRecordsWithAttribute_list(
                                 directory,
                                 query.attribute,
                                 query.value,
@@ -577,7 +576,7 @@
                             maxRecords,
                         ))
                         results = list(
-                            opendirectory.queryRecordsWithAttributes_list(
+                            self.odModule.queryRecordsWithAttributes_list(
                                 directory,
                                 query.generate(),
                                 False,
@@ -593,13 +592,13 @@
                         maxRecords,
                     ))
                     results = list(
-                        opendirectory.listAllRecordsWithAttributes_list(
+                        self.odModule.listAllRecordsWithAttributes_list(
                             directory,
                             recordType,
                             attributes,
                             maxRecords,
                         ))
-            except opendirectory.ODError, ex:
+            except self.odModule.ODError, ex:
                 self.log_error("Open Directory (node=%s) error: %s" % (self.realmName, str(ex)))
                 raise
             

Modified: CalendarServer/trunk/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/stdconfig.py	2010-11-04 20:25:29 UTC (rev 6568)
+++ CalendarServer/trunk/twistedcaldav/stdconfig.py	2010-11-04 21:22:45 UTC (rev 6569)
@@ -599,6 +599,13 @@
 
     "EnableKeepAlive": True,
 
+    # Specify which opendirectory module to use:
+    # "opendirectory" is PyOpenDirectory (the old one which uses
+    # DirectoryService.framework)
+    # "calendarserver.od.opendirectory" is the new PyObjC version which uses
+    # OpenDirectory.framework
+    "OpenDirectoryModule": "opendirectory",
+
     "Includes": [],     # Other plists to parse after this one
 }
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20101104/e46e09bc/attachment-0001.html>


More information about the calendarserver-changes mailing list