From be5e69a7dccaa6c76408f9b7883980bd79bdba28 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 15 Nov 2012 11:00:36 +0000 Subject: First skeletal version of separate mail handling library. --- lib/mail_handler/backends/mail_backend.rb | 12 ++++++++++++ lib/mail_handler/backends/tmail_backend.rb | 11 +++++++++++ 2 files changed, 23 insertions(+) create mode 100644 lib/mail_handler/backends/mail_backend.rb create mode 100644 lib/mail_handler/backends/tmail_backend.rb (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb new file mode 100644 index 000000000..ad1322923 --- /dev/null +++ b/lib/mail_handler/backends/mail_backend.rb @@ -0,0 +1,12 @@ +require 'mail' + +module MailHandler + module Backends + module MailBackend + + def backend() + 'Mail' + end + end + end +end \ No newline at end of file diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb new file mode 100644 index 000000000..b2d36d65f --- /dev/null +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -0,0 +1,11 @@ +module MailHandler + module Backends + module TmailBackend + + def backend() + 'TMail' + end + + end + end +end \ No newline at end of file -- cgit v1.2.3 From ca7bb3d9f7f7e38ca670dee4352a6c81e2b9d19a Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 15 Nov 2012 11:07:48 +0000 Subject: Move TMail monkey patch to MailHandler Tmail backend. --- lib/mail_handler/backends/tmail_backend.rb | 9 +++++++++ 1 file changed, 9 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index b2d36d65f..e5bfa3f49 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -1,3 +1,12 @@ +# Monkeypatch! Adding some extra members to store extra info in. +module TMail + class Mail + attr_accessor :url_part_number + attr_accessor :rfc822_attachment # when a whole email message is attached as text + attr_accessor :within_rfc822_attachment # for parts within a message attached as text (for getting subject mainly) + end +end + module MailHandler module Backends module TmailBackend -- cgit v1.2.3 From faa38d57e2eb87c288741e9cba5550e9532282ca Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 15 Nov 2012 11:38:32 +0000 Subject: Add methods for both backends to generate a mail object from raw data. --- lib/mail_handler/backends/mail_backend.rb | 5 +++++ lib/mail_handler/backends/tmail_backend.rb | 12 ++++++++++++ 2 files changed, 17 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index ad1322923..f7dbb7624 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -7,6 +7,11 @@ module MailHandler def backend() 'Mail' end + + def mail_from_raw_email(data) + Mail.new(data) + end + end end end \ No newline at end of file diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index e5bfa3f49..ff00d92df 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -15,6 +15,18 @@ module MailHandler 'TMail' end + # Turn raw data into a structured TMail::Mail object + # Documentation at http://i.loveruby.net/en/projects/tmail/doc/ + def mail_from_raw_email(data) + # Hack round bug in TMail's MIME decoding. + # Report of TMail bug: + # http://rubyforge.org/tracker/index.php?func=detail&aid=21810&group_id=4512&atid=17370 + copy_of_raw_data = data.gsub(/; boundary=\s+"/im,'; boundary="') + mail = TMail::Mail.parse(copy_of_raw_data) + mail.base64_decode + mail + end + end end end \ No newline at end of file -- cgit v1.2.3 From 8834f67db8cd94a0285dd1bb4702db834e08e995 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 15 Nov 2012 12:48:16 +0000 Subject: Use mail handler for making mail objects of attached emails. Add a flag to use base64 decoding or not. Note that currently the Mail-based backend doesn't use it - I think that eventually we'll want to have the mail handler wrap the mail object with it's own interface. --- lib/mail_handler/backends/mail_backend.rb | 3 ++- lib/mail_handler/backends/tmail_backend.rb | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index f7dbb7624..6a5fff13f 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -8,7 +8,8 @@ module MailHandler 'Mail' end - def mail_from_raw_email(data) + # Note that the decode flag is not yet used + def mail_from_raw_email(data, decode=true) Mail.new(data) end diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index ff00d92df..2f59b1161 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -17,13 +17,13 @@ module MailHandler # Turn raw data into a structured TMail::Mail object # Documentation at http://i.loveruby.net/en/projects/tmail/doc/ - def mail_from_raw_email(data) + def mail_from_raw_email(data, decode=true) # Hack round bug in TMail's MIME decoding. # Report of TMail bug: # http://rubyforge.org/tracker/index.php?func=detail&aid=21810&group_id=4512&atid=17370 copy_of_raw_data = data.gsub(/; boundary=\s+"/im,'; boundary="') mail = TMail::Mail.parse(copy_of_raw_data) - mail.base64_decode + mail.base64_decode if decode mail end -- cgit v1.2.3 From 4bdab94e9d4f0a64647e5f8534c1fea8b4ba2809 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 15 Nov 2012 14:04:55 +0000 Subject: Move TMail extensions to mail handler. --- lib/mail_handler/backends/tmail_backend.rb | 9 -- lib/mail_handler/backends/tmail_extensions.rb | 152 ++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 9 deletions(-) create mode 100644 lib/mail_handler/backends/tmail_extensions.rb (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 2f59b1161..fc675c1ed 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -1,12 +1,3 @@ -# Monkeypatch! Adding some extra members to store extra info in. -module TMail - class Mail - attr_accessor :url_part_number - attr_accessor :rfc822_attachment # when a whole email message is attached as text - attr_accessor :within_rfc822_attachment # for parts within a message attached as text (for getting subject mainly) - end -end - module MailHandler module Backends module TmailBackend diff --git a/lib/mail_handler/backends/tmail_extensions.rb b/lib/mail_handler/backends/tmail_extensions.rb new file mode 100644 index 000000000..bc994b9f3 --- /dev/null +++ b/lib/mail_handler/backends/tmail_extensions.rb @@ -0,0 +1,152 @@ +# lib/tmail_extensions.rb: +# Extensions / fixes to TMail. +# +# Copyright (c) 2009 UK Citizens Online Democracy. All rights reserved. +# Email: francis@mysociety.org; WWW: http://www.mysociety.org/ + +require 'racc/parser' +require 'tmail' +require 'tmail/scanner' +require 'tmail/utils' +require 'tmail/interface' + +# Monkeypatch! + +# These mainly used in app/models/incoming_message.rb +module TMail + class Mail + # Monkeypatch! Adding some extra members to store extra info in. + + attr_accessor :url_part_number + attr_accessor :rfc822_attachment # when a whole email message is attached as text + attr_accessor :within_rfc822_attachment # for parts within a message attached as text (for getting subject mainly) + + # Monkeypatch! (check to see if this becomes a standard function in + # TMail::Mail, then use that, whatever it is called) + def Mail.get_part_file_name(part) + file_name = (part['content-location'] && + part['content-location'].body) || + part.sub_header("content-type", "name") || + part.sub_header("content-disposition", "filename") + file_name = file_name.strip if file_name + file_name + end + + # Monkeypatch! Return the name part of from address, or nil if there isn't one + def from_name_if_present + if self.from && self.from_addrs[0].name + return TMail::Unquoter.unquote_and_convert_to(self.from_addrs[0].name, "utf-8") + else + return nil + end + end + + # Monkeypatch! Generalisation of To:, Cc: + def envelope_to(default = nil) + # XXX assumes only one envelope-to, and no parsing needed + val = self.header_string('envelope-to') + return val ? [val,] : [] + end + + # Monkeypatch! + # Bug fix to this function - is for message in humberside-police-odd-mime-type.email + # Which was originally: https://secure.mysociety.org/admin/foi/request/show_raw_email/11209 + # See test in spec/lib/tmail_extensions.rb + def set_content_type( str, sub = nil, param = nil ) + if sub + main, sub = str, sub + else + main, sub = str.split(%r, 2) + raise ArgumentError, "sub type missing: #{str.inspect}" unless sub + end + if h = @header['content-type'] + h.main_type = main + h.sub_type = sub + h.params.clear if !h.params.nil? # XXX this if statement is the fix # XXX disabled until works with test + else + store 'Content-Type', "#{main}/#{sub}" + end + @header['content-type'].params.replace param if param + str + end + # Need to make sure this alias calls the Monkeypatch too + alias content_type= set_content_type + + end + + class Address + # Monkeypatch! Constructor which makes a TMail::Address given + # a name and an email + def Address.address_from_name_and_email(name, email) + if !MySociety::Validate.is_valid_email(email) + raise "invalid email " + email + " passed to address_from_name_and_email" + end + if name.nil? + return TMail::Address.parse(email) + end + # Botch an always quoted RFC address, then parse it + name = name.gsub(/(["\\])/, "\\\\\\1") + return TMail::Address.parse('"' + name + '" <' + email + '>') + end + end + + module TextUtils + # Monkeypatch! Much more aggressive list of characters to cause quoting + # than in normal TMail. e.g. Have found real cases where @ needs quoting. + # We list characters to allow, rather than characters not to allow. + NEW_PHRASE_UNSAFE=/[^A-Za-z0-9!#\$%&'*+\-\/=?^_`{|}~ ]/n + def quote_phrase( str ) + (NEW_PHRASE_UNSAFE === str) ? dquote(str) : str + end + end +end + +# Monkeypatch! TMail 1.2.7.1 will parse only one address out of a list of addresses with +# unquoted display parts https://github.com/mikel/tmail/issues#issue/9 - this monkeypatch +# fixes this issue. +module TMail + + class Parser < Racc::Parser + +module_eval <<'..end lib/tmail/parser.y modeval..id2dd1c7d21d', 'lib/tmail/parser.y', 340 + + def self.special_quote_address(str) #:nodoc: + # Takes a string which is an address and adds quotation marks to special + # edge case methods that the RACC parser can not handle. + # + # Right now just handles two edge cases: + # + # Full stop as the last character of the display name: + # Mikel L. + # Returns: + # "Mikel L." + # + # Unquoted @ symbol in the display name: + # mikel@me.com + # Returns: + # "mikel@me.com" + # + # Any other address not matching these patterns just gets returned as is. + case + # This handles the missing "" in an older version of Apple Mail.app + # around the display name when the display name contains a '@' + # like 'mikel@me.com ' + # Just quotes it to: '"mikel@me.com" ' + when str =~ /\A([^"][^<]+@[^>]+[^"])\s(<.*?>)\Z/ + return "\"#{$1}\" #{$2}" + # This handles cases where 'Mikel A. ' which is a trailing + # full stop before the address section. Just quotes it to + # '"Mikel A." ' + when str =~ /\A(.*?\.)\s(<.*?>)\s*\Z/ + return "\"#{$1}\" #{$2}" + else + str + end + end + +..end lib/tmail/parser.y modeval..id2dd1c7d21d + end # class Parser + +end # module TMail + + -- cgit v1.2.3 From 388c75bfbd18fcaf273d95c21dc132ad19f0cefe Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 15 Nov 2012 16:12:23 +0000 Subject: Move handling of TNEF mail attachments to mail handler --- lib/mail_handler/backends/mail_backend.rb | 9 +++++++++ lib/mail_handler/backends/tmail_backend.rb | 13 +++++++++++++ 2 files changed, 22 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index 6a5fff13f..a6f2a6a44 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -13,6 +13,15 @@ module MailHandler Mail.new(data) end + # Extracts all attachments from the given TNEF file as a Mail object + def mail_from_tnef(content) + main = Mail.new + tnef_attachments(content).each do |attachment| + main.add_file(attachment) + end + main.ready_to_send! + main + end end end end \ No newline at end of file diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index fc675c1ed..4daa5469f 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -18,6 +18,19 @@ module MailHandler mail end + # Extracts all attachments from the given TNEF file as a TMail::Mail object + def mail_from_tnef(content) + main = TMail::Mail.new + main.set_content_type 'multipart', 'mixed', { 'boundary' => TMail.new_boundary } + tnef_attachments(content).each do |attachment| + tmail_attachment = TMail::Mail.new + tmail_attachment['content-location'] = attachment[:filename] + tmail_attachment.body = attachment[:content] + main.parts << tmail_attachment + end + main + end + end end end \ No newline at end of file -- cgit v1.2.3 From 9ef3f43fca535ffb52d2420bcfd8f18e5213b943 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 15 Nov 2012 16:21:38 +0000 Subject: Add some extra accessors to Mail::Message for now --- lib/mail_handler/backends/mail_extensions.rb | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 lib/mail_handler/backends/mail_extensions.rb (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_extensions.rb b/lib/mail_handler/backends/mail_extensions.rb new file mode 100644 index 000000000..cbe0491ed --- /dev/null +++ b/lib/mail_handler/backends/mail_extensions.rb @@ -0,0 +1,7 @@ +module Mail + class Message + attr_accessor :url_part_number + attr_accessor :rfc822_attachment # when a whole email message is attached as text + attr_accessor :within_rfc822_attachment # for parts within a message attached as text (for getting subject mainly) + end +end \ No newline at end of file -- cgit v1.2.3 From daf42a44bf019128374f3cc636d95b8308a01f2e Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 15 Nov 2012 16:39:46 +0000 Subject: Move _get_file_part_name to mail handler. --- lib/mail_handler/backends/mail_backend.rb | 7 +++++++ lib/mail_handler/backends/tmail_backend.rb | 10 ++++++++++ 2 files changed, 17 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index a6f2a6a44..fd2fa627f 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -22,6 +22,13 @@ module MailHandler main.ready_to_send! main end + + # Return a copy of the file name for the mail part + def get_part_file_name(mail_part) + part_file_name = mail_part.filename + part_file_name.nil? ? nil : part_file_name.dup + end + end end end \ No newline at end of file diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 4daa5469f..0fa90a657 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -31,6 +31,16 @@ module MailHandler main end + # Return a copy of the file name for the mail part + def get_part_file_name(mail_part) + part_file_name = TMail::Mail.get_part_file_name(mail_part) + if part_file_name.nil? + return nil + end + part_file_name = part_file_name.dup + return part_file_name + end + end end end \ No newline at end of file -- cgit v1.2.3 From f5ced2133cd1a66e18b225208fa96f4f36a20889 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 15 Nov 2012 16:56:06 +0000 Subject: Move address_from_name_and_email to mail handler. --- lib/mail_handler/backends/mail_backend.rb | 13 +++++++++++++ lib/mail_handler/backends/tmail_backend.rb | 11 +++++++++++ lib/mail_handler/backends/tmail_extensions.rb | 20 ++------------------ 3 files changed, 26 insertions(+), 18 deletions(-) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index fd2fa627f..bc4bf564c 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -29,6 +29,19 @@ module MailHandler part_file_name.nil? ? nil : part_file_name.dup end + # Format + def address_from_name_and_email(name, email) + if !MySociety::Validate.is_valid_email(email) + raise "invalid email " + email + " passed to address_from_name_and_email" + end + if name.nil? + return Mail::Address.new(email) + end + address = Mail::Address.new + address.display_name = name + address.address = email + address.to_s + end end end end \ No newline at end of file diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 0fa90a657..1c5489145 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -41,6 +41,17 @@ module MailHandler return part_file_name end + def address_from_name_and_email(name, email) + if !MySociety::Validate.is_valid_email(email) + raise "invalid email " + email + " passed to address_from_name_and_email" + end + if name.nil? + return TMail::Address.parse(email) + end + # Botch an always quoted RFC address, then parse it + name = name.gsub(/(["\\])/, "\\\\\\1") + TMail::Address.parse('"' + name + '" <' + email + '>').to_s + end end end end \ No newline at end of file diff --git a/lib/mail_handler/backends/tmail_extensions.rb b/lib/mail_handler/backends/tmail_extensions.rb index bc994b9f3..9359dfeea 100644 --- a/lib/mail_handler/backends/tmail_extensions.rb +++ b/lib/mail_handler/backends/tmail_extensions.rb @@ -74,22 +74,6 @@ module TMail end - class Address - # Monkeypatch! Constructor which makes a TMail::Address given - # a name and an email - def Address.address_from_name_and_email(name, email) - if !MySociety::Validate.is_valid_email(email) - raise "invalid email " + email + " passed to address_from_name_and_email" - end - if name.nil? - return TMail::Address.parse(email) - end - # Botch an always quoted RFC address, then parse it - name = name.gsub(/(["\\])/, "\\\\\\1") - return TMail::Address.parse('"' + name + '" <' + email + '>') - end - end - module TextUtils # Monkeypatch! Much more aggressive list of characters to cause quoting # than in normal TMail. e.g. Have found real cases where @ needs quoting. @@ -101,8 +85,8 @@ module TMail end end -# Monkeypatch! TMail 1.2.7.1 will parse only one address out of a list of addresses with -# unquoted display parts https://github.com/mikel/tmail/issues#issue/9 - this monkeypatch +# Monkeypatch! TMail 1.2.7.1 will parse only one address out of a list of addresses with +# unquoted display parts https://github.com/mikel/tmail/issues#issue/9 - this monkeypatch # fixes this issue. module TMail -- cgit v1.2.3 From 125ca970ad4e2b5e424265c632ae31c6dde62da7 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 15 Nov 2012 17:25:11 +0000 Subject: Wrap address parsing in a address_from_string method in the mail handler. --- lib/mail_handler/backends/mail_backend.rb | 4 ++++ lib/mail_handler/backends/tmail_backend.rb | 5 +++++ 2 files changed, 9 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index bc4bf564c..0e198adf0 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -42,6 +42,10 @@ module MailHandler address.address = email address.to_s end + + def address_from_string(string) + Mail::Address.new(string).address + end end end end \ No newline at end of file diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 1c5489145..0a1236e77 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -52,6 +52,11 @@ module MailHandler name = name.gsub(/(["\\])/, "\\\\\\1") TMail::Address.parse('"' + name + '" <' + email + '>').to_s end + + def address_from_string(string) + TMail::Address.parse(string).address + end + end end end \ No newline at end of file -- cgit v1.2.3 From 24c3ceb2315734ab6e43ae4f75673e251b98a96e Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 15 Nov 2012 17:44:08 +0000 Subject: Bugfix - need to convert to string in the just email address case. --- lib/mail_handler/backends/tmail_backend.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 0a1236e77..87aba73d7 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -46,7 +46,7 @@ module MailHandler raise "invalid email " + email + " passed to address_from_name_and_email" end if name.nil? - return TMail::Address.parse(email) + return TMail::Address.parse(email).to_s end # Botch an always quoted RFC address, then parse it name = name.gsub(/(["\\])/, "\\\\\\1") -- cgit v1.2.3 From 2864188de2e3eb1af03fd83cb10a3701ce8386ec Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 29 Nov 2012 13:05:01 +0000 Subject: Add method for getting the body of a mail part to mail handling modules. --- lib/mail_handler/backends/mail_backend.rb | 4 ++++ lib/mail_handler/backends/tmail_backend.rb | 4 ++++ 2 files changed, 8 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index 0e198adf0..b85ce64a6 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -29,6 +29,10 @@ module MailHandler part_file_name.nil? ? nil : part_file_name.dup end + def get_part_body(mail_part) + mail_part.body.decoded + end + # Format def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 87aba73d7..2a61a5d05 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -41,6 +41,10 @@ module MailHandler return part_file_name end + def get_part_body(mail_part) + mail_part.body + end + def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) raise "invalid email " + email + " passed to address_from_name_and_email" -- cgit v1.2.3 From bfb3fe634d8719336a40f1105d322ae2e9c2d0ad Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Mon, 3 Dec 2012 17:40:58 +0000 Subject: Delegate getting the from address of an incoming mail to the mail handler. --- lib/mail_handler/backends/mail_backend.rb | 17 +++++++++++++++++ lib/mail_handler/backends/tmail_backend.rb | 8 ++++++++ 2 files changed, 25 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index b85ce64a6..ac543540e 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -29,10 +29,27 @@ module MailHandler part_file_name.nil? ? nil : part_file_name.dup end + # Get the body of a mail part def get_part_body(mail_part) mail_part.body.decoded end + # Return the first from field if any + def first_from(mail) + if mail[:from] && mail[:from].addrs[0] + mail[:from].decoded + mail[:from].addrs[0] + else + nil + end + end + + # Return the first from address if any + def get_from_address(mail) + first_from = first_from(mail) + first_from ? first_from.address : nil + end + # Format def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 2a61a5d05..fa9f3fbb6 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -41,10 +41,18 @@ module MailHandler return part_file_name end + # Get the body of a mail part def get_part_body(mail_part) mail_part.body end + def get_from_address(mail) + if mail.from_addrs.nil? || mail.from_addrs.size == 0 + return nil + end + mail.from_addrs[0].spec + end + def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) raise "invalid email " + email + " passed to address_from_name_and_email" -- cgit v1.2.3 From 9b9b875f8bd2b1cd60f0bcce9ff6609be3d86998 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Mon, 3 Dec 2012 18:10:50 +0000 Subject: Move the specifics of getting a From: name from a mail to the mail handler. --- lib/mail_handler/backends/mail_backend.rb | 5 +++++ lib/mail_handler/backends/tmail_backend.rb | 4 ++++ 2 files changed, 9 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index ac543540e..87c0d6181 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -50,6 +50,11 @@ module MailHandler first_from ? first_from.address : nil end + def get_from_name(mail) + first_from = first_from(mail) + first_from ? first_from.name : nil + end + # Format def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index fa9f3fbb6..d2eed39d4 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -53,6 +53,10 @@ module MailHandler mail.from_addrs[0].spec end + def get_from_name(mail) + mail.from_name_if_present + end + def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) raise "invalid email " + email + " passed to address_from_name_and_email" -- cgit v1.2.3 From 5942318f3b1b091dbe96226f6360977443c40f58 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Mon, 3 Dec 2012 18:22:26 +0000 Subject: Add some comments. --- lib/mail_handler/backends/mail_backend.rb | 1 + lib/mail_handler/backends/tmail_backend.rb | 2 ++ 2 files changed, 3 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index 87c0d6181..6f965172b 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -50,6 +50,7 @@ module MailHandler first_from ? first_from.address : nil end + # Return the first from name if any def get_from_name(mail) first_from = first_from(mail) first_from ? first_from.name : nil diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index d2eed39d4..445a81124 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -46,6 +46,7 @@ module MailHandler mail_part.body end + # Return the first from address if any def get_from_address(mail) if mail.from_addrs.nil? || mail.from_addrs.size == 0 return nil @@ -53,6 +54,7 @@ module MailHandler mail.from_addrs[0].spec end + # Return the first from name if any def get_from_name(mail) mail.from_name_if_present end -- cgit v1.2.3 From 30dd01f931ae3dea9a56812387bfea2544818e31 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Mon, 3 Dec 2012 18:53:50 +0000 Subject: Get name and address specs to pass under Ruby 1.9 --- lib/mail_handler/backends/mail_backend.rb | 31 ++++++++++++++++++++++++++----- 1 file changed, 26 insertions(+), 5 deletions(-) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index 6f965172b..4a8bd446c 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -36,9 +36,14 @@ module MailHandler # Return the first from field if any def first_from(mail) - if mail[:from] && mail[:from].addrs[0] - mail[:from].decoded - mail[:from].addrs[0] + if mail[:from] + begin + mail[:from].addrs[0] + mail[:from].decoded + return mail[:from].addrs[0] + rescue + return mail[:from].value + end else nil end @@ -47,13 +52,29 @@ module MailHandler # Return the first from address if any def get_from_address(mail) first_from = first_from(mail) - first_from ? first_from.address : nil + if first_from + if first_from.is_a?(String) + return nil + else + return first_from.address + end + else + return nil + end end # Return the first from name if any def get_from_name(mail) first_from = first_from(mail) - first_from ? first_from.name : nil + if first_from + if first_from.is_a?(String) + return nil + else + return first_from.name + end + else + return nil + end end # Format -- cgit v1.2.3 From 9dfe9de140242c176eef8af65d78ced3f2992cc1 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Tue, 4 Dec 2012 09:53:16 +0000 Subject: Move method for getting the to, cc and envelope-to addresses of a mail to the mail handler. --- lib/mail_handler/backends/mail_backend.rb | 7 +++++++ lib/mail_handler/backends/tmail_backend.rb | 6 ++++++ 2 files changed, 13 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index 4a8bd446c..2b1cef0d4 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -77,6 +77,13 @@ module MailHandler end end + def get_all_addresses(mail) + envelope_to = mail['envelope-to'] ? [mail['envelope-to'].value] : [] + ((mail.to || []) + + (mail.cc || []) + + (envelope_to || [])).uniq + end + # Format def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 445a81124..b8fdb2c88 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -59,6 +59,12 @@ module MailHandler mail.from_name_if_present end + def get_all_addresses(mail) + ((mail.to || []) + + (mail.cc || []) + + (mail.envelope_to || [])).uniq + end + def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) raise "invalid email " + email + " passed to address_from_name_and_email" -- cgit v1.2.3 From 6052df14bab5fe82cd5ccf1979dbfc6d6ab3befa Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Tue, 4 Dec 2012 10:35:22 +0000 Subject: Add methods for finding out if there is an empty return path on a mail and getting the auto-submitted field. --- lib/mail_handler/backends/mail_backend.rb | 10 ++++++++++ lib/mail_handler/backends/tmail_backend.rb | 10 ++++++++++ 2 files changed, 20 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index 2b1cef0d4..b86f84cef 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -84,6 +84,16 @@ module MailHandler (envelope_to || [])).uniq end + def empty_return_path?(mail) + return false if mail['return-path'].nil? + return true if mail['return-path'].value.blank? + return false + end + + def get_auto_submitted(mail) + mail['auto-submitted'] ? mail['auto-submitted'].value : nil + end + # Format def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index b8fdb2c88..e725f7e9f 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -65,6 +65,16 @@ module MailHandler (mail.envelope_to || [])).uniq end + def empty_return_path?(mail) + return false if mail['return-path'].nil? + return true if mail['return-path'].addr.to_s == '<>' + return false + end + + def get_auto_submitted(mail) + mail['auto-submitted'] ? mail['auto-submitted'].body : nil + end + def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) raise "invalid email " + email + " passed to address_from_name_and_email" -- cgit v1.2.3 From 6ea3501d7b0bff1194955d0de716bd3f1aba3ca6 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Tue, 4 Dec 2012 11:23:38 +0000 Subject: Add specs for getting name, email and formatted address - make them pass with the mail backend. --- lib/mail_handler/backends/mail_backend.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index b86f84cef..aeca75ec5 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -70,7 +70,7 @@ module MailHandler if first_from.is_a?(String) return nil else - return first_from.name + return first_from.display_name ? eval(%Q{"#{first_from.display_name}"}) : nil end else return nil -- cgit v1.2.3 From 096c5c5613f426f2e5a73618e6a4e41bc06b57e2 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Tue, 4 Dec 2012 14:13:49 +0000 Subject: Adding methods for getting the content type of a mail part, and getting header strings from a mail. --- lib/mail_handler/backends/mail_backend.rb | 8 ++++++++ lib/mail_handler/backends/tmail_backend.rb | 8 ++++++++ 2 files changed, 16 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index aeca75ec5..8dd2e6b48 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -94,6 +94,14 @@ module MailHandler mail['auto-submitted'] ? mail['auto-submitted'].value : nil end + def get_content_type(part) + part.content_type ? part.content_type.split(';')[0] : nil + end + + def get_header_string(header, mail) + mail.header[header] ? mail.header[header].to_s : nil + end + # Format def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index e725f7e9f..4b7291d00 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -75,6 +75,14 @@ module MailHandler mail['auto-submitted'] ? mail['auto-submitted'].body : nil end + def get_content_type(part) + part.content_type + end + + def get_header_string(header, mail) + mail.header_string(header) + end + def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) raise "invalid email " + email + " passed to address_from_name_and_email" -- cgit v1.2.3 From 23ef65905eb75664d22459cfbe509ae7a6ad9377 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Wed, 5 Dec 2012 15:50:31 +0000 Subject: Move counters to mail object. --- lib/mail_handler/backends/mail_extensions.rb | 2 ++ lib/mail_handler/backends/tmail_extensions.rb | 2 ++ 2 files changed, 4 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_extensions.rb b/lib/mail_handler/backends/mail_extensions.rb index cbe0491ed..a3c70213c 100644 --- a/lib/mail_handler/backends/mail_extensions.rb +++ b/lib/mail_handler/backends/mail_extensions.rb @@ -3,5 +3,7 @@ module Mail attr_accessor :url_part_number attr_accessor :rfc822_attachment # when a whole email message is attached as text attr_accessor :within_rfc822_attachment # for parts within a message attached as text (for getting subject mainly) + attr_accessor :count_parts_count + attr_accessor :count_first_uudecode_count end end \ No newline at end of file diff --git a/lib/mail_handler/backends/tmail_extensions.rb b/lib/mail_handler/backends/tmail_extensions.rb index 9359dfeea..3576a8eca 100644 --- a/lib/mail_handler/backends/tmail_extensions.rb +++ b/lib/mail_handler/backends/tmail_extensions.rb @@ -20,6 +20,8 @@ module TMail attr_accessor :url_part_number attr_accessor :rfc822_attachment # when a whole email message is attached as text attr_accessor :within_rfc822_attachment # for parts within a message attached as text (for getting subject mainly) + attr_accessor :count_parts_count + attr_accessor :count_first_uudecode_count # Monkeypatch! (check to see if this becomes a standard function in # TMail::Mail, then use that, whatever it is called) -- cgit v1.2.3 From 6ceaadf8954c03d7d2723e639f7449de93fec6fa Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Wed, 5 Dec 2012 16:23:50 +0000 Subject: Move part counting to the mail handler. --- lib/mail_handler/backends/tmail_backend.rb | 48 ++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 4b7291d00..3f77f9f8b 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -83,6 +83,54 @@ module MailHandler mail.header_string(header) end + # Number the attachments in depth first tree order, for use in URLs. + # XXX This fills in part.rfc822_attachment and part.url_part_number within + # all the parts of the email (see monkeypatches in lib/mail_handler/tmail_extensions and + # lib/mail_handler/mail_extensions for how these attributes are added). ensure_parts_counted + # must be called before using the attributes. + def ensure_parts_counted(mail) + mail.count_parts_count = 0 + _count_parts_recursive(mail, mail) + # we carry on using these numeric ids for attachments uudecoded from within text parts + mail.count_first_uudecode_count = mail.count_parts_count + end + def _count_parts_recursive(part, mail) + if part.multipart? + part.parts.each do |p| + _count_parts_recursive(p, mail) + end + else + part_filename = MailHandler.get_part_file_name(part) + begin + if part.content_type == 'message/rfc822' + # An email attached as text + # e.g. http://www.whatdotheyknow.com/request/64/response/102 + part.rfc822_attachment = MailHandler.mail_from_raw_email(part.body, decode=false) + elsif part.content_type == 'application/vnd.ms-outlook' || part_filename && AlaveteliFileTypes.filename_to_mimetype(part_filename) == 'application/vnd.ms-outlook' + # An email attached as an Outlook file + # e.g. http://www.whatdotheyknow.com/request/chinese_names_for_british_politi + msg = Mapi::Msg.open(StringIO.new(part.body)) + part.rfc822_attachment = MailHandler.mail_from_raw_email(msg.to_mime.to_s, decode=false) + elsif part.content_type == 'application/ms-tnef' + # A set of attachments in a TNEF file + part.rfc822_attachment = MailHandler.mail_from_tnef(part.body) + end + rescue + # If attached mail doesn't parse, treat it as text part + part.rfc822_attachment = nil + else + unless part.rfc822_attachment.nil? + _count_parts_recursive(part.rfc822_attachment, mail) + end + end + if part.rfc822_attachment.nil? + mail.count_parts_count += 1 + part.url_part_number = mail.count_parts_count + end + end + end + + def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) raise "invalid email " + email + " passed to address_from_name_and_email" -- cgit v1.2.3 From 1b1527b30b6b10493eafd4b63d318bc14bd0d07f Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Wed, 5 Dec 2012 16:27:53 +0000 Subject: Move the getting of attachment leaves to the mail handler. --- lib/mail_handler/backends/tmail_backend.rb | 88 ++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 3f77f9f8b..4df4780a3 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -130,6 +130,94 @@ module MailHandler end end + # (This risks losing info if the unchosen alternative is the only one to contain + # useful info, but let's worry about that another time) + def get_attachment_leaves(mail) + return _get_attachment_leaves_recursive(mail, mail) + end + def _get_attachment_leaves_recursive(curr_mail, parent_mail, within_rfc822_attachment = nil) + leaves_found = [] + if curr_mail.multipart? + if curr_mail.parts.size == 0 + raise "no parts on multipart mail" + end + + if curr_mail.sub_type == 'alternative' + # Choose best part from alternatives + best_part = nil + # Take the last text/plain one, or else the first one + curr_mail.parts.each do |m| + if not best_part + best_part = m + elsif m.content_type == 'text/plain' + best_part = m + end + end + # Take an HTML one as even higher priority. (They tend + # to render better than text/plain, e.g. don't wrap links here: + # http://www.whatdotheyknow.com/request/amount_and_cost_of_freedom_of_in#incoming-72238 ) + curr_mail.parts.each do |m| + if m.content_type == 'text/html' + best_part = m + end + end + leaves_found += _get_attachment_leaves_recursive(best_part, parent_mail, within_rfc822_attachment) + else + # Add all parts + curr_mail.parts.each do |m| + leaves_found += _get_attachment_leaves_recursive(m, parent_mail, within_rfc822_attachment) + end + end + else + # XXX Yuck. this section alters various content_type's. That puts + # it into conflict with MailHandler.ensure_parts_counted which it has to be + # called both before and after. It will fail with cases of + # attachments of attachments etc. + charset = curr_mail.charset # save this, because overwriting content_type also resets charset + # Don't allow nil content_types + if curr_mail.content_type.nil? + curr_mail.content_type = 'application/octet-stream' + end + # PDFs often come with this mime type, fix it up for view code + if curr_mail.content_type == 'application/octet-stream' + part_file_name = MailHandler.get_part_file_name(curr_mail) + part_body = MailHandler.get_part_body(curr_mail) + calc_mime = AlaveteliFileTypes.filename_and_content_to_mimetype(part_file_name, part_body) + if calc_mime + curr_mail.content_type = calc_mime + end + end + + # Use standard content types for Word documents etc. + curr_mail.content_type = MailHandler.normalise_content_type(curr_mail.content_type) + if curr_mail.content_type == 'message/rfc822' + MailHandler.ensure_parts_counted(parent_mail) # fills in rfc822_attachment variable + if curr_mail.rfc822_attachment.nil? + # Attached mail didn't parse, so treat as text + curr_mail.content_type = 'text/plain' + end + end + if curr_mail.content_type == 'application/vnd.ms-outlook' || curr_mail.content_type == 'application/ms-tnef' + MailHandler.ensure_parts_counted(parent_mail) # fills in rfc822_attachment variable + if curr_mail.rfc822_attachment.nil? + # Attached mail didn't parse, so treat as binary + curr_mail.content_type = 'application/octet-stream' + end + end + # If the part is an attachment of email + if curr_mail.content_type == 'message/rfc822' || curr_mail.content_type == 'application/vnd.ms-outlook' || curr_mail.content_type == 'application/ms-tnef' + MailHandler.ensure_parts_counted(parent_mail) # fills in rfc822_attachment variable + leaves_found += _get_attachment_leaves_recursive(curr_mail.rfc822_attachment, parent_mail, curr_mail.rfc822_attachment) + else + # Store leaf + curr_mail.within_rfc822_attachment = within_rfc822_attachment + leaves_found += [curr_mail] + end + # restore original charset + curr_mail.charset = charset + end + return leaves_found + end def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) -- cgit v1.2.3 From 53faf19864cc8bbf872de889e6f59574fc92950c Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Wed, 5 Dec 2012 16:34:12 +0000 Subject: Remove redundant references to MailHandler. --- lib/mail_handler/backends/tmail_backend.rb | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 4df4780a3..4e9cf6628 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -100,20 +100,20 @@ module MailHandler _count_parts_recursive(p, mail) end else - part_filename = MailHandler.get_part_file_name(part) + part_filename = get_part_file_name(part) begin if part.content_type == 'message/rfc822' # An email attached as text # e.g. http://www.whatdotheyknow.com/request/64/response/102 - part.rfc822_attachment = MailHandler.mail_from_raw_email(part.body, decode=false) + part.rfc822_attachment = mail_from_raw_email(part.body, decode=false) elsif part.content_type == 'application/vnd.ms-outlook' || part_filename && AlaveteliFileTypes.filename_to_mimetype(part_filename) == 'application/vnd.ms-outlook' # An email attached as an Outlook file # e.g. http://www.whatdotheyknow.com/request/chinese_names_for_british_politi msg = Mapi::Msg.open(StringIO.new(part.body)) - part.rfc822_attachment = MailHandler.mail_from_raw_email(msg.to_mime.to_s, decode=false) + part.rfc822_attachment = mail_from_raw_email(msg.to_mime.to_s, decode=false) elsif part.content_type == 'application/ms-tnef' # A set of attachments in a TNEF file - part.rfc822_attachment = MailHandler.mail_from_tnef(part.body) + part.rfc822_attachment = mail_from_tnef(part.body) end rescue # If attached mail doesn't parse, treat it as text part @@ -170,7 +170,7 @@ module MailHandler end else # XXX Yuck. this section alters various content_type's. That puts - # it into conflict with MailHandler.ensure_parts_counted which it has to be + # it into conflict with ensure_parts_counted which it has to be # called both before and after. It will fail with cases of # attachments of attachments etc. charset = curr_mail.charset # save this, because overwriting content_type also resets charset @@ -180,8 +180,8 @@ module MailHandler end # PDFs often come with this mime type, fix it up for view code if curr_mail.content_type == 'application/octet-stream' - part_file_name = MailHandler.get_part_file_name(curr_mail) - part_body = MailHandler.get_part_body(curr_mail) + part_file_name = get_part_file_name(curr_mail) + part_body = get_part_body(curr_mail) calc_mime = AlaveteliFileTypes.filename_and_content_to_mimetype(part_file_name, part_body) if calc_mime curr_mail.content_type = calc_mime @@ -189,16 +189,16 @@ module MailHandler end # Use standard content types for Word documents etc. - curr_mail.content_type = MailHandler.normalise_content_type(curr_mail.content_type) + curr_mail.content_type = normalise_content_type(curr_mail.content_type) if curr_mail.content_type == 'message/rfc822' - MailHandler.ensure_parts_counted(parent_mail) # fills in rfc822_attachment variable + ensure_parts_counted(parent_mail) # fills in rfc822_attachment variable if curr_mail.rfc822_attachment.nil? # Attached mail didn't parse, so treat as text curr_mail.content_type = 'text/plain' end end if curr_mail.content_type == 'application/vnd.ms-outlook' || curr_mail.content_type == 'application/ms-tnef' - MailHandler.ensure_parts_counted(parent_mail) # fills in rfc822_attachment variable + ensure_parts_counted(parent_mail) # fills in rfc822_attachment variable if curr_mail.rfc822_attachment.nil? # Attached mail didn't parse, so treat as binary curr_mail.content_type = 'application/octet-stream' @@ -206,7 +206,7 @@ module MailHandler end # If the part is an attachment of email if curr_mail.content_type == 'message/rfc822' || curr_mail.content_type == 'application/vnd.ms-outlook' || curr_mail.content_type == 'application/ms-tnef' - MailHandler.ensure_parts_counted(parent_mail) # fills in rfc822_attachment variable + ensure_parts_counted(parent_mail) # fills in rfc822_attachment variable leaves_found += _get_attachment_leaves_recursive(curr_mail.rfc822_attachment, parent_mail, curr_mail.rfc822_attachment) else # Store leaf -- cgit v1.2.3 From 8d7a02933e9d867bd2d3ce2209df2c80a316fe34 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Wed, 5 Dec 2012 16:35:35 +0000 Subject: Fix typo. --- lib/mail_handler/backends/tmail_backend.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 4e9cf6628..92d478541 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -169,7 +169,7 @@ module MailHandler end end else - # XXX Yuck. this section alters various content_type's. That puts + # XXX Yuck. this section alters various content_types. That puts # it into conflict with ensure_parts_counted which it has to be # called both before and after. It will fail with cases of # attachments of attachments etc. -- cgit v1.2.3 From 0375214ca0c295f0316ec80be8aebdbd1d1c1b8a Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Wed, 5 Dec 2012 16:41:43 +0000 Subject: Add a wrapper method for get_attachment_leaves. --- lib/mail_handler/backends/tmail_backend.rb | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 92d478541..9bcc2ab1f 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -130,6 +130,14 @@ module MailHandler end end + def get_attachment_attributes(mail) + leaves = get_attachment_leaves(mail) + # XXX we have to call ensure_parts_counted after get_attachment_leaves + # which is really messy. + ensure_parts_counted(mail) + leaves + end + # (This risks losing info if the unchosen alternative is the only one to contain # useful info, but let's worry about that another time) def get_attachment_leaves(mail) -- cgit v1.2.3 From 7f79f32bd1021fde6a4c026072febcfabc6d0c72 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Wed, 5 Dec 2012 16:57:38 +0000 Subject: Move mail-specific stuff to mail handler. --- lib/mail_handler/backends/tmail_backend.rb | 47 +++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 9bcc2ab1f..f28eaad79 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -135,7 +135,52 @@ module MailHandler # XXX we have to call ensure_parts_counted after get_attachment_leaves # which is really messy. ensure_parts_counted(mail) - leaves + attachment_attributes = [] + for leaf in leaves + body = MailHandler.get_part_body(leaf) + # As leaf.body causes MIME decoding which uses lots of RAM, do garbage collection here + # to prevent excess memory use. XXX not really sure if this helps reduce + # peak RAM use overall. Anyway, maybe there is something better to do than this. + GC.start + if leaf.within_rfc822_attachment + within_rfc822_subject = leaf.within_rfc822_attachment.subject + # Test to see if we are in the first part of the attached + # RFC822 message and it is text, if so add headers. + # XXX should probably use hunting algorithm to find main text part, rather than + # just expect it to be first. This will do for now though. + # Example request that needs this: + # http://www.whatdotheyknow.com/request/2923/response/7013/attach/2/Cycle%20Path%20Bank.txt + if leaf.within_rfc822_attachment == leaf && leaf.content_type == 'text/plain' + headers = "" + for header in [ 'Date', 'Subject', 'From', 'To', 'Cc' ] + if leaf.within_rfc822_attachment.header.include?(header.downcase) + header_value = leaf.within_rfc822_attachment.header[header.downcase] + # Example message which has a blank Date header: + # http://www.whatdotheyknow.com/request/30747/response/80253/attach/html/17/Common%20Purpose%20Advisory%20Group%20Meeting%20Tuesday%202nd%20March.txt.html + if !header_value.blank? + headers = headers + header + ": " + header_value.to_s + "\n" + end + end + end + # XXX call _convert_part_body_to_text here, but need to get charset somehow + # e.g. http://www.whatdotheyknow.com/request/1593/response/3088/attach/4/Freedom%20of%20Information%20request%20-%20car%20oval%20sticker:%20Article%2020,%20Convention%20on%20Road%20Traffic%201949.txt + body = headers + "\n" + body + + # This is quick way of getting all headers, but instead we only add some a) to + # make it more usable, b) as at least one authority accidentally leaked security + # information into a header. + #attachment.body = leaf.within_rfc822_attachment.port.to_s + end + end + attachment_attributes << {:url_part_number => leaf.url_part_number, + :content_type => MailHandler.get_content_type(leaf), + :filename => MailHandler.get_part_file_name(leaf), + :charset => leaf.charset, + :within_rfc822_subject => within_rfc822_subject, + :body => body, + :hexdigest => Digest::MD5.hexdigest(body) } + end + attachment_attributes end # (This risks losing info if the unchosen alternative is the only one to contain -- cgit v1.2.3 From 3a55a3eb5601bbb3ae83d32bc92ffdd9a27961c4 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Wed, 5 Dec 2012 17:00:18 +0000 Subject: Remove redundant references to MailHandler --- lib/mail_handler/backends/tmail_backend.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index f28eaad79..3ce82a50c 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -137,7 +137,7 @@ module MailHandler ensure_parts_counted(mail) attachment_attributes = [] for leaf in leaves - body = MailHandler.get_part_body(leaf) + body = get_part_body(leaf) # As leaf.body causes MIME decoding which uses lots of RAM, do garbage collection here # to prevent excess memory use. XXX not really sure if this helps reduce # peak RAM use overall. Anyway, maybe there is something better to do than this. @@ -173,8 +173,8 @@ module MailHandler end end attachment_attributes << {:url_part_number => leaf.url_part_number, - :content_type => MailHandler.get_content_type(leaf), - :filename => MailHandler.get_part_file_name(leaf), + :content_type => get_content_type(leaf), + :filename => get_part_file_name(leaf), :charset => leaf.charset, :within_rfc822_subject => within_rfc822_subject, :body => body, -- cgit v1.2.3 From 1a6d02ca2e41613bad017a449fd3f28af251f903 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Wed, 5 Dec 2012 19:22:20 +0000 Subject: Standardise on part as a param name, not mail_part. --- lib/mail_handler/backends/mail_backend.rb | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index 8dd2e6b48..842a0ecaf 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -24,14 +24,14 @@ module MailHandler end # Return a copy of the file name for the mail part - def get_part_file_name(mail_part) - part_file_name = mail_part.filename + def get_part_file_name(part) + part_file_name = part.filename part_file_name.nil? ? nil : part_file_name.dup end # Get the body of a mail part - def get_part_body(mail_part) - mail_part.body.decoded + def get_part_body(part) + part.body.decoded end # Return the first from field if any -- cgit v1.2.3 From c029763353aa3b762e735bb7ed3523d11a53a032 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Wed, 5 Dec 2012 19:36:37 +0000 Subject: Convert address to string in the case where there's just an address. --- lib/mail_handler/backends/mail_backend.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index 842a0ecaf..30a85ed59 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -108,7 +108,7 @@ module MailHandler raise "invalid email " + email + " passed to address_from_name_and_email" end if name.nil? - return Mail::Address.new(email) + return Mail::Address.new(email).to_s end address = Mail::Address.new address.display_name = name -- cgit v1.2.3 From 74029c7c3994fa09374ea92be01138999a65af0a Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 6 Dec 2012 09:04:26 +0000 Subject: Patch the Message initialize method so that it doesn't strip the initial input - trailing spaces can be meaningful. --- lib/mail_handler/backends/mail_extensions.rb | 39 ++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_extensions.rb b/lib/mail_handler/backends/mail_extensions.rb index a3c70213c..d9106948d 100644 --- a/lib/mail_handler/backends/mail_extensions.rb +++ b/lib/mail_handler/backends/mail_extensions.rb @@ -5,5 +5,44 @@ module Mail attr_accessor :within_rfc822_attachment # for parts within a message attached as text (for getting subject mainly) attr_accessor :count_parts_count attr_accessor :count_first_uudecode_count + + # A patched version of the message initializer to work around a bug where stripping the original + # input removes meaningful spaces - e.g. in the case of uuencoded bodies. + def initialize(*args, &block) + @body = nil + @body_raw = nil + @separate_parts = false + @text_part = nil + @html_part = nil + @errors = nil + @header = nil + @charset = 'UTF-8' + @defaulted_charset = true + + @perform_deliveries = true + @raise_delivery_errors = true + + @delivery_handler = nil + + @delivery_method = Mail.delivery_method.dup + + @transport_encoding = Mail::Encodings.get_encoding('7bit') + + @mark_for_delete = false + + if args.flatten.first.respond_to?(:each_pair) + init_with_hash(args.flatten.first) + else + # The replacement of this commented out line is the change. + # init_with_string(args.flatten[0].to_s.strip) + init_with_string(args.flatten[0].to_s) + end + + if block_given? + instance_eval(&block) + end + + self + end end end \ No newline at end of file -- cgit v1.2.3 From f026dbc4c23ca25dd31dc6d3d132d6f1668728de Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 6 Dec 2012 13:46:05 +0000 Subject: Convert example URL to spec. --- lib/mail_handler/backends/tmail_backend.rb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index 3ce82a50c..e28765d54 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -155,9 +155,7 @@ module MailHandler for header in [ 'Date', 'Subject', 'From', 'To', 'Cc' ] if leaf.within_rfc822_attachment.header.include?(header.downcase) header_value = leaf.within_rfc822_attachment.header[header.downcase] - # Example message which has a blank Date header: - # http://www.whatdotheyknow.com/request/30747/response/80253/attach/html/17/Common%20Purpose%20Advisory%20Group%20Meeting%20Tuesday%202nd%20March.txt.html - if !header_value.blank? + if !header_value.blank? headers = headers + header + ": " + header_value.to_s + "\n" end end -- cgit v1.2.3 From 36c82a1fce563c0f23720589e1ac2741576bd4dd Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 6 Dec 2012 13:58:18 +0000 Subject: Remove url in comment - has been converted to spec. --- lib/mail_handler/backends/tmail_backend.rb | 2 -- 1 file changed, 2 deletions(-) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index e28765d54..f5da3049e 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -148,8 +148,6 @@ module MailHandler # RFC822 message and it is text, if so add headers. # XXX should probably use hunting algorithm to find main text part, rather than # just expect it to be first. This will do for now though. - # Example request that needs this: - # http://www.whatdotheyknow.com/request/2923/response/7013/attach/2/Cycle%20Path%20Bank.txt if leaf.within_rfc822_attachment == leaf && leaf.content_type == 'text/plain' headers = "" for header in [ 'Date', 'Subject', 'From', 'To', 'Cc' ] -- cgit v1.2.3 From 14125a23696ef17002bf9ca6ae983da93032823c Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 6 Dec 2012 14:24:14 +0000 Subject: Add functions for basic mail handling to the mail backend of mail handler. --- lib/mail_handler/backends/mail_backend.rb | 199 ++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_backend.rb b/lib/mail_handler/backends/mail_backend.rb index 30a85ed59..b75e6ed63 100644 --- a/lib/mail_handler/backends/mail_backend.rb +++ b/lib/mail_handler/backends/mail_backend.rb @@ -23,6 +23,14 @@ module MailHandler main end + # Returns an outlook message as a Mail object + def mail_from_outlook(content) + msg = Mapi::Msg.open(StringIO.new(content)) + mail = mail_from_raw_email(msg.to_mime.to_s) + mail.ready_to_send! + mail + end + # Return a copy of the file name for the mail part def get_part_file_name(part) part_file_name = part.filename @@ -102,6 +110,197 @@ module MailHandler mail.header[header] ? mail.header[header].to_s : nil end + # Detects whether a mail part is an Outlook email + def is_outlook?(part) + filename = get_part_file_name(part) + return true if get_content_type(part) == 'application/vnd.ms-outlook' + if filename && AlaveteliFileTypes.filename_to_mimetype(filename) == 'application/vnd.ms-outlook' + return true + end + return false + end + + # Convert a mail part which is an attached mail in one of + # several formats into a mail object and set it as the + # rfc822_attachment on the part. If the mail part can't be + # converted, the content type on the part is updated to + # 'text/plain' for an RFC822 attachment, and 'application/octet-stream' + # for other types + def decode_attached_part(part, parent_mail) + if get_content_type(part) == 'message/rfc822' + # An email attached as text + part.rfc822_attachment = mail_from_raw_email(part.body) + if part.rfc822_attachment.nil? + # Attached mail didn't parse, so treat as text + part.content_type = 'text/plain' + end + elsif is_outlook?(part) + part.rfc822_attachment = mail_from_outlook(part.body.decoded) + if part.rfc822_attachment.nil? + # Attached mail didn't parse, so treat as binary + part.content_type = 'application/octet-stream' + end + elsif get_content_type(part) == 'application/ms-tnef' + # A set of attachments in a TNEF file + part.rfc822_attachment = mail_from_tnef(part.body.decoded) + if part.rfc822_attachment.nil? + # Attached mail didn't parse, so treat as binary + part.content_type = 'application/octet-stream' + end + end + if part.rfc822_attachment + expand_and_normalize_parts(part.rfc822_attachment, parent_mail) + end + end + + # Expand and normalize a mail part recursively. Decodes attached messages into + # Mail objects wherever possible. Sets a default content type if none is + # set. Tries to set a more specific content type for binary content types. + def expand_and_normalize_parts(part, parent_mail) + if part.multipart? + part.parts.each{ |sub_part| expand_and_normalize_parts(sub_part, parent_mail) } + else + part_filename = get_part_file_name(part) + charset = part.charset # save this, because overwriting content_type also resets charset + + # Don't allow nil content_types + if get_content_type(part).nil? + part.content_type = 'application/octet-stream' + end + + # PDFs often come with this mime type, fix it up for view code + if get_content_type(part) == 'application/octet-stream' + part_body = get_part_body(part) + calc_mime = AlaveteliFileTypes.filename_and_content_to_mimetype(part_filename, + part_body) + if calc_mime + part.content_type = calc_mime + end + end + + # Use standard content types for Word documents etc. + part.content_type = normalise_content_type(get_content_type(part)) + decode_attached_part(part, parent_mail) + part.charset = charset + end + end + + # Count the parts in a mail part recursively, including any attached messages. + # Set the count on the parent mail, and set a url_part_number on the part itself. + # Set the count for the first uudecoded part on the parent mail also. + def count_parts(part, parent_mail) + if part.multipart? + part.parts.each { |p| count_parts(p, parent_mail) } + else + if part.rfc822_attachment + count_parts(part.rfc822_attachment, parent_mail) + else + parent_mail.count_parts_count += 1 + part.url_part_number = parent_mail.count_parts_count + end + end + parent_mail.count_first_uudecode_count = parent_mail.count_parts_count + end + + # Choose the best part from alternatives + def choose_best_alternative(mail) + if mail.html_part + return mail.html_part + elsif mail.text_part + return mail.text_part + else + return mail.parts.first + end + end + + # Expand and normalize the parts of a mail, select the best part + # wherever there is an alternative, and then count the returned + # leaves and assign url_part values to them + def get_attachment_leaves(mail) + expand_and_normalize_parts(mail, mail) + leaves = _get_attachment_leaves_recursive(mail, nil, mail) + mail.count_parts_count = 0 + count_parts(mail, mail) + return leaves + end + + # Recurse through a mail part, selecting the best part wherever there is + # an alternative + def _get_attachment_leaves_recursive(part, within_rfc822_attachment, parent_mail) + leaves_found = [] + if part.multipart? + raise "no parts on multipart mail" if part.parts.size == 0 + if part.sub_type == 'alternative' + best_part = choose_best_alternative(part) + leaves_found += _get_attachment_leaves_recursive(best_part, + within_rfc822_attachment, + parent_mail) + else + # Add all parts + part.parts.each do |sub_part| + leaves_found += _get_attachment_leaves_recursive(sub_part, + within_rfc822_attachment, + parent_mail) + end + end + else + # Add all the parts of a decoded attached message + if part.rfc822_attachment + leaves_found += _get_attachment_leaves_recursive(part.rfc822_attachment, + part.rfc822_attachment, + parent_mail) + else + # Store leaf + part.within_rfc822_attachment = within_rfc822_attachment + leaves_found += [part] + end + end + return leaves_found + end + + # Add selected useful headers from an attached message to its body + def extract_attached_message_headers(leaf) + body = get_part_body(leaf) + # Test to see if we are in the first part of the attached + # RFC822 message and it is text, if so add headers. + if leaf.within_rfc822_attachment == leaf && get_content_type(leaf) == 'text/plain' + headers = "" + [ 'Date', 'Subject', 'From', 'To', 'Cc' ].each do |header| + if header_value = get_header_string(header, leaf.within_rfc822_attachment) + if !header_value.blank? + headers = headers + header + ": " + header_value.to_s + "\n" + end + end + end + # XXX call _convert_part_body_to_text here, but need to get charset somehow + # e.g. http://www.whatdotheyknow.com/request/1593/response/3088/attach/4/Freedom%20of%20Information%20request%20-%20car%20oval%20sticker:%20Article%2020,%20Convention%20on%20Road%20Traffic%201949.txt + body = headers + "\n" + body + end + body + end + + # Generate a hash of the attributes associated with each significant part of a Mail object + def get_attachment_attributes(mail) + leaves = get_attachment_leaves(mail) + attachments = [] + for leaf in leaves + body = get_part_body(leaf) + if leaf.within_rfc822_attachment + within_rfc822_subject = leaf.within_rfc822_attachment.subject + body = extract_attached_message_headers(leaf) + end + leaf_attributes = { :url_part_number => leaf.url_part_number, + :content_type => get_content_type(leaf), + :filename => get_part_file_name(leaf), + :charset => leaf.charset, + :within_rfc822_subject => within_rfc822_subject, + :body => body, + :hexdigest => Digest::MD5.hexdigest(body) } + attachments << leaf_attributes + end + return attachments + end + # Format def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) -- cgit v1.2.3 From ac1c1329eeebefec8c9952cbae372fe8c4255307 Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 6 Dec 2012 16:34:52 +0000 Subject: Convert url in comment to spec. Conflicts: lib/mail_handler/backends/tmail_backend.rb --- lib/mail_handler/backends/tmail_backend.rb | 1 + 1 file changed, 1 insertion(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/tmail_backend.rb b/lib/mail_handler/backends/tmail_backend.rb index f5da3049e..02124cdb1 100644 --- a/lib/mail_handler/backends/tmail_backend.rb +++ b/lib/mail_handler/backends/tmail_backend.rb @@ -268,6 +268,7 @@ module MailHandler return leaves_found end + def address_from_name_and_email(name, email) if !MySociety::Validate.is_valid_email(email) raise "invalid email " + email + " passed to address_from_name_and_email" -- cgit v1.2.3 From 67ab55412f1fad8f6ab9e457f6d81b68d6a47b8c Mon Sep 17 00:00:00 2001 From: Louise Crow Date: Thu, 6 Dec 2012 16:25:49 +0000 Subject: Patch the parameter hash used in Mail to handle nil values. --- lib/mail_handler/backends/mail_extensions.rb | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) (limited to 'lib/mail_handler/backends') diff --git a/lib/mail_handler/backends/mail_extensions.rb b/lib/mail_handler/backends/mail_extensions.rb index d9106948d..f756abd1a 100644 --- a/lib/mail_handler/backends/mail_extensions.rb +++ b/lib/mail_handler/backends/mail_extensions.rb @@ -1,3 +1,5 @@ +require 'mail/message' +require 'mail/fields/common/parameter_hash' module Mail class Message attr_accessor :url_part_number @@ -45,4 +47,21 @@ module Mail self end end + + # A patched version of the parameter hash that handles nil values without throwing + # an error. + class ParameterHash < IndifferentHash + + def encoded + map.sort { |a,b| a.first.to_s <=> b.first.to_s }.map do |key_name, value| + # The replacement of this commented out line is the change + # unless value.ascii_only? + unless value.nil? || value.ascii_only? + value = Mail::Encodings.param_encode(value) + key_name = "#{key_name}*" + end + %Q{#{key_name}=#{quote_token(value)}} + end.join(";\r\n\s") + end + end end \ No newline at end of file -- cgit v1.2.3