5 # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
7 # Permission is hereby granted, free of charge, to any person obtaining
8 # a copy of this software and associated documentation files (the
9 # "Software"), to deal in the Software without restriction, including
10 # without limitation the rights to use, copy, modify, merge, publish,
11 # distribute, sublicense, and/or sell copies of the Software, and to
12 # permit persons to whom the Software is furnished to do so, subject to
13 # the following conditions:
15 # The above copyright notice and this permission notice shall be
16 # included in all copies or substantial portions of the Software.
18 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
27 # with permission of Minero Aoki.
37 def header_string( name, default = nil )
38 h = @header[name.downcase] or return default
48 def set_string_array_attr( key, strs )
51 @header.delete key.downcase
53 store key, strs.join(', ')
57 private :set_string_array_attr
59 def set_string_attr( key, str )
63 @header.delete key.downcase
67 private :set_string_attr
69 def set_addrfield( name, arg )
71 h = HeaderField.internal_new(name, @config)
72 h.addrs.replace [arg].flatten
79 private :set_addrfield
81 def addrs2specs( addrs )
82 return nil unless addrs
83 list = addrs.map {|addr|
84 if addr.address_group?
85 then addr.map {|a| a.spec }
89 return nil if list.empty?
99 def date( default = nil )
100 if h = @header['date']
109 store 'Date', time2str(time)
111 @header.delete 'date'
116 def strftime( fmt, default = nil )
129 def to_addrs( default = nil )
137 def cc_addrs( default = nil )
145 def bcc_addrs( default = nil )
146 if h = @header['bcc']
154 set_addrfield 'to', arg
158 set_addrfield 'cc', arg
161 def bcc_addrs=( arg )
162 set_addrfield 'bcc', arg
165 def to( default = nil )
166 addrs2specs(to_addrs(nil)) || default
169 def cc( default = nil )
170 addrs2specs(cc_addrs(nil)) || default
173 def bcc( default = nil )
174 addrs2specs(bcc_addrs(nil)) || default
178 set_string_array_attr 'To', strs
182 set_string_array_attr 'Cc', strs
186 set_string_array_attr 'Bcc', strs
194 def from_addrs( default = nil )
195 if h = @header['from']
202 def from_addrs=( arg )
203 set_addrfield 'from', arg
206 def from( default = nil )
207 addrs2specs(from_addrs(nil)) || default
211 set_string_array_attr 'From', strs
214 def friendly_from( default = nil )
217 return default unless a
218 return a.phrase if a.phrase
219 return h.comments.join(' ') unless h.comments.empty?
224 def reply_to_addrs( default = nil )
225 if h = @header['reply-to']
232 def reply_to_addrs=( arg )
233 set_addrfield 'reply-to', arg
236 def reply_to( default = nil )
237 addrs2specs(reply_to_addrs(nil)) || default
240 def reply_to=( *strs )
241 set_string_array_attr 'Reply-To', strs
245 def sender_addr( default = nil )
246 f = @header['sender'] or return default
247 f.addr or return default
250 def sender_addr=( addr )
252 h = HeaderField.internal_new('sender', @config)
254 @header['sender'] = h
256 @header.delete 'sender'
261 def sender( default )
262 f = @header['sender'] or return default
263 a = f.addr or return default
268 set_string_attr 'Sender', str
276 def subject( default = nil )
277 if h = @header['subject']
283 alias quoted_subject subject
286 set_string_attr 'Subject', str
291 # identity & threading
294 def message_id( default = nil )
295 if h = @header['message-id']
302 def message_id=( str )
303 set_string_attr 'Message-Id', str
306 def in_reply_to( default = nil )
307 if h = @header['in-reply-to']
314 def in_reply_to=( *idstrs )
315 set_string_array_attr 'In-Reply-To', idstrs
318 def references( default = nil )
319 if h = @header['references']
326 def references=( *strs )
327 set_string_array_attr 'References', strs
335 def mime_version( default = nil )
336 if h = @header['mime-version']
343 def mime_version=( m, opt = nil )
345 if h = @header['mime-version']
349 store 'Mime-Version', "#{m}.#{opt}"
352 store 'Mime-Version', m
358 def content_type( default = nil )
359 if h = @header['content-type']
360 h.content_type || default
366 def main_type( default = nil )
367 if h = @header['content-type']
368 h.main_type || default
374 def sub_type( default = nil )
375 if h = @header['content-type']
376 h.sub_type || default
382 def set_content_type( str, sub = nil, param = nil )
386 main, sub = str.split(%r</>, 2)
387 raise ArgumentError, "sub type missing: #{str.inspect}" unless sub
389 if h = @header['content-type']
394 store 'Content-Type', "#{main}/#{sub}"
396 @header['content-type'].params.replace param if param
401 alias content_type= set_content_type
403 def type_param( name, default = nil )
404 if h = @header['content-type']
411 def charset( default = nil )
412 if h = @header['content-type']
413 h['charset'] or default
421 if h = @header[ 'content-type' ]
424 store 'Content-Type', "text/plain; charset=#{str}"
431 def transfer_encoding( default = nil )
432 if h = @header['content-transfer-encoding']
433 h.encoding || default
439 def transfer_encoding=( str )
440 set_string_attr 'Content-Transfer-Encoding', str
443 alias encoding transfer_encoding
444 alias encoding= transfer_encoding=
445 alias content_transfer_encoding transfer_encoding
446 alias content_transfer_encoding= transfer_encoding=
449 def disposition( default = nil )
450 if h = @header['content-disposition']
451 h.disposition || default
457 alias content_disposition disposition
459 def set_disposition( str, params = nil )
460 if h = @header['content-disposition']
464 store('Content-Disposition', str)
465 h = @header['content-disposition']
467 h.params.replace params if params
470 alias disposition= set_disposition
471 alias set_content_disposition set_disposition
472 alias content_disposition= set_disposition
474 def disposition_param( name, default = nil )
475 if h = @header['content-disposition']
487 mail = TMail::Mail.parse('')
488 mail.subject = 'Re: ' + subject('').sub(/\A(?:\[[^\]]+\])?(?:\s*Re:)*\s*/i, '')
489 mail.to_addrs = reply_addresses([])
490 mail.in_reply_to = [message_id(nil)].compact
491 mail.references = references([]) + [message_id(nil)].compact
492 mail.mime_version = '1.0'
498 store 'Content-Transfer-Encoding', 'Base64'
499 self.body = Base64.folding_encode(self.body)
503 if /base64/i === self.transfer_encoding('')
504 store 'Content-Transfer-Encoding', '8bit'
505 self.body = Base64.decode(self.body, @config.strict_base64decode?)
510 def destinations( default = nil )
512 %w( to cc bcc ).each do |nm|
514 h.addrs.each {|i| ret.push i.address }
517 ret.empty? ? default : ret
520 def each_destination( &block )
521 destinations([]).each do |i|
530 alias each_dest each_destination
533 def reply_addresses( default = nil )
534 reply_to_addrs(nil) or from_addrs(nil) or default
537 def error_reply_addresses( default = nil )
547 main_type('').downcase == 'multipart'