--- calendarserver-1.2.dfsg.orig/debian/calendarserver-doc-api.docs +++ calendarserver-1.2.dfsg/debian/calendarserver-doc-api.docs @@ -0,0 +1 @@ +#doc/apidocs --- calendarserver-1.2.dfsg.orig/debian/calendarserver.manpages +++ calendarserver-1.2.dfsg/debian/calendarserver.manpages @@ -0,0 +1,2 @@ +doc/caldavd.8 +doc/caladmin.8 --- calendarserver-1.2.dfsg.orig/debian/copyright +++ calendarserver-1.2.dfsg/debian/copyright @@ -0,0 +1,41 @@ +This package was debianized by Guido Guenther on +Sun, 27 Aug 2006 19:53:15 +0200. + +It was downloaded from http://trac.calendarserver.org/browser/CalendarServer + +Upstream Author: Cyrus Daboo + +Copyright: 2006 Apple Computer, Inc. All rights reserved. + +License: + +You are free to distribute this software under the terms of the Apache License +2.0. The full text of this license can be found in the file +/usr/share/common-licenses/Apache-2.0. + +Except for bin/xattr which is: + +## +# Copyright (c) 2007 Apple Inc. +# +# This is the MIT license. This software may also be distributed under the +# same terms as Python (the PSF license). +# +# Permission is hereby granted, free of charge, to any person obtaining a +# copy of this software and associated documentation files (the "Software"), +# to deal in the Software without restriction, including without limitation +# the rights to use, copy, modify, merge, publish, distribute, sublicense, +# and/or sell copies of the Software, and to permit persons to whom the +# Software is furnished to do so, subject to the following conditions: +# +# The above copyright notice and this permission notice shall be included in +# all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS +# IN THE SOFTWARE. +## --- calendarserver-1.2.dfsg.orig/debian/calendarserver.postinst +++ calendarserver-1.2.dfsg/debian/calendarserver.postinst @@ -0,0 +1,52 @@ +#!/bin/sh +# postinst script for calendarserver +# +# see: dh_installdeb(1) + +set -e + +# summary of how this script can be called: +# * `configure' +# * `abort-upgrade' +# * `abort-remove' `in-favour' +# +# * `abort-deconfigure' `in-favour' +# `removing' +# +# for details, see http://www.debian.org/doc/debian-policy/ or +# the debian-policy package +# + +case "$1" in + configure) + if ! getent passwd caldavd >/dev/null 2>&1; then + adduser --system --home /var/spool/caldavd --no-create-home \ + --gecos "calendarserver daemon" --group --disabled-password \ + caldavd + fi + adduser caldavd ssl-cert + + for dir in spool run log; do + if ! dpkg-statoverride --list /var/$dir/caldavd >/dev/null 2>&1; then + chown caldavd: /var/$dir/caldavd + fi + done + ;; + abort-upgrade|abort-remove|abort-deconfigure) + + ;; + + *) + echo "postinst called with unknown argument \`$1'" >&2 + exit 1 + ;; +esac + +# dh_installdeb will replace this with shell code automatically +# generated by other debhelper scripts. + +#DEBHELPER# + +exit 0 + + --- calendarserver-1.2.dfsg.orig/debian/calendarserver.dirs +++ calendarserver-1.2.dfsg/debian/calendarserver.dirs @@ -0,0 +1,3 @@ +/var/log/caldavd +/var/run/caldavd +/var/spool/caldavd --- calendarserver-1.2.dfsg.orig/debian/TODO +++ calendarserver-1.2.dfsg/debian/TODO @@ -0,0 +1,2 @@ +* fix apidoc build +* push pydirector patches upstream --- calendarserver-1.2.dfsg.orig/debian/control +++ calendarserver-1.2.dfsg/debian/control @@ -0,0 +1,26 @@ +Source: calendarserver +Section: python +Priority: optional +Maintainer: Debian QA Group +Build-Depends: cdbs (>= 0.4.43), debhelper (>= 5), quilt, python-dev, python-central +Standards-Version: 3.8.0 +Vcs-Git: git://git.debian.org/git/calendarserver/calendarserver.git +Vcs-Browser: http://git.debian.org/?p=calendarserver/calendarserver.git +Homepage: http://calendarserver.org +XS-Python-Version: >= 2.4 + +Package: calendarserver +Architecture: all +Depends: ${python:Depends}, ${misc:Depends}, + python-kerberos (>= 1.0), python-pysqlite2, python-openssl, + python-vobject (>= 0.4.8), python-twisted-calendarserver (>= 0.2.0.svn19773-3), + python-dateutil (>= 1.2), + python-xattr, + ssl-cert, adduser, lsb-base (>= 3.0-10) +Suggests: python-pydirector +XB-Python-Version: ${python:Versions} +Description: Apple's Calendar Server + Apple's Calendarserver is a standalone caldav server with: + * Basic or Kerberos Authentication + * support for shared calendars + --- calendarserver-1.2.dfsg.orig/debian/calendarserver.docs +++ calendarserver-1.2.dfsg/debian/calendarserver.docs @@ -0,0 +1 @@ +README --- calendarserver-1.2.dfsg.orig/debian/changelog +++ calendarserver-1.2.dfsg/debian/changelog @@ -0,0 +1,253 @@ +calendarserver (1.2.dfsg-9) unstable; urgency=low + + [ Guido Günther ] + * [e933bae] Orphan package + * [aa801ee] use lower case http in the principals name since this is + what iCal expects. clients don't break. (Closes: #514931) - thanks + to Arthur P Prokosch for pointing this out and testing that other + * [2de5e32] We need both principals in the servers's keytab. (Closes: + #514931) + + [ Christoph Goehre ] + * [080f99a] remove package depends 'python-xml' python-xml was merged into + the python core package and removed from unstable on 16th August 2009 + + -- Guido Günther Sun, 16 May 2010 15:15:51 +0200 + +calendarserver (1.2.dfsg-8) unstable; urgency=low + + * [8b63fa5] fix basic auth via apache directoryService (Closes: + #503727) - thanks to Thomas Viehmann for the patch + * [a9f92f3] minor fix: tabs vs. spaces + + -- Guido Günther Thu, 06 Nov 2008 09:57:56 +0100 + +calendarserver (1.2.dfsg-7) experimental; urgency=low + + * [972f1c3] add more info about the name service switch backend and + warn about ldap server search limits (Closes: #499963) + * [45cc01f] add Ticket207-2.patch fixes "Events more than 356 days + from creation are ignored" (Closes: #489188) - Patch by Peter Mogensen + + -- Guido Guenther Thu, 02 Oct 2008 13:18:01 +0200 + +calendarserver (1.2.dfsg-6) unstable; urgency=low + + * [cf51d29] allow dh_installinit to start/stop the daemon + * [f2450f8] don't start calendarserver by default + * [67f428c] don't fail when trying to stop a not running daemon + * [b3386ab] bump standards version + * [da9254c] add README.source + + -- Guido Guenther Fri, 08 Aug 2008 11:58:23 +0200 + +calendarserver (1.2.dfsg-5) unstable; urgency=low + + * [b52ad1f] remove dependency on python-plistlib, it's included in included + in python2.5 and in Debian's python2.4 + + -- Guido Guenther Fri, 08 Aug 2008 10:36:43 +0200 + +calendarserver (1.2.dfsg-4) unstable; urgency=low + + * [41eff3c] nss backend: use shortname for groups and users. The groupPrefix + makes sure these don't overlap. This way we don't have to use random uids + for the calendars on disk which makes administration a lot easier. + * [1d6701b] depend on python-openssl instead of the transitional + package python-pyopenssl + * [d90a173] refer to /usr/share/common-licenses/Apache-2.0 instead of + shipping the whole license + * [1937567] update upstream URL + + -- Guido Guenther Sun, 22 Jun 2008 21:05:39 +0200 + +calendarserver (1.2.dfsg-3) unstable; urgency=low + + [ Guido Guenther ] + * upload to unstable - we no longer conflict on twisted + * [31d2b55] drop dependency on ctypes - it's already included in python2.5 + * [652da62] Mention XFS (Closes: #483987) - thanks to Peter Mann + * [29edb85] add Homepage: + * [0c5bcee] redirect stderr to /dev/null on daemon restart This is a + temporary workaround until the twisted deprecation warnings got + fixed. + + [ Noel Köthe ] + * [1c03474] xs- prefix from Vcs fields + + -- Guido Guenther Thu, 19 Jun 2008 17:05:15 +0200 + +calendarserver (1.2.dfsg-2) experimental; urgency=low + + [ Guido Guenther ] + * fix epydoc errors + * use a python-twisted-calendarserver that doesn't ship the whole twisted + + [ Noel Köthe ] + * bind the caldavd only to localhost as described in README.Debian + + -- Guido Guenther Mon, 05 May 2008 17:28:58 +0200 + +calendarserver (1.2.dfsg-1) unstable; urgency=low + + [ Guido Guenther ] + * New upstream 1.2 + * add NSS directory backend + * bump python-twisted-calendarserver dependency to one that has the patches + for 1.2 + * README.Debian: use non SSL port + + [ Noel Köthe ] + * README.Debian: + * s/sudoers.xml/sudoers.plist/ + * correcting path + * update TODO + + -- Guido Guenther Sun, 27 Apr 2008 10:36:57 +0200 + +calendarserver (1.2.dfsg~dev020221-5) unstable; urgency=low + + * first upload to unstable + * tighten dependencies and drop suggests superflous suggests + * switch to Python 2.5 + * README.Debian: add URI for group calendars + + -- Guido Guenther Sun, 20 Apr 2008 13:59:04 +0200 + +calendarserver (1.2.dfsg~dev020221-4) experimental; urgency=low + + * update README.Debian on SPNEGO/Kerberos + * fix snakeoil certificate paths + + -- Guido Guenther Sun, 16 Mar 2008 12:48:34 +0100 + +calendarserver (1.2.dfsg~dev020221-3) experimental; urgency=low + + * repackage upstream branch and remove RFCs too make the document dfsg clean + * add license of bin/xattr + + -- Guido Guenther Wed, 27 Feb 2008 10:31:48 +0100 + +calendarserver (1.2~dev020221-2) experimental; urgency=low + + * disable the api-doc generation until it works with newer epydoc + + -- Guido Guenther Tue, 26 Feb 2008 11:01:00 +0100 + +calendarserver (1.2~dev020221-1) experimental; urgency=low + + * first upload to experimental (Closes: #384644) + * switch to upstreams 1.2 development branch + * drop krb5 patch, applied upstream + * refreh paths.diff + * README.Debian: add calendar URI + * depend on renamed python-twisted-calendarserver package + + -- Guido Guenther Thu, 21 Feb 2008 17:54:56 +0100 + +calendarserver (0.0.svn1755-1) experimental; urgency=low + + * UNRELEASED + * New Upstream SVN Snapshot + * update dependencies + * drop opendirectory-dummy.patch, not needed anymore, can be disabled via + the config file + * drop caldavd-kerberos.patch, not needed anymore. Kerberos can be enabled + via config file now + * update paths.diff to new layout and config options + * new fix-krb-service.diff: fix kerberos service names + * calendarserver.init: daemon switches users itself, new commandline options + * set process count to avoid pydirector for now + + -- Guido Guenther Thu, 09 Aug 2007 10:24:46 +0200 + +calendarserver (0.0.svn209-2) calendarserver; urgency=low + + * create /var/run/caldavd (needed inc ase /var/run is on a tmpfs) + * drop dependencies on python-dateutil and python-zopeinterface since + these are indirect dependencies of python-vobject and + twisted-calendarserver respectively. + * build the api documentation + + -- Guido Guenther Mon, 2 Oct 2006 11:03:27 +0200 + +calendarserver (0.0.svn209-1) calendarserver; urgency=low + + * New Upstream Version + * depend on newer pykerberos + * depend on newer twisted-calendarserver + + -- Guido Guenther Wed, 27 Sep 2006 12:34:28 +0200 + +calendarserver (0.0.svn197-1) calendarserver; urgency=low + + * New Upstream Version + * depend on newer twisted + * twiddle path patch to apply again + + -- Guido Guenther Tue, 26 Sep 2006 10:21:00 +0200 + +calendarserver (0.0.svn188-1) unstable; urgency=low + + * New upstream version 0.0.svn188 + * bump dependencies on python-vobject + * depend on python-xml + * adjust patch path to look for twisted unter /usr/lib/caldavd + since we ship our own twisted version in this subdir now. This way + we don't have to conflict with the twisted shipped in Debian. + * depend on twisted-calendarserver (which was formerly + python-twisted-acl-branch) + + -- Guido Guenther Mon, 25 Sep 2006 18:33:19 +0200 + +calendarserver (0.0.svn142-3) unstable; urgency=low + + * add a sample diff for kerberos authentication + + -- Guido Guenther Tue, 19 Sep 2006 10:06:53 +0200 + +calendarserver (0.0.svn142-2) unstable; urgency=low + + * depend on python-plistlib + + -- Guido Guenther Mon, 18 Sep 2006 19:54:24 +0200 + +calendarserver (0.0.svn142-1) unstable; urgency=low + + * new SVN version (only patches merged into twisted) + * depend on more recent twisted-acl-branch + + -- Guido Guenther Mon, 18 Sep 2006 17:06:15 +0200 + +calendarserver (0.0.svn135-2) unstable; urgency=low + + * really drop upstream-patches/ + * fix restart target in init script, use LSB logging + * add LSB header + + -- Guido Guenther Mon, 18 Sep 2006 16:00:45 +0200 + +calendarserver (0.0.svn135-1) unstable; urgency=low + + * New upstream svn version + * no need to rename patches to upstream-patches, upstream changed that to + lib-patches + * depend on newer twisted-acl-branch and newer pykerberos + * remove superflous heimdal-dev from build-depends + * dropped patches (applied upstream): + * bashism + * move-patch-dir + * linux-xattr + * use snake-oil certificates for SSL + + -- Guido Guenther Fri, 15 Sep 2006 18:38:10 +0200 + +calendarserver (0.0.svn62-1) unstable; urgency=low + + * Initial release + * Add dummies for OpenDirectory interaction from: + http://svn.macosforge.org/projects/calendarserver/browser/PyOpenDirectory + until we have a proper port + + -- Guido Guenther Wed, 6 Sep 2006 13:45:40 +0200 + --- calendarserver-1.2.dfsg.orig/debian/calendarserver.default +++ calendarserver-1.2.dfsg/debian/calendarserver.default @@ -0,0 +1,8 @@ +# Defaults for calendarserver initscript (/etc/init.d/calendarserver) +# This is a POSIX shell fragment + +# uncomment to start calendarserver on system startup +#start_calendarserver=yes + +# options to pass to calendarserver on startup +#DAEMON_OPTS="" --- calendarserver-1.2.dfsg.orig/debian/calendarserver.examples +++ calendarserver-1.2.dfsg/debian/calendarserver.examples @@ -0,0 +1,2 @@ +conf/accounts.xml +conf/sudoers.plist --- calendarserver-1.2.dfsg.orig/debian/pycompat +++ calendarserver-1.2.dfsg/debian/pycompat @@ -0,0 +1 @@ +2 --- calendarserver-1.2.dfsg.orig/debian/README.Debian +++ calendarserver-1.2.dfsg/debian/README.Debian @@ -0,0 +1,79 @@ +calendar server for Debian +========================== + +Basic Setup +=========== +Since calendarserver uses extended attributes you must mount the filesystem +that contains the calendars (/var/spool/caldavd by default) with extended +attributes enabled. On ext2/ext3 filesystems use the user_xattr mount option, +XFS has extended attributes enabled by default. + +You have to add a /etc/caldavd/accounts.xml to tell caldavd about your accounts +and users. See /usr/share/doc/calendarserver/examples/accounts.xml for an +example. Likewise you have to add a /etc/caldavd/sudoers.plist. Both files have +to be present, otherwise the calendarserver will not work. + +By default calendarserver listens on localhost only so the URI to your caldav +calendar will typically look like: + + http://localhost:8008/calendars/users//calendar/ + +where is the username of a calendarserver user as specified in +accounts.xml. And for groups defined in accounts.xml it's: + + http://localhost:8008/calendars/groups//calendar/ + + +Loadbalancing +============= +In order to enable laod balancing onto different processors/cores you need to +install python-pydirecotor and set the ProcessCount in +/etc/caldavd/caldavd.plist accordingly (0 means one process per +processor/core). + + +Enabling SPNEGO/Kerberos +======================== + +To make SPNEGO/Kerberos authentication work you have to add service principals +for HTTP/caldavd.example.com@EXAMPLE.COM and +http/caldavd.example.com@EXAMPLE.COM to your servers keytab /etc/krb5.keytab +(replace caldavd.example.com by the fqdn of your caldav server and EXAMPLE.COM +by your Kerberos realm). +The uppercase http variant is used by most clients like iceowl and icedove with +iceowl-extension while the lowercase version is used by iCal. The keytab must +be readable for user caldavd which can be achieved by: + +chgrp caldavd /etc/krb5.keytab +chmod 0640 /etc/krb5.keytab + +Now you have to specify the name of a ServicePrincipal in +/etc/caldavd/caldavd.plist: + + + Kerberos + + Enabled + + ServicePrincipal + http/caldavd.example.com@EXAMPLE.COM + + +Note: if you use iceowl/iceowl-extension the +network.negotiate-auth.trusted-uris in iceowl/icedove must match on your +calendarservers uri otherwise SPNEGO will not work. A good choice is +"https://". + + +Nameservice Switch Backend +========================== +If you don't want to manage accounts in a separate XML file you can use the +names service switch backend. Details on how to set this up can be found at: + +http://honk.sigxcpu.org/con/Apple_Calendarser_with_Name_Service_Switch_directory_backend.html + +Note that in order to function properly "getent passwd" must list all users +that should be able to access the calendarserver. This might not be the case if +you hit the search limit of your LDAP server. + + -- Guido Guenther Thu, 30 Apr 2008 16:17:56 +0100 --- calendarserver-1.2.dfsg.orig/debian/calendarserver.init.d +++ calendarserver-1.2.dfsg/debian/calendarserver.init.d @@ -0,0 +1,97 @@ +#! /bin/sh +# +# calendarserver startup script +# +### BEGIN INIT INFO +# Provides: caldavserver +# Required-Start: $network +# Required-Stop: $network +# Default-Start: 2 3 4 5 +# Default-Stop: 0 1 6 +# Short-Description: CalDAV Calendarserver +### END INIT INFO + +PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin +DAEMON=/usr/bin/caldavd +NAME=caldavd +DESC=calendarserver +RUNDIR=/var/run/caldavd/ +SPOOLDIR=/var/spool/caldavd/ + +test -x $DAEMON || exit 0 + +# Include calendarserver defaults if available +if [ -f /etc/default/calendarserver ] ; then + . /etc/default/calendarserver +fi + +. /lib/lsb/init-functions + +set -e + +check_start_daemon() { + if [ ! "$start_calendarserver" = "yes" ]; then + log_warning_msg "Not starting calendarserver, disabled via /etc/default/calendarserver" + return 1 + else + return 0 + fi +} + +case "$1" in + start) + if check_start_daemon; then + log_daemon_msg "Starting $DESC" "$NAME" + mkdir -p $RUNDIR + chown --reference=$SPOOLDIR $RUNDIR + if start-stop-daemon --start --quiet --pidfile $RUNDIR$NAME.pid \ + --exec $DAEMON -- $DAEMON_OPTS 2>/dev/null; then + log_end_msg 0 + RET=0 + else + log_end_msg 1 + RET=1 + fi + fi + ;; + stop) + log_daemon_msg "Stopping $DESC" "$NAME" + if start-stop-daemon --oknodo --stop --quiet --pidfile $RUNDIR$NAME.pid \ + --exec /usr/bin/python; then + log_end_msg 0 + RET=0 + else + log_end_msg 1 + RET=1 + fi + ;; + restart|force-reload) + # + # If the "reload" option is implemented, move the "force-reload" + # option to the "reload" entry above. If not, "force-reload" is + # just the same as "restart". + # + if check_start_daemon; then + log_daemon_msg "Restarting $DESC" "$NAME" + start-stop-daemon --stop --quiet --oknodo --pidfile \ + $RUNDIR$NAME.pid --exec /usr/bin/python + sleep 1 + if start-stop-daemon --start --quiet --pidfile \ + $RUNDIR$NAME.pid --exec $DAEMON -- $DAEMON_OPTS 2>/dev/null; then + log_end_msg 0 + RET=0 + else + log_end_msg 1 + RET=1 + fi + fi + ;; + *) + N=/etc/init.d/$NAME + # echo "Usage: $N {start|stop|restart|reload|force-reload}" >&2 + echo "Usage: $N {start|stop|restart|force-reload}" >&2 + exit 1 + ;; +esac + +exit $RET --- calendarserver-1.2.dfsg.orig/debian/compat +++ calendarserver-1.2.dfsg/debian/compat @@ -0,0 +1 @@ +5 --- calendarserver-1.2.dfsg.orig/debian/pyversions +++ calendarserver-1.2.dfsg/debian/pyversions @@ -0,0 +1 @@ +2.5- --- calendarserver-1.2.dfsg.orig/debian/rules +++ calendarserver-1.2.dfsg/debian/rules @@ -0,0 +1,20 @@ +#!/usr/bin/make -f + +DEB_PYTHON_SYSTEM = pycentral + +include /usr/share/cdbs/1/rules/debhelper.mk +include /usr/share/cdbs/1/class/python-distutils.mk +include /usr/share/cdbs/1/rules/patchsys-quilt.mk + +DEB_DESTDIR=$(CURDIR)/debian/calendarserver + +calendarserver-doc-api-stamp: + #cd doc/Developer && pydoctor -c twistedcaldav.cfg --resolve-aliases --make-html + touch calendarserver-doc-api-stamp + +build/calendarserver-doc-api:: calendarserver-doc-api-stamp + +clean:: + -rm twistedcaldav/version.py + -rm -r doc/Developer/apidocs calendarserver-doc-api-stamp + --- calendarserver-1.2.dfsg.orig/debian/calendarserver.TODO +++ calendarserver-1.2.dfsg/debian/calendarserver.TODO @@ -0,0 +1,2 @@ + + --- calendarserver-1.2.dfsg.orig/debian/README.source +++ calendarserver-1.2.dfsg/debian/README.source @@ -0,0 +1,57 @@ +This package uses quilt to manage all modifications to the upstream +source. Changes are stored in the source package as diffs in +debian/patches and applied during the build. + +To configure quilt to use debian/patches instead of patches, you want +either to export QUILT_PATCHES=debian/patches in your environment +or use this snippet in your ~/.quiltrc: + + for where in ./ ../ ../../ ../../../ ../../../../ ../../../../../; do + if [ -e ${where}debian/rules -a -d ${where}debian/patches ]; then + export QUILT_PATCHES=debian/patches + fi + done + +To get the fully patched source after unpacking the source package, cd to +the root level of the source package and run: + + quilt push -a + +The last patch listed in debian/patches/series will become the current +patch. + +To add a new set of changes, first run quilt push -a, and then run: + + quilt new + +where is a descriptive name for the patch, used as the filename in +debian/patches. Then, for every file that will be modified by this patch, +run: + + quilt add + +before editing those files. You must tell quilt with quilt add what files +will be part of the patch before making changes or quilt will not work +properly. After editing the files, run: + + quilt refresh + +to save the results as a patch. + +Alternately, if you already have an external patch and you just want to +add it to the build system, run quilt push -a and then: + + quilt import -P /path/to/patch + quilt push -a + +(add -p 0 to quilt import if needed). as above is the filename to +use in debian/patches. The last quilt push -a will apply the patch to +make sure it works properly. + +To remove an existing patch from the list of patches that will be applied, +run: + + quilt delete + +You may need to run quilt pop -a to unapply patches first before running +this command. --- calendarserver-1.2.dfsg.orig/debian/patches/0003-add-guid.patch +++ calendarserver-1.2.dfsg/debian/patches/0003-add-guid.patch @@ -0,0 +1,71 @@ +From 6cbdd109499397010d08ea1538b96ef177244f20 Mon Sep 17 00:00:00 2001 +From: Guido Guenther +Date: Sun, 22 Jun 2008 20:17:45 +0200 +Subject: [PATCH] add guid so calendars get nicer names on disk + +use shortname for groups and users. The groupPrefix makes sure these +don't overlap +--- + twistedcaldav/directory/nss.py | 15 +++++++++------ + 1 files changed, 9 insertions(+), 6 deletions(-) + +diff --git a/twistedcaldav/directory/nss.py b/twistedcaldav/directory/nss.py +index 4fb4cfc..c7de423 100644 +--- a/twistedcaldav/directory/nss.py ++++ b/twistedcaldav/directory/nss.py +@@ -31,8 +31,8 @@ Example caldavd.plist configuration: + + realmName + Test Realm +- ++ + groupPrefix + caldavd- + +@@ -100,6 +100,8 @@ class NssDirectoryService(DirectoryService): + firstValidGid, lastValidGid): + super(NssDirectoryService, self).__init__() + self.nsswitch = NsSwitch() ++ if not groupPrefix: ++ raise ValueError("groupPrefix cannot be empty") + self.groupPrefix = groupPrefix + self.realmName = realmName + self.first_valid_uid = firstValidUid +@@ -181,11 +183,11 @@ class NssDirectoryRecord(DirectoryRecord): + """ + Nss Directory Record + """ +- def __init__(self, service, recordType, shortName, fullName = None, calendarUserAddresses = set()): ++ def __init__(self, service, recordType, shortName, guid, fullName=None, calendarUserAddresses=set()): + super(NssDirectoryRecord, self).__init__( + service = service, + recordType = recordType, +- guid = None, ++ guid = guid, + shortName = shortName, + fullName = fullName, + calendarUserAddresses = calendarUserAddresses, +@@ -202,7 +204,8 @@ class NssUserRecord(NssDirectoryRecord): + calendarUserAddresses = set() + if service.mailDomain: + calendarUserAddresses.add("mailto:%s@%s" % (shortName, service.mailDomain)) +- super(NssUserRecord, self).__init__(service, recordType, shortName, fullName, calendarUserAddresses) ++ super(NssUserRecord, self).__init__(service, recordType, shortName, guid=shortName, ++ fullName=fullName, calendarUserAddresses=calendarUserAddresses) + + def verifyCredentials(self, credentials): + # FIXME: plugin in PAM authentication here if you want too - kerberos works +@@ -223,7 +226,7 @@ class NssGroupRecord(NssDirectoryRecord): + """ + def __init__(self, service, recordType, groupName, members=()): + shortName = groupName.replace(service.groupPrefix,'',1) +- super(NssGroupRecord, self).__init__(service, recordType, shortName) ++ super(NssGroupRecord, self).__init__(service, recordType, shortName, guid=groupName) + self._members = members + + def members(self): +-- +1.5.5.4 + --- calendarserver-1.2.dfsg.orig/debian/patches/fix-krb-service.diff +++ calendarserver-1.2.dfsg/debian/patches/fix-krb-service.diff @@ -0,0 +1,19 @@ +diff --git a/twistedcaldav/authkerb.py b/twistedcaldav/authkerb.py +index 4f9abe3..6cdb7f0 100644 +--- a/twistedcaldav/authkerb.py ++++ b/twistedcaldav/authkerb.py +@@ -84,12 +84,13 @@ class KerberosCredentialFactoryBase(object): + splits = principal.split("/") + servicetype = splits[0] + splits = splits[1].split("@") ++ server = splits[0] + realm = splits[1] + except IndexError: + logging.err("Invalid Kerberos principal: %s" % (principal,), system="KerberosCredentialFactoryBase") + raise ValueError('Authentication System Failure: Invalid Kerberos principal: %s' % (principal,)) + +- self.service = "%s@%s" % (servicetype, realm,) ++ self.service = "%s@%s" % (servicetype, server,) + self.realm = realm + + class BasicKerberosCredentials(credentials.UsernamePassword): --- calendarserver-1.2.dfsg.orig/debian/patches/Ticket207-2.patch +++ calendarserver-1.2.dfsg/debian/patches/Ticket207-2.patch @@ -0,0 +1,588 @@ +Fixes events being more than one year in the future not showing up. + +http://trac.calendarserver.org/ticket/207 +http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=489188 + +Patch by Peter Mogensen + +Retrieved from + +http://trac.calendarserver.org/raw-attachment/ticket/207/Ticket207-2.patch + +diff -x '*.svn' -x '*.pyc' -ru ./twistedcaldav/index.py ../../DCS1.2/CalendarServer-1.2/twistedcaldav/index.py +--- ./twistedcaldav/index.py 2008-08-20 10:30:02.000000000 +0200 ++++ ../../DCS1.2/CalendarServer-1.2/twistedcaldav/index.py 2008-08-22 16:48:11.000000000 +0200 +@@ -26,6 +26,7 @@ + __all__ = [ + "Index", + "IndexSchedule", ++ "IndexedSearchException", + ] + + import datetime +@@ -83,6 +84,10 @@ + which is not reserved. + """ + ++class IndexedSearchException(ValueError): ++ pass ++ ++ + class AbstractCalendarIndex(AbstractSQLDatabase): + """ + Calendar collection index abstract base class that defines the apis for the index. +@@ -246,16 +251,15 @@ + statement += ")" + results = self._db_values_for_sql(statement, *names) + return results +- +- def searchValid(self, filter): +- if isinstance(filter, caldavxml.Filter): +- qualifiers = calendarquery.sqlcalendarquery(filter) +- else: +- qualifiers = None +- +- return qualifiers is not None + +- def search(self, filter): ++ def testAndUpdateIndex(self, mindate): ++ # Find out if the index is expanded far enough. ++ names = self.notExpandedBeyond(mindate) ++ # Actually expand recurrance max ++ for name in names: ++ self.reExpandResource(name,mindate) ++ ++ def indexedSearch(self, filter): + """ + Finds resources matching the given qualifiers. + @param filter: the L{Filter} for the calendar-query to execute. +@@ -266,17 +270,48 @@ + """ + # FIXME: Don't forget to use maximum_future_expansion_duration when we + # start caching... +- ++ + # Make sure we have a proper Filter element and get the partial SQL statement to use. + if isinstance(filter, caldavxml.Filter): +- qualifiers = calendarquery.sqlcalendarquery(filter) ++ # Get a tuple of (SQL-qualifier, hint-to-update-index:date) ++ qualifier = calendarquery.sqlcalendarquery(filter) ++ if qualifier is not None: ++ sqlqualifiers = qualifier[0] ++ if qualifier[1] is not None: ++ # bring index up to a a given date if it's not already ++ self.testAndUpdateIndex(qualifier[1]) ++ else: ++ # We cannot handle this filter in an indexed search ++ raise IndexedSearchException() + else: +- qualifiers = None +- if qualifiers is not None: +- rowiter = self._db_execute("select DISTINCT RESOURCE.NAME, RESOURCE.UID, RESOURCE.TYPE" + qualifiers[0], *qualifiers[1]) ++ sqlqualifiers = None ++ ++ # Perform the search ++ if sqlqualifiers is not None: ++ rowiter = self._db_execute("select DISTINCT RESOURCE.NAME, RESOURCE.UID, RESOURCE.TYPE" + sqlqualifiers[0], ++ *sqlqualifiers[1]) + else: +- rowiter = self._db_execute("select NAME, UID, TYPE from RESOURCE") +- ++ raise IndexedSearchException() ++ ++ # Check result for missing resources ++ for row in rowiter: ++ name = row[0] ++ if self.resource.getChild(name.encode("utf-8")): ++ yield row ++ else: ++ log.err("Calendar resource %s is missing from %s. Removing from index." ++ % (name, self.resource)) ++ self.deleteResource(name) ++ ++ def bruteforceSearch(self): ++ """ ++ List the whole index and tests for existance, updating the index. ++ @return: all resources in the index. ++ """ ++ # List all resources ++ rowiter = self._db_execute("select NAME, UID, TYPE from RESOURCE") ++ ++ # Check result for missing resources + for row in rowiter: + name = row[0] + if self.resource.getChild(name.encode("utf-8")): +@@ -393,7 +428,27 @@ + """ + ) + +- def _add_to_db(self, name, calendar, cursor = None): ++ def notExpandedBeyond(self, mindate): ++ """ ++ Gives all resources which has not been expanded beyond a given date in the index ++ """ ++ return self._db_values_for_sql("select NAME from RESOURCE where RECURRANCE_MAX <= :1", mindate) ++ ++ def reExpandResource(self,name,until_date): ++ """ ++ Given a resource name, remove it from the database and re-add it ++ with a longer expansion. ++ """ ++ calendar = self.resource.getChild(name).iCalendar() ++ ++ oldUID = self.resourceUIDForName(name) ++ if oldUID is not None: ++ self._delete_from_db(name, oldUID) ++ self._add_to_db(name, calendar,until_date) ++ self._db_commit() ++ ++ ++ def _add_to_db(self, name, calendar, expand_wish = None, cursor = None): + """ + Records the given calendar resource in the index with the given name. + Resource names and UIDs must both be unique; only one resource name may +@@ -406,9 +461,18 @@ + """ + uid = calendar.resourceUID() + +- expand_max = datetime.date.today() + default_future_expansion_duration ++ expand_default = datetime.date.today() + default_future_expansion_duration ++ expand_max = datetime.date.today() + maximum_future_expansion_duration ++ ++ expand = expand_default ++ if expand_wish is not None: ++ if expand_wish > expand_default: ++ expand = expand_wish ++ if expand > expand_max: ++ # Will not handle ++ raise IndexedSearchException + +- instances = calendar.expandTimeRanges(expand_max) ++ instances = calendar.expandTimeRanges(expand) + for key in instances: + instance = instances[key] + start = instance.start.replace(tzinfo=utc) +diff -x '*.svn' -x '*.pyc' -ru ./twistedcaldav/method/report_calquery.py ../../DCS1.2/CalendarServer-1.2/twistedcaldav/method/report_calquery.py +--- ./twistedcaldav/method/report_calquery.py 2008-08-20 10:29:59.000000000 +0200 ++++ ../../DCS1.2/CalendarServer-1.2/twistedcaldav/method/report_calquery.py 2008-08-21 17:56:25.000000000 +0200 +@@ -35,6 +35,7 @@ + from twistedcaldav.caldavxml import caldav_namespace + from twistedcaldav.customxml import TwistedCalendarAccessProperty + from twistedcaldav.method import report_common ++from twistedcaldav.index import IndexedSearchException + + import urllib + +@@ -166,15 +167,20 @@ + + # Check for disabled access + if filteredaces is not None: +- # See whether the filter is valid for an index only query +- index_query_ok = calresource.index().searchValid(filter) +- +- # Get list of children that match the search and have read access +- names = [name for name, ignore_uid, ignore_type in calresource.index().search(filter)] ++ # Variable to remember whether the filter is valid for an index only query ++ index_query_ok = None ++ try: ++ # Get list of children that match the search and have read access ++ names = [name for name, ignore_uid, ignore_type in calresource.index().indexedSearch(filter)] ++ index_query_ok = True ++ except IndexedSearchException: ++ names = [name for name, ignore_uid, ignore_type in calresource.index().bruteforceSearch()] ++ index_query_ok = False ++ + if not names: + yield None + return +- ++ + # Now determine which valid resources are readable and which are not + ok_resources = [] + d = calresource.findChildrenFaster( +@@ -189,7 +195,7 @@ + x = waitForDeferred(d) + yield x + x.getResult() +- ++ + for child, child_uri in ok_resources: + child_uri_name = child_uri[child_uri.rfind("/") + 1:] + child_path_name = urllib.unquote(child_uri_name) +diff -x '*.svn' -x '*.pyc' -ru ./twistedcaldav/method/report_common.py ../../DCS1.2/CalendarServer-1.2/twistedcaldav/method/report_common.py +--- ./twistedcaldav/method/report_common.py 2008-08-20 10:29:59.000000000 +0200 ++++ ../../DCS1.2/CalendarServer-1.2/twistedcaldav/method/report_common.py 2008-08-21 17:55:18.000000000 +0200 +@@ -47,6 +47,7 @@ + from twistedcaldav.dateops import clipPeriod, normalizePeriodList, timeRangesOverlap + from twistedcaldav.ical import Component, Property, iCalendarProductID + from twistedcaldav.instance import InstanceList ++from twistedcaldav.index import IndexedSearchException + + from vobject.icalendar import utc + +@@ -346,7 +347,12 @@ + yield filteredaces + filteredaces = filteredaces.getResult() + +- for name, uid, type in calresource.index().search(filter): #@UnusedVariable ++ try: ++ resources = calresource.index().indexedSearch(filter) ++ except IndexedSearchException: ++ resources = calresource.index().bruteforceSearch() ++ ++ for name, uid, type in resources: #@UnusedVariable + + # Check privileges - must have at least CalDAV:read-free-busy + child = waitForDeferred(request.locateChildResource(calresource, name)) +diff -x '*.svn' -x '*.pyc' -ru ./twistedcaldav/query/calendarquery.py ../../DCS1.2/CalendarServer-1.2/twistedcaldav/query/calendarquery.py +--- ./twistedcaldav/query/calendarquery.py 2008-07-02 12:54:08.000000000 +0200 ++++ ../../DCS1.2/CalendarServer-1.2/twistedcaldav/query/calendarquery.py 2008-08-22 16:20:27.000000000 +0200 +@@ -24,7 +24,7 @@ + __version__ = "0.0" + + __all__ = [ +- "calendarquery", ++ "CalendarQueryExpressionGenerator", + "sqlcalendarquery", + ] + +@@ -42,151 +42,162 @@ + #FIELD_DESCRIPTION = "RESOURCE.DESCRIPTION" + #FIELD_LOCATION = "RESOURCE.LOCATION" + +-def calendarquery(filter): ++class CalendarQueryExpressionGenerator(object): + """ +- Convert the supplied calendar-query into an expression tree. +- +- @param filter: the L{Filter} for thw calendar-query to convert. +- @return: a L{baseExpression} for the expression tree. ++ Can parse CalDAV XML filters to expression structures and ++ Hold information about the expression useful for clients + """ +- +- # Lets assume we have a valid filter from the outset. +- +- # Top-level filter contains exactly one comp-filter element +- assert len(filter.children) == 1 +- vcalfilter = filter.children[0] +- assert isinstance(vcalfilter, caldavxml.ComponentFilter) +- assert vcalfilter.filter_name == "VCALENDAR" +- +- if len(vcalfilter.children) > 0: +- # Only comp-filters are handled +- for _ignore in [x for x in vcalfilter.children if not isinstance(x, caldavxml.ComponentFilter)]: ++ ++ def __init__(self): ++ self.enddate = None ++ ++ def calendarquery(self, filter): ++ """ ++ Convert the supplied calendar-query into an expression tree. ++ ++ @param filter: the L{Filter} for thw calendar-query to convert. ++ @return: a L{baseExpression} for the expression tree. ++ """ ++ ++ # Lets assume we have a valid filter from the outset. ++ ++ # Top-level filter contains exactly one comp-filter element ++ assert len(filter.children) == 1 ++ vcalfilter = filter.children[0] ++ assert isinstance(vcalfilter, caldavxml.ComponentFilter) ++ assert vcalfilter.filter_name == "VCALENDAR" ++ ++ if len(vcalfilter.children) > 0: ++ # Only comp-filters are handled ++ for _ignore in [x for x in vcalfilter.children if not isinstance(x, caldavxml.ComponentFilter)]: ++ raise ValueError ++ ++ return self.compfilterListExpression(vcalfilter.children) ++ else: ++ return expression.allExpression() ++ ++ def compfilterListExpression(self, compfilters): ++ """ ++ Create an expression for a list of comp-filter elements. ++ ++ @param compfilters: the C{list} of L{ComponentFilter} elements. ++ @return: a L{baseExpression} for the expression tree. ++ """ ++ ++ if len(compfilters) == 1: ++ return self.compfilterExpression(compfilters[0]) ++ else: ++ return expression.orExpression([self.compfilterExpression(c) for c in compfilters]) ++ ++ def compfilterExpression(self, compfilter): ++ """ ++ Create an expression for a single comp-filter element. ++ ++ @param compfilter: the L{ComponentFilter} element. ++ @return: a L{baseExpression} for the expression tree. ++ """ ++ ++ # Handle is-not-defined case ++ if not compfilter.defined: ++ # Test for TYPE != <> ++ return expression.isnotExpression(FIELD_TYPE, compfilter.filter_name, True) ++ ++ expressions = [] ++ if isinstance(compfilter.filter_name, str): ++ expressions.append(expression.isExpression(FIELD_TYPE, compfilter.filter_name, True)) ++ else: ++ expressions.append(expression.inExpression(FIELD_TYPE, compfilter.filter_name, True)) ++ ++ # Handle time-range ++ if compfilter.qualifier and isinstance(compfilter.qualifier, caldavxml.TimeRange): ++ start, end, startfloat, endfloat = getTimerangeArguments(compfilter.qualifier) ++ expressions.append(expression.timerangeExpression(start, end, startfloat, endfloat)) ++ self.enddate = compfilter.qualifier.end.date() ++ ++ # Handle properties - we can only do UID right now ++ props = [] ++ for p in [x for x in compfilter.filters if isinstance(x, caldavxml.PropertyFilter)]: ++ props.append(self.propfilterExpression(p)) ++ if len(props) > 1: ++ propsExpression = expression.orExpression[props] ++ elif len(props) == 1: ++ propsExpression = props[0] ++ else: ++ propsExpression = None ++ ++ # Handle embedded components - we do not right now as our Index does not handle them ++ comps = [] ++ for _ignore in [x for x in compfilter.filters if isinstance(x, caldavxml.ComponentFilter)]: + raise ValueError +- +- return compfilterListExpression(vcalfilter.children) +- else: +- return expression.allExpression() ++ if len(comps) > 1: ++ compsExpression = expression.orExpression[comps] ++ elif len(comps) == 1: ++ compsExpression = comps[0] ++ else: ++ compsExpression = None + +-def compfilterListExpression(compfilters): +- """ +- Create an expression for a list of comp-filter elements. +- +- @param compfilters: the C{list} of L{ComponentFilter} elements. +- @return: a L{baseExpression} for the expression tree. +- """ +- +- if len(compfilters) == 1: +- return compfilterExpression(compfilters[0]) +- else: +- return expression.orExpression([compfilterExpression(c) for c in compfilters]) ++ # Now build compound expression ++ if ((propsExpression is not None) and (compsExpression is not None)): ++ expressions.append(expression.orExpression([propsExpression, compsExpression])) ++ elif propsExpression is not None: ++ expressions.append(propsExpression) ++ elif compsExpression is not None: ++ expressions.append(compsExpression) ++ ++ # Now build return expression ++ return expression.andExpression(expressions) ++ ++ def propfilterExpression(self, propfilter): ++ """ ++ Create an expression for a single prop-filter element. ++ ++ @param propfilter: the L{PropertyFilter} element. ++ @return: a L{baseExpression} for the expression tree. ++ """ + +-def compfilterExpression(compfilter): +- """ +- Create an expression for a single comp-filter element. +- +- @param compfilter: the L{ComponentFilter} element. +- @return: a L{baseExpression} for the expression tree. +- """ +- +- # Handle is-not-defined case +- if not compfilter.defined: +- # Test for TYPE != <> +- return expression.isnotExpression(FIELD_TYPE, compfilter.filter_name, True) +- +- expressions = [] +- if isinstance(compfilter.filter_name, str): +- expressions.append(expression.isExpression(FIELD_TYPE, compfilter.filter_name, True)) +- else: +- expressions.append(expression.inExpression(FIELD_TYPE, compfilter.filter_name, True)) +- +- # Handle time-range +- if compfilter.qualifier and isinstance(compfilter.qualifier, caldavxml.TimeRange): +- start, end, startfloat, endfloat = getTimerangeArguments(compfilter.qualifier) +- expressions.append(expression.timerangeExpression(start, end, startfloat, endfloat)) +- +- # Handle properties - we can only do UID right now +- props = [] +- for p in [x for x in compfilter.filters if isinstance(x, caldavxml.PropertyFilter)]: +- props.append(propfilterExpression(p)) +- if len(props) > 1: +- propsExpression = expression.orExpression[props] +- elif len(props) == 1: +- propsExpression = props[0] +- else: +- propsExpression = None +- +- # Handle embedded components - we do not right now as our Index does not handle them +- comps = [] +- for _ignore in [x for x in compfilter.filters if isinstance(x, caldavxml.ComponentFilter)]: +- raise ValueError +- if len(comps) > 1: +- compsExpression = expression.orExpression[comps] +- elif len(comps) == 1: +- compsExpression = comps[0] +- else: +- compsExpression = None +- +- # Now build compound expression +- if ((propsExpression is not None) and (compsExpression is not None)): +- expressions.append(expression.orExpression([propsExpression, compsExpression])) +- elif propsExpression is not None: +- expressions.append(propsExpression) +- elif compsExpression is not None: +- expressions.append(compsExpression) ++ # Only handle UID right now ++ if propfilter.filter_name != "UID": ++ raise ValueError + +- # Now build return expression +- return expression.andExpression(expressions) ++ # Handle is-not-defined case ++ if not propfilter.defined: ++ # Test for <> != "*" ++ return expression.isExpression(FIELD_UID, "", True) + +-def propfilterExpression(propfilter): +- """ +- Create an expression for a single prop-filter element. +- +- @param propfilter: the L{PropertyFilter} element. +- @return: a L{baseExpression} for the expression tree. +- """ +- +- # Only handle UID right now +- if propfilter.filter_name != "UID": +- raise ValueError +- +- # Handle is-not-defined case +- if not propfilter.defined: +- # Test for <> != "*" +- return expression.isExpression(FIELD_UID, "", True) +- +- # Handle time-range - we cannot do this with our Index right now +- if propfilter.qualifier and isinstance(propfilter.qualifier, caldavxml.TimeRange): +- raise ValueError +- +- # Handle text-match +- tm = None +- if propfilter.qualifier and isinstance(propfilter.qualifier, caldavxml.TextMatch): +- if propfilter.qualifier.negate: +- tm = expression.notcontainsExpression(propfilter.filter_name, str(propfilter.qualifier), propfilter.qualifier) ++ # Handle time-range - we cannot do this with our Index right now ++ if propfilter.qualifier and isinstance(propfilter.qualifier, caldavxml.TimeRange): ++ raise ValueError ++ ++ # Handle text-match ++ tm = None ++ if propfilter.qualifier and isinstance(propfilter.qualifier, caldavxml.TextMatch): ++ if propfilter.qualifier.negate: ++ tm = expression.notcontainsExpression(propfilter.filter_name, str(propfilter.qualifier), propfilter.qualifier) ++ else: ++ tm = expression.containsExpression(propfilter.filter_name, str(propfilter.qualifier), propfilter.qualifier) ++ ++ # Handle embedded parameters - we do not right now as our Index does not handle them ++ params = [] ++ for _ignore in propfilter.filters: ++ raise ValueError ++ if len(params) > 1: ++ paramsExpression = expression.orExpression[params] ++ elif len(params) == 1: ++ paramsExpression = params[0] + else: +- tm = expression.containsExpression(propfilter.filter_name, str(propfilter.qualifier), propfilter.qualifier) +- +- # Handle embedded parameters - we do not right now as our Index does not handle them +- params = [] +- for _ignore in propfilter.filters: +- raise ValueError +- if len(params) > 1: +- paramsExpression = expression.orExpression[params] +- elif len(params) == 1: +- paramsExpression = params[0] +- else: +- paramsExpression = None +- +- # Now build return expression +- if (tm is not None) and (paramsExpression is not None): +- return expression.andExpression([tm, paramsExpression]) +- elif tm is not None: +- return tm +- elif paramsExpression is not None: +- return paramsExpression +- else: +- return None ++ paramsExpression = None ++ ++ # Now build return expression ++ if (tm is not None) and (paramsExpression is not None): ++ return expression.andExpression([tm, paramsExpression]) ++ elif tm is not None: ++ return tm ++ elif paramsExpression is not None: ++ return paramsExpression ++ else: ++ return None + ++# Utility function + def getTimerangeArguments(timerange): + """ + Get start/end and floating start/end (adjusted for timezone offset) values from the +@@ -209,20 +220,24 @@ + + return str(start), str(end), str(startfloat), str(endfloat) + ++# return SQL qualifiers and info to index. + def sqlcalendarquery(filter): + """ +- Convert the supplied calendar-query into a oartial SQL statement. ++ Convert the supplied calendar-query into a partial SQL statement. + +- @param filter: the L{Filter} for thw calendar-query to convert. ++ @param filter: the L{Filter} for the calendar-query to convert. + @return: a C{tuple} of (C{str}, C{list}), where the C{str} is the partial SQL statement, + and the C{list} is the list of argument substitutions to use with the SQL API execute method. + Or return C{None} if it is not possible to create an SQL query to fully match the calendar-query. + """ + try: +- expression = calendarquery(filter) ++ expression_generator = CalendarQueryExpressionGenerator() ++ expression = expression_generator.calendarquery(filter) + sql = sqlgenerator.sqlgenerator(expression) +- return sql.generate() ++ qualifiers = (sql.generate(),expression_generator.enddate) ++ return qualifiers + except ValueError: ++ # Indicate an unsupported filter + return None + + +diff -x '*.svn' -x '*.pyc' -ru ./twistedcaldav/static.py ../../DCS1.2/CalendarServer-1.2/twistedcaldav/static.py +--- ./twistedcaldav/static.py 2008-08-22 16:42:51.000000000 +0200 ++++ ../../DCS1.2/CalendarServer-1.2/twistedcaldav/static.py 2008-08-21 11:31:30.000000000 +0200 +@@ -187,7 +187,7 @@ + filteredaces = filteredaces.getResult() + + # Must verify ACLs which means we need a request object at this point +- for name, uid, type in self.index().search(None): #@UnusedVariable ++ for name, uid, type in self.index().bruteforceSearch(): + try: + child = waitForDeferred(request.locateChildResource(self, name)) + yield child --- calendarserver-1.2.dfsg.orig/debian/patches/paths.diff +++ calendarserver-1.2.dfsg/debian/patches/paths.diff @@ -0,0 +1,142 @@ +Index: calendarserver/conf/caldavd.plist +=================================================================== +--- calendarserver.orig/conf/caldavd.plist 2008-04-30 16:33:13.000000000 +0200 ++++ calendarserver/conf/caldavd.plist 2008-04-30 16:42:47.000000000 +0200 +@@ -54,7 +54,7 @@ + + + BindAddresses +- ++ localhost + + + BindHTTPPorts +@@ -75,7 +75,7 @@ + + + DocumentRoot +- /Library/CalendarServer/Documents ++ /var/spool/caldavd + + + UserQuota +@@ -96,7 +96,6 @@ + --> + + +- + +- ++ + + + + ServerStatsFile +- /var/run/caldavd/stats.plist ++ /var/spool/caldavd/stats.plist + + + PIDFile +- /var/run/caldavd.pid ++ /var/run/caldavd/caldavd.pid + + + + SSLCertificate +- ++ /etc/ssl/certs/ssl-cert-snakeoil.pem + + + SSLPrivateKey +- ++ /etc/ssl/private/ssl-cert-snakeoil.key + + + + + UserName +- calendar ++ caldavd + + GroupName +- calendar ++ caldavd + + ProcessType + Combined +@@ -240,7 +239,7 @@ + MultiProcess + + ProcessCount +- 0 ++ 1 + + + +@@ -264,14 +263,27 @@ + EnableNotifications + + +- + + ++ Twisted ++ ++ twistd ++ /usr/bin/twistd ++ ++ ++ PythonDirector ++ ++ pydir ++ /usr/share/pydirector/pydir.py ++ ControlSocket ++ /var/run/caldavd/caldavd-pydir.sock ++ ++ + + ControlSocket +- /var/run/caldavd.sock ++ /var/run/caldavd/caldavd.socket + + + ResponseCompression +Index: calendarserver/setup.py +=================================================================== +--- calendarserver.orig/setup.py 2008-04-30 16:33:13.000000000 +0200 ++++ calendarserver/setup.py 2008-04-30 16:40:20.000000000 +0200 +@@ -140,7 +140,7 @@ + "twistedcaldav": ["zoneinfo/*.ics", "zoneinfo/*/*.ics", "zoneinfo/*/*/*.ics"], + }, + scripts = [ "bin/caldavd", "bin/caladmin" ], +- data_files = [ ("caldavd", ["conf/caldavd.plist"]) ], ++ data_files = [ ("/etc/caldavd", ["conf/caldavd.plist"]) ], + ext_modules = extensions, + ) + --- calendarserver-1.2.dfsg.orig/debian/patches/allow-apache-basic-auth.diff +++ calendarserver-1.2.dfsg/debian/patches/allow-apache-basic-auth.diff @@ -0,0 +1,40 @@ +Author: Thomas Viehmann +Fix apache basic auth by allowing non-preconfigured directory services. +See also: + http://trac.calendarserver.org/ticket/305 + +--- a/twistedcaldav/config.py 2008-10-27 21:55:00.000000000 +0100 ++++ b/twistedcaldav/config.py 2008-10-27 21:02:40.000000000 +0100 +@@ -218,14 +218,15 @@ + self._data["DirectoryService"]["params"] = {} + + for param in items.get("DirectoryService", {}).get("params", {}): +- if param not in serviceDefaultParams[dsType]: ++ if dsType in serviceDefaultParams and param not in serviceDefaultParams[dsType]: + raise ConfigurationError("Parameter %s is not supported by service %s" % (param, dsType)) + + _mergeData(self._data, items) + +- for param in tuple(self._data["DirectoryService"]["params"]): +- if param not in serviceDefaultParams[self._data["DirectoryService"]["type"]]: +- del self._data["DirectoryService"]["params"][param] ++ if self._data["DirectoryService"]["type"] in serviceDefaultParams: ++ for param in tuple(self._data["DirectoryService"]["params"]): ++ if param not in serviceDefaultParams[self._data["DirectoryService"]["type"]]: ++ del self._data["DirectoryService"]["params"][param] + + self.updateServerCapabilities() + +--- a/twistedcaldav/directory/apache.py 2008-04-20 17:12:01.000000000 +0200 ++++ b/twistedcaldav/directory/apache.py 2008-10-27 21:57:28.000000000 +0100 +@@ -40,7 +40,9 @@ + def __repr__(self): + return "<%s %r: %r %r>" % (self.__class__.__name__, self.realmName, self.userFile, self.groupFile) + +- def __init__(self, realmName, userFile, groupFile=None): ++ def __init__(self, realmName=None, userFile=None, groupFile=None): ++ assert realmName ++ assert userFile + super(AbstractDirectoryService, self).__init__() + + if type(userFile) is str: --- calendarserver-1.2.dfsg.orig/debian/patches/series +++ calendarserver-1.2.dfsg/debian/patches/series @@ -0,0 +1,7 @@ +paths.diff +epydoc-fixes.diff +0001-add-name-service-switch-directory-backend.patch +0002-add-default-values-for-the-NSS-backend.patch +0003-add-guid.patch +Ticket207-2.patch +allow-apache-basic-auth.diff --- calendarserver-1.2.dfsg.orig/debian/patches/0002-add-default-values-for-the-NSS-backend.patch +++ calendarserver-1.2.dfsg/debian/patches/0002-add-default-values-for-the-NSS-backend.patch @@ -0,0 +1,35 @@ +From 56032ff57d7a5ea3cfcf06fdcabe383fcd921df2 Mon Sep 17 00:00:00 2001 +From: Guido Guenther +Date: Sun, 27 Apr 2008 02:53:02 +0200 +Subject: [PATCH] add default values for the NSS backend + +--- + twistedcaldav/config.py | 12 ++++++++++++ + 1 files changed, 12 insertions(+), 0 deletions(-) + +diff --git a/twistedcaldav/config.py b/twistedcaldav/config.py +index ccaa605..2be8daa 100644 +--- a/twistedcaldav/config.py ++++ b/twistedcaldav/config.py +@@ -33,6 +33,18 @@ serviceDefaultParams = { + "node": "/Search", + "requireComputerRecord": True, + }, ++ "twistedcaldav.directory.nss.NssDirectoryService": { ++ "realmName": "Test Realm", ++ # we only consider groups starting with: ++ "groupPrefix": "caldavd-", ++ # dont set calendarUserAdresses by default ++ "mailDomain": None, ++ # exclude system users and nobody by "default": ++ "firstValidUid": 1000, ++ "lastValidUid": 65533, ++ "firstValidGid": 1000, ++ "lastValidGid": 65533, ++ }, + } + + defaultConfig = { +-- +1.5.5.1 + --- calendarserver-1.2.dfsg.orig/debian/patches/0001-add-name-service-switch-directory-backend.patch +++ calendarserver-1.2.dfsg/debian/patches/0001-add-name-service-switch-directory-backend.patch @@ -0,0 +1,252 @@ +From 4d4b0465c28ed5b5d5cffb749e5bad1466aa60c8 Mon Sep 17 00:00:00 2001 +From: Guido Guenther +Date: Sat, 26 Apr 2008 21:03:31 +0200 +Subject: [PATCH] add name service switch directory backend + +--- + twistedcaldav/directory/nss.py | 233 ++++++++++++++++++++++++++++++++++++++++ + 1 files changed, 233 insertions(+), 0 deletions(-) + create mode 100644 twistedcaldav/directory/nss.py + +diff --git a/twistedcaldav/directory/nss.py b/twistedcaldav/directory/nss.py +new file mode 100644 +index 0000000..4fb4cfc +--- /dev/null ++++ b/twistedcaldav/directory/nss.py +@@ -0,0 +1,233 @@ ++## ++# vim: set fileencoding=utf-8 : ++# Copyright (c) 2008 Guido Guenther ++# ++# 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. ++# ++## ++ ++""" ++NSS Directory service interfaces. ++ ++Uses libc's Name Service Switch for user and groups (/etc/nsswitch.conf). ++Example caldavd.plist configuration: ++ ++ DirectoryService ++ ++ type ++ twistedcaldav.directory.nss.NssDirectoryService ++ ++ params ++ ++ realmName ++ Test Realm ++ ++ groupPrefix ++ caldavd- ++ ++ firstValidUid ++ 1000 ++ lastValidUid ++ 65533 ++ ++ firstValidGid ++ 1000 ++ lastValidGid ++ 65533 ++ ++ mailDomain ++ example.com ++ ++ ++ ++TODO: add enableCalendaring via a special group ++""" ++ ++__all__ = [ ++ "NssDirectoryService", ++] ++ ++from twistedcaldav.directory.directory import DirectoryService, DirectoryRecord ++from twisted.cred.credentials import UsernamePassword ++from twisted.python import log ++import pwd, grp, socket ++ ++class NsSwitch(object): ++ """Simple interface to the nsswitch calls""" ++ ++ def get_user(self, username): ++ try: ++ return pwd.getpwnam(username) ++ except KeyError: ++ return None ++ ++ def get_group(self, groupname): ++ try: ++ return grp.getgrnam(groupname) ++ except KeyError: ++ return None ++ ++ def get_users(self): ++ return pwd.getpwall() ++ ++ def get_groups(self): ++ return grp.getgrall() ++ ++ ++class NssDirectoryService(DirectoryService): ++ """ ++ Nss based Directory Service of L{IDirectoryService} ++ """ ++ ++ baseGUID = "8EFFFAF-5221-4813-B971-58506B963573" ++ ++ def __repr__(self): ++ return "<%s %r>" % (self.__class__.__name__, self.realmName) ++ ++ # Defaults are in twistedcaldav.config: ++ def __init__(self, realmName, groupPrefix, mailDomain, firstValidUid, lastValidUid, ++ firstValidGid, lastValidGid): ++ super(NssDirectoryService, self).__init__() ++ self.nsswitch = NsSwitch() ++ self.groupPrefix = groupPrefix ++ self.realmName = realmName ++ self.first_valid_uid = firstValidUid ++ self.first_valid_gid = firstValidGid ++ self.last_valid_uid = lastValidUid ++ self.last_valid_gid = lastValidGid ++ self.mailDomain = mailDomain ++ ++ def recordTypes(self): ++ recordTypes = ( ++ DirectoryService.recordType_users, ++ DirectoryService.recordType_groups, ++ ) ++ return recordTypes ++ ++ def _isValidUid(self, uid): ++ if uid >= self.first_valid_uid and uid <= self.last_valid_uid: ++ return True ++ ++ def _isValidGid(self, gid): ++ if gid >= self.first_valid_gid and gid <= self.last_valid_gid: ++ return True ++ ++ def listRecords(self, recordType): ++ """ ++ @param type: the type of records to retrieve. ++ @return: an iterable of records of the given type. ++ """ ++ if recordType == DirectoryService.recordType_users: ++ for result in self.nsswitch.get_users(): ++ if self._isValidUid(result[2]): ++ yield NssUserRecord( ++ service = self, ++ recordType = recordType, ++ shortName = result[0], ++ gecos = result[4], ++ ) ++ elif recordType == DirectoryService.recordType_groups: ++ for result in self.nsswitch.get_groups(): ++ if self._isValidGid(result[2]): ++ if result[0].startswith(self.groupPrefix): ++ yield NssGroupRecord( ++ service = self, ++ recordType = recordType, ++ groupName = result[0], ++ members = result[3], ++ ) ++ else: ++ raise AssertionError("Unknown record type: %r" % (recordType,)) ++ ++ def recordWithShortName(self, recordType, shortName): ++ if recordType == DirectoryService.recordType_users: ++ result = self.nsswitch.get_user(shortName) ++ if result and self._isValidUid(result[2]): ++ return NssUserRecord( ++ service = self, ++ recordType = recordType, ++ shortName = result[0], ++ gecos = result[4], ++ ) ++ else: ++ return None ++ elif recordType == DirectoryService.recordType_groups: ++ result = self.nsswitch.get_group(self.groupPrefix + shortName) ++ if result and self._isValidGid(result[2]): ++ return NssGroupRecord( ++ service = self, ++ recordType = recordType, ++ groupName = result[0], ++ members = result[3] ++ ) ++ else: ++ return None ++ else: ++ raise AssertionError("Unknown record type: %r" % (recordType,)) ++ ++ ++class NssDirectoryRecord(DirectoryRecord): ++ """ ++ Nss Directory Record ++ """ ++ def __init__(self, service, recordType, shortName, fullName = None, calendarUserAddresses = set()): ++ super(NssDirectoryRecord, self).__init__( ++ service = service, ++ recordType = recordType, ++ guid = None, ++ shortName = shortName, ++ fullName = fullName, ++ calendarUserAddresses = calendarUserAddresses, ++ autoSchedule = False, ++ ) ++ ++ ++class NssUserRecord(NssDirectoryRecord): ++ """ ++ NSS Users implementation of L{IDirectoryRecord}. ++ """ ++ def __init__(self, service, recordType, shortName, gecos): ++ fullName = gecos.split(",",1)[0] ++ calendarUserAddresses = set() ++ if service.mailDomain: ++ calendarUserAddresses.add("mailto:%s@%s" % (shortName, service.mailDomain)) ++ super(NssUserRecord, self).__init__(service, recordType, shortName, fullName, calendarUserAddresses) ++ ++ def verifyCredentials(self, credentials): ++ # FIXME: plugin in PAM authentication here if you want too - kerberos works ++ #return super(NssUserRecord, self).verifyCredentials(credentials) ++ return False ++ ++ def groups(self): ++ for group in self.service.listRecords(DirectoryService.recordType_groups): ++ for member in group.members(): ++ if member == self: ++ yield group ++ continue ++ ++ ++class NssGroupRecord(NssDirectoryRecord): ++ """ ++ NSS Groups implementation of L{IDirectoryRecord}. ++ """ ++ def __init__(self, service, recordType, groupName, members=()): ++ shortName = groupName.replace(service.groupPrefix,'',1) ++ super(NssGroupRecord, self).__init__(service, recordType, shortName) ++ self._members = members ++ ++ def members(self): ++ for shortName in self._members: ++ yield self.service.recordWithShortName(DirectoryService.recordType_users, shortName) ++ ++# vim:et:ts=4:sw=4:et:sts=4:ai:set list listchars=tab\:»·,trail\:·: +-- +1.5.5.1 + --- calendarserver-1.2.dfsg.orig/debian/patches/epydoc-fixes.diff +++ calendarserver-1.2.dfsg/debian/patches/epydoc-fixes.diff @@ -0,0 +1,144 @@ +fix epydoc errors + +diff --git a/twistedcaldav/admin/logs.py b/twistedcaldav/admin/logs.py +index f9bdb95..117bfbb 100644 +--- a/twistedcaldav/admin/logs.py ++++ b/twistedcaldav/admin/logs.py +@@ -16,12 +16,11 @@ + # DRI: David Reid, dreid@apple.com + ## + """ +- Log Stats: +- # Invitations sent per day/week/month +- # bytes out (bytes in not provided in the current log format.)/ +- # requests +- user agents +- ++Logging Statistics: ++ - # Invitations sent per day/week/month ++ - # bytes out (bytes in not provided in the current log format) ++ - # requests ++ - user agents + """ + + import plistlib +diff --git a/twistedcaldav/admin/principals.py b/twistedcaldav/admin/principals.py +index 07e80ee..64c018b 100644 +--- a/twistedcaldav/admin/principals.py ++++ b/twistedcaldav/admin/principals.py +@@ -16,11 +16,11 @@ + # DRI: David Reid, dreid@apple.com + ## + """ +- Account Stats: +- # of calendars +- # of events +- # storage used (including things that don't count against quota?) +- Last login? ++Account Stats: ++ - # of calendars ++ - # of events ++ - # storage used (including things that don't count against quota?) ++ - Last login? + """ + + from twistedcaldav.admin import util +diff --git a/twistedcaldav/admin/purge.py b/twistedcaldav/admin/purge.py +index d83bc8b..0085aa8 100644 +--- a/twistedcaldav/admin/purge.py ++++ b/twistedcaldav/admin/purge.py +@@ -25,12 +25,12 @@ def purgeEvents(collection, purgeDate): + Recursively purge all events older than purgeDate. + + for VTODO: +- * if completed +- * purge if it's dueDate is older than purgeDate. ++ - if completed ++ - purge if it's dueDate is older than purgeDate. + + for V*: +- * purge if endDate is older than purgeDate +- """ ++ - purge if endDate is older than purgeDate ++ """ + + from twistedcaldav import ical + +diff --git a/twistedcaldav/admin/script.py b/twistedcaldav/admin/script.py +index 4c22afc..d326ab6 100644 +--- a/twistedcaldav/admin/script.py ++++ b/twistedcaldav/admin/script.py +@@ -18,14 +18,10 @@ + + """ + Examples: +- +- caladmin users +- +- caladmin purge +- +- caladmin backup +- +- caladmin restore ++ - caladmin users ++ - caladmin purge ++ - caladmin backup ++ - caladmin restore + """ + + import sys, os +diff --git a/twistedcaldav/admin/stats.py b/twistedcaldav/admin/stats.py +index f2dfb75..ed7aa83 100644 +--- a/twistedcaldav/admin/stats.py ++++ b/twistedcaldav/admin/stats.py +@@ -19,10 +19,10 @@ + """ + Statisitcs Types: + +- Overall Stats: +- # of accounts +- # of calendars +- # of events ++ - Overall Stats: ++ - # of accounts ++ - # of calendars ++ - # of events + + """ + +diff --git a/twistedcaldav/py/plistlib.py b/twistedcaldav/py/plistlib.py +index 0084960..43fc69f 100644 +--- a/twistedcaldav/py/plistlib.py ++++ b/twistedcaldav/py/plistlib.py +@@ -23,7 +23,7 @@ UTF-8. + The plist type is supported through the Data class. This is a + thin wrapper around a Python string. + +-Generate Plist example: ++Generate Plist example:: + + pl = dict( + aString="Doodah", +@@ -44,7 +44,7 @@ Generate Plist example: + pl[u'\xc5benraa'] = "That was a unicode key." + writePlist(pl, fileName) + +-Parse Plist example: ++Parse Plist example:: + + pl = readPlist(pathOrFile) + print pl["aKey"] +diff --git a/twistedcaldav/static.py b/twistedcaldav/static.py +index 7d6edf0..8ec02bc 100644 +--- a/twistedcaldav/static.py ++++ b/twistedcaldav/static.py +@@ -296,8 +296,7 @@ class CalDAVFile (CalDAVResource, DAVFile): + def quotaSize(self, request): + """ + Get the size of this resource. +- TODO: Take into account size of dead-properties. Does stat +- include xattrs size? ++ TODO: Take into account size of dead-properties. Does stat include xattrs size? + + @return: an L{Deferred} with a C{int} result containing the size of the resource. + """