From 72a531ccf6207c076f405d699646ade19ac2d289 Mon Sep 17 00:00:00 2001 From: Christine Spang Date: Sun, 6 Jun 2010 14:49:55 -0400 Subject: [PATCH] add feature: configurable subject prefixing for mailing lists --- enemies-of-carlotta.1 | 5 +++++ eoc.py | 39 +++++++++++++++++++++++++++++++++++++-- eocTests.py | 29 +++++++++++++++++++++++++++++ 3 files changed, 71 insertions(+), 2 deletions(-) diff --git a/enemies-of-carlotta.1 b/enemies-of-carlotta.1 index 2fb10f5..5d97093 100644 --- a/enemies-of-carlotta.1 +++ b/enemies-of-carlotta.1 @@ -360,6 +360,11 @@ is set to "fi", then the template named "foo" is first searched as .B pristine\-headers Do not MIME encode the headers. Set to "yes" to not encode, anything else (including empty or unset) means encoding will happen. +.TP +.B subject\-prefix +A string to prepend to the "Subject" header of mails sent to this +list, such as "[list\-name]". The prefix will not be added to +subjects which already contain the prefix string. .SH EXAMPLES To create a list called .IR moviefans@example.com , diff --git a/eoc.py b/eoc.py index ac89923..e328a4a 100644 --- a/eoc.py +++ b/eoc.py @@ -469,6 +469,7 @@ class MailingList: self.cp.set("list", "ignore-bounce", "no") self.cp.set("list", "language", "") self.cp.set("list", "pristine-headers", "") + self.cp.set("list", "subject-prefix", "") self.dirname = os.path.join(self.mlm.dotdir, name) self.make_listdir() @@ -587,6 +588,7 @@ class MailingList: return if self.cp.get("list", "pristine-headers") != "yes": text = self.mime_encode_headers(text) + text = self.add_subject_prefix(text) self.mlm.send_mail(envelope_sender, recipients, text) def send_info_message(self, recipients, template_name, dict): @@ -730,6 +732,7 @@ class MailingList: def obey_owner(self, text): sender = get_from_environ("SENDER") recipients = self.cp.get("list", "owners").split() + text = self.add_subject_prefix(text) self.mlm.send_mail(sender, recipients, text) def obey_subscribe_or_unsubscribe(self, dict, template_name, command, @@ -877,7 +880,7 @@ class MailingList: else: return "" - def remove_some_headers(self, mail, headers_to_remove): + def headers_and_body(self, mail): endpos = mail.find("\n\n") if endpos == -1: endpos = mail.find("\n\r\n") @@ -885,7 +888,11 @@ class MailingList: return mail headers = mail[:endpos].split("\n") body = mail[endpos:] - + return (headers, body) + + def remove_some_headers(self, mail, headers_to_remove): + headers, body = self.headers_and_body(mail) + headers_to_remove = [x.lower() for x in headers_to_remove] remaining = [] @@ -933,6 +940,7 @@ class MailingList: "list-owner", "precedence"]) text = self.headers_to_add() + self.list_headers() + \ self.headers_to_remove(text) + text = self.add_subject_prefix(text) text = self.append_footer(text) text, = self.mlm.call_plugins("send_mail_to_subscribers_hook", self, text) @@ -945,6 +953,33 @@ class MailingList: addresses = self.subscribers.in_group(group) self.mlm.send_mail(bounce, addresses, text) + def add_subject_prefix(self, text): + """Given a full-text mail, munge its subject header with the configured + subject prefix (if any) and return the updated mail text. + """ + headers, body = self.headers_and_body(text) + + prefix = self.cp.get("list", "subject-prefix") + + # We don't need to do anything special to deal with multi-line + # subjects since adding the prefix to the first line of the subject + # and leaving the later lines untouched is sufficient. + if prefix: + has_subject = False + for header in headers: + if header.startswith('Subject:'): + has_subject = True + if prefix not in header: + text = text.replace(header, + header[:9] + prefix + " " + header[9:], 1) + break + # deal with the case where there was no Subject in the original + # mail (broken mailer?) + if not has_subject: + text = text.replace("\n\n", "Subject: " + prefix + "\n\n", 1) + + return text + def post_into_moderate(self, poster, dict, text): id = self.moderation_box.add(poster, text) recipients = self.moderators() diff --git a/eocTests.py b/eocTests.py index 1ecbfb1..ca60797 100644 --- a/eocTests.py +++ b/eocTests.py @@ -356,6 +356,7 @@ class ListOptionTestCases(ListBase): "ignore-bounce": "no", "language": "", "pristine-headers": "", + "subject-prefix": "", }) def testChangeOptions(self): @@ -382,6 +383,7 @@ class ListOptionTestCases(ListBase): "ignore-bounce": "no", "language": "", "pristine-headers": "", + "subject-prefix": "", }) class SubscriberDatabaseTestCases(ListBase): @@ -440,6 +442,33 @@ class SubscriberDatabaseTestCases(ListBase): subs.sort() self.failUnlessEqual(subs, addrs) + def testSubjectPrefix(self): + ml = self.mlm.create_list("prefix@example.com") + ml.cp.set("list", "subject-prefix", "[test]") + ml.save_config() + + self.failUnlessEqual(ml.cp.get("list", "subject-prefix"), "[test]") + + mail = """\ +To: test@example.com +From: test2@example.com +Subject: testing whether the subject prefix works +Precedence: bulk + +Body. +""" + prefixed_mail = ml.add_subject_prefix(mail) + + self.failUnlessEqual(prefixed_mail, """\ +To: test@example.com +From: test2@example.com +Subject: [test] testing whether the subject prefix works +Precedence: bulk + +Body. +""") + + class ModerationBoxTestCases(ListBase): def testModerationBox(self): -- 2.39.5