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 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 lib/mail_handler/backends/mail_backend.rb (limited to 'lib/mail_handler/backends/mail_backend.rb') 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 -- 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 +++++ 1 file changed, 5 insertions(+) (limited to 'lib/mail_handler/backends/mail_backend.rb') 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 -- 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 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'lib/mail_handler/backends/mail_backend.rb') 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 -- 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 +++++++++ 1 file changed, 9 insertions(+) (limited to 'lib/mail_handler/backends/mail_backend.rb') 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 -- 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 +++++++ 1 file changed, 7 insertions(+) (limited to 'lib/mail_handler/backends/mail_backend.rb') 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 -- 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 +++++++++++++ 1 file changed, 13 insertions(+) (limited to 'lib/mail_handler/backends/mail_backend.rb') 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 -- 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 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/mail_handler/backends/mail_backend.rb') 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 -- 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 ++++ 1 file changed, 4 insertions(+) (limited to 'lib/mail_handler/backends/mail_backend.rb') 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) -- 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 +++++++++++++++++ 1 file changed, 17 insertions(+) (limited to 'lib/mail_handler/backends/mail_backend.rb') 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) -- 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 +++++ 1 file changed, 5 insertions(+) (limited to 'lib/mail_handler/backends/mail_backend.rb') 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) -- 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 + 1 file changed, 1 insertion(+) (limited to 'lib/mail_handler/backends/mail_backend.rb') 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 -- 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/mail_backend.rb') 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 +++++++ 1 file changed, 7 insertions(+) (limited to 'lib/mail_handler/backends/mail_backend.rb') 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) -- 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 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'lib/mail_handler/backends/mail_backend.rb') 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) -- 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/mail_backend.rb') 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 ++++++++ 1 file changed, 8 insertions(+) (limited to 'lib/mail_handler/backends/mail_backend.rb') 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) -- 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/mail_backend.rb') 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/mail_backend.rb') 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 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/mail_backend.rb') 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