summaryrefslogtreecommitdiff
path: root/split-mailman-mails-and-discard-and-save
diff options
context:
space:
mode:
Diffstat (limited to 'split-mailman-mails-and-discard-and-save')
-rwxr-xr-xsplit-mailman-mails-and-discard-and-save91
1 files changed, 91 insertions, 0 deletions
diff --git a/split-mailman-mails-and-discard-and-save b/split-mailman-mails-and-discard-and-save
new file mode 100755
index 0000000..aec0bc8
--- /dev/null
+++ b/split-mailman-mails-and-discard-and-save
@@ -0,0 +1,91 @@
+#!/usr/bin/ruby
+
+require 'rmail'
+
+
+MAILIN="mail-in"
+SPAM="spam-learn"
+OUTBOX="outbox"
+
+DOMAIN='lists.oftc.net'
+FROM="listmoderators@lists.oftc.net"
+HOSTNAME=`hostname`.chop
+
+class Counter
+ @@counter = 0
+
+ def Counter.value
+ @@counter += 1
+ end
+end
+
+def uniqueName
+ "%d.%d_%d.%s"%[
+ Time.now.to_i,
+ $$,
+ Counter.value,
+ HOSTNAME]
+end
+
+def check_maildir(d)
+ throw "#{d} is not a maildir" unless FileTest.directory?(d)
+ throw "#{d} is not a maildir" unless FileTest.directory?(d+"/new")
+ throw "#{d} is not a maildir" unless FileTest.directory?(d+"/cur")
+ throw "#{d} is not a maildir" unless FileTest.directory?(d+"/tmp")
+ true
+end
+
+def store_in_maildir(md, msg)
+ fn = uniqueName
+ File.open(md+"/tmp/"+fn, "w", 0600) do |f|
+ f.puts msg
+ end
+ File.link(md+"/tmp/"+fn, md+"/new/"+fn)
+ File.unlink(md+"/tmp/"+fn)
+ md+"/new/"+fn
+end
+
+def process_mail(filename)
+ message = File.open(filename) { |f| RMail::Parser.read(f) }
+ # some sanity checks
+ throw "Mailman moderation mails are expected to have 3 mime parts" unless message.body.length == 3
+ throw "Mime Part 0 does have an unexpected content type: #{message.body[0].header['Content-Type']}" unless message.body[0].header['Content-Type'] == 'text/plain; charset="us-ascii"'
+ throw "Mime Part 1 does have an unexpected content type: #{message.body[1].header['Content-Type']}" unless message.body[1].header['Content-Type'] == 'message/rfc822'
+ throw "Mime Part 2 does have an unexpected content type: #{message.body[2].header['Content-Type']}" unless message.body[2].header['Content-Type'] == 'message/rfc822'
+ explanation_body = message.body[0].body
+ held_part = RMail::Parser.read( message.body[1].body )
+ discard_part = RMail::Parser.read( message.body[2].body )
+
+ # more sanity checks
+ throw "Did not find 'As list administrator, your..' boilerplate in mail" unless explanation_body =~ /^As list administrator, your authorization is requested for the/
+ throw "Did not find listname in mail" unless explanation_body =~ /^ *List: *.*@#{DOMAIN}/
+ throw "discard_part does have an unexpected content type: #{discard_part.header['Content-Type']}" unless discard_part.header['Content-Type'] == 'text/plain; charset="us-ascii"'
+
+ request_address = discard_part.header['From']
+ throw "discard_part does not have a from address" unless request_address
+
+ matchdata = /confirm ([0-9a-f]*)/.match discard_part.header['Subject']
+ throw "Could not find cookie in discard_part" unless matchdata and matchdata[1]
+ cookie = matchdata[1]
+
+ store_in_maildir(SPAM, held_part)
+ mail_request = RMail::Message.new()
+ mail_request.header['From'] = FROM
+ mail_request.header['To'] = request_address
+ mail_request.header['Subject'] = "Re: confirm #{cookie}"
+ mail_request.body = ''
+ store_in_maildir(OUTBOX, mail_request)
+end
+
+check_maildir MAILIN
+check_maildir SPAM
+check_maildir OUTBOX
+
+Dir[MAILIN+"/new/*"].each do |filename|
+ begin
+ process_mail filename
+ File.unlink filename
+ rescue Exception => e
+ STDERR.puts "Error when processing #{filename}: #{e}"
+ end
+end