diff options
Diffstat (limited to 'split-mailman-mails-and-discard-and-save')
-rwxr-xr-x | split-mailman-mails-and-discard-and-save | 91 |
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 |