[CalendarServer-changes] [3053] CalendarServer/branches/users/sagen/principal-property-search-3051

source_changes at macosforge.org source_changes at macosforge.org
Wed Sep 24 16:14:18 PDT 2008


Revision: 3053
          http://trac.macosforge.org/projects/calendarserver/changeset/3053
Author:   sagen at apple.com
Date:     2008-09-24 16:14:18 -0700 (Wed, 24 Sep 2008)
Log Message:
-----------
Merged trunk changes into branch

Modified Paths:
--------------
    CalendarServer/branches/users/sagen/principal-property-search-3051/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch
    CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/customxml.py
    CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/aggregate.py
    CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/apache.py
    CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/appleopendirectory.py
    CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/directory.py
    CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/principal.py
    CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/sqldb.py
    CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/sudo.py
    CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/xmlaccountsparser.py
    CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/xmlfile.py
    CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/resource.py

Modified: CalendarServer/branches/users/sagen/principal-property-search-3051/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-3051/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch	2008-09-24 23:13:24 UTC (rev 3052)
+++ CalendarServer/branches/users/sagen/principal-property-search-3051/lib-patches/Twisted/twisted.web2.dav.method.report_principal_property_search.patch	2008-09-24 23:14:18 UTC (rev 3053)
@@ -22,7 +22,51 @@
      # Get a single DAV:prop element from the REPORT request body
      propertiesForResource = None
      propElement = None
-@@ -93,73 +99,155 @@
+@@ -71,10 +77,22 @@
+         elif child.qname() == (dav_namespace, "property-search"):
+             props = child.childOfType(davxml.PropertyContainer)
+             props.removeWhitespaceNodes()
++
+             match = child.childOfType(davxml.Match)
+-            propertySearches.append((props.children, str(match).lower()))
++            caseless = match.attributes.get("caseless", "yes")
++            if caseless not in ("yes", "no"):
++                raise ValueError("Unknown value for caseless attribute: %s" %
++                    (caseless,))
++            caseless = True if caseless == "yes" else False
++            matchType = match.attributes.get("match-type", "contains")
++            if matchType not in ("starts-with", "contains"):
++                raise ValueError("Unknown value for match-type attribute: %s" %
++                    (matchType,))
++
++            propertySearches.append((props.children, str(match),
++                caseless, matchType))
+     
+-    def nodeMatch(node, match):
++    def nodeMatch(node, match, caseless, matchType):
+         """
+         See if the content of the supplied node matches the supplied text.
+         Try to follow the matching guidance in rfc3744 section 9.4.1.
+@@ -85,81 +103,174 @@
+         node.removeWhitespaceNodes()
+         for child in node.children:
+             if isinstance(child, davxml.PCDATAElement):
+-                comp = str(child).lower()
+-                if comp.find(match) != -1:
++                if caseless:
++                    comp = str(child).lower()
++                    match = match.lower()
++                else:
++                    comp = str(child)
++
++                if matchType == "starts-with":
++                    if comp.find(match) == 0:
++                        return True
++                elif comp.find(match) != -1:
+                     return True
++
+             else:
+                 return nodeMatch(child, match)
          else:
              return False
          
@@ -46,7 +90,7 @@
 -                    if propvalue and not nodeMatch(propvalue, match):
 +
 +        if operand == "and":
-+            for props, match in propertySearches:
++            for props, match, caseless, matchType in propertySearches:
 +                # Test each property
 +                for prop in props:
 +                    try:
@@ -54,7 +98,8 @@
 +                        yield propvalue
 +                        propvalue = propvalue.getResult()
 +                        if propvalue:
-+                            if not nodeMatch(propvalue, match):
++                            if not nodeMatch(propvalue, match, caseless,
++                                matchType):
 +                                yield False
 +                                return
 +                    except HTTPError:
@@ -71,7 +116,7 @@
 +            yield True
  
 +        else: # "or"
-+            for props, match in propertySearches:
++            for props, match, caseless, matchType in propertySearches:
 +                # Test each property
 +                for prop in props:
 +                    try:
@@ -79,7 +124,7 @@
 +                        yield propvalue
 +                        propvalue = propvalue.getResult()
 +                        if propvalue:
-+                            if nodeMatch(propvalue, match):
++                            if nodeMatch(propvalue, match, caseless, matchType):
 +                                yield True
 +                                return
 +                    except HTTPError:
@@ -99,7 +144,7 @@
 +        # See if we can take advantage of the directory
 +        fields = []
 +        nonDirectorySearches = []
-+        for props, match in propertySearches:
++        for props, match, caseless, matchType in propertySearches:
 +            nonDirectoryProps = []
 +            for prop in props:
 +                try:
@@ -107,11 +152,12 @@
 +                except AttributeError:
 +                    fieldName = None
 +                if fieldName:
-+                    fields.append((fieldName, match))
++                    fields.append((fieldName, match, caseless, matchType))
 +                else:
 +                    nonDirectoryProps.append(prop)
 +            if nonDirectoryProps:
-+                nonDirectorySearches.append((nonDirectoryProps, match))
++                nonDirectorySearches.append((nonDirectoryProps, match,
++                    caseless, matchType))
 +
 +        matchingResources = []
          matchcount = 0
@@ -224,7 +270,7 @@
                      yield d
                      d = d.getResult()
                      if d:
-@@ -167,18 +255,26 @@
+@@ -167,18 +278,26 @@
                          matchcount += 1
                          if matchcount > max_number_of_matches:
                              raise NumberOfMatchesWithinLimits

Modified: CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/customxml.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/customxml.py	2008-09-24 23:13:24 UTC (rev 3052)
+++ CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/customxml.py	2008-09-24 23:14:18 UTC (rev 3053)
@@ -315,7 +315,7 @@
     name = "last-name"
     protected = True
 
-class EMailProperty (davxml.WebDAVTextElement):
+class EmailAddressProperty (davxml.WebDAVTextElement):
     """
     A property representing email address of a principal
     """
@@ -323,6 +323,16 @@
     name = "email-address"
     protected = True
 
+class EmailAddressSet (davxml.WebDAVElement):
+    """
+    The list of email addresses of a principal
+    """
+    namespace = calendarserver_namespace
+    name = "email-address-set"
+    hidden = True
+
+    allowed_children = { (calendarserver_namespace, "email-address"): (0, None) }
+
 class IScheduleInbox (davxml.WebDAVEmptyElement):
     """
     Denotes the resourcetype of a iSchedule Inbox.

Modified: CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/aggregate.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/aggregate.py	2008-09-24 23:13:24 UTC (rev 3052)
+++ CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/aggregate.py	2008-09-24 23:14:18 UTC (rev 3053)
@@ -103,8 +103,7 @@
     def recordWithCalendarUserAddress(self, address):
         return self._queryAll("recordWithCalendarUserAddress", address)
 
-    def recordsMatchingFields(self, fields, caseInsensitive=True, operand="or",
-        recordType=None):
+    def recordsMatchingFields(self, fields, operand="or", recordType=None):
         if recordType:
             services = (self.serviceForRecordType(recordType),)
         else:
@@ -112,8 +111,7 @@
 
         for service in services:
             for record in service.recordsMatchingFields(fields,
-                caseInsensitive=caseInsensitive, operand=operand,
-                recordType=recordType):
+                operand=operand, recordType=recordType):
                     yield record
 
     def serviceForRecordType(self, recordType):

Modified: CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/apache.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/apache.py	2008-09-24 23:13:24 UTC (rev 3052)
+++ CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/apache.py	2008-09-24 23:14:18 UTC (rev 3053)
@@ -131,7 +131,7 @@
             fullName              = None,
             firstName             = None,
             lastName              = None,
-            emailAddress          = None,
+            emailAddresses        = set(),
             calendarUserAddresses = set(),
             autoSchedule          = False,
         )

Modified: CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/appleopendirectory.py	2008-09-24 23:13:24 UTC (rev 3052)
+++ CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/appleopendirectory.py	2008-09-24 23:14:18 UTC (rev 3053)
@@ -465,7 +465,7 @@
         'fullName' : dsattributes.kDS1AttrDistinguishedName,
         'firstName' : dsattributes.kDS1AttrFirstName,
         'lastName' : dsattributes.kDS1AttrLastName,
-        'emailAddress' : dsattributes.kDSNAttrEMailAddress,
+        'emailAddresses' : dsattributes.kDSNAttrEMailAddress,
     }
 
     _toODRecordTypes = {
@@ -481,17 +481,23 @@
 
     _fromODRecordTypes = dict([(b, a) for a, b in _toODRecordTypes.iteritems()])
 
-    def recordsMatchingFields(self, fields, caseInsensitive=True, operand="or",
-        recordType=None):
+    def recordsMatchingFields(self, fields, operand="or", recordType=None):
 
-        comparison = dsattributes.eDSStartsWith
+        # Note that OD applies case-sensitivity globally across the entire
+        # query, not per expression, so the current code uses whatever is
+        # specified in the last field in the fields list
+
         operand = (dsquery.expression.OR if operand == "or"
             else dsquery.expression.AND)
 
         expressions = []
-        for field, value in fields:
+        for field, value, caseless, matchType in fields:
             if field in self._ODFields:
                 ODField = self._ODFields[field]
+                if matchType == "starts-with":
+                    comparison = dsattributes.eDSStartsWith
+                else:
+                    comparison = dsattributes.eDSContains
                 expressions.append(dsquery.match(ODField, value, comparison))
 
 
@@ -503,12 +509,11 @@
         for recordType in recordTypes:
 
             try:
-                self.log_info("Calling OD: %s %s %s" % (recordType, operand,
-                    fields))
+                self.log_info("Calling OD: Type %s, Operand %s, Caseless %s, %s" % (recordType, operand, caseless, fields))
                 results = opendirectory.queryRecordsWithAttributes(
                     self.directory,
                     dsquery.expression(operand, expressions).generate(),
-                    caseInsensitive,
+                    caseless,
                     recordType,
                     [
                         dsattributes.kDS1AttrGeneratedUID,
@@ -522,7 +527,19 @@
                 self.log_info("Got back %d records from OD" % (len(results),))
                 for key, val in results.iteritems():
                     self.log_debug("OD result: %s %s" % (key, val))
+
                     try:
+
+                        # Email field from OD can either be a string or a list
+                        emailAddresses = set()
+                        addrs = val.get(dsattributes.kDSNAttrEMailAddress, None)
+                        if isinstance(addrs, str):
+                            emailAddresses.add(addrs)
+                        elif isinstance(addrs, list):
+                            for addr in addrs:
+                                emailAddresses.add(addr)
+
+                        # TODO: Review this code...
                         calendarUserAddresses = set()
                         enabledForCalendaring = False
                         if val.has_key(dsattributes.kDSNAttrEMailAddress):
@@ -537,7 +554,7 @@
                             fullName = val.get(dsattributes.kDS1AttrDistinguishedName, ""),
                             firstName = val.get(dsattributes.kDS1AttrFirstName, ""),
                             lastName = val.get(dsattributes.kDS1AttrLastName, ""),
-                            emailAddress = val.get(dsattributes.kDSNAttrEMailAddress, ""),
+                            emailAddresses = emailAddresses,
                             calendarUserAddresses = calendarUserAddresses,
                             autoSchedule = False,
                             enabledForCalendaring = enabledForCalendaring,
@@ -643,6 +660,14 @@
             else:
                 calendarUserAddresses = ()
 
+            # Get email address from directory record
+            emailAddresses = set()
+            if isinstance(recordEmailAddress, str):
+                emailAddresses.add(recordEmailAddress)
+            elif isinstance(recordEmailAddress, list):
+                for addr in emailAddresses:
+                    emailAddresses.add(addr)
+
             # Special case for groups, which have members.
             if recordType == DirectoryService.recordType_groups:
                 memberGUIDs = value.get(dsattributes.kDSNAttrGroupMembers)
@@ -680,7 +705,7 @@
                 fullName              = recordFullName,
                 firstName             = recordFirstName,
                 lastName              = recordLastName,
-                emailAddress          = recordEmailAddress,
+                emailAddresses        = emailAddresses,
                 calendarUserAddresses = calendarUserAddresses,
                 autoSchedule          = autoSchedule,
                 enabledForCalendaring = enabledForCalendaring,
@@ -929,7 +954,7 @@
     """
     def __init__(
         self, service, recordType, guid, nodeName, shortName, fullName,
-        firstName, lastName, emailAddress,
+        firstName, lastName, emailAddresses,
         calendarUserAddresses, autoSchedule, enabledForCalendaring,
         memberGUIDs, proxyGUIDs, readOnlyProxyGUIDs,
     ):
@@ -941,7 +966,7 @@
             fullName              = fullName,
             firstName             = firstName,
             lastName              = lastName,
-            emailAddress          = emailAddress,
+            emailAddresses        = emailAddresses,
             calendarUserAddresses = calendarUserAddresses,
             autoSchedule          = autoSchedule,
             enabledForCalendaring = enabledForCalendaring,

Modified: CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/directory.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/directory.py	2008-09-24 23:13:24 UTC (rev 3052)
+++ CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/directory.py	2008-09-24 23:14:18 UTC (rev 3053)
@@ -138,8 +138,7 @@
             for record in self.listRecords(recordType):
                 yield record
 
-    def recordsMatchingFields(self, fields, caseInsensitive=True, operand="or",
-        recordType=None):
+    def recordsMatchingFields(self, fields, operand="or", recordType=None):
         # Default, bruteforce method; override with one optimized for each
         # service
 
@@ -153,18 +152,27 @@
         else:
             recordTypes = (recordType,)
 
-        def fieldMatches(fieldValue, value):
-            if caseInsensitive:
+        def fieldMatches(fieldValue, value, caseless, matchType):
+            if caseless:
+                fieldValue = fieldValue.lower()
+                value = value.lower()
+
+            if matchType == 'starts-with':
                 return fieldValue.lower().startswith(value.lower())
             else:
-                return fieldValue.startswith(value)
+                try:
+                    discard = fieldValue.lower().index(value.lower())
+                    return True
+                except ValueError:
+                    return False
 
         def recordMatches(record):
             if operand == "and":
-                for fieldName, value in fields:
+                for fieldName, value, caseless, matchType in fields:
                     try:
                         fieldValue = getattr(record, fieldName)
-                        if not fieldMatches(fieldValue, value):
+                        if not fieldMatches(fieldValue, value, caseless,
+                            matchType):
                             return False
                     except AttributeError:
                         # No property => no match
@@ -172,10 +180,11 @@
                 # we hit on every property
                 return True
             else: # "or"
-                for fieldName, value in fields:
+                for fieldName, value, caseless, matchType in fields:
                     try:
                         fieldValue = getattr(record, fieldName)
-                        if fieldMatches(fieldValue, value):
+                        if fieldMatches(fieldValue, value, caseless,
+                            matchType):
                             return True
                     except AttributeError:
                         # No value
@@ -209,7 +218,7 @@
 
     def __init__(
         self, service, recordType, guid, shortName, fullName,
-        firstName, lastName, emailAddress,
+        firstName, lastName, emailAddresses,
         calendarUserAddresses, autoSchedule, enabledForCalendaring=True,
     ):
         assert service.realmName is not None
@@ -231,7 +240,7 @@
         self.fullName              = fullName
         self.firstName             = firstName
         self.lastName              = lastName
-        self.emailAddress          = emailAddress
+        self.emailAddresses        = emailAddresses
         self.enabledForCalendaring = enabledForCalendaring
         self.calendarUserAddresses = calendarUserAddresses
         self.autoSchedule          = autoSchedule

Modified: CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/principal.py	2008-09-24 23:13:24 UTC (rev 3052)
+++ CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/principal.py	2008-09-24 23:14:18 UTC (rev 3053)
@@ -134,7 +134,7 @@
         ("DAV:" , "displayname") : "fullName",
         (_cs_ns, "first-name") : "firstName",
         (_cs_ns, "last-name") : "lastName",
-        (_cs_ns, "email-address") : "emailAddress",
+        (_cs_ns, "email-address-set") : "emailAddresses",
     }
 
     def propertyToField(self, property):
@@ -462,7 +462,7 @@
             """Full name: %s\n"""              % (self.record.fullName,),
             """First name: %s\n"""             % (self.record.firstName,),
             """Last name: %s\n"""              % (self.record.lastName,),
-            """Email address: %s\n"""          % (self.record.emailAddress,),
+            """Email addresses:\n"""           , format_list(self.record.emailAddresses),
             """Principal UID: %s\n"""          % (self.principalUID(),),
             """Principal URL: %s\n"""          % (format_link(self.principalURL()),),
             """\nAlternate URIs:\n"""          , format_list(format_link(u) for u in self.alternateURIs()),
@@ -625,7 +625,7 @@
             """Full name: %s\n"""              % (self.record.fullName,),
             """First name: %s\n"""             % (self.record.firstName,),
             """Last name: %s\n"""              % (self.record.lastName,),
-            """Email address: %s\n"""          % (self.record.emailAddress,),
+            """Email addresses:\n"""           , format_list(self.record.emailAddresses),
             """Principal UID: %s\n"""          % (self.principalUID(),),
             """Principal URL: %s\n"""          % (format_link(self.principalURL()),),
             """\nAlternate URIs:\n"""          , format_list(format_link(u) for u in self.alternateURIs()),

Modified: CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/sqldb.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/sqldb.py	2008-09-24 23:13:24 UTC (rev 3052)
+++ CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/sqldb.py	2008-09-24 23:14:18 UTC (rev 3053)
@@ -352,7 +352,7 @@
             fullName              = name,
             firstName             = None,
             lastName              = None,
-            emailAddress          = None,
+            emailAddresses        = set(),
             calendarUserAddresses = calendarUserAddresses,
             autoSchedule          = autoSchedule,
         )

Modified: CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/sudo.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/sudo.py	2008-09-24 23:13:24 UTC (rev 3052)
+++ CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/sudo.py	2008-09-24 23:14:18 UTC (rev 3053)
@@ -134,7 +134,7 @@
             fullName=shortName,
             firstName="",
             lastName="",
-            emailAddress="",
+            emailAddresses=set(),
             calendarUserAddresses=set(),
             autoSchedule=False,
             enabledForCalendaring=False)

Modified: CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/xmlaccountsparser.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/xmlaccountsparser.py	2008-09-24 23:13:24 UTC (rev 3052)
+++ CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/xmlaccountsparser.py	2008-09-24 23:14:18 UTC (rev 3053)
@@ -168,7 +168,7 @@
         self.name = None
         self.firstName = None
         self.lastName = None
-        self.emailAddress = None
+        self.emailAddresses = set()
         self.members = set()
         self.groups = set()
         self.calendarUserAddresses = set()
@@ -209,10 +209,12 @@
             lastName = self.lastName % ctr
         else:
             lastName = self.lastName
-        if self.emailAddress and self.emailAddress.find("%") != -1:
-            emailAddress = self.emailAddress % ctr
-        else:
-            emailAddress = self.emailAddress
+        emailAddresses = set()
+        for emailAddr in self.emailAddresses:
+            if emailAddr.find("%") != -1:
+                emailAddresses.add(emailAddr % ctr)
+            else:
+                emailAddresses.add(emailAddr)
         calendarUserAddresses = set()
         for cuaddr in self.calendarUserAddresses:
             if cuaddr.find("%") != -1:
@@ -227,7 +229,7 @@
         result.name = name
         result.firstName = firstName
         result.lastName = lastName
-        result.emailAddress = emailAddress
+        result.emailAddresses = emailAddresses
         result.members = self.members
         result.calendarUserAddresses = calendarUserAddresses
         result.autoSchedule = self.autoSchedule
@@ -266,7 +268,7 @@
                     self.lastName = child.firstChild.data.encode("utf-8")
             elif child_name == ELEMENT_EMAIL_ADDRESS:
                 if child.firstChild is not None:
-                    self.emailAddress = child.firstChild.data.encode("utf-8")
+                    self.emailAddresses.add(child.firstChild.data.encode("utf-8"))
             elif child_name == ELEMENT_MEMBERS:
                 self._parseMembers(child, self.members)
             elif child_name == ELEMENT_CUADDR:

Modified: CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/xmlfile.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/xmlfile.py	2008-09-24 23:13:24 UTC (rev 3052)
+++ CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/directory/xmlfile.py	2008-09-24 23:14:18 UTC (rev 3053)
@@ -116,7 +116,7 @@
             fullName              = xmlPrincipal.name,
             firstName             = xmlPrincipal.firstName,
             lastName              = xmlPrincipal.lastName,
-            emailAddress          = xmlPrincipal.emailAddress,
+            emailAddresses        = xmlPrincipal.emailAddresses,
             calendarUserAddresses = xmlPrincipal.calendarUserAddresses,
             autoSchedule          = xmlPrincipal.autoSchedule,
             enabledForCalendaring = xmlPrincipal.enabledForCalendaring,

Modified: CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/resource.py	2008-09-24 23:13:24 UTC (rev 3052)
+++ CalendarServer/branches/users/sagen/principal-property-search-3051/twistedcaldav/resource.py	2008-09-24 23:14:18 UTC (rev 3053)
@@ -695,7 +695,7 @@
         (caldav_namespace, "schedule-outbox-URL"      ),
         (calendarserver_namespace, "first-name"       ),
         (calendarserver_namespace, "last-name"        ),
-        (calendarserver_namespace, "email-address"    ),
+        (calendarserver_namespace, "email-address-set"),
     )
 
     @classmethod
@@ -765,14 +765,11 @@
                     else:
                         return None
 
-                if name == "email-address":
-                    emailAddress = self.record.emailAddress
-                    if emailAddress:
-                        return customxml.EMailProperty(emailAddress)
-                    else:
-                        return None
+                if name == "email-address-set":
+                    return succeed(customxml.EmailAddressSet(
+                        *[customxml.EmailAddressProperty(addr) for addr in self.record.emailAddresses]
+                    ))
 
-
             return super(CalendarPrincipalResource, self).readProperty(property, request)
 
         return maybeDeferred(defer)
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20080924/487d0539/attachment-0001.html 


More information about the calendarserver-changes mailing list