[CalendarServer-changes] [2821] CalendarServer/branches/users/sagen/mailgateway-implicit-2745/ twistedcaldav

source_changes at macosforge.org source_changes at macosforge.org
Wed Aug 13 19:40:34 PDT 2008


Revision: 2821
          http://trac.macosforge.org/projects/calendarserver/changeset/2821
Author:   sagen at apple.com
Date:     2008-08-13 19:40:34 -0700 (Wed, 13 Aug 2008)
Log Message:
-----------
Refactoring DSN/reply processing a bit for testability

Modified Paths:
--------------
    CalendarServer/branches/users/sagen/mailgateway-implicit-2745/twistedcaldav/mail.py
    CalendarServer/branches/users/sagen/mailgateway-implicit-2745/twistedcaldav/test/test_mail.py

Modified: CalendarServer/branches/users/sagen/mailgateway-implicit-2745/twistedcaldav/mail.py
===================================================================
--- CalendarServer/branches/users/sagen/mailgateway-implicit-2745/twistedcaldav/mail.py	2008-08-13 21:56:59 UTC (rev 2820)
+++ CalendarServer/branches/users/sagen/mailgateway-implicit-2745/twistedcaldav/mail.py	2008-08-14 02:40:34 UTC (rev 2821)
@@ -284,7 +284,8 @@
 
 
     def __init__(self, path):
-        path = os.path.join(path, MailGatewayTokensDatabase.dbFilename)
+        if path != ":memory:":
+            path = os.path.join(path, MailGatewayTokensDatabase.dbFilename)
         super(MailGatewayTokensDatabase, self).__init__(path, True)
 
     def createToken(self, organizer, attendee):
@@ -515,13 +516,11 @@
 
             return True, action, calBody
 
-
         else:
             # Not a DSN
             return False, None, None
 
 
-
     def _extractToken(self, text):
         try:
             pre, post = text.split('@')
@@ -530,50 +529,33 @@
         except ValueError:
             return None
 
+    def processDSN(self, calBody, msgId, fn):
+        calendar = ical.Component.fromString(calBody)
+        # Extract the token (from organizer property)
+        organizer = calendar.getOrganizer()
+        token = self._extractToken(organizer)
+        if not token:
+            self.log_error("Mail gateway can't find token in DSN %s" % (msgId,))
+            return
 
-    def inbound(self, message):
-        msg = email.message_from_string(message)
+        result = self.db.lookupByToken(token)
+        if result is None:
+            # This isn't a token we recognize
+            self.log_error("Mail gateway found a token (%s) but didn't recognize it in DSN %s" % (token, msgId))
+            return
 
-        isDSN, action, calBody = self.checkDSN(msg)
-        if isDSN:
-            if action == 'failed' and calBody:
-                # This is a DSN we can handle
-                calendar = ical.Component.fromString(calBody)
-                # Extract the token (from organizer property)
-                organizer = calendar.getOrganizer()
-                token = self._extractToken(organizer)
-                if not token:
-                    self.log_error("Mail gateway can't find token in DSN %s" % (msg['Message-ID'],))
-                    return
+        organizer, attendee = result
+        organizer = str(organizer)
+        attendee = str(attendee)
+        calendar.removeAllButOneAttendee(attendee)
+        calendar.getOrganizerProperty().setValue(organizer)
+        calendar.addProperty(Property("REQUEST-STATUS",
+            "5.1;Service unavailable"))
 
-                result = self.db.lookupByToken(token)
-                if result is None:
-                    # This isn't a token we recognize
-                    self.log_error("Mail gateway found a token (%s) but didn't recognize it in DSN %s" % (token, msg['Message-ID']))
-                    return
+        self.log_error("Mail gateway processing DSN %s" % (msgId,))
+        return fn(organizer, attendee, calendar, msgId)
 
-                organizer, attendee = result
-                organizer = str(organizer)
-                attendee = str(attendee)
-                calendar.removeAllButOneAttendee(attendee)
-                calendar.getOrganizerProperty().setValue(organizer)
-                calendar.addProperty(Property("REQUEST-STATUS",
-                    "5.1;Service unavailable"))
-
-                self.log_error("Mail gateway processing DSN %s" % (msg['Message-ID'],))
-                return injectMessage(organizer, attendee, calendar,
-                    msg['Message-ID'])
-
-            else:
-                # It's a DSN without enough to go on
-                self.log_error("Mail gateway can't process DSN %s" % (msg['Message-ID'],))
-                return
-
-        self.log_info("Mail gateway received message %s from %s to %s" %
-            (msg['Message-ID'], msg['From'], msg['To']))
-
-        # TODO: make sure this is an email message we want to handle
-
+    def processReply(self, msg, fn):
         # extract the token from the To header
         name, addr = email.utils.parseaddr(msg['To'])
         if addr:
@@ -610,10 +592,29 @@
         attendee = str(attendee)
         calendar.removeAllButOneAttendee(attendee)
         calendar.getOrganizerProperty().setValue(organizer)
-        return injectMessage(organizer, attendee, calendar,
-            msg['Message-ID'])
+        return fn(organizer, attendee, calendar, msg['Message-ID'])
 
 
+    def inbound(self, message, fn=injectMessage):
+        msg = email.message_from_string(message)
+
+        isDSN, action, calBody = self.checkDSN(msg)
+        if isDSN:
+            if action == 'failed' and calBody:
+                # This is a DSN we can handle
+                return self.processDSN(calBody, msg['Message-ID'], fn)
+            else:
+                # It's a DSN without enough to go on
+                self.log_error("Mail gateway can't process DSN %s" % (msg['Message-ID'],))
+                return
+
+        self.log_info("Mail gateway received message %s from %s to %s" %
+            (msg['Message-ID'], msg['From'], msg['To']))
+
+        return self.processReply(msg, fn)
+
+
+
     def outbound(self, organizer, attendee, calendar):
         # create token, send email
         token = self.db.getToken(organizer, attendee)
@@ -646,6 +647,7 @@
         attendee = attendee[7:]
         message = message.replace("${toaddress}", attendee)
 
+        self.log_debug("Sending: %s" % (message,))
         def _success(result, msgId, fromAddr, toAddr):
             self.log_info("Mail gateway sent message %s from %s to %s" %
                 (msgId, fromAddr, toAddr))
@@ -674,6 +676,14 @@
         msgId = messageid()
         msg["Message-ID"] = msgId
 
+        # the icalendar attachment (putting this first because if we get a
+        # DSN failure in response, having this attachment in this position
+        # seems to increase the chance we will get it back in the DSN).
+        msgIcal = MIMEText(str(calendar), "calendar", "UTF-8")
+        msgIcal.add_header("Content-Disposition",
+            "attachment;filename=invitation.ics")
+        msg.attach(msgIcal)
+
         msgAlt = MIMEMultipart("alternative")
         msg.attach(msgAlt)
 
@@ -707,12 +717,6 @@
             (imageName,))
         msgHtmlRelated.attach(msgImage)
 
-        # the icalendar attachment
-        msgIcal = MIMEText(str(calendar), "calendar", "UTF-8")
-        msgIcal.add_header("Content-Disposition",
-            "attachment;filename=invitation.ics")
-        msg.attach(msgIcal)
-
         return msgId, msg.as_string()
 
     def _generateCalendarSummary(self, calendar, organizer):
@@ -1045,7 +1049,7 @@
             return
 
         d = self.factory.handleMessage(messageData)
-        if d:
+        if isinstance(d, defer.Deferred):
             d.addCallback(self.cbFlagDeleted, messageList)
         else:
             # No deferred returned, so no need for addCallback( )

Modified: CalendarServer/branches/users/sagen/mailgateway-implicit-2745/twistedcaldav/test/test_mail.py
===================================================================
--- CalendarServer/branches/users/sagen/mailgateway-implicit-2745/twistedcaldav/test/test_mail.py	2008-08-13 21:56:59 UTC (rev 2820)
+++ CalendarServer/branches/users/sagen/mailgateway-implicit-2745/twistedcaldav/test/test_mail.py	2008-08-14 02:40:34 UTC (rev 2821)
@@ -44,3 +44,27 @@
                 file(os.path.join(self.dataDir, filename)).read()
             )
             self.assertEquals(self.handler.checkDSN(msg), expected)
+
+
+    def test_processDSN(self):
+
+        template = 'BEGIN:VCALENDAR\nVERSION:2.0\nCALSCALE:GREGORIAN\nMETHOD:REQUEST\nPRODID:-//example Inc.//iCal 3.0//EN\nBEGIN:VTIMEZONE\nTZID:US/Pacific\nBEGIN:STANDARD\nDTSTART:20071104T020000\nRRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU\nTZNAME:PST\nTZOFFSETFROM:-0700\nTZOFFSETTO:-0800\nEND:STANDARD\nBEGIN:DAYLIGHT\nDTSTART:20070311T020000\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU\nTZNAME:PDT\nTZOFFSETFROM:-0800\nTZOFFSETTO:-0700\nEND:DAYLIGHT\nEND:VTIMEZONE\nBEGIN:VEVENT\nUID:1E71F9C8-AEDA-48EB-98D0-76E898F6BB5C\nDTSTART;TZID=US/Pacific:20080812T094500\nDTEND;TZID=US/Pacific:20080812T104500\nATTENDEE;CUTYPE=INDIVIDUAL;CN=User 01;PARTSTAT=ACCEPTED:mailto:user01 at exam\n ple.com\nATTENDEE;CUTYPE=INDIVIDUAL;RSVP=TRUE;ROLE=REQ-PARTICIPANT;PARTSTAT=NEEDS-A\n CTION;CN=nonexistant at example.com:mailto:nonexistant at example.com\nCREATED:20080812T191857Z\nDTSTAMP:20080812T191932Z\nORGANIZER;CN=User 01:mailto:xyzzy+%s at example.com\nSEQUENCE:2\nSUMMARY:New Event\nTRANSP:OPAQUE\nEND:VEVENT\nEND
 :VCALENDAR\n'
+        calBody = template % "bogus_token"
+
+        def echo(*args):
+            return args
+
+        self.assertEquals(self.handler.processDSN(calBody, "xyzzy", echo),
+           None)
+
+        token = self.handler.db.createToken("mailto:user01 at example.com",
+            "mailto:user02 at example.com")
+
+        calBody = template % token
+
+        organizer, attendee, calendar, msgId = self.handler.processDSN(calBody,
+            "xyzzy", echo)
+        self.assertEquals(organizer, 'mailto:user01 at example.com')
+        self.assertEquals(attendee, 'mailto:user02 at example.com')
+        self.assertEquals(str(calendar), 'BEGIN:VCALENDAR\r\nVERSION:2.0\r\nCALSCALE:GREGORIAN\r\nMETHOD:REQUEST\r\nPRODID:-//example Inc.//iCal 3.0//EN\r\nBEGIN:VTIMEZONE\r\nTZID:US/Pacific\r\nBEGIN:STANDARD\r\nDTSTART:20071104T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=11;BYDAY=1SU\r\nTZNAME:PST\r\nTZOFFSETFROM:-0700\r\nTZOFFSETTO:-0800\r\nEND:STANDARD\r\nBEGIN:DAYLIGHT\r\nDTSTART:20070311T020000\r\nRRULE:FREQ=YEARLY;BYMONTH=3;BYDAY=2SU\r\nTZNAME:PDT\r\nTZOFFSETFROM:-0800\r\nTZOFFSETTO:-0700\r\nEND:DAYLIGHT\r\nEND:VTIMEZONE\r\nREQUEST-STATUS:5.1\\;Service unavailable\r\nBEGIN:VEVENT\r\nUID:1E71F9C8-AEDA-48EB-98D0-76E898F6BB5C\r\nDTSTART;TZID=US/Pacific:20080812T094500\r\nDTEND;TZID=US/Pacific:20080812T104500\r\nCREATED:20080812T191857Z\r\nDTSTAMP:20080812T191932Z\r\nORGANIZER;CN=User 01:mailto:user01 at example.com\r\nSEQUENCE:2\r\nSUMMARY:New Event\r\nTRANSP:OPAQUE\r\nEND:VEVENT\r\nEND:VCALENDAR\r\n')
+        self.assertEquals(msgId, 'xyzzy')
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://lists.macosforge.org/pipermail/calendarserver-changes/attachments/20080813/3f067b5c/attachment-0001.html 


More information about the calendarserver-changes mailing list