1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
|
module MailHandler
module Backends
module TmailBackend
def backend()
'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, 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 if decode
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
# 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
# Get the body of a mail part
def get_part_body(mail_part)
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
end
mail.from_addrs[0].spec
end
# Return the first from name if any
def get_from_name(mail)
mail.from_name_if_present
end
def get_all_addresses(mail)
((mail.to || []) +
(mail.cc || []) +
(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 get_content_type(part)
part.content_type
end
def get_header_string(header, mail)
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"
end
if name.nil?
return TMail::Address.parse(email).to_s
end
# Botch an always quoted RFC address, then parse it
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
|