[CalendarServer-changes] [10886] CalendarServer/branches/users/gaya/directorybacker

source_changes at macosforge.org source_changes at macosforge.org
Mon Mar 11 13:20:39 PDT 2013


Revision: 10886
          http://trac.calendarserver.org//changeset/10886
Author:   gaya at apple.com
Date:     2013-03-11 13:20:39 -0700 (Mon, 11 Mar 2013)
Log Message:
-----------
use     "OpenDirectoryModule": "calendarserver.platform.darwin.od.opendirectory"

Modified Paths:
--------------
    CalendarServer/branches/users/gaya/directorybacker/conf/carddav-ldaptest.plist
    CalendarServer/branches/users/gaya/directorybacker/conf/carddav-ldaptest2.plist
    CalendarServer/branches/users/gaya/directorybacker/twistedcaldav/directory/opendirectorybacker.py
    CalendarServer/branches/users/gaya/directorybacker/twistedcaldav/stdconfig.py

Modified: CalendarServer/branches/users/gaya/directorybacker/conf/carddav-ldaptest.plist
===================================================================
--- CalendarServer/branches/users/gaya/directorybacker/conf/carddav-ldaptest.plist	2013-03-10 06:57:22 UTC (rev 10885)
+++ CalendarServer/branches/users/gaya/directorybacker/conf/carddav-ldaptest.plist	2013-03-11 20:20:39 UTC (rev 10886)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 <!--
-    Copyright (c) 2006-2012 Apple Inc. All rights reserved.
+    Copyright (c) 2006-2013 Apple Inc. All rights reserved.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -167,11 +167,6 @@
     <key>MaxAllowedInstances</key>
     <integer>3000</integer>
 
-    <!-- Maximum number of instances allowed for a single RRULE -->
-    <!-- 0 for no limit -->
-    <key>MaxInstancesForRRULE</key>
-    <integer>400</integer>
-
     <!--
         Directory service
 
@@ -220,14 +215,17 @@
 
       <key>params</key>
       <dict>
-        <key>restrictEnabledRecords</key>
-        <false/>
-        <key>restrictToGroup</key>
-        <string>odtestgrouptop</string>
+        <key>recordTypes</key>
+        <array>
+           <string>users</string>
+           <string>groups</string>
+           <string>locations</string>
+           <string>resources</string>
+        </array>
         <key>cacheTimeout</key>
-        <integer>30</integer>
+        <integer>10</integer>
         <key>uri</key>
-        <string>ldap://example.com/</string>
+        <string>ldap://ldapserver.example.com/</string>
         <key>tls</key>
         <false/>
         <key>tlsCACertFile</key>
@@ -239,92 +237,118 @@
         <key>credentials</key>
         <dict>
           <key>dn</key>
-          <string></string>
+          <string>uid=admin,ou=people,o=example.com</string>
           <key>password</key>
-          <string></string>
+          <string>PASSWORD</string>
         </dict>
-        <key>authMethod</key>
-        <string>LDAP</string>
         <key>rdnSchema</key>
         <dict>
           <key>base</key>
-          <string>dc=example,dc=com</string>
+          <string>o=example.com</string>
           <key>guidAttr</key>
-          <string>entryUUID</string>
+          <string>GUID</string>
           <key>users</key>
           <dict>
             <key>rdn</key>
-            <string>cn=users</string>
-            <key>attr</key>
-            <string>uid</string>
-            <key>emailSuffix</key>
-            <string></string>
-            <key>filter</key>
-            <string></string>
-            <key>loginEnabledAttr</key>
-            <string></string>
-            <key>loginEnabledValue</key>
-            <string>yes</string>
+            <string>ou=people</string>
             <key>mapping</key>
             <dict>
-              <key>recordName</key>
-              <string>uid</string>
-              <key>fullName</key>
-              <string>cn</string>
-              <key>emailAddresses</key>
-              <string>mail</string>
-              <key>firstName</key>
-              <string>givenName</string>
-              <key>lastName</key>
-              <string>sn</string>
+                <key>recordName</key>
+                <string>uid</string>
+                <key>fullName</key>
+                <string>cn</string>
+                <key>emailAddresses</key>
+                <array>
+                    <string>mail</string>
+                    <string>mailAlias</string>
+                </array>
+                <key>firstName</key>
+                <string>givenName</string>
+                <key>lastName</key>
+                <string>sn</string>
             </dict>
           </dict>
           <key>groups</key>
           <dict>
             <key>rdn</key>
-            <string>cn=groups</string>
-            <key>attr</key>
-            <string>cn</string>
-            <key>emailSuffix</key>
-            <string></string>
-            <key>filter</key>
-            <string></string>
+            <string>ou=groups</string>
             <key>mapping</key>
             <dict>
-              <key>recordName</key>
-              <string>cn</string>
-              <key>fullName</key>
-              <string>cn</string>
-              <key>emailAddresses</key>
-              <string>mail</string>
-              <key>firstName</key>
-              <string>givenName</string>
-              <key>lastName</key>
-              <string>sn</string>
+                <key>recordName</key>
+                <string>cn</string>
+                <key>fullName</key>
+                <string>cn</string>
+                <key>emailAddresses</key>
+                <array>
+                    <string>mail</string>
+                    <string>mailAlias</string>
+                </array>
+                <key>firstName</key>
+                <string></string>
+                <key>lastName</key>
+                <string></string>
             </dict>
           </dict>
+          <key>locations</key>
+          <dict>
+            <key>rdn</key>
+            <string>ou=locations</string>
+            <key>mapping</key>
+            <dict>
+                <key>recordName</key>
+                <string>cn</string>
+                <key>fullName</key>
+                <string>cn</string>
+                <key>emailAddresses</key>
+                <array>
+                </array>
+                <key>firstName</key>
+                <string></string>
+                <key>lastName</key>
+                <string></string>
+            </dict>
+          </dict>
+          <key>resources</key>
+          <dict>
+            <key>rdn</key>
+            <string>ou=resources</string>
+            <key>mapping</key>
+            <dict>
+                <key>recordName</key>
+                <string>cn</string>
+                <key>fullName</key>
+                <string>cn</string>
+                <key>emailAddresses</key>
+                <array>
+                </array>
+                <key>firstName</key>
+                <string></string>
+                <key>lastName</key>
+                <string></string>
+            </dict>
+          </dict>
         </dict>
         <key>groupSchema</key>
         <dict>
           <key>membersAttr</key>
-          <string>apple-group-memberguid</string>
+          <string>uniqueMember</string>
           <key>nestedGroupsAttr</key>
-          <string>apple-group-nestedgroup</string>
+          <string></string>
           <key>memberIdAttr</key>
-          <string>apple-generateduid</string>
+          <string></string>
         </dict>
         <key>resourceSchema</key>
         <dict>
-          <key>resourceInfoAttr</key>
-          <string>apple-resource-info</string>
-          <key>autoScheduleAttr</key>
-          <string></string>
-          <key>autoScheduleEnabledValue</key>
-          <string>yes</string>
-          <key>proxyAttr</key>
-          <string></string>
-          <key>readOnlyProxyAttr</key>
-          <string></string>
+         <key>resourceInfoAttr</key>
+         <string></string>
+         <key>autoScheduleAttr</key>
+         <string></string>
+         <key>autoScheduleEnabledValue</key>
+         <string></string>
+         <key>proxyAttr</key>
+         <string></string>
+         <key>readOnlyProxyAttr</key>
+         <string></string>
         </dict>
       </dict>
     </dict>
@@ -483,6 +507,8 @@
       <dict>
         <key>Enabled</key>
         <true/>
+        <key>AllowedOverWireUnencrypted</key> <!-- advertised over non SSL? -->
+        <true/>
       </dict>
 
       <!-- Digest challenge/response -->
@@ -490,6 +516,8 @@
       <dict>
         <key>Enabled</key>
         <true/>
+        <key>AllowedOverWireUnencrypted</key> <!-- advertised over non SSL? -->
+        <true/>
         <key>Algorithm</key>
         <string>md5</string>
         <key>Qop</key>
@@ -501,6 +529,8 @@
       <dict>
         <key>Enabled</key>
         <true/>
+        <key>AllowedOverWireUnencrypted</key> <!-- advertised over non SSL? -->
+        <true/>
         <key>ServicePrincipal</key>
         <string></string>
       </dict>
@@ -543,7 +573,7 @@
 
     <!-- Log levels -->
     <key>DefaultLogLevel</key>
-    <string>debug</string> <!-- debug, info, warn, error -->
+    <string>info</string> <!-- debug, info, warn, error -->
 
     <!-- Log level overrides for specific functionality -->
     <key>LogLevels</key>
@@ -626,21 +656,13 @@
       <key>CoalesceSeconds</key>
       <integer>3</integer>
 
-      <key>InternalNotificationHost</key>
-      <string>localhost</string>
-
-      <key>InternalNotificationPort</key>
-      <integer>62309</integer>
-
       <key>Services</key>
       <dict>
 
-        <key>AMPNotifier</key>
+        <key>AMP</key>
         <dict>
-          <key>Service</key>
-          <string>calendarserver.push.amppush.AMPPushNotifierService</string>
           <key>Enabled</key>
-          <true/>
+          <false/>
           <key>Port</key>
           <integer>62311</integer>
           <key>EnableStaggering</key>
@@ -649,81 +671,6 @@
           <integer>3</integer>
         </dict>
 
-        <key>SimpleLineNotifier</key>
-        <dict>
-          <!-- Simple line notification service (for testing) -->
-          <key>Service</key>
-          <string>twistedcaldav.notify.SimpleLineNotifierService</string>
-          <key>Enabled</key>
-          <false/>
-          <key>Port</key>
-          <integer>62308</integer>
-        </dict>
-
-        <key>XMPPNotifier</key>
-        <dict>
-          <!-- XMPP notification service -->
-          <key>Service</key>
-          <string>twistedcaldav.notify.XMPPNotifierService</string>
-          <key>Enabled</key>
-          <false/>
-
-          <!-- XMPP host and port to contact -->
-          <key>Host</key>
-          <string>xmpp.host.name</string>
-          <key>Port</key>
-          <integer>5222</integer>
-
-          <!-- Jabber ID and password for the server -->
-          <key>JID</key>
-          <string>jid at xmpp.host.name/resource</string>
-          <key>Password</key>
-          <string>password_goes_here</string>
-
-          <!-- PubSub service address -->
-          <key>ServiceAddress</key>
-          <string>pubsub.xmpp.host.name</string>
-
-          <!-- Apple-specific config -->
-          <key>CalDAV</key>
-          <dict>
-              <key>APSBundleID</key>
-              <string></string>
-              <key>SubscriptionURL</key>
-              <string></string>
-          </dict>
-          <key>CardDAV</key>
-          <dict>
-              <key>APSBundleID</key>
-              <string></string>
-              <key>SubscriptionURL</key>
-              <string></string>
-          </dict>
-
-          <key>NodeConfiguration</key>
-          <dict>
-            <key>pubsub#deliver_payloads</key>
-            <string>1</string>
-            <key>pubsub#persist_items</key>
-            <string>1</string>
-          </dict>
-
-          <!-- Sends a presence notification to XMPP server at this interval (prevents disconnect) -->
-          <key>KeepAliveSeconds</key>
-          <integer>120</integer>
-
-          <!-- Sends a pubsub publish to a particular heartbeat node at this interval -->
-          <key>HeartbeatMinutes</key>
-          <integer>30</integer>
-
-          <!-- List of glob-like expressions defining which XMPP JIDs can converse with the server (for debugging) -->
-          <key>AllowedJIDs</key>
-          <array>
-            <!--
-            <string>*.example.com</string>
-             -->
-          </array>
-        </dict>
       </dict>
     </dict>
 
@@ -761,8 +708,8 @@
         <key>AddressPatterns</key>
         <array>
         </array>
-        <key>Servers</key>
-        <string>servertoserver-test.xml</string>
+        <key>RemoteServers</key>
+        <string>remoteservers-test.xml</string>
       </dict>
 
       <!-- iMIP protocol options -->
@@ -869,6 +816,10 @@
 
     <!-- Calendar Drop Box -->
     <key>EnableDropBox</key>
+    <false/>
+
+    <!-- Calendar Managed Attachments -->
+    <key>EnableManagedAttachments</key>
     <true/>
 
     <!-- Private Events -->
@@ -879,6 +830,28 @@
     <key>EnableTimezoneService</key>
     <true/>
 
+    <!-- Standard Timezone Service -->
+    <key>TimezoneService</key>
+    <dict>
+    	<key>Enabled</key>
+    	<true/>
+    	<key>Mode</key>
+    	<string>primary</string>
+    	<key>BasePath</key>
+    	<string></string>
+    	<key>XMLInfoPath</key>
+    	<string></string>
+    	<key>SecondaryService</key>
+    	<dict>
+    		<key>Host</key>
+    		<string></string>
+    		<key>URI</key>
+    		<string></string>
+    		<key>UpdateIntervalMinutes</key>
+    		<integer>1440</integer>
+    	</dict>
+    </dict>
+
     <!-- Batch Upload via POST -->
     <key>EnableBatchUpload</key>
     <true/>
@@ -1013,7 +986,7 @@
       <key>LocalesDirectory</key>
       <string>locales</string>
       <key>Language</key>
-      <string>English</string>
+      <string>en</string>
     </dict>
 
     <!--
@@ -1026,7 +999,7 @@
       <false/>
     -->
     
-    <!-- Open Directory-backed Directory Address Book -->
+    <!-- LDAP-backed Directory Address Book -->
     <key>EnableSearchAddressBook</key>
     <true/>
     <key>DirectoryAddressBook</key>

Modified: CalendarServer/branches/users/gaya/directorybacker/conf/carddav-ldaptest2.plist
===================================================================
--- CalendarServer/branches/users/gaya/directorybacker/conf/carddav-ldaptest2.plist	2013-03-10 06:57:22 UTC (rev 10885)
+++ CalendarServer/branches/users/gaya/directorybacker/conf/carddav-ldaptest2.plist	2013-03-11 20:20:39 UTC (rev 10886)
@@ -1,7 +1,7 @@
 <?xml version="1.0" encoding="UTF-8"?>
 
 <!--
-    Copyright (c) 2006-2012 Apple Inc. All rights reserved.
+    Copyright (c) 2006-2013 Apple Inc. All rights reserved.
 
     Licensed under the Apache License, Version 2.0 (the "License");
     you may not use this file except in compliance with the License.
@@ -167,11 +167,6 @@
     <key>MaxAllowedInstances</key>
     <integer>3000</integer>
 
-    <!-- Maximum number of instances allowed for a single RRULE -->
-    <!-- 0 for no limit -->
-    <key>MaxInstancesForRRULE</key>
-    <integer>400</integer>
-
     <!--
         Directory service
 
@@ -220,14 +215,17 @@
 
       <key>params</key>
       <dict>
-        <key>restrictEnabledRecords</key>
-        <false/>
-        <key>restrictToGroup</key>
-        <string>odtestgrouptop</string>
+        <key>recordTypes</key>
+        <array>
+           <string>users</string>
+           <string>groups</string>
+           <string>locations</string>
+           <string>resources</string>
+        </array>
         <key>cacheTimeout</key>
-        <integer>30</integer>
+        <integer>10</integer>
         <key>uri</key>
-        <string>ldap://example.com/</string>
+        <string>ldap://ldapserver.example.com/</string>
         <key>tls</key>
         <false/>
         <key>tlsCACertFile</key>
@@ -239,92 +237,118 @@
         <key>credentials</key>
         <dict>
           <key>dn</key>
-          <string></string>
+          <string>uid=admin,ou=people,o=example.com</string>
           <key>password</key>
-          <string></string>
+          <string>PASSWORD</string>
         </dict>
-        <key>authMethod</key>
-        <string>LDAP</string>
         <key>rdnSchema</key>
         <dict>
           <key>base</key>
-          <string>dc=example,dc=com</string>
+          <string>o=example.com</string>
           <key>guidAttr</key>
-          <string>entryUUID</string>
+          <string>GUID</string>
           <key>users</key>
           <dict>
             <key>rdn</key>
-            <string>cn=users</string>
-            <key>attr</key>
-            <string>uid</string>
-            <key>emailSuffix</key>
-            <string></string>
-            <key>filter</key>
-            <string></string>
-            <key>loginEnabledAttr</key>
-            <string></string>
-            <key>loginEnabledValue</key>
-            <string>yes</string>
+            <string>ou=people</string>
             <key>mapping</key>
             <dict>
-              <key>recordName</key>
-              <string>uid</string>
-              <key>fullName</key>
-              <string>cn</string>
-              <key>emailAddresses</key>
-              <string>mail</string>
-              <key>firstName</key>
-              <string>givenName</string>
-              <key>lastName</key>
-              <string>sn</string>
+                <key>recordName</key>
+                <string>uid</string>
+                <key>fullName</key>
+                <string>cn</string>
+                <key>emailAddresses</key>
+                <array>
+                    <string>mail</string>
+                    <string>mailAlias</string>
+                </array>
+                <key>firstName</key>
+                <string>givenName</string>
+                <key>lastName</key>
+                <string>sn</string>
             </dict>
           </dict>
           <key>groups</key>
           <dict>
             <key>rdn</key>
-            <string>cn=groups</string>
-            <key>attr</key>
-            <string>cn</string>
-            <key>emailSuffix</key>
-            <string></string>
-            <key>filter</key>
-            <string></string>
+            <string>ou=groups</string>
             <key>mapping</key>
             <dict>
-              <key>recordName</key>
-              <string>cn</string>
-              <key>fullName</key>
-              <string>cn</string>
-              <key>emailAddresses</key>
-              <string>mail</string>
-              <key>firstName</key>
-              <string>givenName</string>
-              <key>lastName</key>
-              <string>sn</string>
+                <key>recordName</key>
+                <string>cn</string>
+                <key>fullName</key>
+                <string>cn</string>
+                <key>emailAddresses</key>
+                <array>
+                    <string>mail</string>
+                    <string>mailAlias</string>
+                </array>
+                <key>firstName</key>
+                <string></string>
+                <key>lastName</key>
+                <string></string>
             </dict>
           </dict>
+          <key>locations</key>
+          <dict>
+            <key>rdn</key>
+            <string>ou=locations</string>
+            <key>mapping</key>
+            <dict>
+                <key>recordName</key>
+                <string>cn</string>
+                <key>fullName</key>
+                <string>cn</string>
+                <key>emailAddresses</key>
+                <array>
+                </array>
+                <key>firstName</key>
+                <string></string>
+                <key>lastName</key>
+                <string></string>
+            </dict>
+          </dict>
+          <key>resources</key>
+          <dict>
+            <key>rdn</key>
+            <string>ou=resources</string>
+            <key>mapping</key>
+            <dict>
+                <key>recordName</key>
+                <string>cn</string>
+                <key>fullName</key>
+                <string>cn</string>
+                <key>emailAddresses</key>
+                <array>
+                </array>
+                <key>firstName</key>
+                <string></string>
+                <key>lastName</key>
+                <string></string>
+            </dict>
+          </dict>
         </dict>
         <key>groupSchema</key>
         <dict>
           <key>membersAttr</key>
-          <string>apple-group-memberguid</string>
+          <string>uniqueMember</string>
           <key>nestedGroupsAttr</key>
-          <string>apple-group-nestedgroup</string>
+          <string></string>
           <key>memberIdAttr</key>
-          <string>apple-generateduid</string>
+          <string></string>
         </dict>
         <key>resourceSchema</key>
         <dict>
-          <key>resourceInfoAttr</key>
-          <string>apple-resource-info</string>
-          <key>autoScheduleAttr</key>
-          <string></string>
-          <key>autoScheduleEnabledValue</key>
-          <string>yes</string>
-          <key>proxyAttr</key>
-          <string></string>
-          <key>readOnlyProxyAttr</key>
-          <string></string>
+         <key>resourceInfoAttr</key>
+         <string></string>
+         <key>autoScheduleAttr</key>
+         <string></string>
+         <key>autoScheduleEnabledValue</key>
+         <string></string>
+         <key>proxyAttr</key>
+         <string></string>
+         <key>readOnlyProxyAttr</key>
+         <string></string>
         </dict>
       </dict>
     </dict>
@@ -483,6 +507,8 @@
       <dict>
         <key>Enabled</key>
         <true/>
+        <key>AllowedOverWireUnencrypted</key> <!-- advertised over non SSL? -->
+        <true/>
       </dict>
 
       <!-- Digest challenge/response -->
@@ -490,6 +516,8 @@
       <dict>
         <key>Enabled</key>
         <true/>
+        <key>AllowedOverWireUnencrypted</key> <!-- advertised over non SSL? -->
+        <true/>
         <key>Algorithm</key>
         <string>md5</string>
         <key>Qop</key>
@@ -501,6 +529,8 @@
       <dict>
         <key>Enabled</key>
         <true/>
+        <key>AllowedOverWireUnencrypted</key> <!-- advertised over non SSL? -->
+        <true/>
         <key>ServicePrincipal</key>
         <string></string>
       </dict>
@@ -543,7 +573,7 @@
 
     <!-- Log levels -->
     <key>DefaultLogLevel</key>
-    <string>debug</string> <!-- debug, info, warn, error -->
+    <string>info</string> <!-- debug, info, warn, error -->
 
     <!-- Log level overrides for specific functionality -->
     <key>LogLevels</key>
@@ -626,21 +656,13 @@
       <key>CoalesceSeconds</key>
       <integer>3</integer>
 
-      <key>InternalNotificationHost</key>
-      <string>localhost</string>
-
-      <key>InternalNotificationPort</key>
-      <integer>62309</integer>
-
       <key>Services</key>
       <dict>
 
-        <key>AMPNotifier</key>
+        <key>AMP</key>
         <dict>
-          <key>Service</key>
-          <string>calendarserver.push.amppush.AMPPushNotifierService</string>
           <key>Enabled</key>
-          <true/>
+          <false/>
           <key>Port</key>
           <integer>62311</integer>
           <key>EnableStaggering</key>
@@ -649,81 +671,6 @@
           <integer>3</integer>
         </dict>
 
-        <key>SimpleLineNotifier</key>
-        <dict>
-          <!-- Simple line notification service (for testing) -->
-          <key>Service</key>
-          <string>twistedcaldav.notify.SimpleLineNotifierService</string>
-          <key>Enabled</key>
-          <false/>
-          <key>Port</key>
-          <integer>62308</integer>
-        </dict>
-
-        <key>XMPPNotifier</key>
-        <dict>
-          <!-- XMPP notification service -->
-          <key>Service</key>
-          <string>twistedcaldav.notify.XMPPNotifierService</string>
-          <key>Enabled</key>
-          <false/>
-
-          <!-- XMPP host and port to contact -->
-          <key>Host</key>
-          <string>xmpp.host.name</string>
-          <key>Port</key>
-          <integer>5222</integer>
-
-          <!-- Jabber ID and password for the server -->
-          <key>JID</key>
-          <string>jid at xmpp.host.name/resource</string>
-          <key>Password</key>
-          <string>password_goes_here</string>
-
-          <!-- PubSub service address -->
-          <key>ServiceAddress</key>
-          <string>pubsub.xmpp.host.name</string>
-
-          <!-- Apple-specific config -->
-          <key>CalDAV</key>
-          <dict>
-              <key>APSBundleID</key>
-              <string></string>
-              <key>SubscriptionURL</key>
-              <string></string>
-          </dict>
-          <key>CardDAV</key>
-          <dict>
-              <key>APSBundleID</key>
-              <string></string>
-              <key>SubscriptionURL</key>
-              <string></string>
-          </dict>
-
-          <key>NodeConfiguration</key>
-          <dict>
-            <key>pubsub#deliver_payloads</key>
-            <string>1</string>
-            <key>pubsub#persist_items</key>
-            <string>1</string>
-          </dict>
-
-          <!-- Sends a presence notification to XMPP server at this interval (prevents disconnect) -->
-          <key>KeepAliveSeconds</key>
-          <integer>120</integer>
-
-          <!-- Sends a pubsub publish to a particular heartbeat node at this interval -->
-          <key>HeartbeatMinutes</key>
-          <integer>30</integer>
-
-          <!-- List of glob-like expressions defining which XMPP JIDs can converse with the server (for debugging) -->
-          <key>AllowedJIDs</key>
-          <array>
-            <!--
-            <string>*.example.com</string>
-             -->
-          </array>
-        </dict>
       </dict>
     </dict>
 
@@ -761,8 +708,8 @@
         <key>AddressPatterns</key>
         <array>
         </array>
-        <key>Servers</key>
-        <string>servertoserver-test.xml</string>
+        <key>RemoteServers</key>
+        <string>remoteservers-test.xml</string>
       </dict>
 
       <!-- iMIP protocol options -->
@@ -869,6 +816,10 @@
 
     <!-- Calendar Drop Box -->
     <key>EnableDropBox</key>
+    <false/>
+
+    <!-- Calendar Managed Attachments -->
+    <key>EnableManagedAttachments</key>
     <true/>
 
     <!-- Private Events -->
@@ -879,6 +830,28 @@
     <key>EnableTimezoneService</key>
     <true/>
 
+    <!-- Standard Timezone Service -->
+    <key>TimezoneService</key>
+    <dict>
+    	<key>Enabled</key>
+    	<true/>
+    	<key>Mode</key>
+    	<string>primary</string>
+    	<key>BasePath</key>
+    	<string></string>
+    	<key>XMLInfoPath</key>
+    	<string></string>
+    	<key>SecondaryService</key>
+    	<dict>
+    		<key>Host</key>
+    		<string></string>
+    		<key>URI</key>
+    		<string></string>
+    		<key>UpdateIntervalMinutes</key>
+    		<integer>1440</integer>
+    	</dict>
+    </dict>
+
     <!-- Batch Upload via POST -->
     <key>EnableBatchUpload</key>
     <true/>
@@ -1013,7 +986,7 @@
       <key>LocalesDirectory</key>
       <string>locales</string>
       <key>Language</key>
-      <string>English</string>
+      <string>en</string>
     </dict>
 
     <!--
@@ -1026,7 +999,7 @@
       <false/>
     -->
     
-    <!-- Open Directory-backed Directory Address Book -->
+    <!-- LDAP-backed Directory Address Book -->
     <key>EnableSearchAddressBook</key>
     <true/>
     <key>DirectoryAddressBook</key>

Modified: CalendarServer/branches/users/gaya/directorybacker/twistedcaldav/directory/opendirectorybacker.py
===================================================================
--- CalendarServer/branches/users/gaya/directorybacker/twistedcaldav/directory/opendirectorybacker.py	2013-03-10 06:57:22 UTC (rev 10885)
+++ CalendarServer/branches/users/gaya/directorybacker/twistedcaldav/directory/opendirectorybacker.py	2013-03-11 20:20:39 UTC (rev 10886)
@@ -62,31 +62,31 @@
     """
 
     baseGUID = "BF07A1A2-5BB5-4A4D-A59A-67260EA7E143"
-    
+
     def __repr__(self):
-        return "<%s %r>" % (self.__class__.__name__, self.realmName, )
+        return "<%s %r>" % (self.__class__.__name__, self.realmName,)
 
     def __init__(self, params):
         self._actuallyConfigure(**params)
 
     def _actuallyConfigure(
-        self, queryPeopleRecords=True, 
-        peopleNode = "/Search/Contacts",
-        queryUserRecords=True, 
-        userNode = "/Search",
-        queryGroupRecords=True, 
-        groupNode = "/Search",
-        maxDSQueryRecords = 0,            # maximum number of records requested for any ds query
-        
-        queryDSLocal = False,             #query in DSLocal -- debug
-        dsLocalCacheTimeout = 30,
-        ignoreSystemRecords = True,
-        
-        fakeETag = True,                  # eTag is not reliable if True 
-                
-        addDSAttrXProperties=False,       # add dsattributes to vcards as "X-" attributes
+        self, queryPeopleRecords=True,
+        peopleNode="/Search/Contacts",
+        queryUserRecords=True,
+        userNode="/Search",
+        queryGroupRecords=True,
+        groupNode="/Search",
+        maxDSQueryRecords=0, # maximum number of records requested for any ds query
+
+        queryDSLocal=False, #query in DSLocal -- debug
+        dsLocalCacheTimeout=30,
+        ignoreSystemRecords=True,
+
+        fakeETag=True, # eTag is not reliable if True 
+
+        addDSAttrXProperties=False, # add dsattributes to vcards as "X-" attributes
         appleInternalServer=False,
-        
+
         additionalAttributes=None,
         allowedAttributes=None,
         searchAttributes=None,
@@ -109,15 +109,15 @@
         self.peopleNode = None
         self.userDirectory = None
         self.userNode = None
-        
 
+
         # get node to record type map
         def addNodesToNodeRecordTypeMap(nodeList, recordType):
             for node in nodeList if isinstance(nodeList, list) else (nodeList,):
                 if not node in nodeRecordTypeMap:
                     nodeRecordTypeMap[node] = []
-                nodeRecordTypeMap[node] += [recordType,]
-            self.recordTypes += [recordType,]
+                nodeRecordTypeMap[node] += [recordType, ]
+            self.recordTypes += [recordType, ]
 
         nodeRecordTypeMap = {}
         self.recordTypes = []
@@ -127,26 +127,26 @@
             addNodesToNodeRecordTypeMap(userNode, dsattributes.kDSStdRecordTypeUsers,)
         if queryGroupRecords:
             addNodesToNodeRecordTypeMap(groupNode, dsattributes.kDSStdRecordTypeGroups,)
-        
+
         # get query info
         nodeDirectoryRecordTypeMap = {}
         self.odModule = namedModule(config.OpenDirectoryModule)
         for node in nodeRecordTypeMap:
-            queryInfo = {"recordTypes":nodeRecordTypeMap[node],}
+            queryInfo = {"recordTypes":nodeRecordTypeMap[node], }
             try:
                 queryInfo["directory"] = self.odModule.odInit(node)
             except self.odModule.ODError, e:
                 self.log_error("Open Directory (node=%s) Initialization error: %s" % (node, e))
                 raise
-            
+
             nodeDirectoryRecordTypeMap[node] = queryInfo
-        
+
         self.nodeDirectoryRecordTypeMap = nodeDirectoryRecordTypeMap
-        
-        
+
+
         # calc realm name
         self.realmName = "+".join(nodeDirectoryRecordTypeMap.keys())
-        
+
         self.queryPeopleRecords = queryPeopleRecords
         self.queryUserRecords = queryUserRecords
         self.queryGroupRecords = queryGroupRecords
@@ -157,11 +157,11 @@
         self.dsLocalCacheTimeout = dsLocalCacheTimeout
 
         self.fakeETag = fakeETag
-                
+
         self.addDSAttrXProperties = addDSAttrXProperties
         self.appleInternalServer = appleInternalServer
-        
-        
+
+
         if searchAttributes is None:
             # this is the intersection of ds default indexed attributes and ABDirectoryQueryResult.vcardPropToDSAttrMap.values()
             # so, not all indexed attributes are below
@@ -183,91 +183,97 @@
         elif not searchAttributes:
             # if search Attributes is [], don't restrict searching (but no binary)
             searchAttributes = ABDirectoryQueryResult.stringDSAttrNames
-        self.log_debug("self.searchAttributes=%s" % (searchAttributes, ))
-        
+        self.log_debug("self.searchAttributes=%s" % (searchAttributes,))
+
         # calculate search map
         vcardPropToSearchableDSAttrMap = {}
         for prop, dsAttributeList in ABDirectoryQueryResult.vcardPropToDSAttrMap.iteritems():
             dsIndexedAttributeList = [attr for attr in dsAttributeList if attr in searchAttributes]
             if len(dsIndexedAttributeList):
                 vcardPropToSearchableDSAttrMap[prop] = dsIndexedAttributeList
-        
+
         self.vcardPropToSearchableDSAttrMap = vcardPropToSearchableDSAttrMap
-        self.log_debug("self.vcardPropToSearchableDSAttrMap=%s" % (self.vcardPropToSearchableDSAttrMap, ))
- 
+        self.log_debug("self.vcardPropToSearchableDSAttrMap=%s" % (self.vcardPropToSearchableDSAttrMap,))
+
         #get attributes required for needed for valid vCard
         requiredAttributes = [attr for prop in ("UID", "FN", "N") for attr in ABDirectoryQueryResult.vcardPropToDSAttrMap[prop]]
-        requiredAttributes += [dsattributes.kDS1AttrModificationTimestamp, dsattributes.kDS1AttrCreationTimestamp,] # for VCardResult DAVPropertyMixIn
+        requiredAttributes += [dsattributes.kDS1AttrModificationTimestamp, dsattributes.kDS1AttrCreationTimestamp, ] # for VCardResult DAVPropertyMixIn
         self.requiredAttributes = list(set(requiredAttributes))
-        self.log_debug("self.requiredAttributes=%s" % (self.requiredAttributes, ))
-           
+        self.log_debug("self.requiredAttributes=%s" % (self.requiredAttributes,))
+
         # get returned attributes
         #allowedAttributes = [dsattributes.kDS1AttrUniqueID,]
         if allowedAttributes:
-            
+
             returnedAttributes = [attr for attr in ABDirectoryQueryResult.allDSQueryAttributes
                                                     if (isinstance(attr, str) and attr in allowedAttributes) or
                                                        (isinstance(attr, tuple) and attr[0] in allowedAttributes)]
-            self.log_debug("allowedAttributes%s" % (allowedAttributes, ))
+            self.log_debug("allowedAttributes%s" % (allowedAttributes,))
         else:
             returnedAttributes = ABDirectoryQueryResult.allDSQueryAttributes
-            
+
         # add required
         returnedAttributes += self.requiredAttributes
-        
+
         if additionalAttributes:
             returnedAttributes += additionalAttributes
-        
+
         if ignoreSystemRecords:
-            returnedAttributes += [dsattributes.kDS1AttrUniqueID,]
+            returnedAttributes += [dsattributes.kDS1AttrUniqueID, ]
         if not queryDSLocal:
-            returnedAttributes += [dsattributes.kDSNAttrMetaNodeLocation,]
+            returnedAttributes += [dsattributes.kDSNAttrMetaNodeLocation, ]
         if queryGroupRecords:
-            returnedAttributes += [dsattributes.kDSNAttrGroupMembers,]
-        
+            returnedAttributes += [dsattributes.kDSNAttrGroupMembers, ]
+
         #for debugging
-        returnedAttributes += [dsattributes.kDSNAttrRecordType,]
+        returnedAttributes += [dsattributes.kDSNAttrRecordType, ]
 
         self.returnedAttributes = list(set(returnedAttributes))
-        self.log_debug("self.returnedAttributes=%s" % (self.returnedAttributes, ))
-              
-        
+        self.log_debug("self.returnedAttributes=%s" % (self.returnedAttributes,))
+
+
         self._dsLocalResults = {}
         self._nextDSLocalQueryTime = 0
-        
 
+
     def createCache(self):
         succeed(None)
 
     def _isSystemRecord(self, recordShortName, recordAttributes):
-        
+
         recordType = recordAttributes.get(dsattributes.kDSNAttrRecordType)
+        if type(recordType) is list:
+            recordType = recordType[0]
         guid = recordAttributes.get(dsattributes.kDS1AttrGeneratedUID)
+        if type(guid) is list:
+            guid = guid[0]
         if guid and guid.startswith("FFFFEEEE-DDDD-CCCC-BBBB-AAAA"):
-            self.log_info("Ignoring record %s (type %s) with %s %s"  % (recordShortName, recordType, dsattributes.kDS1AttrGeneratedUID, guid,))
+            self.log_info("Ignoring record %s (type %s) with %s %s" % (recordShortName, recordType, dsattributes.kDS1AttrGeneratedUID, guid,))
             return True
-    
+
         uniqueID = recordAttributes.get(dsattributes.kDS1AttrUniqueID)
+        if type(uniqueID) is list:
+            uniqueID = uniqueID[0]
         if uniqueID and (int(uniqueID) < 500 or (recordType == dsattributes.kDSStdRecordTypeUsers and int(uniqueID) == 1000)):
-            self.log_info("Ignoring record %s (type %s) with %s %s"  % (recordShortName, recordType, dsattributes.kDS1AttrUniqueID, uniqueID,))
+            self.log_info("Ignoring record %s (type %s) with %s %s" % (recordShortName, recordType, dsattributes.kDS1AttrUniqueID, uniqueID,))
             return True
 
         if recordShortName.startswith("_"):
-            self.log_info("Ignoring record %s (type %s) with %s %s"  % (recordShortName, recordType, dsattributes.kDSNAttrRecordName, recordShortName,))
+            self.log_info("Ignoring record %s (type %s) with %s %s" % (recordShortName, recordType, dsattributes.kDSNAttrRecordName, recordShortName,))
             return True
-        
+
         return False
 
-  
+
     def _getAllDSLocalResults(self):
         """
         Get a dictionary of ABDirectoryQueryResult by enumerating the local directory
         """
-       
+
         def generateDSLocalResults():
-                        
+
             resultsDictionary = {}
-            
+
             try:
                 localNodeDirectory = self.odModule.odInit("/Local/Default")
                 self.log_debug("opendirectory.listAllRecordsWithAttributes_list(%r,%r,%r)" % (
@@ -283,110 +289,117 @@
             except self.odModule.ODError, ex:
                 self.log_error("Open Directory (node=%s) error: %s" % ("/Local/Default", str(ex)))
                 raise
-            
+
             for (recordShortName, recordAttributes) in records: #@UnusedVariable
-                
+
                 try:
-                    self.log_info("Inspecting record %s"  % (recordAttributes,))
+                    self.log_info("Inspecting record %s" % (recordAttributes,))
                     if self.ignoreSystemRecords:
                         if self._isSystemRecord(recordShortName, recordAttributes):
                             continue
 
                     result = ABDirectoryQueryResult(self.directoryBackedAddressBook, recordAttributes)
-                    
+
                 except:
                     traceback.print_exc()
                     self.log_info("Could not get vcard for record %s" % (recordShortName,))
-                    
+
                 else:
                     uid = result.vCard().propertyValue("UID")
 
                     if uid in resultsDictionary:
                         self.log_info("Record %s skipped due to duplicate UID: %s" % (recordShortName, uid,))
                         continue
-                        
-                    self.log_debug("VCard text =\n%s" % (result.vCardText(), ))
-                    resultsDictionary[uid] = result                   
 
-    
+                    self.log_debug("VCard text =\n%s" % (result.vCardText(),))
+                    resultsDictionary[uid] = result
+
+
             return resultsDictionary
-        
 
+
         if not self.queryDSLocal:
             return {}
-        
+
         if time.time() > self._nextDSLocalQueryTime:
             self._dsLocalResults = generateDSLocalResults()
             # Add jitter/fuzz factor 
-            self._nextDSLocalQueryTime = time.time() + self.dsLocalCacheTimeout * (random() + 0.5)  * 60
+            self._nextDSLocalQueryTime = time.time() + self.dsLocalCacheTimeout * (random() + 0.5) * 60
 
         return self._dsLocalResults
-    
 
+
     @inlineCallbacks
-    def _getDirectoryQueryResults(self, query=None, attributes=None, maxRecords=0, allowedRecordTypes=None ):
+    def _getDirectoryQueryResults(self, query=None, attributes=None, maxRecords=0, allowedRecordTypes=None):
         """
         Get a list of ABDirectoryQueryResult for the given query with the given attributes.
         query == None gets all records. attribute == None gets ABDirectoryQueryResult.allDSQueryAttributes
         """
         limited = False
-        records = (yield self._queryDirectory(query, attributes, maxRecords, allowedRecordTypes=allowedRecordTypes ))
+        records = (yield self._queryDirectory(query, attributes, maxRecords, allowedRecordTypes=allowedRecordTypes))
         if maxRecords and len(records) >= maxRecords:
             limited = True
-            self.log_debug("Directory address book record limit (= %d) reached." % (maxRecords, ))
+            self.log_debug("Directory address book record limit (= %d) reached." % (maxRecords,))
 
         self.log_debug("Query done. Inspecting %s records" % (len(records),))
 
         resultsDictionary = self._getAllDSLocalResults().copy()
         self.log_debug("Adding %s DSLocal results" % len(resultsDictionary.keys()))
-        
+
         for (recordShortName, recordAttributes) in records: #@UnusedVariable
-            
+
             try:
                 # fix ds strangeness
-                if recordAttributes.get(dsattributes.kDS1AttrLastName, "") == "99":
+                lastName = recordAttributes.get(dsattributes.kDS1AttrLastName)
+                if type(lastName) is list:
+                    lastName = lastName[0]
+                if lastName and lastName == "99":
                     del recordAttributes[dsattributes.kDS1AttrLastName]
-        
+
                 if self.ignoreSystemRecords:
                     if self._isSystemRecord(recordShortName, recordAttributes):
                         continue
-                    
+
                 if not self.queryDSLocal:
                     # skip records in local node which happens for non-complex od queries
                     node = recordAttributes.get(dsattributes.kDSNAttrMetaNodeLocation)
+                    if type(node) is list:
+                        node = node[0]
                     if node and node.startswith("/Local/"):
                         recordType = recordAttributes.get(dsattributes.kDSNAttrRecordType)
-                        self.log_info("Ignoring record %s (type %s) with %s %s"  % (recordShortName, recordType, dsattributes.kDSNAttrMetaNodeLocation, recordAttributes.get(dsattributes.kDSNAttrMetaNodeLocation),))
+                        if type(recordType) is list:
+                            recordType = recordType[0]
+                        self.log_info("Ignoring record %s (type %s) with %s %s" % (recordShortName, recordType, dsattributes.kDSNAttrMetaNodeLocation, node,))
                         continue
 
-                result = ABDirectoryQueryResult(self.directoryBackedAddressBook, recordAttributes, 
+                result = ABDirectoryQueryResult(self.directoryBackedAddressBook, recordAttributes,
                                      addDSAttrXProperties=self.addDSAttrXProperties,
                                      appleInternalServer=self.appleInternalServer,
                                      )
             except:
                 traceback.print_exc()
                 self.log_info("Could not get vcard for record %s" % (recordShortName,))
-                
+
             else:
                 uid = result.vCard().propertyValue("UID")
 
                 if uid in resultsDictionary:
                     self.log_info("Record skipped due to duplicate UID: %s" % (recordShortName,))
                     continue
-                    
-                self.log_debug("VCard text =\n%s" % (result.vCardText(), ))
-                resultsDictionary[uid] = result                   
-        
+
+                self.log_debug("VCard text =\n%s" % (result.vCardText(),))
+                resultsDictionary[uid] = result
+
         self.log_debug("_getDirectoryQueryResults: %s results (limited=%s)." % (len(resultsDictionary), limited))
-        returnValue((resultsDictionary.values(), limited, ))
+        returnValue((resultsDictionary.values(), limited,))
 
 
-    def _queryDirectory(self, query=None, attributes=None, maxRecords=0, allowedRecordTypes=None ):
-        
+    def _queryDirectory(self, query=None, attributes=None, maxRecords=0, allowedRecordTypes=None):
+
         startTime = time.time()
         if not attributes:
             attributes = self.returnedAttributes
-                    
+
         allResults = []
         for node, queryInfo in self.nodeDirectoryRecordTypeMap.iteritems():
             directory = queryInfo["directory"]
@@ -395,7 +408,7 @@
                 recordTypes = list(set(recordTypes).intersection(set(allowedRecordTypes)))
                 if not recordTypes:
                     continue
-            
+
             try:
                 if query:
                     if isinstance(query, dsquery.match) and query.value is not "":
@@ -455,64 +468,64 @@
             except self.odModule.ODError, ex:
                 self.log_error("Open Directory (node=%s) error: %s" % (self.realmName, str(ex)))
                 raise
-            
+
             allResults.extend(results)
-            
+
             if maxRecords:
                 maxRecords -= len(results)
                 if maxRecords <= 0:
                     break
-        
 
-        elaspedTime = time.time()-startTime
-        self.log_info("Timing: Directory query: %.1f ms (%d records, %.2f records/sec)" % (elaspedTime*1000, len(allResults), len(allResults)/elaspedTime))
+
+        elaspedTime = time.time() - startTime
+        self.log_info("Timing: Directory query: %.1f ms (%d records, %.2f records/sec)" % (elaspedTime * 1000, len(allResults), len(allResults) / elaspedTime))
         return succeed(allResults)
-    
 
+
     @inlineCallbacks
-    def doAddressBookQuery(self, addressBookFilter, addressBookQuery, maxResults ):
+    def doAddressBookQuery(self, addressBookFilter, addressBookQuery, maxResults):
         """
         Get vCards for a given addressBookFilter and addressBookQuery
         """
-        
+
         def allowedRecordTypes():
             constantProperties = ABDirectoryQueryResult.constantProperties.copy()
-    
+
             # optimization: use KIND as constant to filter record type list
             dsRecordTypeToKindMap = {
                            dsattributes.kDSStdRecordTypeGroups:"group",
                            dsattributes.kDSStdRecordTypeLocations:"location",
                            dsattributes.kDSStdRecordTypeResources:"device",
                            }
-            
+
             allowedRecordTypes = []
             for recordType in set(self.recordTypes):
                 kind = dsRecordTypeToKindMap.get(recordType, "individual")
                 constantProperties["KIND"] = kind
-           
-                filterPropertyNames, dsFilter  = dsFilterFromAddressBookFilter( addressBookFilter,  #@UnusedVariable
+
+                filterPropertyNames, dsFilter = dsFilterFromAddressBookFilter(addressBookFilter, #@UnusedVariable
                                                                                          self.vcardPropToSearchableDSAttrMap,
-                                                                                         constantProperties=constantProperties );
+                                                                                         constantProperties=constantProperties);
                 if not dsFilter is False:
-                    allowedRecordTypes += [recordType,]
+                    allowedRecordTypes += [recordType, ]
             return set(allowedRecordTypes)
-        
 
-        filterPropertyNames, dsFilter  = dsFilterFromAddressBookFilter( addressBookFilter, 
+
+        filterPropertyNames, dsFilter = dsFilterFromAddressBookFilter(addressBookFilter,
                                                                                  self.vcardPropToSearchableDSAttrMap,
-                                                                                 constantProperties=ABDirectoryQueryResult.constantProperties );
+                                                                                 constantProperties=ABDirectoryQueryResult.constantProperties);
         self.log_debug("doAddressBookQuery: query=%s, propertyNames=%s" % (dsFilter if isinstance(dsFilter, bool) else dsFilter.generate(), filterPropertyNames,))
 
         results = []
         limited = False
         if dsFilter:
-            
+
             if dsFilter is True:
                 dsFilter = None  # None means get all records hereafter
-            
+
             # calculate minimum attributes needed for this query
-            etagRequested, queryPropNames = propertiesInAddressBookQuery( addressBookQuery )
-        
+            etagRequested, queryPropNames = propertiesInAddressBookQuery(addressBookQuery)
+
             if (etagRequested and not self.fakeETag) or not queryPropNames:
                 queryAttributes = self.returnedAttributes
             elif queryPropNames:
@@ -522,9 +535,9 @@
                     attributes = ABDirectoryQueryResult.vcardPropToDSAttrMap.get(prop)
                     if attributes:
                         queryAttributes += attributes
-                        
-                queryAttributes =  list(set(queryAttributes + self.requiredAttributes).intersection(self.returnedAttributes))
-            
+
+                queryAttributes = list(set(queryAttributes + self.requiredAttributes).intersection(self.returnedAttributes))
+
             self.log_debug("doAddressBookQuery: etagRequested=%s, queryPropNames=%s, queryAttributes=%s" % (etagRequested, queryPropNames, queryAttributes,))
 
             '''
@@ -543,66 +556,66 @@
             # keep trying query till we get results based on filter.  Especially when doing "all results" query
             while True:
                 dsQueryResults, dsQueryLimited = (yield self._getDirectoryQueryResults(dsFilter, queryAttributes, maxRecords, allowedRecordTypes=allowedRecordTypes()))
-                
+
                 filteredResults = []
                 for dsQueryResult in dsQueryResults:
                     if addressBookFilter.match(dsQueryResult.vCard()):
                         filteredResults.append(dsQueryResult)
                     else:
                         self.log_debug("doAddressBookQuery: result did not match filter: %s (%s)" % (dsQueryResult.vCard().propertyValue("FN"), dsQueryResult.vCard().propertyValue("UID"),))
-                
+
                 #no more results    
                 if not dsQueryLimited:
                     break;
-                
+
                 # more than requested results
                 if maxResults and len(filteredResults) >= maxResults:
                     break
-                
+
                 # more than max report results
                 if len(filteredResults) >= config.MaxQueryWithDataResults:
                     break
-                
+
                 # more than self limit
                 if self.maxDSQueryRecords and maxRecords >= self.maxDSQueryRecords:
                     break
-                
+
                 # try again with 2x
                 maxRecords *= 2
                 if self.maxDSQueryRecords and maxRecords > self.maxDSQueryRecords:
                     maxRecords = self.maxDSQueryRecords
-                
-            
+
+
             results = filteredResults
             limited = maxResults and len(results) >= maxResults
-                        
+
         #if self.sortResults:
         #    results = sorted(list(results), key=lambda result:result.vCard().propertyValue("UID"))
 
         self.log_debug("doAddressBookQuery: %s results (limited=%s)." % (len(results), limited))
-        returnValue((results, limited,))        
+        returnValue((results, limited,))
 
 
 #utility
-def propertiesInAddressBookQuery( addressBookQuery ):
+def propertiesInAddressBookQuery(addressBookQuery):
     """
     Get the vCard properties requested by a given query
     """
-    
+
     etagRequested = False
-    propertyNames = [] 
+    propertyNames = []
     if addressBookQuery.qname() == ("DAV:", "prop"):
-    
-        for property in addressBookQuery.children:                
+
+        for property in addressBookQuery.children:
             if isinstance(property, carddavxml.AddressData):
                 for addressProperty in property.children:
                     if isinstance(addressProperty, carddavxml.Property):
-                        propertyNames += [addressProperty.attributes["name"],]
-                    
+                        propertyNames += [addressProperty.attributes["name"], ]
+
             elif property.qname() == ("DAV:", "getetag"):
                 # for a real etag == md5(vCard), we need all attributes
                 etagRequested = True
-    
+
     return (etagRequested, propertyNames if len(propertyNames) else None)
 
 
@@ -651,8 +664,8 @@
                         expressionList += addedExpressions
             #log.debug("propFilterListQuery(): out expressionList=%s (%s)" % (expressionList, explen(expressionList)))
             return expressionList
-            
 
+
         def propFilterExpression(filterAllOf, propFilter):
             """
             Create an expression for a single prop-filter element.
@@ -660,8 +673,8 @@
             @param propFilter: the L{PropertyFilter} element.
             @return: (filterProperyNames, expressions) tuple.  expression==True means list all results, expression==False means no results
             """
-            
-            def definedExpression( defined, allOf ):
+
+            def definedExpression(defined, allOf):
                 if constant or propFilter.filter_name in ("N" , "FN", "UID", "SOURCE",):
                     return defined     # all records have this property so no records do not have it
                 else:
@@ -670,46 +683,46 @@
                         return andOrExpression(allOf, matchList)
                     else:
                         if len(matchList) > 1:
-                            expr = dsquery.expression( dsquery.expression.OR, matchList )
+                            expr = dsquery.expression(dsquery.expression.OR, matchList)
                         else:
                             expr = matchList[0]
-                        return [dsquery.expression( dsquery.expression.NOT, expr),]
+                        return [dsquery.expression(dsquery.expression.NOT, expr), ]
                 #end definedExpression()
 
 
             def andOrExpression(propFilterAllOf, matchList):
                 if propFilterAllOf and len(matchList) > 1:
                     # add OR expression because parent will AND
-                    return [dsquery.expression( dsquery.expression.OR, matchList),]
+                    return [dsquery.expression(dsquery.expression.OR, matchList), ]
                 else:
                     return matchList
                 #end andOrExpression()
-                
 
+
             def paramFilterElementExpression(propFilterAllOf, paramFilterElement):
 
                 params = ABDirectoryQueryResult.vcardPropToParamMap.get(propFilter.filter_name.upper())
                 defined = params and paramFilterElement.filter_name.upper() in params
-                
+
                 #defined test
                 if defined != paramFilterElement.defined:
                     return False
-                
+
                 #parameter value text match
                 if defined and paramFilterElement.filters:
                     paramValues = params[paramFilterElement.filter_name.upper()]
                     if paramValues and paramFilterElement.filters[0].text.upper() not in paramValues:
                         return False
-                
+
                 return True
 
-            
-            def textMatchElementExpression( propFilterAllOf, textMatchElement ):
 
+            def textMatchElementExpression(propFilterAllOf, textMatchElement):
+
                 # pre process text match strings for ds query 
-                def getMatchStrings( propFilter, matchString ):
-                                        
-                    if propFilter.filter_name in ("REV" , "BDAY", ):
+                def getMatchStrings(propFilter, matchString):
+
+                    if propFilter.filter_name in ("REV" , "BDAY",):
                         rawString = matchString
                         matchString = ""
                         for c in rawString:
@@ -717,32 +730,32 @@
                                 matchString += c
                     elif propFilter.filter_name == "GEO":
                         matchString = ",".join(matchString.split(";"))
-                    
-                    if propFilter.filter_name in ("N" , "ADR", "ORG", ):
+
+                    if propFilter.filter_name in ("N" , "ADR", "ORG",):
                         # for structured properties, change into multiple strings for ds query
                         if propFilter.filter_name == "ADR":
                             #split by newline and comma
-                            rawStrings = ",".join( matchString.split("\n") ).split(",")
+                            rawStrings = ",".join(matchString.split("\n")).split(",")
                         else:
                             #split by space
                             rawStrings = matchString.split(" ")
-                        
+
                         # remove empty strings
                         matchStrings = []
                         for oneString in rawStrings:
                             if len(oneString):
-                                matchStrings += [oneString,]
+                                matchStrings += [oneString, ]
                         return matchStrings
-                    
+
                     elif len(matchString):
-                        return [matchString,]
+                        return [matchString, ]
                     else:
                         return []
                     # end getMatchStrings
 
                 if constant:
                     #FIXME: match is not implemented in twisteddaldav.query.addressbookqueryfilter.TextMatch so use _match for now
-                    return textMatchElement._match([constant,])
+                    return textMatchElement._match([constant, ])
                 else:
 
                     matchStrings = getMatchStrings(propFilter, textMatchElement.text)
@@ -753,68 +766,68 @@
                             return definedExpression(False, propFilterAllOf)
                         # else fall through to attribute exists case below
                     else:
-                        
+
                         # special case UID's formed from node and record name
                         if propFilter.filter_name == "UID":
                             matchString = matchStrings[0]
                             seperatorIndex = matchString.find(ABDirectoryQueryResult.uidSeparator)
                             if seperatorIndex > 1:
                                 recordNameStart = seperatorIndex + len(ABDirectoryQueryResult.uidSeparator)
-                                
-                                if recordNameStart < len(matchString)-1:
+
+                                if recordNameStart < len(matchString) - 1:
                                     try:
                                         recordNameQualifier = matchString[recordNameStart:].decode("base64").decode("utf8")
                                     except Exception, e:
                                         log.debug("Could not decode UID string %r in %r: %r" % (matchString[recordNameStart:], matchString, e,))
                                     else:
                                         if textMatchElement.negate:
-                                            return [dsquery.expression(dsquery.expression.NOT, dsquery.match(dsattributes.kDSNAttrRecordName, recordNameQualifier, dsattributes.eDSExact)),]
+                                            return [dsquery.expression(dsquery.expression.NOT, dsquery.match(dsattributes.kDSNAttrRecordName, recordNameQualifier, dsattributes.eDSExact)), ]
                                         else:
-                                            return [dsquery.match(dsattributes.kDSNAttrRecordName, recordNameQualifier, dsattributes.eDSExact),]
-                        
+                                            return [dsquery.match(dsattributes.kDSNAttrRecordName, recordNameQualifier, dsattributes.eDSExact), ]
+
                         # use match_type where possible depending on property/attribute mapping
                         # FIXME: case-sensitive negate will not work.  This should return all all records in that case
                         matchType = dsattributes.eDSContains
-                        if propFilter.filter_name in ("NICKNAME" , "TITLE" , "NOTE" , "UID", "URL", "N", "ADR", "ORG", "REV",  "LABEL", ):
+                        if propFilter.filter_name in ("NICKNAME" , "TITLE" , "NOTE" , "UID", "URL", "N", "ADR", "ORG", "REV", "LABEL",):
                             if textMatchElement.match_type == "equals":
                                     matchType = dsattributes.eDSExact
                             elif textMatchElement.match_type == "starts-with":
                                     matchType = dsattributes.eDSStartsWith
                             elif textMatchElement.match_type == "ends-with":
                                     matchType = dsattributes.eDSEndsWith
-                        
+
                         matchList = []
                         for matchString in matchStrings:
                             matchList += [dsquery.match(attrName, matchString, matchType) for attrName in searchableAttributes]
-                        
+
                         matchList = list(set(matchList))
 
                         if textMatchElement.negate:
                             if len(matchList) > 1:
-                                expr = dsquery.expression( dsquery.expression.OR, matchList )
+                                expr = dsquery.expression(dsquery.expression.OR, matchList)
                             else:
                                 expr = matchList[0]
-                            return [dsquery.expression( dsquery.expression.NOT, expr),]
+                            return [dsquery.expression(dsquery.expression.NOT, expr), ]
                         else:
                             return andOrExpression(propFilterAllOf, matchList)
 
                 # attribute exists search
                 return definedExpression(True, propFilterAllOf)
                 #end textMatchElementExpression()
-                
 
+
             # searchablePropFilterAttrNames are attributes to be used by this propfilter's expression
             searchableAttributes = vcardPropToSearchableAttrMap.get(propFilter.filter_name, [])
             if isinstance(searchableAttributes, str):
-                searchableAttributes = [searchableAttributes,]
+                searchableAttributes = [searchableAttributes, ]
             searchablePropFilterAttrNames = list(searchableAttributes)
-            
+
             constant = constantProperties.get(propFilter.filter_name)
             if not searchablePropFilterAttrNames and not constant:
                 # not allAttrNames means propFilter.filter_name is not mapped
                 # return None to try to match all items if this is the only property filter
                 return None
-            
+
             #create a textMatchElement for the IsNotDefined qualifier
             if isinstance(propFilter.qualifier, addressbookqueryfilter.IsNotDefined):
                 textMatchElement = addressbookqueryfilter.TextMatch(carddavxml.TextMatch.fromString(""))
@@ -837,12 +850,12 @@
                 propFilterExpressions = combineExpressionLists(propFilterExpressions, propFilterAllOf, propFilterExpression)
                 if isinstance(propFilterExpressions, bool) and propFilterAllOf != propFilterExpression:
                     break
-                
+
             if isinstance(propFilterExpressions, list):
                 propFilterExpressions = list(set(propFilterExpressions))
                 if propFilterExpressions and (filterAllOf != propFilterAllOf):
                     propFilterExpressions = [dsquery.expression(dsquery.expression.AND if propFilterAllOf else dsquery.expression.OR , propFilterExpressions)]
-            
+
             return propFilterExpressions
             #end propFilterExpression
 
@@ -855,14 +868,14 @@
         """
         expressions = None
         for propFilter in propFilters:
-            
+
             propExpressions = propFilterExpression(filterAllOf, propFilter)
             expressions = combineExpressionLists(expressions, filterAllOf, propExpressions)
-        
+
             # early loop exit
             if isinstance(expressions, bool) and filterAllOf != expressions:
                 break
-            
+
         # convert to needsAllRecords to return
         if isinstance(expressions, list):
             expressions = list(set(expressions))
@@ -877,13 +890,13 @@
         else:
             # True or False
             expr = expressions
-            
+
         properties = [propFilter.filter_name for propFilter in propFilters]
 
         return (list(set(properties)), expr)
-    
+
     # Lets assume we have a valid filter from the outset
-    
+
     # Top-level filter contains zero or more prop-filters
     if addressBookFilter:
         filterAllOf = addressBookFilter.filter_test == "allof"
@@ -892,10 +905,10 @@
         else:
             return ([], not filterAllOf)
     else:
-        return ([], False)    
-    
-                        
+        return ([], False)
 
+
+
 class ABDirectoryQueryResult(DAVPropertyMixIn, LoggingMixIn):
     """
     Result from ab query report or multiget on directory
@@ -905,10 +918,10 @@
     # will be used to translate vCard queries to od queries
 
     vcardPropToDSAttrMap = {
-                             
+
         "FN" : [
-               dsattributes.kDS1AttrFirstName, 
-               dsattributes.kDS1AttrLastName, 
+               dsattributes.kDS1AttrFirstName,
+               dsattributes.kDS1AttrLastName,
                dsattributes.kDS1AttrMiddleName,
                dsattributes.kDSNAttrNamePrefix,
                dsattributes.kDSNAttrNameSuffix,
@@ -916,8 +929,8 @@
                dsattributes.kDSNAttrRecordName,
                ],
         "N" : [
-               dsattributes.kDS1AttrFirstName, 
-               dsattributes.kDS1AttrLastName, 
+               dsattributes.kDS1AttrFirstName,
+               dsattributes.kDS1AttrLastName,
                dsattributes.kDS1AttrMiddleName,
                dsattributes.kDSNAttrNamePrefix,
                dsattributes.kDSNAttrNameSuffix,
@@ -1000,13 +1013,13 @@
                 ],
          "X-ABRELATEDNAMES" :  [
                 dsattributes.kDSNAttrRelationships,
-                ],  
+                ],
          "SOURCE" : [
                 dsattributes.kDS1AttrGeneratedUID,
                 dsattributes.kDSNAttrRecordName,
                 ],
     }
-    
+
     allDSQueryAttributes = list(set([attr for lookupAttributes in vcardPropToDSAttrMap.values()
                                       for attr in lookupAttributes]))
     binaryDSAttrNames = [attr[0] for attr in allDSQueryAttributes
@@ -1014,7 +1027,7 @@
     stringDSAttrNames = [attr for attr in allDSQueryAttributes
                                 if isinstance(attr, str) ]
     allDSAttrNames = stringDSAttrNames + binaryDSAttrNames
-   
+
     # all possible generated parameters.
     vcardPropToParamMap = {
         "PHOTO": { "ENCODING": ("B",), "TYPE": ("JPEG",), },
@@ -1034,7 +1047,7 @@
 
     uidSeparator = "-cf07a1a2-"
 
-    
+
     constantProperties = {
         # 3.6.3 PRODID Type Definition
         "PRODID": vCardProductID,
@@ -1042,16 +1055,16 @@
         "VERSION": "3.0",
         }
 
-    
-    def __init__(self, directoryBackedAddressBook, recordAttributes, 
-                 kind=None, 
-                 additionalVCardProps=None, 
-                 addDSAttrXProperties=False, 
-                 appleInternalServer=False, 
+
+    def __init__(self, directoryBackedAddressBook, recordAttributes,
+                 kind=None,
+                 additionalVCardProps=None,
+                 addDSAttrXProperties=False,
+                 appleInternalServer=False,
                  ):
 
         self.log_debug("directoryBackedAddressBook=%s, attributes=%s, additionalVCardProps=%s" % (directoryBackedAddressBook, recordAttributes, additionalVCardProps,))
-        
+
         constantProperties = ABDirectoryQueryResult.constantProperties.copy()
         if additionalVCardProps:
             for key, value in additionalVCardProps.iteritems():
@@ -1068,7 +1081,7 @@
 
         self._directoryBackedAddressBook = directoryBackedAddressBook
         self._vCard = None
-        
+
         #clean attributes
         self.attributes = {}
         for key, values in recordAttributes.items():
@@ -1079,16 +1092,16 @@
                     self.attributes[key] = removeControlChars(values).decode("utf8")
             else:
                 self.attributes[key] = values
-                
+
         # find or create guid 
         guid = self.firstValueForAttribute(dsattributes.kDS1AttrGeneratedUID)
         if not guid:
             nameUUIDStr = "".join(self.firstValueForAttribute(dsattributes.kDSNAttrRecordName).encode("base64").split("\n"))
-            guid =  ABDirectoryQueryResult.uidSeparator.join(["00000000", nameUUIDStr,])
+            guid = ABDirectoryQueryResult.uidSeparator.join(["00000000", nameUUIDStr, ])
             #guid =  ABDirectoryQueryResult.uidSeparator.join(["d9a8e41b", nameUUIDStr,])
-            
+
             self.attributes[dsattributes.kDS1AttrGeneratedUID] = guid
-        
+
         if not kind:
             dsRecordTypeToKindMap = {
                            #dsattributes.kDSStdRecordTypePeople:"individual",
@@ -1104,16 +1117,16 @@
 
        #generate a vCard here.  May throw an exception
         self.vCard()
-        
 
 
+
     def __repr__(self):
         return "<%s[%s(%s)]>" % (
             self.__class__.__name__,
             self.vCard().propertyValue("FN"),
             self.vCard().propertyValue("UID")
         )
-    
+
     def __hash__(self):
         s = "".join([
               "%s:%s" % (attribute, self.valuesForAttribute(attribute),)
@@ -1121,29 +1134,29 @@
               ])
         return hash(s)
 
-    
-    def hasAttribute(self, attributeName ):
+
+    def hasAttribute(self, attributeName):
         return self.valuesForAttribute(attributeName, None) is not None
 
 
-    def valuesForAttribute(self, attributeName, default_values=[] ):
+    def valuesForAttribute(self, attributeName, default_values=[]):
         values = self.attributes.get(attributeName)
         if (values is None):
             return default_values
         elif not isinstance(values, list):
-            values = [values, ] 
-        
+            values = [values, ]
+
         # ds templates often return empty attribute values
         #     get rid of them here
         nonEmptyValues = [(value.encode("utf-8") if isinstance(value, unicode) else value) for value in values if len(value) > 0 ]
-        
+
         if len(nonEmptyValues) > 0:
             return nonEmptyValues
         else:
             return default_values
-        
 
-    def firstValueForAttribute(self, attributeName, default_value="" ):
+
+    def firstValueForAttribute(self, attributeName, default_value=""):
         values = self.attributes.get(attributeName)
         if values is None:
             return default_value
@@ -1152,32 +1165,32 @@
         else:
             return values.encode("utf_8") if isinstance(values, unicode) else values
 
-    def joinedValuesForAttribute(self, attributeName, separator=",", default_string="" ):
+    def joinedValuesForAttribute(self, attributeName, separator=",", default_string=""):
         values = self.valuesForAttribute(attributeName, None)
         if not values:
             return default_string
         else:
             return separator.join(values)
-            
 
-    def isoDateStringForDateAttribute(self, attributeName, default_string="" ):
+
+    def isoDateStringForDateAttribute(self, attributeName, default_string=""):
         modDate = self.firstValueForAttribute(attributeName, default_string)
         revDate = None
         if modDate:
             if len(modDate) >= len("YYYYMMDD") and modDate[:8].isdigit():
-                revDate = "%s-%s-%s" % (modDate[:4],modDate[4:6],modDate[6:8], )
+                revDate = "%s-%s-%s" % (modDate[:4], modDate[4:6], modDate[6:8],)
             if len(modDate) >= len("YYYYMMDDHHMMSS") and modDate[8:14].isdigit():
-                revDate += "T%s:%s:%sZ" % (modDate[8:10],modDate[10:12],modDate[12:14], )
+                revDate += "T%s:%s:%sZ" % (modDate[8:10], modDate[10:12], modDate[12:14],)
         return revDate
 
-    
-                
+
+
     def vCard(self):
-        
-        
+
+
         def generateVCard():
-            
-            def isUniqueProperty(vcard, newProperty, ignoreParams = None):
+
+            def isUniqueProperty(vcard, newProperty, ignoreParams=None):
                 existingProperties = vcard.properties(newProperty.name())
                 for existingProperty in existingProperties:
                     if ignoreParams:
@@ -1188,14 +1201,14 @@
                         return False
                 return True
 
-            def addUniqueProperty(vcard, newProperty, ignoreParams = None, attrType = None, attrValue = None):
+            def addUniqueProperty(vcard, newProperty, ignoreParams=None, attrType=None, attrValue=None):
                 if isUniqueProperty(vcard, newProperty, ignoreParams):
                     vcard.addProperty(newProperty)
                 else:
                     if attrType and attrValue:
-                        self.log_info("Ignoring attribute %r with value %r in creating property %r. A duplicate property already exists." % (attrType, attrValue, newProperty, ))
-                            
-            def addPropertyAndLabel(groupCount, label, propertyName, propertyValue, parameters = None ):
+                        self.log_info("Ignoring attribute %r with value %r in creating property %r. A duplicate property already exists." % (attrType, attrValue, newProperty,))
+
+            def addPropertyAndLabel(groupCount, label, propertyName, propertyValue, parameters=None):
                 groupCount[0] += 1
                 groupPrefix = "item%d" % groupCount[0]
                 vcard.addProperty(Property(propertyName, propertyValue, params=parameters, group=groupPrefix))
@@ -1215,22 +1228,22 @@
                                     defaultLabel = splitValue[1]
 
                         colonIndex = attrValue.find(":")
-                        if (colonIndex > len(attrValue)-2):
+                        if (colonIndex > len(attrValue) - 2):
                             raise ValueError("Nothing after colon.")
 
-                        propertyValue = attrValue[colonIndex+1:]
+                        propertyValue = attrValue[colonIndex + 1:]
                         labelString = attrValue[:colonIndex] if colonIndex > 0 else defaultLabel
                         paramTypeString = labelString.upper()
-                        
+
                         if specialParamType:
                             parameters = { specialParamType: (paramTypeString,) }
                             if preferred:
                                 parameters["TYPE"] = ("PREF",)
                         else:
                             # add PREF to first prop's parameters
-                            paramTypeStrings = [paramTypeString,]
+                            paramTypeStrings = [paramTypeString, ]
                             if preferred and "PREF" != paramTypeString:
-                                paramTypeStrings += ["PREF",]
+                                paramTypeStrings += ["PREF", ]
                             parameters = { "TYPE": paramTypeStrings, }
 
                         #special case for IMHandles which the param is the last part of the property like X-AIM or X-JABBER 
@@ -1239,7 +1252,7 @@
 
                         # only add label prop if needed
                         if paramTypeString in nolabelParamTypes:
-                            addUniqueProperty(vcard, Property(propertyName, attrValue[colonIndex+1:], params=parameters), None, attrValue, attrType)
+                            addUniqueProperty(vcard, Property(propertyName, attrValue[colonIndex + 1:], params=parameters), None, attrValue, attrType)
                         else:
                             # use special localizable addressbook labels where possible
                             localizedABLabelString = labelMap.get(labelString, labelString)
@@ -1251,22 +1264,22 @@
                         self.log_debug("addPropertiesAndLabelsForPrefixedAttribute(): groupCount=%r, propertyPrefix=%r, propertyName=%r, nolabelParamTypes=%r, labelMap=%r, attrType=%r" % (groupCount[0], propertyPrefix, propertyName, nolabelParamTypes, labelMap, attrType,))
                         self.log_error("addPropertiesAndLabelsForPrefixedAttribute(): Trouble parsing attribute %s, with value \"%s\".  Error = %s" % (attrType, attrValue, e,))
 
-            
+
             # create vCard
             vcard = Component("VCARD")
             groupCount = [0]
-            
+
             # add constant properties - properties that are the same regardless of the record attributes
             for key, value in self.constantProperties.items():
                 vcard.addProperty(Property(key, value))
-                
+
             # 3.1 IDENTIFICATION TYPES http://tools.ietf.org/html/rfc2426#section-3.1
             # 3.1.1 FN Type Definition
             # dsattributes.kDS1AttrDistinguishedName,      # Users distinguished or real name
             #
             # full name is required but this is set in OpenDiretoryBackingRecord.__init__
             #vcard.addProperty(Property("FN", self.firstValueForAttribute(dsattributes.kDS1AttrDistinguishedName)))
-            
+
             # 3.1.2 N Type Definition
             # dsattributes.kDS1AttrFirstName,           # Used for first name of user or person record.
             # dsattributes.kDS1AttrLastName,            # Used for the last name of user or person record.
@@ -1279,60 +1292,60 @@
                                                         #      ie. Mr., Ms., Mrs., Dr., etc.
                                                         #      Usually found in user or people records (kDSStdRecordTypeUsers or 
                                                         #      dsattributes.kDSStdRecordTypePeople).
-                                                        
+
             # name is required, so make sure we have one
             # vcard says: Each name attribute can be a string or a list of strings.
             if not self.hasAttribute(dsattributes.kDS1AttrFirstName) and not self.hasAttribute(dsattributes.kDS1AttrLastName):
                 familyName = self.firstValueForAttribute(dsattributes.kDS1AttrDistinguishedName)
             else:
                 familyName = self.valuesForAttribute(dsattributes.kDS1AttrLastName, "")
-            
+
             nameObject = N(
-                first = self.valuesForAttribute(dsattributes.kDS1AttrFirstName, ""),
-                last = familyName, 
-                middle = self.valuesForAttribute(dsattributes.kDS1AttrMiddleName, ""),
-                prefix = self.valuesForAttribute(dsattributes.kDSNAttrNamePrefix, ""),
-                suffix = self.valuesForAttribute(dsattributes.kDSNAttrNameSuffix, ""),
+                first=self.valuesForAttribute(dsattributes.kDS1AttrFirstName, ""),
+                last=familyName,
+                middle=self.valuesForAttribute(dsattributes.kDS1AttrMiddleName, ""),
+                prefix=self.valuesForAttribute(dsattributes.kDSNAttrNamePrefix, ""),
+                suffix=self.valuesForAttribute(dsattributes.kDSNAttrNameSuffix, ""),
             )
             vcard.addProperty(Property("N", nameObject))
-            
+
             # set full name to Name with contiguous spaces stripped
             # it turns out that Address Book.app ignores FN and creates it fresh from N in ABRecord
             # so no reason to have FN distinct from N
-            vcard.addProperty(Property("FN", nameObject.getFullName() ))
-            
+            vcard.addProperty(Property("FN", nameObject.getFullName()))
+
             # 3.1.3 NICKNAME Type Definition
             # dsattributes.kDSNAttrNickName,            # Represents the nickname of a user or person.
                                                         #    Usually found in user or people records (kDSStdRecordTypeUsers or 
                                                         #    dsattributes.kDSStdRecordTypePeople).
             for nickname in self.valuesForAttribute(dsattributes.kDSNAttrNickName):
                 addUniqueProperty(vcard, Property("NICKNAME", nickname), None, dsattributes.kDSNAttrNickName, nickname)
-            
+
             # 3.1.4 PHOTO Type Definition
             # dsattributes.kDSNAttrJPEGPhoto,           # Used to store binary picture data in JPEG format. 
                                                         #      Usually found in user, people or group records (kDSStdRecordTypeUsers, 
                                                         #      dsattributes.kDSStdRecordTypePeople,dsattributes.kDSStdRecordTypeGroups).
             # pyOpenDirectory always returns binary-encoded string                                       
-                                                        
+
             for photo in self.valuesForAttribute(dsattributes.kDSNAttrJPEGPhoto):
                 photo = "".join("".join(photo.split("\r")).split("\n")) #get rid of line folding: for PHOTO
-                addUniqueProperty(vcard, Property("PHOTO", photo, params={"ENCODING": ["b",], "TYPE": ["JPEG",],}), None, dsattributes.kDSNAttrJPEGPhoto, photo)
-    
-    
+                addUniqueProperty(vcard, Property("PHOTO", photo, params={"ENCODING": ["b", ], "TYPE": ["JPEG", ], }), None, dsattributes.kDSNAttrJPEGPhoto, photo)
+
+
             # 3.1.5 BDAY Type Definition
             # dsattributes.kDS1AttrBirthday,            # Single-valued attribute that defines the user's birthday.
                                                         #      Format is x.208 standard YYYYMMDDHHMMSSZ which we will require as GMT time.
                                                         #                               012345678901234
-            
+
             birthdate = self.isoDateStringForDateAttribute(dsattributes.kDS1AttrBirthday)
             if birthdate:
                 vcard.addProperty(Property("BDAY", PyCalendarDateTime.parseText(birthdate, fullISO=True)))
-    
-    
+
+
             # 3.2 Delivery Addressing Types http://tools.ietf.org/html/rfc2426#section-3.2
             #
             # 3.2.1 ADR Type Definition
-    
+
             #address
             # vcard says: Each address attribute can be a string or a list of strings.
             extended = self.valuesForAttribute(dsattributes.kDSNAttrBuilding, "")
@@ -1341,37 +1354,37 @@
             region = self.valuesForAttribute(dsattributes.kDSNAttrState, "")
             code = self.valuesForAttribute(dsattributes.kDSNAttrPostalCode, "")
             country = self.valuesForAttribute(dsattributes.kDSNAttrCountry, "")
-            
+
             if len(extended) > 0 or len(street) > 0 or len(city) > 0 or len(region) > 0 or len(code) > 0 or len(country) > 0:
                 vcard.addProperty(Property("ADR",
                     Adr(
                         #pobox = box,
-                        extended = extended,
-                        street = street,
-                        locality = city,
-                        region = region,
-                        postalcode = code,
-                        country = country,
+                        extended=extended,
+                        street=street,
+                        locality=city,
+                        region=region,
+                        postalcode=code,
+                        country=country,
                     ),
-                    params = {"TYPE": ["WORK", "PREF", "POSTAL", "PARCEL",],}
+                    params={"TYPE": ["WORK", "PREF", "POSTAL", "PARCEL", ], }
                 ))
-    
-    
+
+
             # 3.2.2 LABEL Type Definition
-            
+
             # dsattributes.kDSNAttrPostalAddress,           # The postal address usually excluding postal code.
             # dsattributes.kDSNAttrPostalAddressContacts,   # multi-valued attribute that defines a record's alternate postal addresses .
                                                             #      found in user records (kDSStdRecordTypeUsers) and resource records (kDSStdRecordTypeResources).
             # dsattributes.kDSNAttrAddressLine1,            # Line one of multiple lines of address data for a user.
             # dsattributes.kDSNAttrAddressLine2,            # Line two of multiple lines of address data for a user.
             # dsattributes.kDSNAttrAddressLine3,            # Line three of multiple lines of address data for a user.
-            
+
             for label in self.valuesForAttribute(dsattributes.kDSNAttrPostalAddress):
-                addUniqueProperty(vcard, Property("LABEL", label, params={"TYPE": ["POSTAL", "PARCEL",]}), None, dsattributes.kDSNAttrPostalAddress, label)
-                
+                addUniqueProperty(vcard, Property("LABEL", label, params={"TYPE": ["POSTAL", "PARCEL", ]}), None, dsattributes.kDSNAttrPostalAddress, label)
+
             for label in self.valuesForAttribute(dsattributes.kDSNAttrPostalAddressContacts):
-                addUniqueProperty(vcard, Property("LABEL", label, params={"TYPE": ["POSTAL", "PARCEL",]}), None, dsattributes.kDSNAttrPostalAddressContacts, label)
-                
+                addUniqueProperty(vcard, Property("LABEL", label, params={"TYPE": ["POSTAL", "PARCEL", ]}), None, dsattributes.kDSNAttrPostalAddressContacts, label)
+
             address = self.joinedValuesForAttribute(dsattributes.kDSNAttrAddressLine1)
             addressLine2 = self.joinedValuesForAttribute(dsattributes.kDSNAttrAddressLine2)
             if len(addressLine2) > 0:
@@ -1379,14 +1392,14 @@
             addressLine3 = self.joinedValuesForAttribute(dsattributes.kDSNAttrAddressLine3)
             if len(addressLine3) > 0:
                 address += "\n" + addressLine3
-            
+
             if len(address) > 0:
-                vcard.addProperty(Property("LABEL", address, params={"TYPE": ["POSTAL", "PARCEL",]}))
-    
+                vcard.addProperty(Property("LABEL", address, params={"TYPE": ["POSTAL", "PARCEL", ]}))
+
             # 3.3 TELECOMMUNICATIONS ADDRESSING TYPES http://tools.ietf.org/html/rfc2426#section-3.3
             # 3.3.1 TEL Type Definition
             #          TEL;TYPE=work,voice,pref,msg:+1-213-555-1234
-    
+
             # dsattributes.kDSNAttrPhoneNumber,         # Telephone number of a user.
             # dsattributes.kDSNAttrMobileNumber,        # Represents the mobile numbers of a user or person.
                                                         #      Usually found in user or people records (kDSStdRecordTypeUsers or 
@@ -1401,61 +1414,61 @@
             # dsattributes.kDSNAttrPhoneContacts,       # multi-valued attribute that defines a record's custom phone numbers .
                                                         #      found in user records (kDSStdRecordTypeUsers). 
                                                         #      Example: home fax:408-555-4444
-            
-            params = {"TYPE": ["WORK", "PREF", "VOICE",],}
+
+            params = {"TYPE": ["WORK", "PREF", "VOICE", ], }
             for phone in self.valuesForAttribute(dsattributes.kDSNAttrPhoneNumber):
                 addUniqueProperty(vcard, Property("TEL", phone, params=params), (("TYPE", "PREF"),), phone, dsattributes.kDSNAttrPhoneNumber)
-                params = {"TYPE": ["WORK", "VOICE",],}
-    
-            params = { "TYPE": ["WORK", "PREF", "CELL",], }
+                params = {"TYPE": ["WORK", "VOICE", ], }
+
+            params = { "TYPE": ["WORK", "PREF", "CELL", ], }
             for phone in self.valuesForAttribute(dsattributes.kDSNAttrMobileNumber):
                 addUniqueProperty(vcard, Property("TEL", phone, params=params), (("TYPE", "PREF"),), phone, dsattributes.kDSNAttrMobileNumber)
-                params = { "TYPE": ["WORK", "CELL",], }
-    
-            params = { "TYPE": ["WORK", "PREF", "FAX",], }
+                params = { "TYPE": ["WORK", "CELL", ], }
+
+            params = { "TYPE": ["WORK", "PREF", "FAX", ], }
             for phone in self.valuesForAttribute(dsattributes.kDSNAttrFaxNumber):
                 addUniqueProperty(vcard, Property("TEL", phone, params=params), (("TYPE", "PREF"),), phone, dsattributes.kDSNAttrFaxNumber)
-                params = { "TYPE": ["WORK", "FAX",], }
-    
-            params = { "TYPE": ["WORK", "PREF", "PAGER",], }
+                params = { "TYPE": ["WORK", "FAX", ], }
+
+            params = { "TYPE": ["WORK", "PREF", "PAGER", ], }
             for phone in self.valuesForAttribute(dsattributes.kDSNAttrPagerNumber):
                 addUniqueProperty(vcard, Property("TEL", phone, params=params), (("TYPE", "PREF"),), phone, dsattributes.kDSNAttrPagerNumber)
-                params = { "TYPE": ["WORK", "PAGER",], }
-    
-            params = { "TYPE": ["HOME", "PREF", "VOICE",], }
+                params = { "TYPE": ["WORK", "PAGER", ], }
+
+            params = { "TYPE": ["HOME", "PREF", "VOICE", ], }
             for phone in self.valuesForAttribute(dsattributes.kDSNAttrHomePhoneNumber):
                 addUniqueProperty(vcard, Property("TEL", phone, params=params), (("TYPE", "PREF"),), phone, dsattributes.kDSNAttrHomePhoneNumber)
-                params = { "TYPE": ["HOME", "VOICE",], }
-                    
+                params = { "TYPE": ["HOME", "VOICE", ], }
+
             addPropertiesAndLabelsForPrefixedAttribute(groupCount=groupCount, propertyPrefix=None, propertyName="TEL", defaultLabel="work",
                                                         nolabelParamTypes=("VOICE", "CELL", "FAX", "PAGER",),
-                                                        attrType=dsattributes.kDSNAttrPhoneContacts, )
+                                                        attrType=dsattributes.kDSNAttrPhoneContacts,)
 
             """
             # EXTEND:  Use this attribute
             # dsattributes.kDSNAttrAreaCode,            # Area code of a user's phone number.
             """
-    
+
             # 3.3.2 EMAIL Type Definition
             # dsattributes.kDSNAttrEMailAddress,        # Email address of usually a user record.
-    
+
             # setup some params
-            preferredWorkParams = { "TYPE": ["WORK", "PREF", "INTERNET",], }
-            workParams = { "TYPE": ["WORK", "INTERNET",], }
+            preferredWorkParams = { "TYPE": ["WORK", "PREF", "INTERNET", ], }
+            workParams = { "TYPE": ["WORK", "INTERNET", ], }
             params = preferredWorkParams
             for emailAddress in self.valuesForAttribute(dsattributes.kDSNAttrEMailAddress):
                 addUniqueProperty(vcard, Property("EMAIL", emailAddress, params=params), (("TYPE", "PREF"),), emailAddress, dsattributes.kDSNAttrEMailAddress)
                 params = workParams
-                
+
             # dsattributes.kDSNAttrEMailContacts,       # multi-valued attribute that defines a record's custom email addresses .
                                                         #    found in user records (kDSStdRecordTypeUsers). 
                                                         #      Example: home:johndoe at mymail.com
-    
+
             # check to see if parameters type are open ended. Could be any string
             addPropertiesAndLabelsForPrefixedAttribute(groupCount=groupCount, propertyPrefix=None, propertyName="EMAIL", defaultLabel="work",
-                                                        nolabelParamTypes=("WORK", "HOME",), 
-                                                        attrType=dsattributes.kDSNAttrEMailContacts, )
-    
+                                                        nolabelParamTypes=("WORK", "HOME",),
+                                                        attrType=dsattributes.kDSNAttrEMailContacts,)
+
             """
             # UNIMPLEMENTED:
             # 3.3.3 MAILER Type Definition
@@ -1481,7 +1494,7 @@
             # 3.5.1 TITLE Type Definition
             for jobTitle in self.valuesForAttribute(dsattributes.kDSNAttrJobTitle):
                 addUniqueProperty(vcard, Property("TITLE", jobTitle), None, dsattributes.kDSNAttrJobTitle, jobTitle)
-    
+
             """
             # UNIMPLEMENTED:
             # 3.5.2 ROLE Type Definition
@@ -1495,8 +1508,8 @@
             department = self.joinedValuesForAttribute(dsattributes.kDSNAttrDepartment)
             extra = self.joinedValuesForAttribute(dsattributes.kDSNAttrOrganizationInfo)
             if len(company) > 0 or len(department) > 0:
-                vcard.addProperty(Property("ORG", (company, department, extra, ),))
-            
+                vcard.addProperty(Property("ORG", (company, department, extra,),))
+
             # 3.6 EXPLANATORY TYPES http://tools.ietf.org/html/rfc2426#section-3.6
             """
             # UNIMPLEMENTED:
@@ -1508,17 +1521,17 @@
             notes = self.valuesForAttribute(dsattributes.kDS1AttrComment, []) + self.valuesForAttribute(dsattributes.kDS1AttrNote, []);
             if len(notes):
                 vcard.addProperty(Property("NOTE", "\n".join(notes),))
-    
+
             # 3.6.3 PRODID Type Definition
             #vcard.addProperty(Property("PRODID", vCardProductID + "//BUILD %s" % twistedcaldav.__version__))
             #vcard.addProperty(Property("PRODID", vCardProductID))
             # ADDED WITH CONTSTANT PROPERTIES
-            
+
             # 3.6.4 REV Type Definition
             revDate = self.isoDateStringForDateAttribute(dsattributes.kDS1AttrModificationTimestamp)
             if revDate:
                 vcard.addProperty(Property("REV", PyCalendarDateTime.parseText(revDate, fullISO=True)))
-            
+
             """
             # UNIMPLEMENTED:
             # 3.6.5 SORT-STRING Type Definition
@@ -1528,31 +1541,31 @@
             # dsattributes.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.
-                                                        
+
             vcard.addProperty(Property("UID", self.firstValueForAttribute(dsattributes.kDS1AttrGeneratedUID)))
-    
-    
+
+
             # 3.6.8 URL Type Definition 
             # dsattributes.kDSNAttrURL,                 # List of URLs.
             # dsattributes.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
             for url in self.valuesForAttribute(dsattributes.kDS1AttrWeblogURI):
-                addPropertyAndLabel(groupCount, "weblog", "URL", url, parameters = {"TYPE": ["WEBLOG",]})
-    
+                addPropertyAndLabel(groupCount, "weblog", "URL", url, parameters={"TYPE": ["WEBLOG", ]})
+
             for url in self.valuesForAttribute(dsattributes.kDSNAttrURL):
-                addPropertyAndLabel(groupCount, "_$!<HomePage>!$_", "URL", url, parameters = {"TYPE": ["HOMEPAGE",]})
-    
-    
+                addPropertyAndLabel(groupCount, "_$!<HomePage>!$_", "URL", url, parameters={"TYPE": ["HOMEPAGE", ]})
+
+
             # 3.6.9 VERSION Type Definition
             # ALREADY ADDED
-    
+
             # 3.7 SECURITY TYPES http://tools.ietf.org/html/rfc2426#section-3.7
             # 3.7.1 CLASS Type Definition
             # ALREADY ADDED
-            
+
             # 3.7.2 KEY Type Definition
-            
+
             # dsattributes.kDSNAttrPGPPublicKey,        # Pretty Good Privacy public encryption key.
             # dsattributes.kDS1AttrUserCertificate,     # Attribute containing the binary of the user's certificate.
                                                         #       Usually found in user records. The certificate is data which identifies a user.
@@ -1566,19 +1579,19 @@
                                                         #       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.
-    
+
             for key in self.valuesForAttribute(dsattributes.kDSNAttrPGPPublicKey):
-                addUniqueProperty(vcard, Property("KEY", key, params = {"ENCODING": ["b",], "TYPE": ["PGPPublicKey",]}), None, dsattributes.kDSNAttrPGPPublicKey, key)
-    
+                addUniqueProperty(vcard, Property("KEY", key, params={"ENCODING": ["b", ], "TYPE": ["PGPPublicKey", ]}), None, dsattributes.kDSNAttrPGPPublicKey, key)
+
             for key in self.valuesForAttribute(dsattributes.kDS1AttrUserCertificate):
-                addUniqueProperty(vcard, Property("KEY", key, params = {"ENCODING": ["b",], "TYPE": ["UserCertificate",]}), None, dsattributes.kDS1AttrUserCertificate, key)
-    
+                addUniqueProperty(vcard, Property("KEY", key, params={"ENCODING": ["b", ], "TYPE": ["UserCertificate", ]}), None, dsattributes.kDS1AttrUserCertificate, key)
+
             for key in self.valuesForAttribute(dsattributes.kDS1AttrUserPKCS12Data):
-                addUniqueProperty(vcard, Property("KEY", key, params = {"ENCODING": ["b",], "TYPE": ["UserPKCS12Data",]}), None, dsattributes.kDS1AttrUserPKCS12Data, key)
-    
+                addUniqueProperty(vcard, Property("KEY", key, params={"ENCODING": ["b", ], "TYPE": ["UserPKCS12Data", ]}), None, dsattributes.kDS1AttrUserPKCS12Data, key)
+
             for key in self.valuesForAttribute(dsattributes.kDS1AttrUserSMIMECertificate):
-                addUniqueProperty(vcard, Property("KEY", key, params = {"ENCODING": ["b",], "TYPE": ["UserSMIMECertificate",]}), None, dsattributes.kDS1AttrUserSMIMECertificate, key)
-    
+                addUniqueProperty(vcard, Property("KEY", key, params={"ENCODING": ["b", ], "TYPE": ["UserSMIMECertificate", ]}), None, dsattributes.kDS1AttrUserSMIMECertificate, key)
+
             """
             X- attributes, Address Book support
             """
@@ -1588,21 +1601,21 @@
                                                         #      Values should be prefixed with the appropriate IM type
                                                         #       ie. AIM:, Jabber:, MSN:, Yahoo:, or ICQ:
                                                         #       Usually found in user records (kDSStdRecordTypeUsers).
-            imNolabelParamTypes=("AIM", "FACEBOOK", "GAGU-GAGU", "GOOGLE TALK", "ICQ", "JABBER", "MSN", "QQ", "SKYPE", "YAHOO",)
+            imNolabelParamTypes = ("AIM", "FACEBOOK", "GAGU-GAGU", "GOOGLE TALK", "ICQ", "JABBER", "MSN", "QQ", "SKYPE", "YAHOO",)
             addPropertiesAndLabelsForPrefixedAttribute(groupCount=groupCount, propertyPrefix="X-", propertyName=None, defaultLabel="aim",
-                                                        nolabelParamTypes=imNolabelParamTypes, 
+                                                        nolabelParamTypes=imNolabelParamTypes,
                                                         attrType=dsattributes.kDSNAttrIMHandle,)
-            
-            
 
+
+
             # IMPP
             # Address Book's implementation of http://tools.ietf.org/html/rfc6350#section-6.4.3
             # adding IMPP property allows ab query report search on one property
             addPropertiesAndLabelsForPrefixedAttribute(groupCount=groupCount, propertyPrefix=None, propertyName="IMPP", defaultLabel="aim",
-                                                        specialParamType = "X-SERVICE-TYPE",
-                                                        nolabelParamTypes=imNolabelParamTypes, 
+                                                        specialParamType="X-SERVICE-TYPE",
+                                                        nolabelParamTypes=imNolabelParamTypes,
                                                         attrType=dsattributes.kDSNAttrIMHandle,)
-                    
+
             # X-ABRELATEDNAMES
             # dsattributes.kDSNAttrRelationships,       #      multi-valued attribute that defines the relationship to the record type .
                                                         #      found in user records (kDSStdRecordTypeUsers). 
@@ -1619,9 +1632,9 @@
                                                             "PARTNER":"_$!<Partner>!$_",
                                                             "ASSISTANT":"_$!<Assistant>!$_",
                                                             "MANAGER":"_$!<Manager>!$_", },
-                                                        attrType=dsattributes.kDSNAttrRelationships, )
-            
-            
+                                                        attrType=dsattributes.kDSNAttrRelationships,)
+
+
             # special case for Apple
             if self.appleInternalServer:
                 for manager in self.valuesForAttribute("dsAttrTypeNative:appleManager"):
@@ -1632,17 +1645,17 @@
                         managerValue = "%s %s" % (splitManager[0], splitManager[1])
                     else:
                         managerValue = manager
-                    addPropertyAndLabel( groupCount, "_$!<Manager>!$_", "X-ABRELATEDNAMES", managerValue, parameters={ "TYPE": ["MANAGER",]} )
-            
- 
+                    addPropertyAndLabel(groupCount, "_$!<Manager>!$_", "X-ABRELATEDNAMES", managerValue, parameters={ "TYPE": ["MANAGER", ]})
+
+
             # add apple-defined group vcard properties if record type is group
             if self.kind == "group":
                 vcard.addProperty(Property("X-ADDRESSBOOKSERVER-KIND", "group"))
-            
+
             # add members
             for memberguid in self.valuesForAttribute(dsattributes.kDSNAttrGroupMembers):
                 vcard.addProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", "urn:uuid:" + memberguid))
-    
+
             """
             # UNIMPLEMENTED: X- attributes
             
@@ -1663,15 +1676,15 @@
             dsattributes.kDSNAttrMIME,                  # Data contained in this attribute type is a fully qualified MIME Type. 
             
             """
-            
+
             # 2.1.4 SOURCE Type http://tools.ietf.org/html/rfc2426#section-2.1.4
             #    If the SOURCE type is present, then its value provides information
             #    how to find the source for the vCard.
-            
+
             # add the source, so that if the SOURCE is copied out and preserved, the client can refresh information
             # However, client should really do a ab-query report matching UID on /directory/ not a multiget.
             uri = joinURL(self._directoryBackedAddressBook.uri, vcard.propertyValue("UID") + ".vcf")
-            
+
             # seems like this should be in some standard place.
             if config.EnableSSL and config.SSLPort:
                 if config.SSLPort == 443:
@@ -1680,18 +1693,18 @@
                     source = "https://%s:%s%s" % (config.ServerHostName, config.SSLPort, uri)
             else:
                 if config.HTTPPort == 80:
-                    source = "http://%s%s" % (config.ServerHostName, uri) 
+                    source = "http://%s%s" % (config.ServerHostName, uri)
                 else:
                     source = "http://%s:%s%s" % (config.ServerHostName, config.HTTPPort, uri)
             vcard.addProperty(Property("SOURCE", source))
-                       
+
             #  in 4.0 spec: 
             # 6.1.4.  KIND http://tools.ietf.org/html/rfc6350#section-6.1.4
             # 
             # see also: http://www.iana.org/assignments/vcard-elements/vcard-elements.xml
             #
             vcard.addProperty(Property("KIND", self.kind))
-            
+
             # one more X- related to kind
             if self.kind == "org":
                 vcard.addProperty(Property("X-ABShowAs", "COMPANY"))
@@ -1701,40 +1714,40 @@
             if self.addDSAttrXProperties:
                 for attribute in self.originalAttributes:
                     for value in self.valuesForAttribute(attribute):
-                        vcard.addProperty(Property("X-"+"-".join(attribute.split(":")), removeControlChars(value)))
-    
+                        vcard.addProperty(Property("X-" + "-".join(attribute.split(":")), removeControlChars(value)))
+
             return vcard
 
-        
+
         if not self._vCard:
             self._vCard = generateVCard()
-        
+
         return self._vCard
-    
+
     def vCardText(self):
         return str(self.vCard())
-    
+
     def uri(self):
         return self.vCard().propertyValue("UID") + ".vcf"
-        
+
     def hRef(self, parentURI=None):
         return davxml.HRef.fromString(joinURL(parentURI if parentURI else  self._directoryBackedAddressBook.uri, self.uri()))
- 
-                       
+
+
     def readProperty(self, property, request):
-        
+
         if type(property) is tuple:
             qname = property
         else:
             qname = property.qname()
         namespace, name = qname
-                
+
         if namespace == dav_namespace:
             if name == "resourcetype":
                 result = davxml.ResourceType.empty #@UndefinedVariable
                 return result
             elif name == "getetag":
-                result = davxml.GETETag( ETag(hashlib.md5(self.vCardText()).hexdigest()).generate() )
+                result = davxml.GETETag(ETag(hashlib.md5(self.vCardText()).hexdigest()).generate())
                 return result
             elif name == "getcontenttype":
                 mimeType = MimeType('text', 'vcard', {})
@@ -1785,8 +1798,8 @@
 
         # Add dynamic live properties that exist
         dynamicLiveProperties = (
-            (dav_namespace, "quota-available-bytes"     ),
-            (dav_namespace, "quota-used-bytes"          ),
+            (dav_namespace, "quota-available-bytes"),
+            (dav_namespace, "quota-used-bytes"),
         )
         for dqname in dynamicLiveProperties:
             qnames.remove(dqname)
@@ -1796,12 +1809,12 @@
                 qnames.add(qname)
 
         yield qnames
-        
+
     listProperties = deferredGenerator(listProperties)
-    
+
 # utility
 #remove illegal XML
-def removeControlChars( utf8String ):
+def removeControlChars(utf8String):
     result = ''.join([c for c in utf8String if c not in "\x01\x02\x03\x04\x05\x06\x07\x08\x0b\x0c\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"])
     return result
 

Modified: CalendarServer/branches/users/gaya/directorybacker/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/branches/users/gaya/directorybacker/twistedcaldav/stdconfig.py	2013-03-10 06:57:22 UTC (rev 10885)
+++ CalendarServer/branches/users/gaya/directorybacker/twistedcaldav/stdconfig.py	2013-03-11 20:20:39 UTC (rev 10886)
@@ -245,7 +245,7 @@
         "authMethod": "LDAP",
         "rdnSchema": {
             "base": "dc=example,dc=com",
-            "queryTypes": ("people", ),
+            "queryTypes": ("people",),
             "people": {
                 "rdn": "ou=People",
                 "attr": "uid", # used only to synthesize email address
@@ -547,8 +547,8 @@
         "Enabled" : True,
         "Seconds" : 60, # How often to check memory sizes (in seconds)
         "Bytes"   : 2 * 1024 * 1024 * 1024, # Memory limit (RSS in bytes)
-        "ResidentOnly" : True,  # True: only take into account resident memory;
-                                # False: include virtual memory
+        "ResidentOnly" : True, # True: only take into account resident memory;
+                              # False: include virtual memory
     },
 
     #
@@ -681,7 +681,7 @@
             "Enabled"          : False, # iSchedule protocol
             "AddressPatterns"  : [], # Reg-ex patterns to match iSchedule-able calendar user addresses
             "RemoteServers"    : "remoteservers.xml", # iSchedule server configurations
-            "SerialNumber"     : 1,  # Capabilities serial number
+            "SerialNumber"     : 1, # Capabilities serial number
             "DNSDebug"         : "", # File where a fake Bind zone exists for creating fake DNS results
             "DKIM"             : {      # DKIM options
                 "Enabled"               : True, # DKIM signing/verification enabled
@@ -992,7 +992,7 @@
     # DirectoryService.framework)
     # "calendarserver.platform.darwin.od.opendirectory" is the new PyObjC
     # version which uses OpenDirectory.framework
-    "OpenDirectoryModule": "opendirectory",
+    "OpenDirectoryModule": "calendarserver.platform.darwin.od.opendirectory",
 
     # The RootResource uses a twext property store. Specify the class here
     "RootResourcePropStoreClass": "twext.web2.dav.xattrprops.xattrPropertyStore",
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20130311/f0c52b58/attachment-0001.html>


More information about the calendarserver-changes mailing list