[CalendarServer-changes] [2954] CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav
source_changes at macosforge.org
source_changes at macosforge.org
Tue Sep 9 11:48:26 PDT 2008
Revision: 2954
http://trac.macosforge.org/projects/calendarserver/changeset/2954
Author: cdaboo at apple.com
Date: 2008-09-09 11:48:26 -0700 (Tue, 09 Sep 2008)
Log Message:
-----------
Auto-accept now works.
Modified Paths:
--------------
CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/itip.py
CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/method/put_common.py
CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/scheduling/caldav.py
CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/scheduling/implicit.py
Modified: CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/itip.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/itip.py 2008-09-09 16:53:15 UTC (rev 2953)
+++ CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/itip.py 2008-09-09 18:48:26 UTC (rev 2954)
@@ -45,7 +45,7 @@
from twistedcaldav import caldavxml
from twistedcaldav.accounting import accountingEnabled, emitAccounting
from twistedcaldav.log import Logger
-from twistedcaldav.ical import Property, iCalendarProductID
+from twistedcaldav.ical import Property
from twistedcaldav.method import report_common
from twistedcaldav.resource import isCalendarCollectionResource
@@ -108,10 +108,8 @@
2. See if this updates existing ones in free-busy-set calendars.
3. Remove existing ones in those calendars.
4. See if this fits into a free slot:
- 1. If not, send REPLY with failure status
- 2. If so
- 1. send REPLY with success
- 2. add to f-b-s calendar
+ 1. If not, add to f-b-s calendar DECLINED
+ 2. If so, add to f-b-s calendar ACCEPTED
2. If not,
1. remove the one we got - its 'stale'
3. Delete the request from the Inbox.
@@ -153,30 +151,24 @@
if check_reply:
# Process the reply by determining PARTSTAT and sending the reply and booking the event.
- doreply, replycal, accepted = yield self.checkForReply()
+ valid, accepted = yield self.checkForReply()
- try:
- if accepted:
+ if valid:
+ try:
if calmatch:
+ log.info("Replaced calendar component %s with new iTIP message in %s (%s)." % (calmatch, calURL, accepted,))
yield self.writeResource(calURL, updatecal, calmatch, self.calendar)
- log.info("Replaced calendar component %s with new iTIP message in %s." % (calmatch, calURL))
else:
+ log.info("Added new calendar component in %s (%s)." % (calURL, accepted,))
yield self.writeResource(calURL, updatecal, None, self.calendar)
- log.info("Added new calendar component in %s." % (calURL,))
- else:
- if calmatch:
- yield self.deleteResource(updatecal, calmatch)
- log.info("Deleted calendar component %s in %s as update was not accepted." % (calmatch, calURL))
-
- # Send a reply if needed.
- if doreply:
- log.info("Sending iTIP REPLY %s" % (("declined","accepted")[accepted],))
- yield self.writeReply(replycal)
- processed = "processed"
- except:
- # FIXME: bare except
- log.err("Error while auto-processing iTIP: %s" % (Failure(),))
- raise iTipException()
+
+ processed = "processed"
+ except:
+ # FIXME: bare except
+ log.err("Error while auto-processing iTIP: %s" % (Failure(),))
+ raise iTipException()
+ else:
+ processed = "ignored"
else:
# So we have a partial update. That means we have to do partial updates to instances in
@@ -215,29 +207,26 @@
if check_reply:
# Process the reply by determining PARTSTAT and sending the reply and booking the event.
- doreply, replycal, accepted = yield self.checkForReply()
+ valid, accepted = yield self.checkForReply()
- try:
- if calmatch:
- # Merge the new instances with the old ones
- self.mergeComponents(self.calendar, cal)
- yield self.writeResource(calURL, updatecal, calmatch, cal)
- log.info("Merged calendar component %s with new iTIP message in %s." % (calmatch, calURL))
- else:
- if accepted:
+ if valid:
+ try:
+ if calmatch:
+ # Merge the new instances with the old ones
+ self.mergeComponents(self.calendar, cal)
+ log.info("Merged calendar component %s with new iTIP message in %s (%s)." % (calmatch, calURL, accepted,))
+ yield self.writeResource(calURL, updatecal, calmatch, cal)
+ else:
+ log.info("Added new calendar component in %s (%s)." % (calURL, accepted,))
yield self.writeResource(calURL, updatecal, None, self.calendar)
- log.info("Added new calendar component in %s." % (calURL,))
- # Do reply if needed.
- if doreply:
- log.info("Sending iTIP REPLY %s" % (("declined","accepted")[accepted],))
- yield self.writeReply(replycal)
-
- processed = "processed"
- except:
- # FIXME: bare except
- log.err("Error while auto-processing iTIP: %s" % (Failure(),))
- raise iTipException()
+ processed = "processed"
+ except:
+ # FIXME: bare except
+ log.err("Error while auto-processing iTIP: %s" % (Failure(),))
+ raise iTipException()
+ else:
+ processed = "ignored"
# Remove the now processed incoming request.
if self.inbox:
@@ -315,8 +304,8 @@
if self.compareSyncInfo(info, newinfo) < 0:
# Delete existing resource which has been cancelled
try:
- yield self.deleteResource(updatecal, calmatch,)
log.info("Delete calendar component %s in %s as it was cancelled." % (calmatch, calURL))
+ yield self.deleteResource(updatecal, calmatch,)
except:
# FIXME: bare except
log.err("Error while auto-processing iTIP: %s" % (Failure(),))
@@ -371,12 +360,12 @@
# in which case the calendar object is empty (except for VTIMEZONEs).
if existing_calendar.mainType() is None:
# Delete the now empty calendar object
- yield self.deleteResource(updatecal, calmatch)
log.info("Deleted calendar component %s after cancellations from iTIP message in %s." % (calmatch, calURL))
+ yield self.deleteResource(updatecal, calmatch)
else:
# Update the existing calendar object
- yield self.writeResource(calURL, updatecal, calmatch, existing_calendar)
log.info("Updated calendar component %s with cancellations from iTIP message in %s." % (calmatch, calURL))
+ yield self.writeResource(calURL, updatecal, calmatch, existing_calendar)
processed = "processed"
else:
processed = "older"
@@ -405,7 +394,7 @@
BTW The incoming iTIP message may contain multiple components so we need to iterate over all those.
At the moment we will treat a failure on one instance as a DECLINE of the entire set.
- @return: C{True} if a reply is needed, C{False} otherwise.
+ @return: a C{tuple} of C{bool} indicating whether a valid iTIP was received, and C{str} new partstat.
"""
# We need to figure out whether the specified component will clash with any others in the f-b-set calendars
@@ -454,58 +443,21 @@
cuas = self.principal.calendarUserAddresses()
attendeeProps = self.calendar.getAttendeeProperties(cuas)
if not attendeeProps:
- returnValue((False, None, accepted))
+ returnValue((False, accepted,))
- # Look for specific parameters
- rsvp = True
- for attendeeProp in attendeeProps:
- if "RSVP" in attendeeProp.params():
- if attendeeProp.params()["RSVP"][0] == "FALSE":
- rsvp = False
-
- # Now modify the original component
- del attendeeProp.params()["RSVP"]
-
if accepted:
partstat = "ACCEPTED"
else:
partstat = "DECLINED"
+
+ # Make sure declined events are TRANSPARENT on the calendar
+ self.calendar.replacePropertyInAllComponents(Property("TRANSP", "TRANSPARENT"))
+
for attendeeProp in attendeeProps:
- if "PARTSTAT" in attendeeProp.params():
- attendeeProp.params()["PARTSTAT"][0] = partstat
- else:
- attendeeProp.params()["PARTSTAT"] = [partstat]
+ attendeeProp.params()["PARTSTAT"] = [partstat]
- # Now create a new calendar object for the reply
-
- # First get useful props from the original
- replycal = self.calendar.duplicate()
-
- # Change METHOD
- replycal.getProperty("METHOD").setValue("REPLY")
-
- # Change PRODID to this server
- replycal.getProperty("PRODID").setValue(iCalendarProductID)
-
- # Add REQUEST-STATUS
- for component in replycal.subcomponents():
- if accepted:
- component.addProperty(Property(name="REQUEST-STATUS", value="2.0; Success."))
- else:
- component.addProperty(Property(name="REQUEST-STATUS", value="4.0; Event conflict. Date/time is busy."))
+ returnValue((True, accepted,))
- # Remove all attendees other than ourselves
- for component in replycal.subcomponents():
- if component.name() == "VTIMEZONE":
- continue
- attendeeProp = component.getAttendeeProperty(cuas)
- attendees = tuple(component.properties("ATTENDEE"))
- for attendee in attendees:
- if attendeeProp is None or (attendee.value() != attendeeProp.value()):
- component.removeProperty(attendee)
-
- returnValue((rsvp, replycal, accepted))
-
@inlineCallbacks
def writeReply(self, replycal):
"""
@@ -583,7 +535,8 @@
destinationparent = collection,
destinationcal = True,
calendar = calendar,
- isiTIP = itipper
+ isiTIP = itipper,
+ internal_request=True,
).run()
returnValue(newchild)
Modified: CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/method/put_common.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/method/put_common.py 2008-09-09 16:53:15 UTC (rev 2953)
+++ CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/method/put_common.py 2008-09-09 18:48:26 UTC (rev 2954)
@@ -183,6 +183,7 @@
calendar=None,
isiTIP=False,
allowImplicitSchedule=True,
+ internal_request=False,
):
"""
Function that does common PUT/COPY/MOVE behavior.
@@ -201,6 +202,7 @@
@param deletesource: True if the source resource is to be deleted on successful completion, False otherwise.
@param isiTIP: True if relaxed calendar data validation is to be done, False otherwise.
@param allowImplicitSchedule: True if implicit scheduling should be attempted, False otherwise.
+ @param internal_request: True if this request originates internally and needs to bypass scheduling authorization checks.
"""
# Check that all arguments are valid
@@ -239,6 +241,7 @@
self.deletesource = deletesource
self.isiTIP = isiTIP
self.allowImplicitSchedule = allowImplicitSchedule
+ self.internal_request = internal_request
self.rollback = None
self.access = None
@@ -690,7 +693,7 @@
# Do scheduling
if not self.isiTIP and self.allowImplicitSchedule:
scheduler = ImplicitScheduler()
- new_calendar = (yield scheduler.doImplicitScheduling(self.request, self.destination, self.calendar, False))
+ new_calendar = (yield scheduler.doImplicitScheduling(self.request, self.destination, self.calendar, False, internal_request=self.internal_request))
if new_calendar:
self.calendar = new_calendar
self.calendardata = str(self.calendar)
Modified: CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/scheduling/caldav.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/scheduling/caldav.py 2008-09-09 16:53:15 UTC (rev 2953)
+++ CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/scheduling/caldav.py 2008-09-09 18:48:26 UTC (rev 2954)
@@ -135,7 +135,7 @@
for principal, inbox, child in autoresponses:
# Add delayed reactor task to handle iTIP responses
itip = iTipProcessor()
- reactor.callLater(0.0, itip.handleRequest, *(self.scheduler.request, principal, inbox, self.scheduler.calendar.duplicate(), child))
+ reactor.callLater(2.0, itip.handleRequest, *(self.scheduler.request, principal, inbox, self.scheduler.calendar.duplicate(), child))
@inlineCallbacks
def generateResponse(self, recipient, responses, autoresponses):
@@ -147,20 +147,24 @@
childURL = joinURL(recipient.inboxURL, name)
child = (yield self.scheduler.request.locateResource(childURL))
- # Do implicit scheduling message processing
- try:
- processor = ImplicitProcessor()
- processed, autoprocessed = (yield processor.doImplicitProcessing(
- self.scheduler.request,
- self.scheduler.calendar,
- self.scheduler.originator,
- recipient
- ))
- except ImplicitProcessorException, e:
- log.err("Could not store data in Inbox : %s" % (recipient.inbox,))
- err = HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "recipient-permissions")))
- responses.add(recipient.cuaddr, Failure(exc_value=err), reqstatus=e.msg)
- returnValue(False)
+ # Do implicit scheduling message processing - but not for auto-accept principals.
+ # Auto-accepts will be processed internally by the server a little later on.
+ if not recipient.principal.autoSchedule():
+ try:
+ processor = ImplicitProcessor()
+ processed, autoprocessed = (yield processor.doImplicitProcessing(
+ self.scheduler.request,
+ self.scheduler.calendar,
+ self.scheduler.originator,
+ recipient
+ ))
+ except ImplicitProcessorException, e:
+ log.err("Could not store data in Inbox : %s" % (recipient.inbox,))
+ err = HTTPError(ErrorResponse(responsecode.FORBIDDEN, (caldav_namespace, "recipient-permissions")))
+ responses.add(recipient.cuaddr, Failure(exc_value=err), reqstatus=e.msg)
+ returnValue(False)
+ else:
+ processed = autoprocessed = False
if autoprocessed:
# No need to write the inbox item as it has already been auto-processed
@@ -198,7 +202,7 @@
child.writeDeadProperty(caldavxml.ScheduleState(caldavxml.ScheduleProcessed() if processed else caldavxml.ScheduleUnprocessed()))
# Look for auto-schedule option
- if not processed and recipient.principal.autoSchedule():
+ if recipient.principal.autoSchedule():
autoresponses.append((recipient.principal, recipient.inbox, child))
returnValue(True)
Modified: CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/scheduling/implicit.py
===================================================================
--- CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/scheduling/implicit.py 2008-09-09 16:53:15 UTC (rev 2953)
+++ CalendarServer/branches/users/cdaboo/implicitauto-2947/twistedcaldav/scheduling/implicit.py 2008-09-09 18:48:26 UTC (rev 2954)
@@ -47,7 +47,7 @@
pass
@inlineCallbacks
- def doImplicitScheduling(self, request, resource, calendar, deleting):
+ def doImplicitScheduling(self, request, resource, calendar, deleting, internal_request=False):
"""
Do implicit scheduling operation based on the calendar data that is being PUT
@@ -69,7 +69,7 @@
self.calendar = calendar
self.calendar_owner = (yield self.resource.owner(self.request))
self.deleting = deleting
- self.internal_request = False
+ self.internal_request = internal_request
self.except_attendees = ()
# When deleting we MUST have the calendar as the actual resource
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20080909/a6cd9e4c/attachment-0001.html
More information about the calendarserver-changes
mailing list