[CalendarServer-changes] [772] CalendarServer/trunk

source_changes at macosforge.org source_changes at macosforge.org
Fri Dec 8 14:02:43 PST 2006


Revision: 772
          http://trac.macosforge.org/projects/calendarserver/changeset/772
Author:   dreid at apple.com
Date:     2006-12-08 14:02:43 -0800 (Fri, 08 Dec 2006)

Log Message:
-----------
merge caldavd-twistd-plugin-2

Modified Paths:
--------------
    CalendarServer/trunk/bin/caldavd
    CalendarServer/trunk/conf/caldavd-test.plist
    CalendarServer/trunk/conf/caldavd.plist
    CalendarServer/trunk/run
    CalendarServer/trunk/setup.py
    CalendarServer/trunk/twistedcaldav/directory/calendar.py
    CalendarServer/trunk/twistedcaldav/root.py
    CalendarServer/trunk/twistedcaldav/static.py

Added Paths:
-----------
    CalendarServer/trunk/twisted/
    CalendarServer/trunk/twisted/plugins/
    CalendarServer/trunk/twisted/plugins/caldav.py
    CalendarServer/trunk/twistedcaldav/config.py
    CalendarServer/trunk/twistedcaldav/tap.py
    CalendarServer/trunk/twistedcaldav/test/test_config.py

Removed Paths:
-------------
    CalendarServer/trunk/twisted/plugins/
    CalendarServer/trunk/twisted/plugins/caldav.py
    CalendarServer/trunk/twistedcaldav/caldavd.py
    CalendarServer/trunk/twistedcaldav/repository.py

Modified: CalendarServer/trunk/bin/caldavd
===================================================================
--- CalendarServer/trunk/bin/caldavd	2006-12-08 22:00:47 UTC (rev 771)
+++ CalendarServer/trunk/bin/caldavd	2006-12-08 22:02:43 UTC (rev 772)
@@ -1,4 +1,4 @@
-#!/usr/bin/env python
+#!/bin/sh
 
 ##
 # Copyright (c) 2005-2006 Apple Computer, Inc. All rights reserved.
@@ -15,16 +15,56 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 #
-# DRI: Cyrus Daboo, cdaboo at apple.com
+# DRI: David Reid, dreid at apple.com
 ##
 
+daemonize="";
+username="";
+groupname="";
+configfile="";
+twistdpath="$(type -p twistd)";
 
-if __name__ == "__main__":     
-    from twistedcaldav.caldavd import caldavd
+python="$(type -p python2.5)";
 
-    import sys
+if [ "$?" != "0" ]; then
+    python="$(type -p python2.4)";
+fi;
 
-    try:
-        caldavd().run()
-    except Exception, e:
-        sys.exit(str(e))
+usage ()
+{
+    program="$(basename "$0")";
+    
+    if [ "${1--}" != "-" ]; then echo "${1}"; echo; fi;
+
+    echo "Usage: ${program} [-hX] [-u username] [-g groupname] [-T twistd] [-f caldavd.plist]";
+    echo "Options:";
+    echo "        -h Print this help and exit";
+    echo "        -X Do not daemonize";
+    echo "        -u Username to run as";
+    echo "        -g Group to run as";
+    echo "        -f Configuration file to read";
+    echo "        -T Path to twistd binary";
+    
+    if [ "${1-}" == "-" ]; then return 0; fi;
+    exit 64;
+}
+
+while getopts 'hXu:g:f:T:' option; do
+    case "${option}" in
+        '?') usage; ;;
+        'h') usage -; exit 0; ;;
+        'X') daemonize='-n'; ;;
+        'f') configfile="-f ${OPTARG}"; ;;
+        'T') twistdpath="${OPTARG}"; ;;
+        'u') username="-u ${OPTARG}"; ;;
+        'g') grouname="-g ${OPTARG}"; ;;
+    esac;
+done;
+
+shift $((${OPTIND} - 1));
+
+if [ $# != 0 ]; then usage "Unrecognized arguments:" "$@"; fi;
+
+exec "${python}" "${twistdpath}" \
+    "${daemonize}" ${username} ${groupname} caldav ${configfile};
+

Modified: CalendarServer/trunk/conf/caldavd-test.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd-test.plist	2006-12-08 22:00:47 UTC (rev 771)
+++ CalendarServer/trunk/conf/caldavd-test.plist	2006-12-08 22:02:43 UTC (rev 772)
@@ -51,7 +51,7 @@
   <string>server.log</string>
 
   <key>ErrorLogFile</key>
-  <string>error.log</string>
+  <string>-</string>
 
   <key>ServerStatsFile</key>
   <string>stats.plist</string>

Modified: CalendarServer/trunk/conf/caldavd.plist
===================================================================
--- CalendarServer/trunk/conf/caldavd.plist	2006-12-08 22:00:47 UTC (rev 771)
+++ CalendarServer/trunk/conf/caldavd.plist	2006-12-08 22:02:43 UTC (rev 772)
@@ -105,5 +105,15 @@
   <key>SACLEnable</key>
   <true/>
 
+  <key>AuthSchemes</key>
+  <array>
+    <string>Basic</string>
+  </array>
+
+  <key>AdminPrincipals</key>
+  <array>
+    <string>/principals/users/admin</string>
+  </array>
+
 </dict>
 </plist>

Modified: CalendarServer/trunk/run
===================================================================
--- CalendarServer/trunk/run	2006-12-08 22:00:47 UTC (rev 771)
+++ CalendarServer/trunk/run	2006-12-08 22:02:43 UTC (rev 772)
@@ -176,10 +176,9 @@
     fi;
 
     cd "${wd}";
-    exec "${python}" "${caldav}/bin/caldavd" ${daemonize} \
-        -f "${config}"                                    \
-        -T "${twisted}/bin/twistd"                        \
-        start;
+    exec /bin/sh "${caldav}/bin/caldavd" ${daemonize} \
+        -f "${config}"                                \
+        -T "${twisted}/bin/twistd";                    
     cd /;
   fi;
 }

Modified: CalendarServer/trunk/setup.py
===================================================================
--- CalendarServer/trunk/setup.py	2006-12-08 22:00:47 UTC (rev 771)
+++ CalendarServer/trunk/setup.py	2006-12-08 22:02:43 UTC (rev 772)
@@ -90,7 +90,8 @@
     author_email     = None,
     license          = None,
     platforms        = [ "all" ],
-    packages         = [ "twistedcaldav", "twistedcaldav.directory", "twistedcaldav.method", "twistedcaldav.query" ],
+    packages         = [ "twistedcaldav", "twistedcaldav.directory", "twistedcaldav.method", "twistedcaldav.query"],
+    package_data     = { "twisted": ["plugins/caldav.py"] },
     scripts          = [ "bin/caldavd" ],
     data_files       = data_files
 )

Copied: CalendarServer/trunk/twisted (from rev 771, CalendarServer/branches/caldavd-twistd-plugin-2/twisted)

Copied: CalendarServer/trunk/twisted/plugins (from rev 771, CalendarServer/branches/caldavd-twistd-plugin-2/twisted/plugins)

Deleted: CalendarServer/trunk/twisted/plugins/caldav.py
===================================================================
--- CalendarServer/branches/caldavd-twistd-plugin-2/twisted/plugins/caldav.py	2006-12-08 22:00:47 UTC (rev 771)
+++ CalendarServer/trunk/twisted/plugins/caldav.py	2006-12-08 22:02:43 UTC (rev 772)
@@ -1,3 +0,0 @@
-from twistedcaldav import tap
-
-TwistedCalDAV = tap.CaldavServiceMaker()

Copied: CalendarServer/trunk/twisted/plugins/caldav.py (from rev 771, CalendarServer/branches/caldavd-twistd-plugin-2/twisted/plugins/caldav.py)
===================================================================
--- CalendarServer/trunk/twisted/plugins/caldav.py	                        (rev 0)
+++ CalendarServer/trunk/twisted/plugins/caldav.py	2006-12-08 22:02:43 UTC (rev 772)
@@ -0,0 +1,3 @@
+from twistedcaldav import tap
+
+TwistedCalDAV = tap.CaldavServiceMaker()

Deleted: CalendarServer/trunk/twistedcaldav/caldavd.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/caldavd.py	2006-12-08 22:00:47 UTC (rev 771)
+++ CalendarServer/trunk/twistedcaldav/caldavd.py	2006-12-08 22:02:43 UTC (rev 772)
@@ -1,409 +0,0 @@
-#!/usr/bin/env python
-
-##
-# Copyright (c) 2005-2006 Apple Computer, 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.
-#
-# DRI: Cyrus Daboo, cdaboo at apple.com
-##
-
-import sys
-import os
-import getopt
-import signal
-from tempfile import mkstemp
-
-try:
-    #
-    # plistlib is only included in Mac OS distributions of Python.
-    # This may change in Python 2.6, see:
-    #   https://sourceforge.net/tracker/?func=detail&atid=105470&aid=1555501&group_id=5470
-    #
-    from plistlib import readPlist
-except ImportError:
-    from twistedcaldav.py.plistlib import readPlist
-
-sys.path.insert(0, "/usr/share/caldavd/lib/python")
-
-"""
-Parse the command line and read in a configuration file and then launch the server.
-"""
-
-DEFAULTS = {
-    'DirectoryService': {'params': {'node': '/Search'},
-                         'type': 'OpenDirectoryService'},
-    'DocumentRoot': '/Library/CalendarServer/Documents',
-    'DropBoxEnabled': True,
-    'DropBoxInheritedACLs': True,
-    'ErrorLogFile': '/var/log/caldavd/error.log',
-    'ManholePort': 0,
-    'MaximumAttachmentSizeBytes': 1048576,
-    'NotificationsEnabled': False,
-    'PIDFile': '/var/run/caldavd.pid',
-    'Port': 8008,
-    'Repository': '/etc/caldavd/repository.xml',
-    'RunStandalone': True,
-    'SSLCertificate': '/etc/certificates/Default.crt',
-    'SSLEnable': False,
-    'SSLOnly': False,
-    'SSLPort': 8443,
-    'SSLPrivateKey': '/etc/certificates/Default.key',
-    'ServerLogFile': '/var/log/caldavd/server.log',
-    'ServerStatsFile': '/Library/CalendarServer/Documents/stats.plist',
-    'UserQuotaBytes': 104857600,
-    'Verbose': False,
-    'twistdLocation': '/usr/share/caldavd/bin/twistd',
-    'SACLEnable': True,
-    }
-
-# FIXME: This doesn't actually work because the webserver runs in a different
-# python process from the commandline util caldavd that actually parses the 
-# plists the twistd plugin will fix this.
-CONFIG = DEFAULTS.copy()
-
-
-class caldavd(object):
-    """
-    Runs the caldav server.
-    """
-    
-    def __init__(self):
-        # Option defaults
-        self.plistfile = "/etc/caldavd/caldavd.plist"
-
-        self.config = CONFIG
-
-        self.action = None
-    
-    def printit(self):
-        """
-        Print out details about the current configuration.
-        """
-
-        print "Current Configuration"
-        print ""
-        print "Configuration File:               %s" % (self.plistfile,)
-        print ""
-        print "Run as daemon:                    %s" % (self.config['RunStandalone'],)
-        print "Document Root:                    %s" % (self.config['DocumentRoot'],)
-        print "Repository Configuration:         %s" % (self.config['Repository'],)
-        print "Non-ssl Port:                     %s" % (self.config['Port'],)
-        print "Use SSL:                          %s" % (self.config['SSLEnable'],)
-        print "SSL Port:                         %s" % (self.config['SSLPort'],)
-        print "Only Use SSL:                     %s" % (self.config['SSLOnly'],)
-        print "SSL Private Key File:             %s" % (self.config['SSLPrivateKey'],)
-        print "SSL Certificate File:             %s" % (self.config['SSLCertificate'],)
-        print "Directory Service:                %s" % (self.config['DirectoryService']["type"],)
-        print "Directory Service Parameters:     %r" % (self.config['DirectoryService']["params"],)
-        print "Drop Box Enabled:                 %s" % (self.config['DropBoxEnabled'],)
-        print "Drop Box ACLs are Inherited       %s" % (self.config['DropBoxInheritedACLs'],)
-        print "Notifications Enabled:            %s" % (self.config['NotificationsEnabled'],)
-        print "Server Log File:                  %s" % (self.config['ServerLogFile'],)
-        print "Error Log File:                   %s" % (self.config['ErrorLogFile'],)
-        print "PID File:                         %s" % (self.config['PIDFile'],)
-        print "twistd Location:                  %s" % (self.config['twistdLocation'],)
-        print "Maximum Calendar Resource Size:   %d bytes" % (self.config['MaximumAttachmentSizeBytes'],)
-        print "Global per-user quota limit:      %d bytes" % (self.config['UserQuotaBytes'],)
-
-    def run(self):
-        """
-        Run the caldavd server using the provided options and configuration.
-
-        @raise: C:{ValueError} if options or configuration are wrong.
-        """
-
-        # Parse command line options and config file
-        self.commandLine()
-        if self.action is None:
-            return
-        
-        # Dispatch action
-        {"start":   self.start,
-         "stop":    self.stop,
-         "restart": self.restart,
-         "debug":   self.debug,  }[self.action]()
-
-    def start(self):
-        """
-        Start the caldavd server.
-        """
-        
-        print "Starting CalDAV Server",
-        try:
-            fd, tac = mkstemp(prefix="caldav")
-            os.write(fd, self.generateTAC())
-            os.close(fd)
-        except Exception, e:
-            print "        [Failed]"
-            print "Unable to create temporary file for server configuration."
-            print e
-            sys.exit(1)
-        
-        # Create arguments for twistd
-        args = [os.path.basename(sys.executable)]
-        args.append(self.config['twistdLocation'])
-        if not self.config['RunStandalone']:
-            args.append("-n")
-        args.append("--logfile=%s" % (self.config['ErrorLogFile'],))
-        args.append("--pidfile=%s" % (self.config['PIDFile'],))
-        args.append("-y")
-        args.append(tac)
-
-        # Create environment for twistd
-        environment = dict(os.environ)
-        environment["PYTHONPATH"] = ":".join(sys.path)
-
-        # spawn the twistd python process
-        try:
-            os.spawnve(os.P_WAIT, sys.executable, args, environment)
-        except OSError, why:
-            print "        [Failed]"
-            print "Error: %s" % (why[1],)
-        
-        # Get rid of temp file
-        try:
-            os.unlink(tac)
-        except:
-            pass
-        print "        [Done]"
-    
-    def stop(self):
-        """
-        Stop the caldavd server.
-        """
-        
-        if os.path.exists(self.config['PIDFile']):
-            try:
-                pid = int(open(self.config['PIDFile']).read())
-            except ValueError:
-                sys.exit("Pidfile %s contains non-numeric value" % self.config['PIDFile'])
-            try:
-                print "Stopping CalDAV Server",
-                os.kill(pid, signal.SIGTERM)
-                print "        [Done]"
-            except OSError, why:
-                print "        [Failed]"
-                print "Error: %s" % (why[1],)
-        else:
-            print "CalDAV server is not running"
-    
-    def restart(self):
-        """
-        Restart the caldavd server.
-        """
-        self.stop()
-        self.start()
-        
-    def debug(self):
-        """
-        Debug the caldavd server. This is the same as starting it except we do not
-        spawn a seperate process - we run twistd directly so a debugger stays 'attached'.
-        """
-        
-        print "Starting CalDAV Server",
-        try:
-            fd, tac = mkstemp(prefix="caldav")
-            os.write(fd, self.generateTAC())
-            os.close(fd)
-        except Exception, e:
-            print "        [Failed]"
-            print "Unable to create temporary file for server configuration."
-            print e
-            sys.exit(1)
-        
-        # Create arguments for twistd
-        args = []
-        args.append(self.config['twistdLocation'])
-        if not self.config['RunStandalone']:
-            args.append("-n")
-        args.append("--logfile=%s" % (self.config['ErrorLogFile'],))
-        args.append("--pidfile=%s" % (self.config['PIDFile'],))
-        args.append("-y")
-        args.append(tac)
-
-        # Create environment for twistd
-        environment = dict(os.environ)
-        environment["PYTHONPATH"] = ":".join(sys.path)
-
-        # run the twistd python process directly
-        try:
-            sys.argv = args
-            os.environ = environment
-            from twisted.scripts.twistd import run
-            run()
-        except OSError, why:
-            print "        [Failed]"
-            print "Error: %s" % (why[1],)
-        
-        # Get rid of temp file
-        try:
-            os.unlink(tac)
-        except:
-            pass
-        print "        [Done]"
-    
-    def commandLine(self):
-        """
-        Parse the command line options into the config object.
-        
-        @return: the C{str} for the requested action, or C{None} when
-            immediate exit is called for.
-        @raise: C{ValueError} when a problem occurs with the options.
-        """
-        options, args = getopt.getopt(sys.argv[1:], "hvf:XT:p")
-        
-        # Process the plist file first, then the options, so that command line
-        # options get to override plist options
-        pls = [p for p in options if p[0] == "-f"]
-        if len(pls) == 1:
-            self.plistfile = pls[0][1]
-        if not os.path.exists(self.plistfile):
-            print "Configuration file does not exist: %s" % (self.plistfile,)
-            raise ValueError
-        self.parsePlist()
-    
-        # Parse all the options
-        do_print = False
-        for option, value in options:
-            if option == "-h":
-                self.usage()
-                return
-            elif option == "-v":
-                self.config['Verbose'] = True
-            elif option == "-f":
-                # We should have handled this already
-                pass
-            elif option == "-X":
-                self.config['RunStandalone'] = False
-            elif option == "-T":
-                self.config['twistdLocation'] = value
-            elif option == "-p":
-                do_print = True
-            else:
-                print "Unrecognized option: %s" % (option,)
-                self.usage()
-                raise ValueError
-        
-        # Print out config if requested
-        if do_print:
-            self.printit()
-            return
-    
-        # Process arguments
-        if len(args) == 0:
-            print "No arguments given. One of start, stop, restart or debug must be present."
-            self.usage()
-            raise ValueError
-        elif len(args) > 1:
-            print "Too many arguments given. Only one of start, stop, restart or debug must be present."
-            self.usage()
-            raise ValueError
-        elif args[0] not in ("start", "stop", "restart", "debug",):
-            print "Wrong arguments given: %s" % (args[0],)
-            self.usage()
-            raise ValueError
-        
-        # Verify that configuration is valid
-        if not self.validate():
-            raise ValueError
-    
-        self.action = args[0]
-    
-    def parsePlist(self):
-        print "Reading configuration file %s." % (self.plistfile,)
-
-        root = readPlist(self.plistfile)
-        
-        for k,v in root.items():
-            if k in self.config:
-                self.config[k] = v
-            else:
-                print "Unknown option: %s" % (k,)
-
-        CONFIG = self.config
-
-    def validate(self):
-        
-        result = True
-
-        if not os.path.exists(self.config['DocumentRoot']):
-            print "Document Root does not exist: %s" % (self.config['DocumentRoot'],)
-            result = False
-
-        if not os.path.exists(self.config['Repository']):
-            print "Repository File does not exist: %s" % (self.config['Repository'],)
-            result = False
-
-        if self.config['SSLEnable'] and not os.path.exists(self.config['SSLPrivateKey']):
-            print "SSL Private Key File does not exist: %s" % (self.config['SSLPrivateKey'],)
-            result = False
-
-        if self.config['SSLEnable'] and not os.path.exists(self.config['SSLCertificate']):
-            print "SSL Certificate File does not exist: %s" % (self.config['SSLCertificate'],)
-            result = False
-
-        if not self.config['SSLEnable'] and self.config['SSLOnly']:
-            self.config['SSLEnable'] = True
-
-        if not self.config['RunStandalone']:
-            self.config['ErrorLogFile'] = "-"
-
-        if not os.path.exists(self.config['twistdLocation']):
-            print "twistd does not exist: %s" % (self.config['twistdLocation'],)
-            result = False
-            
-        return result
-
-    def usage(self):
-        default = caldavd()
-        print """Usage: caldavd [options] start|stop|restart|debug
-Options:
-    -h          Print this help and exit
-    -v          Be verbose
-    -f config   Specify path to configuration file [""" + default.plistfile + """]
-    -X          Do not daemonize
-    -T twistd   Specify path to twistd [""" + default.twistd + """]
-    -p          Print current configuration and exit
-"""
-    
-    def generateTAC(self):
-        return """
-from twistedcaldav.repository import startServer
-
-application, site = startServer(
-    %(DocumentRoot)r,
-    %(Repository)r,
-    %(SSLEnable)s,
-    %(SSLPrivateKey)r,
-    %(SSLCertificate)r,
-    %(SSLOnly)s,
-    %(Port)d,
-    %(SSLPort)d,
-    %(MaximumAttachmentSizeBytes)d,
-    %(UserQuotaBytes)d,
-    %(ServerLogFile)r,
-    %(DirectoryService)r,
-    %(DropBoxEnabled)r,
-    %(DropBoxInheritedACLs)r,
-    %(NotificationsEnabled)r,
-    %(ManholePort)d,
-)
-""" % self.config
-
-
-if __name__ == "__main__":
-    try:
-        caldavd().run()
-    except Exception, e:
-        sys.exit(str(e))

Copied: CalendarServer/trunk/twistedcaldav/config.py (from rev 771, CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/config.py)
===================================================================
--- CalendarServer/trunk/twistedcaldav/config.py	                        (rev 0)
+++ CalendarServer/trunk/twistedcaldav/config.py	2006-12-08 22:02:43 UTC (rev 772)
@@ -0,0 +1,69 @@
+##
+# Copyright (c) 2005-2006 Apple Computer, 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.
+#
+# DRI: David Reid, dreid at apple.com
+##
+
+import os
+
+from twistedcaldav.py.plistlib import readPlist
+
+DEFAULTPLISTFILE = '/etc/caldavd/caldavd.plist'
+
+DEFAULTS = {
+    'CreateAccounts': False,
+    'DirectoryService': {
+        'params': {'node': '/Search'},
+        'type': 'twistedcaldav.directory.appleopendirectory.OpenDirectoryService'},
+    'DocumentRoot': '/Library/CalendarServer/Documents',
+    'DropBoxEnabled': True,
+    'DropBoxInheritedACLs': True,
+    'DropBoxName': 'dropbox',
+    'ErrorLogFile': '/var/log/caldavd/error.log',
+    'ManholePort': 0,
+    'MaximumAttachmentSizeBytes': 1048576,
+    'NotificationCollectionName': 'notifications',
+    'NotificationsEnabled': False,
+    'PIDFile': '/var/run/caldavd.pid',
+    'Port': 8008,
+    'Repository': '/etc/caldavd/repository.xml',
+    'ResetAccountACLs': False,
+    'RunStandalone': True,
+    'SSLCertificate': '/etc/certificates/Default.crt',
+    'SSLEnable': False,
+    'SSLOnly': False,
+    'SSLPort': 8443,
+    'SSLPrivateKey': '/etc/certificates/Default.key',
+    'ServerLogFile': '/var/log/caldavd/server.log',
+    'ServerStatsFile': '/Library/CalendarServer/Documents/stats.plist',
+    'UserQuotaBytes': 104857600,
+    'Verbose': False,
+    'twistdLocation': '/usr/share/caldavd/bin/twistd',
+    'SACLEnable': False,
+    'AuthSchemes': ['Basic'],
+    'AdminPrincipals': ['/principal/users/admin']
+}
+
+globs = globals()
+globs.update(DEFAULTS.copy())
+
+def parseConfig(configFile):
+    global globs
+    if os.path.exists(configFile):
+        plist = readPlist(configFile)
+        globs.update(plist)
+
+
+    

Modified: CalendarServer/trunk/twistedcaldav/directory/calendar.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/directory/calendar.py	2006-12-08 22:00:47 UTC (rev 771)
+++ CalendarServer/trunk/twistedcaldav/directory/calendar.py	2006-12-08 22:02:43 UTC (rev 772)
@@ -42,8 +42,8 @@
     """
     def __init__(self, directory, url):
         """
-        @param path: the path to the file which will back the resource.
         @param directory: an L{IDirectoryService} to provision calendars from.
+        @param url: the canonical URL for the resource.
         """
         assert url.endswith("/"), "Collection URL must end in '/'"
 

Deleted: CalendarServer/trunk/twistedcaldav/repository.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/repository.py	2006-12-08 22:00:47 UTC (rev 771)
+++ CalendarServer/trunk/twistedcaldav/repository.py	2006-12-08 22:02:43 UTC (rev 772)
@@ -1,700 +0,0 @@
-##
-# Copyright (c) 2006 Apple Computer, 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.
-#
-# DRI: Cyrus Daboo, cdaboo at apple.com
-##
-
-"""
-Initial setup of CalDAV repository resource hierarchy, together with optional
-auto-provisioning of user calendar home collections and principals, with appropriate
-properties, access control etc setup.
-"""
-
-__all__ = ["RepositoryBuilder"]
-
-import os
-
-from xml.dom.minidom import Element
-from xml.dom.minidom import Text
-import xml.dom.minidom
-
-from twisted.application.internet import SSLServer, TCPServer
-from twisted.application.service import Application, IServiceCollection, MultiService
-from twisted.cred.portal import Portal
-from twisted.internet.ssl import DefaultOpenSSLContextFactory
-from twisted.python import log
-from twisted.python.reflect import namedObject
-from twisted.web2.auth import basic, digest
-from twisted.web2.channel.http import HTTPFactory
-from twisted.web2.dav import auth, davxml
-from twisted.web2.dav.element.base import PCDATAElement
-from twisted.web2.dav.element.parser import lookupElement
-from twisted.web2.dav.resource import TwistedACLInheritable
-from twisted.web2.dav.util import joinURL
-from twisted.web2.dav.idav import IDAVPrincipalCollectionResource
-from twisted.web2.log import LogWrapperResource
-from twisted.web2.server import Site
-
-from twistedcaldav.dropbox import DropBox
-from twistedcaldav import authkerb
-from twistedcaldav.logging import RotatingFileAccessLoggingObserver
-from twistedcaldav.resource import CalDAVResource
-from twistedcaldav.static import CalendarHomeFile
-
-ELEMENT_REPOSITORY = "repository"
-
-ELEMENT_DOCROOT = "docroot"
-ELEMENT_COLLECTION = "collection"
-ELEMENT_PYTYPE = "pytype"
-ELEMENT_PARAMS = "params"
-ELEMENT_PARAM = "param"
-ELEMENT_KEY = "key"
-ELEMENT_VALUE = "value"
-ELEMENT_PROPERTIES = "properties"
-ELEMENT_PROP = "prop"
-ELEMENT_MEMBERS = "members"
-
-ELEMENT_ACL = "acl"
-ELEMENT_ACE = "ace"
-ELEMENT_PRINCIPAL = "principal"
-ELEMENT_HREF = "href"
-ELEMENT_ALL = "all"
-ELEMENT_AUTHENTICATED = "authenticated"
-ELEMENT_UNAUTHENTICATED = "unauthenticated"
-ELEMENT_GRANT = "grant"
-ELEMENT_DENY = "deny"
-ELEMENT_PRIVILEGE = "privilege"
-ELEMENT_PROTECTED = "protected"
-ELEMENT_INHERITABLE = "inheritable"
-
-ELEMENT_READ = "read"
-
-ATTRIBUTE_VALUE_YES = "yes"
-ATTRIBUTE_VALUE_NO = "no"
-
-ATTRIBUTE_NAME = "name"
-ATTRIBUTE_TAG = "tag"
-ATTRIBUTE_ACCOUNT = "account"
-ATTRIBUTE_INITIALIZE = "initialize"
-
-ATTRVALUE_NONE = "none"
-ATTRVALUE_PRINCIPALS = "principals"
-ATTRVALUE_CALENDARS = "calendars"
-
-ELEMENT_AUTHENTICATION = "authentication"
-ELEMENT_BASIC = "basic"
-ELEMENT_DIGEST = "digest"
-ELEMENT_KERBEROS = "kerberos"
-ELEMENT_REALM = "realm"
-ELEMENT_SERVICE = "service"
-
-ATTRIBUTE_ENABLE = "enable"
-ATTRIBUTE_ONLYSSL = "onlyssl"
-
-ATTRIBUTE_VALUE_DIRECTORY = "directory"
-ATTRIBUTE_VALUE_KERBEROS = "kerberos"
-
-def startServer(docroot, repo, dossl,
-                keyfile, certfile, onlyssl, port, sslport, maxsize,
-                quota, serverlogfile,
-                directoryservice,
-                dropbox, dropboxACLs,
-                notifications,
-                manhole):
-    """
-    Start the server using XML-based configuration details and supplied .plist based options.
-    """
-    
-    # Make sure SSL options make sense
-    if not dossl and onlyssl:
-        dossl = True
-    
-    # Check the file paths for validity
-    if os.path.exists(docroot):
-        print "Document root is: %s" % (docroot,)
-    else:
-        raise IOError("No such docroot: %s" % (docroot,))
-    
-    if os.path.exists(repo):
-        print "Repository configuration is: %s" % (repo,)
-    else:
-        raise IOError("No such repo: %s" % (repo,))
-    
-    if dossl:
-        if os.path.exists(keyfile):
-            print "Using SSL private key file: %s" % (keyfile,)
-        else:
-            raise IOError("SSL Private Key file does not exist: %s" % (keyfile,))
-    
-        if os.path.exists(certfile):
-            print "Using SSL certificate file: %s" % (certfile,)
-        else:
-            raise IOError("SSL Certificate file does not exist: %s" % (certfile,))
-    
-    # We need a special service for the access log
-    class Web2Service(MultiService):
-        def __init__(self, logObserver):
-            self.logObserver = logObserver
-            MultiService.__init__(self)
-    
-        def startService(self):
-            MultiService.startService(self)
-            self.logObserver.start()
-    
-        def stopService(self):
-            MultiService.stopService(self)
-            self.logObserver.stop()
-    
-    # Turn on drop box support before building the repository
-    DropBox.enable(dropbox, dropboxACLs, notifications)
-
-    dirname = directoryservice["type"]
-    dirparams = directoryservice["params"]
-    try:
-        resource_class = namedObject(dirname)
-    except:
-        log.err("Unable to locate Python class %r" % (dirname,))
-        raise
-    try:
-        directory = resource_class(**dirparams)
-    except Exception:
-        log.err("Unable to instantiate Python class %r with arguments %r" % (resource_class, dirparams))
-        raise
-
-    # Build the server
-    builder = RepositoryBuilder(docroot,
-                                maxsize=maxsize,
-                                quota=quota)
-    builder.buildFromFile(repo, directory)
-    rootresource = builder.docRoot.collection.resource
-    
-    application = Application("CalDAVServer")
-    parent      = IServiceCollection(application)
-    web2        = Web2Service(RotatingFileAccessLoggingObserver(serverlogfile))
-    web2.setServiceParent(parent)
-    parent = web2
-    
-    # Configure appropriate authentication 
-    authenticator = builder.authentication.getEnabledAuthenticator()
-    
-    portal = Portal(auth.DavRealm())
-    if authenticator.credentials == ATTRIBUTE_VALUE_DIRECTORY:
-        portal.registerChecker(directory)
-        print "Using directory-based password checker."
-    elif authenticator.credentials == ATTRIBUTE_VALUE_KERBEROS:
-        if authenticator.type == "basic":
-            portal.registerChecker(authkerb.BasicKerberosCredentialsChecker())
-        elif authenticator.type == "kerberos":
-            portal.registerChecker(authkerb.NegotiateCredentialsChecker())
-        print "Using Kerberos-based password checker."
-    
-    if authenticator.type == "basic":
-        if authenticator.credentials == ATTRIBUTE_VALUE_KERBEROS:
-            credentialFactories = (authkerb.BasicKerberosCredentialFactory(authenticator.service, authenticator.realm),)
-        else:
-            credentialFactories = (basic.BasicCredentialFactory(authenticator.realm),)
-        print "Using HTTP BASIC authentication."
-    elif authenticator.type == "digest":
-        credentialFactories = (digest.DigestCredentialFactory("md5", authenticator.realm),)
-        print "Using HTTP DIGEST authentication."
-    elif authenticator.type == "kerberos":
-        credentialFactories = (authkerb.NegotiateCredentialFactory(authenticator.service),)
-        print "Using HTTP NEGOTIATE authentication."
-    
-    loginInterfaces = (auth.IPrincipal,)
-    
-    # Build the site and server instances
-    site = Site(LogWrapperResource(auth.AuthenticationWrapper(rootresource, 
-                                                              portal,
-                                                              credentialFactories,
-                                                              loginInterfaces)))
-    
-    factory = HTTPFactory(site)
-    
-    if not onlyssl:
-        print "Starting http server"
-        TCPServer(port, factory).setServiceParent(parent)
-    
-    if dossl:
-        print "Starting https server"
-        sslContext = DefaultOpenSSLContextFactory(keyfile, certfile)
-        SSLServer(sslport, factory, sslContext).setServiceParent(parent)
-
-    if manhole:
-        print "Starting manhole on port %d" % (manhole,)
-        from twisted.manhole.telnet import ShellFactory
-        from twisted.internet import reactor
-        manhole_factory = ShellFactory()
-        reactor.listenTCP(manhole, manhole_factory)
-        manhole_factory.username = "admin"
-        manhole_factory.password = ""
-        manhole_factory.namespace["site"] = site
-        manhole_factory.namespace["portal"] = portal
-
-    return application, site
-
-class RepositoryBuilder (object):
-    """
-    Builds a repository hierarchy at a supplied document root file system path.
-    """
-    
-    def __init__(self, docroot, maxsize=None, quota=None):
-        """
-        @param docroot:    file system path to use as the root.
-        @param maxsize:    maximum size in bytes for any calendar object resource, C{int} to set size,
-            if <= 0, then no limit will be set.
-        @param quota:    maximum quota size in bytes for a user's calendar home, C{int} to set size,
-            if <= 0, then no limit will be set.
-        """
-        self.docRoot = DocRoot(docroot)
-        self.authentication = Authentication()
-        self.maxsize = maxsize
-        self.quota = quota
-        
-        if self.maxsize <= 0:
-            self.maxsized = None
-        if self.quota <= 0:
-            self.quota = None
-        
-    def buildFromFile(self, filename, directory):
-        """
-        Parse the required information from an XML file.
-        @param file: the path of the XML file to parse.
-        """
-        # Read in XML
-        fd = open(filename, "r")
-        doc = xml.dom.minidom.parse( fd )
-        fd.close()
-
-        # Verify that top-level element is correct
-        repository_node = doc._get_documentElement()
-        if repository_node._get_localName() != ELEMENT_REPOSITORY:
-            self.log("Ignoring file %r because it is not a repository builder file" % (filename,))
-            return
-        self.parseXML(repository_node)
-        
-        self.docRoot.build(directory)
-            
-        # Handle global quota value
-        CalendarHomeFile.quotaLimit = self.quota
-        CalDAVResource.sizeLimit = self.maxsize
-
-    def parseXML(self, node):
-        """
-        Parse the XML root node from the repository configuration document.
-        @param node: the L{Node} to parse.
-        """
-        for child in node._get_childNodes():
-            if child._get_localName() == ELEMENT_DOCROOT:
-                self.docRoot.parseXML(child)
-            elif child._get_localName() == ELEMENT_AUTHENTICATION:
-                self.authentication.parseXML(child)
-
-class DocRoot (object):
-    """
-    Represents the hierarchy of resource collections that form the CalDAV repository.
-    """
-    def __init__(self, docroot):
-        """
-        @param docroot: the file system path for the root of the hierarchy.
-        """
-        self.collection = None
-        self.path = docroot
-        self.principalCollections = []
-        self.accountCollection = None
-        self.initCollections = []
-        self.calendarHome = None
-        
-    def parseXML(self, node):
-        """
-        Parse the XML collection nodes from the repository configuration document.
-        @param node: the L{Node} to parse.
-        """
-        for child in node._get_childNodes():
-            if child._get_localName() == ELEMENT_COLLECTION:
-                self.collection = Collection()
-                self.collection.parseXML(child, self)
-                break
-
-    def build(self, directory):
-        """
-        Build the entire repository starting at the root resource.
-        """
-        self.collection.build(self, self.path, "/", directory)
-        
-        # Cheat        
-        self.collection.resource._principalCollections = self.principalCollections
-            
-class Collection (object):
-    """
-    Contains information about a collection in the repository.
-    """
-    def __init__(self):
-        self.name = None
-        self.pytype = None
-        self.params = {}
-        self.properties = []
-        self.acl = None
-        self.members = []
-        self.resource = None
-        self.uri = None
-
-    def parseXML(self, node, builder):
-        """
-        Parse the XML collection node from the repository configuration document.
-        @param node:    the L{Node} to parse.
-        @param builder: the L{RepositoryBuilder} in use.
-        """
-        if node.hasAttribute(ATTRIBUTE_NAME):
-            self.name = node.getAttribute(ATTRIBUTE_NAME).encode("utf-8")
-        if node.hasAttribute(ATTRIBUTE_TAG):
-            tag = node.getAttribute(ATTRIBUTE_TAG)
-            if tag == ATTRVALUE_PRINCIPALS:
-                builder.principalCollections.append(self)
-            elif tag == ATTRVALUE_CALENDARS:
-                builder.calendarHome = self
-        if node.hasAttribute(ATTRIBUTE_ACCOUNT) and node.getAttribute(ATTRIBUTE_ACCOUNT) == ATTRIBUTE_VALUE_YES:
-            builder.accountCollection = self
-        if node.hasAttribute(ATTRIBUTE_INITIALIZE) and node.getAttribute(ATTRIBUTE_INITIALIZE) == ATTRIBUTE_VALUE_YES:
-            builder.initCollections.append(self)
-        
-        for child in node._get_childNodes():
-            if child._get_localName() == ELEMENT_PYTYPE:
-                if child.firstChild is not None:
-                   self.pytype = child.firstChild.data.encode("utf-8")
-            elif child._get_localName() == ELEMENT_PARAMS:
-                self.parseParamsXML(child)
-            elif child._get_localName() == ELEMENT_PROPERTIES:
-                self.parsePropertiesXML(child)
-            elif child._get_localName() == ELEMENT_MEMBERS:
-                for member in child._get_childNodes():
-                    if member._get_localName() == ELEMENT_COLLECTION:
-                        collection = Collection()
-                        collection.parseXML(member, builder)
-                        self.members.append(collection)
-    
-    def parseParamsXML(self, node):
-        """
-        Parse the XML node for parameters for the collection.
-         @param node: the L{Node} to parse.
-        """
-        for child in node._get_childNodes():
-            if child._get_localName() == ELEMENT_PARAM:
-                self.parseParamXML(child)
-
-    def parseParamXML(self, node):
-        """
-        Parse the XML node for a parameter for the collection.
-         @param node: the L{Node} to parse.
-        """
-        key = None
-        value = None
-        for child in node._get_childNodes():
-            if child._get_localName() == ELEMENT_KEY:
-                if child.firstChild is not None:
-                   key = child.firstChild.data.encode("utf-8")
-            elif child._get_localName() == ELEMENT_VALUE:
-                if child.firstChild is not None:
-                   value = child.firstChild.data.encode("utf-8")
-
-        if (key is not None) and (value is not None):
-            self.params[key] = value
-
-    def parsePropertiesXML(self, node):
-        """
-        Parse the XML node for properties in the collection.
-        @param node: the L{Node} to parse.
-        """
-        for child in node._get_childNodes():
-            if child._get_localName() == ELEMENT_ACL:
-                self.acl = ACL()
-                self.acl.parseXML(child)
-            elif child._get_localName() == ELEMENT_PROP:
-                self.properties.append(Prop())
-                self.properties[-1].parseXML(child)
-
-    def build(self, docroot, mypath, urlroot, directory):
-        """
-        Create this collection, initialising any properties and then create any child
-        collections.
-        @param docroot: the file system path to create the collection in.
-        @param urlroot: the URI path root to create the collection resource in.
-        """
-        myurl = urlroot
-        if self.name is not None:
-            mypath = os.path.join(mypath, self.name)
-            myurl = joinURL(urlroot, self.name + "/")
-
-        if not os.path.exists(mypath):
-            os.mkdir(mypath)
-
-        try:
-            resource_class = namedObject(self.pytype)
-        except:
-            log.err("Unable to locate Python class %r" % (self.pytype,))
-            raise
-        kwargs = {}
-        argnames = resource_class.__init__.func_code.co_varnames
-        for name, value in (
-            ("path"     , mypath   ),
-            ("url"      , myurl    ),
-            ("directory", directory),
-        ):
-            if name in argnames:
-                kwargs[name] = value
-        if self.params:
-            kwargs["params"] = self.params
-        try:
-            self.resource = resource_class(**kwargs)
-        except Exception:
-            log.err("Unable to instantiate Python class %r with arguments %r" % (resource_class, kwargs))
-            raise
-
-        self.uri = myurl
-        
-        # Set properties now
-        for prop in self.properties:
-            self.resource.writeDeadProperty(prop.prop)
-
-        # Set ACL now
-        if self.acl is not None:
-            self.resource.setAccessControlList(self.acl.acl)
-        
-        for member in self.members:
-            child = member.build(docroot, mypath, myurl, directory)
-            # Only putChild if one does not already exists
-            if self.resource.putChildren.get(member.name, None) is None:
-                self.resource.putChild(member.name, child)
-
-            if IDAVPrincipalCollectionResource.providedBy(child):
-                docroot.principalCollections.append(child)
-                
-        return self.resource
-
-class Prop (object):
-    """
-    Parses a property from XML.
-    """
-    def __init__(self):
-        self.prop = None
-
-    def parseXML(self, node):
-        """
-        Parse the XML node for a property.
-        @param node: the L{Node} to parse.
-        """
-    
-        self.prop = self.toWebDAVElement(node.firstChild)
-
-    def toWebDAVElement(self, node):
-        """
-        Convert XML dom element to WebDAVElement.
-        """
-        ns = node.namespaceURI
-        name = node._get_localName()
-        children = []
-        for child in node._get_childNodes():
-            if isinstance(child, Element):
-                children.append(self.toWebDAVElement(child))
-            elif isinstance(child, Text):
-                children.append(PCDATAElement(child.data))
-    
-        propClazz = lookupElement((ns, name,))
-
-        return propClazz(*children)
-        
-class ACL (object):
-    """
-    Parses a DAV:ACL from XML.
-    """
-    def __init__(self):
-        self.acl = None
-
-    def parseXML(self, node):
-        """
-        Parse the XML node for an ACL.
-        @param node: the L{Node} to parse.
-        """
-        aces = []
-        for child in node._get_childNodes():
-            if child._get_localName() == ELEMENT_ACE:
-                aces.append(self.parseACEXML(child))
-        self.acl = davxml.ACL(*aces)
-
-    def parseACEXML(self, node):
-        """
-        Parse the XML node for an ACE.
-        @param node: the L{Node} to parse.
-        """
-        principal = None
-        grant = None
-        deny = None
-        protected = None
-        inheritable = False
-        for child in node._get_childNodes():
-            if child._get_localName() == ELEMENT_PRINCIPAL:
-                principal = self.parsePrincipalXML(child)
-            elif child._get_localName() == ELEMENT_GRANT:
-                grant = self.parseGrantDenyXML(child)
-            elif child._get_localName() == ELEMENT_DENY:
-                deny = self.parseGrantDenyXML(child)
-            elif child._get_localName() == ELEMENT_PROTECTED:
-                protected = davxml.Protected()
-            elif child._get_localName() == ELEMENT_INHERITABLE:
-                inheritable = True
-        items = []
-        if principal is not None:
-            items.append(principal)
-        if grant is not None:
-            items.append(grant)
-        if deny is not None:
-            items.append(deny)
-        if protected is not None:
-            items.append(protected)
-        if inheritable:
-            items.append(TwistedACLInheritable())
-        return davxml.ACE(*items)
-    
-    def parsePrincipalXML(self, node):
-        """
-        Parse the XML node for a Principal.
-        @param node: the L{Node} to parse.
-        """
-        item = None
-        for child in node._get_childNodes():
-            if child._get_localName() == ELEMENT_HREF:
-                if child.firstChild is not None:
-                   item = davxml.HRef.fromString(child.firstChild.data)
-                else:
-                   item = davxml.HRef.fromString("")
-            elif child._get_localName() == ELEMENT_ALL:
-                item = davxml.All()
-            elif child._get_localName() == ELEMENT_AUTHENTICATED:
-                item = davxml.Authenticated()
-            elif child._get_localName() == ELEMENT_UNAUTHENTICATED:
-                item = davxml.Unauthenticated()
-        return davxml.Principal(item)
-    
-    def parseGrantDenyXML(self, node):
-        """
-        Parse the XML node for Grant/Deny items.
-        @param node: the L{Node} to parse.
-        """
-        items = []
-        for child in node._get_childNodes():
-            if child._get_localName() == ELEMENT_PRIVILEGE:
-                for privilege in child._get_childNodes():
-                    if privilege._get_localName() == ELEMENT_ALL:
-                        items.append(davxml.All())
-                    elif privilege._get_localName() == ELEMENT_READ:
-                        items.append(davxml.Read())
-        if node._get_localName() == ELEMENT_GRANT:
-            return davxml.Grant(davxml.Privilege(*items))
-        else:
-            return davxml.Deny(davxml.Privilege(*items))
-        
-    def parseInheritedXML(self, node):
-        """
-        Parse the XML node for inherited items.
-        @param node: the L{Node} to parse.
-        """
-        item = None
-        for child in node._get_childNodes():
-            if child._get_localName() == ELEMENT_HREF:
-                if child.firstChild is not None:
-                   item = davxml.HRef.fromString(child.firstChild.data)
-                else:
-                   item = davxml.HRef.fromString("")
-        return davxml.Inherited(item)
-
-class Authentication:
-    """
-    Parses authentication information  for XML file.
-    """
-    
-    class AuthType:
-        """
-        Base class for authentication method behaviors.
-        """
-        
-        def __init__(self, type):
-            self.type = type
-            self.enabled = False
-            self.onlyssl = False
-            if type == "kerberos":
-                self.credentials = ATTRIBUTE_VALUE_KERBEROS
-            else:
-                self.credentials = ATTRIBUTE_VALUE_DIRECTORY
-            self.realm = ""
-            self.service = ""
-            
-        def parseXML(self, node):
-            if node.hasAttribute(ATTRIBUTE_ENABLE):
-                self.enabled = node.getAttribute(ATTRIBUTE_ENABLE) == ATTRIBUTE_VALUE_YES
-            if node.hasAttribute(ATTRIBUTE_ONLYSSL):
-                self.onlyssl = node.getAttribute(ATTRIBUTE_ONLYSSL) == ATTRIBUTE_VALUE_YES
-            for child in node._get_childNodes():
-                if child._get_localName() == ELEMENT_REALM:
-                    if child.firstChild is not None:
-                       self.realm = child.firstChild.data.encode("utf-8")
-                elif child._get_localName() == ELEMENT_SERVICE:
-                    if child.firstChild is not None:
-                       self.service = child.firstChild.data.encode("utf-8")
-            
-    def __init__(self):
-        self.basic = Authentication.AuthType("basic")
-        self.digest = Authentication.AuthType("digest")
-        self.kerberos = Authentication.AuthType("kerberos")
-    
-    def getEnabledAuthenticator(self):
-        if self.basic.enabled:
-            return self.basic
-        elif self.digest.enabled:
-            return self.digest
-        elif self.kerberos.enabled:
-            return self.kerberos
-        else:
-            return None
-
-    def parseXML(self, node):
-        for child in node._get_childNodes():
-            if child._get_localName() == ELEMENT_BASIC:
-                self.basic.parseXML(child)
-            elif child._get_localName() == ELEMENT_DIGEST:
-                self.digest.parseXML(child)
-            elif child._get_localName() == ELEMENT_KERBEROS:
-                self.kerberos.parseXML(child)
-        
-        # Sanity checks
-        ctr = 0
-        if self.basic.enabled:
-            ctr += 1
-        if self.digest.enabled:
-            ctr += 1
-        if self.kerberos.enabled:
-            ctr += 1
-        if ctr == 0:
-            log.msg("One authentication method must be enabled.")
-            raise ValueError, "One authentication method must be enabled."
-        elif ctr > 1:
-            log.msg("Only one authentication method allowed.")
-            raise ValueError, "Only one authentication method allowed."
-        
-        # FIXME: currently we have no way to turn off an auth mechanism based on whether SSL is in use or not,
-        # so the onlyssl attribute is meaning less for now.
-#        if self.basic.enabled and not self.basic.onlyssl:
-#            log.msg("IMPORTANT: plain text passwords are allowed without an encrypted/secure connection.")
-        if self.basic.enabled:
-            log.msg("IMPORTANT: plain text passwords are allowed without an encrypted/secure connection.")

Modified: CalendarServer/trunk/twistedcaldav/root.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/root.py	2006-12-08 22:00:47 UTC (rev 771)
+++ CalendarServer/trunk/twistedcaldav/root.py	2006-12-08 22:02:43 UTC (rev 772)
@@ -38,9 +38,9 @@
     def __init__(self, path, *args, **kwargs):
         super(RootResource, self).__init__(path, *args, **kwargs)
         
-        from twistedcaldav import caldavd
+        from twistedcaldav import config
 
-        if caldavd.CONFIG['SACLEnable'] and RootResource.CheckSACL:
+        if config.SACLEnable and RootResource.CheckSACL:
             self.useSacls = True
 
     def checkSacl(self, request):

Modified: CalendarServer/trunk/twistedcaldav/static.py
===================================================================
--- CalendarServer/trunk/twistedcaldav/static.py	2006-12-08 22:00:47 UTC (rev 771)
+++ CalendarServer/trunk/twistedcaldav/static.py	2006-12-08 22:02:43 UTC (rev 772)
@@ -437,6 +437,7 @@
         """
         @param path: the path to the file which will back the resource.
         @param directory: an L{IDirectoryService} to provision calendars from.
+        @param url: the canonical URL for the resource.
         """
         DAVFile.__init__(self, path)
         DirectoryCalendarHomeProvisioningResource.__init__(self, directory, url)

Copied: CalendarServer/trunk/twistedcaldav/tap.py (from rev 771, CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/tap.py)
===================================================================
--- CalendarServer/trunk/twistedcaldav/tap.py	                        (rev 0)
+++ CalendarServer/trunk/twistedcaldav/tap.py	2006-12-08 22:02:43 UTC (rev 772)
@@ -0,0 +1,190 @@
+##
+# Copyright (c) 2005-2006 Apple Computer, 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.
+#
+# DRI: David Reid, dreid at apple.com
+##
+
+import os
+import sys
+
+from zope.interface import implements
+
+from twisted.python.usage import Options
+from twisted.python.reflect import namedClass
+
+from twisted.application import internet, service
+from twisted.plugin import IPlugin
+
+from twisted.cred.portal import Portal
+
+from twisted.web2.dav import auth
+from twisted.web2.dav import davxml
+from twisted.web2.auth import basic
+from twisted.web2.auth import digest
+from twisted.web2.channel import http
+
+from twisted.web2.tap import Web2Service
+from twisted.web2.log import LogWrapperResource
+from twisted.web2.server import Site
+
+from twistedcaldav import config
+from twistedcaldav.logging import RotatingFileAccessLoggingObserver
+from twistedcaldav.root import RootResource
+from twistedcaldav.directory.principal import DirectoryPrincipalProvisioningResource
+from twistedcaldav.static import CalendarHomeProvisioningFile
+
+
+class CaldavOptions(Options):
+    optParameters = [
+        ["config", "f", "/etc/caldavd/caldavd.plist",
+         "Path to configuration file."]
+        ]
+
+    zsh_actions = {"config" : "_files -g '*.plist'"}
+
+    def postOptions(self):
+        if not os.path.exists(self['config']):
+            print "Config file %s not found, using defaults" % (self['config'],)
+
+        config.parseConfig(self['config'])
+
+        self.parent['logfile'] = config.ErrorLogFile
+        self.parent['pidfile'] = config.PIDFile
+
+class CaldavServiceMaker(object):
+    implements(IPlugin, service.IServiceMaker)
+
+    tapname = "caldav"
+
+    description = "The Darwin Calendar Server"
+
+    options = CaldavOptions
+
+    #
+    # default resource classes
+    #
+
+    rootResourceClass = RootResource
+    principalResourceClass = DirectoryPrincipalProvisioningResource
+    calendarResourceClass = CalendarHomeProvisioningFile
+
+    def makeService(self, options):
+        #
+        # Setup the Directory
+        #
+
+        directoryClass = namedClass(config.DirectoryService['type'])
+
+        directory = directoryClass(**config.DirectoryService['params'])
+
+        #
+        # Setup Resource hierarchy
+        #
+
+        principalCollection = self.principalResourceClass(
+            os.path.join(config.DocumentRoot, 'principals'),
+            '/principals/',
+            directory
+            )
+
+        calendarCollection = self.calendarResourceClass(
+            os.path.join(config.DocumentRoot, 'calendars'),
+            directory,
+            '/calendars/')
+        
+        root = self.rootResourceClass(config.DocumentRoot, 
+                            principalCollections=(principalCollection,)
+                            )
+
+        root.putChild('principals', principalCollection)
+        root.putChild('calendars', calendarCollection)
+
+        # Configure default ACLs on the root resource
+
+        rootACEs = [
+            davxml.ACE(
+                davxml.Principal(davxml.All()),
+                davxml.Grant(davxml.Privilege(davxml.Read()))),]
+
+        for principal in config.AdminPrincipals:
+            rootACEs.append(
+                davxml.ACE(
+                    davxml.Principal(davxml.HRef(principal)),
+                    davxml.Grant(davxml.Privilege(davxml.All()))))
+
+        root.setAccessControlList(davxml.ACL(*rootACEs))
+
+        #
+        # Configure the Site and Wrappers
+        #
+
+        credentialFactories = []
+
+        portal = Portal(auth.DavRealm())
+
+        portal.registerChecker(directory)
+
+        realm = directory.realmName or ""
+
+        # TODO: figure out the list of supported schemes from the directory
+        schemes = {'basic': basic.BasicCredentialFactory(realm),
+                   'digest': digest.DigestCredentialFactory("md5", realm),
+                   }
+
+        for scheme in config.AuthSchemes:
+            scheme = scheme.lower()
+            
+            if scheme not in schemes:
+                print "Scheme not supported: %s" % (scheme,)
+                sys.exit(1)
+            else:
+                # TODO: limit basic scheme to SSL
+                credentialFactories.append(schemes[scheme])
+                
+        authWrapper = auth.AuthenticationWrapper(
+            root,
+            portal,
+            credentialFactories,
+            (auth.IPrincipal,))
+
+        site = Site(LogWrapperResource(authWrapper))
+
+        #
+        # Configure the service
+        # 
+
+        channel = http.HTTPFactory(site)
+
+        logObserver = RotatingFileAccessLoggingObserver(config.ServerLogFile)
+        
+        service = Web2Service(logObserver)
+
+        httpService = internet.TCPServer(
+            int(config.Port),
+            channel)
+
+        httpService.setServiceParent(service)
+
+        if config.SSLEnable:
+            from twisted.internet.ssl import DefaultOpenSSLContextFactory
+            httpsService = internet.SSLServer(
+                int(config.SSLPort),
+                channel,
+                DefaultOpenSSLContextFactory(config.SSLPrivateKey,
+                                             config.SSLCertificate))
+
+            httpsService.setServiceParent(service)
+            
+        return service

Copied: CalendarServer/trunk/twistedcaldav/test/test_config.py (from rev 771, CalendarServer/branches/caldavd-twistd-plugin-2/twistedcaldav/test/test_config.py)
===================================================================
--- CalendarServer/trunk/twistedcaldav/test/test_config.py	                        (rev 0)
+++ CalendarServer/trunk/twistedcaldav/test/test_config.py	2006-12-08 22:02:43 UTC (rev 772)
@@ -0,0 +1,62 @@
+##
+# Copyright (c) 2005-2006 Apple Computer, 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.
+#
+# DRI: David Reid, dreid at apple.com
+##
+
+from twisted.trial import unittest
+
+from twistedcaldav import config
+
+testConfig = """<?xml version="1.0" encoding="UTF-8"?>
+<!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>Verbose</key>
+  <true/>
+</dict>
+</plist>
+"""
+
+class ConfigTests(unittest.TestCase):
+    def setUp(self):
+        reload(config)
+        self.testConfig = self.mktemp()
+        open(self.testConfig, 'w').write(testConfig)
+
+    def testDefaults(self):
+        for key, value in config.DEFAULTS.iteritems():
+            self.failUnless(key in config.__dict__)
+            self.assertEquals(config.__dict__[key], value)
+
+    def testParseConfig(self):
+        self.assertEquals(config.Verbose, False)
+
+        config.parseConfig(self.testConfig)
+
+        self.assertEquals(config.Verbose, True)
+    
+    def testScoping(self):
+        def getVerbose():
+            from twistedcaldav import config
+            self.assertEquals(config.Verbose, True)
+
+        self.assertEquals(config.Verbose, False)
+
+        config.parseConfig(self.testConfig)
+
+        self.assertEquals(config.Verbose, True)
+
+        getVerbose()

-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20061208/84ab9203/attachment.html


More information about the calendarserver-changes mailing list