[CalendarServer-changes] [933] PyOpenDirectory/trunk

source_changes at macosforge.org source_changes at macosforge.org
Fri Jan 5 09:29:27 PST 2007


Revision: 933
          http://trac.macosforge.org/projects/calendarserver/changeset/933
Author:   cdaboo at apple.com
Date:     2007-01-05 09:29:27 -0800 (Fri, 05 Jan 2007)

Log Message:
-----------
Merge of branches/users/cdaboo/new-schema-892. This changes the api to a simpler, more generic, one.

Modified Paths:
--------------
    PyOpenDirectory/trunk/pysrc/dsattributes.py
    PyOpenDirectory/trunk/pysrc/opendirectory.py
    PyOpenDirectory/trunk/src/CDirectoryService.cpp
    PyOpenDirectory/trunk/src/CDirectoryService.h
    PyOpenDirectory/trunk/src/CFStringUtil.cpp
    PyOpenDirectory/trunk/src/CFStringUtil.h
    PyOpenDirectory/trunk/src/PythonWrapper.cpp
    PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/cyrusdaboo.mode1
    PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/cyrusdaboo.pbxuser
    PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/project.pbxproj
    PyOpenDirectory/trunk/support/test.cpp
    PyOpenDirectory/trunk/test.py

Added Paths:
-----------
    PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/cyrusdaboo.mode1v3

Modified: PyOpenDirectory/trunk/pysrc/dsattributes.py
===================================================================
--- PyOpenDirectory/trunk/pysrc/dsattributes.py	2007-01-05 16:57:13 UTC (rev 932)
+++ PyOpenDirectory/trunk/pysrc/dsattributes.py	2007-01-05 17:29:27 UTC (rev 933)
@@ -17,17 +17,1844 @@
 ##
 
 """
-Attribute names from Directory Service.
+Record types and attribute names from Directory Service.
+This comes directly (with C->Python conversion) from <DirectoryServices/DirServicesConst.h>
 """
 
-attrRealName             = "dsAttrTypeStandard:RealName"
-attrGUID                 = "dsAttrTypeStandard:GeneratedUID"
-attrLastModified         = "dsAttrTypeStandard:ModificationTimestamp"
-attrCalendarPrincipalURI = "dsAttrTypeStandard:CalendarPrincipalURI"
-attrGroupMembers         = "dsAttrTypeStandard:GroupMembers"
+# Specific Record Type Constants
 
-# Array indices for the attributes returned when listing records
-indexUID                  = 0
-indexGUID                 = 1
-indexLastModified         = 2
-indexCalendarPrincipalURI = 3
+"""
+ DirectoryService Specific Record Type Constants
+"""
+ 
+"""
+ kDSStdRecordTypeAccessControls
+  Record type that contains directory access control directives.
+"""
+kDSStdRecordTypeAccessControls = "dsRecTypeStandard:AccessControls"
+
+"""
+ kDSStdRecordTypeAFPServer
+  Record type of AFP server records.
+"""
+kDSStdRecordTypeAFPServer = "dsRecTypeStandard:AFPServer"
+
+"""
+ kDSStdRecordTypeAFPUserAliases
+  Record type of AFP user aliases used exclusively by AFP processes.
+"""
+kDSStdRecordTypeAFPUserAliases = "dsRecTypeStandard:AFPUserAliases"
+
+"""
+ kDSStdRecordTypeAliases
+  Used to represent alias records.
+"""
+kDSStdRecordTypeAliases = "dsRecTypeStandard:Aliases"
+
+"""
+ kDSStdRecordTypeAugments
+  Used to store augmented record data.
+"""
+kDSStdRecordTypeAugments = "dsRecTypeStandard:Augments"
+
+"""
+ kDSStdRecordTypeAutomount
+  Used to store automount record data.
+"""
+kDSStdRecordTypeAutomount = "dsRecTypeStandard:Automount"
+
+"""
+ kDSStdRecordTypeAutomountMap
+  Used to store automountMap record data.
+"""
+kDSStdRecordTypeAutomountMap = "dsRecTypeStandard:AutomountMap"
+
+"""
+ kDSStdRecordTypeAutoServerSetup
+  Used to discover automated server setup information.
+"""
+kDSStdRecordTypeAutoServerSetup = "dsRecTypeStandard:AutoServerSetup"
+
+"""
+ kDSStdRecordTypeBootp
+  Record in the local node for storing bootp info.
+"""
+kDSStdRecordTypeBootp = "dsRecTypeStandard:Bootp"
+
+"""
+ kDSStdRecordTypeCertificateAuthority
+  Record type that contains certificate authority information.
+"""
+kDSStdRecordTypeCertificateAuthorities = "dsRecTypeStandard:CertificateAuthorities"
+
+"""
+ kDSStdRecordTypeComputerLists
+  Identifies computer list records.
+"""
+kDSStdRecordTypeComputerLists = "dsRecTypeStandard:ComputerLists"
+
+"""
+ kDSStdRecordTypeComputerGroups
+  Identifies computer group records.
+"""
+kDSStdRecordTypeComputerGroups = "dsRecTypeStandard:ComputerGroups"
+
+"""
+ kDSStdRecordTypeComputers
+  Identifies computer records.
+"""
+kDSStdRecordTypeComputers = "dsRecTypeStandard:Computers"
+
+"""
+ kDSStdRecordTypeConfig
+  Identifies config records.
+"""
+kDSStdRecordTypeConfig = "dsRecTypeStandard:Config"
+
+"""
+ kDSStdRecordTypeEthernets
+  Record in the local node for storing ethernets.
+"""
+kDSStdRecordTypeEthernets = "dsRecTypeStandard:Ethernets"
+
+"""
+ kDSStdRecordTypeFileMakerServers
+  FileMaker servers record type. Describes available FileMaker servers, 
+  used for service discovery.
+"""
+kDSStdRecordTypeFileMakerServers = "dsRecTypeStandard:FileMakerServers"
+
+"""
+ kDSStdRecordTypeFTPServer
+  Identifies ftp server records.
+"""
+kDSStdRecordTypeFTPServer = "dsRecTypeStandard:FTPServer"
+
+"""
+ kDSStdRecordTypeGroupAliases
+  No longer supported in Mac OS X 10.4 or later.
+"""
+kDSStdRecordTypeGroupAliases = "dsRecTypeStandard:GroupAliases"
+
+"""
+ kDSStdRecordTypeGroups
+  Identifies group records.
+"""
+kDSStdRecordTypeGroups = "dsRecTypeStandard:Groups"
+
+"""
+ kDSStdRecordTypeHostServices
+  Record in the local node for storing host services.
+"""
+kDSStdRecordTypeHostServices = "dsRecTypeStandard:HostServices"
+
+"""
+ kDSStdRecordTypeHosts
+  Identifies host records.
+"""
+kDSStdRecordTypeHosts = "dsRecTypeStandard:Hosts"
+
+"""
+ kDSStdRecordTypeLDAPServer
+  Identifies LDAP server records.
+"""
+kDSStdRecordTypeLDAPServer = "dsRecTypeStandard:LDAPServer"
+
+"""
+ kDSStdRecordTypeLocations
+  Location record type.
+"""
+kDSStdRecordTypeLocations = "dsRecTypeStandard:Locations"
+
+"""
+ kDSStdRecordTypeMachines
+  Identifies machine records.
+"""
+kDSStdRecordTypeMachines = "dsRecTypeStandard:Machines"
+
+"""
+ kDSStdRecordTypeMeta
+  Identifies meta records.
+"""
+kDSStdRecordTypeMeta = "dsRecTypeStandard:AppleMetaRecord"
+
+"""
+ kDSStdRecordTypeMounts
+  Identifies mount records.
+"""
+kDSStdRecordTypeMounts = "dsRecTypeStandard:Mounts"
+
+"""
+ kDSStdRecordTypMounts
+  Supported only for backward compatibility to kDSStdRecordTypeMounts.
+"""
+kDSStdRecordTypMounts = "dsRecTypeStandard:Mounts"
+
+"""
+ kDSStdRecordTypeNeighborhoods
+  Neighborhood record type. Describes a list of computers and other
+  neighborhoods, used for network browsing.
+"""
+kDSStdRecordTypeNeighborhoods = "dsRecTypeStandard:Neighborhoods"
+
+"""
+ kDSStdRecordTypeNFS
+  Identifies NFS records.
+"""
+kDSStdRecordTypeNFS = "dsRecTypeStandard:NFS"
+
+"""
+ kDSStdRecordTypeNetDomains
+  Record in the local node for storing net domains.
+"""
+kDSStdRecordTypeNetDomains = "dsRecTypeStandard:NetDomains"
+
+"""
+ kDSStdRecordTypeNetGroups
+  Record in the local node for storing net groups.
+"""
+kDSStdRecordTypeNetGroups = "dsRecTypeStandard:NetGroups"
+
+"""
+ kDSStdRecordTypeNetworks
+  Identifies network records.
+"""
+kDSStdRecordTypeNetworks = "dsRecTypeStandard:Networks"
+
+"""
+ kDSStdRecordTypePasswordServer
+  Used to discover password servers via Bonjour.
+"""
+kDSStdRecordTypePasswordServer = "dsRecTypeStandard:PasswordServer"
+
+"""
+ kDSStdRecordTypePeople
+  Record type that contains "People" records used for contact information.
+"""
+kDSStdRecordTypePeople = "dsRecTypeStandard:People"
+
+"""
+ kDSStdRecordTypePresetComputers
+  The computer record type used for presets in record creation.
+"""
+kDSStdRecordTypePresetComputers = "dsRecTypeStandard:PresetComputers"
+
+"""
+ kDSStdRecordTypePresetComputerGroups
+  The computer group record type used for presets in record creation.
+"""
+kDSStdRecordTypePresetComputerGroups = "dsRecTypeStandard:PresetComputerGroups"
+
+"""
+ kDSStdRecordTypePresetComputerLists
+  The computer list record type used for presets in record creation.
+"""
+kDSStdRecordTypePresetComputerLists = "dsRecTypeStandard:PresetComputerLists"
+
+"""
+ kDSStdRecordTypePresetGroups
+  The group record type used for presets in record creation.
+"""
+kDSStdRecordTypePresetGroups = "dsRecTypeStandard:PresetGroups"
+
+"""
+ kDSStdRecordTypePresetUsers
+  The user record type used for presets in record creation.
+"""
+kDSStdRecordTypePresetUsers = "dsRecTypeStandard:PresetUsers"
+
+"""
+ kDSStdRecordTypePrintService
+  Identifies print service records.
+"""
+kDSStdRecordTypePrintService = "dsRecTypeStandard:PrintService"
+
+"""
+ kDSStdRecordTypePrintServiceUser
+  Record in the local node for storing quota usage for a user.
+"""
+kDSStdRecordTypePrintServiceUser = "dsRecTypeStandard:PrintServiceUser"
+
+"""
+ kDSStdRecordTypePrinters
+  Identifies printer records.
+"""
+kDSStdRecordTypePrinters = "dsRecTypeStandard:Printers"
+
+"""
+ kDSStdRecordTypeProtocols
+  Identifies protocol records.
+"""
+kDSStdRecordTypeProtocols = "dsRecTypeStandard:Protocols"
+
+"""
+ kDSStdRecordTypProtocols
+  Supported only for backward compatibility to kDSStdRecordTypeProtocols.
+"""
+kDSStdRecordTypProtocols = "dsRecTypeStandard:Protocols"
+
+"""
+ kDSStdRecordTypeQTSServer
+  Identifies quicktime streaming server records.
+"""
+kDSStdRecordTypeQTSServer = "dsRecTypeStandard:QTSServer"
+
+"""
+ kDSStdRecordTypeResources
+  Identifies resources used in group services.
+"""
+kDSStdRecordTypeResources = "dsRecTypeStandard:Resources"
+
+"""
+ kDSStdRecordTypeRPC
+  Identifies remote procedure call records.
+"""
+kDSStdRecordTypeRPC = "dsRecTypeStandard:RPC"
+
+"""
+ kDSStdRecordTypRPC
+  Supported only for backward compatibility to kDSStdRecordTypeRPC.
+"""
+kDSStdRecordTypRPC = "dsRecTypeStandard:RPC"
+
+"""
+ kDSStdRecordTypeSMBServer
+  Identifies SMB server records.
+"""
+kDSStdRecordTypeSMBServer = "dsRecTypeStandard:SMBServer"
+
+"""
+ kDSStdRecordTypeServer
+  Identifies generic server records.
+"""
+kDSStdRecordTypeServer = "dsRecTypeStandard:Server"
+
+"""
+ kDSStdRecordTypeServices
+  Identifies directory based service records.
+"""
+kDSStdRecordTypeServices = "dsRecTypeStandard:Services"
+
+"""
+ kDSStdRecordTypeSharePoints
+  Share point record type.
+"""
+kDSStdRecordTypeSharePoints = "dsRecTypeStandard:SharePoints"
+
+"""
+ kDSStdRecordTypeUserAliases
+  No longer supported in Mac OS X 10.4 or later.
+"""
+kDSStdRecordTypeUserAliases = "dsRecTypeStandard:UserAliases"
+
+"""
+ kDSStdRecordTypeUsers
+  Identifies user records.
+"""
+kDSStdRecordTypeUsers = "dsRecTypeStandard:Users"
+
+"""
+ kDSStdRecordTypeWebServer
+  Identifies web server records.
+"""
+kDSStdRecordTypeWebServer = "dsRecTypeStandard:WebServer"
+
+# Specific Attribute Type Constants
+
+
+"""
+ DirectoryService Specific Attribute Type Constants
+ As a guideline for the attribute types the following legend is used:
+
+        eDS1xxxxxx  Single Valued Attribute
+
+        eDSNxxxxxx  Multi-Valued Attribute
+
+    NOTE #1: Access controls may prevent any particular client from reading/writting
+            various attribute types.  In addition some attribute types may not be stored at
+            all and could also represent "real-time" data generated by the directory node
+            plug-in.
+
+    NOTE #2: Attributes in the model are available for records and directory nodes.
+"""
+ 
+
+# Single Valued Specific Attribute Type Constants
+
+
+"""
+ DirectoryService Single Valued Specific Attribute Type Constants
+"""
+
+"""
+    kDS1AttrAdminLimits
+    XML plist indicating what an admin user can edit.
+        Found in kDSStdRecordTypeUsers records.
+"""
+kDS1AttrAdminLimits = "dsAttrTypeStandard:AdminLimits"
+
+"""
+ kDS1AttrAliasData
+ Used to identify alias data.
+"""
+kDS1AttrAliasData = "dsAttrTypeStandard:AppleAliasData"
+
+"""
+ kDS1AttrAlternateDatastoreLocation
+ Unix path used for determining where a user's email is stored.
+"""
+kDS1AttrAlternateDatastoreLocation = "dsAttrTypeStandard:AlternateDatastoreLocation"
+
+"""
+ kDS1AttrAuthenticationHint
+ Used to identify the authentication hint phrase.
+"""
+kDS1AttrAuthenticationHint = "dsAttrTypeStandard:AuthenticationHint"
+
+"""
+ kDSNAttrAttributeTypes
+ Used to indicated recommended attribute types for a record type in the Config node.
+"""
+kDSNAttrAttributeTypes = "dsAttrTypeStandard:AttributeTypes"
+
+"""
+ kDS1AttrAuthorityRevocationList
+ Attribute containing the binary of the authority revocation list.
+ A certificate revocation list that defines certificate authority certificates
+ which are no longer trusted.  No user certificates are included in this list.
+ Usually found in kDSStdRecordTypeCertificateAuthority records.
+"""
+kDS1AttrAuthorityRevocationList = "dsAttrTypeStandard:AuthorityRevocationList"
+
+"""
+ kDS1AttrBirthday
+ Single-valued attribute that defines the user's birthday.
+ Format is x.208 standard YYYYMMDDHHMMSSZ which we will require as GMT time.
+"""
+kDS1AttrBirthday = "dsAttrTypeStandard:Birthday"
+
+
+"""
+ kDS1AttrBootFile
+ Attribute type in host or machine records for the name of the 
+        kernel that this machine will use by default when NetBooting.
+"""
+kDS1AttrBootFile = "dsAttrTypeStandard:BootFile"
+
+"""
+ kDS1AttrCACertificate
+ Attribute containing the binary of the certificate of a
+ certificate authority. Its corresponding private key is used to sign certificates.
+ Usually found in kDSStdRecordTypeCertificateAuthority records.
+"""
+kDS1AttrCACertificate = "dsAttrTypeStandard:CACertificate"
+
+"""
+ kDS1AttrCapabilities
+ Used with directory nodes so that clients can "discover" the
+ API capabilities for this Directory Node.
+"""
+kDS1AttrCapabilities = "dsAttrTypeStandard:Capabilities"
+
+"""
+ kDS1AttrCapacity
+ Attribute type for the capacity of a resource. 
+     found in resource records (kDSStdRecordTypeResources). 
+    Example: 50
+"""
+kDS1AttrCapacity = "dsAttrTypeStandard:Capacity"
+
+"""
+    kDS1AttrCategory
+    The category of an item used for browsing
+"""
+kDS1AttrCategory = "dsAttrTypeStandard:Category"
+
+"""
+ kDS1AttrCertificateRevocationList
+ Attribute containing the binary of the certificate revocation list.
+ This is a list of certificates which are no longer trusted.
+ Usually found in kDSStdRecordTypeCertificateAuthority records.
+"""
+kDS1AttrCertificateRevocationList = "dsAttrTypeStandard:CertificateRevocationList"
+
+"""
+ kDS1AttrChange
+ Retained for backward compatibility.
+"""
+kDS1AttrChange = "dsAttrTypeStandard:Change"
+
+"""
+ kDS1AttrComment
+ Attribute used for unformatted comment.
+"""
+kDS1AttrComment = "dsAttrTypeStandard:Comment"
+
+"""
+ kDS1AttrContactGUID
+ Attribute type for the contact GUID of a group. 
+     found in group records (kDSStdRecordTypeGroups). 
+"""
+kDS1AttrContactGUID = "dsAttrTypeStandard:ContactGUID"
+
+"""
+ kDS1AttrContactPerson
+ Attribute type for the contact person of the machine. 
+        Found in host or machine records.
+"""
+kDS1AttrContactPerson = "dsAttrTypeStandard:ContactPerson"
+
+"""
+ kDS1AttrCreationTimestamp
+ Attribute showing date/time of record creation.
+ Format is x.208 standard YYYYMMDDHHMMSSZ which we will require as GMT time.
+"""
+kDS1AttrCreationTimestamp = "dsAttrTypeStandard:CreationTimestamp"
+
+"""
+ kDS1AttrCrossCertificatePair
+ Attribute containing the binary of a pair of certificates which 
+ verify each other.  Both certificates have the same level of authority.
+ Usually found in kDSStdRecordTypeCertificateAuthority records.
+"""
+kDS1AttrCrossCertificatePair = "dsAttrTypeStandard:CrossCertificatePair"
+
+"""
+ kDS1AttrDataStamp
+ checksum/meta data
+"""
+kDS1AttrDataStamp = "dsAttrTypeStandard:DataStamp"
+
+"""
+ kDS1AttrDistinguishedName
+ Users distinguished or real name
+"""
+kDS1AttrDistinguishedName = "dsAttrTypeStandard:RealName"
+
+"""
+ kDS1AttrDNSDomain
+ DNS Resolver domain attribute.
+"""
+kDS1AttrDNSDomain = "dsAttrTypeStandard:DNSDomain"
+
+"""
+ kDS1AttrDNSNameServer
+ DNS Resolver nameserver attribute.
+"""
+kDS1AttrDNSNameServer = "dsAttrTypeStandard:DNSNameServer"
+
+"""
+ kDS1AttrENetAddress
+ Single-valued attribute for hardware Ethernet address (MAC address).
+        Found in machine records (kDSStdRecordTypeMachines) and computer records
+        (kDSStdRecordTypeComputers).
+"""
+kDS1AttrENetAddress = "dsAttrTypeStandard:ENetAddress"
+
+"""
+ kDS1AttrExpire
+ Used for expiration date or time depending on association.
+"""
+kDS1AttrExpire = "dsAttrTypeStandard:Expire"
+
+"""
+ kDS1AttrFirstName
+ Used for first name of user or person record.
+"""
+kDS1AttrFirstName = "dsAttrTypeStandard:FirstName"
+
+"""
+ kDS1AttrGeneratedUID
+ Used for 36 character (128 bit) unique ID. Usually found in user, 
+ group, and computer records. An example value is "A579E95E-CDFE-4EBC-B7E7-F2158562170F".
+ The standard format contains 32 hex characters and four hyphen characters.
+"""
+kDS1AttrGeneratedUID = "dsAttrTypeStandard:GeneratedUID"
+
+"""
+    kDS1AttrHomeDirectoryQuota
+    Represents the allowed usage for a user's home directory in bytes.
+        Found in user records (kDSStdRecordTypeUsers).
+"""
+kDS1AttrHomeDirectoryQuota = "dsAttrTypeStandard:HomeDirectoryQuota"
+
+"""
+ kDS1AttrHomeDirectorySoftQuota
+ Used to define home directory size limit in bytes when user is notified
+ that the hard limit is approaching.
+"""
+kDS1AttrHomeDirectorySoftQuota = "dsAttrTypeStandard:HomeDirectorySoftQuota"
+
+"""
+    kDS1AttrHomeLocOwner
+    Represents the owner of a workgroup's shared home directory.
+        Typically found in kDSStdRecordTypeGroups records.
+"""
+kDS1AttrHomeLocOwner = "dsAttrTypeStandard:HomeLocOwner"
+
+"""
+    kDS1StandardAttrHomeLocOwner
+    Retained for backward compatibility.
+"""
+kDS1StandardAttrHomeLocOwner = kDS1AttrHomeLocOwner
+
+"""
+ kDS1AttrInternetAlias
+ Used to track internet alias.
+"""
+kDS1AttrInternetAlias = "dsAttrTypeStandard:InetAlias"
+
+"""
+ kDS1AttrKDCConfigData
+ Contents of the kdc.conf file.
+"""
+kDS1AttrKDCConfigData = "dsAttrTypeStandard:KDCConfigData"
+
+"""
+ kDS1AttrLastName
+ Used for the last name of user or person record.
+"""
+kDS1AttrLastName = "dsAttrTypeStandard:LastName"
+
+"""
+ kDS1AttrLDAPSearchBaseSuffix
+ Search base suffix for a LDAP server.
+"""
+kDS1AttrLDAPSearchBaseSuffix = "dsAttrTypeStandard:LDAPSearchBaseSuffix"
+
+"""
+ kDS1AttrLocation
+ Represents the location a service is available from (usually domain name).
+     Typically found in service record types including kDSStdRecordTypeAFPServer,
+     kDSStdRecordTypeLDAPServer, and kDSStdRecordTypeWebServer.
+"""
+kDS1AttrLocation = "dsAttrTypeStandard:Location"
+
+"""
+ kDS1AttrMapGUID
+ Represents the GUID for a record's map.
+"""
+kDS1AttrMapGUID = "dsAttrTypeStandard:MapGUID"
+
+"""
+ kDS1AttrMCXFlags
+ Used by MCX.
+"""
+kDS1AttrMCXFlags = "dsAttrTypeStandard:MCXFlags"
+
+"""
+ kDS1AttrMCXSettings
+ Used by MCX.
+"""
+kDS1AttrMCXSettings = "dsAttrTypeStandard:MCXSettings"
+
+"""
+ kDS1AttrMailAttribute
+ Holds the mail account config data.
+"""
+kDS1AttrMailAttribute = "dsAttrTypeStandard:MailAttribute"
+
+"""
+ kDS1AttrMetaAutomountMap
+ Used to query for kDSStdRecordTypeAutomount entries associated with a specific 
+ kDSStdRecordTypeAutomountMap.
+"""
+kDS1AttrMetaAutomountMap = "dsAttrTypeStandard:MetaAutomountMap"
+
+"""
+ kDS1AttrMiddleName
+ Used for the middle name of user or person record.
+"""
+kDS1AttrMiddleName = "dsAttrTypeStandard:MiddleName"
+
+"""
+ kDS1AttrModificationTimestamp
+ Attribute showing date/time of record modification.
+ Format is x.208 standard YYYYMMDDHHMMSSZ which we will require as GMT time.
+"""
+kDS1AttrModificationTimestamp = "dsAttrTypeStandard:ModificationTimestamp"
+
+"""
+ kDSNAttrNeighborhoodAlias
+ Attribute type in Neighborhood records describing sub-neighborhood records.
+"""
+kDSNAttrNeighborhoodAlias = "dsAttrTypeStandard:NeighborhoodAlias"
+
+"""
+ kDS1AttrNeighborhoodType
+ Attribute type in Neighborhood records describing their function.
+"""
+kDS1AttrNeighborhoodType = "dsAttrTypeStandard:NeighborhoodType"
+
+"""
+ kDS1AttrNetworkView
+ The name of the managed network view a computer should use for browsing.
+"""
+kDS1AttrNetworkView = "dsAttrTypeStandard:NetworkView"
+
+"""
+ kDS1AttrNFSHomeDirectory
+ Defines a user's home directory mount point on the local machine.
+"""
+kDS1AttrNFSHomeDirectory = "dsAttrTypeStandard:NFSHomeDirectory"
+
+"""
+ kDS1AttrNote
+ Note attribute. Commonly used in printer records.
+"""
+kDS1AttrNote = "dsAttrTypeStandard:Note"
+
+"""
+ kDS1AttrOwner
+ Attribute type for the owner of a record. 
+        Typically the value is a LDAP distinguished name.
+"""
+kDS1AttrOwner = "dsAttrTypeStandard:Owner"
+
+"""
+ kDS1AttrOwnerGUID
+ Attribute type for the owner GUID of a group. 
+     found in group records (kDSStdRecordTypeGroups). 
+"""
+kDS1AttrOwnerGUID = "dsAttrTypeStandard:OwnerGUID"
+
+"""
+ kDS1AttrPassword
+ Holds the password or credential value.
+"""
+kDS1AttrPassword = "dsAttrTypeStandard:Password"
+
+"""
+ kDS1AttrPasswordPlus
+ Holds marker data to indicate possible authentication redirection.
+"""
+kDS1AttrPasswordPlus = "dsAttrTypeStandard:PasswordPlus"
+
+"""
+ kDS1AttrPasswordPolicyOptions
+ Collection of password policy options in single attribute.
+ Used in user presets record.
+"""
+kDS1AttrPasswordPolicyOptions = "dsAttrTypeStandard:PasswordPolicyOptions"
+
+"""
+ kDS1AttrPasswordServerList
+ Represents the attribute for storing the password server's replication information.
+"""
+kDS1AttrPasswordServerList = "dsAttrTypeStandard:PasswordServerList"
+
+"""
+    kDS1AttrPasswordServerLocation
+    Specifies the IP address or domain name of the Password Server associated
+        with a given directory node. Found in a config record named PasswordServer.
+"""
+kDS1AttrPasswordServerLocation = "dsAttrTypeStandard:PasswordServerLocation"
+
+"""
+ kDS1AttrPicture
+ Represents the path of the picture for each user displayed in the login window.
+ Found in user records (kDSStdRecordTypeUsers).
+"""
+kDS1AttrPicture = "dsAttrTypeStandard:Picture"
+
+"""
+ kDS1AttrPort
+ Represents the port number a service is available on.
+     Typically found in service record types including kDSStdRecordTypeAFPServer,
+     kDSStdRecordTypeLDAPServer, and kDSStdRecordTypeWebServer.
+"""
+kDS1AttrPort = "dsAttrTypeStandard:Port"
+
+"""
+    kDS1AttrPresetUserIsAdmin
+    Flag to indicate whether users created from this preset are administrators
+        by default. Found in kDSStdRecordTypePresetUsers records.
+"""
+kDS1AttrPresetUserIsAdmin = "dsAttrTypeStandard:PresetUserIsAdmin"
+
+"""
+ kDS1AttrPrimaryComputerGUID
+ Single-valued attribute that defines a primary computer of the computer group.  
+ added via extensible object for computer group record type (kDSStdRecordTypeComputerGroups)
+"""
+kDS1AttrPrimaryComputerGUID = "dsAttrTypeStandard:PrimaryComputerGUID"
+
+"""
+ kDS1AttrPrimaryComputerList
+ The GUID of the computer list with which this computer record is associated.
+"""
+kDS1AttrPrimaryComputerList = "dsAttrTypeStandard:PrimaryComputerList"
+
+"""
+ kDS1AttrPrimaryGroupID
+ This is the 32 bit unique ID that represents the primary group 
+ a user is part of, or the ID of a group. Format is a signed 32 bit integer
+ represented as a string.
+"""
+kDS1AttrPrimaryGroupID = "dsAttrTypeStandard:PrimaryGroupID"
+
+"""
+ kDS1AttrPrinter1284DeviceID
+ Single-valued attribute that defines the IEEE 1284 DeviceID of a printer.
+              This is used when configuring a printer.
+"""
+kDS1AttrPrinter1284DeviceID = "dsAttrTypeStandard:Printer1284DeviceID"
+
+"""
+ kDS1AttrPrinterLPRHost
+ Standard attribute type for kDSStdRecordTypePrinters.
+"""
+kDS1AttrPrinterLPRHost = "dsAttrTypeStandard:PrinterLPRHost"
+
+"""
+ kDS1AttrPrinterLPRQueue
+ Standard attribute type for kDSStdRecordTypePrinters.
+"""
+kDS1AttrPrinterLPRQueue = "dsAttrTypeStandard:PrinterLPRQueue"
+
+"""
+ kDS1AttrPrinterMakeAndModel
+ Single-valued attribute for definition of the Printer Make and Model.  An example
+              Value would be "HP LaserJet 2200".  This would be used to determine the proper PPD
+              file to be used when configuring a printer from the Directory.  This attribute
+              is based on the IPP Printing Specification RFC and IETF IPP-LDAP Printer Record.
+"""
+kDS1AttrPrinterMakeAndModel = "dsAttrTypeStandard:PrinterMakeAndModel"
+
+"""
+ kDS1AttrPrinterType
+ Standard attribute type for kDSStdRecordTypePrinters.
+"""
+kDS1AttrPrinterType = "dsAttrTypeStandard:PrinterType"
+
+"""
+ kDS1AttrPrinterURI
+ Single-valued attribute that defines the URI of a printer "ipp://address" or
+              "smb://server/queue".  This is used when configuring a printer. This attribute
+                is based on the IPP Printing Specification RFC and IETF IPP-LDAP Printer Record.
+"""
+kDS1AttrPrinterURI = "dsAttrTypeStandard:PrinterURI"
+
+"""
+ kDS1AttrPrinterXRISupported
+ Multi-valued attribute that defines additional URIs supported by a printer.
+              This is used when configuring a printer. This attribute is based on the IPP 
+                Printing Specification RFC and IETF IPP-LDAP Printer Record.
+"""
+kDSNAttrPrinterXRISupported = "dsAttrTypeStandard:PrinterXRISupported"
+
+"""
+ kDS1AttrPrintServiceInfoText
+ Standard attribute type for kDSStdRecordTypePrinters.
+"""
+kDS1AttrPrintServiceInfoText = "dsAttrTypeStandard:PrintServiceInfoText"
+
+"""
+ kDS1AttrPrintServiceInfoXML
+ Standard attribute type for kDSStdRecordTypePrinters.
+"""
+kDS1AttrPrintServiceInfoXML = "dsAttrTypeStandard:PrintServiceInfoXML"
+
+"""
+ kDS1AttrPrintServiceUserData
+ Single-valued attribute for print quota configuration or statistics
+        (XML data). Found in user records (kDSStdRecordTypeUsers) or print service
+        statistics records (kDSStdRecordTypePrintServiceUser).
+"""
+kDS1AttrPrintServiceUserData = "dsAttrTypeStandard:PrintServiceUserData"
+
+"""
+ kDS1AttrRealUserID
+ Used by MCX.
+"""
+kDS1AttrRealUserID = "dsAttrTypeStandard:RealUserID"
+
+"""
+ kDS1AttrRelativeDNPrefix
+ Used to map the first native LDAP attribute type required in the building of the
+  Relative Distinguished Name for LDAP record creation.
+"""
+kDS1AttrRelativeDNPrefix = "dsAttrTypeStandard:RelativeDNPrefix"
+
+"""
+ kDS1AttrSMBAcctFlags
+ Account control flag.
+"""
+kDS1AttrSMBAcctFlags = "dsAttrTypeStandard:SMBAccountFlags"
+
+"""
+ kDS1AttrSMBGroupRID
+ Constant for supporting PDC SMB interaction with DS.
+"""
+kDS1AttrSMBGroupRID = "dsAttrTypeStandard:SMBGroupRID"
+
+"""
+ kDS1AttrSMBHome
+ 
+     UNC address of Windows homedirectory mount point (\\server\\sharepoint).
+"""
+kDS1AttrSMBHome = "dsAttrTypeStandard:SMBHome"
+
+"""
+ kDS1AttrSMBHomeDrive
+ 
+     Drive letter for homedirectory mount point.
+"""
+kDS1AttrSMBHomeDrive = "dsAttrTypeStandard:SMBHomeDrive"
+
+"""
+ kDS1AttrSMBKickoffTime
+ Attribute in support of SMB interaction.
+"""
+kDS1AttrSMBKickoffTime = "dsAttrTypeStandard:SMBKickoffTime"
+
+"""
+ kDS1AttrSMBLogoffTime
+ Attribute in support of SMB interaction.
+"""
+kDS1AttrSMBLogoffTime = "dsAttrTypeStandard:SMBLogoffTime"
+
+"""
+ kDS1AttrSMBLogonTime
+ Attribute in support of SMB interaction.
+"""
+kDS1AttrSMBLogonTime = "dsAttrTypeStandard:SMBLogonTime"
+
+"""
+ kDS1AttrSMBPrimaryGroupSID
+ SMB Primary Group Security ID, stored as a string attribute of
+    up to 64 bytes. Found in user, group, and computer records
+    (kDSStdRecordTypeUsers, kDSStdRecordTypeGroups, kDSStdRecordTypeComputers).
+"""
+kDS1AttrSMBPrimaryGroupSID = "dsAttrTypeStandard:SMBPrimaryGroupSID"
+
+"""
+ kDS1AttrSMBPWDLastSet
+ Attribute in support of SMB interaction.
+"""
+kDS1AttrSMBPWDLastSet = "dsAttrTypeStandard:SMBPasswordLastSet"
+
+"""
+ kDS1AttrSMBProfilePath
+ Desktop management info (dock, desktop links, etc).
+"""
+kDS1AttrSMBProfilePath = "dsAttrTypeStandard:SMBProfilePath"
+
+"""
+ kDS1AttrSMBRID
+ Attribute in support of SMB interaction.
+"""
+kDS1AttrSMBRID = "dsAttrTypeStandard:SMBRID"
+
+"""
+ kDS1AttrSMBScriptPath
+ Login script path.
+"""
+kDS1AttrSMBScriptPath = "dsAttrTypeStandard:SMBScriptPath"
+
+"""
+ kDS1AttrSMBSID
+ SMB Security ID, stored as a string attribute of up to 64 bytes.
+    Found in user, group, and computer records (kDSStdRecordTypeUsers, 
+    kDSStdRecordTypeGroups, kDSStdRecordTypeComputers).
+"""
+kDS1AttrSMBSID = "dsAttrTypeStandard:SMBSID"
+
+"""
+ kDS1AttrSMBUserWorkstations
+ List of workstations user can login from (machine account names).
+"""
+kDS1AttrSMBUserWorkstations = "dsAttrTypeStandard:SMBUserWorkstations"
+
+"""
+ kDS1AttrServiceType
+ Represents the service type for the service.  This is the raw service type of the
+     service.  For example a service record type of kDSStdRecordTypeWebServer 
+     might have a service type of "http" or "https".
+"""
+kDS1AttrServiceType = "dsAttrTypeStandard:ServiceType"
+
+"""
+ kDS1AttrSetupAdvertising
+ Used for Setup Assistant automatic population.
+"""
+kDS1AttrSetupAdvertising = "dsAttrTypeStandard:SetupAssistantAdvertising"
+
+"""
+ kDS1AttrSetupAutoRegister
+ Used for Setup Assistant automatic population.
+"""
+kDS1AttrSetupAutoRegister = "dsAttrTypeStandard:SetupAssistantAutoRegister"
+
+"""
+ kDS1AttrSetupLocation
+ Used for Setup Assistant automatic population.
+"""
+kDS1AttrSetupLocation = "dsAttrTypeStandard:SetupAssistantLocation"
+
+"""
+ kDS1AttrSetupOccupation
+ Used for Setup Assistant automatic population.
+"""
+kDS1AttrSetupOccupation = "dsAttrTypeStandard:Occupation"
+
+"""
+ kDS1AttrTimeToLive
+ Attribute recommending how long to cache the record's attribute values.
+ Format is an unsigned 32 bit representing seconds. ie. 300 is 5 minutes.
+"""
+kDS1AttrTimeToLive = "dsAttrTypeStandard:TimeToLive"
+
+"""
+ kDS1AttrUniqueID
+ This is the 32 bit unique ID that represents the user in the legacy manner.
+ Format is a signed integer represented as a string.
+"""
+kDS1AttrUniqueID = "dsAttrTypeStandard:UniqueID"
+
+"""
+ kDS1AttrUserCertificate
+ Attribute containing the binary of the user's certificate.
+ Usually found in user records. The certificate is data which identifies a user.
+ This data is attested to by a known party, and can be independently verified 
+ by a third party.
+"""
+kDS1AttrUserCertificate = "dsAttrTypeStandard:UserCertificate"
+
+"""
+ kDS1AttrUserPKCS12Data
+ Attribute containing binary data in PKCS #12 format. 
+ Usually found in user records. The value can contain keys, certificates,
+ and other related information and is encrypted with a passphrase.
+"""
+kDS1AttrUserPKCS12Data = "dsAttrTypeStandard:UserPKCS12Data"
+
+"""
+ kDS1AttrUserShell
+ Used to represent the user's shell setting.
+"""
+kDS1AttrUserShell = "dsAttrTypeStandard:UserShell"
+
+"""
+ kDS1AttrUserSMIMECertificate
+ Attribute containing the binary of the user's SMIME certificate.
+ Usually found in user records. The certificate is data which identifies a user.
+ This data is attested to by a known party, and can be independently verified 
+ by a third party. SMIME certificates are often used for signed or encrypted
+ emails.
+"""
+kDS1AttrUserSMIMECertificate = "dsAttrTypeStandard:UserSMIMECertificate"
+
+"""
+ kDS1AttrVFSDumpFreq
+ Attribute used to support mount records.
+"""
+kDS1AttrVFSDumpFreq = "dsAttrTypeStandard:VFSDumpFreq"
+
+"""
+ kDS1AttrVFSLinkDir
+ Attribute used to support mount records.
+"""
+kDS1AttrVFSLinkDir = "dsAttrTypeStandard:VFSLinkDir"
+
+"""
+ kDS1AttrVFSPassNo
+ Attribute used to support mount records.
+"""
+kDS1AttrVFSPassNo = "dsAttrTypeStandard:VFSPassNo"
+
+"""
+ kDS1AttrVFSType
+ Attribute used to support mount records.
+"""
+kDS1AttrVFSType = "dsAttrTypeStandard:VFSType"
+
+"""
+ kDS1AttrWeblogURI
+ Single-valued attribute that defines the URI of a user's weblog.
+    Usually found in user records (kDSStdRecordTypeUsers). 
+    Example: http://example.com/blog/jsmith
+"""
+kDS1AttrWeblogURI = "dsAttrTypeStandard:WeblogURI"
+
+"""
+    kDS1AttrXMLPlist
+    SA config settings plist.
+"""
+kDS1AttrXMLPlist = "dsAttrTypeStandard:XMLPlist"
+
+"""
+ kDS1AttrProtocolNumber
+ Single-valued attribute that defines a protocol number.  Usually found
+  in protocol records (kDSStdRecordTypeProtocols)
+"""
+kDS1AttrProtocolNumber = "dsAttrTypeStandard:ProtocolNumber"
+
+"""
+ kDS1AttrRPCNumber
+ Single-valued attribute that defines an RPC number.  Usually found
+  in RPC records (kDSStdRecordTypeRPC)
+"""
+kDS1AttrRPCNumber = "dsAttrTypeStandard:RPCNumber"
+
+"""
+ kDS1AttrNetworkNumber
+ Single-valued attribute that defines a network number.  Usually found
+  in network records (kDSStdRecordTypeNetworks)
+"""
+kDS1AttrNetworkNumber = "dsAttrTypeStandard:NetworkNumber"
+
+
+# Multiple Valued Specific Attribute Type Constants
+
+
+"""
+ DirectoryService Multiple Valued Specific Attribute Type Constants
+"""
+
+"""
+ kDSNAttrAccessControlEntry
+ Attribute type which stores directory access control directives.
+"""
+kDSNAttrAccessControlEntry = "dsAttrTypeStandard:AccessControlEntry"
+
+"""
+ kDSNAttrAddressLine1
+ Line one of multiple lines of address data for a user.
+"""
+kDSNAttrAddressLine1 = "dsAttrTypeStandard:AddressLine1"
+
+"""
+ kDSNAttrAddressLine2
+ Line two of multiple lines of address data for a user.
+"""
+kDSNAttrAddressLine2 = "dsAttrTypeStandard:AddressLine2"
+
+"""
+ kDSNAttrAddressLine3
+ Line three of multiple lines of address data for a user.
+"""
+kDSNAttrAddressLine3 = "dsAttrTypeStandard:AddressLine3"
+
+"""
+ kDSNAttrAreaCode
+ Area code of a user's phone number.
+"""
+kDSNAttrAreaCode = "dsAttrTypeStandard:AreaCode"
+
+"""
+ kDSNAttrAuthenticationAuthority
+ Determines what mechanism is used to verify or set a user's password.
+     If multiple values are present, the first attributes returned take precedence.
+     Typically found in User records (kDSStdRecordTypeUsers).
+"""
+kDSNAttrAuthenticationAuthority = "dsAttrTypeStandard:AuthenticationAuthority"
+
+"""
+ kDSNAttrAutomountInformation
+ Used to store automount information in kDSStdRecordTypeAutomount records.
+"""
+kDSNAttrAutomountInformation = "dsAttrTypeStandard:AutomountInformation"
+
+"""
+ kDSNAttrBootParams
+ Attribute type in host or machine records for storing boot params.
+"""
+kDSNAttrBootParams = "dsAttrTypeStandard:BootParams"
+
+"""
+ kDSNAttrBuilding
+ Represents the building name for a user or person record.
+ Usually found in user or people records (kDSStdRecordTypeUsers or 
+ kDSStdRecordTypePeople).
+"""
+kDSNAttrBuilding = "dsAttrTypeStandard:Building"
+
+"""
+ kDSNAttrCalendarPrincipalURI
+ the URI for a record's calendar
+"""
+kDSNAttrCalendarPrincipalURI = "dsAttrTypeStandard:CalendarPrincipalURI"
+
+"""
+ kDSNAttrCity
+ Usually, city for a user or person record.
+ Usually found in user or people records (kDSStdRecordTypeUsers or 
+ kDSStdRecordTypePeople).
+"""
+kDSNAttrCity = "dsAttrTypeStandard:City"
+
+"""
+ kDSNAttrCompany
+ attribute that defines the user's company.
+ Example: Apple Computer, Inc
+"""
+kDSNAttrCompany = "dsAttrTypeStandard:Company"
+
+"""
+ kDSNAttrComputerAlias
+ Attribute type in Neighborhood records describing computer records pointed to by
+ this neighborhood.
+"""
+kDSNAttrComputerAlias = "dsAttrTypeStandard:ComputerAlias"
+
+"""
+ kDSNAttrComputers
+ List of computers.
+"""
+kDSNAttrComputers = "dsAttrTypeStandard:Computers"
+
+"""
+ kDSNAttrCountry
+ Represents country of a record entry.
+ Usually found in user or people records (kDSStdRecordTypeUsers or 
+ kDSStdRecordTypePeople).
+"""
+kDSNAttrCountry = "dsAttrTypeStandard:Country"
+
+"""
+ kDSNAttrDepartment
+ Represents the department name of a user or person.
+ Usually found in user or people records (kDSStdRecordTypeUsers or 
+ kDSStdRecordTypePeople).
+"""
+kDSNAttrDepartment = "dsAttrTypeStandard:Department"
+
+"""
+ kDSNAttrDNSName
+ Domain Name Service name.
+"""
+kDSNAttrDNSName = "dsAttrTypeStandard:DNSName"
+
+"""
+ kDSNAttrEMailAddress
+ Email address of usually a user record.
+"""
+kDSNAttrEMailAddress = "dsAttrTypeStandard:EMailAddress"
+
+"""
+ kDSNAttrEMailContacts
+ multi-valued attribute that defines a record's custom email addresses .
+     found in user records (kDSStdRecordTypeUsers). 
+    Example: home:johndoe at mymail.com
+"""
+kDSNAttrEMailContacts = "dsAttrTypeStandard:EMailContacts"
+
+"""
+ kDSNAttrFaxNumber
+ Represents the FAX numbers of a user or person.
+ Usually found in user or people records (kDSStdRecordTypeUsers or 
+ kDSStdRecordTypePeople).
+"""
+kDSNAttrFaxNumber = "dsAttrTypeStandard:FAXNumber"
+
+"""
+ kDSNAttrGroup
+ List of groups.
+"""
+kDSNAttrGroup = "dsAttrTypeStandard:Group"
+
+"""
+ kDSNAttrGroupMembers
+ Attribute type in group records containing lists of GUID values for members other than groups.
+"""
+kDSNAttrGroupMembers = "dsAttrTypeStandard:GroupMembers"
+
+"""
+ kDSNAttrGroupMembership
+ Usually a list of users that below to a given group record.
+"""
+kDSNAttrGroupMembership = "dsAttrTypeStandard:GroupMembership"
+
+"""
+ kDSNAttrGroupServices
+ xml-plist attribute that defines a group's services .
+     found in group records (kDSStdRecordTypeGroups). 
+"""
+kDSNAttrGroupServices = "dsAttrTypeStandard:GroupServices"
+
+"""
+ kDSNAttrHomePhoneNumber
+ Home telephone number of a user or person.
+"""
+kDSNAttrHomePhoneNumber = "dsAttrTypeStandard:HomePhoneNumber"
+
+"""
+ kDSNAttrHTML
+ HTML location.
+"""
+kDSNAttrHTML = "dsAttrTypeStandard:HTML"
+
+"""
+ kDSNAttrHomeDirectory
+ Network home directory URL.
+"""
+kDSNAttrHomeDirectory = "dsAttrTypeStandard:HomeDirectory"
+
+"""
+ kDSNAttrIMHandle
+ Represents the Instant Messaging handles of a user.
+ Values should be prefixed with the appropriate IM type
+ ie. AIM:, Jabber:, MSN:, Yahoo:, or ICQ:
+ Usually found in user records (kDSStdRecordTypeUsers).
+"""
+kDSNAttrIMHandle = "dsAttrTypeStandard:IMHandle"
+
+"""
+ kDSNAttrIPAddress
+ IP address expressed either as domain or IP notation.
+"""
+kDSNAttrIPAddress = "dsAttrTypeStandard:IPAddress"
+
+"""
+    kDSNAttrIPAddressAndENetAddress
+ A pairing of IPv4 or IPv6 addresses with Ethernet addresses 
+ (e.g., "10.1.1.1/00:16:cb:92:56:41").  Usually found on kDSStdRecordTypeComputers for use by 
+ services that need specific pairing of the two values.  This should be in addition to 
+ kDSNAttrIPAddress, kDSNAttrIPv6Address and kDS1AttrENetAddress. This is necessary because not
+ all directories return attribute values in a guaranteed order.
+"""
+kDSNAttrIPAddressAndENetAddress = "dsAttrTypeStandard:IPAddressAndENetAddress"
+
+"""
+ kDSNAttrIPv6Address
+ IPv6 address expressed in the standard notation (e.g., "fe80::236:caff:fcc2:5641" )
+ Usually found on kDSStdRecordTypeComputers, kDSStdRecordTypeHosts, and 
+ kDSStdRecordTypeMachines.
+"""
+kDSNAttrIPv6Address = "dsAttrTypeStandard:IPv6Address"
+
+"""
+ kDSNAttrJPEGPhoto
+ Used to store binary picture data in JPEG format. 
+ Usually found in user, people or group records (kDSStdRecordTypeUsers, 
+ kDSStdRecordTypePeople, kDSStdRecordTypeGroups).
+"""
+kDSNAttrJPEGPhoto = "dsAttrTypeStandard:JPEGPhoto"
+
+"""
+ kDSNAttrJobTitle
+ Represents the job title of a user.
+ Usually found in user or people records (kDSStdRecordTypeUsers or 
+ kDSStdRecordTypePeople).
+"""
+kDSNAttrJobTitle = "dsAttrTypeStandard:JobTitle"
+
+"""
+ kDSNAttrKDCAuthKey
+ KDC master key RSA encrypted with realm public key.
+"""
+kDSNAttrKDCAuthKey = "dsAttrTypeStandard:KDCAuthKey"
+
+"""
+    kDSNAttrKeywords
+    Keywords using for searching capability.
+"""
+kDSNAttrKeywords = "dsAttrTypeStandard:Keywords"
+
+"""
+ kDSNAttrLDAPReadReplicas
+ List of LDAP server URLs which can each be used to read directory data.
+"""
+kDSNAttrLDAPReadReplicas = "dsAttrTypeStandard:LDAPReadReplicas"
+
+"""
+ kDSNAttrLDAPWriteReplicas
+ List of LDAP server URLs which can each be used to write directory data.
+"""
+kDSNAttrLDAPWriteReplicas = "dsAttrTypeStandard:LDAPWriteReplicas"
+
+"""
+ kDSNAttrMachineServes
+ Attribute type in host or machine records for storing NetInfo 
+        domains served.
+"""
+kDSNAttrMachineServes = "dsAttrTypeStandard:MachineServes"
+
+"""
+ kDSNAttrMapCoordinates
+ attribute that defines coordinates for a user's location .
+*     found in user records (kDSStdRecordTypeUsers) and resource records (kDSStdRecordTypeResources).
+    Example: 7.7,10.6
+"""
+kDSNAttrMapCoordinates = "dsAttrTypeStandard:MapCoordinates"
+
+"""
+ kDSNAttrMapURI
+ attribute that defines the URI of a user's location.
+    Usually found in user records (kDSStdRecordTypeUsers). 
+    Example: http://example.com/bldg1
+"""
+kDSNAttrMapURI = "dsAttrTypeStandard:MapURI"
+
+"""
+ kDSNAttrMCXSettings
+ Used by MCX.
+"""
+kDSNAttrMCXSettings = "dsAttrTypeStandard:MCXSettings"
+
+"""
+ kDSNAttrMIME
+ Data contained in this attribute type is a fully qualified MIME Type. 
+"""
+kDSNAttrMIME = "dsAttrTypeStandard:MIME"
+
+"""
+ kDSNAttrMember
+ List of member records. 
+"""
+kDSNAttrMember = "dsAttrTypeStandard:Member"
+
+"""
+ kDSNAttrMobileNumber
+ Represents the mobile numbers of a user or person.
+ Usually found in user or people records (kDSStdRecordTypeUsers or 
+ kDSStdRecordTypePeople).
+"""
+kDSNAttrMobileNumber = "dsAttrTypeStandard:MobileNumber"
+
+"""
+ kDSNAttrNBPEntry
+ Appletalk data.
+"""
+kDSNAttrNBPEntry = "dsAttrTypeStandard:NBPEntry"
+
+"""
+ kDSNAttrNestedGroups
+ Attribute type in group records for the list of GUID values for nested groups.
+"""
+kDSNAttrNestedGroups = "dsAttrTypeStandard:NestedGroups"
+
+"""
+ kDSNAttrNetGroups
+ Attribute type that indicates which netgroups its record is a member of.
+        Found in user, host, and netdomain records.
+"""
+kDSNAttrNetGroups = "dsAttrTypeStandard:NetGroups"
+
+"""
+ kDSNAttrNickName
+ Represents the nickname of a user or person.
+ Usually found in user or people records (kDSStdRecordTypeUsers or 
+ kDSStdRecordTypePeople).
+"""
+kDSNAttrNickName = "dsAttrTypeStandard:NickName"
+
+"""
+ kDSNAttrNodePathXMLPlist
+ Attribute type in Neighborhood records describing the DS Node to search while
+ looking up aliases in this neighborhood.
+"""
+kDSNAttrNodePathXMLPlist = "dsAttrTypeStandard:NodePathXMLPlist"
+
+"""
+ kDSNAttrOrganizationInfo
+ Usually the organization info of a user.
+"""
+kDSNAttrOrganizationInfo = "dsAttrTypeStandard:OrganizationInfo"
+
+"""
+ kDSNAttrOrganizationName
+ Usually the organization of a user.
+"""
+kDSNAttrOrganizationName = "dsAttrTypeStandard:OrganizationName"
+
+"""
+ kDSNAttrPagerNumber
+ Represents the pager numbers of a user or person.
+ Usually found in user or people records (kDSStdRecordTypeUsers or 
+ kDSStdRecordTypePeople).
+"""
+kDSNAttrPagerNumber = "dsAttrTypeStandard:PagerNumber"
+
+"""
+ kDSNAttrPhoneContacts
+ multi-valued attribute that defines a record's custom phone numbers .
+     found in user records (kDSStdRecordTypeUsers). 
+    Example: home fax:408-555-4444
+"""
+kDSNAttrPhoneContacts = "dsAttrTypeStandard:PhoneContacts"
+
+
+"""
+ kDSNAttrPhoneNumber
+ Telephone number of a user.
+"""
+kDSNAttrPhoneNumber = "dsAttrTypeStandard:PhoneNumber"
+
+"""
+ kDSNAttrPGPPublicKey
+ Pretty Good Privacy public encryption key.
+"""
+kDSNAttrPGPPublicKey = "dsAttrTypeStandard:PGPPublicKey"
+
+"""
+ kDSNAttrPostalAddress
+ The postal address usually excluding postal code.
+"""
+kDSNAttrPostalAddress = "dsAttrTypeStandard:PostalAddress"
+
+"""
+* kDSNAttrPostalAddressContacts
+* multi-valued attribute that defines a record's alternate postal addresses .
+*     found in user records (kDSStdRecordTypeUsers) and resource records (kDSStdRecordTypeResources).
+"""
+kDSNAttrPostalAddressContacts = "dsAttrTypeStandard:PostalAddressContacts"
+
+"""
+ kDSNAttrPostalCode
+ The postal code such as zip code in the USA.
+"""
+kDSNAttrPostalCode = "dsAttrTypeStandard:PostalCode"
+
+"""
+ kDSNAttrNamePrefix
+ Represents the title prefix of a user or person.
+ ie. Mr., Ms., Mrs., Dr., etc.
+ Usually found in user or people records (kDSStdRecordTypeUsers or 
+ kDSStdRecordTypePeople).
+"""
+kDSNAttrNamePrefix = "dsAttrTypeStandard:NamePrefix"
+
+"""
+ kDSNAttrProtocols
+ List of protocols.
+"""
+kDSNAttrProtocols = "dsAttrTypeStandard:Protocols"
+
+"""
+ kDSNAttrRecordName
+ List of names/keys for this record.
+"""
+kDSNAttrRecordName = "dsAttrTypeStandard:RecordName"
+
+"""
+ kDSNAttrRelationships
+ multi-valued attribute that defines the relationship to the record type .
+     found in user records (kDSStdRecordTypeUsers). 
+    Example: brother:John
+"""
+kDSNAttrRelationships = "dsAttrTypeStandard:Relationships"
+
+"""
+* kDSNAttrResourceInfo
+* multi-valued attribute that defines a resource record's info.
+"""
+kDSNAttrResourceInfo = "dsAttrTypeStandard:ResourceInfo"
+
+"""
+ kDSNAttrResourceType
+ Attribute type for the kind of resource. 
+     found in resource records (kDSStdRecordTypeResources). 
+    Example: ConferenceRoom
+"""
+kDSNAttrResourceType = "dsAttrTypeStandard:ResourceType"
+
+"""
+ kDSNAttrState
+ The state or province of a country.
+"""
+kDSNAttrState = "dsAttrTypeStandard:State"
+
+"""
+ kDSNAttrStreet
+ Represents the street address of a user or person.
+ Usually found in user or people records (kDSStdRecordTypeUsers or 
+ kDSStdRecordTypePeople).
+"""
+kDSNAttrStreet = "dsAttrTypeStandard:Street"
+
+"""
+ kDSNAttrNameSuffix
+ Represents the name suffix of a user or person.
+ ie. Jr., Sr., etc.
+ Usually found in user or people records (kDSStdRecordTypeUsers or 
+ kDSStdRecordTypePeople).
+"""
+kDSNAttrNameSuffix = "dsAttrTypeStandard:NameSuffix"
+
+"""
+ kDSNAttrURL
+ List of URLs.
+"""
+kDSNAttrURL = "dsAttrTypeStandard:URL"
+
+"""
+ kDSNAttrURLForNSL
+ List of URLs used by NSL.
+"""
+kDSNAttrURLForNSL = "dsAttrTypeStandard:URLForNSL"
+
+"""
+ kDSNAttrVFSOpts
+ Used in support of mount records.
+"""
+kDSNAttrVFSOpts = "dsAttrTypeStandard:VFSOpts"
+
+
+
+# Other Attribute Type Constants
+
+
+"""
+ DirectoryService Other Attribute Type Constants Not Mapped by Directory Node Plugins
+ Mainly used internally by the DirectoryService Daemon or made available via dsGetDirNodeInfo()
+"""
+
+"""
+ kDS1AttrAdminStatus
+ Retained only for backward compatibility.
+"""
+kDS1AttrAdminStatus = "dsAttrTypeStandard:AdminStatus"
+
+"""
+ kDS1AttrAlias
+ Alias attribute, contain pointer to another node/record/attribute.
+"""
+kDS1AttrAlias = "dsAttrTypeStandard:Alias"
+
+"""
+ kDS1AttrAuthCredential
+ An "auth" credential, to be used to authenticate to other Directory nodes.
+"""
+kDS1AttrAuthCredential = "dsAttrTypeStandard:AuthCredential"
+
+"""
+ kDS1AttrCopyTimestamp
+ Timestamp used in local account caching.
+"""
+kDS1AttrCopyTimestamp = "dsAttrTypeStandard:CopyTimestamp"
+
+"""
+    kDS1AttrDateRecordCreated
+    Date of record creation.
+"""
+kDS1AttrDateRecordCreated = "dsAttrTypeStandard:DateRecordCreated"
+
+"""
+ kDS1AttrKerberosRealm
+ Supports Kerberized SMB Server services.
+"""
+kDS1AttrKerberosRealm = "dsAttrTypeStandard:KerberosRealm"
+
+"""
+ kDS1AttrNTDomainComputerAccount
+ Supports Kerberized SMB Server services.
+"""
+kDS1AttrNTDomainComputerAccount = "dsAttrTypeStandard:NTDomainComputerAccount"
+
+"""
+ kDSNAttrOriginalHomeDirectory
+ Home directory URL used in local account caching.
+"""
+kDSNAttrOriginalHomeDirectory = "dsAttrTypeStandard:OriginalHomeDirectory"
+
+"""
+ kDS1AttrOriginalNFSHomeDirectory
+ NFS home directory used in local account caching.
+"""
+kDS1AttrOriginalNFSHomeDirectory = "dsAttrTypeStandard:OriginalNFSHomeDirectory"
+
+"""
+ kDS1AttrOriginalNodeName
+ Nodename used in local account caching.
+"""
+kDS1AttrOriginalNodeName = "dsAttrTypeStandard:OriginalNodeName"
+
+"""
+ kDS1AttrPrimaryNTDomain
+ Supports Kerberized SMB Server services.
+"""
+kDS1AttrPrimaryNTDomain = "dsAttrTypeStandard:PrimaryNTDomain"
+
+"""
+ kDS1AttrPwdAgingPolicy
+ Contains the password aging policy data for an authentication capable record.
+"""
+kDS1AttrPwdAgingPolicy = "dsAttrTypeStandard:PwdAgingPolicy"
+
+"""
+ kDS1AttrRARA
+ Retained only for backward compatibility.
+"""
+kDS1AttrRARA = "dsAttrTypeStandard:RARA"
+
+"""
+ kDS1AttrReadOnlyNode
+ Can be found using dsGetDirNodeInfo and will return one of
+ ReadOnly, ReadWrite, or WriteOnly strings.
+ Note that ReadWrite does not imply fully readable or writable
+"""
+kDS1AttrReadOnlyNode = "dsAttrTypeStandard:ReadOnlyNode"
+
+"""
+ kDS1AttrRecordImage
+ A binary image of the record and all it's attributes.
+ Has never been supported.
+"""
+kDS1AttrRecordImage = "dsAttrTypeStandard:RecordImage"
+
+"""
+ kDS1AttrSMBGroupRID
+ Attributefor supporting PDC SMB interaction.
+"""
+kDS1AttrSMBGroupRID = "dsAttrTypeStandard:SMBGroupRID"
+
+"""
+ kDS1AttrTimePackage
+ Data of Create, Modify, Backup time in UTC.
+"""
+kDS1AttrTimePackage = "dsAttrTypeStandard:TimePackage"
+
+"""
+ kDS1AttrTotalSize
+ checksum/meta data.
+"""
+kDS1AttrTotalSize = "dsAttrTypeStandard:TotalSize"
+
+"""
+ kDSNAttrAllNames
+ Backward compatibility only - all possible names for a record.
+ Has never been supported.
+"""
+kDSNAttrAllNames = "dsAttrTypeStandard:AllNames"
+
+"""
+ kDSNAttrAuthMethod
+ Authentication method for an authentication capable record.
+"""
+kDSNAttrAuthMethod = "dsAttrTypeStandard:AuthMethod"
+
+"""
+ kDSNAttrMetaNodeLocation
+ Meta attribute returning registered node name by directory node plugin.
+"""
+kDSNAttrMetaNodeLocation = "dsAttrTypeStandard:AppleMetaNodeLocation"
+
+"""
+ kDSNAttrNodePath
+ Sub strings of a Directory Service Node given in order.
+"""
+kDSNAttrNodePath = "dsAttrTypeStandard:NodePath"
+
+"""
+ kDSNAttrPlugInInfo
+ Information (version, signature, about, credits, etc.) about the plug-in
+ that is actually servicing a particular directory node.
+ Has never been supported.
+"""
+kDSNAttrPlugInInfo = "dsAttrTypeStandard:PlugInInfo"
+
+"""
+ kDSNAttrRecordAlias
+ No longer supported in Mac OS X 10.4 or later.
+"""
+kDSNAttrRecordAlias = "dsAttrTypeStandard:RecordAlias"
+
+"""
+ kDSNAttrRecordType
+ Single Valued for a Record, Multi-valued for a Directory Node.
+"""
+kDSNAttrRecordType = "dsAttrTypeStandard:RecordType"
+
+"""
+ kDSNAttrSchema
+ List of attribute types.
+"""
+kDSNAttrSchema = "dsAttrTypeStandard:Scheama"
+
+"""
+ kDSNAttrSetPasswdMethod
+ Retained only for backward compatibility.
+"""
+kDSNAttrSetPasswdMethod = "dsAttrTypeStandard:SetPasswdMethod"
+
+"""
+ kDSNAttrSubNodes
+ Attribute of a node which lists the available subnodes
+        of that node.
+"""
+kDSNAttrSubNodes = "dsAttrTypeStandard:SubNodes"
+
+"""
+ kStandardSourceAlias
+ No longer supported in Mac OS X 10.4 or later.
+"""
+kStandardSourceAlias = "dsAttrTypeStandard:AppleMetaAliasSource"
+
+"""
+ kStandardTargetAlias
+ No longer supported in Mac OS X 10.4 or later.
+"""
+kStandardTargetAlias = "dsAttrTypeStandard:AppleMetaAliasTarget"
+
+"""
+ kDSNAttrNetGroupTriplet
+ Multivalued attribute that defines the host, user and domain triplet combinations
+  to support NetGroups.  Each attribute value is comma separated string to maintain the
+  triplet (e.g., host,user,domain).
+"""
+kDSNAttrNetGroupTriplet = "dsAttrTypeStandard:NetGroupTriplet"
+
+
+# Search Node attribute type Constants
+
+
+"""
+ Search Node attribute type Constants
+"""
+ 
+"""
+ kDS1AttrSearchPath
+ Search path used by the search node.
+"""
+kDS1AttrSearchPath = "dsAttrTypeStandard:SearchPath"
+
+"""
+ kDSNAttrSearchPath
+ Retained only for backward compatibility.
+"""
+kDSNAttrSearchPath = "dsAttrTypeStandard:SearchPath"
+
+"""
+ kDS1AttrSearchPolicy
+ Search policy for the search node.
+"""
+kDS1AttrSearchPolicy = "dsAttrTypeStandard:SearchPolicy"
+
+"""
+ kDS1AttrNSPSearchPath
+ Automatic search path defined by the search node.
+"""
+kDS1AttrNSPSearchPath = "dsAttrTypeStandard:NSPSearchPath"
+
+"""
+ kDSNAttrNSPSearchPath
+ Retained only for backward compatibility.
+"""
+kDSNAttrNSPSearchPath = "dsAttrTypeStandard:NSPSearchPath"
+
+"""
+ kDS1AttrLSPSearchPath
+ Local only search path defined by the search node.
+"""
+kDS1AttrLSPSearchPath = "dsAttrTypeStandard:LSPSearchPath"
+
+"""
+ kDSNAttrLSPSearchPath
+ Retained only for backward compatibility.
+"""
+kDSNAttrLSPSearchPath = "dsAttrTypeStandard:LSPSearchPath"
+
+"""
+ kDS1AttrCSPSearchPath
+ Admin user configured custom search path defined by the search node.
+"""
+kDS1AttrCSPSearchPath = "dsAttrTypeStandard:CSPSearchPath"
+
+"""
+ kDSNAttrCSPSearchPath
+ Retained only for backward compatibility.
+"""
+kDSNAttrCSPSearchPath = "dsAttrTypeStandard:CSPSearchPath"
+

Modified: PyOpenDirectory/trunk/pysrc/opendirectory.py
===================================================================
--- PyOpenDirectory/trunk/pysrc/opendirectory.py	2007-01-05 16:57:13 UTC (rev 932)
+++ PyOpenDirectory/trunk/pysrc/opendirectory.py	2007-01-05 17:29:27 UTC (rev 933)
@@ -29,99 +29,40 @@
         C{None} on failure.
     """
 
-def listUsers(obj):
+def listAllRecordsWithAttributes(obj, recordType, attributes):
     """
-    List users in Open Directory, and return key attributes for each user.
-    The attributes in the tuple are (uid, guid, last-modified, calendar-principal-uri).
+    List records in Open Directory, and return key attributes for each one.
     
     @param obj: C{object} the object obtained from an odInit call.
-    @return: C{list} containing a C{tuple} of C{str} for each user found,
-        or C{None} on failure.
+    @param recordType: C{str} containing the OD record type to lookup.
+    @param attributes: C{list} 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.
     """
 
-def listGroups(obj):
+def authenticateUserBasic(obj, user, pswd):
     """
-    List groups in Open Directory, and return key attributes for each group.
-    The attributes in the tuple are (uid, guid, last-modified, calendar-principal-uri).
+    Authenticate a user with a password to Open Directory.
     
     @param obj: C{object} the object obtained from an odInit call.
-    @return: C{list} containg a C{tuple} of C{str} for each group found,
-        or C{None} on failure.
+    @param user: C{str} container the user to check.
+    @param pswd: C{str} containing the password to check.
+    @return: C{True} if the user was found, C{False} otherwise.
     """
 
-def listResources(obj):
+def authenticateUserDigest(obj, user, challenge, response, method):
     """
-    List resources in Open Directory, and return key attributes for each resource.
-    The attributes in the tuple are (uid, guid, last-modified, calendar-principal-uri).
+    Authenticate using HTTP Digest credentials to Open Directory.
     
     @param obj: C{object} the object obtained from an odInit call.
-    @return: C{list} containg a C{tuple} of C{str} for each resource found,
-        or C{None} on failure.
-    """
-
-def checkUser(obj, user):
-    """
-    Check that a user exists in Open Directory.
-    
-    @param obj: C{object} the object obtained from an odInit call.
-    @param user: C{str} containing the user to check.
+    @param user: C{str} container the user to check.
+    @param challenge: C{str} the HTTP challenge sent to the client.
+    @param response: C{str} the HTTP response sent from the client.
+    @param method: C{str} the HTTP method being used.
     @return: C{True} if the user was found, C{False} otherwise.
     """
 
-def checkGroup(obj, group):
+class ODError(exception):
     """
-    Check that a group exists in Open Directory.
-    
-    @param obj: C{object} the object obtained from an odInit call.
-    @param group: C{str} containing the group to check.
-    @return: C{True} if the group was found, C{False} otherwise.
+    Exceptions from DirectoryServices errors.
     """
-
-def checkResource(obj, resource):
-    """
-    Check that a resource exists in Open Directory.
-    
-    @param obj: C{object} the object obtained from an odInit call.
-    @param resource: C{str} containing the resource to check.
-    @return: C{True} if the resource was found, C{False} otherwise.
-    """
-
-def listUsersWithAttributes(obj, user):
-    """
-    Get user attributes relevant to CalDAV from Open Directory.
-    
-    @param obj: C{object} the object obtained from an odInit call.
-    @param users: C{list} containing C{str}'s for each user to get attributes for.
-    @return: C{dict} containing a C{dict} of attributes for each requested user, 
-        or C{None} otherwise.
-    """
-
-def listGroupsWithAttributes(obj, grp):
-    """
-    Get group attributes relevant to CalDAV from Open Directory.
-    
-    @param obj: C{object} the object obtained from an odInit call.
-    @param grp: C{str} containing the group to get attributes for.
-    @return: C{dict} containing a C{dict} of attributes for each requested group, 
-        or C{None} otherwise.
-    """
-
-def listResourcesWithAttributes(obj, rsrc):
-    """
-    Get resource attributes relevant to CalDAV from Open Directory.
-    
-    @param obj: C{object} the object obtained from an odInit call.
-    @param rsrc: C{str} containing the resource to get attributes for.
-    @return: C{dict} containing a C{dict} of attributes for each requested resource, 
-        or C{None} otherwise.
-    """
-
-def authenticateUser(obj, user, pswd):
-    """
-    Authenticate a user with a password to Open Directory.
-    
-    @param obj: C{object} the object obtained from an odInit call.
-    @param user: C{str} container the user to check.
-    @param pswd: C{str} containing the password to check.
-    @return: C{True} if the user was found, C{False} otherwise.
-    """

Modified: PyOpenDirectory/trunk/src/CDirectoryService.cpp
===================================================================
--- PyOpenDirectory/trunk/src/CDirectoryService.cpp	2007-01-05 16:57:13 UTC (rev 932)
+++ PyOpenDirectory/trunk/src/CDirectoryService.cpp	2007-01-05 17:29:27 UTC (rev 933)
@@ -23,10 +23,14 @@
 
 #include "CFStringUtil.h"
 
+#include <Python.h>
+
 #include <stdlib.h>
 #include <string.h>
 #include <memory>
 
+extern PyObject* ODException_class;
+
 # define ThrowIfDSErr(x) { long dirStatus = x; if (dirStatus != eDSNoErr) throw dirStatus; }
 # define ThrowIfNULL(x) { if (x == NULL) throw -1L; }
 
@@ -46,6 +50,7 @@
 	mDir = 0L;
 	mNode = 0L;
 	mData = NULL;
+	mDataSize = 0;
 }
 
 CDirectoryService::~CDirectoryService()
@@ -74,534 +79,102 @@
 	mNodeName = NULL;
 }
 
-// ListUsers
+// ListAllRecordsWithAttributes
 // 
-// List all users in the directory returning a list consisting of elements that contain attribute values
-// for each user. The attributes are in order: uid, guid, last-modified, calendar-principal-uri.
+// Get specific attributes for one or more user records in the directory.
 //
-// @return: CFMutableArrayRef composed of values which are CFMutableArrayRef which contain CFStringRef for each attribute,
+// @param recordType: the record type to list.
+// @param attributes: CFArray of CFString listing the attributes to return for each record.
+// @return: CFMutableDictionaryRef composed of 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::ListUsers()
+CFMutableDictionaryRef CDirectoryService::ListAllRecordsWithAttributes(const char* recordType, CFArrayRef attributes)
 {
 	try
 	{
-		return ListRecords(kDSStdRecordTypeUsers);
+		// Get attribute map
+		return _ListAllRecordsWithAttributes(recordType, NULL, attributes);
 	}
-	catch(...)
+	catch(long dserror)
 	{
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices Error", dserror));		
 		return NULL;
 	}
-}
-
-// ListGroups
-// 
-// List all groups in the directory returning a list consisting of elements that contain attribute values
-// for each group. The attributes are in order: uid, guid, last-modified, calendar-principal-uri.
-//
-// @return: CFMutableArrayRef composed of values which are CFMutableArrayRef which contain CFStringRef for each attribute,
-//		    or NULL if it fails.
-//
-CFMutableArrayRef CDirectoryService::ListGroups()
-{
-	try
-	{
-		return ListRecords(kDSStdRecordTypeGroups);
-	}
 	catch(...)
 	{
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "Unknown Error", -1));		
 		return NULL;
 	}
 }
 
-// ListResources
+// AuthenticateUserBasic
 // 
-// List all resources in the directory returning a list consisting of elements that contain attribute values
-// for each resource. The attributes are in order: uid, guid, last-modified, calendar-principal-uri.
+// Authenticate a user to the directory using plain text credentials.
 //
-// @return: CFMutableArrayRef composed of values which are CFMutableArrayRef which contain CFStringRef for each attribute,
-//		    or NULL if it fails.
-//
-CFMutableArrayRef CDirectoryService::ListResources()
-{
-	try
-	{
-		return ListRecords(kDSStdRecordTypeResources);
-	}
-	catch(...)
-	{
-		return NULL;
-	}
-}
-
-// CheckUser
-// 
-// Check whether the specified user exists in the directory.
-//
 // @param user: the uid of the user.
-// @return: true if user is found, false otherwise.
+// @param pswd: the plain text password to authenticate with.
+// @return: true if authentication succeeds, false otherwise.
 //
-bool CDirectoryService::CheckUser(const char* user)
+bool CDirectoryService::AuthenticateUserBasic(const char* user, const char* pswd, bool& result)
 {
 	try
 	{
-		return HasRecord(kDSStdRecordTypeUsers, user);
+		result = NativeAuthenticationBasic(user, pswd);
+		return true;
 	}
-	catch(...)
+	catch(long dserror)
 	{
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices Error", dserror));		
 		return false;
 	}
-}
-
-// CheckGroup
-// 
-// Check whether the specified group exists in the directory.
-//
-// @param user: the uid of the group.
-// @return: true if group is found, false otherwise.
-//
-bool CDirectoryService::CheckGroup(const char* grp)
-{
-	try
-	{
-		return HasRecord(kDSStdRecordTypeGroups, grp);
-	}
 	catch(...)
 	{
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "Unknown Error", -1));		
 		return false;
 	}
 }
 
-// CheckResource
+// AuthenticateUserDigest
 // 
-// Check whether the specified resource exists in the directory.
+// Authenticate a user to the directory using HTTP DIGEST credentials.
 //
-// @param user: the uid of the resource.
-// @return: true if resource is found, false otherwise.
+// @param challenge: HTTP challenge sent by server.
+// @param response: HTTP response sent by client.
+// @return: true if authentication succeeds, false otherwise.
 //
-bool CDirectoryService::CheckResource(const char* rsrc)
+bool CDirectoryService::AuthenticateUserDigest(const char* user, const char* challenge, const char* response, const char* method, bool& result)
 {
 	try
 	{
-		return HasRecord(kDSStdRecordTypeResources, rsrc);
+		result = NativeAuthenticationDigest(user, challenge, response, method);
+		return true;
 	}
-	catch(...)
+	catch(long dserror)
 	{
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices Error", dserror));		
 		return false;
 	}
-}
-
-
-// Set of attributes to be looked up for a user record.
-CFStringRef userattrs[] = {
-	CFSTR(kDS1AttrDistinguishedName),
-	CFSTR(kDS1AttrGeneratedUID),
-	CFSTR(kDS1AttrModificationTimestamp),
-	CFSTR(kDS1AttrCalendarPrincipalURI),
-	NULL};
-
-// ListUsersWithAttributes
-// 
-// Get specific attributes for one or more user records in the directory.
-//
-// @param users: a list of uids of the users.
-// @return: CFMutableDictionaryRef composed of CFMutableDictionaryRef of CFStringRef key and value entries
-//			for each attribute/value requested in the record indexed by uid,
-//		    or NULL if it fails.
-//
-CFMutableDictionaryRef CDirectoryService::ListUsersWithAttributes(CFArrayRef users)
-{
-	CFMutableDictionaryRef result = NULL;
-	CFMutableArrayRef attrs = NULL;
-	try
-	{
-		// Build array of required attributes
-		attrs = ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-		if (attrs == NULL)
-			throw -1L;
-		CFStringRef* str = userattrs;
-		while(*str != NULL)
-			::CFArrayAppendValue(attrs, *str++);
-		
-		// Get attribute map
-		result = ListRecordsWithAttributes(kDSStdRecordTypeUsers, users, attrs);
-		::CFRelease(attrs);
-		return result;
-	}
 	catch(...)
 	{
-		if (attrs != NULL)
-			::CFRelease(attrs);
-		return NULL;
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "Unknown Error", -1));		
+		return false;
 	}
 }
 
-// Set of attributes to be looked up for a group record.
-CFStringRef grpattrs[] = {
-	CFSTR(kDS1AttrDistinguishedName),
-	CFSTR(kDS1AttrGeneratedUID),
-	CFSTR(kDS1AttrModificationTimestamp),
-	CFSTR(kDS1AttrCalendarPrincipalURI),
-	CFSTR(kDSNAttrGroupMembers),
-	NULL};
-
-// ListGroupsWithAttributes
-// 
-// Get specific attributes for one or more group records in the directory.
-//
-// @param grps: a list of uids of the groups.
-// @return: CFMutableDictionaryRef composed of CFMutableDictionaryRef of CFStringRef key and value entries
-//			for each attribute/value requested in the record indexed by uid,
-//		    or NULL if it fails.
-//
-CFMutableDictionaryRef CDirectoryService::ListGroupsWithAttributes(CFArrayRef grps)
-{
-	CFMutableDictionaryRef result = NULL;
-	CFMutableArrayRef attrs = NULL;
-	try
-	{
-		// Build array of required attributes
-		attrs = ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-		if (attrs == NULL)
-			throw -1L;
-		CFStringRef* str = grpattrs;
-		while(*str != NULL)
-			::CFArrayAppendValue(attrs, *str++);
-		
-		// Get attribute map
-		result = ListRecordsWithAttributes(kDSStdRecordTypeGroups, grps, attrs);
-		::CFRelease(attrs);
-		return result;
-	}
-	catch(...)
-	{
-		if (attrs != NULL)
-			::CFRelease(attrs);
-		return NULL;
-	}
-}
-
-// Set of attributes to be looked up for a resource record.
-CFStringRef rsrcattrs[] = {
-	CFSTR(kDS1AttrDistinguishedName),
-	CFSTR(kDS1AttrGeneratedUID),
-	CFSTR(kDS1AttrModificationTimestamp),
-	CFSTR(kDS1AttrCalendarPrincipalURI),
-	NULL};
-
-// ListResourcesWithAttributes
-// 
-// Get specific attributes for one or more resource records in the directory.
-//
-// @param rsrc: a list of uids of the resources.
-// @return: CFMutableDictionaryRef composed of CFMutableDictionaryRef of CFStringRef key and value entries
-//			for each attribute/value requested in the record indexed by uid,
-//		    or NULL if it fails.
-//
-CFMutableDictionaryRef CDirectoryService::ListResourcesWithAttributes(CFArrayRef rsrcs)
-{
-	CFMutableDictionaryRef result = NULL;
-	CFMutableArrayRef attrs = NULL;
-	try
-	{
-		// Build array of required attributes
-		attrs = ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-		if (attrs == NULL)
-			throw -1L;
-		CFStringRef* str = rsrcattrs;
-		while(*str != NULL)
-			::CFArrayAppendValue(attrs, *str++);
-		
-		// Get attribute map
-		result = ListRecordsWithAttributes(kDSStdRecordTypeResources, rsrcs, attrs);
-		::CFRelease(attrs);
-		return result;
-	}
-	catch(...)
-	{
-		if (attrs != NULL)
-			::CFRelease(attrs);
-		return NULL;
-	}
-}
-
-// AuthenticateUser
-// 
-// Authenticate a user to the directory.
-//
-// @param user: the uid of the user.
-// @param pswd: the plain text password to authenticate with.
-// @return: true if authentication succeeds, false otherwise.
-//
-bool CDirectoryService::AuthenticateUser(const char* user, const char* pswd)
-{
-	try
-{
-	return NativeAuthentication(user, pswd);
-}
-catch(...)
-{
-	return false;
-}
-}
-
 #pragma mark -----Private API
 
-// ListRecords
+// _ListAllRecordsWithAttributes
 // 
-// List all records of the specified type in the directory returning a list consisting of elements that contain attribute values
-// for each user. The attributes are in order: uid, guid, last-modified, calendar-principal-uri.
-//
-// @return: CFMutableArrayRef composed of values which are CFMutableArrayRef which contain CFStringRef for each attribute,
-//          or NULL if it fails.
-//
-CFMutableArrayRef CDirectoryService::ListRecords(const char* type)
-{
-	CFMutableArrayRef result = NULL;
-	CFMutableArrayRef vresult = NULL;
-	tDataListPtr recNames = NULL;
-	tDataListPtr recTypes = NULL;
-	tDataListPtr attrTypes = NULL;
-	tContextData context = NULL;
-	tAttributeListRef attrListRef = 0L;
-	tRecordEntry* pRecEntry = NULL;
-	
-	try
-	{
-		// Make sure we have a valid directory service
-		OpenService();
-		
-		// Open the node we want to query
-		OpenNode();
-
-		// We need a buffer for what comes next
-		CreateBuffer();
-		
-		result = ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-		
-		recNames = ::dsDataListAllocate(mDir);
-		ThrowIfNULL(recNames);
-		recTypes = ::dsDataListAllocate(mDir);
-		ThrowIfNULL(recTypes);
-		attrTypes = ::dsDataListAllocate(mDir);
-		ThrowIfNULL(attrTypes);
-		ThrowIfDSErr(::dsBuildListFromStringsAlloc(mDir, recNames,  kDSRecordsAll, NULL));
-		ThrowIfDSErr(::dsBuildListFromStringsAlloc(mDir, recTypes,  type, NULL));
-		ThrowIfDSErr(::dsBuildListFromStringsAlloc(mDir, attrTypes,  kDS1AttrGeneratedUID, kDS1AttrModificationTimestamp, kDS1AttrCalendarPrincipalURI, NULL));
-
-		do
-		{
-			// List all the appropriate records
-			unsigned long recCount = 0;
-			ThrowIfDSErr(::dsGetRecordList(mNode, mData, recNames, eDSExact, recTypes, attrTypes, false, &recCount, &context));
-			for(unsigned long i = 1; i <= recCount; i++)
-			{
-				// Get the record entry
-				ThrowIfDSErr(::dsGetRecordEntry(mNode, mData, i, &attrListRef, &pRecEntry));
-
-				// Get the entry's name
-				char* temp = NULL;
-				ThrowIfDSErr(::dsGetRecordNameFromEntry(pRecEntry, &temp));
-				std::auto_ptr<char> recname(temp);
-
-				// Create an array for the values
-				vresult = ::CFArrayCreateMutable(kCFAllocatorDefault, 4, &kCFTypeArrayCallBacks);
-				for(unsigned long j = 0; j < 4; j++)
-				{
-					CFStringUtil strvalue("");
-					::CFArrayAppendValue(vresult, strvalue.get());
-				}
-
-				// Build a CFString from this name and add to results
-				CFStringUtil str(recname.get());
-				::CFArraySetValueAtIndex(vresult, 0, str.get());
-				
-				// Look at each requested attribute and get one value
-				for(unsigned long j = 1; j <= pRecEntry->fRecordAttributeCount; j++)
-				{
-					tAttributeValueListRef attributeValueListRef = 0L;
-					tAttributeEntryPtr attributeInfoPtr = NULL;
-
-					ThrowIfDSErr(::dsGetAttributeEntry(mNode, mData, attrListRef, j, &attributeValueListRef, &attributeInfoPtr));
-					
-					if (attributeInfoPtr->fAttributeValueCount > 0)
-					{
-						// Determine what the attribute is and where in the result list it should be put
-						std::auto_ptr<char> attrname(CStringFromBuffer(&attributeInfoPtr->fAttributeSignature));
-						unsigned long attrindex = 0xFFFFFFFF;
-						if (::strcmp(attrname.get(), kDS1AttrGeneratedUID) == 0)
-							attrindex = 1;
-						else if (::strcmp(attrname.get(), kDS1AttrModificationTimestamp) == 0)
-							attrindex = 2;
-						else if (::strcmp(attrname.get(), kDS1AttrCalendarPrincipalURI) == 0)
-							attrindex = 3;
-							
-						// Get the attribute value and store in results
-						tAttributeValueEntryPtr attributeValue = NULL;
-						ThrowIfDSErr(::dsGetAttributeValue(mNode, mData, 1, attributeValueListRef, &attributeValue));
-						std::auto_ptr<char> data(CStringFromBuffer(&attributeValue->fAttributeValueData));
-						CFStringUtil strvalue(data.get());
-						::CFArraySetValueAtIndex(vresult, attrindex, strvalue.get());
-						::dsDeallocAttributeValueEntry(mDir, attributeValue);
-						attributeValue = NULL;
-					}
-
-					::dsCloseAttributeValueList(attributeValueListRef);
-					attributeValueListRef = NULL;
-					::dsDeallocAttributeEntry(mDir, attributeInfoPtr);
-					attributeInfoPtr = NULL;
-				}
-
-				// Add array of values to result array
-				::CFArrayAppendValue(result, vresult);
-				::CFRelease(vresult);
-				vresult = NULL;
-
-				// Clean-up
-				::dsCloseAttributeList(attrListRef);
-				attrListRef = 0L;
-				::dsDeallocRecordEntry(mDir, pRecEntry);
-				pRecEntry = NULL;
-			}
-		} while (context != NULL); // Loop until all data has been obtained.
-
-		// Cleanup
-		::dsDataListDeallocate(mDir, recNames);
-		::dsDataListDeallocate(mDir, recTypes);
-		::dsDataListDeallocate(mDir, attrTypes);
-		free(recNames);
-		free(recTypes);
-		free(attrTypes);
-		RemoveBuffer();
-		CloseNode();
-		CloseService();
-	}
-	catch(...)
-	{
-		// Cleanup
-		if (context != NULL)
-			::dsReleaseContinueData(mDir, context);
-		if (attrListRef != 0L)
-			::dsCloseAttributeList(attrListRef);
-		if (pRecEntry != NULL)
-			dsDeallocRecordEntry(mDir, pRecEntry);
-		if (recNames != NULL)
-		{
-			::dsDataListDeallocate(mDir, recNames);
-			free(recNames);
-			recNames = NULL;
-		}
-		if (recTypes != NULL)
-		{
-			::dsDataListDeallocate(mDir, recTypes);
-			free(recTypes);
-			recTypes = NULL;
-		}
-		if (attrTypes != NULL)
-		{
-			::dsDataListDeallocate(mDir, attrTypes);
-			free(attrTypes);
-			attrTypes = NULL;
-		}
-		
-		RemoveBuffer();
-		CloseNode();
-		CloseService();
-	
-		if (vresult != NULL)
-		{
-			::CFRelease(vresult);
-			vresult = NULL;
-		}
-		if (result != NULL)
-		{
-			::CFRelease(result);
-			result = NULL;
-		}
-		throw;
-	}
-
-	return result;
-}
-
-// HasRecord
-// 
-// Check whether the specified record with the specified type exists in the directory.
-//
-// @param type: the record type to check.
-// @param name: the uid of the record to check.
-// @return: true if record is found, false otherwise.
-//
-bool CDirectoryService::HasRecord(const char* type, const char* name)
-{
-	bool result = false;
-	tDataNodePtr recName = NULL;
-    tDataNodePtr recType = NULL;
-	tRecordReference recRef = NULL;
-
-	try
-	{
-		// Make sure we have a valid directory service
-		OpenService();
-		
-		// Open the node we want to query
-		OpenNode();
-		
-		recName = ::dsDataNodeAllocateString(mDir, name);
-		if (recName == NULL)
-			throw eDSBadDataNodeLength;
-		recType = ::dsDataNodeAllocateString(mDir, type);
-		if (recType == NULL)
-			throw eDSBadDataNodeLength;
-		
-		long dirStatus = ::dsOpenRecord(mNode, recType, recName, &recRef);
-		if (dirStatus == eDSNoErr)
-		{
-			result = true;
-			::dsCloseRecord(recRef);
-			recRef = NULL;
-		}
-		else if (dirStatus == eDSRecordNotFound)
-			result = false;
-		else
-			throw dirStatus;
-		
-		// Cleanup
-		::dsDataNodeDeAllocate(mDir, recType);
-		recType = NULL;
-		::dsDataNodeDeAllocate(mDir, recName);
-		recName = NULL;
-		CloseNode();
-		CloseService();
-	}
-	catch(...)
-	{
-		// Cleanup
-		if (recType != NULL)
-			::dsDataNodeDeAllocate(mDir, recType);
-		if (recName != NULL)
-			::dsDataNodeDeAllocate(mDir, recName);
-		CloseNode();
-		CloseService();
-		
-		throw;
-	}
-	
-	return result;
-}
-
-// ListRecordsWithAttributes
-// 
 // Get specific attributes for records of a specified type in the directory.
 //
 // @param type: the record type to check.
-// @param names: the uids of the records to check.
 // @param attrs: a list of attributes to return.
 // @return: CFMutableDictionaryRef composed of CFMutableDictionaryRef of CFStringRef key and value entries
 //			for each attribute/value requested in the record indexed by uid,
 //		    or NULL if it fails.
 //
-CFMutableDictionaryRef CDirectoryService::ListRecordsWithAttributes(const char* type, CFArrayRef names, CFArrayRef attrs)
+CFMutableDictionaryRef CDirectoryService::_ListAllRecordsWithAttributes(const char* type, CFArrayRef names, CFArrayRef attrs)
 {
 	CFMutableDictionaryRef result = NULL;
 	CFMutableDictionaryRef vresult = NULL;
@@ -613,8 +186,8 @@
 	tAttributeListRef attrListRef = 0L;
 	tRecordEntry* pRecEntry = NULL;
 	
-	// Must have names and attributes
-	if ((::CFArrayGetCount(names) == 0) || (::CFArrayGetCount(attrs) == 0))
+	// Must have attributes
+	if (::CFArrayGetCount(attrs) == 0)
 		return NULL;
 
 	try
@@ -631,8 +204,12 @@
 		// Build data list of names
 		recNames = ::dsDataListAllocate(mDir);
 		ThrowIfNULL(recNames);
-		BuildStringDataList(names, recNames);
-		
+		if (names != NULL)
+			BuildStringDataList(names, recNames);
+		else
+			ThrowIfDSErr(::dsBuildListFromStringsAlloc(mDir, recNames,  kDSRecordsAll, NULL));
+
+		// Build data list of types
 		recTypes = ::dsDataListAllocate(mDir);
 		ThrowIfNULL(recTypes);
 		ThrowIfDSErr(::dsBuildListFromStringsAlloc(mDir, recTypes,  type, NULL));
@@ -648,7 +225,14 @@
 		{
 			// List all the appropriate records
 			unsigned long recCount = 0;
-			ThrowIfDSErr(::dsGetRecordList(mNode, mData, recNames, eDSExact, recTypes, attrTypes, false, &recCount, &context));
+			tDirStatus err;
+			do
+			{
+				err = ::dsGetRecordList(mNode, mData, recNames, eDSExact, recTypes, attrTypes, false, &recCount, &context);
+				if (err == eDSBufferTooSmall)
+					ReallocBuffer();
+			} while(err == eDSBufferTooSmall);
+			ThrowIfDSErr(err);
 			for(unsigned long i = 1; i <= recCount; i++)
 			{
 				// Get the record entry
@@ -739,7 +323,7 @@
 		CloseNode();
 		CloseService();
 	}
-	catch(...)
+	catch(long dsStatus)
 	{
 		// Cleanup
 		if (context != NULL)
@@ -791,19 +375,19 @@
 	return result;
 }
 
-// NativeAuthentication
+// AuthenticationGetNode
 // 
 // Authenticate a user to the directory.
 //
 // @param user: the uid of the user.
-// @param pswd: the plain text password to authenticate with.
-// @return: true if authentication succeeds, false otherwise.
+// @return: CFStringUtil for node name.
 //
-bool CDirectoryService::NativeAuthentication(const char* user, const char* pswd)
+CFStringRef CDirectoryService::AuthenticationGetNode(const char* user)
 {
 	// We need to find the 'native' node for the specifies user as the current node
 	// made not support this user's authentication directly.
-	
+	CFStringRef result = NULL;
+
 	CFMutableArrayRef users = ::CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
 	CFStringUtil cfuser(user);
 	::CFArrayAppendValue(users, cfuser.get());
@@ -813,50 +397,70 @@
 	::CFArrayAppendValue(attrs, cfattr.get());
 	
 	// First list the record for the current user and get its node.
-	CFMutableDictionaryRef found = ListRecordsWithAttributes(kDSStdRecordTypeUsers, users, attrs);
+	CFMutableDictionaryRef found = _ListAllRecordsWithAttributes(kDSStdRecordTypeUsers, users, attrs);
 	::CFRelease(users);
 	::CFRelease(attrs);
 	if (found == NULL)
-		return false;
+		return result;
 
 	// Now extract the returned data.
 	CFDictionaryRef dictvalue = (CFDictionaryRef)CFDictionaryGetValue(found, cfuser.get());
 	if ((dictvalue == NULL) || (::CFDictionaryGetCount(dictvalue) == 0))
 	{
 		::CFRelease(found);
-		return false;
+		return result;
 	}
 	const void* value = ::CFDictionaryGetValue(dictvalue, cfattr.get());
 
 	// The dictionary value may be a string or a list
-	CFStringRef strvalue = NULL;
 	if (::CFGetTypeID((CFTypeRef)value) == ::CFStringGetTypeID())
 	{
-		strvalue = (CFStringRef)value;
+		result = (CFStringRef)value;
 	}
 	else if(::CFGetTypeID((CFTypeRef)value) == ::CFArrayGetTypeID())
 	{
 		CFArrayRef arrayvalue = (CFArrayRef)value;
 		if (::CFArrayGetCount(arrayvalue) == 0)
-			return false;
-		strvalue = (CFStringRef)CFArrayGetValueAtIndex(arrayvalue, 0);
+			return result;
+		result = (CFStringRef)CFArrayGetValueAtIndex(arrayvalue, 0);
 	}
 
-	CFStringUtil cfvalue(strvalue);
+	::CFRetain(result);
 	::CFRelease(found);
-	return NativeAuthenticationToNode(cfvalue.temp_str(), user, pswd);
+	return result;
 }
 
-// NativeAuthenticationToNode
+// NativeAuthenticationBasic
 // 
 // Authenticate a user to the directory.
 //
+// @param user: the uid of the user.
+// @param pswd: the plain text password to authenticate with.
+// @return: true if authentication succeeds, false otherwise.
+//
+bool CDirectoryService::NativeAuthenticationBasic(const char* user, const char* pswd)
+{
+	// We need to find the 'native' node for the specifies user as the current node
+	// made not support this user's authentication directly.
+	
+	CFStringRef result = AuthenticationGetNode(user);
+	if (result == NULL)
+		return false;
+	CFStringUtil cfvalue(result);
+	::CFRelease(result);
+	return NativeAuthenticationBasicToNode(cfvalue.temp_str(), user, pswd);
+}
+
+// NativeAuthenticationBasicToNode
+// 
+// Authenticate a user to the directory.
+//
 // @param nodename: the node to authenticate to.
 // @param user: the uid of the user.
 // @param pswd: the plain text password to authenticate with.
 // @return: true if authentication succeeds, false otherwise.
 //
-bool CDirectoryService::NativeAuthenticationToNode(const char* nodename, const char* user, const char* pswd)
+bool CDirectoryService::NativeAuthenticationBasicToNode(const char* nodename, const char* user, const char* pswd)
 {	
 	bool result = false;
 	tDirNodeReference node = 0L;
@@ -875,8 +479,7 @@
 		CreateBuffer();
 
 		// First, specify the type of authentication.
-		authType = ::dsDataNodeAllocateString(mDir, kDSStdAuthNodeNativeClearTextOK);
-		/* authType = ::dsDataNodeAllocate(mDir, kDSStdAuthNodeNativeNoClearText); */
+		authType = ::dsDataNodeAllocateString(mDir, kDSStdAuthClearText);
 
 		// Build input data
 		//  Native authentication is a one step authentication scheme.
@@ -942,6 +545,143 @@
     return result;
 }
 
+// NativeAuthenticationDigest
+// 
+// Authenticate a user to the directory.
+//
+// @param user: the uid of the user.
+// @param challenge: the server challenge.
+// @param response: the client response.
+// @param method: the HTTP method.
+// @return: true if authentication succeeds, false otherwise.
+//
+bool CDirectoryService::NativeAuthenticationDigest(const char* user, const char* challenge, const char* response, const char* method)
+{
+	// We need to find the 'native' node for the specifies user as the current node
+	// made not support this user's authentication directly.
+	
+	CFStringRef result = AuthenticationGetNode(user);
+	if (result == NULL)
+		return false;
+	CFStringUtil cfvalue(result);
+	::CFRelease(result);
+	return NativeAuthenticationDigestToNode(cfvalue.temp_str(), user, challenge, response, method);
+}
+
+// NativeAuthenticationDigestToNode
+// 
+// Authenticate a user to the directory.
+//
+// @param nodename: the node to authenticate to.
+// @param user: the uid of the user.
+// @param challenge: the server challenge.
+// @param response: the client response.
+// @param method: the HTTP method.
+// @return: true if authentication succeeds, false otherwise.
+//
+bool CDirectoryService::NativeAuthenticationDigestToNode(const char* nodename, const char* user,
+														 const char* challenge, const char* response, const char* method)
+{	
+	bool result = false;
+	tDirNodeReference node = 0L;
+    tDataNodePtr authType = NULL;
+    tDataBufferPtr authData = NULL;
+    tContextData context = NULL;
+	
+	try
+	{
+		// Make sure we have a valid directory service
+		OpenService();
+		
+		// Open the node we want to query
+		node = OpenNamedNode(nodename);
+		
+		CreateBuffer();
+
+		// First, specify the type of authentication.
+		authType = ::dsDataNodeAllocateString(mDir, kDSStdAuthDIGEST_MD5);
+
+		// Build input data
+		//  Native authentication is a one step authentication scheme.
+		//  Step 1
+		//      Send: <length><user>
+		//			  <length><challenge>
+		//            <length><response>
+		//			  <length><method>
+		//   Receive: success or failure.
+		long aDataBufSize = sizeof(long) + ::strlen(user) +
+							sizeof(long) + ::strlen(challenge) +
+							sizeof(long) + ::strlen(response) +
+							sizeof(long) + ::strlen(method);
+		authData = ::dsDataBufferAllocate(mDir, aDataBufSize);
+		if (authData == NULL)
+			throw eDSNullDataBuff;
+		long aCurLength = 0;
+		long aTempLength = ::strlen(user);
+		::memcpy(&(authData->fBufferData[aCurLength]), &aTempLength,  sizeof(long));
+		aCurLength += sizeof(long);
+
+		::memcpy(&(authData->fBufferData[aCurLength]), user,  aTempLength);
+		aCurLength += aTempLength;
+
+		aTempLength = ::strlen(challenge);
+		::memcpy(&(authData->fBufferData[aCurLength]), &aTempLength,  sizeof(long));
+		aCurLength += sizeof(long);
+
+		::memcpy(&(authData->fBufferData[aCurLength]), challenge,  aTempLength);
+		
+		aTempLength = ::strlen(response);
+		::memcpy(&(authData->fBufferData[aCurLength]), &aTempLength,  sizeof(long));
+		aCurLength += sizeof(long);
+
+		::memcpy(&(authData->fBufferData[aCurLength]), response,  aTempLength);
+		
+		aTempLength = ::strlen(method);
+		::memcpy(&(authData->fBufferData[aCurLength]), &aTempLength,  sizeof(long));
+		aCurLength += sizeof(long);
+
+		::memcpy(&(authData->fBufferData[aCurLength]), method,  aTempLength);
+		
+		authData->fBufferLength = aDataBufSize;
+		
+		// Do authentication
+		long dirStatus = ::dsDoDirNodeAuth(node, authType, true,  authData,  mData, &context);
+		result = (dirStatus == eDSNoErr);
+		
+		// Cleanup
+		::dsDataBufferDeAllocate(mDir, authData);
+		authData = NULL;
+		::dsDataNodeDeAllocate(mDir, authType);
+		authType = NULL;
+		RemoveBuffer();
+		if (node != 0L)
+		{
+			::dsCloseDirNode(node);
+			node = 0L;
+		}
+		CloseService();
+	}
+	catch(...)
+	{
+		// Cleanup
+		if (authData != NULL)
+			::dsDataBufferDeAllocate(mDir, authData);
+		if (authType != NULL)
+			::dsDataNodeDeAllocate(mDir, authType);
+		RemoveBuffer();
+		if (node != 0L)
+		{
+			::dsCloseDirNode(node);
+			node = 0L;
+		}
+		CloseService();
+		
+		throw;
+	}
+
+    return result;
+}
+
 // OpenService
 // 
 // Open the directory service.
@@ -1059,6 +799,7 @@
 		{
 			throw eDSNullDataBuff;
 		}
+		mDataSize = cBufferSize;
 	}
 }
 
@@ -1075,6 +816,21 @@
 	}
 }
 
+// ReallocBuffer
+// 
+// Destroy the data buffer, then re-create with double previous size.
+//
+void CDirectoryService::ReallocBuffer()
+{
+	RemoveBuffer();
+	mData = ::dsDataBufferAllocate(mDir, 2 * mDataSize);
+	if (mData == NULL)
+	{
+		throw eDSNullDataBuff;
+	}
+	mDataSize *= 2;
+}
+
 void CDirectoryService::BuildStringDataList(CFArrayRef strs, tDataListPtr data)
 {
 	CFStringUtil add_cfname((CFStringRef)::CFArrayGetValueAtIndex(strs, 0));

Modified: PyOpenDirectory/trunk/src/CDirectoryService.h
===================================================================
--- PyOpenDirectory/trunk/src/CDirectoryService.h	2007-01-05 16:57:13 UTC (rev 932)
+++ PyOpenDirectory/trunk/src/CDirectoryService.h	2007-01-05 17:29:27 UTC (rev 933)
@@ -24,39 +24,33 @@
 #include <CoreFoundation/CoreFoundation.h>
 #include <DirectoryService/DirectoryService.h>
 
+class CFStringUtil;
+
 class CDirectoryService
 {
 public:
 	CDirectoryService(const char* nodename);
 	~CDirectoryService();
 	
-	CFMutableArrayRef ListUsers();
-	CFMutableArrayRef ListGroups();
-	CFMutableArrayRef ListResources();
-	
-	bool CheckUser(const char* user);
-	bool CheckGroup(const char* grp);
-	bool CheckResource(const char* rsrc);
-	
-	CFMutableDictionaryRef ListUsersWithAttributes(CFArrayRef users);
-	CFMutableDictionaryRef ListGroupsWithAttributes(CFArrayRef grps);
-	CFMutableDictionaryRef ListResourcesWithAttributes(CFArrayRef rsrcs);
+	CFMutableDictionaryRef ListAllRecordsWithAttributes(const char* recordType, CFArrayRef attributes);
 
-	bool AuthenticateUser(const char* user, const char* pswd);
+	bool AuthenticateUserBasic(const char* user, const char* pswd, bool& result);
+	bool AuthenticateUserDigest(const char* user, const char* challenge, const char* response, const char* method, bool& result);
 	
 private:
 	const char*			mNodeName;
 	tDirReference		mDir;
 	tDirNodeReference	mNode;
 	tDataBufferPtr		mData;
+	UInt32				mDataSize;
 	
-	CFMutableArrayRef ListRecords(const char* type);
-	CFMutableDictionaryRef ListRecordsWithAttributes(const char* type, CFArrayRef names, CFArrayRef attrs);
+	CFMutableDictionaryRef _ListAllRecordsWithAttributes(const char* type, CFArrayRef names, CFArrayRef attrs);
 
-	bool HasRecord(const char* type, const char* name);
-
-	bool NativeAuthentication(const char* user, const char* pswd);
-	bool NativeAuthenticationToNode(const char* nodename, const char* user, const char* pswd);
+	CFStringRef CDirectoryService::AuthenticationGetNode(const char* user);
+	bool NativeAuthenticationBasic(const char* user, const char* pswd);
+	bool NativeAuthenticationBasicToNode(const char* nodename, const char* user, const char* pswd);
+	bool NativeAuthenticationDigest(const char* user, const char* challenge, const char* response, const char* method);
+	bool NativeAuthenticationDigestToNode(const char* nodename, const char* user, const char* challenge, const char* response, const char* method);
 	
 	void OpenService();
 	void CloseService();
@@ -67,6 +61,7 @@
 	
 	void CreateBuffer();
 	void RemoveBuffer();
+	void ReallocBuffer();
 
 	void BuildStringDataList(CFArrayRef strs, tDataListPtr data);
 

Modified: PyOpenDirectory/trunk/src/CFStringUtil.cpp
===================================================================
--- PyOpenDirectory/trunk/src/CFStringUtil.cpp	2007-01-05 16:57:13 UTC (rev 932)
+++ PyOpenDirectory/trunk/src/CFStringUtil.cpp	2007-01-05 17:29:27 UTC (rev 933)
@@ -56,6 +56,17 @@
 	}
 }
 
+CFStringUtil& CFStringUtil::operator=(const CFStringUtil& copy)
+{
+	mRef = copy.get();
+	if (mRef != NULL)
+		::CFRetain(mRef);
+	mTemp = NULL;
+	
+	return *this;
+}
+
+
 // Return a new c-string from the CFString data.
 //
 // @return: c-string created from CFString - this must be deallocated (free) by caller.

Modified: PyOpenDirectory/trunk/src/CFStringUtil.h
===================================================================
--- PyOpenDirectory/trunk/src/CFStringUtil.h	2007-01-05 16:57:13 UTC (rev 932)
+++ PyOpenDirectory/trunk/src/CFStringUtil.h	2007-01-05 17:29:27 UTC (rev 933)
@@ -29,6 +29,8 @@
 	CFStringUtil(CFStringRef ref);
 	~CFStringUtil();
 	
+	CFStringUtil& operator=(const CFStringUtil& copy);
+
 	CFStringRef get() const
 	{
 		return mRef;

Modified: PyOpenDirectory/trunk/src/PythonWrapper.cpp
===================================================================
--- PyOpenDirectory/trunk/src/PythonWrapper.cpp	2007-01-05 16:57:13 UTC (rev 932)
+++ PyOpenDirectory/trunk/src/PythonWrapper.cpp	2007-01-05 17:29:27 UTC (rev 933)
@@ -118,6 +118,42 @@
 }
 
 // Utility function - not exposed to Python
+static CFDictionaryRef PyDictToCFDictionary(PyObject* dict)
+{
+	CFMutableDictionaryRef result = CFDictionaryCreateMutable(kCFAllocatorDefault, PyDict_Size(dict), &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
+	PyObject* key;
+	PyObject* value;
+	int pos = 0;
+	
+	while (PyDict_Next(dict, &pos, &key, &value))
+	{
+		if ((key == NULL) || !PyString_Check(key) ||
+			(value == NULL) || !PyString_Check(value))
+		{
+			CFRelease(result);
+			return NULL;
+		}
+		const char* ckey = PyString_AsString(key);
+		if (ckey == NULL)
+		{
+			CFRelease(result);
+			return NULL;
+		}
+		CFStringUtil cfkey(ckey);
+		const char* cvalue = PyString_AsString(value);
+		if (cvalue == NULL)
+		{
+			CFRelease(result);
+			return NULL;
+		}
+		CFStringUtil cfvalue(cvalue);
+		CFDictionaryAddValue(result, cfkey.get(), cfvalue.get());
+	}
+	
+	return result;
+}
+
+// Utility function - not exposed to Python
 static CFComparisonResult CompareRecordListValues(const void *val1, const void *val2, void *context)
 {
 	CFMutableArrayRef l1 = (CFMutableArrayRef)val1;
@@ -216,6 +252,8 @@
 	return result;
 }
 
+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.
@@ -238,410 +276,183 @@
  */
 extern "C" PyObject* odInit(PyObject* self, PyObject* args)
 {
-    int result = 0;
-
     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;
-	
+    }
+
 	CDirectoryService* ds = new CDirectoryService(nodename);
-	PyObject* pyds;
 	if (ds != NULL)
 	{
-		pyds = PyCObject_FromVoidPtr(ds, odDestroy);
-		result = 1;
+		return PyCObject_FromVoidPtr(ds, odDestroy);
 	}
 	
-	if (result == 1)
-		return pyds;
-	else
-		Py_RETURN_NONE;
+	PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices odInit: could not initialize directory service", 0));		
+	return NULL;
 }
 
 /*
- def listUsers(obj):
-	"""
-	List users in Open Directory, and return key attributes for each user.
-	The attributes in the tuple are (uid, guid, last-modified, calendar-principal-uri).
-	
-	@param obj: C{object} the object obtained from an odInit call.
-	@return: C{list} containing a C{tuple} of C{str} for each user found,
-		or C{None} on failure.
-	"""
+def listAllRecordsWithAttributes(obj, recordType, attributes):
+    """
+    List records in Open Directory, and return key attributes for each one.
+    
+    @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} 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 *listUsers(PyObject *self, PyObject *args)
+extern "C" PyObject *listAllRecordsWithAttributes(PyObject *self, PyObject *args)
 {
 	PyObject* pyds;
-	PyObject* result = NULL;
-    if (!PyArg_ParseTuple(args, "O", &pyds) || !PyCObject_Check(pyds))
+	const char* recordType;
+	PyObject* attributes;
+    if (!PyArg_ParseTuple(args, "OsO", &pyds, &recordType, &attributes) || !PyCObject_Check(pyds) || !PyList_Check(attributes))
+    {
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices listAllRecordsWithAttributes: could not parse arguments", 0));		
         return NULL;
+    }
 	
-	CDirectoryService* ds = static_cast<CDirectoryService*>(PyCObject_AsVoidPtr(pyds));
-	if (ds != NULL)
-	{
-		CFMutableArrayRef list = ds->ListUsers();
-		if (list != NULL)
-		{
-			result = CFArrayArrayToPyList(list, true);
-			CFRelease(list);
-		}
-		else
-			result = PyList_New(0);
-		
-		return result;
-	}
-	else
-		Py_RETURN_NONE;
-}
-
-/*
- def listGroups(obj):
-	"""
-	List groups in Open Directory, and return key attributes for each group.
-	The attributes in the tuple are (uid, guid, last-modified, calendar-principal-uri).
-	
-	@param obj: C{object} the object obtained from an odInit call.
-	@return: C{list} containg a C{tuple} of C{str} for each group found,
-		or C{None} on failure.
-	"""
- */
-extern "C" PyObject *listGroups(PyObject *self, PyObject *args)
-{
-	PyObject* pyds;
-	PyObject* result = NULL;
-    if (!PyArg_ParseTuple(args, "O", &pyds) || !PyCObject_Check(pyds))
+	// Convert list to CFArray of CFString
+	CFArrayRef cfattributes = PyListToCFArray(attributes);
+	if (cfattributes == NULL)
+    {
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices listAllRecordsWithAttributes: could not parse attributes list", 0));		
         return NULL;
-	
-	CDirectoryService* ds = static_cast<CDirectoryService*>(PyCObject_AsVoidPtr(pyds));
-	if (ds != NULL)
-	{
-		CFMutableArrayRef list = ds->ListGroups();
-		if (list != NULL)
-		{
-			result = CFArrayArrayToPyList(list, true);
-			CFRelease(list);
-		}
-		else
-			result = PyList_New(0);
-		
-		return result;
-	}
-	else
-		Py_RETURN_NONE;
-}
+    }
 
-/*
- def listResources(obj):
-	"""
-	List resources in Open Directory, and return key attributes for each resource.
-	The attributes in the tuple are (uid, guid, last-modified, calendar-principal-uri).
-	
-	@param obj: C{object} the object obtained from an odInit call.
-	@return: C{list} containg a C{tuple} of C{str} for each resource found,
-		or C{None} on failure.
-	"""
- */
-extern "C" PyObject *listResources(PyObject *self, PyObject *args)
-{
-	PyObject* pyds;
-	PyObject* result = NULL;
-    if (!PyArg_ParseTuple(args, "O", &pyds) || !PyCObject_Check(pyds))
-        return NULL;
-	
 	CDirectoryService* ds = static_cast<CDirectoryService*>(PyCObject_AsVoidPtr(pyds));
 	if (ds != NULL)
 	{
-		CFMutableArrayRef list = ds->ListResources();
-		if (list != NULL)
-		{
-			result = CFArrayArrayToPyList(list, true);
-			CFRelease(list);
-		}
-		else
-			result = PyList_New(0);
-		
-		return result;
-	}
-	else
-		Py_RETURN_NONE;
-}
-
-/*
- def checkUser(obj, user):
-	"""
-	Check that a user exists in Open Directory.
-	
-	@param obj: C{object} the object obtained from an odInit call.
-	@param user: C{str} containing the user to check.
-	@return: C{True} if the user was found, C{False} otherwise.
-	"""
- */
-extern "C" PyObject *checkUser(PyObject *self, PyObject *args)
-{
-	bool result = false;
-	
-	PyObject* pyds;
-	const char* user;
-    if (!PyArg_ParseTuple(args, "Os", &pyds, &user) || !PyCObject_Check(pyds))
-        return NULL;
-
-	CDirectoryService* ds = static_cast<CDirectoryService*>(PyCObject_AsVoidPtr(pyds));
-	if (ds != NULL)
-	{
-		result = ds->CheckUser(user);
-	}
-	
-	if (result)
-		Py_RETURN_TRUE;
-	else
-		Py_RETURN_FALSE;
-}
-
-/*
- def checkGroup(obj, group):
-	"""
-	Check that a group exists in Open Directory.
-	
-	@param obj: C{object} the object obtained from an odInit call.
-	@param group: C{str} containing the group to check.
-	@return: C{True} if the group was found, C{False} otherwise.
-	"""
- */
-extern "C" PyObject *checkGroup(PyObject *self, PyObject *args)
-{
-	bool result = false;
-	
-	PyObject* pyds;
-	const char* group;
-    if (!PyArg_ParseTuple(args, "Os", &pyds, &group) || !PyCObject_Check(pyds))
-        return NULL;
-	
-	CDirectoryService* ds = static_cast<CDirectoryService*>(PyCObject_AsVoidPtr(pyds));
-	if (ds != NULL)
-	{
-		result = ds->CheckGroup(group);
-	}
-	
-	if (result)
-		Py_RETURN_TRUE;
-	else
-		Py_RETURN_FALSE;
-}
-
-/*
- def checkResource(obj, resource):
-	"""
-	Check that a resource exists in Open Directory.
-	
-	@param obj: C{object} the object obtained from an odInit call.
-	@param resource: C{str} containing the resource to check.
-	@return: C{True} if the resource was found, C{False} otherwise.
-	"""
- */
-extern "C" PyObject *checkResource(PyObject *self, PyObject *args)
-{
-	bool result = false;
-	
-	PyObject* pyds;
-	const char* resource;
-    if (!PyArg_ParseTuple(args, "Os", &pyds, &resource) || !PyCObject_Check(pyds))
-        return NULL;
-	
-	CDirectoryService* ds = static_cast<CDirectoryService*>(PyCObject_AsVoidPtr(pyds));
-	if (ds != NULL)
-	{
-		result = ds->CheckResource(resource);
-	}
-	
-	if (result)
-		Py_RETURN_TRUE;
-	else
-		Py_RETURN_FALSE;
-}
-
-/*
- def listUsersWithAttributes(obj, users):
-	"""
-	Get user attributes relevant to CalDAV from Open Directory.
-	
-	@param obj: C{object} the object obtained from an odInit call.
-	@param users: C{list} containing C{str}'s for each user to get attributes for.
-	@return: C{dict} containing a C{dict} of attributes for each requested user, 
-		or C{None} otherwise.
-	"""
- */
-extern "C" PyObject *listUsersWithAttributes(PyObject *self, PyObject *args)
-{
-	PyObject* pyds;
-	PyObject* users;
-    if (!PyArg_ParseTuple(args, "OO", &pyds, &users) || !PyCObject_Check(pyds) || !PyList_Check(users))
-        return NULL;
-	
-	// Convert list to CFArray of CFString
-	CFArrayRef cfusers = PyListToCFArray(users);
-	if (cfusers == NULL)
-		return NULL;
-
-	CDirectoryService* ds = static_cast<CDirectoryService*>(PyCObject_AsVoidPtr(pyds));
-	if (ds != NULL)
-	{
-		CFMutableDictionaryRef dict = ds->ListUsersWithAttributes(cfusers);
+		CFMutableDictionaryRef dict = ds->ListAllRecordsWithAttributes(recordType, cfattributes);
 		if (dict != NULL)
 		{
 			PyObject* result = CFDictionaryDictionaryToPyDict(dict);
 			CFRelease(dict);
-			CFRelease(cfusers);
+			CFRelease(cfattributes);
 			
 			return result;
 		}
 	}
+	else
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices listAllRecordsWithAttributes: invalid directory service argument", 0));		
 	
-	CFRelease(cfusers);
-	Py_RETURN_NONE;
+	CFRelease(cfattributes);
+	return NULL;
 }
 
 /*
- def listGroupsWithAttributes(obj, groups):
+def authenticateUserBasic(obj, user, pswd):
 	"""
-	Get group attributes relevant to CalDAV from Open Directory.
+	Authenticate a user with a password to Open Directory.
 	
 	@param obj: C{object} the object obtained from an odInit call.
-	@param groups: C{list} containing C{str}'s for each group to get attributes for.
-	@return: C{dict} containing a C{dict} of attributes for each requested group, 
-		or C{None} otherwise.
+	@param user: C{str} container the user to check.
+	@param pswd: C{str} containing the password to check.
+	@return: C{True} if the user was found, C{False} otherwise.
 	"""
  */
-extern "C" PyObject *listGroupsWithAttributes(PyObject *self, PyObject *args)
+extern "C" PyObject *authenticateUserBasic(PyObject *self, PyObject *args)
 {
 	PyObject* pyds;
-	PyObject* grps;
-    if (!PyArg_ParseTuple(args, "OO", &pyds, &grps) || !PyCObject_Check(pyds) || !PyList_Check(grps))
+	const char* user;
+	const char* pswd;
+    if (!PyArg_ParseTuple(args, "Oss", &pyds, &user, &pswd) || !PyCObject_Check(pyds))
+    {
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices authenticateUserBasic: could not parse arguments", 0));		
         return NULL;
+    }
 	
-	// Convert list to CFArray of CFString
-	CFArrayRef cfgrps = PyListToCFArray(grps);
-	if (cfgrps == NULL)
-		return NULL;
-	
 	CDirectoryService* ds = static_cast<CDirectoryService*>(PyCObject_AsVoidPtr(pyds));
 	if (ds != NULL)
 	{
-		CFMutableDictionaryRef dict = ds->ListGroupsWithAttributes(cfgrps);
-		if (dict != NULL)
+		bool result = false;
+		if (ds->AuthenticateUserBasic(user, pswd, result))
 		{
-			PyObject* result = CFDictionaryDictionaryToPyDict(dict);
-			CFRelease(dict);
-			CFRelease(cfgrps);
-			
-			return result;
+			if (result)
+				Py_RETURN_TRUE;
+			else
+				Py_RETURN_FALSE;
 		}
 	}
+	else
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices authenticateUserBasic: invalid directory service argument", 0));		
 	
-	CFRelease(cfgrps);
-	Py_RETURN_NONE;
+	return NULL;
 }
 
 /*
- def listResourcesWithAttributes(obj, rsrcs):
-	"""
-	Get resource attributes relevant to CalDAV from Open Directory.
-	
-	@param obj: C{object} the object obtained from an odInit call.
-	@param rsrcs: C{list} containing C{str}'s for each resource to get attributes for.
-	@return: C{dict} containing a C{dict} of attributes for each requested resource, 
-		or C{None} otherwise.
-	"""
+def authenticateUserDigest(obj, user, challenge, response, method):
+    """
+    Authenticate using HTTP Digest credentials to Open Directory.
+    
+    @param obj: C{object} the object obtained from an odInit call.
+	@param user: C{str} container the user to check.
+    @param challenge: C{str} the HTTP challenge sent to the client.
+    @param response: C{str} the HTTP response sent from the client.
+    @param method: C{str} the HTTP method being used.
+    @return: C{True} if the user was found, C{False} otherwise.
+    """
  */
-extern "C" PyObject *listResourcesWithAttributes(PyObject *self, PyObject *args)
+extern "C" PyObject *authenticateUserDigest(PyObject *self, PyObject *args)
 {
 	PyObject* pyds;
-	PyObject* rsrcs;
-    if (!PyArg_ParseTuple(args, "OO", &pyds, &rsrcs) || !PyCObject_Check(pyds) || !PyList_Check(rsrcs))
+	const char* user;
+	const char* challenge;
+	const char* response;
+	const char* method;
+    if (!PyArg_ParseTuple(args, "Ossss", &pyds, &user, &challenge, &response, &method) || !PyCObject_Check(pyds))
+    {
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices authenticateUserDigest: could not parse arguments", 0));		
         return NULL;
+    }
 	
-	// Convert list to CFArray of CFString
-	CFArrayRef cfrsrcs = PyListToCFArray(rsrcs);
-	if (cfrsrcs == NULL)
-		return NULL;
-	
 	CDirectoryService* ds = static_cast<CDirectoryService*>(PyCObject_AsVoidPtr(pyds));
 	if (ds != NULL)
 	{
-		CFMutableDictionaryRef dict = ds->ListResourcesWithAttributes(cfrsrcs);
-		if (dict != NULL)
+		bool result = false;
+		if (ds->AuthenticateUserDigest(user, challenge, response, method, result))
 		{
-			PyObject* result = CFDictionaryDictionaryToPyDict(dict);
-			CFRelease(dict);
-			CFRelease(cfrsrcs);
-			
-			return result;
+			if (result)
+				Py_RETURN_TRUE;
+			else
+				Py_RETURN_FALSE;
 		}
 	}
+	else
+		PyErr_SetObject(ODException_class, Py_BuildValue("((s:i))", "DirectoryServices authenticateUserDigest: invalid directory service argument", 0));		
 	
-	CFRelease(cfrsrcs);
-	Py_RETURN_NONE;
+	return NULL;
 }
 
-/*
- def authenticateUser(obj, user, pswd):
-	"""
-	Authenticate a user with a password to Open Directory.
-	
-	@param obj: C{object} the object obtained from an odInit call.
-	@param user: C{str} container the user to check.
-	@param pswd: C{str} containing the password to check.
-	@return: C{True} if the user was found, C{False} otherwise.
-	"""
- */
-extern "C" PyObject *authenticateUser(PyObject *self, PyObject *args)
-{
-	bool result = false;
-	
-	PyObject* pyds;
-	const char* user;
-	const char* pswd;
-    if (!PyArg_ParseTuple(args, "Oss", &pyds, &user, &pswd) || !PyCObject_Check(pyds))
-        return NULL;
-	
-	CDirectoryService* ds = static_cast<CDirectoryService*>(PyCObject_AsVoidPtr(pyds));
-	if (ds != NULL)
-	{
-		result = ds->AuthenticateUser(user, pswd);
-	}
-	
-	if (result)
-		Py_RETURN_TRUE;
-	else
-		Py_RETURN_FALSE;
-}
-
 static PyMethodDef ODMethods[] = {
     {"odInit",  odInit, METH_VARARGS,
 		"Initialize the Open Directory system."},
-    {"listUsers",  listUsers, METH_VARARGS,
-		"List all users in Open Directory."},
-    {"listGroups",  listGroups, METH_VARARGS,
-		"List all groups in Open Directory."},
-    {"listResources",  listResources, METH_VARARGS,
-		"List all resources in Open Directory."},
-    {"checkUser",  checkUser, METH_VARARGS,
-		"Check that a user exists in Open Directory."},
-    {"checkGroup",  checkGroup, METH_VARARGS,
-		"Check that a group exists in Open Directory."},
-    {"checkResource",  checkResource, METH_VARARGS,
-		"Check that a resource exists in Open Directory."},
-    {"listUsersWithAttributes",  listUsersWithAttributes, METH_VARARGS,
-		"Get user attributes relevant to CalDAV from Open Directory."},
-    {"listGroupsWithAttributes",  listGroupsWithAttributes, METH_VARARGS,
-		"Get group attributes relevant to CalDAV from Open Directory."},
-    {"listResourcesWithAttributes",  listResourcesWithAttributes, METH_VARARGS,
-		"Get resource attributes relevant to CalDAV from Open Directory."},
-    {"authenticateUser",  authenticateUser, METH_VARARGS,
-		"Authenticate a user with a password to Open Directory."},
+    {"listAllRecordsWithAttributes",  listAllRecordsWithAttributes, METH_VARARGS,
+		"List all records of the specified type in Open Directory, returning requested attributes."},
+    {"authenticateUserBasic",  authenticateUserBasic, METH_VARARGS,
+		"Authenticate a user with a password to Open Directory using plain text authentication."},
+    {"authenticateUserDigest",  authenticateUserDigest, METH_VARARGS,
+		"Authenticate a user with a password to Open Directory using HTTP DIGEST authentication."},
     {NULL, NULL, 0, NULL}        /* Sentinel */
 };
 
 PyMODINIT_FUNC initopendirectory(void)
 {
-    (void) Py_InitModule("opendirectory", ODMethods);
+    PyObject* m = Py_InitModule("opendirectory", ODMethods);
+
+    PyObject* d = PyModule_GetDict(m);
+
+    if (!(ODException_class = PyErr_NewException("opendirectory.ODError", NULL, NULL)))
+        goto error;
+    PyDict_SetItemString(d, "ODError", ODException_class);
+    Py_INCREF(ODException_class);
+
+
+error:
+    if (PyErr_Occurred())
+		PyErr_SetString(PyExc_ImportError, "opendirectory: init failed");
 }

Modified: PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/cyrusdaboo.mode1
===================================================================
--- PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/cyrusdaboo.mode1	2007-01-05 16:57:13 UTC (rev 932)
+++ PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/cyrusdaboo.mode1	2007-01-05 17:29:27 UTC (rev 933)
@@ -185,7 +185,48 @@
 	<key>Notifications</key>
 	<array/>
 	<key>OpenEditors</key>
-	<array/>
+	<array>
+		<dict>
+			<key>Content</key>
+			<dict>
+				<key>PBXProjectModuleGUID</key>
+				<string>AF8B08260AA33EF5008DBE58</string>
+				<key>PBXProjectModuleLabel</key>
+				<string>PythonWrapper.cpp</string>
+				<key>PBXSplitModuleInNavigatorKey</key>
+				<dict>
+					<key>Split0</key>
+					<dict>
+						<key>PBXProjectModuleGUID</key>
+						<string>AF8B08270AA33EF5008DBE58</string>
+						<key>PBXProjectModuleLabel</key>
+						<string>PythonWrapper.cpp</string>
+						<key>_historyCapacity</key>
+						<integer>0</integer>
+						<key>bookmark</key>
+						<string>AF5B518E0AA3689500DCCB52</string>
+						<key>history</key>
+						<array>
+							<string>AF8B08280AA33EF5008DBE58</string>
+						</array>
+					</dict>
+					<key>SplitCount</key>
+					<string>1</string>
+				</dict>
+				<key>StatusBarVisibility</key>
+				<true/>
+			</dict>
+			<key>Geometry</key>
+			<dict>
+				<key>Frame</key>
+				<string>{{0, 20}, {811, 731}}</string>
+				<key>PBXModuleWindowStatusBarHidden2</key>
+				<false/>
+				<key>RubberWindowFrame</key>
+				<string>113 60 811 772 0 0 1680 1028 </string>
+			</dict>
+		</dict>
+	</array>
 	<key>PerspectiveWidths</key>
 	<array>
 		<integer>-1</integer>
@@ -219,8 +260,6 @@
 			<key>Layout</key>
 			<array>
 				<dict>
-					<key>BecomeActive</key>
-					<true/>
 					<key>ContentConfiguration</key>
 					<dict>
 						<key>PBXBottomSmartGroupGIDs</key>
@@ -258,6 +297,7 @@
 							<array>
 								<string>08FB7794FE84155DC02AAC07</string>
 								<string>08FB7795FE84155DC02AAC07</string>
+								<string>AF155A3D0A501FA0007E1E6E</string>
 								<string>1C37FABC05509CD000000102</string>
 							</array>
 							<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
@@ -287,7 +327,7 @@
 							<real>186</real>
 						</array>
 						<key>RubberWindowFrame</key>
-						<string>102 425 1006 600 0 0 1680 1028 </string>
+						<string>374 263 1006 600 0 0 1680 1028 </string>
 					</dict>
 					<key>Module</key>
 					<string>PBXSmartGroupTreeModule</string>
@@ -324,7 +364,7 @@
 								<key>Frame</key>
 								<string>{{0, 0}, {798, 0}}</string>
 								<key>RubberWindowFrame</key>
-								<string>102 425 1006 600 0 0 1680 1028 </string>
+								<string>374 263 1006 600 0 0 1680 1028 </string>
 							</dict>
 							<key>Module</key>
 							<string>PBXNavigatorGroup</string>
@@ -332,6 +372,8 @@
 							<string>0pt</string>
 						</dict>
 						<dict>
+							<key>BecomeActive</key>
+							<true/>
 							<key>ContentConfiguration</key>
 							<dict>
 								<key>PBXProjectModuleGUID</key>
@@ -344,7 +386,7 @@
 								<key>Frame</key>
 								<string>{{0, 5}, {798, 554}}</string>
 								<key>RubberWindowFrame</key>
-								<string>102 425 1006 600 0 0 1680 1028 </string>
+								<string>374 263 1006 600 0 0 1680 1028 </string>
 							</dict>
 							<key>Module</key>
 							<string>XCDetailModule</string>
@@ -368,9 +410,9 @@
 			</array>
 			<key>TableOfContents</key>
 			<array>
-				<string>AF155B1D0A50313D007E1E6E</string>
+				<string>AF5B51850AA343BE00DCCB52</string>
 				<string>1CE0B1FE06471DED0097A5F4</string>
-				<string>AF155B1E0A50313D007E1E6E</string>
+				<string>AF5B51860AA343BE00DCCB52</string>
 				<string>1CE0B20306471E060097A5F4</string>
 				<string>1CE0B20506471E060097A5F4</string>
 			</array>
@@ -504,18 +546,11 @@
 	<integer>5</integer>
 	<key>WindowOrderList</key>
 	<array>
-		<string>AF155C300A505917007E1E6E</string>
-		<string>AF155C310A505917007E1E6E</string>
-		<string>AF155AB60A502582007E1E6E</string>
-		<string>1CD10A99069EF8BA00B06720</string>
-		<string>AF155BA40A503D93007E1E6E</string>
-		<string>1C530D57069F1CE1000CFCEE</string>
-		<string>1C0AD2B3069F1EA900FABCE6</string>
-		<string>AF155A7F0A501FE9007E1E6E</string>
+		<string>AF8B08260AA33EF5008DBE58</string>
 		<string>/Users/cyrusdaboo/Documents/Development/Apple/eclipse/PyOpenDirectory/support/PyOpenDirectory.xcodeproj</string>
 	</array>
 	<key>WindowString</key>
-	<string>102 425 1006 600 0 0 1680 1028 </string>
+	<string>374 263 1006 600 0 0 1680 1028 </string>
 	<key>WindowTools</key>
 	<array>
 		<dict>
@@ -538,7 +573,7 @@
 								<key>PBXProjectModuleGUID</key>
 								<string>1CD0528F0623707200166675</string>
 								<key>PBXProjectModuleLabel</key>
-								<string>PythonWrapper.cpp</string>
+								<string>test.cpp</string>
 								<key>StatusBarVisibility</key>
 								<true/>
 							</dict>
@@ -547,7 +582,7 @@
 								<key>Frame</key>
 								<string>{{0, 0}, {1075, 361}}</string>
 								<key>RubberWindowFrame</key>
-								<string>512 367 1075 643 0 0 1680 1028 </string>
+								<string>511 368 1075 643 0 0 1680 1028 </string>
 							</dict>
 							<key>Module</key>
 							<string>PBXNavigatorGroup</string>
@@ -571,7 +606,7 @@
 								<key>Frame</key>
 								<string>{{0, 366}, {1075, 236}}</string>
 								<key>RubberWindowFrame</key>
-								<string>512 367 1075 643 0 0 1680 1028 </string>
+								<string>511 368 1075 643 0 0 1680 1028 </string>
 							</dict>
 							<key>Module</key>
 							<string>PBXBuildResultsModule</string>
@@ -594,14 +629,14 @@
 			<key>TableOfContents</key>
 			<array>
 				<string>AF155A7F0A501FE9007E1E6E</string>
-				<string>AF155AE50A5028AA007E1E6E</string>
+				<string>AF8B08020AA33E0B008DBE58</string>
 				<string>1CD0528F0623707200166675</string>
 				<string>XCMainBuildResultsModuleGUID</string>
 			</array>
 			<key>ToolbarConfiguration</key>
 			<string>xcode.toolbar.config.build</string>
 			<key>WindowString</key>
-			<string>512 367 1075 643 0 0 1680 1028 </string>
+			<string>511 368 1075 643 0 0 1680 1028 </string>
 			<key>WindowToolGUID</key>
 			<string>AF155A7F0A501FE9007E1E6E</string>
 			<key>WindowToolIsVisible</key>
@@ -739,7 +774,7 @@
 										<key>PBXProjectModuleGUID</key>
 										<string>1CDD528C0622207200134675</string>
 										<key>PBXProjectModuleLabel</key>
-										<string>stringobject.h</string>
+										<string></string>
 										<key>StatusBarVisibility</key>
 										<true/>
 									</dict>
@@ -748,7 +783,7 @@
 										<key>Frame</key>
 										<string>{{0, 0}, {1008, 542}}</string>
 										<key>RubberWindowFrame</key>
-										<string>36 200 1008 800 0 0 1680 1028 </string>
+										<string>15 28 1008 800 0 0 1280 832 </string>
 									</dict>
 									<key>Module</key>
 									<string>PBXNavigatorGroup</string>
@@ -774,7 +809,7 @@
 								<key>Frame</key>
 								<string>{{0, 547}, {1008, 212}}</string>
 								<key>RubberWindowFrame</key>
-								<string>36 200 1008 800 0 0 1680 1028 </string>
+								<string>15 28 1008 800 0 0 1280 832 </string>
 							</dict>
 							<key>Module</key>
 							<string>PBXProjectFindModule</string>
@@ -797,13 +832,13 @@
 			<key>TableOfContents</key>
 			<array>
 				<string>1C530D57069F1CE1000CFCEE</string>
-				<string>AF155AF10A502ABE007E1E6E</string>
-				<string>AF155AF20A502ABE007E1E6E</string>
+				<string>AF2939EF0A82D1E200D4E295</string>
+				<string>AF2939F00A82D1E200D4E295</string>
 				<string>1CDD528C0622207200134675</string>
 				<string>1CD0528E0623707200166675</string>
 			</array>
 			<key>WindowString</key>
-			<string>36 200 1008 800 0 0 1680 1028 </string>
+			<string>15 28 1008 800 0 0 1280 832 </string>
 			<key>WindowToolGUID</key>
 			<string>1C530D57069F1CE1000CFCEE</string>
 			<key>WindowToolIsVisible</key>

Copied: PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/cyrusdaboo.mode1v3 (from rev 931, PyOpenDirectory/branches/users/cdaboo/new-schema-892/support/PyOpenDirectory.xcodeproj/cyrusdaboo.mode1v3)
===================================================================
--- PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/cyrusdaboo.mode1v3	                        (rev 0)
+++ PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/cyrusdaboo.mode1v3	2007-01-05 17:29:27 UTC (rev 933)
@@ -0,0 +1,1495 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+	<key>ActivePerspectiveName</key>
+	<string>Project</string>
+	<key>AllowedModules</key>
+	<array>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXSmartGroupTreeModule</string>
+			<key>Name</key>
+			<string>Groups and Files Outline View</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXNavigatorGroup</string>
+			<key>Name</key>
+			<string>Editor</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>XCTaskListModule</string>
+			<key>Name</key>
+			<string>Task List</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>XCDetailModule</string>
+			<key>Name</key>
+			<string>File and Smart Group Detail Viewer</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>1</string>
+			<key>Module</key>
+			<string>PBXBuildResultsModule</string>
+			<key>Name</key>
+			<string>Detailed Build Results Viewer</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>1</string>
+			<key>Module</key>
+			<string>PBXProjectFindModule</string>
+			<key>Name</key>
+			<string>Project Batch Find Tool</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXRunSessionModule</string>
+			<key>Name</key>
+			<string>Run Log</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXBookmarksModule</string>
+			<key>Name</key>
+			<string>Bookmarks Tool</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXClassBrowserModule</string>
+			<key>Name</key>
+			<string>Class Browser</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXCVSModule</string>
+			<key>Name</key>
+			<string>Source Code Control Tool</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXDebugBreakpointsModule</string>
+			<key>Name</key>
+			<string>Debug Breakpoints Tool</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>XCDockableInspector</string>
+			<key>Name</key>
+			<string>Inspector</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>PBXOpenQuicklyModule</string>
+			<key>Name</key>
+			<string>Open Quickly Tool</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>1</string>
+			<key>Module</key>
+			<string>PBXDebugSessionModule</string>
+			<key>Name</key>
+			<string>Debugger</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>1</string>
+			<key>Module</key>
+			<string>PBXDebugCLIModule</string>
+			<key>Name</key>
+			<string>Debug Console</string>
+		</dict>
+		<dict>
+			<key>BundleLoadPath</key>
+			<string></string>
+			<key>MaxInstances</key>
+			<string>n</string>
+			<key>Module</key>
+			<string>XCSnapshotModule</string>
+			<key>Name</key>
+			<string>Snapshots Tool</string>
+		</dict>
+	</array>
+	<key>Description</key>
+	<string>DefaultDescriptionKey</string>
+	<key>DockingSystemVisible</key>
+	<false/>
+	<key>Extension</key>
+	<string>mode1v3</string>
+	<key>FavBarConfig</key>
+	<dict>
+		<key>PBXProjectModuleGUID</key>
+		<string>AFBD6A470B4AB8D400A565AE</string>
+		<key>XCBarModuleItemNames</key>
+		<dict/>
+		<key>XCBarModuleItems</key>
+		<array/>
+	</dict>
+	<key>FirstTimeWindowDisplayed</key>
+	<false/>
+	<key>Identifier</key>
+	<string>com.apple.perspectives.project.mode1v3</string>
+	<key>MajorVersion</key>
+	<integer>32</integer>
+	<key>MinorVersion</key>
+	<integer>1</integer>
+	<key>Name</key>
+	<string>Default</string>
+	<key>Notifications</key>
+	<array/>
+	<key>OpenEditors</key>
+	<array/>
+	<key>PerspectiveWidths</key>
+	<array>
+		<integer>-1</integer>
+		<integer>-1</integer>
+	</array>
+	<key>Perspectives</key>
+	<array>
+		<dict>
+			<key>ChosenToolbarItems</key>
+			<array>
+				<string>active-target-popup</string>
+				<string>active-buildstyle-popup</string>
+				<string>action</string>
+				<string>NSToolbarFlexibleSpaceItem</string>
+				<string>buildOrClean</string>
+				<string>build-and-goOrGo</string>
+				<string>com.apple.ide.PBXToolbarStopButton</string>
+				<string>get-info</string>
+				<string>toggle-editor</string>
+				<string>NSToolbarFlexibleSpaceItem</string>
+				<string>com.apple.pbx.toolbar.searchfield</string>
+			</array>
+			<key>ControllerClassBaseName</key>
+			<string></string>
+			<key>IconName</key>
+			<string>WindowOfProjectWithEditor</string>
+			<key>Identifier</key>
+			<string>perspective.project</string>
+			<key>IsVertical</key>
+			<false/>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>ContentConfiguration</key>
+					<dict>
+						<key>PBXBottomSmartGroupGIDs</key>
+						<array>
+							<string>1C37FBAC04509CD000000102</string>
+							<string>1C37FAAC04509CD000000102</string>
+							<string>1C08E77C0454961000C914BD</string>
+							<string>1C37FABC05509CD000000102</string>
+							<string>1C37FABC05539CD112110102</string>
+							<string>E2644B35053B69B200211256</string>
+							<string>1C37FABC04509CD000100104</string>
+							<string>1CC0EA4004350EF90044410B</string>
+							<string>1CC0EA4004350EF90041110B</string>
+						</array>
+						<key>PBXProjectModuleGUID</key>
+						<string>1CE0B1FE06471DED0097A5F4</string>
+						<key>PBXProjectModuleLabel</key>
+						<string>Files</string>
+						<key>PBXProjectStructureProvided</key>
+						<string>yes</string>
+						<key>PBXSmartGroupTreeModuleColumnData</key>
+						<dict>
+							<key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
+							<array>
+								<real>186</real>
+							</array>
+							<key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
+							<array>
+								<string>MainColumn</string>
+							</array>
+						</dict>
+						<key>PBXSmartGroupTreeModuleOutlineStateKey_v7</key>
+						<dict>
+							<key>PBXSmartGroupTreeModuleOutlineStateExpansionKey</key>
+							<array>
+								<string>08FB7794FE84155DC02AAC07</string>
+								<string>1C37FABC05509CD000000102</string>
+							</array>
+							<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
+							<array>
+								<array>
+									<integer>0</integer>
+								</array>
+							</array>
+							<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
+							<string>{{0, 0}, {186, 887}}</string>
+						</dict>
+						<key>PBXTopSmartGroupGIDs</key>
+						<array/>
+						<key>XCIncludePerspectivesSwitch</key>
+						<true/>
+						<key>XCSharingToken</key>
+						<string>com.apple.Xcode.GFSharingToken</string>
+					</dict>
+					<key>GeometryConfiguration</key>
+					<dict>
+						<key>Frame</key>
+						<string>{{0, 0}, {203, 905}}</string>
+						<key>GroupTreeTableConfiguration</key>
+						<array>
+							<string>MainColumn</string>
+							<real>186</real>
+						</array>
+						<key>RubberWindowFrame</key>
+						<string>3 232 1359 946 0 0 1920 1178 </string>
+					</dict>
+					<key>Module</key>
+					<string>PBXSmartGroupTreeModule</string>
+					<key>Proportion</key>
+					<string>203pt</string>
+				</dict>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>BecomeActive</key>
+							<true/>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CE0B20306471E060097A5F4</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>CDirectoryService.cpp</string>
+								<key>PBXSplitModuleInNavigatorKey</key>
+								<dict>
+									<key>Split0</key>
+									<dict>
+										<key>PBXProjectModuleGUID</key>
+										<string>1CE0B20406471E060097A5F4</string>
+										<key>PBXProjectModuleLabel</key>
+										<string>CDirectoryService.cpp</string>
+										<key>_historyCapacity</key>
+										<integer>0</integer>
+										<key>bookmark</key>
+										<string>AFAC4ECD0B4C437900D59661</string>
+										<key>history</key>
+										<array>
+											<string>AF8974920B4AFA6600965268</string>
+											<string>AFAC4E900B4C267800D59661</string>
+											<string>AFAC4ECB0B4C437900D59661</string>
+											<string>AFAC4EBA0B4C41FE00D59661</string>
+										</array>
+										<key>prevStack</key>
+										<array>
+											<string>AF8974940B4AFA6600965268</string>
+											<string>AFAC4E700B4C18D400D59661</string>
+											<string>AFAC4E790B4C23EC00D59661</string>
+											<string>AFAC4E890B4C25AD00D59661</string>
+											<string>AFAC4E920B4C267800D59661</string>
+											<string>AFAC4EC00B4C431100D59661</string>
+											<string>AFAC4ECC0B4C437900D59661</string>
+										</array>
+									</dict>
+									<key>SplitCount</key>
+									<string>1</string>
+								</dict>
+								<key>StatusBarVisibility</key>
+								<true/>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 0}, {1151, 503}}</string>
+								<key>RubberWindowFrame</key>
+								<string>3 232 1359 946 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXNavigatorGroup</string>
+							<key>Proportion</key>
+							<string>503pt</string>
+						</dict>
+						<dict>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CE0B20506471E060097A5F4</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Detail</string>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 508}, {1151, 397}}</string>
+								<key>RubberWindowFrame</key>
+								<string>3 232 1359 946 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>XCDetailModule</string>
+							<key>Proportion</key>
+							<string>397pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>1151pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Project</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>XCModuleDock</string>
+				<string>PBXSmartGroupTreeModule</string>
+				<string>XCModuleDock</string>
+				<string>PBXNavigatorGroup</string>
+				<string>XCDetailModule</string>
+			</array>
+			<key>TableOfContents</key>
+			<array>
+				<string>AFAC4E720B4C18D400D59661</string>
+				<string>1CE0B1FE06471DED0097A5F4</string>
+				<string>AFAC4E730B4C18D400D59661</string>
+				<string>1CE0B20306471E060097A5F4</string>
+				<string>1CE0B20506471E060097A5F4</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.defaultV3</string>
+		</dict>
+		<dict>
+			<key>ControllerClassBaseName</key>
+			<string></string>
+			<key>IconName</key>
+			<string>WindowOfProject</string>
+			<key>Identifier</key>
+			<string>perspective.morph</string>
+			<key>IsVertical</key>
+			<integer>0</integer>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>BecomeActive</key>
+					<integer>1</integer>
+					<key>ContentConfiguration</key>
+					<dict>
+						<key>PBXBottomSmartGroupGIDs</key>
+						<array>
+							<string>1C37FBAC04509CD000000102</string>
+							<string>1C37FAAC04509CD000000102</string>
+							<string>1C08E77C0454961000C914BD</string>
+							<string>1C37FABC05509CD000000102</string>
+							<string>1C37FABC05539CD112110102</string>
+							<string>E2644B35053B69B200211256</string>
+							<string>1C37FABC04509CD000100104</string>
+							<string>1CC0EA4004350EF90044410B</string>
+							<string>1CC0EA4004350EF90041110B</string>
+						</array>
+						<key>PBXProjectModuleGUID</key>
+						<string>11E0B1FE06471DED0097A5F4</string>
+						<key>PBXProjectModuleLabel</key>
+						<string>Files</string>
+						<key>PBXProjectStructureProvided</key>
+						<string>yes</string>
+						<key>PBXSmartGroupTreeModuleColumnData</key>
+						<dict>
+							<key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
+							<array>
+								<real>186</real>
+							</array>
+							<key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
+							<array>
+								<string>MainColumn</string>
+							</array>
+						</dict>
+						<key>PBXSmartGroupTreeModuleOutlineStateKey_v7</key>
+						<dict>
+							<key>PBXSmartGroupTreeModuleOutlineStateExpansionKey</key>
+							<array>
+								<string>29B97314FDCFA39411CA2CEA</string>
+								<string>1C37FABC05509CD000000102</string>
+							</array>
+							<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
+							<array>
+								<array>
+									<integer>0</integer>
+								</array>
+							</array>
+							<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
+							<string>{{0, 0}, {186, 337}}</string>
+						</dict>
+						<key>PBXTopSmartGroupGIDs</key>
+						<array/>
+						<key>XCIncludePerspectivesSwitch</key>
+						<integer>1</integer>
+						<key>XCSharingToken</key>
+						<string>com.apple.Xcode.GFSharingToken</string>
+					</dict>
+					<key>GeometryConfiguration</key>
+					<dict>
+						<key>Frame</key>
+						<string>{{0, 0}, {203, 355}}</string>
+						<key>GroupTreeTableConfiguration</key>
+						<array>
+							<string>MainColumn</string>
+							<real>186</real>
+						</array>
+						<key>RubberWindowFrame</key>
+						<string>373 269 690 397 0 0 1440 878 </string>
+					</dict>
+					<key>Module</key>
+					<string>PBXSmartGroupTreeModule</string>
+					<key>Proportion</key>
+					<string>100%</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Morph</string>
+			<key>PreferredWidth</key>
+			<integer>300</integer>
+			<key>ServiceClasses</key>
+			<array>
+				<string>XCModuleDock</string>
+				<string>PBXSmartGroupTreeModule</string>
+			</array>
+			<key>TableOfContents</key>
+			<array>
+				<string>11E0B1FE06471DED0097A5F4</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.default.shortV3</string>
+		</dict>
+	</array>
+	<key>PerspectivesBarVisible</key>
+	<false/>
+	<key>ShelfIsVisible</key>
+	<false/>
+	<key>SourceDescription</key>
+	<string>file at '/System/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecificationMode1.xcperspec'</string>
+	<key>StatusbarIsVisible</key>
+	<true/>
+	<key>TimeStamp</key>
+	<real>0.0</real>
+	<key>ToolbarDisplayMode</key>
+	<integer>1</integer>
+	<key>ToolbarIsVisible</key>
+	<true/>
+	<key>ToolbarSizeMode</key>
+	<integer>1</integer>
+	<key>Type</key>
+	<string>Perspectives</string>
+	<key>UpdateMessage</key>
+	<string>The Default Workspace in this version of Xcode now includes support to hide and show the detail view (what has been referred to as the "Metro-Morph" feature).  You must discard your current Default Workspace settings and update to the latest Default Workspace in order to gain this feature.  Do you wish to update to the latest Workspace defaults for project '%@'?</string>
+	<key>WindowJustification</key>
+	<integer>5</integer>
+	<key>WindowOrderList</key>
+	<array>
+		<string>AFAC4EC90B4C436E00D59661</string>
+		<string>AFBD6A500B4AC44700A565AE</string>
+		<string>AFAC4E740B4C18D400D59661</string>
+		<string>AFAC4E750B4C18D400D59661</string>
+		<string>AFAC4E760B4C18D400D59661</string>
+		<string>/Users/cyrusdaboo/Documents/Development/Apple/eclipse/PyOpenDirectory/support/PyOpenDirectory.xcodeproj</string>
+		<string>1CD10A99069EF8BA00B06720</string>
+		<string>1C78EAAD065D492600B07095</string>
+	</array>
+	<key>WindowString</key>
+	<string>3 232 1359 946 0 0 1920 1178 </string>
+	<key>WindowToolsV3</key>
+	<array>
+		<dict>
+			<key>FirstTimeWindowDisplayed</key>
+			<false/>
+			<key>Identifier</key>
+			<string>windowTool.build</string>
+			<key>IsVertical</key>
+			<true/>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>BecomeActive</key>
+							<true/>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CD0528F0623707200166675</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>test.cpp</string>
+								<key>StatusBarVisibility</key>
+								<true/>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 0}, {1110, 390}}</string>
+								<key>RubberWindowFrame</key>
+								<string>23 483 1110 672 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXNavigatorGroup</string>
+							<key>Proportion</key>
+							<string>390pt</string>
+						</dict>
+						<dict>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>XCMainBuildResultsModuleGUID</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Build</string>
+								<key>XCBuildResultsTrigger_Collapse</key>
+								<integer>1021</integer>
+								<key>XCBuildResultsTrigger_Open</key>
+								<integer>1011</integer>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 395}, {1110, 236}}</string>
+								<key>RubberWindowFrame</key>
+								<string>23 483 1110 672 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXBuildResultsModule</string>
+							<key>Proportion</key>
+							<string>236pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>631pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Build Results</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXBuildResultsModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<true/>
+			<key>TableOfContents</key>
+			<array>
+				<string>AFBD6A500B4AC44700A565AE</string>
+				<string>AFAC4E640B4C182700D59661</string>
+				<string>1CD0528F0623707200166675</string>
+				<string>XCMainBuildResultsModuleGUID</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.buildV3</string>
+			<key>WindowString</key>
+			<string>23 483 1110 672 0 0 1920 1178 </string>
+			<key>WindowToolGUID</key>
+			<string>AFBD6A500B4AC44700A565AE</string>
+			<key>WindowToolIsVisible</key>
+			<false/>
+		</dict>
+		<dict>
+			<key>FirstTimeWindowDisplayed</key>
+			<false/>
+			<key>Identifier</key>
+			<string>windowTool.debugger</string>
+			<key>IsVertical</key>
+			<true/>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>Debugger</key>
+								<dict>
+									<key>HorizontalSplitView</key>
+									<dict>
+										<key>_collapsingFrameDimension</key>
+										<real>0.0</real>
+										<key>_indexOfCollapsedView</key>
+										<integer>0</integer>
+										<key>_percentageOfCollapsedView</key>
+										<real>0.0</real>
+										<key>isCollapsed</key>
+										<string>yes</string>
+										<key>sizes</key>
+										<array>
+											<string>{{0, 0}, {588, 382}}</string>
+											<string>{{588, 0}, {701, 382}}</string>
+										</array>
+									</dict>
+									<key>VerticalSplitView</key>
+									<dict>
+										<key>_collapsingFrameDimension</key>
+										<real>0.0</real>
+										<key>_indexOfCollapsedView</key>
+										<integer>0</integer>
+										<key>_percentageOfCollapsedView</key>
+										<real>0.0</real>
+										<key>isCollapsed</key>
+										<string>yes</string>
+										<key>sizes</key>
+										<array>
+											<string>{{0, 0}, {1289, 382}}</string>
+											<string>{{0, 382}, {1289, 368}}</string>
+										</array>
+									</dict>
+								</dict>
+								<key>LauncherConfigVersion</key>
+								<string>8</string>
+								<key>PBXProjectModuleGUID</key>
+								<string>1C162984064C10D400B95A72</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Debug - GLUTExamples (Underwater)</string>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>DebugConsoleVisible</key>
+								<string>None</string>
+								<key>DebugConsoleWindowFrame</key>
+								<string>{{200, 200}, {500, 300}}</string>
+								<key>DebugSTDIOWindowFrame</key>
+								<string>{{200, 200}, {500, 300}}</string>
+								<key>Frame</key>
+								<string>{{0, 0}, {1289, 750}}</string>
+								<key>PBXDebugSessionStackFrameViewKey</key>
+								<dict>
+									<key>DebugVariablesTableConfiguration</key>
+									<array>
+										<string>Name</string>
+										<real>213</real>
+										<string>Value</string>
+										<real>85</real>
+										<string>Summary</string>
+										<real>378</real>
+									</array>
+									<key>Frame</key>
+									<string>{{588, 0}, {701, 382}}</string>
+									<key>RubberWindowFrame</key>
+									<string>300 338 1289 791 0 0 1920 1178 </string>
+								</dict>
+								<key>RubberWindowFrame</key>
+								<string>300 338 1289 791 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXDebugSessionModule</string>
+							<key>Proportion</key>
+							<string>750pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>750pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Debugger</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXDebugSessionModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<true/>
+			<key>TableOfContents</key>
+			<array>
+				<string>1CD10A99069EF8BA00B06720</string>
+				<string>AFAC4E650B4C182700D59661</string>
+				<string>1C162984064C10D400B95A72</string>
+				<string>AFAC4E660B4C182700D59661</string>
+				<string>AFAC4E670B4C182700D59661</string>
+				<string>AFAC4E680B4C182700D59661</string>
+				<string>AFAC4E690B4C182700D59661</string>
+				<string>AFAC4E6A0B4C182700D59661</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.debugV3</string>
+			<key>WindowString</key>
+			<string>300 338 1289 791 0 0 1920 1178 </string>
+			<key>WindowToolGUID</key>
+			<string>1CD10A99069EF8BA00B06720</string>
+			<key>WindowToolIsVisible</key>
+			<true/>
+		</dict>
+		<dict>
+			<key>FirstTimeWindowDisplayed</key>
+			<false/>
+			<key>Identifier</key>
+			<string>windowTool.find</string>
+			<key>IsVertical</key>
+			<true/>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>Dock</key>
+							<array>
+								<dict>
+									<key>ContentConfiguration</key>
+									<dict>
+										<key>PBXProjectModuleGUID</key>
+										<string>1CDD528C0622207200134675</string>
+										<key>PBXProjectModuleLabel</key>
+										<string></string>
+										<key>StatusBarVisibility</key>
+										<true/>
+									</dict>
+									<key>GeometryConfiguration</key>
+									<dict>
+										<key>Frame</key>
+										<string>{{0, 0}, {781, 212}}</string>
+										<key>RubberWindowFrame</key>
+										<string>65 639 781 470 0 0 1920 1178 </string>
+									</dict>
+									<key>Module</key>
+									<string>PBXNavigatorGroup</string>
+									<key>Proportion</key>
+									<string>781pt</string>
+								</dict>
+							</array>
+							<key>Proportion</key>
+							<string>212pt</string>
+						</dict>
+						<dict>
+							<key>BecomeActive</key>
+							<true/>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CD0528E0623707200166675</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Project Find</string>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 217}, {781, 212}}</string>
+								<key>RubberWindowFrame</key>
+								<string>65 639 781 470 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXProjectFindModule</string>
+							<key>Proportion</key>
+							<string>212pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>429pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Project Find</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXProjectFindModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<true/>
+			<key>TableOfContents</key>
+			<array>
+				<string>1C530D57069F1CE1000CFCEE</string>
+				<string>AF8974B30B4B08A700965268</string>
+				<string>AF8974B40B4B08A700965268</string>
+				<string>1CDD528C0622207200134675</string>
+				<string>1CD0528E0623707200166675</string>
+			</array>
+			<key>WindowString</key>
+			<string>65 639 781 470 0 0 1920 1178 </string>
+			<key>WindowToolGUID</key>
+			<string>1C530D57069F1CE1000CFCEE</string>
+			<key>WindowToolIsVisible</key>
+			<false/>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>MENUSEPARATOR</string>
+		</dict>
+		<dict>
+			<key>FirstTimeWindowDisplayed</key>
+			<false/>
+			<key>Identifier</key>
+			<string>windowTool.debuggerConsole</string>
+			<key>IsVertical</key>
+			<true/>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>BecomeActive</key>
+							<true/>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1C78EAAC065D492600B07095</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Debugger Console</string>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 0}, {1110, 583}}</string>
+								<key>RubberWindowFrame</key>
+								<string>695 422 1110 624 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXDebugCLIModule</string>
+							<key>Proportion</key>
+							<string>583pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>583pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Debugger Console</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXDebugCLIModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<true/>
+			<key>TableOfContents</key>
+			<array>
+				<string>1C78EAAD065D492600B07095</string>
+				<string>AFAC4E6B0B4C182700D59661</string>
+				<string>1C78EAAC065D492600B07095</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.consoleV3</string>
+			<key>WindowString</key>
+			<string>695 422 1110 624 0 0 1920 1178 </string>
+			<key>WindowToolGUID</key>
+			<string>1C78EAAD065D492600B07095</string>
+			<key>WindowToolIsVisible</key>
+			<true/>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.snapshots</string>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>Module</key>
+							<string>XCSnapshotModule</string>
+							<key>Proportion</key>
+							<string>100%</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>100%</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Snapshots</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>XCSnapshotModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<string>Yes</string>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.snapshots</string>
+			<key>WindowString</key>
+			<string>315 824 300 550 0 0 1440 878 </string>
+			<key>WindowToolIsVisible</key>
+			<string>Yes</string>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.run</string>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>LauncherConfigVersion</key>
+								<string>3</string>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CD0528B0623707200166675</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Run</string>
+								<key>Runner</key>
+								<dict>
+									<key>HorizontalSplitView</key>
+									<dict>
+										<key>_collapsingFrameDimension</key>
+										<real>0.0</real>
+										<key>_indexOfCollapsedView</key>
+										<integer>0</integer>
+										<key>_percentageOfCollapsedView</key>
+										<real>0.0</real>
+										<key>isCollapsed</key>
+										<string>yes</string>
+										<key>sizes</key>
+										<array>
+											<string>{{0, 0}, {493, 167}}</string>
+											<string>{{0, 176}, {493, 267}}</string>
+										</array>
+									</dict>
+									<key>VerticalSplitView</key>
+									<dict>
+										<key>_collapsingFrameDimension</key>
+										<real>0.0</real>
+										<key>_indexOfCollapsedView</key>
+										<integer>0</integer>
+										<key>_percentageOfCollapsedView</key>
+										<real>0.0</real>
+										<key>isCollapsed</key>
+										<string>yes</string>
+										<key>sizes</key>
+										<array>
+											<string>{{0, 0}, {405, 443}}</string>
+											<string>{{414, 0}, {514, 443}}</string>
+										</array>
+									</dict>
+								</dict>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 0}, {460, 159}}</string>
+								<key>RubberWindowFrame</key>
+								<string>316 696 459 200 0 0 1280 1002 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXRunSessionModule</string>
+							<key>Proportion</key>
+							<string>159pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>159pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Run Log</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXRunSessionModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<integer>1</integer>
+			<key>TableOfContents</key>
+			<array>
+				<string>1C0AD2B3069F1EA900FABCE6</string>
+				<string>1C0AD2B4069F1EA900FABCE6</string>
+				<string>1CD0528B0623707200166675</string>
+				<string>1C0AD2B5069F1EA900FABCE6</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.run</string>
+			<key>WindowString</key>
+			<string>316 696 459 200 0 0 1280 1002 </string>
+			<key>WindowToolGUID</key>
+			<string>1C0AD2B3069F1EA900FABCE6</string>
+			<key>WindowToolIsVisible</key>
+			<integer>0</integer>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.scm</string>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1C78EAB2065D492600B07095</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>&lt;No Editor&gt;</string>
+								<key>PBXSplitModuleInNavigatorKey</key>
+								<dict>
+									<key>Split0</key>
+									<dict>
+										<key>PBXProjectModuleGUID</key>
+										<string>1C78EAB3065D492600B07095</string>
+									</dict>
+									<key>SplitCount</key>
+									<string>1</string>
+								</dict>
+								<key>StatusBarVisibility</key>
+								<integer>1</integer>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 0}, {452, 0}}</string>
+								<key>RubberWindowFrame</key>
+								<string>743 379 452 308 0 0 1280 1002 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXNavigatorGroup</string>
+							<key>Proportion</key>
+							<string>0pt</string>
+						</dict>
+						<dict>
+							<key>BecomeActive</key>
+							<integer>1</integer>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CD052920623707200166675</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>SCM</string>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>ConsoleFrame</key>
+								<string>{{0, 259}, {452, 0}}</string>
+								<key>Frame</key>
+								<string>{{0, 7}, {452, 259}}</string>
+								<key>RubberWindowFrame</key>
+								<string>743 379 452 308 0 0 1280 1002 </string>
+								<key>TableConfiguration</key>
+								<array>
+									<string>Status</string>
+									<real>30</real>
+									<string>FileName</string>
+									<real>199</real>
+									<string>Path</string>
+									<real>197.09500122070312</real>
+								</array>
+								<key>TableFrame</key>
+								<string>{{0, 0}, {452, 250}}</string>
+							</dict>
+							<key>Module</key>
+							<string>PBXCVSModule</string>
+							<key>Proportion</key>
+							<string>262pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>266pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>SCM</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXCVSModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<integer>1</integer>
+			<key>TableOfContents</key>
+			<array>
+				<string>1C78EAB4065D492600B07095</string>
+				<string>1C78EAB5065D492600B07095</string>
+				<string>1C78EAB2065D492600B07095</string>
+				<string>1CD052920623707200166675</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.scm</string>
+			<key>WindowString</key>
+			<string>743 379 452 308 0 0 1280 1002 </string>
+		</dict>
+		<dict>
+			<key>FirstTimeWindowDisplayed</key>
+			<false/>
+			<key>Identifier</key>
+			<string>windowTool.breakpoints</string>
+			<key>IsVertical</key>
+			<false/>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXBottomSmartGroupGIDs</key>
+								<array>
+									<string>1C77FABC04509CD000000102</string>
+								</array>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CE0B1FE06471DED0097A5F4</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Files</string>
+								<key>PBXProjectStructureProvided</key>
+								<string>no</string>
+								<key>PBXSmartGroupTreeModuleColumnData</key>
+								<dict>
+									<key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
+									<array>
+										<real>168</real>
+									</array>
+									<key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
+									<array>
+										<string>MainColumn</string>
+									</array>
+								</dict>
+								<key>PBXSmartGroupTreeModuleOutlineStateKey_v7</key>
+								<dict>
+									<key>PBXSmartGroupTreeModuleOutlineStateExpansionKey</key>
+									<array>
+										<string>1C77FABC04509CD000000102</string>
+									</array>
+									<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
+									<array>
+										<array>
+											<integer>0</integer>
+										</array>
+									</array>
+									<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
+									<string>{{0, 0}, {168, 350}}</string>
+								</dict>
+								<key>PBXTopSmartGroupGIDs</key>
+								<array/>
+								<key>XCIncludePerspectivesSwitch</key>
+								<false/>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 0}, {185, 368}}</string>
+								<key>GroupTreeTableConfiguration</key>
+								<array>
+									<string>MainColumn</string>
+									<real>168</real>
+								</array>
+								<key>RubberWindowFrame</key>
+								<string>44 723 744 409 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXSmartGroupTreeModule</string>
+							<key>Proportion</key>
+							<string>185pt</string>
+						</dict>
+						<dict>
+							<key>BecomeActive</key>
+							<true/>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CA1AED706398EBD00589147</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Detail</string>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{190, 0}, {554, 368}}</string>
+								<key>RubberWindowFrame</key>
+								<string>44 723 744 409 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>XCDetailModule</string>
+							<key>Proportion</key>
+							<string>554pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>368pt</string>
+				</dict>
+			</array>
+			<key>MajorVersion</key>
+			<integer>3</integer>
+			<key>MinorVersion</key>
+			<integer>0</integer>
+			<key>Name</key>
+			<string>Breakpoints</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXSmartGroupTreeModule</string>
+				<string>XCDetailModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<true/>
+			<key>TableOfContents</key>
+			<array>
+				<string>AFAC4EC90B4C436E00D59661</string>
+				<string>AFAC4ECA0B4C436E00D59661</string>
+				<string>1CE0B1FE06471DED0097A5F4</string>
+				<string>1CA1AED706398EBD00589147</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.breakpointsV3</string>
+			<key>WindowString</key>
+			<string>44 723 744 409 0 0 1920 1178 </string>
+			<key>WindowToolGUID</key>
+			<string>AFAC4EC90B4C436E00D59661</string>
+			<key>WindowToolIsVisible</key>
+			<false/>
+		</dict>
+		<dict>
+			<key>FirstTimeWindowDisplayed</key>
+			<false/>
+			<key>Identifier</key>
+			<string>windowTool.debugAnimator</string>
+			<key>IsVertical</key>
+			<true/>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>BecomeActive</key>
+							<true/>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>PBXProjectModuleGUID</key>
+								<string>AF8974CE0B4B09FA00965268</string>
+								<key>PBXProjectModuleLabel</key>
+								<string></string>
+								<key>StatusBarVisibility</key>
+								<true/>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{{0, 0}, {700, 459}}</string>
+								<key>RubberWindowFrame</key>
+								<string>24 655 700 500 0 0 1920 1178 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXNavigatorGroup</string>
+							<key>Proportion</key>
+							<string>459pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>459pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Debug Visualizer</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXNavigatorGroup</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<true/>
+			<key>TableOfContents</key>
+			<array>
+				<string>AF8974D00B4B09FA00965268</string>
+				<string>AF8974D10B4B09FA00965268</string>
+				<string>AF8974CE0B4B09FA00965268</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.debugAnimatorV3</string>
+			<key>WindowString</key>
+			<string>24 655 700 500 0 0 1920 1178 </string>
+			<key>WindowToolGUID</key>
+			<string>AF8974D00B4B09FA00965268</string>
+			<key>WindowToolIsVisible</key>
+			<false/>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.bookmarks</string>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>Module</key>
+							<string>PBXBookmarksModule</string>
+							<key>Proportion</key>
+							<string>100%</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>100%</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Bookmarks</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXBookmarksModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<integer>0</integer>
+			<key>WindowString</key>
+			<string>538 42 401 187 0 0 1280 1002 </string>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.classBrowser</string>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>BecomeActive</key>
+							<integer>1</integer>
+							<key>ContentConfiguration</key>
+							<dict>
+								<key>OptionsSetName</key>
+								<string>Hierarchy, all classes</string>
+								<key>PBXProjectModuleGUID</key>
+								<string>1CA6456E063B45B4001379D8</string>
+								<key>PBXProjectModuleLabel</key>
+								<string>Class Browser - NSObject</string>
+							</dict>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>ClassesFrame</key>
+								<string>{{0, 0}, {374, 96}}</string>
+								<key>ClassesTreeTableConfiguration</key>
+								<array>
+									<string>PBXClassNameColumnIdentifier</string>
+									<real>208</real>
+									<string>PBXClassBookColumnIdentifier</string>
+									<real>22</real>
+								</array>
+								<key>Frame</key>
+								<string>{{0, 0}, {630, 331}}</string>
+								<key>MembersFrame</key>
+								<string>{{0, 105}, {374, 395}}</string>
+								<key>MembersTreeTableConfiguration</key>
+								<array>
+									<string>PBXMemberTypeIconColumnIdentifier</string>
+									<real>22</real>
+									<string>PBXMemberNameColumnIdentifier</string>
+									<real>216</real>
+									<string>PBXMemberTypeColumnIdentifier</string>
+									<real>97</real>
+									<string>PBXMemberBookColumnIdentifier</string>
+									<real>22</real>
+								</array>
+								<key>PBXModuleWindowStatusBarHidden2</key>
+								<integer>1</integer>
+								<key>RubberWindowFrame</key>
+								<string>385 179 630 352 0 0 1440 878 </string>
+							</dict>
+							<key>Module</key>
+							<string>PBXClassBrowserModule</string>
+							<key>Proportion</key>
+							<string>332pt</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>332pt</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Class Browser</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>PBXClassBrowserModule</string>
+			</array>
+			<key>StatusbarIsVisible</key>
+			<integer>0</integer>
+			<key>TableOfContents</key>
+			<array>
+				<string>1C0AD2AF069F1E9B00FABCE6</string>
+				<string>1C0AD2B0069F1E9B00FABCE6</string>
+				<string>1CA6456E063B45B4001379D8</string>
+			</array>
+			<key>ToolbarConfiguration</key>
+			<string>xcode.toolbar.config.classbrowser</string>
+			<key>WindowString</key>
+			<string>385 179 630 352 0 0 1440 878 </string>
+			<key>WindowToolGUID</key>
+			<string>1C0AD2AF069F1E9B00FABCE6</string>
+			<key>WindowToolIsVisible</key>
+			<integer>0</integer>
+		</dict>
+		<dict>
+			<key>Identifier</key>
+			<string>windowTool.refactoring</string>
+			<key>IncludeInToolsMenu</key>
+			<integer>0</integer>
+			<key>Layout</key>
+			<array>
+				<dict>
+					<key>Dock</key>
+					<array>
+						<dict>
+							<key>BecomeActive</key>
+							<integer>1</integer>
+							<key>GeometryConfiguration</key>
+							<dict>
+								<key>Frame</key>
+								<string>{0, 0}, {500, 335}</string>
+								<key>RubberWindowFrame</key>
+								<string>{0, 0}, {500, 335}</string>
+							</dict>
+							<key>Module</key>
+							<string>XCRefactoringModule</string>
+							<key>Proportion</key>
+							<string>100%</string>
+						</dict>
+					</array>
+					<key>Proportion</key>
+					<string>100%</string>
+				</dict>
+			</array>
+			<key>Name</key>
+			<string>Refactoring</string>
+			<key>ServiceClasses</key>
+			<array>
+				<string>XCRefactoringModule</string>
+			</array>
+			<key>WindowString</key>
+			<string>200 200 500 356 0 0 1920 1200 </string>
+		</dict>
+	</array>
+</dict>
+</plist>

Modified: PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/cyrusdaboo.pbxuser
===================================================================
--- PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/cyrusdaboo.pbxuser	2007-01-05 16:57:13 UTC (rev 932)
+++ PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/cyrusdaboo.pbxuser	2007-01-05 17:29:27 UTC (rev 933)
@@ -8,20 +8,42 @@
 			8DD76F620486A84900D96B5E /* PyOpenDirectory */,
 		);
 		breakpoints = (
-			AF155C230A50587A007E1E6E /* main.cpp:72 */,
 		);
-		breakpointsGroup = AF155B8E0A5036CE007E1E6E /* XCBreakpointsBucket */;
 		codeSenseManager = AF155A2E0A501F7B007E1E6E /* Code sense */;
 		executables = (
 			AF155A290A501F5C007E1E6E /* PyOpenDirectory */,
 		);
 		perUserDictionary = {
+			"PBXConfiguration.PBXBreakpointsDataSource.v1:1CA1AED706398EBD00589147" = {
+				PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
+				PBXFileTableDataSourceColumnSortingKey = PBXBreakpointsDataSource_BreakpointID;
+				PBXFileTableDataSourceColumnWidthsKey = (
+					20,
+					20,
+					198,
+					20,
+					99,
+					99,
+					29,
+					20,
+				);
+				PBXFileTableDataSourceColumnsKey = (
+					PBXBreakpointsDataSource_ActionID,
+					PBXBreakpointsDataSource_TypeID,
+					PBXBreakpointsDataSource_BreakpointID,
+					PBXBreakpointsDataSource_UseID,
+					PBXBreakpointsDataSource_LocationID,
+					PBXBreakpointsDataSource_ConditionID,
+					PBXBreakpointsDataSource_IgnoreCountID,
+					PBXBreakpointsDataSource_ContinueID,
+				);
+			};
 			PBXConfiguration.PBXFileTableDataSource3.PBXFileTableDataSource = {
-				PBXFileTableDataSourceColumnSortingDirectionKey = "-1";
+				PBXFileTableDataSourceColumnSortingDirectionKey = 1;
 				PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
 				PBXFileTableDataSourceColumnWidthsKey = (
 					20,
-					559,
+					912,
 					20,
 					48,
 					43,
@@ -38,19 +60,70 @@
 					PBXFileDataSource_Target_ColumnID,
 				);
 			};
-			PBXPerProjectTemplateStateSaveDate = 173025236;
-			PBXWorkspaceStateSaveDate = 173025236;
+			PBXPerProjectTemplateStateSaveDate = 189535876;
+			PBXWorkspaceStateSaveDate = 189535876;
 		};
+		perUserProjectItems = {
+			AF8974920B4AFA6600965268 = AF8974920B4AFA6600965268 /* PBXTextBookmark */;
+			AF8974940B4AFA6600965268 = AF8974940B4AFA6600965268 /* PBXTextBookmark */;
+			AF8974950B4AFA6600965268 = AF8974950B4AFA6600965268 /* PBXTextBookmark */;
+			AF89749E0B4B07D600965268 = AF89749E0B4B07D600965268 /* PBXTextBookmark */;
+			AF8974D80B4B0BC500965268 = AF8974D80B4B0BC500965268 /* PBXTextBookmark */;
+			AF8974D90B4B0BC500965268 = AF8974D90B4B0BC500965268 /* PBXTextBookmark */;
+			AF8974DA0B4B0BC500965268 = AF8974DA0B4B0BC500965268 /* PBXTextBookmark */;
+			AF8974E30B4B0C6000965268 = AF8974E30B4B0C6000965268 /* PBXTextBookmark */;
+			AFAC4E620B4C182700D59661 /* PBXTextBookmark */ = AFAC4E620B4C182700D59661 /* PBXTextBookmark */;
+			AFAC4E630B4C182700D59661 /* PBXTextBookmark */ = AFAC4E630B4C182700D59661 /* PBXTextBookmark */;
+			AFAC4E6E0B4C18D400D59661 /* PBXTextBookmark */ = AFAC4E6E0B4C18D400D59661 /* PBXTextBookmark */;
+			AFAC4E6F0B4C18D400D59661 /* PBXTextBookmark */ = AFAC4E6F0B4C18D400D59661 /* PBXTextBookmark */;
+			AFAC4E700B4C18D400D59661 /* PBXTextBookmark */ = AFAC4E700B4C18D400D59661 /* PBXTextBookmark */;
+			AFAC4E710B4C18D400D59661 /* PBXTextBookmark */ = AFAC4E710B4C18D400D59661 /* PBXTextBookmark */;
+			AFAC4E780B4C23EC00D59661 /* PBXTextBookmark */ = AFAC4E780B4C23EC00D59661 /* PBXTextBookmark */;
+			AFAC4E790B4C23EC00D59661 /* PBXTextBookmark */ = AFAC4E790B4C23EC00D59661 /* PBXTextBookmark */;
+			AFAC4E7A0B4C23EC00D59661 /* PBXTextBookmark */ = AFAC4E7A0B4C23EC00D59661 /* PBXTextBookmark */;
+			AFAC4E7B0B4C246E00D59661 /* PBXTextBookmark */ = AFAC4E7B0B4C246E00D59661 /* PBXTextBookmark */;
+			AFAC4E810B4C259700D59661 /* PBXTextBookmark */ = AFAC4E810B4C259700D59661 /* PBXTextBookmark */;
+			AFAC4E820B4C259700D59661 /* PBXTextBookmark */ = AFAC4E820B4C259700D59661 /* PBXTextBookmark */;
+			AFAC4E840B4C259700D59661 /* PBXTextBookmark */ = AFAC4E840B4C259700D59661 /* PBXTextBookmark */;
+			AFAC4E850B4C259700D59661 /* PBXTextBookmark */ = AFAC4E850B4C259700D59661 /* PBXTextBookmark */;
+			AFAC4E870B4C25AD00D59661 /* PBXTextBookmark */ = AFAC4E870B4C25AD00D59661 /* PBXTextBookmark */;
+			AFAC4E880B4C25AD00D59661 /* PBXTextBookmark */ = AFAC4E880B4C25AD00D59661 /* PBXTextBookmark */;
+			AFAC4E890B4C25AD00D59661 /* PBXTextBookmark */ = AFAC4E890B4C25AD00D59661 /* PBXTextBookmark */;
+			AFAC4E8A0B4C25AD00D59661 /* PBXTextBookmark */ = AFAC4E8A0B4C25AD00D59661 /* PBXTextBookmark */;
+			AFAC4E900B4C267800D59661 /* PBXTextBookmark */ = AFAC4E900B4C267800D59661 /* PBXTextBookmark */;
+			AFAC4E910B4C267800D59661 /* PBXTextBookmark */ = AFAC4E910B4C267800D59661 /* PBXTextBookmark */;
+			AFAC4E920B4C267800D59661 /* PBXTextBookmark */ = AFAC4E920B4C267800D59661 /* PBXTextBookmark */;
+			AFAC4E930B4C267800D59661 /* PBXTextBookmark */ = AFAC4E930B4C267800D59661 /* PBXTextBookmark */;
+			AFAC4E980B4C26BC00D59661 /* PBXTextBookmark */ = AFAC4E980B4C26BC00D59661 /* PBXTextBookmark */;
+			AFAC4E9A0B4C279100D59661 /* PBXTextBookmark */ = AFAC4E9A0B4C279100D59661 /* PBXTextBookmark */;
+			AFAC4EB00B4C3E7700D59661 /* PBXTextBookmark */ = AFAC4EB00B4C3E7700D59661 /* PBXTextBookmark */;
+			AFAC4EB40B4C41C300D59661 /* PBXTextBookmark */ = AFAC4EB40B4C41C300D59661 /* PBXTextBookmark */;
+			AFAC4EB60B4C41D100D59661 /* PBXTextBookmark */ = AFAC4EB60B4C41D100D59661 /* PBXTextBookmark */;
+			AFAC4EB80B4C41E500D59661 /* PBXTextBookmark */ = AFAC4EB80B4C41E500D59661 /* PBXTextBookmark */;
+			AFAC4EB90B4C41E500D59661 /* PBXTextBookmark */ = AFAC4EB90B4C41E500D59661 /* PBXTextBookmark */;
+			AFAC4EBA0B4C41FE00D59661 /* PBXTextBookmark */ = AFAC4EBA0B4C41FE00D59661 /* PBXTextBookmark */;
+			AFAC4EBE0B4C431100D59661 /* PBXTextBookmark */ = AFAC4EBE0B4C431100D59661 /* PBXTextBookmark */;
+			AFAC4EBF0B4C431100D59661 /* PBXTextBookmark */ = AFAC4EBF0B4C431100D59661 /* PBXTextBookmark */;
+			AFAC4EC00B4C431100D59661 /* PBXTextBookmark */ = AFAC4EC00B4C431100D59661 /* PBXTextBookmark */;
+			AFAC4EC10B4C431100D59661 /* PBXTextBookmark */ = AFAC4EC10B4C431100D59661 /* PBXTextBookmark */;
+			AFAC4EC30B4C434200D59661 /* PBXTextBookmark */ = AFAC4EC30B4C434200D59661 /* PBXTextBookmark */;
+			AFAC4EC40B4C434200D59661 /* PBXTextBookmark */ = AFAC4EC40B4C434200D59661 /* PBXTextBookmark */;
+			AFAC4EC50B4C434200D59661 /* PBXTextBookmark */ = AFAC4EC50B4C434200D59661 /* PBXTextBookmark */;
+			AFAC4EC80B4C436E00D59661 /* PBXTextBookmark */ = AFAC4EC80B4C436E00D59661 /* PBXTextBookmark */;
+			AFAC4ECB0B4C437900D59661 /* PBXTextBookmark */ = AFAC4ECB0B4C437900D59661 /* PBXTextBookmark */;
+			AFAC4ECC0B4C437900D59661 /* PBXTextBookmark */ = AFAC4ECC0B4C437900D59661 /* PBXTextBookmark */;
+			AFAC4ECD0B4C437900D59661 /* PBXTextBookmark */ = AFAC4ECD0B4C437900D59661 /* PBXTextBookmark */;
+		};
 		sourceControlManager = AF155A2D0A501F7B007E1E6E /* Source Control */;
 		userBuildSettings = {
 		};
 	};
-	08FB7796FE84155DC02AAC07 /* main.cpp */ = {
+	08FB7796FE84155DC02AAC07 /* test.cpp */ = {
 		uiCtxt = {
-			sepNavIntBoundsRect = "{{0, 0}, {971, 7616}}";
-			sepNavSelRange = "{2467, 0}";
-			sepNavVisRect = "{{0, 886}, {971, 342}}";
-			sepNavWindowFrame = "{{436, 4}, {811, 1024}}";
+			sepNavIntBoundsRect = "{{0, 0}, {1104, 2856}}";
+			sepNavSelRange = "{5935, 0}";
+			sepNavVisRect = "{{0, 1690}, {1104, 448}}";
+			sepNavWindowFrame = "{{436, 4}, {811, 828}}";
 		};
 	};
 	8DD76F620486A84900D96B5E /* PyOpenDirectory */ = {
@@ -67,6 +140,7 @@
 		argumentStrings = (
 		);
 		autoAttachOnCrash = 1;
+		breakpointsEnabled = 1;
 		configStateDict = {
 		};
 		customDataFormattersEnabled = 1;
@@ -85,6 +159,21 @@
 		sourceDirectories = (
 		);
 		variableFormatDictionary = {
+			$cs = 1;
+			$ds = 1;
+			$eax = 1;
+			$ebp = 1;
+			$ebx = 1;
+			$ecx = 1;
+			$edi = 1;
+			$edx = 1;
+			$eflags = 1;
+			$eip = 1;
+			$es = 1;
+			$esi = 1;
+			$esp = 1;
+			$gs = 1;
+			$ss = 1;
 		};
 	};
 	AF155A2D0A501F7B007E1E6E /* Source Control */ = {
@@ -101,64 +190,523 @@
 	};
 	AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */ = {
 		uiCtxt = {
-			sepNavIntBoundsRect = "{{0, 0}, {1001, 13062}}";
-			sepNavSelRange = "{4911, 46}";
-			sepNavVisRect = "{{0, 2486}, {1001, 895}}";
-			sepNavWindowFrame = "{{550, 4}, {1046, 1024}}";
+			sepNavIntBoundsRect = "{{0, 0}, {1104, 11914}}";
+			sepNavSelRange = "{9255, 26}";
+			sepNavVisRect = "{{0, 4025}, {1104, 471}}";
+			sepNavWindowFrame = "{{144, 200}, {1046, 828}}";
 		};
 	};
 	AF155A300A501F84007E1E6E /* CDirectoryService.h */ = {
 		uiCtxt = {
-			sepNavIntBoundsRect = "{{0, 0}, {766, 910}}";
+			sepNavIntBoundsRect = "{{0, 0}, {766, 1106}}";
 			sepNavSelRange = "{1276, 0}";
-			sepNavVisRect = "{{0, 10}, {766, 895}}";
-			sepNavWindowFrame = "{{15, -1}, {811, 1024}}";
+			sepNavVisRect = "{{0, 163}, {766, 699}}";
+			sepNavWindowFrame = "{{15, 4}, {811, 828}}";
 		};
 	};
 	AF155A310A501F84007E1E6E /* PythonWrapper.cpp */ = {
 		uiCtxt = {
-			sepNavIntBoundsRect = "{{0, 0}, {1028, 8694}}";
-			sepNavSelRange = "{15855, 0}";
-			sepNavVisRect = "{{0, 8313}, {1028, 329}}";
-			sepNavWindowFrame = "{{15, -1}, {811, 1024}}";
+			sepNavIntBoundsRect = "{{0, 0}, {1134, 6790}}";
+			sepNavSelRange = "{14121, 0}";
+			sepNavVisRect = "{{0, 1858}, {1134, 471}}";
+			sepNavWindowFrame = "{{113, 4}, {811, 828}}";
 		};
 	};
 	AF155AFB0A502C09007E1E6E /* CFStringUtil.h */ = {
 		uiCtxt = {
-			sepNavIntBoundsRect = "{{0, 0}, {766, 895}}";
+			sepNavIntBoundsRect = "{{0, 0}, {766, 699}}";
 			sepNavSelRange = "{546, 0}";
-			sepNavVisRect = "{{0, 0}, {766, 895}}";
-			sepNavWindowFrame = "{{810, -8}, {811, 1024}}";
+			sepNavVisRect = "{{0, 0}, {766, 699}}";
+			sepNavWindowFrame = "{{746, 81}, {811, 828}}";
 		};
 	};
 	AF155AFC0A502C09007E1E6E /* CFStringUtil.cpp */ = {
 		uiCtxt = {
-			sepNavIntBoundsRect = "{{0, 0}, {1028, 1148}}";
-			sepNavSelRange = "{1112, 16}";
-			sepNavVisRect = "{{0, 725}, {1028, 329}}";
+			sepNavIntBoundsRect = "{{0, 0}, {1242, 1736}}";
+			sepNavSelRange = "{2369, 0}";
+			sepNavVisRect = "{{0, 1307}, {1242, 313}}";
 			sepNavWindowFrame = "{{36, 4}, {811, 1024}}";
 		};
 	};
-	AF155B8E0A5036CE007E1E6E /* XCBreakpointsBucket */ = {
-		isa = XCBreakpointsBucket;
-		name = "Project Breakpoints";
-		objects = (
-			AF155C230A50587A007E1E6E /* main.cpp:72 */,
-		);
+	AF8974920B4AFA6600965268 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A310A501F84007E1E6E /* PythonWrapper.cpp */;
+		name = "PythonWrapper.cpp: 485";
+		rLen = 0;
+		rLoc = 14121;
+		rType = 0;
+		vrLen = 900;
+		vrLoc = 3735;
 	};
-	AF155C230A50587A007E1E6E /* main.cpp:72 */ = {
-		isa = PBXFileBreakpoint;
-		actions = (
-		);
-		breakpointStyle = 0;
-		continueAfterActions = 0;
-		delayBeforeContinue = 0;
-		fileReference = 08FB7796FE84155DC02AAC07 /* main.cpp */;
-		functionName = "main()";
-		hitCount = 1;
-		lineNumber = 72;
-		location = main.ob;
-		modificationTime = 173039851.35989;
-		state = 1;
+	AF8974940B4AFA6600965268 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A310A501F84007E1E6E /* PythonWrapper.cpp */;
+		name = Python/Python.h;
+		rLen = 15;
+		rLoc = 726;
+		rType = 0;
+		vrLen = 1115;
+		vrLoc = 0;
 	};
+	AF8974950B4AFA6600965268 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A310A501F84007E1E6E /* PythonWrapper.cpp */;
+		name = "PythonWrapper.cpp: 485";
+		rLen = 0;
+		rLoc = 14121;
+		rType = 0;
+		vrLen = 900;
+		vrLoc = 3735;
+	};
+	AF89749E0B4B07D600965268 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 840";
+		rLen = 0;
+		rLoc = 22889;
+		rType = 0;
+		vrLen = 1059;
+		vrLoc = 15544;
+	};
+	AF8974D80B4B0BC500965268 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = 08FB7796FE84155DC02AAC07 /* test.cpp */;
+		name = "test.cpp: 59";
+		rLen = 0;
+		rLoc = 1922;
+		rType = 0;
+		vrLen = 790;
+		vrLoc = 1868;
+	};
+	AF8974D90B4B0BC500965268 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		comments = "error: no matching function for call to 'CDirectoryService::_ListAllRecordsWithAttributes(const char*&, const __CFArray*&)'";
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		rLen = 1;
+		rLoc = 92;
+		rType = 1;
+	};
+	AF8974DA0B4B0BC500965268 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = 08FB7796FE84155DC02AAC07 /* test.cpp */;
+		name = "test.cpp: 59";
+		rLen = 0;
+		rLoc = 1922;
+		rType = 0;
+		vrLen = 790;
+		vrLoc = 1868;
+	};
+	AF8974E30B4B0C6000965268 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 843";
+		rLen = 0;
+		rLoc = 22991;
+		rType = 0;
+		vrLen = 1128;
+		vrLoc = 1882;
+	};
+	AFAC4E620B4C182700D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		comments = "error: no matching function for call to 'CDirectoryService::BuildStringDataList(<type error>, tDataList*&)'";
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		rLen = 1;
+		rLoc = 413;
+		rType = 1;
+	};
+	AFAC4E630B4C182700D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "";
+		rLen = 3;
+		rLoc = 12268;
+		rType = 0;
+		vrLen = 767;
+		vrLoc = 11968;
+	};
+	AFAC4E6E0B4C18D400D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = 08FB7796FE84155DC02AAC07 /* test.cpp */;
+		name = "test.cpp: 177";
+		rLen = 0;
+		rLoc = 5134;
+		rType = 0;
+		vrLen = 1062;
+		vrLoc = 1408;
+	};
+	AFAC4E6F0B4C18D400D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		comments = "error: no matching function for call to 'CDirectoryService::BuildStringDataList(<type error>, tDataList*&)'";
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		rLen = 1;
+		rLoc = 413;
+		rType = 1;
+	};
+	AFAC4E700B4C18D400D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = 08FB7796FE84155DC02AAC07 /* test.cpp */;
+		name = "test.cpp: 177";
+		rLen = 0;
+		rLoc = 5134;
+		rType = 0;
+		vrLen = 1062;
+		vrLoc = 1408;
+	};
+	AFAC4E710B4C18D400D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 1069";
+		rLen = 0;
+		rLoc = 30221;
+		rType = 0;
+		vrLen = 1047;
+		vrLoc = 11877;
+	};
+	AFAC4E780B4C23EC00D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		comments = "error: conversion from 'int' to 'CFStringUtil' is ambiguous";
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		rLen = 1;
+		rLoc = 370;
+		rType = 1;
+	};
+	AFAC4E790B4C23EC00D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 1069";
+		rLen = 0;
+		rLoc = 30221;
+		rType = 0;
+		vrLen = 1047;
+		vrLoc = 11877;
+	};
+	AFAC4E7A0B4C23EC00D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "return NULL;";
+		rLen = 15;
+		rLoc = 10914;
+		rType = 0;
+		vrLen = 1309;
+		vrLoc = 10178;
+	};
+	AFAC4E7B0B4C246E00D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 822";
+		rLen = 0;
+		rLoc = 22141;
+		rType = 0;
+		vrLen = 1064;
+		vrLoc = 10347;
+	};
+	AFAC4E810B4C259700D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 822";
+		rLen = 0;
+		rLoc = 22141;
+		rType = 0;
+		vrLen = 1064;
+		vrLoc = 10347;
+	};
+	AFAC4E820B4C259700D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AFAC4E830B4C259700D59661 /* asm _class_isInitialized  0x90863f5e */;
+		rLen = 0;
+		rLoc = 1;
+		rType = 1;
+	};
+	AFAC4E830B4C259700D59661 /* asm _class_isInitialized  0x90863f5e */ = {
+		isa = PBXFileReference;
+		lastKnownFileType = file;
+		path = "asm _class_isInitialized  0x90863f5e";
+		sourceTree = "<group>";
+	};
+	AFAC4E840B4C259700D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 822";
+		rLen = 0;
+		rLoc = 22141;
+		rType = 0;
+		vrLen = 1064;
+		vrLoc = 10347;
+	};
+	AFAC4E850B4C259700D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AFAC4E860B4C259700D59661 /* asm _class_isInitialized  0x90863f5e */;
+		name = "(null): 2";
+		rLen = 0;
+		rLoc = 42;
+		rType = 0;
+		vrLen = 168;
+		vrLoc = 0;
+	};
+	AFAC4E860B4C259700D59661 /* asm _class_isInitialized  0x90863f5e */ = {
+		isa = PBXFileReference;
+		path = "asm _class_isInitialized  0x90863f5e";
+		sourceTree = "<group>";
+	};
+	AFAC4E870B4C25AD00D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 822";
+		rLen = 0;
+		rLoc = 22141;
+		rType = 0;
+		vrLen = 1267;
+		vrLoc = 10178;
+	};
+	AFAC4E880B4C25AD00D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155AFC0A502C09007E1E6E /* CFStringUtil.cpp */;
+		name = "FStringUtil(CFSt";
+		rLen = 16;
+		rLoc = 1112;
+		rType = 0;
+		vrLen = 633;
+		vrLoc = 736;
+	};
+	AFAC4E890B4C25AD00D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 822";
+		rLen = 0;
+		rLoc = 22141;
+		rType = 0;
+		vrLen = 1267;
+		vrLoc = 10178;
+	};
+	AFAC4E8A0B4C25AD00D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155AFC0A502C09007E1E6E /* CFStringUtil.cpp */;
+		name = "CFStringUtil.cpp: 124";
+		rLen = 0;
+		rLoc = 2726;
+		rType = 0;
+		vrLen = 533;
+		vrLoc = 842;
+	};
+	AFAC4E900B4C267800D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155AFC0A502C09007E1E6E /* CFStringUtil.cpp */;
+		name = "CFStringUtil.cpp: 124";
+		rLen = 0;
+		rLoc = 2726;
+		rType = 0;
+		vrLen = 599;
+		vrLoc = 842;
+	};
+	AFAC4E910B4C267800D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		comments = "error: cannot convert 'CFStringUtil' to 'const __CFString*' in return";
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		rLen = 1;
+		rLoc = 391;
+		rType = 1;
+	};
+	AFAC4E920B4C267800D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155AFC0A502C09007E1E6E /* CFStringUtil.cpp */;
+		name = "CFStringUtil.cpp: 124";
+		rLen = 0;
+		rLoc = 2726;
+		rType = 0;
+		vrLen = 599;
+		vrLoc = 842;
+	};
+	AFAC4E930B4C267800D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "return CFStringUtil(result);";
+		rLen = 32;
+		rLoc = 11575;
+		rType = 0;
+		vrLen = 1069;
+		vrLoc = 10993;
+	};
+	AFAC4E980B4C26BC00D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 826";
+		rLen = 0;
+		rLoc = 22175;
+		rType = 0;
+		vrLen = 741;
+		vrLoc = 12242;
+	};
+	AFAC4E9A0B4C279100D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 826";
+		rLen = 0;
+		rLoc = 22175;
+		rType = 0;
+		vrLen = 1055;
+		vrLoc = 10993;
+	};
+	AFAC4EB00B4C3E7700D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 827";
+		rLen = 0;
+		rLoc = 22211;
+		rType = 0;
+		vrLen = 939;
+		vrLoc = 10994;
+	};
+	AFAC4EB40B4C41C300D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 851";
+		rLen = 0;
+		rLoc = 22653;
+		rType = 0;
+		vrLen = 1010;
+		vrLoc = 10903;
+	};
+	AFAC4EB60B4C41D100D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 851";
+		rLen = 0;
+		rLoc = 22652;
+		rType = 0;
+		vrLen = 1010;
+		vrLoc = 10902;
+	};
+	AFAC4EB80B4C41E500D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		comments = "error: 'RemoveBuffer' was not declared in this scope";
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		rLen = 1;
+		rLoc = 801;
+		rType = 1;
+	};
+	AFAC4EB90B4C41E500D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 851";
+		rLen = 0;
+		rLoc = 22671;
+		rType = 0;
+		vrLen = 652;
+		vrLoc = 21167;
+	};
+	AFAC4EBA0B4C41FE00D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		rLen = 1;
+		rLoc = 303;
+		rType = 1;
+	};
+	AFAC4EBE0B4C431100D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 851";
+		rLen = 0;
+		rLoc = 22671;
+		rType = 0;
+		vrLen = 1010;
+		vrLoc = 10902;
+	};
+	AFAC4EBF0B4C431100D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		comments = "error: invalid conversion from 'const __CFArray*' to '__CFArray*'";
+		fRef = 08FB7796FE84155DC02AAC07 /* test.cpp */;
+		rLen = 1;
+		rLoc = 147;
+		rType = 1;
+	};
+	AFAC4EC00B4C431100D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 851";
+		rLen = 0;
+		rLoc = 22671;
+		rType = 0;
+		vrLen = 1010;
+		vrLoc = 10902;
+	};
+	AFAC4EC10B4C431100D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = 08FB7796FE84155DC02AAC07 /* test.cpp */;
+		name = "PrintArray(arrayvalue);";
+		rLen = 26;
+		rLoc = 4366;
+		rType = 0;
+		vrLen = 1015;
+		vrLoc = 3547;
+	};
+	AFAC4EC30B4C434200D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 851";
+		rLen = 0;
+		rLoc = 22671;
+		rType = 0;
+		vrLen = 652;
+		vrLoc = 21167;
+	};
+	AFAC4EC40B4C434200D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "CDirectoryService.cpp: 851";
+		rLen = 0;
+		rLoc = 22671;
+		rType = 0;
+		vrLen = 652;
+		vrLoc = 21167;
+	};
+	AFAC4EC50B4C434200D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = 08FB7796FE84155DC02AAC07 /* test.cpp */;
+		name = "test.cpp: 204";
+		rLen = 0;
+		rLoc = 5935;
+		rType = 0;
+		vrLen = 837;
+		vrLoc = 3572;
+	};
+	AFAC4EC80B4C436E00D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = 08FB7796FE84155DC02AAC07 /* test.cpp */;
+		name = "test.cpp: 204";
+		rLen = 0;
+		rLoc = 5935;
+		rType = 0;
+		vrLen = 832;
+		vrLoc = 3572;
+	};
+	AFAC4ECB0B4C437900D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = 08FB7796FE84155DC02AAC07 /* test.cpp */;
+		name = "test.cpp: 204";
+		rLen = 0;
+		rLoc = 5935;
+		rType = 0;
+		vrLen = 964;
+		vrLoc = 3540;
+	};
+	AFAC4ECC0B4C437900D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = 08FB7796FE84155DC02AAC07 /* test.cpp */;
+		name = "test.cpp: 204";
+		rLen = 0;
+		rLoc = 5935;
+		rType = 0;
+		vrLen = 964;
+		vrLoc = 3540;
+	};
+	AFAC4ECD0B4C437900D59661 /* PBXTextBookmark */ = {
+		isa = PBXTextBookmark;
+		fRef = AF155A2F0A501F84007E1E6E /* CDirectoryService.cpp */;
+		name = "printf(\"%d\", dsStatus);";
+		rLen = 26;
+		rLoc = 9255;
+		rType = 0;
+		vrLen = 814;
+		vrLoc = 8902;
+	};
 }

Modified: PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/project.pbxproj
===================================================================
--- PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/project.pbxproj	2007-01-05 16:57:13 UTC (rev 932)
+++ PyOpenDirectory/trunk/support/PyOpenDirectory.xcodeproj/project.pbxproj	2007-01-05 17:29:27 UTC (rev 933)
@@ -17,23 +17,6 @@
 		AF155AFE0A502C09007E1E6E /* CFStringUtil.cpp in Sources */ = {isa = PBXBuildFile; fileRef = AF155AFC0A502C09007E1E6E /* CFStringUtil.cpp */; };
 /* End PBXBuildFile section */
 
-/* Begin PBXBuildStyle section */
-		356A20860A65924600725179 /* Development */ = {
-			isa = PBXBuildStyle;
-			buildSettings = {
-				COPY_PHASE_STRIP = NO;
-			};
-			name = Development;
-		};
-		356A20870A65924600725179 /* Deployment */ = {
-			isa = PBXBuildStyle;
-			buildSettings = {
-				COPY_PHASE_STRIP = YES;
-			};
-			name = Deployment;
-		};
-/* End PBXBuildStyle section */
-
 /* Begin PBXCopyFilesBuildPhase section */
 		8DD76F690486A84900D96B5E /* CopyFiles */ = {
 			isa = PBXCopyFilesBuildPhase;
@@ -140,15 +123,12 @@
 		08FB7793FE84155DC02AAC07 /* Project object */ = {
 			isa = PBXProject;
 			buildConfigurationList = 1DEB923508733DC60010E9CD /* Build configuration list for PBXProject "PyOpenDirectory" */;
-			buildSettings = {
-			};
-			buildStyles = (
-				356A20860A65924600725179 /* Development */,
-				356A20870A65924600725179 /* Deployment */,
-			);
+			compatibilityVersion = "Xcode 2.4";
 			hasScannedForEncodings = 1;
 			mainGroup = 08FB7794FE84155DC02AAC07 /* PyOpenDirectory */;
 			projectDirPath = "";
+			projectRoot = "";
+			shouldCheckCompatibility = 1;
 			targets = (
 				8DD76F620486A84900D96B5E /* PyOpenDirectory */,
 			);

Modified: PyOpenDirectory/trunk/support/test.cpp
===================================================================
--- PyOpenDirectory/trunk/support/test.cpp	2007-01-05 16:57:13 UTC (rev 932)
+++ PyOpenDirectory/trunk/support/test.cpp	2007-01-05 17:29:27 UTC (rev 933)
@@ -28,66 +28,23 @@
 
 tDirReference gDirRef = NULL;
 
-void ListNodes ( void );
-void FindNodes ( char* inNodePath );
-void NodeInfo ( const tDirNodeReference nodeRef );
-long MyOpenDirNode ( tDirNodeReference *outNodeRef, char* inNodePath );
-long GetRecordList ( const tDirNodeReference nodeRef );
 char* CStringFromCFString(CFStringRef str);
 void PrintDictionaryDictionary(const void* key, const void* value, void* ref);
 void PrintDictionary(const void* key, const void* value, void* ref);
 void PrintArrayArray(CFMutableArrayRef list);
-void PrintArray(CFMutableArrayRef list);
-void PrintNodeName ( tDataListPtr inNode );
-void CheckUser(CDirectoryService* dir, const char* user);
-void CheckGroup(CDirectoryService* dir, const char* grp);
-void CheckResource(CDirectoryService* dir, const char* rsrc);
-void UserAttributes(CDirectoryService* dir, const char* user);
+void PrintArray(CFArrayRef list);
 void AuthenticateUser(CDirectoryService* dir, const char* user, const char* pswd);
 
 int main (int argc, const char * argv[]) {
-#if 0
-    // insert code here...
-	long dirStatus = eDSNoErr;
-	tDirNodeReference nodeRef = NULL;
-    dirStatus = dsOpenDirService( &gDirRef );
-    if ( dirStatus == eDSNoErr )
-    {
-        //ListNodes();
-		//FindNodes("/LDAPv3/webboserver.apple.com");
-		
-        dirStatus = MyOpenDirNode( &nodeRef, "/LDAPv3/webboserver.apple.com" );
-        if ( dirStatus == eDSNoErr )
-        {
-			//	NodeInfo(nodeRef);
-			GetRecordList( nodeRef );
-            dsCloseDirNode( nodeRef );
-        }
-    }
-    if ( gDirRef != NULL )
-    {
-        dirStatus = dsCloseDirService( gDirRef );
-    }
-#else
     
-	CDirectoryService* dir = new CDirectoryService("/LDAPv3/webboserver.apple.com");
-	CFMutableArrayRef list = dir->ListResources();
-	if (list != NULL)
-	{
-		printf("\n*** Users: %d ***\n", CFArrayGetCount(list));
-		//PrintArrayArray(list);
-		//CFRelease(list);
-	}
-	else
-	{
-		printf("No Users returned");
-	}
+	CDirectoryService* dir = new CDirectoryService("/Search");
 
-	CFMutableArrayRef users = CFArrayCreateMutable(kCFAllocatorDefault, 0, &kCFTypeArrayCallBacks);
-	for(CFIndex i = 0; i < CFArrayGetCount(list); i++)
-		CFArrayAppendValue(users, CFArrayGetValueAtIndex((CFArrayRef)CFArrayGetValueAtIndex(list, i), 0));
-
-	CFMutableDictionaryRef dict = dir->ListResourcesWithAttributes(users);
+	CFStringRef strings[2];
+	strings[0] = CFSTR(kDS1AttrDistinguishedName);
+	strings[1] = CFSTR(kDS1AttrGeneratedUID);
+	CFArrayRef array = CFArrayCreate(kCFAllocatorDefault, (const void **)strings, 2, &kCFTypeArrayCallBacks);
+                        
+	CFMutableDictionaryRef dict = dir->ListAllRecordsWithAttributes(kDSStdRecordTypeUsers, array);
 	if (dict != NULL)
 	{
 		printf("\n*** Users: %d ***\n", CFDictionaryGetCount(dict));
@@ -96,96 +53,41 @@
 	}
 	else
 	{
-		printf("No Users returned");
+		printf("\nNo Users returned\n");
 	}
-#if 0
-	list = dir->ListGroups();
-	if (list != NULL)
+	CFRelease(array);
+
+	strings[0] = CFSTR(kDSNAttrGroupMembers);
+	strings[1] = CFSTR(kDS1AttrGeneratedUID);
+	array = CFArrayCreate(kCFAllocatorDefault, (const void **)strings, 2, &kCFTypeArrayCallBacks);
+                        
+	dict = dir->ListAllRecordsWithAttributes(kDSStdRecordTypeGroups, array);
+	if (dict != NULL)
 	{
-		printf("\n*** Groups ***\n");
-		PrintArrayArray(list);
-		CFRelease(list);
+		printf("\n*** Groups: %d ***\n", CFDictionaryGetCount(dict));
+		CFDictionaryApplyFunction(dict, PrintDictionaryDictionary, NULL);
+		CFRelease(dict);
 	}
 	else
 	{
-		printf("No Groups returned");
+		printf("\nNo Groups returned\n");
 	}
-	list = dir->ListResources();
-	if (list != NULL)
-	{
-		printf("\n*** Resources ***\n");
-		PrintArrayArray(list);
-		CFRelease(list);
-	}
-	else
-	{
-		printf("No Resources returned");
-	}
+	CFRelease(array);
+
+	AuthenticateUser(dir, "cdaboo", "appledav1234");
+	AuthenticateUser(dir, "cdaboo", "appledav6585");
 	
-	CheckUser(dir, "cyrusdaboo");
-	CheckUser(dir, "chris");
-	CheckGroup(dir, "sangriafest");
-	CheckGroup(dir, "cyrusdaboo");
-	CheckResource(dir, "Attitude Adjuster");
-	CheckResource(dir, "cyrusdaboo");
-	
-	AuthenticateUser(dir, "cyrusdaboo", "54321");
-	CFMutableArrayRef list = dir->ListUsers();
-	PrintArrayArray(list);
-	CFRelease(list);
-	UserAttributes(dir, "cyrusdaboo");
-	UserAttributes(dir, "oliverdaboo");
-#endif
-	
-#if 0
-	unsigned long total = 10;
-	time_t start = time(NULL);
-	for(unsigned long i = 0; i < total; i++)
-		//dir->UserAttributes("cyrusdaboo");
-		dir->ListUsers();
-	time_t end = time(NULL);
-	float diff = (end - start);
-	printf("Total time: %f, average time: %f", diff, diff/total);
-	delete dir;
-#endif
-	
-#endif
-	
 	return 0;
 }
 
 void AuthenticateUser(CDirectoryService* dir, const char* user, const char* pswd)
 {
-	if (dir->AuthenticateUser(user, pswd))
+	if (dir->AuthenticateUserBasic(user, pswd))
 		printf("Authenticated user: %s\n", user);
 	else
 		printf("Not Authenticated user: %s\n", user);
 }
 
-void CheckUser(CDirectoryService* dir, const char* user)
-{
-	if (dir->CheckUser(user))
-		printf("Found user: %s\n", user);
-	else
-		printf("Not Found user: %s\n", user);
-}
-
-void CheckGroup(CDirectoryService* dir, const char* grp)
-{
-	if (dir->CheckGroup(grp))
-		printf("Found user: %s\n", grp);
-	else
-		printf("Not Found user: %s\n", grp);
-}
-
-void CheckResource(CDirectoryService* dir, const char* rsrc)
-{
-	if (dir->CheckResource(rsrc))
-		printf("Found user: %s\n", rsrc);
-	else
-		printf("Not Found user: %s\n", rsrc);
-}
-
 void CFDictionaryIterator(const void* key, const void* value, void* ref)
 {
 	CFStringRef strkey = (CFStringRef)key;
@@ -201,265 +103,6 @@
 	free(pystrvalue);
 }
 
-void UserAttributes(CDirectoryService* dir, const char* user)
-{
-	CFMutableDictionaryRef dict = dir->UserAttributes(user);
-	if (dict != NULL)
-	{
-		printf("\nAttributes for %s\n", user);
-		CFDictionaryApplyFunction(dict, CFDictionaryIterator, NULL);
-		CFRelease(dict);
-	}
-}
-
-void ListNodes ( void ) {
-    bool done = false;
-    long dirStatus = eDSNoErr;
-    unsigned long index = 0;
-    unsigned long nodeCount = 0;
-    unsigned long bufferCount = 0;
-    tDataBufferPtr dataBuffer = NULL;
-    tDataListPtr nodeName = NULL;
-    tContextData context = NULL;
-	
-    dirStatus = dsGetDirNodeCount( gDirRef, &nodeCount );
-    printf( "Registered node count is: %lu\n", nodeCount  );
-    if ( (dirStatus == eDSNoErr) && (nodeCount != 0) )
-    {
-        //Allocate a 32k buffer.
-        dataBuffer = dsDataBufferAllocate( gDirRef, 32 * 1024 );
-        if ( dataBuffer != NULL )
-        {
-            while ( (dirStatus == eDSNoErr) && (done ==  false) )
-            {
-                dirStatus = dsGetDirNodeList( gDirRef, dataBuffer,  &bufferCount,  &context );
-                if ( dirStatus == eDSNoErr )
-                {
-                    for ( index = 1; index <= bufferCount; index++  )
-                    {
-                        dirStatus = dsGetDirNodeName( gDirRef, dataBuffer,  index,  &nodeName );
-                        if ( dirStatus == eDSNoErr )
-                        {
-                            printf( "#%4ld ", index );
-                            PrintNodeName( nodeName );
-                            //Deallocate the data list containing  the node name.
-                            dirStatus = dsDataListDeallocate( gDirRef,  nodeName );
-                            free(nodeName);
-                        }
-                        else
-                        {
-                            printf("dsGetDirNodeName error  = %ld\n", dirStatus );
-                        }
-                    }
-                }
-                done = (context == NULL);
-            }
-            if (context != NULL)
-            {
-                dsReleaseContinueData( gDirRef, context );
-            }
-            dsDataBufferDeAllocate( gDirRef, dataBuffer );
-            dataBuffer = NULL;
-        }
-    }
-} // ListNodes
-
-void FindNodes ( char* inNodePath ){
-    bool done = false;
-    long dirStatus = eDSNoErr;
-    unsigned long index = 0;
-    unsigned long bufferCount = 0;
-    tDataBufferPtr dataBuffer = NULL;
-    tDataListPtr nodeName = NULL;
-    tContextData context = NULL;
-    nodeName = dsBuildFromPath( gDirRef, inNodePath, "/");
-    if ( nodeName != NULL )
-    {
-        //Allocate a 32k buffer.
-        dataBuffer = dsDataBufferAllocate( gDirRef, 32 * 1024 );
-        if ( dataBuffer != NULL )
-        {
-            while ( (dirStatus == eDSNoErr) && (done ==  false) )
-            {
-                dirStatus = dsFindDirNodes( gDirRef, dataBuffer,  nodeName,  eDSStartsWith, &bufferCount, &context );
-                if ( dirStatus == eDSNoErr )
-                {
-                    for ( index = 1; index <= bufferCount; index++  )
-                    {
-                        dirStatus = dsGetDirNodeName( gDirRef, dataBuffer,  index,  &nodeName );
-                        if ( dirStatus == eDSNoErr )
-                        {
-                            printf( "#%4ld ", index );
-                            PrintNodeName( nodeName );
-                            //Deallocate the nodes.
-                            dirStatus = dsDataListDeallocate( gDirRef,  nodeName );
-                            free(nodeName);
-                        }
-                        else
-                        {
-                            printf("dsGetDirNodeName error  = %ld\n", dirStatus );
-                        }
-                    }
-                }
-                done = (context == NULL);
-            }
-            dirStatus = dsDataBufferDeAllocate( gDirRef, dataBuffer  );
-            dataBuffer = NULL;
-        }
-    }
-} // FindNodes
-
-void NodeInfo ( const tDirNodeReference nodeRef ){
-    bool done = false;
-    long dirStatus = eDSNoErr;
-    unsigned long index = 0;
-    unsigned long bufferCount = 0;
-    tDataBufferPtr dataBuffer = NULL;
-    tDataListPtr nodeName = NULL;
-    tAttributeListRef attrListRef = NULL;
-    unsigned long count = 0;
-    tDataList attrTypes;
-    tContextData context = NULL;
-    {
-        //Allocate a 32k buffer.
-        dataBuffer = dsDataBufferAllocate( gDirRef, 32 * 1024 );
-        if ( dataBuffer != NULL )
-        {
-            while ( (dirStatus == eDSNoErr) && (done ==  false) )
-            {
-				dirStatus = dsBuildListFromStringsAlloc ( gDirRef, &attrTypes,  kDSNAttrRecordType, NULL );
-				dirStatus = dsGetDirNodeInfo(nodeRef, &attrTypes, dataBuffer, false, &count, &attrListRef, &context);
-                if ( dirStatus == eDSNoErr )
-                {
-                    for ( index = 1; index <= count; index++  )
-                    {
-						tAttributeValueListRef 	valueRef		= 0;
-						tAttributeEntryPtr 		pAttrEntry		= NULL;
-						tAttributeValueEntryPtr	pValueEntry		= NULL;
-						dirStatus = dsGetAttributeEntry(nodeRef, dataBuffer, attrListRef, index, &valueRef, &pAttrEntry);
-						if ( dirStatus != eDSNoErr )
-							break;
-                    }
-                }
-                done = (context == NULL);
-            }
-			dsDataListDeallocate ( gDirRef, &attrTypes );
-            dirStatus = dsDataBufferDeAllocate( gDirRef, dataBuffer  );
-            dataBuffer = NULL;
-        }
-    }
-} // FindNodes
-
-long MyOpenDirNode ( tDirNodeReference *outNodeRef, char* inNodePath )
-{
-    long dirStatus = eDSNoErr;
-    char nodeName[ 256 ] = "\0";
-    tDataListPtr nodePath = NULL;
-    strncpy( nodeName, inNodePath, 256 );
-    printf( "Opening: %s.\n", nodeName );
-    nodePath = dsBuildFromPath( gDirRef, nodeName, "/"  );
-    if ( nodePath != NULL )
-    {
-        dirStatus = dsOpenDirNode( gDirRef, nodePath, outNodeRef  );
-        if ( dirStatus == eDSNoErr )
-        {
-            printf( "Open succeeded. Node Reference = %lu\n",  (unsigned  long)outNodeRef );
-        }
-        else
-        {
-            printf( "Open node failed. Err = %ld\n", dirStatus  );
-        }
-    }
-    dsDataListDeallocate( gDirRef, nodePath );
-    free( nodePath );
-    return( dirStatus );
-} // MyOpenDirNode
-
-long GetRecordList ( const tDirNodeReference nodeRef )
-{
-    unsigned long i = 0;
-    unsigned long j = 0;
-    unsigned long k = 0;
-    long dirStatus = eDSNoErr;
-    unsigned long recCount = 0; // Get all records.
-    tDataBufferPtr dataBuffer = NULL;
-    tContextData context = NULL;
-    tAttributeListRef attrListRef = NULL;
-    tAttributeValueListRef valueRef = NULL;
-    tRecordEntry *pRecEntry = NULL;
-    tAttributeEntry *pAttrEntry = NULL;
-    tAttributeValueEntry *pValueEntry = NULL;
-    tDataList recNames;
-    tDataList recTypes;
-    tDataList attrTypes;
-    dataBuffer = dsDataBufferAllocate( gDirRef, 2 * 1024 ); // allocate  a 2k buffer
-    if ( dataBuffer != NULL )
-    {
-		CFMutableArrayRef list;
-		
-		list = CFArrayCreateMutable(kCFAllocatorDefault, 0, NULL);
-		
-        // For readability, the sample code does not check dirStatus  after 
-        // each call, but 
-        // your code should.
-        dirStatus = dsBuildListFromStringsAlloc ( gDirRef, &recNames,  kDSRecordsAll, NULL );
-        dirStatus = dsBuildListFromStringsAlloc ( gDirRef, &recTypes,  kDSStdRecordTypeUsers, NULL );
-        dirStatus = dsBuildListFromStringsAlloc ( gDirRef, &attrTypes,  kDSNAttrRecordName, NULL );
-        do
-        {
-            dirStatus = dsGetRecordList( nodeRef, dataBuffer, &recNames,  eDSExact,  &recTypes, &attrTypes, false, &recCount, &context  );
-            for ( i = 1; i <= recCount; i++ )
-            {
-				char* recname = NULL;
-				CFStringRef str;
-				
-                dirStatus = dsGetRecordEntry( nodeRef, dataBuffer,  i, &attrListRef,  &pRecEntry );
-				dirStatus = dsGetRecordNameFromEntry(pRecEntry, &recname);
-				str = CFStringCreateWithCString(kCFAllocatorDefault, recname, kCFStringEncodingUTF8);
-				free(recname);
-				if (str != NULL)
-				{
-					CFArrayAppendValue(list, str);
-					//CFRelease(str);
-				}
-                for ( j = 1; j <= pRecEntry->fRecordAttributeCount;  j++ )
-                {
-                    dirStatus = dsGetAttributeEntry( nodeRef, dataBuffer,  attrListRef, j, &valueRef, &pAttrEntry );
-                    for ( k = 1; k <= pAttrEntry->fAttributeValueCount;  k++ )
-                    {
-                        dirStatus = dsGetAttributeValue( nodeRef,  dataBuffer, k,  valueRef, &pValueEntry );
-                        printf( "%s\t- %lu\n", pValueEntry->fAttributeValueData.fBufferData, pValueEntry->fAttributeValueID  );
-                        dirStatus = dsDeallocAttributeValueEntry(  gDirRef,  pValueEntry );
-                        pValueEntry = NULL;
-                        // Deallocate pAttrEntry, pValueEntry, and  pRecEntry
-                        // by calling dsDeallocAttributeEntry,
-                        // dsDeallocAttributeValueEntry, and
-                        // dsDeallocRecordEntry, respectively.
-                    }
-                    dirStatus = dsCloseAttributeValueList( valueRef  );
-                    valueRef = NULL;
-                    dirStatus = dsDeallocAttributeEntry( gDirRef,  pAttrEntry);
-                    pAttrEntry = NULL;
-                }
-                dirStatus = dsCloseAttributeList( attrListRef );
-                attrListRef = NULL;
-                dirStatus = dsDeallocRecordEntry( gDirRef, pRecEntry  );
-                pRecEntry = NULL;
-            }
-        } while (context != NULL); // Loop until all data has been  obtained.
-								   // Call dsDataListDeallocate to deallocate recNames, recTypes,  and
-								   // attrTypes.
-								   // Deallocate dataBuffer by calling dsDataBufferDeAllocate.
-		dsDataListDeallocate ( gDirRef, &recNames );
-		dsDataListDeallocate ( gDirRef, &recTypes );
-		dsDataListDeallocate ( gDirRef, &attrTypes );
-		dsDataBufferDeAllocate ( gDirRef, dataBuffer );
-		dataBuffer = NULL;
-		
-    }
-    return dirStatus;
-} // GetRecordList
-
 char* CStringFromCFString(CFStringRef str)
 {
 	const char* bytes = CFStringGetCStringPtr(str, kCFStringEncodingUTF8);
@@ -492,9 +135,19 @@
 void PrintDictionary(const void* key, const void* value, void* ref)
 {
 	CFStringUtil strkey((CFStringRef)key);
-	CFStringUtil strvalue((CFStringRef)value);
+	if (CFGetTypeID((CFTypeRef)value) == CFStringGetTypeID())
+	{
+		CFStringUtil strvalue((CFStringRef)value);
 
-	printf("Key: \"%s\"; Value: \"%s\"\n", strkey.temp_str(), strvalue.temp_str());
+		printf("Key: \"%s\"; Value: \"%s\"\n", strkey.temp_str(), strvalue.temp_str());
+	}
+	else if(CFGetTypeID((CFTypeRef)value) == CFArrayGetTypeID())
+	{
+		CFArrayRef arrayvalue = (CFArrayRef)value;
+		printf("Key: \"%s\"; Value: Array:\n", strkey.temp_str());
+		PrintArray(arrayvalue);
+		printf("---\n");
+	}
 }
 
 CFComparisonResult CompareRecordListValues(const void *val1, const void *val2, void *context)
@@ -527,7 +180,7 @@
 	}
 }
 
-void PrintArray(CFMutableArrayRef list)
+void PrintArray(CFArrayRef list)
 {
 	//CFArraySortValues(list, CFRangeMake(0, CFArrayGetCount(list)), (CFComparatorFunction)CFStringCompare, NULL);
 	for(CFIndex i = 0; i < CFArrayGetCount(list); i++)
@@ -548,14 +201,3 @@
 		}
 	}
 }
-
-void PrintNodeName ( tDataListPtr inNode ) {
-    char* pPath;
-    pPath = dsGetPathFromList( gDirRef, inNode, "/" );
-    printf( "%s\n", pPath );
-    if ( pPath != NULL )
-    {
-        free( pPath );
-        pPath = NULL;
-    }
-} // PrintNodeName

Modified: PyOpenDirectory/trunk/test.py
===================================================================
--- PyOpenDirectory/trunk/test.py	2007-01-05 16:57:13 UTC (rev 932)
+++ PyOpenDirectory/trunk/test.py	2007-01-05 17:29:27 UTC (rev 933)
@@ -20,69 +20,42 @@
 import dsattributes
 import time
 
-ref = opendirectory.odInit("/LDAPv3/webboserver.apple.com")
-if ref is None:
-	print "Failed odInit"
-else:
-	print "OK odInit"
-
-list = opendirectory.listUsers(ref)
-if list is None:
-	print "Failed listUsers"
-else:
-	for i in list:
-		print i
-
-def CheckUser(user):
-	if opendirectory.checkUser(ref, user):
-		print "Found User: %s" % (user,)
+try:
+	ref = opendirectory.odInit("/Search")
+	if ref is None:
+		print "Failed odInit"
 	else:
-		print "Not Found User: %s" % (user,)
-
-def CheckGroup(grp):
-	if opendirectory.checkGroup(ref, grp):
-		print "Found Group: %s" % (grp,)
+		print "OK odInit"
+	
+	d = opendirectory.listAllRecordsWithAttributes(ref, dsattributes.kDSStdRecordTypeUsers,
+												   [dsattributes.kDS1AttrGeneratedUID, dsattributes.kDS1AttrDistinguishedName,])
+	if d is None:
+		print "Failed to list users"
 	else:
-		print "Not Found Group: %s" % (grp,)
-
-def CheckResource(rsrc):
-	if opendirectory.checkResource(ref, rsrc):
-		print "Found Resource: %s" % (rsrc,)
+		names = [v for v in d.iterkeys()]
+		names.sort()
+		for n in names:
+			print "Name: %s" % n
+			print "dict: %s" % str(d[n])
+	
+	d = opendirectory.listAllRecordsWithAttributes(ref, dsattributes.kDSStdRecordTypeGroups,
+												   [dsattributes.kDS1AttrGeneratedUID, dsattributes.kDSNAttrGroupMembers,])
+	if d is None:
+		print "Failed to list groups"
 	else:
-		print "Not Found Resource: %s" % (rsrc,)
+		names = [v for v in d.iterkeys()]
+		names.sort()
+		for n in names:
+			print "Name: %s" % n
+			print "dict: %s" % str(d[n])
+	
+	if opendirectory.authenticateUserBasic(ref, "test", "test"):
+		print "Authenticated user"
+	else:
+		print "Failed to authenticate user"
+	
+	ref = None
+except opendirectory.ODError, ex:
+	print ex
 
-#CheckUser("cyrusdaboo");
-#CheckUser("chris");
-#CheckGroup("sangriafest");
-#CheckGroup("cyrusdaboo");
-#CheckResource("Attitude Adjuster");
-#CheckResource("cyrusdaboo");
-#
-#CheckUser("steevef\xc3\xbchr")
-#CheckUser("steevefu\xcc\x88hr")
-#
-
-dict = opendirectory.listGroupsWithAttributes(ref, [i[0] for i in list])
-names = [v for v in dict.iterkeys()]
-names.sort()
-for n in names:
-	print "Name: %s" % n
-	print "dict: %s" % str(dict[n])
-
-#
-#dict = opendirectory.groupAttributes(ref, "admin")
-#print dict
-#
-#print dsattributes.attrRealName
-
-#if False:
-#	t = time.time()
-#	total = 10
-#	for i in range(total):
-#		opendirectory.userAttributes(ref, "cyrusdaboo")
-#	t = time.time() - t
-#	print "Total time: %f, average time: %f" % (t, t/total)
-
-ref = None
-
 print "Done."

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20070105/310869b8/attachment.html


More information about the calendarserver-changes mailing list