# HG changeset patch # User Paul Boddie # Date 1482187160 -3600 # Node ID d0bf1870b447f4c9ff0b87125a3e77c6339a0774 # Parent 85897718c7ce45d3b4c373681c1e22a020a418f0 Consolidate informational messages from handlers in summary messages. Add extra spacing between messages for clarity. diff -r 85897718c7ce -r d0bf1870b447 imiptools/handlers/__init__.py --- a/imiptools/handlers/__init__.py Sun Oct 23 23:21:01 2016 +0200 +++ b/imiptools/handlers/__init__.py Mon Dec 19 23:39:20 2016 +0100 @@ -74,12 +74,20 @@ texts = [] texts.append(text) + + # Add a link to the manager application if available and requested. + if link and self.have_manager(): texts.append(_("If your mail program cannot handle this " - "message, you may view the details here:\n\n%s") % + "message, you may view the details here:\n\n%s\n") % get_object_url(self.uid, self.recurrenceid)) - return self.add_result(None, None, MIMEText("\n".join(texts))) + # Create the text part, tagging it with a header that allows this part + # to be merged with other calendar information. + + text_part = MIMEText("\n\n".join(texts)) + text_part["X-IMIP-Agent"] = "info" + return self.add_result(None, None, text_part) # Result registration. diff -r 85897718c7ce -r d0bf1870b447 imiptools/mail.py --- a/imiptools/mail.py Sun Oct 23 23:21:01 2016 +0200 +++ b/imiptools/mail.py Mon Dec 19 23:39:20 2016 +0100 @@ -3,7 +3,7 @@ """ Mail preparation support. -Copyright (C) 2014, 2015 Paul Boddie +Copyright (C) 2014, 2015, 2016 Paul Boddie This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software @@ -128,41 +128,104 @@ """ Return a simple summary using details from 'msg' and the given 'parts'. + Information messages provided amongst the parts by the handlers will be + merged into the preamble so that mail programs will show them + immediately. """ - message = self._make_summary_for_parts(parts) + message = self._make_summary_for_parts(parts, True) self._copy_headers(message, msg) return message def wrap_message(self, msg, parts): - "Wrap 'msg' and provide the given 'parts' as the primary content." + """ + Wrap 'msg' and provide the given 'parts' as the primary content. + Information messages provided amongst the parts by the handlers will be + merged into the preamble so that mail programs will show them + immediately. + """ - message = self._make_container_for_parts(parts) + message = self._make_container_for_parts(parts, True) payload = message.get_payload() payload.append(MIMEMessage(msg)) self._copy_headers(message, msg) return message - def _make_summary_for_parts(self, parts): + def _make_summary_for_parts(self, parts, merge=False): - "Return a simple summary for the given 'parts'." + """ + Return a simple summary for the given 'parts', merging information parts if + 'merge' is specified and set to a true value. + """ if len(parts) == 1: return parts[0] else: - return self._make_container_for_parts(parts) + return self._make_container_for_parts(parts, merge) + + def _make_container_for_parts(self, parts, merge=False): + + """ + Return a container for the given 'parts', merging information parts if + 'merge' is specified and set to a true value. + """ - def _make_container_for_parts(self, parts): + # Merge calendar information if requested. - "Return a container for the given 'parts'." + if merge: + info, parts = self._merge_calendar_info_parts(parts) + else: + info = [] + + # Insert a preamble message before any calendar information messages. + + info.insert(0, self.preamble_text or + self.gettext and self.gettext(PREAMBLE_TEXT) or PREAMBLE_TEXT) message = MIMEMultipart("mixed", _subparts=parts) - message.preamble = self.preamble_text or \ - self.gettext and self.gettext(PREAMBLE_TEXT) or PREAMBLE_TEXT + message.preamble = "\n\n".join(info) return message + def _merge_calendar_info_parts(self, parts): + + """ + Return a collection of plain text calendar information messages from + 'parts', together with a collection of the remaining parts. + """ + + info = [] + remaining = [] + + for part in parts: + + # Attempt to acquire informational messages. + + if part.get("X-IMIP-Agent") == "info": + + # Ignore the preamble of any multipart message and just + # collect its parts. + + if part.is_multipart(): + i, r = self._merge_calendar_info_parts(part.get_payload()) + remaining += r + + # Obtain any single-part messages. + + else: + info.append(part.get_payload(decode=True)) + + # Accumulate other parts regardless of their purpose. + + else: + remaining.append(part) + + return info, remaining + def _copy_headers(self, message, msg): + + "Copy to 'message' certain headers from 'msg'." + message["From"] = msg["From"] message["To"] = msg["To"] message["Subject"] = msg["Subject"]