[CalendarServer-changes] [4205] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Thu May 7 14:12:09 PDT 2009


Revision: 4205
          http://trac.macosforge.org/projects/calendarserver/changeset/4205
Author:   wsanchez at apple.com
Date:     2009-05-07 14:12:08 -0700 (Thu, 07 May 2009)
Log Message:
-----------
Rename caldav_* tools to calendarserver_*

Modified Paths:
--------------
    CalendarServer/trunk/setup.py
    CalendarServer/trunk/support/Makefile.Apple

Added Paths:
-----------
    CalendarServer/trunk/bin/calendarserver_export
    CalendarServer/trunk/bin/calendarserver_manage_principals
    CalendarServer/trunk/doc/calendarserver_export.8
    CalendarServer/trunk/doc/calendarserver_manage_principals.8

Removed Paths:
-------------
    CalendarServer/trunk/bin/caldav_export
    CalendarServer/trunk/bin/caldav_utility
    CalendarServer/trunk/doc/caldav_export.8
    CalendarServer/trunk/doc/caldav_utility.8

Deleted: CalendarServer/trunk/bin/caldav_export
===================================================================
--- CalendarServer/trunk/bin/caldav_export	2009-05-07 20:30:26 UTC (rev 4204)
+++ CalendarServer/trunk/bin/caldav_export	2009-05-07 21:12:08 UTC (rev 4205)
@@ -1,39 +0,0 @@
-#!/usr/bin/env python
-##
-# Copyright (c) 2006-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.
-##
-
-import sys
-
-#PYTHONPATH
-
-if __name__ == "__main__":
-    if "PYTHONPATH" in globals():
-        sys.path.insert(0, PYTHONPATH)
-    else:
-        from os.path import dirname, abspath, join
-        from subprocess import Popen, PIPE
-
-        home = dirname(dirname(abspath(__file__)))
-        run = join(home, "run")
-
-        child = Popen((run, "-p"), stdout=PIPE)
-        path, stderr = child.communicate()
-
-        if child.wait() == 0:
-            sys.path[0:0] = path.split(":")
-
-    from calendarserver.tools.export import main
-    main()

Deleted: CalendarServer/trunk/bin/caldav_utility
===================================================================
--- CalendarServer/trunk/bin/caldav_utility	2009-05-07 20:30:26 UTC (rev 4204)
+++ CalendarServer/trunk/bin/caldav_utility	2009-05-07 21:12:08 UTC (rev 4205)
@@ -1,458 +0,0 @@
-#!/usr/bin/env python
-
-##
-# Copyright (c) 2006-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 __future__ import with_statement
-import sys
-
-#PYTHONPATH
-
-if "PYTHONPATH" in globals():
-    sys.path.insert(0, PYTHONPATH)
-else:
-    from os.path import dirname, abspath, join
-    from subprocess import Popen, PIPE
-
-    home = dirname(dirname(abspath(__file__)))
-    run = join(home, "run")
-
-    child = Popen((run, "-p"), stdout=PIPE)
-    path, stderr = child.communicate()
-
-    if child.wait() == 0:
-        sys.path[0:0] = path.split(":")
-
-
-from calendarserver.provision.root import RootResource
-from getopt import getopt, GetoptError
-import operator
-from twisted.internet import reactor
-from twisted.internet.address import IPv4Address
-from twisted.internet.defer import inlineCallbacks, returnValue, succeed
-from twisted.python import log
-from twisted.python.reflect import namedClass
-from twisted.web2.dav import davxml
-from twistedcaldav import caldavxml
-from twistedcaldav import memcachepool
-from twistedcaldav.config import config, defaultConfigFile
-from twistedcaldav.customxml import calendarserver_namespace
-from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord
-from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
-from twistedcaldav.log import setLogLevelForNamespace
-from twistedcaldav.notify import installNotificationClient
-from twistedcaldav.static import CalendarHomeProvisioningFile
-import itertools
-import os
-
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-def usage(e=None):
-    if e:
-        print e
-        print ""
-
-    name = os.path.basename(sys.argv[0])
-    print "usage: %s [options]" % (name,)
-    print ""
-    print "options:"
-    print "  -h --help: print this help and exit"
-    print "  -f --config <path>: Specify caldavd.plist configuration path"
-    print "  --resource <prinicpal-path>: path of the resource to use"
-    print "  --search <search-string>: search for matching resources"
-    print "  --read-property: namespace-qualified DAV property to read, e.g. 'DAV:#group-member-set'"
-    print "  --list-read-delegates: list delegates with read-only access to the current resource"
-    print "  --list-write-delegates: list delegates with read-write access to the current resource"
-    print "  --add-read-delegate <prinicpal-path>: add argument as a read-only delegate to the current resource"
-    print "  --add-write-delegate <prinicpal-path>: add argument as a read-write delegate to the current resource"
-    print "  --remove-delegate <prinicpal-path>: strip argument of delegate status for the current resource"
-    print "  --set-auto-schedule [true|false] : determines whether the current resource auto-accepts invitations"
-    print "  --get-auto-schedule : returns the current resource's auto-schedule state"
-
-    if e:
-        sys.exit(64)
-    else:
-        sys.exit(0)
-
-class UsageError (StandardError):
-    pass
-
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-def main():
-    try:
-        (optargs, args) = getopt(
-            sys.argv[1:], "hf:r:s:", [
-                "config=",
-                "help",
-                "resource=",
-                "search=",
-                "read-property=",
-                "list-read-delegates",
-                "list-write-delegates",
-                "add-read-delegate=",
-                "add-write-delegate=",
-                "remove-delegate=",
-                "set-auto-schedule=",
-                "get-auto-schedule",
-            ],
-        )
-    except GetoptError, e:
-        usage(e)
-
-    if args:
-        usage("Too many arguments: %s" % (" ".join(args),))
-
-    logFileName = "/dev/stdout"
-    observer = log.FileLogObserver(open(logFileName, "a"))
-    log.addObserver(observer.emit)
-
-    # First pass through the args:
-
-    configFileName = None
-
-    for opt, arg in optargs:
-        if opt in ("-h", "--help"):
-            usage()
-
-        elif opt in ("-f", "--config"):
-            configFileName = arg
-
-    loadConfig(configFileName)
-    directory, root = setup()
-    root = ResourceWrapper(root)
-
-    reactor.callLater(0, run, directory, root, optargs)
-    reactor.run()
-
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
- at inlineCallbacks
-def run(directory, root, optargs):
-
-    print ""
-
-    resource = None
-
-    for opt, arg in optargs:
-
-        if opt in ("-r", "--resource",):
-            resource = root.lookupResource(arg)
-            if resource is not None:
-                print "Found resource %s at %s" % (resource.resource, arg)
-            else:
-                abort("Could not find resource at %s" % (arg,))
-
-        elif opt in ("-s", "--search",):
-            fields = []
-            for fieldName in ("fullName", "firstName", "lastName",
-                "emailAddresses"):
-                fields.append((fieldName, arg, True, "contains"))
-
-            records = list((yield directory.recordsMatchingFields(fields)))
-            if records:
-                records.sort(key=operator.attrgetter('fullName'))
-                print "%d matches found:" % (len(records),)
-                for record in records:
-                    print "\n%s (%s)" % (record.fullName,
-                        { "users"     : "User",
-                          "groups"    : "Group",
-                          "locations" : "Place",
-                          "resources" : "Resource",
-                        }.get(record.recordType),
-                    )
-                    print record.guid
-                    print "   Record names: %s" % (", ".join(record.shortNames),)
-                    if record.authIDs:
-                        print "   Auth IDs: %s" % (", ".join(record.authIDs),)
-                    if record.emailAddresses:
-                        print "   Emails: %s" % (", ".join(record.emailAddresses),)
-            else:
-                print "No matches found"
-
-        elif opt in ("--read-property",):
-            if resource is None: abort("No current resource.")
-
-            try:
-                namespace, name = arg.split("#")
-            except Exception, e:
-                abort("Can't parse --propertyToRead: %s" % (arg,))
-
-            result = (yield resource.readProperty((namespace, name)))
-            print result.toxml()
-
-        elif opt in ("--list-write-delegates", "--list-read-delegates"):
-            if resource is None: abort("No current resource.")
-
-            permission = "write" if "write" in opt else "read"
-            print "Delegates (%s) for %s:" % (permission, resource.resource)
-            paths = (yield resource.getDelegates(permission))
-            for path in paths:
-                delegate = root.getChild(path)
-                print delegate.resource
-
-        elif opt in ("--add-write-delegate", "--add-read-delegate"):
-            if resource is None: abort("No current resource.")
-
-            delegate = root.lookupResource(arg)
-            if delegate is None:
-                abort("No delegate found for %s" % (arg,))
-
-            permission = "write" if "write" in opt else "read"
-            result = (yield resource.addDelegate(delegate, permission))
-
-        elif opt == "--remove-delegate":
-            if resource is None: abort("No current resource.")
-
-            delegate = root.lookupResource(arg)
-            if delegate is None:
-                abort("No delegate found for %s" % (arg,))
-
-            result = (yield resource.removeDelegate(delegate, "read"))
-            result = (yield resource.removeDelegate(delegate, "write"))
-
-        elif opt == "--set-auto-schedule":
-            if resource is None: abort("No current resource.")
-
-            result = (yield resource.setAutoSchedule(arg.lower() in ("true", "1")))
-
-        elif opt == "--get-auto-schedule":
-            if resource is None: abort("No current resource.")
-
-            result = (yield resource.getAutoSchedule())
-            print "Auto-Schedule: %s" % ("True" if result else "False",)
-
-    print ""
-
-    # reactor.callLater(0, reactor.stop)
-    reactor.stop()
-
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-class ResourceWrapper(object):
-
-    def __init__(self, resource):
-        self.resource = resource
-
-    def readProperty(self, prop):
-        return self.resource.readProperty(prop, FakeRequest())
-
-    def writeProperty(self, prop):
-        return self.resource.writeProperty(prop, FakeRequest())
-
-    def lookupResource(self, specifier):
-        # For now, support GUID lookup
-        return self.getChild("principals/__uids__/%s" % (specifier,))
-
-    def getChild(self, path):
-        resource = self.resource
-        segments = path.strip("/").split("/")
-        for segment in segments:
-            resource = resource.getChild(segment)
-            if resource is None:
-                return None
-        return ResourceWrapper(resource)
-
-    @inlineCallbacks
-    def removeDelegate(self, delegate, permission):
-        subPrincipalName = "calendar-proxy-%s" % (permission,)
-        subPrincipal = self.getChild(subPrincipalName)
-        if subPrincipal is None:
-            abort("No proxy subprincipal found for %s" % (self.resource,))
-
-        namespace, name = davxml.dav_namespace, "group-member-set"
-        prop = (yield subPrincipal.readProperty((namespace, name)))
-        newChildren = []
-        for child in prop.children:
-            if str(child) != delegate.url():
-                newChildren.append(child)
-
-        if len(prop.children) == len(newChildren):
-            # Nothing to do -- the delegate wasn't there
-            returnValue(False)
-
-        newProp = davxml.GroupMemberSet(*newChildren)
-        result = (yield subPrincipal.writeProperty(newProp))
-        returnValue(result)
-
-    @inlineCallbacks
-    def addDelegate(self, delegate, permission):
-
-        opposite = "read" if permission == "write" else "write"
-        result = (yield self.removeDelegate(delegate, opposite))
-
-        subPrincipalName = "calendar-proxy-%s" % (permission,)
-        subPrincipal = self.getChild(subPrincipalName)
-        if subPrincipal is None:
-            abort("No proxy subprincipal found for %s" % (self.resource,))
-
-        namespace, name = davxml.dav_namespace, "group-member-set"
-        prop = (yield subPrincipal.readProperty((namespace, name)))
-        for child in prop.children:
-            if str(child) == delegate.url():
-                # delegate is already in the group
-                break
-        else:
-            # delegate is not already in the group
-            newChildren = list(prop.children)
-            newChildren.append(davxml.HRef(delegate.url()))
-            newProp = davxml.GroupMemberSet(*newChildren)
-            result = (yield subPrincipal.writeProperty(newProp))
-            returnValue(result)
-
-    @inlineCallbacks
-    def getDelegates(self, permission):
-
-        subPrincipalName = "calendar-proxy-%s" % (permission,)
-        subPrincipal = self.getChild(subPrincipalName)
-        if subPrincipal is None:
-            abort("No proxy subprincipal found for %s" % (self.resource,))
-
-        namespace, name = davxml.dav_namespace, "group-member-set"
-        prop = (yield subPrincipal.readProperty((namespace, name)))
-        result = []
-        for child in prop.children:
-            result.append(str(child))
-        returnValue(result)
-
-    def setAutoSchedule(self, autoSchedule):
-        return self.resource.setAutoSchedule(autoSchedule)
-
-    def getAutoSchedule(self):
-        return self.resource.getAutoSchedule()
-
-    def url(self):
-        return self.resource.url()
-
-class FakeRequest(object):
-    pass
-
-def abort(msg, errno=1):
-    print "ERROR:", msg
-    print "Exiting"
-    reactor.stop()
-    sys.exit(errno)
-
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-def setup():
-
-    setLogLevelForNamespace(None, "warn")
-
-    directory = getDirectory()
-    if config.Memcached["ClientEnabled"]:
-        memcachepool.installPool(
-            IPv4Address(
-                'TCP',
-                config.Memcached["BindAddress"],
-                config.Memcached["Port"]
-            ),
-            config.Memcached["MaxClients"]
-        )
-    if config.Notifications["Enabled"]:
-        installNotificationClient(
-            config.Notifications["InternalNotificationHost"],
-            config.Notifications["InternalNotificationPort"],
-        )
-    principalCollection = directory.getPrincipalCollection()
-    root = RootResource(
-        config.DocumentRoot,
-        principalCollections=(principalCollection,),
-    )
-    root.putChild("principals", principalCollection)
-    calendarCollection = CalendarHomeProvisioningFile(
-        os.path.join(config.DocumentRoot, "calendars"),
-        directory, "/calendars/",
-    )
-    root.putChild("calendars", calendarCollection)
-
-    return (directory, root)
-
-def loadConfig(configFileName):
-    if configFileName is None:
-        configFileName = defaultConfigFile
-
-    if not os.path.isfile(configFileName):
-        sys.stderr.write("No config file: %s\n" % (configFileName,))
-        sys.exit(1)
-
-    config.loadConfig(configFileName)
-
-    return config
-
-
-def getDirectory():
-    BaseDirectoryService = namedClass(config.DirectoryService["type"])
-
-    class MyDirectoryService (BaseDirectoryService):
-        def getPrincipalCollection(self):
-            if not hasattr(self, "_principalCollection"):
-                from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
-                self._principalCollection = DirectoryPrincipalProvisioningResource("/principals/", self)
-
-            return self._principalCollection
-
-        def setPrincipalCollection(self, coll):
-            # See principal.py line 237:  self.directory.principalCollection = self
-            pass
-
-        principalCollection = property(getPrincipalCollection, setPrincipalCollection)
-
-        def calendarHomeForRecord(self, record):
-            principal = self.principalCollection.principalForRecord(record)
-            if principal:
-                try:
-                    return principal._calendarHome()
-                except AttributeError:
-                    pass
-            return None
-
-        def calendarHomeForShortName(self, recordType, shortName):
-            principal = self.principalCollection.principalForShortName(recordType, shortName)
-            if principal:
-                try:
-                    return principal._calendarHome()
-                except AttributeError:
-                    pass
-            return None
-
-        def principalForCalendarUserAddress(self, cua):
-            return self.principalCollection.principalForCalendarUserAddress(cua)
-
-
-    return MyDirectoryService(**config.DirectoryService["params"])
-
-class DummyDirectoryService (DirectoryService):
-    realmName = ""
-    baseGUID = "51856FD4-5023-4890-94FE-4356C4AAC3E4"
-    def recordTypes(self): return ()
-    def listRecords(self): return ()
-    def recordWithShortName(self): return None
-
-dummyDirectoryRecord = DirectoryRecord(
-    service = DummyDirectoryService(),
-    recordType = "dummy",
-    guid = "8EF0892F-7CB6-4B8E-B294-7C5A5321136A",
-    shortNames = ("dummy",),
-    fullName = "Dummy McDummerson",
-    calendarUserAddresses = set(),
-    # autoSchedule = False,
-)
-
-# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-if __name__ == "__main__":
-    main()

Copied: CalendarServer/trunk/bin/calendarserver_export (from rev 4181, CalendarServer/trunk/bin/caldav_export)
===================================================================
--- CalendarServer/trunk/bin/calendarserver_export	                        (rev 0)
+++ CalendarServer/trunk/bin/calendarserver_export	2009-05-07 21:12:08 UTC (rev 4205)
@@ -0,0 +1,39 @@
+#!/usr/bin/env python
+##
+# Copyright (c) 2006-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.
+##
+
+import sys
+
+#PYTHONPATH
+
+if __name__ == "__main__":
+    if "PYTHONPATH" in globals():
+        sys.path.insert(0, PYTHONPATH)
+    else:
+        from os.path import dirname, abspath, join
+        from subprocess import Popen, PIPE
+
+        home = dirname(dirname(abspath(__file__)))
+        run = join(home, "run")
+
+        child = Popen((run, "-p"), stdout=PIPE)
+        path, stderr = child.communicate()
+
+        if child.wait() == 0:
+            sys.path[0:0] = path.split(":")
+
+    from calendarserver.tools.export import main
+    main()

Copied: CalendarServer/trunk/bin/calendarserver_manage_principals (from rev 4181, CalendarServer/trunk/bin/caldav_utility)
===================================================================
--- CalendarServer/trunk/bin/calendarserver_manage_principals	                        (rev 0)
+++ CalendarServer/trunk/bin/calendarserver_manage_principals	2009-05-07 21:12:08 UTC (rev 4205)
@@ -0,0 +1,458 @@
+#!/usr/bin/env python
+
+##
+# Copyright (c) 2006-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 __future__ import with_statement
+import sys
+
+#PYTHONPATH
+
+if "PYTHONPATH" in globals():
+    sys.path.insert(0, PYTHONPATH)
+else:
+    from os.path import dirname, abspath, join
+    from subprocess import Popen, PIPE
+
+    home = dirname(dirname(abspath(__file__)))
+    run = join(home, "run")
+
+    child = Popen((run, "-p"), stdout=PIPE)
+    path, stderr = child.communicate()
+
+    if child.wait() == 0:
+        sys.path[0:0] = path.split(":")
+
+
+from calendarserver.provision.root import RootResource
+from getopt import getopt, GetoptError
+import operator
+from twisted.internet import reactor
+from twisted.internet.address import IPv4Address
+from twisted.internet.defer import inlineCallbacks, returnValue, succeed
+from twisted.python import log
+from twisted.python.reflect import namedClass
+from twisted.web2.dav import davxml
+from twistedcaldav import caldavxml
+from twistedcaldav import memcachepool
+from twistedcaldav.config import config, defaultConfigFile
+from twistedcaldav.customxml import calendarserver_namespace
+from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord
+from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
+from twistedcaldav.log import setLogLevelForNamespace
+from twistedcaldav.notify import installNotificationClient
+from twistedcaldav.static import CalendarHomeProvisioningFile
+import itertools
+import os
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+def usage(e=None):
+    if e:
+        print e
+        print ""
+
+    name = os.path.basename(sys.argv[0])
+    print "usage: %s [options]" % (name,)
+    print ""
+    print "options:"
+    print "  -h --help: print this help and exit"
+    print "  -f --config <path>: Specify caldavd.plist configuration path"
+    print "  --resource <prinicpal-path>: path of the resource to use"
+    print "  --search <search-string>: search for matching resources"
+    print "  --read-property: namespace-qualified DAV property to read, e.g. 'DAV:#group-member-set'"
+    print "  --list-read-delegates: list delegates with read-only access to the current resource"
+    print "  --list-write-delegates: list delegates with read-write access to the current resource"
+    print "  --add-read-delegate <prinicpal-path>: add argument as a read-only delegate to the current resource"
+    print "  --add-write-delegate <prinicpal-path>: add argument as a read-write delegate to the current resource"
+    print "  --remove-delegate <prinicpal-path>: strip argument of delegate status for the current resource"
+    print "  --set-auto-schedule [true|false] : determines whether the current resource auto-accepts invitations"
+    print "  --get-auto-schedule : returns the current resource's auto-schedule state"
+
+    if e:
+        sys.exit(64)
+    else:
+        sys.exit(0)
+
+class UsageError (StandardError):
+    pass
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+def main():
+    try:
+        (optargs, args) = getopt(
+            sys.argv[1:], "hf:r:s:", [
+                "config=",
+                "help",
+                "resource=",
+                "search=",
+                "read-property=",
+                "list-read-delegates",
+                "list-write-delegates",
+                "add-read-delegate=",
+                "add-write-delegate=",
+                "remove-delegate=",
+                "set-auto-schedule=",
+                "get-auto-schedule",
+            ],
+        )
+    except GetoptError, e:
+        usage(e)
+
+    if args:
+        usage("Too many arguments: %s" % (" ".join(args),))
+
+    logFileName = "/dev/stdout"
+    observer = log.FileLogObserver(open(logFileName, "a"))
+    log.addObserver(observer.emit)
+
+    # First pass through the args:
+
+    configFileName = None
+
+    for opt, arg in optargs:
+        if opt in ("-h", "--help"):
+            usage()
+
+        elif opt in ("-f", "--config"):
+            configFileName = arg
+
+    loadConfig(configFileName)
+    directory, root = setup()
+    root = ResourceWrapper(root)
+
+    reactor.callLater(0, run, directory, root, optargs)
+    reactor.run()
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+ at inlineCallbacks
+def run(directory, root, optargs):
+
+    print ""
+
+    resource = None
+
+    for opt, arg in optargs:
+
+        if opt in ("-r", "--resource",):
+            resource = root.lookupResource(arg)
+            if resource is not None:
+                print "Found resource %s at %s" % (resource.resource, arg)
+            else:
+                abort("Could not find resource at %s" % (arg,))
+
+        elif opt in ("-s", "--search",):
+            fields = []
+            for fieldName in ("fullName", "firstName", "lastName",
+                "emailAddresses"):
+                fields.append((fieldName, arg, True, "contains"))
+
+            records = list((yield directory.recordsMatchingFields(fields)))
+            if records:
+                records.sort(key=operator.attrgetter('fullName'))
+                print "%d matches found:" % (len(records),)
+                for record in records:
+                    print "\n%s (%s)" % (record.fullName,
+                        { "users"     : "User",
+                          "groups"    : "Group",
+                          "locations" : "Place",
+                          "resources" : "Resource",
+                        }.get(record.recordType),
+                    )
+                    print record.guid
+                    print "   Record names: %s" % (", ".join(record.shortNames),)
+                    if record.authIDs:
+                        print "   Auth IDs: %s" % (", ".join(record.authIDs),)
+                    if record.emailAddresses:
+                        print "   Emails: %s" % (", ".join(record.emailAddresses),)
+            else:
+                print "No matches found"
+
+        elif opt in ("--read-property",):
+            if resource is None: abort("No current resource.")
+
+            try:
+                namespace, name = arg.split("#")
+            except Exception, e:
+                abort("Can't parse --propertyToRead: %s" % (arg,))
+
+            result = (yield resource.readProperty((namespace, name)))
+            print result.toxml()
+
+        elif opt in ("--list-write-delegates", "--list-read-delegates"):
+            if resource is None: abort("No current resource.")
+
+            permission = "write" if "write" in opt else "read"
+            print "Delegates (%s) for %s:" % (permission, resource.resource)
+            paths = (yield resource.getDelegates(permission))
+            for path in paths:
+                delegate = root.getChild(path)
+                print delegate.resource
+
+        elif opt in ("--add-write-delegate", "--add-read-delegate"):
+            if resource is None: abort("No current resource.")
+
+            delegate = root.lookupResource(arg)
+            if delegate is None:
+                abort("No delegate found for %s" % (arg,))
+
+            permission = "write" if "write" in opt else "read"
+            result = (yield resource.addDelegate(delegate, permission))
+
+        elif opt == "--remove-delegate":
+            if resource is None: abort("No current resource.")
+
+            delegate = root.lookupResource(arg)
+            if delegate is None:
+                abort("No delegate found for %s" % (arg,))
+
+            result = (yield resource.removeDelegate(delegate, "read"))
+            result = (yield resource.removeDelegate(delegate, "write"))
+
+        elif opt == "--set-auto-schedule":
+            if resource is None: abort("No current resource.")
+
+            result = (yield resource.setAutoSchedule(arg.lower() in ("true", "1")))
+
+        elif opt == "--get-auto-schedule":
+            if resource is None: abort("No current resource.")
+
+            result = (yield resource.getAutoSchedule())
+            print "Auto-Schedule: %s" % ("True" if result else "False",)
+
+    print ""
+
+    # reactor.callLater(0, reactor.stop)
+    reactor.stop()
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+class ResourceWrapper(object):
+
+    def __init__(self, resource):
+        self.resource = resource
+
+    def readProperty(self, prop):
+        return self.resource.readProperty(prop, FakeRequest())
+
+    def writeProperty(self, prop):
+        return self.resource.writeProperty(prop, FakeRequest())
+
+    def lookupResource(self, specifier):
+        # For now, support GUID lookup
+        return self.getChild("principals/__uids__/%s" % (specifier,))
+
+    def getChild(self, path):
+        resource = self.resource
+        segments = path.strip("/").split("/")
+        for segment in segments:
+            resource = resource.getChild(segment)
+            if resource is None:
+                return None
+        return ResourceWrapper(resource)
+
+    @inlineCallbacks
+    def removeDelegate(self, delegate, permission):
+        subPrincipalName = "calendar-proxy-%s" % (permission,)
+        subPrincipal = self.getChild(subPrincipalName)
+        if subPrincipal is None:
+            abort("No proxy subprincipal found for %s" % (self.resource,))
+
+        namespace, name = davxml.dav_namespace, "group-member-set"
+        prop = (yield subPrincipal.readProperty((namespace, name)))
+        newChildren = []
+        for child in prop.children:
+            if str(child) != delegate.url():
+                newChildren.append(child)
+
+        if len(prop.children) == len(newChildren):
+            # Nothing to do -- the delegate wasn't there
+            returnValue(False)
+
+        newProp = davxml.GroupMemberSet(*newChildren)
+        result = (yield subPrincipal.writeProperty(newProp))
+        returnValue(result)
+
+    @inlineCallbacks
+    def addDelegate(self, delegate, permission):
+
+        opposite = "read" if permission == "write" else "write"
+        result = (yield self.removeDelegate(delegate, opposite))
+
+        subPrincipalName = "calendar-proxy-%s" % (permission,)
+        subPrincipal = self.getChild(subPrincipalName)
+        if subPrincipal is None:
+            abort("No proxy subprincipal found for %s" % (self.resource,))
+
+        namespace, name = davxml.dav_namespace, "group-member-set"
+        prop = (yield subPrincipal.readProperty((namespace, name)))
+        for child in prop.children:
+            if str(child) == delegate.url():
+                # delegate is already in the group
+                break
+        else:
+            # delegate is not already in the group
+            newChildren = list(prop.children)
+            newChildren.append(davxml.HRef(delegate.url()))
+            newProp = davxml.GroupMemberSet(*newChildren)
+            result = (yield subPrincipal.writeProperty(newProp))
+            returnValue(result)
+
+    @inlineCallbacks
+    def getDelegates(self, permission):
+
+        subPrincipalName = "calendar-proxy-%s" % (permission,)
+        subPrincipal = self.getChild(subPrincipalName)
+        if subPrincipal is None:
+            abort("No proxy subprincipal found for %s" % (self.resource,))
+
+        namespace, name = davxml.dav_namespace, "group-member-set"
+        prop = (yield subPrincipal.readProperty((namespace, name)))
+        result = []
+        for child in prop.children:
+            result.append(str(child))
+        returnValue(result)
+
+    def setAutoSchedule(self, autoSchedule):
+        return self.resource.setAutoSchedule(autoSchedule)
+
+    def getAutoSchedule(self):
+        return self.resource.getAutoSchedule()
+
+    def url(self):
+        return self.resource.url()
+
+class FakeRequest(object):
+    pass
+
+def abort(msg, errno=1):
+    print "ERROR:", msg
+    print "Exiting"
+    reactor.stop()
+    sys.exit(errno)
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+def setup():
+
+    setLogLevelForNamespace(None, "warn")
+
+    directory = getDirectory()
+    if config.Memcached["ClientEnabled"]:
+        memcachepool.installPool(
+            IPv4Address(
+                'TCP',
+                config.Memcached["BindAddress"],
+                config.Memcached["Port"]
+            ),
+            config.Memcached["MaxClients"]
+        )
+    if config.Notifications["Enabled"]:
+        installNotificationClient(
+            config.Notifications["InternalNotificationHost"],
+            config.Notifications["InternalNotificationPort"],
+        )
+    principalCollection = directory.getPrincipalCollection()
+    root = RootResource(
+        config.DocumentRoot,
+        principalCollections=(principalCollection,),
+    )
+    root.putChild("principals", principalCollection)
+    calendarCollection = CalendarHomeProvisioningFile(
+        os.path.join(config.DocumentRoot, "calendars"),
+        directory, "/calendars/",
+    )
+    root.putChild("calendars", calendarCollection)
+
+    return (directory, root)
+
+def loadConfig(configFileName):
+    if configFileName is None:
+        configFileName = defaultConfigFile
+
+    if not os.path.isfile(configFileName):
+        sys.stderr.write("No config file: %s\n" % (configFileName,))
+        sys.exit(1)
+
+    config.loadConfig(configFileName)
+
+    return config
+
+
+def getDirectory():
+    BaseDirectoryService = namedClass(config.DirectoryService["type"])
+
+    class MyDirectoryService (BaseDirectoryService):
+        def getPrincipalCollection(self):
+            if not hasattr(self, "_principalCollection"):
+                from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
+                self._principalCollection = DirectoryPrincipalProvisioningResource("/principals/", self)
+
+            return self._principalCollection
+
+        def setPrincipalCollection(self, coll):
+            # See principal.py line 237:  self.directory.principalCollection = self
+            pass
+
+        principalCollection = property(getPrincipalCollection, setPrincipalCollection)
+
+        def calendarHomeForRecord(self, record):
+            principal = self.principalCollection.principalForRecord(record)
+            if principal:
+                try:
+                    return principal._calendarHome()
+                except AttributeError:
+                    pass
+            return None
+
+        def calendarHomeForShortName(self, recordType, shortName):
+            principal = self.principalCollection.principalForShortName(recordType, shortName)
+            if principal:
+                try:
+                    return principal._calendarHome()
+                except AttributeError:
+                    pass
+            return None
+
+        def principalForCalendarUserAddress(self, cua):
+            return self.principalCollection.principalForCalendarUserAddress(cua)
+
+
+    return MyDirectoryService(**config.DirectoryService["params"])
+
+class DummyDirectoryService (DirectoryService):
+    realmName = ""
+    baseGUID = "51856FD4-5023-4890-94FE-4356C4AAC3E4"
+    def recordTypes(self): return ()
+    def listRecords(self): return ()
+    def recordWithShortName(self): return None
+
+dummyDirectoryRecord = DirectoryRecord(
+    service = DummyDirectoryService(),
+    recordType = "dummy",
+    guid = "8EF0892F-7CB6-4B8E-B294-7C5A5321136A",
+    shortNames = ("dummy",),
+    fullName = "Dummy McDummerson",
+    calendarUserAddresses = set(),
+    # autoSchedule = False,
+)
+
+# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
+if __name__ == "__main__":
+    main()

Deleted: CalendarServer/trunk/doc/caldav_export.8
===================================================================
--- CalendarServer/trunk/doc/caldav_export.8	2009-05-07 20:30:26 UTC (rev 4204)
+++ CalendarServer/trunk/doc/caldav_export.8	2009-05-07 21:12:08 UTC (rev 4205)
@@ -1,75 +0,0 @@
-.\"
-.\" Copyright (c) 2006-2008 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.
-.\"
-.\" The following requests are required for all man pages.
-.Dd November 6, 2008
-.Dt CALDAV_EXPORT 8
-.Os
-.Sh NAME
-.Nm caldav_export
-.Nd Darwin Calendar Server Export Tool
-.Sh SYNOPSIS
-.Nm
-.Op Fl f Ar config_file
-.Op Fl o Ar output_file
-.Op Fl c Ar collection
-.Op Fl H Ar home
-.Op Fl r Ar record
-.Op Fl u Ar user
-.Sh DESCRIPTION
-.Nm
-is a tool that generates a single iCalendar file containing all of the
-iCalendar components found from all specifies input sources, providing
-server administrators a means by which to export data from the Darwin
-Calandar Server into a format that can be viewed and/or manipulated by
-other tools.  Multiple input sources may be specified; the resulting
-iCalendar data will contain the combined data from all sources.
-.Sh OPTIONS
-.Bl -tag -width flag
-.It Fl h, -help
-Displays usage information
-.It Fl f, -config Ar FILE
-Use the Calendar Server configuration specified in the given file.
-.It Fl o, -output Ar FILE
-Write resulting iCalendar data to the given file.
-.It Fl c, -collection Ar DIRECTORY
-Read iCalendar objects from the calendar collection at the given path.
-.It Fl h, -home Ar DIRECTORY
-Read iCalendar objects from all calendar collections within the
-calendar home at the given path.
-.It Fl r, -record Ar TYPE:NAME
-Read iCalendar objects from all calendar collections within the
-calendar home for the directory record of the given type with the
-given name.
-.It Fl u, -user Ar NAME
-Read iCalendar objects from all calendar collections within the
-calendar home for the directory user with the given name.  This is
-shorthand for
-.Fl r Ar user:NAME .
-.El
-.Sh FILES
-.Bl -tag -width flag
-.It /etc/caldavd/caldavd.plist
-The Calendar Server configuration file.
-.It /Library/CalendarServer/Documents
-The server's document root, which is the used as the backing store for
-the HTTP resources on the server.
-.El
-.Sh SEE ALSO
-.Xr caldavd 8
-.Sh STANDARDS
-The iCalendar data generated by
-.Nm
-is expected to comply with RFC 2445 (iCalendar).

Deleted: CalendarServer/trunk/doc/caldav_utility.8
===================================================================
--- CalendarServer/trunk/doc/caldav_utility.8	2009-05-07 20:30:26 UTC (rev 4204)
+++ CalendarServer/trunk/doc/caldav_utility.8	2009-05-07 21:12:08 UTC (rev 4205)
@@ -1,106 +0,0 @@
-.\"
-.\" Copyright (c) 2006-2008 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.
-.\"
-.\" The following requests are required for all man pages.
-.Dd April 24, 2009
-.Dt CALDAV_UTILITY 8
-.Os
-.Sh NAME
-.Nm caldav_utility
-.Nd Darwin Calendar Server Resource Utility
-.Sh SYNOPSIS
-.Nm
-.Op Fl -config Ar config_file
-.Op Fl -resource Ar guid
-.Op Fl -search Ar search-term
-.Op Fl -read-property Ar dav_property
-.Op Fl -list-read-delegates
-.Op Fl -list-write-delegates
-.Op Fl -add-read-delegate Ar guid
-.Op Fl -add-write-delegate Ar guid
-.Op Fl -remove-delegate Ar guid
-.Op Fl -set-auto-schedule Ar True|False
-.Op Fl -get-auto-schedule
-.Sh DESCRIPTION
-.Nm
-is a tool for manipulating delegate assignments for resources and
-locations, as well as specifying whether they auto-accept scheduling
-invitations.  It must be run as root on a host with a running
-calendar server.  On the command line you first select a resource
-to use (via the
-.Fl -resource
-argument), and follow that with one or
-more commands.
-.Sh OPTIONS
-.Bl -tag -width flag
-.It Fl h, -help
-Displays usage information
-.It Fl f, -config Ar FILE
-Use the Calendar Server configuration specified in the given file.  Defaults to /etc/caldavd/caldavd.plist.
-.It Fl -resource Ar guid
-Specifies the resource the following operations should be applied to.
-.It Fl s, -search Ar search_term
-Search for records matching search_term.
-.It Fl -read-property Ar dav_property
-Prints the value of the dav_property on the current resource.  The format of
-the dav_property is "namespace#property".  Examples:
-"DAV:#alternate-URI-set" or "http://calendarserver.org/ns/#record-type".
-.It Fl -list-read-delegates
-Prints the list of principals that have read-only delegate access for the current resource.
-.It Fl -list-write-delegates
-Prints the list of principals that have read-write delegate access for the current resource.
-.It Fl -add-read-delegate Ar guid
-Adds a principal to the group of principals which have read-only delegate access for the current resource.  Adding a principal as a read-only delegate removes read-write access, if read-write access had previously been granted.
-.It Fl -add-write-delegate Ar guid
-Adds a principal to the group of principals which have read-write delegate access for the current resource.
-.It Fl -remove-delegate Ar guid
-Strips a principal of delegate access for the current resource.
-.It Fl -set-auto-schedule Ar True|False
-Setting auto-schedule to True will cause the current resource to automatically
-accept any scheduling invitations.  A False value means it's up to one of the
-read-write delegates for the resource to accept/decline invitations.
-.It Fl -get-auto-schedule
-Prints the current auto-schedule state of the current resource.
-.El
-.Sh USAGE
-.Nm
-processes the command line options in order, allowing you to chain multiple
-operations.  Each time you specify the
-.Fl -resource
-option, that resource becomes the "current" one.  From then on, each subsequent
-option applies to the current resource, until you
-specify the
-.Fl -resource
-option again.
-.Sh EXAMPLES
-.Bl -tag -width flag
-.It Assign two read-write delegates and display the list of read-write delegates:
-caldav_utility --resource 44234B00-5266-11DD-B22C-A07C87F02F6B --add-write-delegate 98248B00-5266-11DD-B22C-A07C87F02F6B --add-write-delegate 39838B00-5266-11DD-B22C-A07C87F02F6B --list-write-delegates
-.It Turn on auto-scheduling for a resource, and confirm the setting:
-caldav_utility --resource 44234B00-5266-11DD-B22C-A07C87F02F6B --set-auto-schedule True --get-auto-schedule
-.It Turn off auto-scheduling for multiple resources:
-caldav_utility --resource 44234B00-5266-11DD-B22C-A07C87F02F6B --set-auto-schedule False --resource 98344B00-5266-11DD-B22C-A07C87F02F6B --set-auto-schedule False
-.El
-.Sh FILES
-.Bl -tag -width flag
-.It /etc/caldavd/caldavd.plist
-The Calendar Server configuration file.
-.It /Library/CalendarServer/Data/calendaruserproxy.sqlite
-The server's proxy database, used to keep track of which principals have read-only and read-write delegate access to other principals/resources.
-.It /Library/CalendarServer/Data/resourceinfo.sqlite
-The server's resource info database, used to store additional resource information such as auto-schedule settings.
-.El
-.Sh SEE ALSO
-.Xr caldavd 8

Copied: CalendarServer/trunk/doc/calendarserver_export.8 (from rev 4181, CalendarServer/trunk/doc/caldav_export.8)
===================================================================
--- CalendarServer/trunk/doc/calendarserver_export.8	                        (rev 0)
+++ CalendarServer/trunk/doc/calendarserver_export.8	2009-05-07 21:12:08 UTC (rev 4205)
@@ -0,0 +1,75 @@
+.\"
+.\" Copyright (c) 2006-2008 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.
+.\"
+.\" The following requests are required for all man pages.
+.Dd November 6, 2008
+.Dt CALENDARSERVER_EXPORT 8
+.Os
+.Sh NAME
+.Nm calendarserver_export
+.Nd Darwin Calendar Server Export Tool
+.Sh SYNOPSIS
+.Nm
+.Op Fl f Ar config_file
+.Op Fl o Ar output_file
+.Op Fl c Ar collection
+.Op Fl H Ar home
+.Op Fl r Ar record
+.Op Fl u Ar user
+.Sh DESCRIPTION
+.Nm
+is a tool that generates a single iCalendar file containing all of the
+iCalendar components found from all specifies input sources, providing
+server administrators a means by which to export data from the Darwin
+Calandar Server into a format that can be viewed and/or manipulated by
+other tools.  Multiple input sources may be specified; the resulting
+iCalendar data will contain the combined data from all sources.
+.Sh OPTIONS
+.Bl -tag -width flag
+.It Fl h, -help
+Displays usage information
+.It Fl f, -config Ar FILE
+Use the Calendar Server configuration specified in the given file.
+.It Fl o, -output Ar FILE
+Write resulting iCalendar data to the given file.
+.It Fl c, -collection Ar DIRECTORY
+Read iCalendar objects from the calendar collection at the given path.
+.It Fl h, -home Ar DIRECTORY
+Read iCalendar objects from all calendar collections within the
+calendar home at the given path.
+.It Fl r, -record Ar TYPE:NAME
+Read iCalendar objects from all calendar collections within the
+calendar home for the directory record of the given type with the
+given name.
+.It Fl u, -user Ar NAME
+Read iCalendar objects from all calendar collections within the
+calendar home for the directory user with the given name.  This is
+shorthand for
+.Fl r Ar user:NAME .
+.El
+.Sh FILES
+.Bl -tag -width flag
+.It /etc/caldavd/caldavd.plist
+The Calendar Server configuration file.
+.It /Library/CalendarServer/Documents
+The server's document root, which is the used as the backing store for
+the HTTP resources on the server.
+.El
+.Sh SEE ALSO
+.Xr caldavd 8
+.Sh STANDARDS
+The iCalendar data generated by
+.Nm
+is expected to comply with RFC 2445 (iCalendar).

Copied: CalendarServer/trunk/doc/calendarserver_manage_principals.8 (from rev 4181, CalendarServer/trunk/doc/caldav_utility.8)
===================================================================
--- CalendarServer/trunk/doc/calendarserver_manage_principals.8	                        (rev 0)
+++ CalendarServer/trunk/doc/calendarserver_manage_principals.8	2009-05-07 21:12:08 UTC (rev 4205)
@@ -0,0 +1,109 @@
+.\"
+.\" Copyright (c) 2006-2008 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.
+.\"
+.\" The following requests are required for all man pages.
+.Dd April 24, 2009
+.Dt CALENDARSERVER_MANAGE_PRINCIPALS 8
+.Os
+.Sh NAME
+.Nm calendarserver_manage_principals
+.Nd Darwin Calendar Server Resource Utility
+.Sh SYNOPSIS
+.Nm
+.Op Fl -config Ar config_file
+.Op Fl -resource Ar guid
+.Op Fl -search Ar search-term
+.Op Fl -read-property Ar dav_property
+.Op Fl -list-read-delegates
+.Op Fl -list-write-delegates
+.Op Fl -add-read-delegate Ar guid
+.Op Fl -add-write-delegate Ar guid
+.Op Fl -remove-delegate Ar guid
+.Op Fl -set-auto-schedule Ar True|False
+.Op Fl -get-auto-schedule
+.Sh DESCRIPTION
+.Nm
+is a tool for manipulating delegate assignments for resources and
+locations, as well as specifying whether they auto-accept scheduling
+invitations.  It must be run as root on a host with a running
+calendar server.  On the command line you first select a resource
+to use (via the
+.Fl -resource
+argument), and follow that with one or
+more commands.
+.Sh OPTIONS
+.Bl -tag -width flag
+.It Fl h, -help
+Displays usage information
+.It Fl f, -config Ar FILE
+Use the Calendar Server configuration specified in the given file.  Defaults to /etc/caldavd/caldavd.plist.
+.It Fl -resource Ar guid
+Specifies the resource the following operations should be applied to.
+.It Fl s, -search Ar search_term
+Search for records matching search_term.
+.It Fl -read-property Ar dav_property
+Prints the value of the dav_property on the current resource.  The format of
+the dav_property is "namespace#property".  Examples:
+"DAV:#alternate-URI-set" or "http://calendarserver.org/ns/#record-type".
+.It Fl -list-read-delegates
+Prints the list of principals that have read-only delegate access for the current resource.
+.It Fl -list-write-delegates
+Prints the list of principals that have read-write delegate access for the current resource.
+.It Fl -add-read-delegate Ar guid
+Adds a principal to the group of principals which have read-only delegate access for the current resource.  Adding a principal as a read-only delegate removes read-write access, if read-write access had previously been granted.
+.It Fl -add-write-delegate Ar guid
+Adds a principal to the group of principals which have read-write delegate access for the current resource.
+.It Fl -remove-delegate Ar guid
+Strips a principal of delegate access for the current resource.
+.It Fl -set-auto-schedule Ar True|False
+Setting auto-schedule to True will cause the current resource to automatically
+accept any scheduling invitations.  A False value means it's up to one of the
+read-write delegates for the resource to accept/decline invitations.
+.It Fl -get-auto-schedule
+Prints the current auto-schedule state of the current resource.
+.El
+.Sh USAGE
+.Nm
+processes the command line options in order, allowing you to chain multiple
+operations.  Each time you specify the
+.Fl -resource
+option, that resource becomes the "current" one.  From then on, each subsequent
+option applies to the current resource, until you
+specify the
+.Fl -resource
+option again.
+.Sh EXAMPLES
+.Bl -tag -width flag
+.It Assign two read-write delegates and display the list of read-write delegates:
+.Nm
+--resource 44234B00-5266-11DD-B22C-A07C87F02F6B --add-write-delegate 98248B00-5266-11DD-B22C-A07C87F02F6B --add-write-delegate 39838B00-5266-11DD-B22C-A07C87F02F6B --list-write-delegates
+.It Turn on auto-scheduling for a resource, and confirm the setting:
+.Nm
+--resource 44234B00-5266-11DD-B22C-A07C87F02F6B --set-auto-schedule True --get-auto-schedule
+.It Turn off auto-scheduling for multiple resources:
+.Nm
+--resource 44234B00-5266-11DD-B22C-A07C87F02F6B --set-auto-schedule False --resource 98344B00-5266-11DD-B22C-A07C87F02F6B --set-auto-schedule False
+.El
+.Sh FILES
+.Bl -tag -width flag
+.It /etc/caldavd/caldavd.plist
+The Calendar Server configuration file.
+.It /Library/CalendarServer/Data/calendaruserproxy.sqlite
+The server's proxy database, used to keep track of which principals have read-only and read-write delegate access to other principals/resources.
+.It /Library/CalendarServer/Data/resourceinfo.sqlite
+The server's resource info database, used to store additional resource information such as auto-schedule settings.
+.El
+.Sh SEE ALSO
+.Xr caldavd 8

Modified: CalendarServer/trunk/setup.py
===================================================================
--- CalendarServer/trunk/setup.py	2009-05-07 20:30:26 UTC (rev 4204)
+++ CalendarServer/trunk/setup.py	2009-05-07 21:12:08 UTC (rev 4205)
@@ -105,7 +105,11 @@
                            "images/*/*.jpg",
                          ],
                        },
-    scripts          = [ "bin/caldavd", "bin/caladmin", "bin/caldav_export", "bin/caldav_utility" ],
+    scripts          = [
+                         "bin/caldavd",
+                         "bin/calendarserver_export",
+                         "bin/calendarserver_manage_principals"
+                       ],
     data_files       = [ ("caldavd", ["conf/caldavd.plist"]) ],
     ext_modules      = extensions,
     py_modules       = ["kqreactor", "memcacheclient"],

Modified: CalendarServer/trunk/support/Makefile.Apple
===================================================================
--- CalendarServer/trunk/support/Makefile.Apple	2009-05-07 20:30:26 UTC (rev 4204)
+++ CalendarServer/trunk/support/Makefile.Apple	2009-05-07 21:12:08 UTC (rev 4205)
@@ -77,18 +77,18 @@
 	          $(PY_INSTALL_FLAGS)                                                      \
 	          --install-scripts="$(USRSBINDIR)"                                        \
 	          --install-data="$(ETCDIR)"
-	$(_v) cd $(BuildDirectory)/PyKerberos            && $(Environment) $(PYTHON) setup.py install $(PY_INSTALL_FLAGS)
-	$(_v) cd $(BuildDirectory)/PyOpenDirectory       && $(Environment) $(PYTHON) setup.py install $(PY_INSTALL_FLAGS)
-	$(_v) cd $(BuildDirectory)/pydirector-1.0.0      && $(Environment) $(PYTHON) setup.py install $(PY_INSTALL_FLAGS)
-	$(_v) cd $(BuildDirectory)/PyXML-0.8.4           && $(Environment) $(PYTHON) setup.py install $(PY_INSTALL_FLAGS)
-	$(_v) cd $(BuildDirectory)/vobject               && $(Environment) $(PYTHON) setup.py install $(PY_INSTALL_FLAGS)
+	$(_v) cd $(BuildDirectory)/PyKerberos       && $(Environment) $(PYTHON) setup.py install $(PY_INSTALL_FLAGS)
+	$(_v) cd $(BuildDirectory)/PyOpenDirectory  && $(Environment) $(PYTHON) setup.py install $(PY_INSTALL_FLAGS)
+	$(_v) cd $(BuildDirectory)/pydirector-1.0.0 && $(Environment) $(PYTHON) setup.py install $(PY_INSTALL_FLAGS)
+	$(_v) cd $(BuildDirectory)/PyXML-0.8.4      && $(Environment) $(PYTHON) setup.py install $(PY_INSTALL_FLAGS)
+	$(_v) cd $(BuildDirectory)/vobject          && $(Environment) $(PYTHON) setup.py install $(PY_INSTALL_FLAGS)
 	$(_v) cd $(BuildDirectory)/Twisted && $(TwistedSubEnvironment) $(PYTHON) twisted/runner/topfiles/setup.py install $(PY_INSTALL_FLAGS)
 	$(_v) cd $(BuildDirectory)/Twisted && $(TwistedSubEnvironment) $(PYTHON) twisted/mail/topfiles/setup.py   install $(PY_INSTALL_FLAGS)
 	$(_v) cd $(BuildDirectory)/Twisted && $(TwistedSubEnvironment) $(PYTHON) twisted/web/topfiles/setup.py    install $(PY_INSTALL_FLAGS)
 	$(_v) cd $(BuildDirectory)/Twisted && $(TwistedSubEnvironment) $(PYTHON) twisted/web2/topfiles/setup.py   install $(PY_INSTALL_FLAGS)
 	$(_v) cd $(BuildDirectory)/Twisted && $(TwistedSubEnvironment) $(PYTHON) twisted/words/topfiles/setup.py  install $(PY_INSTALL_FLAGS)
 	$(_v) for so in $$(find "$(DSTROOT)$(PY_HOME)/lib" -type f -name '*.so'); do $(STRIP) -Sx "$${so}"; done
-	$(_v) echo "Removing plugins:"
+	@echo "Removing plugins:"
 	$(_v) find "$(DSTROOT)$(PY_HOME)/lib/python/twisted/plugins/" -type f ! -name 'caldav.*' ! -name 'twisted_reactors.*' ! -name 'twisted_trial.*' ! -name '__init__.*' ! -name 'kqueuereactor.*' -print -exec rm '{}' ';'
 	$(_v) rm -fr "$(DSTROOT)$(PY_HOME)/lib/python/twisted/python/zsh"
 	$(_v) rm -f  "$(DSTROOT)$(PY_HOME)/lib/python/twisted/python/zshcomp.py"
@@ -100,25 +100,29 @@
 	$(_v) for f in $$(find "$(DSTROOT)$(ETCDIR)" -type f ! -name '*.default'); do cp "$${f}" "$${f}.default"; done
 
 install::
+	@echo "Installing manual pages..."
 	$(_v) $(INSTALL_DIRECTORY) "$(DSTROOT)$(MANDIR)/man8"
-	$(_v) $(INSTALL_FILE) "$(Sources)/doc/caldavd.8" "$(DSTROOT)$(MANDIR)/man8"
-	$(_v) $(INSTALL_FILE) "$(Sources)/doc/caldav_export.8" "$(DSTROOT)$(MANDIR)/man8"
-	$(_v) $(INSTALL_FILE) "$(Sources)/doc/caladmin.8" "$(DSTROOT)$(MANDIR)/man8"
-	$(_v) $(INSTALL_FILE) "$(Sources)/doc/caldav_utility.8" "$(DSTROOT)$(MANDIR)/man8"
+	$(_v) $(INSTALL_FILE) "$(Sources)/doc/caldavd.8"                          "$(DSTROOT)$(MANDIR)/man8"
+	$(_v) $(INSTALL_FILE) "$(Sources)/doc/calendarserver_export.8"            "$(DSTROOT)$(MANDIR)/man8"
+	$(_v) $(INSTALL_FILE) "$(Sources)/doc/calendarserver_manage_principals.8" "$(DSTROOT)$(MANDIR)/man8"
 	$(_v) gzip -9 -f "$(DSTROOT)$(MANDIR)/man8/"*.[0-9]
+	@echo "Installing launchd config..."
 	$(_v) $(INSTALL_DIRECTORY) "$(DSTROOT)$(NSLOCALDIR)/$(NSLIBRARYSUBDIR)/$(Project)"
 	$(_v) $(INSTALL_DIRECTORY) -m 0755 "$(DSTROOT)$(VARDIR)/log/caldavd"
 	$(_v) $(INSTALL_DIRECTORY) "$(DSTROOT)$(NSLIBRARYDIR)/LaunchDaemons"
 	$(_v) $(INSTALL_FILE) "$(Sources)/contrib/launchd/calendarserver.plist" "$(DSTROOT)$(NSLIBRARYDIR)/LaunchDaemons/org.calendarserver.calendarserver.plist"
+	@echo "Installing migration config..."
 	$(_v) $(INSTALL_DIRECTORY) "$(DSTROOT)/System/Library/ServerSetup/MigrationExtras"
 	$(_v) $(INSTALL_FILE) "$(Sources)/contrib/migration/59_calendarmigrator.py" "$(DSTROOT)/System/Library/ServerSetup/MigrationExtras/59_calendarmigrator.py"
 	$(_v) chmod ugo+x "$(DSTROOT)/System/Library/ServerSetup/MigrationExtras/59_calendarmigrator.py"
+	@echo "Installing backup config..."
 	$(_v) $(INSTALL_DIRECTORY) "$(DSTROOT)$(ETCDIR)/server_backup/"
 	$(_v) $(INSTALL_DIRECTORY) "$(DSTROOT)$(LIBEXECDIR)/server_backup/"
 	$(_v) $(INSTALL_FILE) "$(Sources)/contrib/SBS/conf/85-calendarServer.plist" "$(DSTROOT)$(ETCDIR)/server_backup/"
 	$(_v) $(INSTALL_FILE) "$(Sources)/contrib/SBS/bin/calendarServer_restore" "$(DSTROOT)$(LIBEXECDIR)/server_backup/"
 
 install::
+	@echo "Installing CalDAVTester package..."
 	$(_v) $(INSTALL_DIRECTORY) "$(DSTROOT)/AppleInternal/ServerTools"
 	$(_v) $(INSTALL_FILE) "$(Sources)/CalDAVTester.tgz" "$(DSTROOT)/AppleInternal/ServerTools/CalDAVTester.tgz"
 
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20090507/aa2a53ab/attachment-0001.html>


More information about the calendarserver-changes mailing list