[CalendarServer-changes] [4479] CalendarServer/branches/users/cdaboo/partition-4464

source_changes at macosforge.org source_changes at macosforge.org
Mon Aug 3 14:09:12 PDT 2009


Revision: 4479
          http://trac.macosforge.org/projects/calendarserver/changeset/4479
Author:   cdaboo at apple.com
Date:     2009-08-03 14:09:08 -0700 (Mon, 03 Aug 2009)
Log Message:
-----------
Main partitioning support working with XMLFile accounts.

Modified Paths:
--------------
    CalendarServer/branches/users/cdaboo/partition-4464/conf/auth/accounts-test.xml
    CalendarServer/branches/users/cdaboo/partition-4464/conf/auth/accounts.dtd
    CalendarServer/branches/users/cdaboo/partition-4464/conf/auth/accounts.xml
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/apache.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/appleopendirectory.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/cachingdirectory.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/directory.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/idirectory.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/principal.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/accounts.xml
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_principal.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_proxyprincipalmembers.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_xmlfile.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/xmlaccountsparser.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/xmlfile.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/log.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/addressmapping.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/cuaddress.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/ischedule.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/ischeduleservers.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/scheduler.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/utils.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/static.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/stdconfig.py
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/test_config.py

Added Paths:
-----------
    CalendarServer/branches/users/cdaboo/partition-4464/conf/partitions-test.plist
    CalendarServer/branches/users/cdaboo/partition-4464/conf/partitions.plist
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/partitions.py

Removed Paths:
-------------
    CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_opendirectoryschema.py

Modified: CalendarServer/branches/users/cdaboo/partition-4464/conf/auth/accounts-test.xml
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/conf/auth/accounts-test.xml	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/conf/auth/accounts-test.xml	2009-08-03 21:09:08 UTC (rev 4479)
@@ -44,6 +44,7 @@
     <first-name>User</first-name>
     <last-name>%02d</last-name>
     <email-address>user%02d at example.com</email-address>
+    <enable-calendar>true</enable-calendar>
     <cuaddr>mailto:user%02d at example.com</cuaddr>
   </user>
   <user repeat="10">
@@ -53,6 +54,7 @@
     <name>Public %02d</name>
     <first-name>Public</first-name>
     <last-name>%02d</last-name>
+    <enable-calendar>true</enable-calendar>
     <cuaddr>mailto:public%02d at example.com</cuaddr>
   </user>
   <location repeat="10">
@@ -60,6 +62,7 @@
     <guid>location%02d</guid>
     <password>location%02d</password>
     <name>Room %02d</name>
+    <enable-calendar>true</enable-calendar>
     <auto-schedule/>
   </location>
   <resource repeat="10">
@@ -67,6 +70,7 @@
     <guid>resource%02d</guid>
     <password>resource%02d</password>
     <name>Resource %02d</name>
+    <enable-calendar>true</enable-calendar>
     <auto-schedule/>
     <proxies>
       <member type="users">user01</member>
@@ -119,10 +123,10 @@
     <uid>disabledgroup</uid>
     <guid>disabledgroup</guid>
     <password>disabledgroup</password>
+    <enable>false</enable>
     <name>Disabled Group</name>
     <members>
       <member type="users">user01</member>
     </members>
-    <disable-calendar/>
   </group>
 </accounts>

Modified: CalendarServer/branches/users/cdaboo/partition-4464/conf/auth/accounts.dtd
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/conf/auth/accounts.dtd	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/conf/auth/accounts.dtd	2009-08-03 21:09:08 UTC (rev 4479)
@@ -17,16 +17,16 @@
 <!ELEMENT accounts (user*, group*, resource*, location*) >
   <!ATTLIST accounts realm CDATA "">
 
-  <!ELEMENT user (uid+, guid, password, name, first-name?, last-name?, email-address*, cuaddr*, disable-calendar?)>
+  <!ELEMENT user (uid+, guid, password, enable?, hosted-at, name, first-name?, last-name?, email-address*, enable-calendar?, cuaddr*)>
     <!ATTLIST user repeat CDATA "1">
 
-  <!ELEMENT group (uid+, guid, password, name, members, cuaddr*, disable-calendar?)>
+  <!ELEMENT group (uid+, guid, password, enable?, hosted-at, name, members, enable-calendar?, cuaddr*)>
     <!ATTLIST group repeat CDATA "1">
 
-  <!ELEMENT resource (uid+, guid, password, name, cuaddr*, auto-schedule?, proxies?, read-only-proxies?)>
+  <!ELEMENT resource (uid+, guid, password, enable?, hosted-at, name, enable-calendar?, cuaddr*, auto-schedule?, proxies?, read-only-proxies?)>
     <!ATTLIST resource repeat CDATA "1">
 
-  <!ELEMENT location (uid+, guid, password, name, cuaddr*, auto-schedule?, proxies?, read-only-proxies?)>
+  <!ELEMENT location (uid+, guid, password, enable?, hosted-at, name, enable-calendar?, cuaddr*, auto-schedule?, proxies?, read-only-proxies?)>
     <!ATTLIST location repeat CDATA "1">
 
   <!ELEMENT member (#PCDATA)>
@@ -35,11 +35,16 @@
   <!ELEMENT uid               (#PCDATA)>
   <!ELEMENT guid              (#PCDATA)>
   <!ELEMENT password          (#PCDATA)>
+  <!ELEMENT enable            (#PCDATA)>
+  <!ELEMENT hosted-at         (#PCDATA)>
   <!ELEMENT name              (#PCDATA)>
+  <!ELEMENT first-name        (#PCDATA)>
+  <!ELEMENT last-name         (#PCDATA)>
+  <!ELEMENT email-address     (#PCDATA)>
+  <!ELEMENT members           (member*)>
+  <!ELEMENT enable-calendar   (#PCDATA)>
   <!ELEMENT cuaddr            (#PCDATA)>
-  <!ELEMENT members           (member*)>
-  <!ELEMENT auto-schedule     EMPTY>
-  <!ELEMENT disable-calendar  EMPTY>
+  <!ELEMENT auto-schedule     (#PCDATA)>
   <!ELEMENT proxies           (member*)>
   <!ELEMENT read-only-proxies (member*)>
 >

Modified: CalendarServer/branches/users/cdaboo/partition-4464/conf/auth/accounts.xml
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/conf/auth/accounts.xml	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/conf/auth/accounts.xml	2009-08-03 21:09:08 UTC (rev 4479)
@@ -28,6 +28,7 @@
     <uid>test</uid>
     <password>test</password>
     <name>Test User</name>
+    <enable-calendar>true</enable-calendar>
     <cuaddr>mailto:testuser at example.com</cuaddr>
   </user>
   <group>
@@ -42,7 +43,8 @@
     <uid>mercury</uid>
     <password>mercury</password>
     <name>Mecury Conference Room, Building 1, 2nd Floor</name>
-    <auto-schedule/>
+    <enable-calendar>true</enable-calendar>
+    <auto-schedule>true</auto-schedule>
     <proxies>
       <member type="users">test</member>
     </proxies>

Added: CalendarServer/branches/users/cdaboo/partition-4464/conf/partitions-test.plist
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/conf/partitions-test.plist	                        (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/conf/partitions-test.plist	2009-08-03 21:09:08 UTC (rev 4479)
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Copyright (c) 2009 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 Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>partitions</key>
+  <array>
+    <dict>
+      <key>uid</key>
+      <string>00001</string>
+      <key>url</key>
+      <string>http://localhost:8008</string>
+    </dict>
+    <dict>
+      <key>uid</key>
+      <string>00002</string>
+      <key>url</key>
+      <string>http://localhost:8108</string>
+    </dict>
+  </array>
+</dict>
+</plist>

Added: CalendarServer/branches/users/cdaboo/partition-4464/conf/partitions.plist
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/conf/partitions.plist	                        (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/conf/partitions.plist	2009-08-03 21:09:08 UTC (rev 4479)
@@ -0,0 +1,34 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<!--
+    Copyright (c) 2009 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 Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+  <key>partitions</key>
+  <array>
+  <!--
+    <dict>
+      <key>uid</key>
+      <string>00001</string>
+      <key>url</key>
+      <string>http://localhost:8008</string>
+    </dict>
+  -->
+  </array>
+</dict>
+</plist>

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/apache.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/apache.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/apache.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -153,6 +153,7 @@
             service               = service,
             recordType            = recordType,
             guid                  = None,
+            enabled               = True,
             shortNames            = (shortName,),
         )
 

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/appleopendirectory.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/appleopendirectory.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/appleopendirectory.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -24,12 +24,7 @@
 ]
 
 import sys
-from uuid import UUID
 
-from twext.python.plistlib import readPlistFromString
-
-from xml.parsers.expat import ExpatError
-
 import opendirectory
 import dsattributes
 import dsquery
@@ -616,8 +611,8 @@
                 firstName             = recordFirstName,
                 lastName              = recordLastName,
                 emailAddresses        = recordEmailAddresses,
-                calendarUserAddresses = calendarUserAddresses,
                 enabledForCalendaring = enabledForCalendaring,
+                calendarUserAddresses = calendarUserAddresses,
                 memberGUIDs           = memberGUIDs,
             )
             if enabledForCalendaring:
@@ -647,73 +642,6 @@
 
             self.recordCacheForType(recordType).addRecord(record, indexType, origIndexKey)
 
-    def _parseResourceInfo(self, plist, guid, recordType, shortname):
-        """
-        Parse OD ResourceInfo attribute and extract information that the server needs.
-
-        @param plist: the plist that is the attribute value.
-        @type plist: str
-        @param guid: the directory GUID of the record being parsed.
-        @type guid: str
-        @param shortname: the record shortname of the record being parsed.
-        @type shortname: str
-        @return: a C{tuple} of C{bool} for auto-accept, C{str} for proxy GUID, C{str} for read-only proxy GUID.
-        """
-        try:
-            plist = readPlistFromString(plist)
-            wpframework = plist.get("com.apple.WhitePagesFramework", {})
-            autoaccept = wpframework.get("AutoAcceptsInvitation", False)
-            proxy = wpframework.get("CalendaringDelegate", None)
-            read_only_proxy = wpframework.get("ReadOnlyCalendaringDelegate", None)
-        except (ExpatError, AttributeError), e:
-            self.log_error(
-                "Failed to parse ResourceInfo attribute of record (%s)%s (guid=%s): %s\n%s" %
-                (recordType, shortname, guid, e, plist,)
-            )
-            raise ValueError("Invalid ResourceInfo")
-
-        return (autoaccept, proxy, read_only_proxy,)
-
-    def getResourceInfo(self):
-        """
-        Resource information including proxy assignments for resource and
-        locations, as well as auto-schedule settings, used to live in the
-        directory.  This method fetches old resource info for migration
-        purposes.
-        """
-        attrs = [
-            dsattributes.kDS1AttrGeneratedUID,
-            dsattributes.kDSNAttrResourceInfo,
-        ]
-
-        for recordType in (dsattributes.kDSStdRecordTypePlaces, dsattributes.kDSStdRecordTypeResources):
-            try:
-                self.log_debug("opendirectory.listAllRecordsWithAttributes_list(%r,%r,%r)" % (
-                    self.directory,
-                    recordType,
-                    attrs,
-                ))
-                results = opendirectory.listAllRecordsWithAttributes_list(
-                    self.directory,
-                    recordType,
-                    attrs,
-                )
-            except opendirectory.ODError, ex:
-                self.log_error("OpenDirectory (node=%s) error: %s" % (self.realmName, str(ex)))
-                raise
-
-            for (recordShortName, value) in results:
-                recordGUID = value.get(dsattributes.kDS1AttrGeneratedUID)
-                resourceInfo = value.get(dsattributes.kDSNAttrResourceInfo)
-                if resourceInfo is not None:
-                    try:
-                        autoSchedule, proxy, readOnlyProxy = self._parseResourceInfo(resourceInfo,
-                            recordGUID, recordType, recordShortName)
-                    except ValueError:
-                        continue
-                    yield recordGUID, autoSchedule, proxy, readOnlyProxy
-
-
     def isAvailable(self):
         """
         Returns True if all configured directory nodes are accessible, False otherwise
@@ -765,8 +693,8 @@
     def __init__(
         self, service, recordType, guid, nodeName, shortNames, authIDs,
         fullName, firstName, lastName, emailAddresses,
-        calendarUserAddresses,
         enabledForCalendaring,
+        calendarUserAddresses,
         memberGUIDs,
     ):
         super(OpenDirectoryRecord, self).__init__(
@@ -779,8 +707,8 @@
             firstName             = firstName,
             lastName              = lastName,
             emailAddresses        = emailAddresses,
-            calendarUserAddresses = calendarUserAddresses,
             enabledForCalendaring = enabledForCalendaring,
+            calendarUserAddresses = calendarUserAddresses,
         )
         self.nodeName = nodeName
         self._memberGUIDs = tuple(memberGUIDs)

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/cachingdirectory.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/cachingdirectory.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/cachingdirectory.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -333,23 +333,28 @@
 class CachingDirectoryRecord(DirectoryRecord):
 
     def __init__(
-        self, service, recordType, guid, shortNames=(), authIDs=set(),
+        self, service, recordType, guid,
+        enabled=False, hostedAt="",
+        shortNames=(), authIDs=set(),
         fullName=None, firstName=None, lastName=None, emailAddresses=set(),
+        enabledForCalendaring=None,
         calendarUserAddresses=set(),
-        enabledForCalendaring=None, uid=None,
+        uid=None,
     ):
         super(CachingDirectoryRecord, self).__init__(
             service               = service,
             recordType            = recordType,
             guid                  = guid,
+            enabled               = enabled,
+            hostedAt              = hostedAt,
             shortNames            = shortNames,
             authIDs               = authIDs,
             fullName              = fullName,
             firstName             = firstName,
             lastName              = lastName,
             emailAddresses        = emailAddresses,
+            enabledForCalendaring = enabledForCalendaring,
             calendarUserAddresses = calendarUserAddresses,
-            enabledForCalendaring = enabledForCalendaring,
             uid                   = uid,
         )
         

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/directory.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/directory.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/directory.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -14,6 +14,7 @@
 # limitations under the License.
 ##
 
+
 """
 Generic directory service classes.
 """
@@ -37,9 +38,11 @@
 from twisted.web2.dav.auth import IPrincipalCredentials
 from twisted.internet.defer import succeed
 
+from twistedcaldav.config import config
 from twistedcaldav.log import LoggingMixIn
 from twistedcaldav.directory.idirectory import IDirectoryService, IDirectoryRecord
 from twistedcaldav.directory.util import uuidFromName
+from twistedcaldav.partitions import partitions
 from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
 
 class DirectoryService(LoggingMixIn):
@@ -282,21 +285,24 @@
     implements(IDirectoryRecord)
 
     def __repr__(self):
-        return "<%s[%s@%s(%s)] %s(%s) %r>" % (
+        return "<%s[%s@%s(%s)] %s(%s) %r @ %s>" % (
             self.__class__.__name__,
             self.recordType,
             self.service.guid,
             self.service.realmName,
             self.guid,
             ",".join(self.shortNames),
-            self.fullName
+            self.fullName,
+            self.hostedAt,
         )
 
     def __init__(
-        self, service, recordType, guid, shortNames=(), authIDs=set(), fullName=None,
+        self, service, recordType, guid,
+        enabled=False, hostedAt="",
+        shortNames=(), authIDs=set(), fullName=None,
         firstName=None, lastName=None, emailAddresses=set(),
+        enabledForCalendaring=False,
         calendarUserAddresses=set(),
-        enabledForCalendaring=None,
         uid=None,
     ):
         assert service.realmName is not None
@@ -309,12 +315,6 @@
         if uid is None:
             uid = guid
 
-        if enabledForCalendaring is None:
-            if recordType == service.recordType_groups:
-                enabledForCalendaring = False
-            else:
-                enabledForCalendaring = True
-
         if enabledForCalendaring and recordType == service.recordType_groups:
             raise AssertionError("Groups may not be enabled for calendaring")
 
@@ -328,6 +328,8 @@
         self.recordType            = recordType
         self.guid                  = guid
         self.uid                   = uid
+        self.enabled               = enabled
+        self.hostedAt              = hostedAt
         self.shortNames            = shortNames
         self.authIDs               = authIDs
         self.fullName              = fullName
@@ -350,7 +352,7 @@
     def __hash__(self):
         h = hash(self.__class__)
         for attr in ("service", "recordType", "shortNames", "guid",
-                     "enabledForCalendaring"):
+                     "enabled", "enabledForCalendaring"):
             h = (h + hash(getattr(self, attr))) & sys.maxint
 
         return h
@@ -382,6 +384,12 @@
                 return key
         return None
 
+    def locallyHosted(self):
+        return not self.hostedAt or not config.EnablePartitions or self.hostedAt == config.ServerPartitionID
+    
+    def hostedURL(self):
+        return partitions.getPartitionURL(self.hostedAt)
+
 class DirectoryError(RuntimeError):
     """
     Generic directory error.

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/idirectory.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/idirectory.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/idirectory.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -94,14 +94,16 @@
     recordType            = Attribute("The type of this record.")
     guid                  = Attribute("The GUID of this record.")
     uid                   = Attribute("The UID of this record.")
+    enabled               = Attribute("Determines whether this record should be provisioned as a principal.")
+    hostedAt              = Attribute("Identifies the server that actually hosts data for the record.")
     shortNames            = Attribute("The names for this record.")
     authIDs               = Attribute("Alternative security identities for this record.")
     fullName              = Attribute("The full name of this record.")
     firstName             = Attribute("The first name of this record.")
     lastName              = Attribute("The last name of this record.")
     emailAddress          = Attribute("The email address of this record.")
+    enabledForCalendaring = Attribute("Determines whether this record should be provisioned with a calendar home.")
     calendarUserAddresses = Attribute("A set of calendar user addresses for this record.")
-    enabledForCalendaring = Attribute("Determines whether this record should be provisioned with a calendar home.")
 
     def members():
         """

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/principal.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/principal.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/principal.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -61,6 +61,7 @@
 from twistedcaldav import caldavxml, customxml
 from twistedcaldav.customxml import calendarserver_namespace
 from twistedcaldav.directory.wiki import getWikiACL
+from twistedcaldav.partitions import partitions
 from twistedcaldav.scheduling.cuaddress import normalizeCUAddr
 
 log = Logger()
@@ -184,7 +185,7 @@
         raise NotImplementedError("Subclass must implement principalForUID()")
 
     def principalForRecord(self, record):
-        if record is None:
+        if record is None or not record.enabled:
             return None
         return self.principalForUID(record.uid)
 
@@ -326,7 +327,7 @@
         else:
             # Next try looking it up in the directory
             record = self.directory.recordWithCalendarUserAddress(address)
-            if record is not None:
+            if record is not None and record.enabled:
                 return self.principalForRecord(record)
 
         log.debug("No principal for calendar user address: %r" % (address,))
@@ -402,8 +403,9 @@
 
             def _recordShortnameExpand():
                 for record in self.directory.listRecords(self.recordType):
-                    for shortName in record.shortNames:
-                        yield shortName
+                    if record.enabled:
+                        for shortName in record.shortNames:
+                            yield shortName
 
             return _recordShortnameExpand()
         else:
@@ -463,7 +465,7 @@
 
         record = self.directory.recordWithUID(primaryUID)
 
-        if record is None:
+        if record is None or not record.enabled:
             log.err("No principal found for UID: %s" % (name,))
             return None
 
@@ -751,6 +753,11 @@
     def principalUID(self):
         return self.record.uid
 
+    def locallyHosted(self):
+        return self.record.locallyHosted()
+    
+    def hostedURL(self):
+        return self.record.hostedURL()
 
     ##
     # Extra resource info
@@ -888,11 +895,8 @@
         return succeed(inbox)
 
     def calendarHomeURLs(self):
-        home = self.calendarHome()
-        if home is None:
-            return ()
-        else:
-            return (home.url(),)
+        homeURL = self._homeChildURL(None)
+        return (homeURL,) if homeURL else ()
 
     def scheduleInboxURL(self):
         return self._homeChildURL("inbox/")
@@ -911,7 +915,13 @@
         if home is None:
             return None
         else:
-            return joinURL(home.url(), name)
+            url = home.url()
+            if name:
+                url = joinURL(url, name)
+            if not self.locallyHosted():
+                url = joinURL(self.hostedURL(), url)
+                
+            return url
 
     def calendarHome(self):
         # FIXME: self.record.service.calendarHomesCollection smells like a hack

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/accounts.xml
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/accounts.xml	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/accounts.xml	2009-08-03 21:09:08 UTC (rev 4479)
@@ -16,65 +16,77 @@
 limitations under the License.
  -->
 
-<!DOCTYPE accounts SYSTEM "../../../conf/accounts.dtd">
+<!DOCTYPE accounts SYSTEM "../../../conf/auth/accounts.dtd">
 
 <accounts realm="Test">
   <user>
     <uid>admin</uid>
     <guid>D11F03A0-97EA-48AF-9A6C-FAC7F3975766</guid>
     <password>nimda</password>
+    <enable>true</enable>
     <name>Administrators</name>
   </user>
   <user>
     <uid>wsanchez</uid>
     <guid>6423F94A-6B76-4A3A-815B-D52CFD77935D</guid>
     <password>zehcnasw</password>
+    <enable>true</enable>
     <name>Wilfredo Sanchez</name>
     <email-address>wsanchez at example.com</email-address>
+    <enable-calendar>true</enable-calendar>
     <cuaddr>mailto:wsanchez at example.com</cuaddr>
   </user>
   <user>
     <uid>cdaboo</uid>
     <guid>5A985493-EE2C-4665-94CF-4DFEA3A89500</guid>
     <password>oobadc</password>
+    <enable>true</enable>
     <name>Cyrus Daboo</name>
     <email-address>cdaboo at example.com</email-address>
+    <enable-calendar>true</enable-calendar>
     <cuaddr>mailto:cdaboo at example.com</cuaddr>
   </user>
   <user>
     <uid>lecroy</uid>
     <guid>8B4288F6-CC82-491D-8EF9-642EF4F3E7D0</guid>
     <password>yorcel</password>
+    <enable>true</enable>
     <name>Chris Lecroy</name>
     <email-address>lecroy at example.com</email-address>
+    <enable-calendar>true</enable-calendar>
     <cuaddr>mailto:lecroy at example.com</cuaddr>
   </user>
   <user>
     <uid>dreid</uid>
     <guid>5FF60DAD-0BDE-4508-8C77-15F0CA5C8DD1</guid>
     <password>dierd</password>
+    <enable>true</enable>
     <name>David Reid</name>
     <email-address>dreid at example.com</email-address>
+    <enable-calendar>true</enable-calendar>
     <cuaddr>mailto:dreid at example.com</cuaddr>
   </user>
   <user>
     <uid>nocalendar</uid>
     <guid>543D28BA-F74F-4D5F-9243-B3E3A61171E5</guid>
     <password>radnelacon</password>
+    <enable>true</enable>
     <name>No Calendar</name>
     <email-address>nocalendar at example.com</email-address>
-    <disable-calendar/>
   </user>
   <user repeat="2">
     <uid>user%02d</uid>
     <guid>user%02d</guid>
     <password>%02duser</password>
+    <enable>true</enable>
     <name>User %02d</name>
+    <enable-calendar>true</enable-calendar>
   </user>
   <group>
     <uid>managers</uid>
     <guid>9FF60DAD-0BDE-4508-8C77-15F0CA5C8DD1</guid>
     <password>managers</password>
+    <enable>true</enable>
     <name>Managers</name>
     <members>
       <member type="users">lecroy</member>
@@ -84,6 +96,7 @@
     <uid>admin</uid>
     <guid>admin</guid>
     <password>admin</password>
+    <enable>true</enable>
     <name>Administrators</name>
     <members>
       <member type="groups">managers</member>
@@ -93,6 +106,7 @@
     <uid>grunts</uid>
     <guid>grunts</guid>
     <password>grunts</password>
+    <enable>true</enable>
     <name>We do all the work</name>
     <members>
       <member>wsanchez</member>
@@ -104,6 +118,7 @@
     <uid>right_coast</uid>
     <guid>right_coast</guid>
     <password>right_coast</password>
+    <enable>true</enable>
     <name>East Coast</name>
     <members>
       <member>cdaboo</member>
@@ -113,6 +128,7 @@
     <uid>left_coast</uid>
     <guid>left_coast</guid>
     <password>left_coast</password>
+    <enable>true</enable>
     <name>West Coast</name>
     <members>
       <member>wsanchez</member>
@@ -124,6 +140,7 @@
     <uid>both_coasts</uid>
     <guid>both_coasts</guid>
     <password>both_coasts</password>
+    <enable>true</enable>
     <name>Both Coasts</name>
     <members>
       <member type="groups">right_coast</member>
@@ -134,6 +151,7 @@
     <uid>recursive1_coasts</uid>
     <guid>recursive1_coasts</guid>
     <password>recursive1_coasts</password>
+    <enable>true</enable>
     <name>Recursive1 Coasts</name>
     <members>
       <member type="groups">recursive2_coasts</member>
@@ -144,6 +162,7 @@
     <uid>recursive2_coasts</uid>
     <guid>recursive2_coasts</guid>
     <password>recursive2_coasts</password>
+    <enable>true</enable>
     <name>Recursive2 Coasts</name>
     <members>
       <member type="groups">recursive1_coasts</member>
@@ -154,19 +173,21 @@
     <uid>non_calendar_group</uid>
     <guid>non_calendar_group</guid>
     <password>non_calendar_group</password>
+    <enable>true</enable>
     <name>Non-calendar group</name>
     <members>
       <member>cdaboo</member>
       <member>lecroy</member>
     </members>
-    <disable-calendar/>
   </group>
   <location>
     <uid>mercury</uid>
     <guid>mercury</guid>
     <password>mercury</password>
+    <enable>true</enable>
     <name>Mecury Seven</name>
     <email-address>mercury at example.com</email-address>
+    <enable-calendar>true</enable-calendar>
     <cuaddr>mailto:mercury at example.com</cuaddr>
     <proxies>
       <member type="groups">left_coast</member>
@@ -176,10 +197,12 @@
     <uid>gemini</uid>
     <guid>gemini</guid>
     <password>gemini</password>
+    <enable>true</enable>
     <name>Gemini Twelve</name>
     <email-address>gemini at example.com</email-address>
+    <enable-calendar>true</enable-calendar>
     <cuaddr>mailto:gemini at example.com</cuaddr>
-    <auto-schedule/>
+    <auto-schedule>true</auto-schedule>
     <proxies>
       <member>wsanchez</member>
     </proxies>
@@ -188,8 +211,10 @@
     <uid>apollo</uid>
     <guid>apollo</guid>
     <password>apollo</password>
+    <enable>true</enable>
     <name>Apollo Eleven</name>
     <email-address>apollo at example.com</email-address>
+    <enable-calendar>true</enable-calendar>
     <cuaddr>mailto:apollo at example.com</cuaddr>
     <proxies>
       <member type="groups">both_coasts</member>
@@ -199,8 +224,10 @@
     <uid>orion</uid>
     <guid>orion</guid>
     <password>orion</password>
+    <enable>true</enable>
     <name>Orion</name>
     <email-address>orion at example.com</email-address>
+    <enable-calendar>true</enable-calendar>
     <cuaddr>mailto:orion at example.com</cuaddr>
     <proxies>
       <member type="groups">recursive1_coasts</member>
@@ -210,24 +237,30 @@
     <uid>transporter</uid>
     <guid>transporter</guid>
     <password>transporter</password>
+    <enable>true</enable>
     <name>Mass Transporter</name>
     <email-address>transporter at example.com</email-address>
+    <enable-calendar>true</enable-calendar>
     <cuaddr>mailto:transporter at example.com</cuaddr>
   </resource>
   <resource>
     <uid>ftlcpu</uid>
     <guid>ftlcpu</guid>
     <password>ftlcpu</password>
+    <enable>true</enable>
     <name>Faster-Than-Light Microprocessor</name>
     <email-address>ftlcpu at example.com</email-address>
+    <enable-calendar>true</enable-calendar>
     <cuaddr>mailto:ftlcpu at example.com</cuaddr>
   </resource>
   <resource>
     <uid>non_calendar_proxy</uid>
     <guid>non_calendar_proxy</guid>
     <password>non_calendar_proxy</password>
+    <enable>true</enable>
     <name>Non-calendar proxy</name>
     <email-address>non_calendar_proxy at example.com</email-address>
+    <enable-calendar>true</enable-calendar>
     <cuaddr>mailto:non_calendar_proxy at example.com</cuaddr>
     <proxies>
       <member type="groups">non_calendar_group</member>

Deleted: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_opendirectoryschema.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_opendirectoryschema.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_opendirectoryschema.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -1,147 +0,0 @@
-##
-# Copyright (c) 2005-2007 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.
-##
-
-try:
-    from twistedcaldav.directory.appleopendirectory import OpenDirectoryService
-except ImportError:
-    pass
-else:
-    from twistedcaldav.test.util import TestCase
-
-    class ODResourceInfoParse (TestCase):
-
-        plist_good_false = """<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-    <key>com.apple.WhitePagesFramework</key>
-    <dict>
-        <key>AutoAcceptsInvitation</key>
-        <false/>
-        <key>Label</key>
-        <string>Location</string>
-        <key>CalendaringDelegate</key>
-        <string>1234-GUID-5678</string>
-        <key>ReadOnlyCalendaringDelegate</key>
-        <string>1234-GUID-5679</string>
-    </dict>
-</dict>
-</plist>
-"""
-
-        plist_good_true = """<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-    <key>com.apple.WhitePagesFramework</key>
-    <dict>
-        <key>AutoAcceptsInvitation</key>
-        <true/>
-        <key>Label</key>
-        <string>Location</string>
-        <key>CalendaringDelegate</key>
-        <string></string>
-        <key>ReadOnlyCalendaringDelegate</key>
-        <string></string>
-    </dict>
-</dict>
-</plist>
-"""
-
-        plist_good_missing = """<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-    <key>com.apple.WhitePagesFramework</key>
-    <dict>
-        <key>Label</key>
-        <string>Location</string>
-    </dict>
-</dict>
-</plist>
-"""
-
-        plist_bad = """<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-    <key>com.apple.WhitePagesFramework</key>
-    <string>bogus</string>
-</dict>
-</plist>
-"""
-
-        plist_wrong = """<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-    <key>com.apple.YellowPagesFramework</key>
-    <dict>
-        <key>AutoAcceptsInvitation</key>
-        <true/>
-        <key>Label</key>
-        <string>Location</string>
-        <key>CalendaringDelegate</key>
-        <string>1234-GUID-5678</string>
-        <key>ReadOnlyCalendaringDelegate</key>
-        <string>1234-GUID-5679</string>
-    </dict>
-</dict>
-</plist>
-"""
-
-        plist_invalid = """<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-    <key>com.apple.WhitePagesFramework</key>
-    <string>bogus</string>
-    <string>another bogon</string>
-</dict>
-</plist>
-"""
-
-        plist_invalid_xml = """<?xml version="1.0" encoding="UTF-8"?>
-<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
-<plist version="1.0">
-<dict>
-    <key>com.apple.WhitePagesFramework</key>
-    <string>R&D</string>
-</dict>
-</plist>
-"""
-
-        test_bool = (
-            (plist_good_false, False, "1234-GUID-5678", "1234-GUID-5679", None),
-            (plist_good_true, True, "", "", None),
-            (plist_good_missing, False, None, None, None),
-            (plist_wrong, False, None, None, None),
-            (plist_bad, False, None, None, ValueError),
-            (plist_invalid, False, None, None, ValueError),
-            (plist_invalid_xml, False, None, None, ValueError),
-        )
-
-        def test_plists(self):
-            service = OpenDirectoryService({'node' : "/Search"}, dosetup=False)
-            
-            for item in ODResourceInfoParse.test_bool:
-                if item[4] is None:
-                    item1, item2, item3 = service._parseResourceInfo(item[0], "guid", "locations", "name")
-                    self.assertEqual(item1, item[1])
-                    self.assertEqual(item2, item[2])
-                    self.assertEqual(item3, item[3])
-                else:
-                    self.assertRaises(item[4], service._parseResourceInfo, item[0], "guid", "locations", "name")

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_principal.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_principal.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_principal.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -193,7 +193,7 @@
         """
         for provisioningResource, recordType, recordResource, record in self._allRecords():
             principal = provisioningResource.principalForRecord(record)
-            self.failIf(principal is None)
+            self.failIf(principal is None, msg=str(record))
             self.assertEquals(record, principal.record)
 
     def test_principalForCalendarUserAddress(self):

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_proxyprincipalmembers.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_proxyprincipalmembers.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_proxyprincipalmembers.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -423,7 +423,7 @@
                 delRec = self.directoryService.recordWithShortName(
                     DirectoryService.recordType_users, "dreid")
                 for cache in self.directoryService._recordCaches.itervalues():
-                   cache.removeRecord(delRec)
+                    cache.removeRecord(delRec)
                 del self.directoryService._accounts()[
                     DirectoryService.recordType_users]["dreid"]
 
@@ -479,7 +479,7 @@
                     delRec = self.directoryService.recordWithShortName(
                         DirectoryService.recordType_users, "dreid")
                     for cache in self.directoryService._recordCaches.itervalues():
-                       cache.removeRecord(delRec)
+                        cache.removeRecord(delRec)
                     del self.directoryService._accounts()[
                         DirectoryService.recordType_users]["dreid"]
 

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_xmlfile.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_xmlfile.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/test/test_xmlfile.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -110,6 +110,7 @@
     <uid>admin</uid>
     <guid>admin</guid>
     <password>nimda</password>
+    <enable>true</enable>
     <name>Super User</name>
   </user>
 </accounts>
@@ -142,8 +143,10 @@
     <uid>my office</uid>
     <guid>myoffice</guid>
     <password>nimda</password>
+    <enable>true</enable>
     <name>Super User</name>
-    <auto-schedule/>
+    <enable-calendar>true</enable-calendar>
+    <auto-schedule>true</auto-schedule>
   </location>
 </accounts>
 """
@@ -176,13 +179,14 @@
   <group>
     <uid>enabled</uid>
     <password>enabled</password>
+    <enable>true</enable>
     <name>Enabled</name>
   </group>
   <group>
     <uid>disabled</uid>
     <password>disabled</password>
+    <enable>true</enable>
     <name>Disabled</name>
-    <disable-calendar/>
   </group>
 </accounts>
 """
@@ -218,14 +222,18 @@
     <uid>test</uid>
     <guid>test</guid>
     <password>nimda</password>
+    <enable>true</enable>
     <name>Test</name>
+    <enable-calendar>true</enable-calendar>
   </user>
   <location>
     <uid>my office</uid>
     <guid>myoffice</guid>
     <password>nimda</password>
+    <enable>true</enable>
     <name>Super User</name>
-    <auto-schedule/>
+    <enable-calendar>true</enable-calendar>
+    <auto-schedule>true</auto-schedule>
     <proxies>
         <member>test</member>
     </proxies>

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/xmlaccountsparser.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/xmlaccountsparser.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/xmlaccountsparser.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -44,15 +44,17 @@
 ELEMENT_SHORTNAME         = "uid"
 ELEMENT_GUID              = "guid"
 ELEMENT_PASSWORD          = "password"
+ELEMENT_ENABLE            = "enable"
+ELEMENT_HOSTEDAT          = "hosted-at"
 ELEMENT_NAME              = "name"
 ELEMENT_FIRST_NAME        = "first-name"
 ELEMENT_LAST_NAME         = "last-name"
 ELEMENT_EMAIL_ADDRESS     = "email-address"
 ELEMENT_MEMBERS           = "members"
 ELEMENT_MEMBER            = "member"
+ELEMENT_ENABLECALENDAR    = "enable-calendar"
 ELEMENT_CUADDR            = "cuaddr"
 ELEMENT_AUTOSCHEDULE      = "auto-schedule"
-ELEMENT_DISABLECALENDAR   = "disable-calendar"
 ELEMENT_PROXIES           = "proxies"
 ELEMENT_READ_ONLY_PROXIES = "read-only-proxies"
 
@@ -60,6 +62,9 @@
 ATTRIBUTE_REPEAT          = "repeat"
 ATTRIBUTE_RECORDTYPE      = "type"
 
+VALUE_TRUE                = "true"
+VALUE_FALSE               = "false"
+
 RECORD_TYPES = {
     ELEMENT_USER     : DirectoryService.recordType_users,
     ELEMENT_GROUP    : DirectoryService.recordType_groups,
@@ -204,6 +209,8 @@
         self.shortNames = []
         self.guid = None
         self.password = None
+        self.enabled = True
+        self.hostedAt = ""
         self.fullName = None
         self.firstName = None
         self.lastName = None
@@ -212,10 +219,7 @@
         self.groups = set()
         self.calendarUserAddresses = set()
         self.autoSchedule = False
-        if recordType == DirectoryService.recordType_groups:
-            self.enabledForCalendaring = False
-        else:
-            self.enabledForCalendaring = True
+        self.enabledForCalendaring = False
         self.proxies = set()
         self.proxyFor = set()
         self.readOnlyProxies = set()
@@ -270,6 +274,8 @@
         result.shortNames = shortNames
         result.guid = guid
         result.password = password
+        result.enabled = self.enabled
+        result.hostedAt = self.hostedAt
         result.fullName = fullName
         result.firstName = firstName
         result.lastName = lastName
@@ -295,6 +301,12 @@
                     self.guid = child.firstChild.data.encode("utf-8")
                     if len(self.guid) < 4:
                         self.guid += "?" * (4 - len(self.guid))
+            elif child_name == ELEMENT_ENABLE:
+                if child.firstChild is not None:
+                    self.enabled = (child.firstChild.data.encode("utf-8") == VALUE_TRUE)
+            elif child_name == ELEMENT_HOSTEDAT:
+                if child.firstChild is not None:
+                    self.hostedAt = child.firstChild.data.encode("utf-8")
             elif child_name == ELEMENT_PASSWORD:
                 if child.firstChild is not None:
                     self.password = child.firstChild.data.encode("utf-8")
@@ -312,17 +324,15 @@
                     self.emailAddresses.add(child.firstChild.data.encode("utf-8").lower())
             elif child_name == ELEMENT_MEMBERS:
                 self._parseMembers(child, self.members)
+            elif child_name == ELEMENT_ENABLECALENDAR:
+                if child.firstChild is not None:
+                    self.enabledForCalendaring = (child.firstChild.data.encode("utf-8") == VALUE_TRUE)
             elif child_name == ELEMENT_CUADDR:
                 if child.firstChild is not None:
                     self.calendarUserAddresses.add(child.firstChild.data.encode("utf-8"))
             elif child_name == ELEMENT_AUTOSCHEDULE:
-                self.autoSchedule = True
-            elif child_name == ELEMENT_DISABLECALENDAR:
-                # FIXME: Not sure I see why this restriction is needed. --wsanchez
-                ## Only Users or Groups
-                #if self.recordType != DirectoryService.recordType_users:
-                #    raise ValueError("<disable-calendar> element only allowed for Users: %s" % (child_name,))
-                self.enabledForCalendaring = False
+                if child.firstChild is not None:
+                    self.autoSchedule = (child.firstChild.data.encode("utf-8") == VALUE_TRUE)
             elif child_name == ELEMENT_PROXIES:
                 self._parseMembers(child, self.proxies)
             elif child_name == ELEMENT_READ_ONLY_PROXIES:

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/xmlfile.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/xmlfile.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/directory/xmlfile.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -186,13 +186,15 @@
             service               = service,
             recordType            = recordType,
             guid                  = xmlPrincipal.guid,
+            enabled               = xmlPrincipal.enabled,
+            hostedAt              = xmlPrincipal.hostedAt,
             shortNames            = shortNames,
             fullName              = xmlPrincipal.fullName,
             firstName             = xmlPrincipal.firstName,
             lastName              = xmlPrincipal.lastName,
             emailAddresses        = xmlPrincipal.emailAddresses,
+            enabledForCalendaring = xmlPrincipal.enabledForCalendaring,
             calendarUserAddresses = xmlPrincipal.calendarUserAddresses,
-            enabledForCalendaring = xmlPrincipal.enabledForCalendaring,
         )
 
         self.password          = xmlPrincipal.password
@@ -208,9 +210,10 @@
             yield self.service.recordWithShortName(DirectoryService.recordType_groups, shortName)
 
     def verifyCredentials(self, credentials):
-        if isinstance(credentials, UsernamePassword):
-            return credentials.password == self.password
-        if isinstance(credentials, DigestedCredentials):
-            return credentials.checkPassword(self.password)
+        if self.enabled:
+            if isinstance(credentials, UsernamePassword):
+                return credentials.password == self.password
+            if isinstance(credentials, DigestedCredentials):
+                return credentials.checkPassword(self.password)
 
         return super(XMLDirectoryRecord, self).verifyCredentials(credentials)

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/log.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/log.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/log.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -166,7 +166,7 @@
     Clears all log levels to the default.
     """
     logLevelsByNamespace.clear()
-    logLevelsByNamespace[None] = "info"  # Default log level
+    logLevelsByNamespace[None] = "warn"  # Default log level
 
 logLevelsByNamespace = {}
 clearLogLevels()

Added: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/partitions.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/partitions.py	                        (rev 0)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/partitions.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -0,0 +1,56 @@
+##
+# Copyright (c) 2009 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.
+##
+
+from twistedcaldav.log import Logger
+from twext.python.plistlib import readPlist
+
+"""
+Collection of classes for managing partition information for a group of servers.
+"""
+
+log = Logger()
+
+class Partitions(object):
+
+    def __init__(self):
+        
+        self.clear()
+
+    def clear(self):
+        self.partitions = {}
+        self.ownUID = ""
+
+    def readConfig(self, plistpath):
+        try:
+            dataDict = readPlist(plistpath)
+        except (IOError, OSError):                                    
+            log.error("Configuration file does not exist or is inaccessible: %s" % (self._configFileName,))
+            return
+        
+        for partition in dataDict.get("partitions", ()):
+            uid = partition.get("uid", None)
+            url = partition.get("url", None)
+            if uid and url:
+                self.partitions[uid] = url
+
+    def setSelfPartition(self, uid):
+        self.ownUID = uid
+
+    def getPartitionURL(self, uid):
+        # When the UID matches this server return an empty string
+        return self.partitions.get(uid, None) if uid != self.ownUID else ""
+
+partitions = Partitions()

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/addressmapping.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/addressmapping.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/addressmapping.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -22,7 +22,8 @@
 from twistedcaldav.scheduling.imip import ScheduleViaIMip
 from twistedcaldav.scheduling.ischedule import ScheduleViaISchedule
 from twistedcaldav.scheduling.cuaddress import LocalCalendarUser,\
-    RemoteCalendarUser, EmailCalendarUser, InvalidCalendarUser
+    RemoteCalendarUser, EmailCalendarUser, InvalidCalendarUser,\
+    PartitionedCalendarUser
 from twisted.internet.defer import inlineCallbacks, returnValue
 
 __all__ = [
@@ -49,17 +50,14 @@
     @inlineCallbacks
     def getCalendarUser(self, cuaddr, principal):
         
-        # If we have a principal always treat the user as local
+        # If we have a principal always treat the user as local or partitioned
         if principal:
-            returnValue(LocalCalendarUser(cuaddr, principal))
+            returnValue(LocalCalendarUser(cuaddr, principal) if principal.locallyHosted() else PartitionedCalendarUser(cuaddr, principal))
 
         # Get the type
         cuaddr_type = (yield self.getCalendarUserServiceType(cuaddr))
         if cuaddr_type == DeliveryService.serviceType_caldav:
-            if principal:
-                returnValue(LocalCalendarUser(cuaddr, principal))
-            else:
-                returnValue(InvalidCalendarUser(cuaddr))
+            returnValue(InvalidCalendarUser(cuaddr))
         elif cuaddr_type == DeliveryService.serviceType_ischedule:
             returnValue(RemoteCalendarUser(cuaddr))
         elif cuaddr_type == DeliveryService.serviceType_imip:

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/cuaddress.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/cuaddress.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/cuaddress.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -43,6 +43,15 @@
     def __str__(self):
         return "Local calendar user: %s" % (self.cuaddr,)
 
+class PartitionedCalendarUser(CalendarUser):
+    def __init__(self, cuaddr, principal):
+        self.cuaddr = cuaddr
+        self.principal = principal
+        self.serviceType = DeliveryService.serviceType_ischedule
+
+    def __str__(self):
+        return "Partitioned calendar user: %s" % (self.cuaddr,)
+
 class RemoteCalendarUser(CalendarUser):
     def __init__(self, cuaddr):
         self.cuaddr = cuaddr

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/ischedule.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/ischedule.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/ischedule.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -24,7 +24,7 @@
 from twisted.web2 import responsecode
 from twisted.web2.client.http import ClientRequest
 from twisted.web2.client.http import HTTPClientProtocol
-from twisted.web2.dav.util import davXMLFromStream
+from twisted.web2.dav.util import davXMLFromStream, joinURL
 from twisted.web2.http import HTTPError
 from twisted.web2.http_headers import Headers
 from twisted.web2.http_headers import MimeType
@@ -36,9 +36,12 @@
 from twistedcaldav.config import config
 from twistedcaldav.log import Logger
 from twistedcaldav.scheduling.delivery import DeliveryService
-from twistedcaldav.scheduling.ischeduleservers import IScheduleServers
+from twistedcaldav.scheduling.ischeduleservers import IScheduleServers,\
+    IScheduleServerRecord
 from twistedcaldav.scheduling.itip import iTIPRequestStatus
 from twistedcaldav.util import utf8String
+from twistedcaldav.scheduling.cuaddress import RemoteCalendarUser,\
+    PartitionedCalendarUser
 
 import OpenSSL
 
@@ -76,8 +79,13 @@
         groups = {}
         servermgr = IScheduleServers()
         for recipient in self.recipients:
-            # Map the recipient's domain to a server
-            server = servermgr.mapDomain(recipient.domain)
+            if isinstance(recipient, RemoteCalendarUser):
+                # Map the recipient's domain to a server
+                server = servermgr.mapDomain(recipient.domain)
+            elif isinstance(recipient, PartitionedCalendarUser):
+                server = self._getServerForPartitionedUser(recipient)
+            else:
+                assert False, "Incorrect calendar user address class"
             if not server:
                 # Cannot do server-to-server for this recipient.
                 err = HTTPError(ErrorResponse(responsecode.NOT_FOUND, (caldav_namespace, "recipient-allowed")))
@@ -109,6 +117,18 @@
 
         return DeferredList(deferreds)
 
+    def _getServerForPartitionedUser(self, recipient):
+        
+        if not hasattr(self, "partitionedServers"):
+            self.partitionedServers = {}
+            
+        partition = recipient.principal.hostedURL()
+        if partition not in self.partitionedServers:
+            self.partitionedServers[partition] = IScheduleServerRecord(uri=joinURL(partition, "/ischedule"))
+            self.partitionedServers[partition].unNormalizeAddresses = False
+        
+        return self.partitionedServers[partition]
+
 class IScheduleRequest(object):
     
     def __init__(self, scheduler, server, recipients, responses):
@@ -166,7 +186,7 @@
             )
 
     def _prepareData(self):
-        if self.scheduler.method == "PUT": 
+        if self.server.unNormalizeAddresses and self.scheduler.method == "PUT": 
             def lookupFunction(cuaddr):
                 principal = self.scheduler.resource.principalForCalendarUserAddress(cuaddr)
                 if principal is None:

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/ischeduleservers.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/ischeduleservers.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/ischeduleservers.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -123,7 +123,7 @@
     """
     Contains server-to-server details.
     """
-    def __init__(self):
+    def __init__(self, uri=None):
         """
         @param recordType: record type for directory entry.
         """
@@ -133,6 +133,11 @@
         self.allow_to = True
         self.domains = []
         self.client_hosts = []
+        self.unNormalizeAddresses = True
+        
+        if uri:
+            self.uri = uri
+            self._parseDetails()
 
     def parseXML(self, node):
         for child in node._get_childNodes():

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/scheduler.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/scheduler.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/scheduler.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -36,7 +36,8 @@
 from twistedcaldav.scheduling import addressmapping
 from twistedcaldav.scheduling.caldav import ScheduleViaCalDAV
 from twistedcaldav.scheduling.cuaddress import InvalidCalendarUser,\
-    LocalCalendarUser, RemoteCalendarUser, EmailCalendarUser
+    LocalCalendarUser, RemoteCalendarUser, EmailCalendarUser,\
+    PartitionedCalendarUser
 from twistedcaldav.scheduling.imip import ScheduleViaIMip
 from twistedcaldav.scheduling.ischedule import ScheduleViaISchedule
 from twistedcaldav.scheduling.ischeduleservers import IScheduleServers
@@ -45,6 +46,7 @@
 import itertools
 import re
 import socket
+import urlparse
 
 """
 CalDAV/Server-to-Server scheduling behavior.
@@ -244,7 +246,7 @@
     def checkOriginator(self):
         raise NotImplementedError
 
-    def checkRecipient(self):
+    def checkRecipients(self):
         raise NotImplementedError
 
     def checkOrganizer(self):
@@ -363,6 +365,9 @@
             elif isinstance(recipient, LocalCalendarUser):
                 caldav_recipients.append(recipient)
 
+            elif isinstance(recipient, PartitionedCalendarUser):
+                remote_recipients.append(recipient)
+
             elif isinstance(recipient, RemoteCalendarUser):
                 remote_recipients.append(recipient)
 
@@ -490,10 +495,10 @@
                 inbox = None
                 inboxURL = principal.scheduleInboxURL()
                 if inboxURL:
-                    inbox = (yield self.request.locateResource(inboxURL))
+                    inbox = (yield self.request.locateResource(inboxURL)) if principal.locallyHosted() else "dummy"
 
                 if inbox:
-                    results.append(LocalCalendarUser(recipient, principal, inbox, inboxURL))
+                    results.append(LocalCalendarUser(recipient, principal, inbox, inboxURL) if principal.locallyHosted() else PartitionedCalendarUser(recipient, principal))
                 else:
                     log.err("No schedule inbox for principal: %s" % (principal,))
                     results.append(InvalidCalendarUser(recipient))
@@ -609,8 +614,53 @@
             else:
                 raise HTTPError(StatusResponse(responsecode.BAD_REQUEST, "Invalid iTIP message for implicit scheduling"))
 
-class IScheduleScheduler(Scheduler):
+class RemoteScheduler(Scheduler):
 
+    def checkOrganizer(self):
+        """
+        Delay ORGANIZER check until we know what their role is.
+        """
+        pass
+
+    @inlineCallbacks
+    def checkRecipients(self):
+        """
+        Check the validity of the Recipient header values. These must all be local as there
+        is no concept of server-to-server relaying.
+        """
+        
+        results = []
+        for recipient in self.recipients:
+            # Get the principal resource for this recipient
+            principal = self.resource.principalForCalendarUserAddress(recipient)
+            
+            # If no principal we may have a remote recipient but we should check whether
+            # the address is one that ought to be on our server and treat that as a missing
+            # user. Also if server-to-server is not enabled then remote addresses are not allowed.
+            if principal is None:
+                localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(recipient))
+                if localUser:
+                    log.err("No principal for calendar user address: %s" % (recipient,))
+                else:
+                    log.err("Unknown calendar user address: %s" % (recipient,))
+                results.append(InvalidCalendarUser(recipient))
+            else:
+                # Map recipient to their inbox
+                inbox = None
+                inboxURL = principal.scheduleInboxURL()
+                if inboxURL:
+                    inbox = (yield self.request.locateResource(inboxURL)) if principal.locallyHosted() else "dummy"
+
+                if inbox:
+                    results.append(LocalCalendarUser(recipient, principal, inbox, inboxURL) if principal.locallyHosted() else PartitionedCalendarUser(recipient, principal))
+                else:
+                    log.err("No schedule inbox for principal: %s" % (principal,))
+                    results.append(InvalidCalendarUser(recipient))
+        
+        self.recipients = results
+
+class IScheduleScheduler(RemoteScheduler):
+
     def checkAuthorization(self):
         # Must have an unauthenticated user
         if self.resource.currentPrincipal(self.request) != davxml.Principal(davxml.Unauthenticated()):
@@ -627,11 +677,21 @@
         originatorPrincipal = self.resource.principalForCalendarUserAddress(self.originator)
         localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(self.originator))
         if originatorPrincipal or localUser:
-            log.err("Cannot use originator that is on this server: %s" % (self.originator,))
-            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
+            if originatorPrincipal.locallyHosted():
+                log.err("Cannot use originator that is on this server: %s" % (self.originator,))
+                raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
+            else:
+                self.originator = PartitionedCalendarUser(self.originator, originatorPrincipal)
+                #self._validPartitionServer()
         else:
             self.originator = RemoteCalendarUser(self.originator)
-            
+            self._validiScheduleServer()
+
+    def _validiScheduleServer(self):
+        """
+        Check the validity of the iSchedule host.
+        """
+    
         # We will only accept originator in known domains.
         servermgr = IScheduleServers()
         server = servermgr.mapDomain(self.originator.domain)
@@ -675,49 +735,38 @@
                 log.err("Originator not on allowed server: %s" % (self.originator,))
                 raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
 
-    @inlineCallbacks
-    def checkRecipients(self):
+    def _validPartitionServer(self, principal):
         """
-        Check the validity of the Recipient header values. These must all be local as there
-        is no concept of server-to-server relaying.
+        Check the validity of the partitioned host.
         """
-        
-        results = []
-        for recipient in self.recipients:
-            # Get the principal resource for this recipient
-            principal = self.resource.principalForCalendarUserAddress(recipient)
-            
-            # If no principal we may have a remote recipient but we should check whether
-            # the address is one that ought to be on our server and treat that as a missing
-            # user. Also if server-to-server is not enabled then remote addresses are not allowed.
-            if principal is None:
-                localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(recipient))
-                if localUser:
-                    log.err("No principal for calendar user address: %s" % (recipient,))
-                else:
-                    log.err("Unknown calendar user address: %s" % (recipient,))
-                results.append(InvalidCalendarUser(recipient))
-            else:
-                # Map recipient to their inbox
-                inbox = None
-                inboxURL = principal.scheduleInboxURL()
-                if inboxURL:
-                    inbox = (yield self.request.locateResource(inboxURL))
 
-                if inbox:
-                    results.append(LocalCalendarUser(recipient, principal, inbox, inboxURL))
-                else:
-                    log.err("No schedule inbox for principal: %s" % (principal,))
-                    results.append(InvalidCalendarUser(recipient))
+        # Extract expected host/port
+        expected_uri = principal.hostedURL()
+        expected_uri = urlparse.urlparse(expected_uri)
+    
+        # Get the request IP and map to hostname.
+        clientip = self.request.remoteAddr.host
         
-        self.recipients = results
+        # First compare as dotted IP
+        matched = False
+        if clientip == expected_uri.hostname:
+            matched = True
+        else:
+            # Now do hostname lookup
+            try:
+                host, aliases, _ignore_ips = socket.gethostbyaddr(clientip)
+                for hostname in itertools.chain((host,), aliases):
+                    # Try host match
+                    if hostname == expected_uri.hostname:
+                        matched = True
+                        break
+            except socket.herror, e:
+                log.debug("iSchedule cannot lookup client ip '%s': %s" % (clientip, str(e),))
+        
+        if not matched:
+            log.err("Originator not on allowed server: %s" % (self.originator,))
+            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
 
-    def checkOrganizer(self):
-        """
-        Delay ORGANIZER check until we know what their role is.
-        """
-        pass
-
     @inlineCallbacks
     def checkOrganizerAsOriginator(self):
         """
@@ -729,8 +778,13 @@
         if organizer:
             organizerPrincipal = self.resource.principalForCalendarUserAddress(organizer)
             if organizerPrincipal:
-                log.err("Invalid ORGANIZER in calendar data: %s" % (self.calendar,))
-                raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "organizer-allowed")))
+                if organizerPrincipal.locallyHosted():
+                    log.err("Invalid ORGANIZER in calendar data: %s" % (self.calendar,))
+                    raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "organizer-allowed")))
+                else:
+                    # Check that the origin server is the correct partition
+                    self.organizer = PartitionedCalendarUser(organizer, organizerPrincipal)
+                    self._validPartitionServer(self.organizer.principal)
             else:
                 localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(organizer))
                 if localUser:
@@ -761,8 +815,11 @@
         # Attendee cannot be local.
         attendeePrincipal = self.resource.principalForCalendarUserAddress(attendee)
         if attendeePrincipal:
-            log.err("Invalid ATTENDEE in calendar data: %s" % (self.calendar,))
-            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
+            if attendeePrincipal.locallyHosted():
+                log.err("Invalid ATTENDEE in calendar data: %s" % (self.calendar,))
+                raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "attendee-allowed")))
+            else:
+                self._validPartitionServer(attendeePrincipal)                
         else:
             localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(attendee))
             if localUser:
@@ -817,13 +874,25 @@
         pass
 
 
-class IMIPScheduler(Scheduler):
+class IMIPScheduler(RemoteScheduler):
 
     def checkAuthorization(self):
         pass
 
-    def checkOrganizer(self):
-        pass
+    @inlineCallbacks
+    def checkOriginator(self):
+        """
+        Check the validity of the Originator header.
+        """
+    
+        # For remote requests we do not allow the originator to be a local user or one within our domain.
+        originatorPrincipal = self.resource.principalForCalendarUserAddress(self.originator)
+        localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(self.originator))
+        if originatorPrincipal or localUser:
+            log.err("Cannot use originator that is on this server: %s" % (self.originator,))
+            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
+        else:
+            self.originator = RemoteCalendarUser(self.originator)
 
     def checkOrganizerAsOriginator(self):
         pass
@@ -847,60 +916,7 @@
             # TODO: verify this is the right response:
             raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
 
-    @inlineCallbacks
-    def checkOriginator(self):
-        """
-        Check the validity of the Originator header.
-        """
-    
-        # For remote requests we do not allow the originator to be a local user or one within our domain.
-        originatorPrincipal = self.resource.principalForCalendarUserAddress(self.originator)
-        localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(self.originator))
-        if originatorPrincipal or localUser:
-            log.err("Cannot use originator that is on this server: %s" % (self.originator,))
-            raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "originator-allowed")))
-        else:
-            self.originator = RemoteCalendarUser(self.originator)
 
-    @inlineCallbacks
-    def checkRecipients(self):
-        """
-        Check the validity of the Recipient header values. These must all be local as there
-        is no concept of server-to-server relaying.
-        """
-        
-        results = []
-        for recipient in self.recipients:
-            # Get the principal resource for this recipient
-            principal = self.resource.principalForCalendarUserAddress(recipient)
-            
-            # If no principal we may have a remote recipient but we should check whether
-            # the address is one that ought to be on our server and treat that as a missing
-            # user. Also if server-to-server is not enabled then remote addresses are not allowed.
-            if principal is None:
-                localUser = (yield addressmapping.mapper.isCalendarUserInMyDomain(recipient))
-                if localUser:
-                    log.err("No principal for calendar user address: %s" % (recipient,))
-                else:
-                    log.err("Unknown calendar user address: %s" % (recipient,))
-                results.append(InvalidCalendarUser(recipient))
-            else:
-                # Map recipient to their inbox
-                inbox = None
-                inboxURL = principal.scheduleInboxURL()
-                if inboxURL:
-                    inbox = (yield self.request.locateResource(inboxURL))
-
-                if inbox:
-                    results.append(LocalCalendarUser(recipient, principal, inbox, inboxURL))
-                else:
-                    log.err("No schedule inbox for principal: %s" % (principal,))
-                    results.append(InvalidCalendarUser(recipient))
-        
-        self.recipients = results
-
-
-
 class ScheduleResponseResponse (Response):
     """
     ScheduleResponse L{Response} object.

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/utils.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/utils.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/scheduling/utils.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -23,12 +23,14 @@
     Get a copy of the event for a principal.
     """
     
-    result = {}
-    result["resource"] = None
-    result["resource_name"] = None
-    result["calendar_collection"] = None
-    result["calendar_collection_uri"] = None
-    if principal:
+    result = {
+        "resource": None,
+        "resource_name": None,
+        "calendar_collection": None,
+        "calendar_collection_uri": None,
+    }
+
+    if principal and principal.locallyHosted():
         # Get principal's calendar-home
         calendar_home = principal.calendarHome()
         

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/static.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/static.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/static.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -38,6 +38,7 @@
 import os
 import errno
 from urlparse import urlsplit
+import urlparse
 
 from twext.web2.dav.davxml import ErrorResponse
 
@@ -51,7 +52,8 @@
 from twisted.web2.dav.noneprops import NonePropertyStore
 from twisted.web2.dav.resource import AccessDeniedError
 from twisted.web2.dav.resource import davPrivilegeSet
-from twisted.web2.dav.util import parentForURL, bindMethods
+from twisted.web2.dav.util import parentForURL, bindMethods, joinURL
+from twisted.web2.resource import RedirectResource
 
 from twistedcaldav import caldavxml
 from twistedcaldav import customxml
@@ -652,60 +654,78 @@
 
         assert len(name) > 4, "Directory record has an invalid GUID: %r" % (name,)
         
-        childPath = self.fp.child(name[0:2]).child(name[2:4]).child(name)
-        child = self.homeResourceClass(childPath.path, self, record)
-
-        if not child.exists():
-            self.provision()
-
-            if not childPath.parent().isdir():
-                childPath.parent().makedirs()
-
-            for oldPath in (
-                # Pre 2.0: All in one directory
-                self.fp.child(name),
-                # Pre 1.2: In types hierarchy instead of the GUID hierarchy
-                self.parent.getChild(record.recordType).fp.child(record.shortNames[0]),
-            ):
-                if oldPath.exists():
-                    # The child exists at an old location.  Move to new location.
-                    log.msg("Moving calendar home from old location %r to new location %r." % (oldPath, childPath))
-                    try:
-                        oldPath.moveTo(childPath)
-                    except (OSError, IOError), e:
-                        log.err("Error moving calendar home %r: %s" % (oldPath, e))
+        if record.locallyHosted():
+            childPath = self.fp.child(name[0:2]).child(name[2:4]).child(name)
+            child = self.homeResourceClass(childPath.path, self, record)
+    
+            if not child.exists():
+                self.provision()
+    
+                if not childPath.parent().isdir():
+                    childPath.parent().makedirs()
+    
+                for oldPath in (
+                    # Pre 2.0: All in one directory
+                    self.fp.child(name),
+                    # Pre 1.2: In types hierarchy instead of the GUID hierarchy
+                    self.parent.getChild(record.recordType).fp.child(record.shortNames[0]),
+                ):
+                    if oldPath.exists():
+                        # The child exists at an old location.  Move to new location.
+                        log.msg("Moving calendar home from old location %r to new location %r." % (oldPath, childPath))
+                        try:
+                            oldPath.moveTo(childPath)
+                        except (OSError, IOError), e:
+                            log.err("Error moving calendar home %r: %s" % (oldPath, e))
+                            raise HTTPError(StatusResponse(
+                                responsecode.INTERNAL_SERVER_ERROR,
+                                "Unable to move calendar home."
+                            ))
+                        child.fp.restat(False)
+                        break
+                else:
+                    #
+                    # NOTE: provisionDefaultCalendars() returns a deferred, which we are ignoring.
+                    # The result being that the default calendars will be present at some point
+                    # in the future, not necessarily right now, and we don't have a way to wait
+                    # on that to finish.
+                    #
+                    child.provisionDefaultCalendars()
+    
+                    #
+                    # Try to work around the above a little by telling the client that something
+                    # when wrong temporarily if the child isn't provisioned right away.
+                    #
+                    if not child.exists():
                         raise HTTPError(StatusResponse(
-                            responsecode.INTERNAL_SERVER_ERROR,
-                            "Unable to move calendar home."
+                            responsecode.SERVICE_UNAVAILABLE,
+                            "Provisioning calendar home."
                         ))
-                    child.fp.restat(False)
-                    break
-            else:
-                #
-                # NOTE: provisionDefaultCalendars() returns a deferred, which we are ignoring.
-                # The result being that the default calendars will be present at some point
-                # in the future, not necessarily right now, and we don't have a way to wait
-                # on that to finish.
-                #
-                child.provisionDefaultCalendars()
+    
+                assert child.exists()
+        
+        else:
+            childPath = self.fp.child(name[0:2]).child(name[2:4]).child(name)
+            child = CalendarHomeRedirectFile(childPath.path, self, record)
 
-                #
-                # Try to work around the above a little by telling the client that something
-                # when wrong temporarily if the child isn't provisioned right away.
-                #
-                if not child.exists():
-                    raise HTTPError(StatusResponse(
-                        responsecode.SERVICE_UNAVAILABLE,
-                        "Provisioning calendar home."
-                    ))
-
-            assert child.exists()
-
         return child
 
     def createSimilarFile(self, path):
         raise HTTPError(responsecode.NOT_FOUND)
 
+class CalendarHomeRedirectFile(RedirectResource):
+    
+    def __init__(self, path, parent, record):
+        self.path = path
+        self.parent = parent
+        self.record = record
+        
+        parsedURL = urlparse.urlparse(self.record.hostedURL())
+        super(CalendarHomeRedirectFile, self).__init__(scheme=parsedURL.scheme, host=parsedURL.hostname, port=parsedURL.port)
+    
+    def url(self):
+        return joinURL(self.parent.url(), self.record.uid)
+
 class CalendarHomeFile (PropfindCacheMixin, AutoProvisioningFileMixIn, DirectoryCalendarHomeResource, CalDAVFile):
     """
     Calendar home collection resource.

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/stdconfig.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/stdconfig.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/stdconfig.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -27,6 +27,7 @@
     ConfigProvider, ConfigurationError, config, _mergeData, )
 from twistedcaldav.log import (
     Logger, clearLogLevels, setLogLevelForNamespace, InvalidLogLevelError, )
+from twistedcaldav.partitions import partitions
 from twistedcaldav.util import (
     KeychainAccessError, KeychainPasswordNotFound, getPasswordFromKeychain, )
 
@@ -309,6 +310,13 @@
     },
 
     #
+    # Partitioning
+    #
+    "EnablePartitions":    False,   # Partitioning enabled or not
+    "ServerPartitionID":   "",      # Unique ID for this server's partition instance.
+    "PartitionConfigFile": "/etc/caldavd/partitions.plist", # File path for partition information
+
+    #
     # Performance tuning
     #
 
@@ -533,9 +541,8 @@
     try:
         if "DefaultLogLevel" in configDict:
             level = configDict["DefaultLogLevel"]
-            if not level:
-                level = "warn"
-            setLogLevelForNamespace(None, level)
+            if level:
+                setLogLevelForNamespace(None, level)
 
         if "LogLevels" in configDict:
             for namespace in configDict["LogLevels"]:
@@ -628,7 +635,18 @@
                     # The password doesn't exist in the keychain.
                     log.info("iMIP %s password not found in keychain" %
                         (direction,))
-    
+
+def _updatePartitions(configDict):
+    #
+    # Partitions
+    #
+
+    if configDict.EnablePartitions:
+        partitions.setSelfPartition(configDict.ServerPartitionID)
+        partitions.readConfig(configDict.PartitionConfigFile)
+    else:
+        partitions.clear()
+
 PRE_UPDATE_HOOKS = (
     _preUpdateDirectoryService,
     )
@@ -641,6 +659,7 @@
     _updateLogLevels,
     _updateNotifications,
     _updateScheduling,
+    _updatePartitions,
     )
     
 def _cleanup(configDict, defaultDict):

Modified: CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/test_config.py
===================================================================
--- CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/test_config.py	2009-07-25 00:22:04 UTC (rev 4478)
+++ CalendarServer/branches/users/cdaboo/partition-4464/twistedcaldav/test/test_config.py	2009-08-03 21:09:08 UTC (rev 4479)
@@ -228,6 +228,9 @@
         """
         Logging module configures properly.
         """
+        config.setDefaults(DEFAULT_CONFIG)
+        config.reload()
+
         self.assertEquals(logLevelForNamespace(None), "warn")
         self.assertEquals(logLevelForNamespace("some.namespace"), "warn")
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090803/6b33edcd/attachment-0001.html>


More information about the calendarserver-changes mailing list