[CalendarServer-changes] [2818] CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Wed Aug 13 12:35:58 PDT 2008
Revision: 2818
http://trac.macosforge.org/projects/calendarserver/changeset/2818
Author: cdaboo at apple.com
Date: 2008-08-13 12:35:58 -0700 (Wed, 13 Aug 2008)
Log Message:
-----------
Unroll some simple inlineCallbacks.
Modified Paths:
--------------
CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/fileops.py
CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/log.py
CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/method/put_common.py
CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/method/report_freebusy.py
CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/resource.py
CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/schedule.py
CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/addressmapping.py
CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/implicit.py
CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/ischedule.py
CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/scheduler.py
CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/timezoneservice.py
Modified: CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/fileops.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/fileops.py 2008-08-13 19:32:34 UTC (rev 2817)
+++ CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/fileops.py 2008-08-13 19:35:58 UTC (rev 2818)
@@ -18,7 +18,6 @@
Various file utilities.
"""
-from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.web2.dav.fileop import copy
from twisted.web2.dav.fileop import put
from twisted.web2.dav.xattrprops import xattrPropertyStore
@@ -29,7 +28,6 @@
def __init__(self, fp):
self.fp = fp
- at inlineCallbacks
def putWithXAttrs(stream, filepath):
"""
Write a file to a possibly existing path and preserve any xattrs at that path.
@@ -49,18 +47,21 @@
xold = None
# First do the actual file copy
- response = (yield put(stream, filepath))
+ def _gotResponse(response):
+
+ # Restore original xattrs.
+ if props:
+ xnew = xattrPropertyStore(FakeXAttrResource(filepath))
+ for prop in props:
+ xnew.set(prop)
+ xnew = None
+
+ return response
- # Restore original xattrs.
- if props:
- xnew = xattrPropertyStore(FakeXAttrResource(filepath))
- for prop in props:
- xnew.set(prop)
- xnew = None
+ d = put(stream, filepath)
+ d.addCallback(_gotResponse)
+ return d
- returnValue(response)
-
- at inlineCallbacks
def copyWithXAttrs(source_filepath, destination_filepath, destination_uri):
"""
Copy a file from one path to another and also copy xattrs we care about.
@@ -74,12 +75,16 @@
"""
# First do the actual file copy
- response = (yield copy(source_filepath, destination_filepath, destination_uri, "0"))
-
- # Now copy over xattrs.
- copyXAttrs(source_filepath, destination_filepath)
+ def _gotResponse(response):
- returnValue(response)
+ # Now copy over xattrs.
+ copyXAttrs(source_filepath, destination_filepath)
+
+ return response
+
+ d = copy(source_filepath, destination_filepath, destination_uri, "0")
+ d.addCallback(_gotResponse)
+ return d
def copyToWithXAttrs(from_fp, to_fp):
"""
Modified: CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/log.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/log.py 2008-08-13 19:32:34 UTC (rev 2817)
+++ CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/log.py 2008-08-13 19:35:58 UTC (rev 2818)
@@ -61,7 +61,7 @@
from StringIO import StringIO
-from twisted.internet.defer import inlineCallbacks
+from twisted.internet.defer import succeed
from twisted.web2 import responsecode
from twisted.web2.dav.util import allDataFromStream
@@ -201,7 +201,6 @@
"""
return cmpLogLevels(self.level(), level) <= 0
- @inlineCallbacks
def logRequest(self, level, message, request, **kwargs):
"""
Log an HTTP request.
@@ -229,15 +228,21 @@
# We need to play a trick with the request stream as we can only read it once. So we
# read it, store the value in a MemoryStream, and replace the request's stream with that,
# so the data can be read again.
- data = yield allDataFromStream(request.stream)
- iostr.write(data)
+ def _gotData(data):
+ iostr.write(data)
+
+ request.stream = MemoryStream(data)
+ request.stream.doStartReading = None
- request.stream = MemoryStream(data)
- request.stream.doStartReading = None
+ self.emit(level, iostr.getvalue(), **kwargs)
+
+ d = allDataFromStream(request.stream)
+ d.addCallback(_gotData)
+ return d
- self.emit(level, iostr.getvalue(), **kwargs)
+ else:
+ return succeed(None)
- @inlineCallbacks
def logResponse(self, level, message, response, **kwargs):
"""
Log an HTTP request.
@@ -262,13 +267,17 @@
# We need to play a trick with the response stream to ensure we don't mess it up. So we
# read it, store the value in a MemoryStream, and replace the response's stream with that,
# so the data can be read again.
- data = yield allDataFromStream(response.stream)
- iostr.write(data)
+ def _gotData(data):
+ iostr.write(data)
+
+ response.stream = MemoryStream(data)
+ response.stream.doStartReading = None
- response.stream = MemoryStream(data)
- response.stream.doStartReading = None
-
- self.emit(level, iostr.getvalue(), **kwargs)
+ self.emit(level, iostr.getvalue(), **kwargs)
+
+ d = allDataFromStream(response.stream)
+ d.addCallback(_gotData)
+ return d
class LoggingMixIn (object):
"""
Modified: CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/method/put_common.py 2008-08-13 19:32:34 UTC (rev 2817)
+++ CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/method/put_common.py 2008-08-13 19:35:58 UTC (rev 2818)
@@ -23,7 +23,7 @@
import types
from twisted.internet import reactor
-from twisted.internet.defer import Deferred, inlineCallbacks
+from twisted.internet.defer import Deferred, inlineCallbacks, succeed
from twisted.internet.defer import maybeDeferred, returnValue
from twisted.python import failure
from twisted.python.filepath import FilePath
@@ -240,7 +240,6 @@
self.rollback = None
self.access = None
- @inlineCallbacks
def fullValidation(self):
"""
Do full validation of source and destination calendar data.
@@ -306,7 +305,9 @@
# Check access
if self.destinationcal and config.EnablePrivateEvents:
- yield self.validAccess()
+ return self.validAccess()
+ else:
+ return succeed(None)
def validResourceName(self):
"""
@@ -389,7 +390,6 @@
return result, message
- @inlineCallbacks
def validAccess(self):
"""
Make sure that the X-CALENDARSERVER-ACCESS property is properly dealt with.
@@ -403,17 +403,25 @@
raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (calendarserver_namespace, "valid-access-restriction")))
# Only DAV:owner is able to set the property to other than PUBLIC
- parent_owner = (yield self.destinationparent.owner(self.request))
-
- authz = self.destinationparent.currentPrincipal(self.request)
- if davxml.Principal(parent_owner) != authz and self.access != Component.ACCESS_PUBLIC:
- raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (calendarserver_namespace, "valid-access-restriction-change")))
+ def _callback(parent_owner):
+
+ authz = self.destinationparent.currentPrincipal(self.request)
+ if davxml.Principal(parent_owner) != authz and self.access != Component.ACCESS_PUBLIC:
+ raise HTTPError(ErrorResponse(responsecode.FORBIDDEN, (calendarserver_namespace, "valid-access-restriction-change")))
+
+ return None
+
+ d = self.destinationparent.owner(self.request)
+ d.addCallback(_callback)
+ return d
else:
# Check whether an access property was present before and write that into the calendar data
if not self.source and self.destination.exists() and self.destination.hasDeadProperty(TwistedCalendarAccessProperty):
old_access = str(self.destination.readDeadProperty(TwistedCalendarAccessProperty))
self.calendar.addProperty(Property(name=Component.ACCESS_PROPERTY, value=old_access))
self.calendardata = str(self.calendar)
+
+ return succeed(None)
def noUIDConflict(self, uid):
"""
Modified: CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/method/report_freebusy.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/method/report_freebusy.py 2008-08-13 19:32:34 UTC (rev 2817)
+++ CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/method/report_freebusy.py 2008-08-13 19:35:58 UTC (rev 2818)
@@ -57,7 +57,6 @@
matchcount = [0]
- @inlineCallbacks
def generateFreeBusyInfo(calresource, uri): #@UnusedVariable
"""
Run a free busy report on the specified calendar collection
@@ -65,9 +64,15 @@
@param calresource: the L{CalDAVFile} for a calendar collection.
@param uri: the uri for the calendar collecton resource.
"""
- matchcount[0] = (yield report_common.generateFreeBusyInfo(request, calresource, fbinfo, timerange, matchcount[0]))
- returnValue(True)
+
+ def _gotResult(result):
+ matchcount[0] = result
+ return True
+ d = report_common.generateFreeBusyInfo(request, calresource, fbinfo, timerange, matchcount[0])
+ d.addCallback(_gotResult)
+ return d
+
# Run report taking depth into account
try:
depth = request.headers.getHeader("depth", "0")
Modified: CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/resource.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/resource.py 2008-08-13 19:32:34 UTC (rev 2817)
+++ CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/resource.py 2008-08-13 19:35:58 UTC (rev 2818)
@@ -344,40 +344,44 @@
acls = davxml.ACL(ace, *acls.children)
returnValue(acls)
- @inlineCallbacks
def owner(self, request):
"""
Return the DAV:owner property value (MUST be a DAV:href or None).
"""
- parent = (yield self.locateParent(request, request.urlForResource(self)))
- if parent and isinstance(parent, CalDAVResource):
- result = (yield parent.owner(request))
- returnValue(result)
- else:
- returnValue(None)
+
+ def _gotParent(parent):
+ if parent and isinstance(parent, CalDAVResource):
+ return parent.owner(request)
- @inlineCallbacks
+ d = self.locateParent(request, request.urlForResource(self))
+ d.addCallback(_gotParent)
+ return d
+
def ownerPrincipal(self, request):
"""
Return the DAV:owner property value (MUST be a DAV:href or None).
"""
- parent = (yield self.locateParent(request, request.urlForResource(self)))
- if parent and isinstance(parent, CalDAVResource):
- result = (yield parent.ownerPrincipal(request))
- returnValue(result)
- else:
- returnValue(None)
+ def _gotParent(parent):
+ if parent and isinstance(parent, CalDAVResource):
+ return parent.ownerPrincipal(request)
- @inlineCallbacks
+ d = self.locateParent(request, request.urlForResource(self))
+ d.addCallback(_gotParent)
+ return d
+
def isOwner(self, request):
"""
Determine whether the DAV:owner of this resource matches the currently authorized principal
in the request.
"""
- owner = (yield self.owner(request))
- returnValue(davxml.Principal(owner) == self.currentPrincipal(request))
+ def _gotOwner(owner):
+ return davxml.Principal(owner) == self.currentPrincipal(request)
+ d = self.owner(request)
+ d.addCallback(_gotOwner)
+ return d
+
##
# CalDAV
##
Modified: CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/schedule.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/schedule.py 2008-08-13 19:32:34 UTC (rev 2817)
+++ CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/schedule.py 2008-08-13 19:35:58 UTC (rev 2818)
@@ -280,7 +280,6 @@
def resourceType(self):
return davxml.ResourceType.scheduleOutbox
- @inlineCallbacks
def http_POST(self, request):
"""
The CalDAV POST method.
@@ -291,15 +290,18 @@
issues which the other approach would have with large numbers of recipients.
"""
# Check authentication and access controls
- yield self.authorize(request, (caldavxml.Schedule(),))
+ def _gotResult(_):
+
+ # This is a local CALDAV scheduling operation.
+ scheduler = CalDAVScheduler(request, self)
+
+ # Do the POST processing treating
+ return scheduler.doSchedulingViaPOST()
+
+ d = self.authorize(request, (caldavxml.Schedule(),))
+ d.addCallback(_gotResult)
+ return d
- # This is a local CALDAV scheduling operation.
- scheduler = CalDAVScheduler(request, self)
-
- # Do the POST processing treating
- response = (yield scheduler.doSchedulingViaPOST())
- returnValue(response)
-
class IScheduleInboxResource (CalDAVResource):
"""
iSchedule Inbox resource.
@@ -356,18 +358,21 @@
response.headers.setHeader("content-type", MimeType("text", "html"))
return response
- @inlineCallbacks
def http_POST(self, request):
"""
The server-to-server POST method.
"""
# Check authentication and access controls
- yield self.authorize(request, (caldavxml.Schedule(),))
+ def _gotResult(_):
+
+ # This is a server-to-server scheduling operation.
+ scheduler = IScheduleScheduler(request, self)
+
+ # Do the POST processing treating this as a non-local schedule
+ return scheduler.doSchedulingViaPOST()
- # This is a server-to-server scheduling operation.
- scheduler = IScheduleScheduler(request, self)
+ d = self.authorize(request, (caldavxml.Schedule(),))
+ d.addCallback(_gotResult)
+ return d
- # Do the POST processing treating this as a non-local schedule
- response = (yield scheduler.doSchedulingViaPOST())
- returnValue(response)
Modified: CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/addressmapping.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/addressmapping.py 2008-08-13 19:32:34 UTC (rev 2817)
+++ CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/addressmapping.py 2008-08-13 19:35:58 UTC (rev 2818)
@@ -81,11 +81,14 @@
returnValue(cuaddr_type)
- @inlineCallbacks
def isCalendarUserInMyDomain(self, cuaddr):
# Check whether it is a possible local address
- serviceType = (yield self.getCalendarUserServiceType(cuaddr))
- returnValue(serviceType == DeliveryService.serviceType_caldav)
+ def _gotResult(serviceType):
+ return serviceType == DeliveryService.serviceType_caldav
+
+ d = self.getCalendarUserServiceType(cuaddr)
+ d.addCallback(_gotResult)
+ return d
mapper = ScheduleAddressMapper()
Modified: CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/implicit.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/implicit.py 2008-08-13 19:32:34 UTC (rev 2817)
+++ CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/implicit.py 2008-08-13 19:35:58 UTC (rev 2818)
@@ -139,7 +139,6 @@
return False
- @inlineCallbacks
def doImplicitOrganizer(self):
# Check for a delete
@@ -172,7 +171,7 @@
self.oldcalendar = None
self.cancelledAttendees = ()
- yield self.scheduleWithAttendees()
+ return self.scheduleWithAttendees()
def isChangeInsignificant(self):
@@ -339,23 +338,20 @@
return no_itip
- @inlineCallbacks
def scheduleWithOrganizer(self):
itipmsg = iTipGenerator.generateAttendeeReply(self.calendar, self.attendee)
# Send scheduling message
- yield self.sendToOrganizer("REPLY", itipmsg)
+ return self.sendToOrganizer("REPLY", itipmsg)
- @inlineCallbacks
def scheduleCancelWithOrganizer(self):
itipmsg = iTipGenerator.generateAttendeeReply(self.calendar, self.attendee, True)
# Send scheduling message
- yield self.sendToOrganizer("CANCEL", itipmsg)
+ return self.sendToOrganizer("CANCEL", itipmsg)
- @inlineCallbacks
def sendToOrganizer(self, action, itipmsg):
# Send scheduling message
@@ -364,6 +360,11 @@
scheduler = CalDAVScheduler(self.request, self.resource)
# Do the PUT processing
+ def _gotResponse(response):
+ self.handleSchedulingResponse(response, False)
+
log.info("Implicit %s - attendee: '%s' to organizer: '%s', UID: '%s'" % (action, self.attendee, self.organizer, self.uid,))
- response = (yield scheduler.doSchedulingViaPUT(self.attendee, (self.organizer,), itipmsg))
- self.handleSchedulingResponse(response, False)
+ d = scheduler.doSchedulingViaPUT(self.attendee, (self.organizer,), itipmsg)
+ d.addCallback(_gotResponse)
+ return d
+
Modified: CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/ischedule.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/ischedule.py 2008-08-13 19:32:34 UTC (rev 2817)
+++ CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/ischedule.py 2008-08-13 19:35:58 UTC (rev 2818)
@@ -59,7 +59,6 @@
# Do default match
return super(ScheduleViaISchedule, cls).matchCalendarUserAddress(cuaddr)
- @inlineCallbacks
def generateSchedulingResponses(self):
"""
Generate scheduling responses for remote recipients.
@@ -101,7 +100,7 @@
requestor = IScheduleRequest(self.scheduler, server, recipients, self.responses)
deferreds.append(requestor.doRequest())
- yield DeferredList(deferreds)
+ return DeferredList(deferreds)
class IScheduleRequest(object):
Modified: CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/scheduler.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/scheduler.py 2008-08-13 19:32:34 UTC (rev 2817)
+++ CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/scheduling/scheduler.py 2008-08-13 19:35:58 UTC (rev 2818)
@@ -89,7 +89,6 @@
response = (yield self.doScheduling())
returnValue(response)
- @inlineCallbacks
def doSchedulingViaPUT(self, originator, recipients, calendar):
"""
The implicit scheduling PUT operation.
@@ -105,8 +104,7 @@
self.recipients = recipients
self.calendar = calendar
- response = (yield self.doScheduling())
- returnValue(response)
+ return self.doScheduling()
@inlineCallbacks
def doScheduling(self):
@@ -323,7 +321,6 @@
# Return with final response if we are done
returnValue(responses.response())
- @inlineCallbacks
def generateLocalSchedulingResponses(self, recipients, responses, freebusy):
"""
Generate scheduling responses for CalDAV recipients.
@@ -331,9 +328,8 @@
# Create the scheduler and run it.
requestor = ScheduleViaCalDAV(self, recipients, responses, freebusy)
- yield requestor.generateSchedulingResponses()
+ return requestor.generateSchedulingResponses()
- @inlineCallbacks
def generateRemoteSchedulingResponses(self, recipients, responses, freebusy):
"""
Generate scheduling responses for remote recipients.
@@ -341,9 +337,8 @@
# Create the scheduler and run it.
requestor = ScheduleViaISchedule(self, recipients, responses, freebusy)
- yield requestor.generateSchedulingResponses()
+ return requestor.generateSchedulingResponses()
- @inlineCallbacks
def generateIMIPSchedulingResponses(self, recipients, responses, freebusy):
"""
Generate scheduling responses for iMIP recipients.
@@ -351,7 +346,7 @@
# Create the scheduler and run it.
requestor = ScheduleViaIMip(self, recipients, responses, freebusy)
- yield requestor.generateSchedulingResponses()
+ return requestor.generateSchedulingResponses()
class CalDAVScheduler(Scheduler):
@@ -359,14 +354,12 @@
super(CalDAVScheduler, self).__init__(request, resource)
self.doingPOST = False
- @inlineCallbacks
def doSchedulingViaPOST(self):
"""
The Scheduling POST operation on an Outbox.
"""
self.doingPOST = True
- result = (yield super(CalDAVScheduler, self).doSchedulingViaPOST())
- returnValue(result)
+ return super(CalDAVScheduler, self).doSchedulingViaPOST()
def checkAuthorization(self):
# Must have an authenticated user
Modified: CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/timezoneservice.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/timezoneservice.py 2008-08-13 19:32:34 UTC (rev 2817)
+++ CalendarServer/branches/users/cdaboo/implicit-2799/twistedcaldav/timezoneservice.py 2008-08-13 19:35:58 UTC (rev 2818)
@@ -23,7 +23,6 @@
"TimezoneServiceResource",
]
-from twisted.internet.defer import inlineCallbacks, returnValue
from twisted.web2 import responsecode
from twisted.web2.dav import davxml
from twisted.web2.dav.http import ErrorResponse
@@ -105,36 +104,38 @@
# GET and POST do the same thing
return self.http_POST(request)
- @inlineCallbacks
def http_POST(self, request):
"""
The timezone service POST method.
"""
# Check authentication and access controls
- yield self.authorize(request, (davxml.Read(),))
-
- if not request.args:
- # Do normal GET behavior
- response = yield self.render(request)
- returnValue(response)
-
- method = request.args.get("method", ("",))
- if len(method) != 1:
- raise HTTPError(ErrorResponse(responsecode.BAD_REQUEST, (calendarserver_namespace, "valid-method")))
- method = method[0]
+ def _gotResult(_):
- action = {
- "list" : self.doPOSTList,
- "get" : self.doPOSTGet,
- "expand" : self.doPOSTExpand,
- }.get(method, None)
-
- if action is None:
- raise HTTPError(ErrorResponse(responsecode.BAD_REQUEST, (calendarserver_namespace, "supported-method")))
+ if not request.args:
+ # Do normal GET behavior
+ return self.render(request)
+
+ method = request.args.get("method", ("",))
+ if len(method) != 1:
+ raise HTTPError(ErrorResponse(responsecode.BAD_REQUEST, (calendarserver_namespace, "valid-method")))
+ method = method[0]
+
+ action = {
+ "list" : self.doPOSTList,
+ "get" : self.doPOSTGet,
+ "expand" : self.doPOSTExpand,
+ }.get(method, None)
+
+ if action is None:
+ raise HTTPError(ErrorResponse(responsecode.BAD_REQUEST, (calendarserver_namespace, "supported-method")))
+
+ return action(request)
+
+ d = self.authorize(request, (davxml.Read(),))
+ d.addCallback(_gotResult)
+ return d
- returnValue(action(request))
-
def doPOSTList(self, request):
"""
Return a list of all timezones known to the server.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20080813/aef259e0/attachment-0001.html
More information about the calendarserver-changes
mailing list