imip-agent

Changeset

1200:d0bf1870b447
2016-12-19 Paul Boddie raw files shortlog changelog graph Consolidate informational messages from handlers in summary messages. Add extra spacing between messages for clarity.
imiptools/handlers/__init__.py (file) imiptools/mail.py (file)
     1.1 --- a/imiptools/handlers/__init__.py	Sun Oct 23 23:21:01 2016 +0200
     1.2 +++ b/imiptools/handlers/__init__.py	Mon Dec 19 23:39:20 2016 +0100
     1.3 @@ -74,12 +74,20 @@
     1.4  
     1.5          texts = []
     1.6          texts.append(text)
     1.7 +
     1.8 +        # Add a link to the manager application if available and requested.
     1.9 +
    1.10          if link and self.have_manager():
    1.11              texts.append(_("If your mail program cannot handle this "
    1.12 -                           "message, you may view the details here:\n\n%s") %
    1.13 +                           "message, you may view the details here:\n\n%s\n") %
    1.14                           get_object_url(self.uid, self.recurrenceid))
    1.15  
    1.16 -        return self.add_result(None, None, MIMEText("\n".join(texts)))
    1.17 +        # Create the text part, tagging it with a header that allows this part
    1.18 +        # to be merged with other calendar information.
    1.19 +
    1.20 +        text_part = MIMEText("\n\n".join(texts))
    1.21 +        text_part["X-IMIP-Agent"] = "info"
    1.22 +        return self.add_result(None, None, text_part)
    1.23  
    1.24      # Result registration.
    1.25  
     2.1 --- a/imiptools/mail.py	Sun Oct 23 23:21:01 2016 +0200
     2.2 +++ b/imiptools/mail.py	Mon Dec 19 23:39:20 2016 +0100
     2.3 @@ -3,7 +3,7 @@
     2.4  """
     2.5  Mail preparation support.
     2.6  
     2.7 -Copyright (C) 2014, 2015 Paul Boddie <paul@boddie.org.uk>
     2.8 +Copyright (C) 2014, 2015, 2016 Paul Boddie <paul@boddie.org.uk>
     2.9  
    2.10  This program is free software; you can redistribute it and/or modify it under
    2.11  the terms of the GNU General Public License as published by the Free Software
    2.12 @@ -128,41 +128,104 @@
    2.13  
    2.14          """
    2.15          Return a simple summary using details from 'msg' and the given 'parts'.
    2.16 +        Information messages provided amongst the parts by the handlers will be
    2.17 +        merged into the preamble so that mail programs will show them
    2.18 +        immediately.
    2.19          """
    2.20  
    2.21 -        message = self._make_summary_for_parts(parts)
    2.22 +        message = self._make_summary_for_parts(parts, True)
    2.23          self._copy_headers(message, msg)
    2.24          return message
    2.25  
    2.26      def wrap_message(self, msg, parts):
    2.27  
    2.28 -        "Wrap 'msg' and provide the given 'parts' as the primary content."
    2.29 +        """
    2.30 +        Wrap 'msg' and provide the given 'parts' as the primary content.
    2.31 +        Information messages provided amongst the parts by the handlers will be
    2.32 +        merged into the preamble so that mail programs will show them
    2.33 +        immediately.
    2.34 +        """
    2.35  
    2.36 -        message = self._make_container_for_parts(parts)
    2.37 +        message = self._make_container_for_parts(parts, True)
    2.38          payload = message.get_payload()
    2.39          payload.append(MIMEMessage(msg))
    2.40          self._copy_headers(message, msg)
    2.41          return message
    2.42  
    2.43 -    def _make_summary_for_parts(self, parts):
    2.44 +    def _make_summary_for_parts(self, parts, merge=False):
    2.45  
    2.46 -        "Return a simple summary for the given 'parts'."
    2.47 +        """
    2.48 +        Return a simple summary for the given 'parts', merging information parts if
    2.49 +        'merge' is specified and set to a true value.
    2.50 +        """
    2.51  
    2.52          if len(parts) == 1:
    2.53              return parts[0]
    2.54          else:
    2.55 -            return self._make_container_for_parts(parts)
    2.56 +            return self._make_container_for_parts(parts, merge)
    2.57 +
    2.58 +    def _make_container_for_parts(self, parts, merge=False):
    2.59 +
    2.60 +        """
    2.61 +        Return a container for the given 'parts', merging information parts if
    2.62 +        'merge' is specified and set to a true value.
    2.63 +        """
    2.64  
    2.65 -    def _make_container_for_parts(self, parts):
    2.66 +        # Merge calendar information if requested.
    2.67  
    2.68 -        "Return a container for the given 'parts'."
    2.69 +        if merge:
    2.70 +            info, parts = self._merge_calendar_info_parts(parts)
    2.71 +        else:
    2.72 +            info = []
    2.73 +
    2.74 +        # Insert a preamble message before any calendar information messages.
    2.75 +
    2.76 +        info.insert(0, self.preamble_text or
    2.77 +                       self.gettext and self.gettext(PREAMBLE_TEXT) or PREAMBLE_TEXT)
    2.78  
    2.79          message = MIMEMultipart("mixed", _subparts=parts)
    2.80 -        message.preamble = self.preamble_text or \
    2.81 -            self.gettext and self.gettext(PREAMBLE_TEXT) or PREAMBLE_TEXT
    2.82 +        message.preamble = "\n\n".join(info)
    2.83          return message
    2.84  
    2.85 +    def _merge_calendar_info_parts(self, parts):
    2.86 +
    2.87 +        """
    2.88 +        Return a collection of plain text calendar information messages from
    2.89 +        'parts', together with a collection of the remaining parts.
    2.90 +        """
    2.91 +
    2.92 +        info = []
    2.93 +        remaining = []
    2.94 +
    2.95 +        for part in parts:
    2.96 +
    2.97 +            # Attempt to acquire informational messages.
    2.98 +
    2.99 +            if part.get("X-IMIP-Agent") == "info":
   2.100 +
   2.101 +                # Ignore the preamble of any multipart message and just
   2.102 +                # collect its parts.
   2.103 +
   2.104 +                if part.is_multipart():
   2.105 +                    i, r = self._merge_calendar_info_parts(part.get_payload())
   2.106 +                    remaining += r
   2.107 +
   2.108 +                # Obtain any single-part messages.
   2.109 +
   2.110 +                else:
   2.111 +                    info.append(part.get_payload(decode=True))
   2.112 +
   2.113 +            # Accumulate other parts regardless of their purpose.
   2.114 +
   2.115 +            else:
   2.116 +                remaining.append(part)
   2.117 +
   2.118 +        return info, remaining
   2.119 +
   2.120      def _copy_headers(self, message, msg):
   2.121 +
   2.122 +        "Copy to 'message' certain headers from 'msg'."
   2.123 +
   2.124          message["From"] = msg["From"]
   2.125          message["To"] = msg["To"]
   2.126          message["Subject"] = msg["Subject"]