[CalendarServer-changes] [9133] CalendarServer/branches/users/gaya/ldapdirectorybacker

source_changes at macosforge.org source_changes at macosforge.org
Mon Apr 16 16:10:11 PDT 2012


Revision: 9133
          http://trac.macosforge.org/projects/calendarserver/changeset/9133
Author:   gaya at apple.com
Date:     2012-04-16 16:10:10 -0700 (Mon, 16 Apr 2012)
Log Message:
-----------
support ldap group vCards

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

Added Paths:
-----------
    CalendarServer/branches/users/gaya/ldapdirectorybacker/conf/carddav-ldaptest2.plist

Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/conf/carddav-ldaptest.plist
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/conf/carddav-ldaptest.plist	2012-04-16 22:38:03 UTC (rev 9132)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/conf/carddav-ldaptest.plist	2012-04-16 23:10:10 UTC (rev 9133)
@@ -1269,39 +1269,6 @@
     						<string>EMailAddress</string>
     					</dict>
                     </dict>
-                    <!-- people vCards for another server.  Unused
-                    <dict>
-                        <key>ldapAttrToDSAttrMap</key>
-                        <dict>
-                            <key>givenName</key>
-                            <string>FirstName</string>
-                            <key>sn</key>
-                            <string>LastName</string>
-                            <key>cn</key>
-                            <array>
-                                <string>RealName</string>
-                                <string>RecordName</string>
-                            </array>
-                            <key>mail</key>
-                            <string>EMailAddress</string>
-                            <key>uid</key>
-                            <string>GeneratedUID</string>
-                        </dict>
-                        <key>rdn</key>
-                        <string>ou=People</string>
-                        <key>filter</key>
-                        <string></string>
-                        <key>vcardPropToLdapAttrMap</key>
-                        <dict>
-                            <key>FN</key>
-                            <string>cn</string>
-                            <key>EMAIL</key>
-                            <string>mail</string>
-                            <key>UID</key>
-                            <string>uid</string>
-                        </dict>
-                    </dict>
-                    -->
                 </array>
 			</dict>
 		</dict>

Added: CalendarServer/branches/users/gaya/ldapdirectorybacker/conf/carddav-ldaptest2.plist
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/conf/carddav-ldaptest2.plist	                        (rev 0)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/conf/carddav-ldaptest2.plist	2012-04-16 23:10:10 UTC (rev 9133)
@@ -0,0 +1,1277 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Copyright (c) 2006-2012 Apple Inc. All rights reserved.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+  -->
+
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+  <dict>
+
+    <!--
+        Public network address information
+
+        This is the server's public network address, which is provided to
+        clients in URLs and the like.  It may or may not be the network
+        address that the server is listening to directly, though it is by
+        default.  For example, it may be the address of a load balancer or
+        proxy which forwards connections to the server.
+      -->
+
+    <!-- Network host name [empty = system host name] -->
+    <key>ServerHostName</key>
+    <string></string> <!-- The hostname clients use when connecting -->
+
+    <!-- Enable Calendars -->
+    <key>EnableCalDAV</key>
+    <true/>
+
+    <!-- Enable AddressBooks -->
+    <key>EnableCardDAV</key>
+    <true/>
+
+    <!-- HTTP port [0 = disable HTTP] -->
+    <key>HTTPPort</key>
+    <integer>8008</integer>
+
+    <!-- SSL port [0 = disable HTTPS] -->
+    <!-- (Must also configure SSLCertificate and SSLPrivateKey below) -->
+    <key>SSLPort</key>
+    <integer>8443</integer>
+
+    <!-- Enable listening on SSL port(s) -->
+    <key>EnableSSL</key>
+    <true/>
+
+    <!-- Redirect non-SSL ports to an SSL port (if configured for SSL) -->
+    <key>RedirectHTTPToHTTPS</key>
+    <false/>
+
+
+    <!--
+        Network address configuration information
+
+        This configures the actual network address that the server binds to.
+      -->
+
+    <!-- List of IP addresses to bind to [empty = all] -->
+    <key>BindAddresses</key>
+    <array>
+    </array>
+
+    <!-- List of port numbers to bind to for HTTP [empty = same as "Port"] -->
+    <key>BindHTTPPorts</key>
+    <array>
+        <integer>8008</integer>
+        <integer>8800</integer>
+    </array>
+
+    <!-- List of port numbers to bind to for SSL [empty = same as "SSLPort"] -->
+    <key>BindSSLPorts</key>
+    <array>
+        <integer>8443</integer>
+        <integer>8843</integer>
+    </array>
+
+
+    <!--
+        Data Store
+      -->
+
+    <!-- Server root -->
+    <key>ServerRoot</key>
+    <string>./data</string>
+
+    <!-- Database connection -->
+    <!--
+    <key>DBType</key>
+    <string>postgres</string>
+    <key>DSN</key>
+    <string>:caldav:caldav:::</string>
+     -->
+
+    <!-- Data root -->
+    <key>DataRoot</key>
+    <string>Data</string>
+
+    <!-- Database root -->
+    <key>DatabaseRoot</key>
+    <string>Database</string>
+
+    <!-- Document root -->
+    <key>DocumentRoot</key>
+    <string>Documents</string>
+
+    <!-- Configuration root -->
+    <key>ConfigRoot</key>
+    <string>./conf</string>
+
+    <!-- Run root -->
+    <key>RunRoot</key>
+    <string>Logs/state</string>
+
+    <!-- Child aliases -->
+    <key>Aliases</key>
+    <dict>
+      <!--
+      <key>foo</key>
+      <dict>
+        <key>path</key>
+        <string>/path/to/foo</string>
+      </dict>
+       -->
+    </dict>
+
+
+    <!--
+        Quotas and limits
+      -->
+
+    <!-- User quota (in bytes) [0 = no quota] applies to attachments only -->
+    <key>UserQuota</key>
+    <integer>104857600</integer><!-- 100Mb -->
+
+    <!-- Maximum number of calendars/address books allowed in a home -->
+    <!-- 0 for no limit -->
+    <key>MaxCollectionsPerHome</key>
+    <integer>50</integer>
+
+    <!-- Maximum number of resources in a calendar/address book -->
+    <!-- 0 for no limit -->
+    <key>MaxResourcesPerCollection</key>
+    <integer>10000</integer>
+
+    <!-- Maximum resource size (in bytes) -->
+    <key>MaxResourceSize</key>
+    <integer>1048576</integer> <!-- 1Mb -->
+
+    <!-- Maximum number of unique attendees per entire event -->
+    <!-- 0 for no limit -->
+    <key>MaxAttendeesPerInstance</key>
+    <integer>100</integer>
+
+    <!-- Maximum number of instances allowed during expansion -->
+    <!-- 0 for no limit -->
+    <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
+
+        A directory service provides information about principals (eg.
+        users, groups, locations and resources) to the server.
+
+        A variety of directory services are available for use.
+      -->
+
+    <!-- XML File Directory Service -->
+    <key>DirectoryService</key>
+    <dict>
+      <key>type</key>
+      <string>twistedcaldav.directory.xmlfile.XMLDirectoryService</string>
+      
+      <key>params</key>
+      <dict>
+        <key>xmlFile</key>
+        <string>./conf/auth/accounts-test.xml</string>
+      </dict>
+    </dict>
+    
+    <!-- Open Directory Service (Mac OS X) -->
+    <!--
+    <key>DirectoryService</key>
+    <dict>
+      <key>type</key>
+      <string>twistedcaldav.directory.appleopendirectory.OpenDirectoryService</string>
+      
+      <key>params</key>
+      <dict>
+        <key>node</key>
+        <string>/Search</string>
+        <key>cacheTimeout</key>
+        <integer>10</integer>
+      </dict>
+    </dict>
+    -->
+
+    <!--  OpenLDAP Directory Service -->
+    <!--
+    <key>DirectoryService</key>
+    <dict>
+      <key>type</key>
+      <string>twistedcaldav.directory.ldapdirectory.LdapDirectoryService</string>
+
+      <key>params</key>
+      <dict>
+        <key>restrictEnabledRecords</key>
+        <false/>
+        <key>restrictToGroup</key>
+        <string>odtestgrouptop</string>
+        <key>cacheTimeout</key>
+        <integer>30</integer>
+        <key>uri</key>
+        <string>ldap://example.com/</string>
+        <key>tls</key>
+        <false/>
+        <key>tlsCACertFile</key>
+        <string></string>
+        <key>tlsCACertDir</key>
+        <string></string>
+        <key>tlsRequireCert</key>
+        <string>never</string>
+        <key>credentials</key>
+        <dict>
+          <key>dn</key>
+          <string></string>
+          <key>password</key>
+          <string></string>
+        </dict>
+        <key>authMethod</key>
+        <string>LDAP</string>
+        <key>rdnSchema</key>
+        <dict>
+          <key>base</key>
+          <string>dc=example,dc=com</string>
+          <key>guidAttr</key>
+          <string>apple-generateduid</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>
+            <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>
+            </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>
+            <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>
+            </dict>
+          </dict>
+        </dict>
+        <key>groupSchema</key>
+        <dict>
+          <key>membersAttr</key>
+          <string>apple-group-memberguid</string>
+          <key>nestedGroupsAttr</key>
+          <string>apple-group-nestedgroup</string>
+          <key>memberIdAttr</key>
+          <string>apple-generateduid</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>
+        </dict>
+      </dict>
+    </dict>
+    -->
+
+    <!-- Resource and Location Service -->
+    <key>ResourceService</key>
+    <dict>
+      <key>Enabled</key>
+      <true/>
+      <key>type</key>
+      <string>twistedcaldav.directory.xmlfile.XMLDirectoryService</string>
+      
+      <key>params</key>
+      <dict>
+        <key>xmlFile</key>
+        <string>./conf/auth/resources-test.xml</string>
+      </dict>
+    </dict>
+
+    <!-- XML File Augment Service -->
+    <key>AugmentService</key>
+    <dict>
+      <key>type</key>
+      <string>twistedcaldav.directory.augment.AugmentXMLDB</string>
+      
+      <key>params</key>
+      <dict>
+        <key>xmlFiles</key>
+        <array>
+	      <string>./conf/auth/augments-test.xml</string>
+        </array>
+      </dict>
+    </dict>
+
+    <!-- Sqlite Augment Service -->
+    <!--
+    <key>AugmentService</key>
+    <dict>
+      <key>type</key>
+      <string>twistedcaldav.directory.augment.AugmentSqliteDB</string>
+      
+      <key>params</key>
+      <dict>
+        <key>dbpath</key>
+        <string>./conf/auth/augments.sqlite</string>
+      </dict>
+    </dict>
+     -->
+
+    <!-- PostgreSQL Augment Service -->
+    <!--
+    <key>AugmentService</key>
+    <dict>
+      <key>type</key>
+      <string>twistedcaldav.directory.augment.AugmentPostgreSQLDB</string>
+      
+      <key>params</key>
+      <dict>
+        <key>host</key>
+        <string>localhost</string>
+        <key>database</key>
+        <string>augments</string>
+      </dict>
+    </dict>
+     -->
+
+    <!-- Sqlite ProxyDB Service -->
+    <key>ProxyDBService</key>
+    <dict>
+      <key>type</key>
+      <string>twistedcaldav.directory.calendaruserproxy.ProxySqliteDB</string>
+      
+      <key>params</key>
+      <dict>
+        <key>dbpath</key>
+        <string>proxies.sqlite</string>
+      </dict>
+    </dict>
+
+    <!-- PostgreSQL ProxyDB Service -->
+    <!--
+    <key>ProxyDBService</key>
+    <dict>
+      <key>type</key>
+      <string>twistedcaldav.directory.calendaruserproxy.ProxyPostgreSQLDB</string>
+      
+      <key>params</key>
+      <dict>
+        <key>host</key>
+        <string>localhost</string>
+        <key>database</key>
+        <string>proxies</string>
+      </dict>
+    </dict>
+     -->
+
+    <key>ProxyLoadFromFile</key>
+    <string>./conf/auth/proxies-test.xml</string>
+
+
+    <!--
+        Special principals
+
+        These principals are granted special access and/or perform
+        special roles on the server.
+      -->
+
+    <!-- Principals with "DAV:all" access (relative URLs) -->
+    <key>AdminPrincipals</key>
+    <array>
+      <string>/principals/__uids__/admin/</string>
+    </array>
+
+    <!-- Principals with "DAV:read" access (relative URLs) -->
+    <key>ReadPrincipals</key>
+    <array>
+      <!-- <string>/principals/__uids__/983C8238-FB6B-4D92-9242-89C0A39E5F81/</string> -->
+    </array>
+
+    <!-- Create "proxy access" principals -->
+    <key>EnableProxyPrincipals</key>
+    <true/>
+
+
+    <!--
+        Permissions
+      -->
+
+    <!-- Anonymous read access for root resource -->
+    <key>EnableAnonymousReadRoot</key>
+    <true/>
+
+    <!-- Anonymous read access for resource hierarchy -->
+    <key>EnableAnonymousReadNav</key>
+    <false/>
+
+    <!-- Enables directory listings for principals -->
+    <key>EnablePrincipalListings</key>
+    <true/>
+
+    <!-- Render calendar collections as a monolithic iCalendar object -->
+    <key>EnableMonolithicCalendars</key>
+    <true/>
+
+
+    <!--
+        Authentication
+      -->
+
+    <key>Authentication</key>
+    <dict>
+
+      <!-- Clear text; best avoided -->
+      <key>Basic</key>
+      <dict>
+        <key>Enabled</key>
+        <true/>
+      </dict>
+
+      <!-- Digest challenge/response -->
+      <key>Digest</key>
+      <dict>
+        <key>Enabled</key>
+        <true/>
+        <key>Algorithm</key>
+        <string>md5</string>
+        <key>Qop</key>
+        <string></string>
+      </dict>
+
+      <!-- Kerberos/SPNEGO -->
+      <key>Kerberos</key>
+      <dict>
+        <key>Enabled</key>
+        <true/>
+        <key>ServicePrincipal</key>
+        <string></string>
+      </dict>
+
+      <!-- Wikiserver authentication (Mac OS X) -->
+      <key>Wiki</key>
+      <dict>
+        <key>Enabled</key>
+        <true/>
+        <key>Cookie</key>
+        <string>sessionID</string>
+        <key>URL</key>
+        <string>http://127.0.0.1/RPC2</string>
+        <key>UserMethod</key>
+        <string>userForSession</string>
+        <key>WikiMethod</key>
+        <string>accessLevelForUserWikiCalendar</string>
+      </dict>
+
+    </dict>
+
+
+    <!--
+        Logging
+      -->
+
+    <!-- Log root -->
+    <key>LogRoot</key>
+    <string>Logs</string>
+
+    <!-- Apache-style access log -->
+    <key>AccessLogFile</key>
+    <string>access.log</string>
+    <key>RotateAccessLog</key>
+    <false/>
+
+    <!-- Server activity log -->
+    <key>ErrorLogFile</key>
+    <string>error.log</string>
+
+    <!-- Log levels -->
+    <key>DefaultLogLevel</key>
+    <string>debug</string> <!-- debug, info, warn, error -->
+
+    <!-- Log level overrides for specific functionality -->
+    <key>LogLevels</key>
+    <dict>
+      <!--
+      <key>twistedcaldav.directory.appleopendirectory.OpenDirectoryService</key>
+      <string>debug</string>
+      -->
+    </dict>
+
+    <!-- Server process ID file -->
+    <key>PIDFile</key>
+    <string>caldavd.pid</string>
+
+
+    <!--
+        Accounting
+      -->
+
+    <!-- Enable accounting for certain operations -->
+    <key>AccountingCategories</key>
+    <dict>
+      <key>iTIP</key>
+      <false/>
+      <key>HTTP</key>
+      <false/>
+    </dict>
+
+    <!-- Enable accounting for specific principals -->
+    <key>AccountingPrincipals</key>
+    <array>
+      <!-- <string>/principals/__uids__/454D85C0-09F0-4DC6-A3C6-97DFEB4622CD/</string> -->
+    </array>
+
+
+    <!--
+        SSL/TLS
+      -->
+
+    <!-- Public key -->
+    <key>SSLCertificate</key>
+    <string>twistedcaldav/test/data/server.pem</string>
+
+    <!-- SSL authority chain (for intermediate certs) -->
+    <key>SSLAuthorityChain</key>
+    <string></string>
+
+    <!-- Private key -->
+    <key>SSLPrivateKey</key>
+    <string>twistedcaldav/test/data/server.pem</string>
+
+
+    <!--
+        Process management
+      -->
+
+    <key>UserName</key>
+    <string></string>
+
+    <key>GroupName</key>
+    <string></string>
+
+    <key>ProcessType</key>
+    <string>Combined</string>
+
+    <key>MultiProcess</key>
+    <dict>
+      <key>ProcessCount</key>
+      <integer>2</integer> <!-- 0 = automatic -->
+    </dict>
+
+
+    <!--
+        Notifications
+      -->
+
+    <key>Notifications</key>
+    <dict>
+      <!-- Time spent coalescing notifications before delivery -->
+      <key>CoalesceSeconds</key>
+      <integer>3</integer>
+
+      <key>InternalNotificationHost</key>
+      <string>localhost</string>
+
+      <key>InternalNotificationPort</key>
+      <integer>62309</integer>
+
+      <key>Services</key>
+      <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>
+
+
+    <!--
+        Server-to-server protocol
+      -->
+
+    <key>Scheduling</key>
+    <dict>
+
+      <!-- CalDAV protocol options -->
+      <key>CalDAV</key>
+      <dict>
+        <key>EmailDomain</key>
+        <string></string>
+        <key>HTTPDomain</key>
+        <string></string>
+        <key>AddressPatterns</key>
+        <array>
+        </array>
+        <key>OldDraftCompatibility</key>
+        <true/>
+        <key>ScheduleTagCompatibility</key>
+        <true/>
+        <key>EnablePrivateComments</key>
+        <true/>
+      </dict>
+
+      <!-- iSchedule protocol options -->
+      <key>iSchedule</key>
+      <dict>
+        <key>Enabled</key>
+        <false/>
+        <key>AddressPatterns</key>
+        <array>
+        </array>
+        <key>Servers</key>
+        <string>servertoserver-test.xml</string>
+      </dict>
+
+      <!-- iMIP protocol options -->
+      <key>iMIP</key>
+      <dict>
+        <key>Enabled</key>
+        <false/>
+        <key>MailGatewayServer</key>
+        <string>localhost</string>
+        <key>MailGatewayPort</key>
+        <integer>62310</integer>
+        <key>Sending</key>
+        <dict>
+          <key>Server</key>
+          <string></string>
+          <key>Port</key>
+          <integer>587</integer>
+          <key>UseSSL</key>
+          <true/>
+          <key>Username</key>
+          <string></string>
+          <key>Password</key>
+          <string></string>
+          <key>Address</key>
+          <string></string> <!-- Address email will be sent from -->
+          <key>SupressionDays</key>
+          <integer>7</integer> <!-- Don't send messages for events earlier than this many days in the past -->
+        </dict>
+        <key>Receiving</key>
+        <dict>
+          <key>Server</key>
+          <string></string>
+          <key>Port</key>
+          <integer>995</integer>
+          <key>Type</key>
+          <string></string> <!-- Either "pop" or "imap" -->
+          <key>UseSSL</key>
+          <true/>
+          <key>Username</key>
+          <string></string>
+          <key>Password</key>
+          <string></string>
+          <key>PollingSeconds</key>
+          <integer>30</integer>
+        </dict>
+        <key>AddressPatterns</key>
+        <array>
+          <string>mailto:.*</string>
+        </array>
+      </dict>
+
+      <!-- General options for scheduling -->
+      <key>Options</key>
+      <dict>
+        <key>AllowGroupAsOrganizer</key>
+        <false/>
+        <key>AllowLocationAsOrganizer</key>
+        <false/>
+        <key>AllowResourceAsOrganizer</key>
+        <false/>
+        <key>AttendeeRefreshBatch</key>
+        <integer>0</integer>
+        <key>V1Compatibility</key> <!-- Allow /path-based CUAs in scheduling replies -->
+        <false/>
+
+		<key>AutoSchedule</key>
+		<dict>
+			<key>Enabled</key>
+			<true/>
+			<key>Always</key>
+			<false/>
+			<!-- Default mode for auto-schedule processing, one of:
+	              "none"            - no auto-scheduling
+	              "accept-always"   - always accept, ignore busy time
+	              "decline-always"  - always decline, ignore free time
+	              "accept-if-free"  - accept if free, do nothing if busy
+	              "decline-if-busy" - decline if busy, do nothing if free
+	              "automatic"       - accept if free, decline if busy -->
+	        <key>DefaultMode</key>
+	        <string>automatic</string>
+		</dict>
+      </dict>
+    </dict>
+
+
+    <!--
+        Free-busy URL protocol
+      -->
+
+    <key>FreeBusyURL</key>
+    <dict>
+      <key>Enabled</key>
+      <true/>
+      <key>TimePeriod</key>
+      <integer>14</integer>
+      <key>AnonymousAccess</key>
+      <false/>
+    </dict>
+
+
+    <!--
+        Non-standard CalDAV extensions
+      -->
+
+    <!-- Calendar Drop Box -->
+    <key>EnableDropBox</key>
+    <true/>
+
+    <!-- Private Events -->
+    <key>EnablePrivateEvents</key>
+    <true/>
+
+    <!-- Timezone Service -->
+    <key>EnableTimezoneService</key>
+    <true/>
+
+    <!-- Batch Upload via POST -->
+    <key>EnableBatchUpload</key>
+    <true/>
+
+    <!-- Shared Calendars & Address Books -->
+    <key>Sharing</key>
+    <dict>
+      <key>Enabled</key>
+      <true/>
+      <key>AllowExternalUsers</key>
+      <false/>
+      <key>Calendars</key>
+      <dict>
+    	<key>Enabled</key>
+    	<true/>
+      </dict>
+      <key>AddressBooks</key>
+      <dict>
+    	<key>Enabled</key>
+    	<true/>
+      </dict>
+    </dict>
+
+    <!--
+        Miscellaneous items
+      -->
+
+    <!-- Service ACLs (Mac OS X) -->
+    <key>EnableSACLs</key>
+    <false/>
+
+    <!-- Make entire server read-only -->
+    <key>EnableReadOnlyServer</key>
+    <false/>
+
+    <!-- Web-based administration -->
+    <key>EnableWebAdmin</key>
+    <true/>
+
+    <!-- Support for Content-Encoding compression options as specified in RFC2616 Section 3.5 -->
+    <key>ResponseCompression</key>
+    <false/>
+    
+    <!-- The retry-after value (in seconds) to return with a 503 error. -->
+    <key>HTTPRetryAfter</key>
+    <integer>180</integer>
+
+    <!-- For child-master IPC. [empty = use tcp] -->
+    <key>ControlSocket</key>
+    <string>caldavd.sock</string>
+
+    <!-- Support for Memcached -->
+    <key>Memcached</key>
+    <dict>
+      <key>MaxClients</key>
+      <integer>5</integer>
+      <key>memcached</key>
+      <string>memcached</string> <!-- Find in PATH -->
+      <key>Options</key>
+      <array>
+        <!--<string>-vv</string>--> <!-- Be very verbose -->
+      </array>
+    </dict>
+
+    <!-- Response Caching -->
+    <key>EnableResponseCache</key>
+    <true/>
+    <key>ResponseCacheTimeout</key>
+    <integer>30</integer> <!-- in minutes -->
+
+    <!-- Support for Postgres -->
+    <key>Postgres</key>
+    <dict>
+      <key>Options</key>
+      <array>
+      	<!-- Optional extra logging for posgres -->
+      	<!-- <string>-c log_lock_waits=TRUE</string> -->
+      	<!-- <string>-c log_statement=all</string> -->
+      	<!-- <string>-c log_line_prefix='%t [%p]: [%l] '</string> -->
+      </array>
+    </dict>
+
+    <!-- SQL Query Caching -->
+    <key>QueryCaching</key>
+    <dict>
+      <key>Enabled</key>
+      <true/>
+      <key>MemcachedPool</key>
+      <string>Default</string>
+      <key>ExpireSeconds</key>
+      <integer>3600</integer>
+    </dict>
+
+    <!-- Group Membership Caching -->
+    <key>GroupCaching</key>
+    <dict>
+      <key>Enabled</key>
+      <true/>
+      <key>EnableUpdater</key>
+      <true/>
+      <key>MemcachedPool</key>
+      <string>Default</string>
+      <key>UpdateSeconds</key>
+      <integer>300</integer>
+      <key>ExpireSeconds</key>
+      <integer>3600</integer>
+      <key>LockSeconds</key>
+      <integer>300</integer>
+      <key>UseExternalProxies</key>
+      <false/>
+    </dict>
+
+    <!-- Maximum number of results returned by principal-property-search REPORT -->
+    <key>MaxPrincipalSearchReportResults</key>
+    <integer>500</integer>
+
+    <!--
+        Twisted
+      -->
+
+    <key>Twisted</key>
+    <dict>
+      <key>twistd</key>
+      <string>../Twisted/bin/twistd</string>
+    </dict>
+
+
+    <key>Localization</key>
+    <dict>
+      <key>TranslationsDirectory</key>
+      <string>locales</string>
+      <key>LocalesDirectory</key>
+      <string>locales</string>
+      <key>Language</key>
+      <string>English</string>
+    </dict>
+
+    <!--
+        Directory Address Book
+      -->
+    
+    <!--  Disable Directory Address Book -->
+    <!--
+      <key>DirectoryAddressBook</key>
+      <false/>
+    -->
+    
+    <!-- Open Directory-backed Directory Address Book -->
+    <key>EnableSearchAddressBook</key>
+    <true/>
+    <key>DirectoryAddressBook</key>
+    <dict>
+        <key>Enabled</key>
+        <true/>
+        <!-- twistedcaldav.directory.opendirectorybacker.OpenDirectoryBackingService ->
+        <key>type</key>
+        <string>twistedcaldav.directory.opendirectorybacker.OpenDirectoryBackingService</string>
+        <key>params</key>
+        <dict>
+     	  <!- - Search for people records ->
+          <key>queryPeopleRecords</key>
+          <true/>
+     	  <!- Search for people records in this directory service node ->
+          <key>peopleNode</key>
+          <string>/Search/Contacts</string>
+     	  <!- Search for user records ->
+          <key>queryUserRecords</key>
+          <true/>
+          <key>userNode</key>
+     	  <!- Search for user records in this directory service node ->
+          <string>/Search</string>
+      	  <!- query in directory service local node ->
+          <key>queryDSLocal</key>
+          <false/>
+      	  <!- minutes to keep directory service local node in memory before refresh ->
+          <key>dsLocalCacheTimeout</key>
+          <integer>30</integer>
+     	  <!- approx. maximum number of records returned from a directory service query ->
+          <key>maxDSQueryRecords</key>
+          <integer>0</integer> <!- use 0 to have server calculate the maximum based on MaxAddressBookQueryResults, MaxAddressBookMultigetHrefs keys ->
+     	  <!- ignore system records like "root" when creating vCards ->
+          <key>ignoreSystemRecords</key>
+          <true/>
+       	  <!- fake the eTag.  If false all directory service attributes are used to calculate the eTag ->
+          <key>fakeETag</key>
+          <true/>
+          <key>generateSimpleUIDs</key>
+          <true/>
+          <key>appleInternalServer</key>
+          <false/>
+          <key>addDSAttrXProperties</key>
+          <false/>
+          <!- add this key to use additional directory service attributes in queries.  Needed for some queries with directory service templates.
+          <key>additionalAttributes</key>
+          <array>
+            <string>dsAttrTypeNative:appleAIMPreferred</string>
+            <string>dsAttrTypeNative:appleManager</string>
+          </array>
+          ->
+          <!- add this key to limit directory service attributes used to make vCard properties
+          		When using directory service templates, list should include only mapped attributes.
+          <key>allowedAttributes</key>
+          <array>
+            <string>dsAttrTypeStandard:AddressLine1</string>
+            <string>dsAttrTypeStandard:AddressLine2</string>
+            <string>dsAttrTypeStandard:AddressLine3</string>
+            <string>dsAttrTypeStandard:Birthday</string>
+            <string>dsAttrTypeStandard:Building</string>
+            <string>dsAttrTypeStandard:City</string>
+            <string>dsAttrTypeStandard:Comment</string>
+            <string>dsAttrTypeStandard:Country</string>
+            <string>dsAttrTypeStandard:CreationTimestamp</string>
+            <string>dsAttrTypeStandard:Department</string>
+            <string>dsAttrTypeStandard:EMailAddress</string>
+            <string>dsAttrTypeStandard:EMailContacts</string>
+            <string>dsAttrTypeStandard:FirstName</string>
+            <string>dsAttrTypeStandard:HomePhoneNumber</string>
+            <string>dsAttrTypeStandard:IMHandle</string>
+            <string>dsAttrTypeStandard:JPEGPhoto</string>
+            <string>dsAttrTypeStandard:JobTitle</string>
+            <string>dsAttrTypeStandard:LastName</string>
+            <string>dsAttrTypeStandard:MapCoordinates</string>
+            <string>dsAttrTypeStandard:MiddleName</string>
+            <string>dsAttrTypeStandard:MobileNumber</string>
+            <string>dsAttrTypeStandard:ModificationTimestamp</string>
+            <string>dsAttrTypeStandard:NamePrefix</string>
+            <string>dsAttrTypeStandard:NameSuffix</string>
+            <string>dsAttrTypeStandard:NickName</string>
+            <string>dsAttrTypeStandard:Note</string>
+            <string>dsAttrTypeStandard:OrganizationInfo</string>
+            <string>dsAttrTypeStandard:OrganizationName</string>
+            <string>dsAttrTypeStandard:PGPPublicKey</string>
+            <string>dsAttrTypeStandard:PagerNumber</string>
+            <string>dsAttrTypeStandard:PhoneContacts</string>
+            <string>dsAttrTypeStandard:PhoneNumber</string>
+            <string>dsAttrTypeStandard:PostalAddress</string>
+            <string>dsAttrTypeStandard:PostalAddressContacts</string>
+            <string>dsAttrTypeStandard:PostalCode</string>
+            <string>dsAttrTypeStandard:Relationships</string>
+            <string>dsAttrTypeStandard:State</string>
+            <string>dsAttrTypeStandard:Street</string>
+            <string>dsAttrTypeStandard:URL</string>
+            <string>dsAttrTypeStandard:UserCertificate</string>
+            <string>dsAttrTypeStandard:UserPKCS12Data</string>
+            <string>dsAttrTypeStandard:UserSMIMECertificate</string>
+            <string>dsAttrTypeStandard:WeblogURI</string>
+          </array>
+          ->
+        </dict>
+        -->
+        <!-- twistedcaldav.directory.opendirectorybacker.OpenDirectoryBackingService -->
+ 		<key>type</key>
+		<string>twistedcaldav.directory.ldapdirectorybacker.LdapDirectoryBackingService</string>
+		<key>params</key>
+		<dict>
+			<key>warningThresholdSeconds</key>
+			<integer>1</integer>
+			<key>appleInternalServer</key>
+			<true/>
+            <!-- fake uri, fill in.  -->
+			<key>uri</key>
+			<string>ldap://example.com/</string>
+            <!-- fill in auth info, if needed.  -->
+			<key>tls</key>
+			<false/>
+			<key>tlsCACertFile</key>
+			<string></string>
+			<key>tlsCACertDir</key>
+			<string></string>
+			<key>tlsRequireCert</key>
+			<string>never</string>
+			<key>credentials</key>
+			<dict/>
+			<key>authMethod</key>
+			<string>LDAP</string>
+			<key>rdnSchema</key>
+			<dict>
+				<key>base</key>
+                <string>o=apple.com,o=email</string>
+                <key>queries</key>
+                <array>
+                    <!-- people vCards for another server. -->
+                    <dict>
+                        <key>rdn</key>
+                        <string>ou=People</string>
+                        <key>filter</key>
+                        <string></string>
+                        <!-- map from ab query to indexed ldap attribute.  If unindexed, too slow.  -->
+                        <key>ldapAttrToDSAttrMap</key>
+                        <dict>
+                            <key>givenName</key>
+                            <string>FirstName</string>
+                            <key>sn</key>
+                            <string>LastName</string>
+                            <key>cn</key>
+                            <array>
+                                <string>RealName</string>
+                                <string>RecordName</string>
+                            </array>
+                            <key>mail</key>
+                            <string>EMailAddress</string>
+                            <key>uid</key>
+                            <string>GeneratedUID</string>
+                        </dict>
+                        <key>vcardPropToLdapAttrMap</key>
+                        <dict>
+                            <key>FN</key>
+                            <string>cn</string>
+                            <key>EMAIL</key>
+                            <string>mail</string>
+                            <key>UID</key>
+                            <string>uid</string>
+                        </dict>
+                    </dict>
+                    <!-- group vCards for another server.
+                    <dict>
+                        <key>rdn</key>
+                        <string>ou=Groups</string>
+                        <key>filter</key>
+                        <string></string>
+                        <key>additionalVCardProps</key>
+                         <dict>
+                            <key>X-ADDRESSBOOKSERVER-KIND</key>
+                            <string>group</string>
+                        </dict>
+                        <key>ldapAttrTransforms</key>
+                        <dict>
+                            <key>uniqueMember</key>
+                            <array>
+                                <string>uid</string>
+                                <string>cn</string>
+                            </array>
+                        </dict>
+                        <key>ldapAttrToDSAttrMap</key>
+                        <dict>
+                            <key>givenName</key>
+                            <string>FirstName</string>
+                            <key>sn</key>
+                            <string>LastName</string>
+                            <key>description</key>
+                            <array>
+                                <string>RealName</string>
+                            </array>
+                            <key>cn</key>
+                            <array>
+                                <string>GeneratedUID</string>
+                            </array>
+                            <key>mail</key>
+                            <string>EMailAddress</string>
+                            <key>uniqueMember</key>
+                            <string>GroupMembers</string>
+                        </dict>
+                        <key>vcardPropToLdapAttrMap</key>
+                        <dict>
+                            <key>FN</key>
+                            <string>cn</string>
+                            <key>EMAIL</key>
+                            <string>mail</string>
+                            <key>UID</key>
+                            <string>cn</string>
+                        </dict>
+                    </dict>
+                    -->
+                    <!-- distribution list vCards for another server. Cannot use with groups because UID/href is not unique -->
+                    <dict>
+                        <key>rdn</key>
+                        <string>ou=Groups</string>
+                        <key>filter</key>
+                        <string></string>
+                        <key>additionalVCardProps</key>
+                         <dict>
+                            <key>X-ABShowAs</key>
+                            <string>COMPANY</string>
+                        </dict>
+                        <key>ldapAttrToDSAttrMap</key>
+                        <dict>
+                            <key>givenName</key>
+                            <string>FirstName</string>
+                            <key>sn</key>
+                            <string>LastName</string>
+                            <key>description</key>
+                            <array>
+                                <string>RealName</string>
+                            </array>
+                            <key>cn</key>
+                            <array>
+                                <string>GeneratedUID</string>
+                            </array>
+                            <key>mail</key>
+                            <string>EMailAddress</string>
+                            <key>uniqueMember</key>
+                            <string>Comment</string>
+                        </dict>
+                        <key>vcardPropToLdapAttrMap</key>
+                        <dict>
+                            <key>FN</key>
+                            <array>
+                                <string>cn</string>
+                            </array>
+                            <key>EMAIL</key>
+                            <string>mail</string>
+                            <key>UID</key>
+                            <string>cn</string>
+                        </dict>
+                    </dict>
+                </array>
+			</dict>
+		</dict>
+   </dict>
+  </dict>
+</plist>

Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/ldapdirectorybacker.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/ldapdirectorybacker.py	2012-04-16 22:38:03 UTC (rev 9132)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/ldapdirectorybacker.py	2012-04-16 23:10:10 UTC (rev 9133)
@@ -57,6 +57,7 @@
                         "ldapAttrToDSAttrMap" : { # maps ldap attributes to ds attribute types
                             "cn" : "dsAttrTypeStandard:RealName",
                          },
+                        "additionalVCardProps":None,
                     },
                 ),
 
@@ -114,7 +115,7 @@
  
         assert directoryBackedAddressBook is not None
         self.directoryBackedAddressBook = directoryBackedAddressBook
-        
+       
         self.maxQueryResults = maxQueryResults
         
         ### params for ABDirectoryQueryResult()
@@ -159,7 +160,7 @@
 
  
     @inlineCallbacks
-    def _getLdapQueryResults(self, base, queryStr, attributes=None, maxResults=0, ldapAttrToDSAttrMap={} ):
+    def _getLdapQueryResults(self, base, queryStr, attributes=None, maxResults=0, ldapAttrToDSAttrMap=None, ldapAttrTransforms=None, additionalVCardProps=None ):
         """
         Get a list of ABDirectoryQueryResult for the given query with the given attributes.
         query == None gets all records. attribute == None gets ABDirectoryQueryResult.allDSQueryAttributes
@@ -193,9 +194,41 @@
                     ldapAttributeValues = [attr for attr in ldapAttributeValues if len(attr)]
                     
                     if len(ldapAttributeValues):
+                                                
+                        
                         dsAttributeNames = ldapAttrToDSAttrMap.get(ldapAttributeName)
                         if dsAttributeNames:
                             
+                            if ldapAttrTransforms:
+                            
+                                # do value transforms
+                                # need to expand this to cover all cases
+                                # All this does now is to pull part of an ldap string out
+                                # e.g: uid=renuka,ou=People,o=apple.com,o=email -> renuka
+                                transforms = ldapAttrTransforms.get(ldapAttributeName)
+                                if transforms:
+                                    if not isinstance(transforms, list):
+                                        transforms = [transforms,]
+                                    
+                                    transformedValues = []
+                                    for ldapAttributeValue in ldapAttributeValues:
+                                        transformedValue = ldapAttributeValue
+                                        for valuePart in ldapAttributeValue.lower().split(","):
+                                            kvPair = valuePart.split("=")
+                                            if len(kvPair) == 2:
+                                                for transform in transforms:
+                                                    if transform.lower() == kvPair[0]:
+                                                        transformedValue = kvPair[1]
+                                                        break
+                                                    
+                                        transformedValues += [transformedValue,]
+                                    
+                                    if (ldapAttributeValues != transformedValues):
+                                        self.log_debug("_getLdapQueryResults: %s %s transformed to %s" % (ldapAttributeName, ldapAttributeValues, transformedValues))
+                                        ldapAttributeValues = transformedValues
+                                                
+                                        
+                            
                             if not isinstance(dsAttributeNames, list):
                                 dsAttributeNames = [dsAttributeNames,]
                                 
@@ -213,7 +246,7 @@
                                 self.log_debug("doAddressBookQuery: dsRecordAttributes[%s] = %s" % (dsAttributeName, dsRecordAttributes[dsAttributeName],))
 
                 # get a record for dsRecordAttributes 
-                result = ABDirectoryQueryResult(self.directoryBackedAddressBook, dsRecordAttributes, appleInternalServer=self.appleInternalServer)
+                result = ABDirectoryQueryResult(self.directoryBackedAddressBook, dsRecordAttributes, additionalVCardProps=additionalVCardProps, appleInternalServer=self.appleInternalServer)
             except:
                 traceback.print_exc()
                 self.log_info("Could not get vcard for %s" % (dn,))
@@ -245,6 +278,8 @@
             rdn = queryMap["rdn"]
             vcardPropToLdapAttrMap = queryMap["vcardPropToLdapAttrMap"]
             ldapAttrToDSAttrMap = queryMap["ldapAttrToDSAttrMap"]
+            additionalVCardProps = queryMap.get("additionalVCardProps")
+            ldapAttrTransforms = queryMap.get("ldapAttrTransforms")
 
             allRecords, filterAttributes, dsFilter  = dsFilterFromAddressBookFilter( addressBookFilter, vcardPropToLdapAttrMap );
             self.log_debug("doAddressBookQuery: rdn=%s LDAP allRecords=%s, filterAttributes=%s, query=%s" % (rdn, allRecords, filterAttributes, "None" if dsFilter is None else dsFilter.generate(),))
@@ -283,7 +318,13 @@
                 maxLdapResults = int(remainingMaxResults * 1.2)
     
                 while True:
-                    ldapQueryResultsDictionary, ldapQueryLimited = (yield self._getLdapQueryResults(base=base, queryStr=queryStr, attributes=attributes, maxResults=maxLdapResults, ldapAttrToDSAttrMap=ldapAttrToDSAttrMap))
+                    ldapQueryResultsDictionary, ldapQueryLimited = (yield self._getLdapQueryResults(base=base, 
+                                                                                                    queryStr=queryStr, 
+                                                                                                    attributes=attributes, 
+                                                                                                    maxResults=maxLdapResults, 
+                                                                                                    ldapAttrToDSAttrMap=ldapAttrToDSAttrMap, 
+                                                                                                    ldapAttrTransforms=ldapAttrTransforms, 
+                                                                                                    additionalVCardProps=additionalVCardProps))
                     
                     for uid, ldapQueryResult in ldapQueryResultsDictionary.iteritems():
 

Modified: CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/opendirectorybacker.py
===================================================================
--- CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/opendirectorybacker.py	2012-04-16 22:38:03 UTC (rev 9132)
+++ CalendarServer/branches/users/gaya/ldapdirectorybacker/twistedcaldav/directory/opendirectorybacker.py	2012-04-16 23:10:10 UTC (rev 9133)
@@ -1044,9 +1044,17 @@
         }
 
     
-    def __init__(self, directoryBackedAddressBook, recordAttributes, addDSAttrXProperties=False, appleInternalServer=False, ):
+    def __init__(self, directoryBackedAddressBook, recordAttributes, additionalVCardProps=None, addDSAttrXProperties=False, appleInternalServer=False, ):
 
-        self.log_debug("directoryBackedAddressBook=%s, attributes=%s"    % (directoryBackedAddressBook, recordAttributes))
+        self.log_debug("directoryBackedAddressBook=%s, attributes=%s, additionalVCardProps=%s" % (directoryBackedAddressBook, recordAttributes, additionalVCardProps,))
+        
+        constantProperties = ABDirectoryQueryResult.constantProperties.copy()
+        if additionalVCardProps:
+            for key, value in additionalVCardProps.iteritems():
+                if key not in constantProperties:
+                    constantProperties[key] = value
+        self.constantProperties = constantProperties
+        self.log_debug("directoryBackedAddressBook=%s, attributes=%s, self.constantProperties=%s" % (directoryBackedAddressBook, recordAttributes, self.constantProperties,))
 
         #save off for debugging
         self.addDSAttrXProperties = addDSAttrXProperties;
@@ -1232,7 +1240,7 @@
             groupCount = [0]
             
             # add constant properties - properties that are the same regardless of the record attributes
-            for key, value in ABDirectoryQueryResult.constantProperties.items():
+            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
@@ -1480,12 +1488,10 @@
             # 3.6.2 NOTE Type Definition
             # dsattributes.kDS1AttrComment,               # Attribute used for unformatted comment.
             # dsattributes.kDS1AttrNote,                  # Note attribute. Commonly used in printer records.
-            for comment in self.valuesForAttribute(dsattributes.kDS1AttrComment):
-                addUniqueProperty(vcard, Property("NOTE", comment), None, dsattributes.kDS1AttrComment, comment)
+            notes = self.valuesForAttribute(dsattributes.kDS1AttrComment, []) + self.valuesForAttribute(dsattributes.kDS1AttrNote, []);
+            if len(notes):
+                vcard.addProperty(Property("NOTE", "\n".join(notes),))
     
-            for note in self.valuesForAttribute(dsattributes.kDS1AttrNote):
-                addUniqueProperty(vcard, Property("NOTE", note), None, dsattributes.kDS1AttrNote, note)
-            
             # 3.6.3 PRODID Type Definition
             #vcard.addProperty(Property("PRODID", vCardProductID + "//BUILD %s" % twistedcaldav.__version__))
             #vcard.addProperty(Property("PRODID", vCardProductID))
@@ -1615,9 +1621,10 @@
             # add apple-defined group vcard properties if record type is group
             if self.firstValueForAttribute(dsattributes.kDSNAttrRecordType) == dsattributes.kDSStdRecordTypeGroups:
                 vcard.addProperty(Property("X-ADDRESSBOOKSERVER-KIND", "group"))
-                
-                for memberguid in self.valuesForAttribute(dsattributes.kDSNAttrGroupMembers):
-                    vcard.addProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", "urn:uuid:" + memberguid))
+            
+            # add members
+            for memberguid in self.valuesForAttribute(dsattributes.kDSNAttrGroupMembers):
+                vcard.addProperty(Property("X-ADDRESSBOOKSERVER-MEMBER", "urn:uuid:" + memberguid))
     
             """
             # UNIMPLEMENTED: X- attributes
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20120416/7886c70f/attachment-0001.html>


More information about the calendarserver-changes mailing list