From 762295e0ae9d67450403596412bb8489893378d9 Mon Sep 17 00:00:00 2001 From: Jeremy Kemper Date: Mon, 19 May 2008 19:04:28 -0700 Subject: Bundle tmail 1.2.3 --- actionmailer/lib/action_mailer/vendor.rb | 4 +- .../lib/action_mailer/vendor/tmail-1.2.2/tmail.rb | 5 - .../vendor/tmail-1.2.2/tmail/address.rb | 426 ------ .../vendor/tmail-1.2.2/tmail/attachments.rb | 46 - .../vendor/tmail-1.2.2/tmail/base64.rb | 46 - .../vendor/tmail-1.2.2/tmail/compat.rb | 41 - .../vendor/tmail-1.2.2/tmail/config.rb | 67 - .../vendor/tmail-1.2.2/tmail/core_extensions.rb | 63 - .../vendor/tmail-1.2.2/tmail/encode.rb | 561 -------- .../vendor/tmail-1.2.2/tmail/header.rb | 960 ------------- .../vendor/tmail-1.2.2/tmail/index.rb | 9 - .../vendor/tmail-1.2.2/tmail/interface.rb | 1125 --------------- .../vendor/tmail-1.2.2/tmail/loader.rb | 3 - .../action_mailer/vendor/tmail-1.2.2/tmail/mail.rb | 578 -------- .../vendor/tmail-1.2.2/tmail/mailbox.rb | 495 ------- .../action_mailer/vendor/tmail-1.2.2/tmail/main.rb | 6 - .../action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb | 3 - .../action_mailer/vendor/tmail-1.2.2/tmail/net.rb | 248 ---- .../vendor/tmail-1.2.2/tmail/obsolete.rb | 132 -- .../vendor/tmail-1.2.2/tmail/parser.rb | 1476 -------------------- .../action_mailer/vendor/tmail-1.2.2/tmail/port.rb | 379 ----- .../vendor/tmail-1.2.2/tmail/quoting.rb | 118 -- .../vendor/tmail-1.2.2/tmail/require_arch.rb | 58 - .../vendor/tmail-1.2.2/tmail/scanner.rb | 49 - .../vendor/tmail-1.2.2/tmail/scanner_r.rb | 261 ---- .../vendor/tmail-1.2.2/tmail/stringio.rb | 280 ---- .../vendor/tmail-1.2.2/tmail/utils.rb | 337 ----- .../vendor/tmail-1.2.2/tmail/version.rb | 39 - .../lib/action_mailer/vendor/tmail-1.2.3/tmail.rb | 5 + .../vendor/tmail-1.2.3/tmail/address.rb | 426 ++++++ .../vendor/tmail-1.2.3/tmail/attachments.rb | 46 + .../vendor/tmail-1.2.3/tmail/base64.rb | 46 + .../vendor/tmail-1.2.3/tmail/compat.rb | 41 + .../vendor/tmail-1.2.3/tmail/config.rb | 67 + .../vendor/tmail-1.2.3/tmail/core_extensions.rb | 63 + .../vendor/tmail-1.2.3/tmail/encode.rb | 581 ++++++++ .../vendor/tmail-1.2.3/tmail/header.rb | 960 +++++++++++++ .../vendor/tmail-1.2.3/tmail/index.rb | 9 + .../vendor/tmail-1.2.3/tmail/interface.rb | 1130 +++++++++++++++ .../vendor/tmail-1.2.3/tmail/loader.rb | 3 + .../action_mailer/vendor/tmail-1.2.3/tmail/mail.rb | 578 ++++++++ .../vendor/tmail-1.2.3/tmail/mailbox.rb | 495 +++++++ .../action_mailer/vendor/tmail-1.2.3/tmail/main.rb | 6 + .../action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb | 3 + .../action_mailer/vendor/tmail-1.2.3/tmail/net.rb | 248 ++++ .../vendor/tmail-1.2.3/tmail/obsolete.rb | 132 ++ .../vendor/tmail-1.2.3/tmail/parser.rb | 1476 ++++++++++++++++++++ .../action_mailer/vendor/tmail-1.2.3/tmail/port.rb | 379 +++++ .../vendor/tmail-1.2.3/tmail/quoting.rb | 118 ++ .../vendor/tmail-1.2.3/tmail/require_arch.rb | 58 + .../vendor/tmail-1.2.3/tmail/scanner.rb | 49 + .../vendor/tmail-1.2.3/tmail/scanner_r.rb | 261 ++++ .../vendor/tmail-1.2.3/tmail/stringio.rb | 280 ++++ .../vendor/tmail-1.2.3/tmail/utils.rb | 337 +++++ .../vendor/tmail-1.2.3/tmail/version.rb | 39 + 55 files changed, 7838 insertions(+), 7813 deletions(-) delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/address.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/attachments.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/base64.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/compat.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/config.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/core_extensions.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/encode.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/header.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/index.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/interface.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/loader.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mail.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mailbox.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/main.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/net.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/obsolete.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/parser.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/port.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/quoting.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/require_arch.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner_r.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/stringio.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/utils.rb delete mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/version.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/attachments.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/base64.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/compat.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/config.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/core_extensions.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/encode.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/index.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/loader.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mailbox.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/main.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/net.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/obsolete.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/parser.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/port.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/quoting.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/require_arch.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner_r.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/stringio.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/utils.rb create mode 100644 actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/version.rb diff --git a/actionmailer/lib/action_mailer/vendor.rb b/actionmailer/lib/action_mailer/vendor.rb index 56a2858be5..7a20e9bd6e 100644 --- a/actionmailer/lib/action_mailer/vendor.rb +++ b/actionmailer/lib/action_mailer/vendor.rb @@ -2,9 +2,9 @@ require 'rubygems' begin - gem 'tmail', '~> 1.2.2' + gem 'tmail', '~> 1.2.3' rescue Gem::LoadError - $:.unshift "#{File.dirname(__FILE__)}/vendor/tmail-1.2.2" + $:.unshift "#{File.dirname(__FILE__)}/vendor/tmail-1.2.3" end begin diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail.rb deleted file mode 100644 index 18003659a6..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail.rb +++ /dev/null @@ -1,5 +0,0 @@ -require 'tmail/version' -require 'tmail/mail' -require 'tmail/mailbox' -require 'tmail/core_extensions' -require 'tmail/net' diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/address.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/address.rb deleted file mode 100644 index fa8e5bcd8c..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/address.rb +++ /dev/null @@ -1,426 +0,0 @@ -=begin rdoc - -= Address handling class - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -require 'tmail/encode' -require 'tmail/parser' - - -module TMail - - # = Class Address - # - # Provides a complete handling library for email addresses. Can parse a string of an - # address directly or take in preformatted addresses themseleves. Allows you to add - # and remove phrases from the front of the address and provides a compare function for - # email addresses. - # - # == Parsing and Handling a Valid Address: - # - # Just pass the email address in as a string to Address.parse: - # - # email = TMail::Address.parse('Mikel Lindsaar ) - # #=> # - # email.address - # #=> "mikel@lindsaar.net" - # email.local - # #=> "mikel" - # email.domain - # #=> "lindsaar.net" - # email.name # Aliased as phrase as well - # #=> "Mikel Lindsaar" - # - # == Detecting an Invalid Address - # - # If you want to check the syntactical validity of an email address, just pass it to - # Address.parse and catch any SyntaxError: - # - # begin - # TMail::Mail.parse("mikel 2@@@@@ me .com") - # rescue TMail::SyntaxError - # puts("Invalid Email Address Detected") - # else - # puts("Address is valid") - # end - # #=> "Invalid Email Address Detected" - class Address - - include TextUtils #:nodoc: - - # Sometimes you need to parse an address, TMail can do it for you and provide you with - # a fairly robust method of detecting a valid address. - # - # Takes in a string, returns a TMail::Address object. - # - # Raises a TMail::SyntaxError on invalid email format - def Address.parse( str ) - Parser.parse :ADDRESS, special_quote_address(str) - end - - def Address.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(<.*?>)\Z/ - return "\"#{$1}\" #{$2}" - else - str - end - end - - def address_group? #:nodoc: - false - end - - # Address.new(local, domain) - # - # Accepts: - # - # * local - Left of the at symbol - # - # * domain - Array of the domain split at the periods. - # - # For example: - # - # Address.new("mikel", ["lindsaar", "net"]) - # #=> "#" - def initialize( local, domain ) - if domain - domain.each do |s| - raise SyntaxError, 'empty word in domain' if s.empty? - end - end - - # This is to catch an unquoted "@" symbol in the local part of the - # address. Handles addresses like <"@"@me.com> and makes sure they - # stay like <"@"@me.com> (previously were becomming <@@me.com>) - if local && (local.join == '@' || local.join =~ /\A[^"].*?@.*?[^"]\Z/) - @local = "\"#{local.join}\"" - else - @local = local - end - - @domain = domain - @name = nil - @routes = [] - end - - # Provides the name or 'phrase' of the email address. - # - # For Example: - # - # email = TMail::Address.parse("Mikel Lindsaar ") - # email.name - # #=> "Mikel Lindsaar" - def name - @name - end - - # Setter method for the name or phrase of the email - # - # For Example: - # - # email = TMail::Address.parse("mikel@lindsaar.net") - # email.name - # #=> nil - # email.name = "Mikel Lindsaar" - # email.to_s - # #=> "Mikel Lindsaar " - def name=( str ) - @name = str - @name = nil if str and str.empty? - end - - #:stopdoc: - alias phrase name - alias phrase= name= - #:startdoc: - - # This is still here from RFC 822, and is now obsolete per RFC2822 Section 4. - # - # "When interpreting addresses, the route portion SHOULD be ignored." - # - # It is still here, so you can access it. - # - # Routes return the route portion at the front of the email address, if any. - # - # For Example: - # email = TMail::Address.parse( "<@sa,@another:Mikel@me.com>") - # => # - # email.to_s - # => "<@sa,@another:Mikel@me.com>" - # email.routes - # => ["sa", "another"] - def routes - @routes - end - - def inspect #:nodoc: - "#<#{self.class} #{address()}>" - end - - # Returns the local part of the email address - # - # For Example: - # - # email = TMail::Address.parse("mikel@lindsaar.net") - # email.local - # #=> "mikel" - def local - return nil unless @local - return '""' if @local.size == 1 and @local[0].empty? - # Check to see if it is an array before trying to map it - if @local.respond_to?(:map) - @local.map {|i| quote_atom(i) }.join('.') - else - quote_atom(@local) - end - end - - # Returns the domain part of the email address - # - # For Example: - # - # email = TMail::Address.parse("mikel@lindsaar.net") - # email.local - # #=> "lindsaar.net" - def domain - return nil unless @domain - join_domain(@domain) - end - - # Returns the full specific address itself - # - # For Example: - # - # email = TMail::Address.parse("mikel@lindsaar.net") - # email.address - # #=> "mikel@lindsaar.net" - def spec - s = self.local - d = self.domain - if s and d - s + '@' + d - else - s - end - end - - alias address spec - - # Provides == function to the email. Only checks the actual address - # and ignores the name/phrase component - # - # For Example - # - # addr1 = TMail::Address.parse("My Address ") - # #=> "#" - # addr2 = TMail::Address.parse("Another ") - # #=> "#" - # addr1 == addr2 - # #=> true - def ==( other ) - other.respond_to? :spec and self.spec == other.spec - end - - alias eql? == - - # Provides a unique hash value for this record against the local and domain - # parts, ignores the name/phrase value - # - # email = TMail::Address.parse("mikel@lindsaar.net") - # email.hash - # #=> 18767598 - def hash - @local.hash ^ @domain.hash - end - - # Duplicates a TMail::Address object returning the duplicate - # - # addr1 = TMail::Address.parse("mikel@lindsaar.net") - # addr2 = addr1.dup - # addr1.id == addr2.id - # #=> false - def dup - obj = self.class.new(@local.dup, @domain.dup) - obj.name = @name.dup if @name - obj.routes.replace @routes - obj - end - - include StrategyInterface #:nodoc: - - def accept( strategy, dummy1 = nil, dummy2 = nil ) #:nodoc: - unless @local - strategy.meta '<>' # empty return-path - return - end - - spec_p = (not @name and @routes.empty?) - if @name - strategy.phrase @name - strategy.space - end - tmp = spec_p ? '' : '<' - unless @routes.empty? - tmp << @routes.map {|i| '@' + i }.join(',') << ':' - end - tmp << self.spec - tmp << '>' unless spec_p - strategy.meta tmp - strategy.lwsp '' - end - - end - - - class AddressGroup - - include Enumerable - - def address_group? - true - end - - def initialize( name, addrs ) - @name = name - @addresses = addrs - end - - attr_reader :name - - def ==( other ) - other.respond_to? :to_a and @addresses == other.to_a - end - - alias eql? == - - def hash - map {|i| i.hash }.hash - end - - def []( idx ) - @addresses[idx] - end - - def size - @addresses.size - end - - def empty? - @addresses.empty? - end - - def each( &block ) - @addresses.each(&block) - end - - def to_a - @addresses.dup - end - - alias to_ary to_a - - def include?( a ) - @addresses.include? a - end - - def flatten - set = [] - @addresses.each do |a| - if a.respond_to? :flatten - set.concat a.flatten - else - set.push a - end - end - set - end - - def each_address( &block ) - flatten.each(&block) - end - - def add( a ) - @addresses.push a - end - - alias push add - - def delete( a ) - @addresses.delete a - end - - include StrategyInterface - - def accept( strategy, dummy1 = nil, dummy2 = nil ) - strategy.phrase @name - strategy.meta ':' - strategy.space - first = true - each do |mbox| - if first - first = false - else - strategy.meta ',' - end - strategy.space - mbox.accept strategy - end - strategy.meta ';' - strategy.lwsp '' - end - - end - -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/attachments.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/attachments.rb deleted file mode 100644 index 5dc5efae5e..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/attachments.rb +++ /dev/null @@ -1,46 +0,0 @@ -=begin rdoc - -= Attachment handling file - -=end - -require 'stringio' - -module TMail - class Attachment < StringIO - attr_accessor :original_filename, :content_type - end - - class Mail - def has_attachments? - multipart? && parts.any? { |part| attachment?(part) } - end - - def attachment?(part) - part.disposition_is_attachment? || part.content_type_is_text? - end - - def attachments - if multipart? - parts.collect { |part| - if part.multipart? - part.attachments - elsif attachment?(part) - content = part.body # unquoted automatically by TMail#body - file_name = (part['content-location'] && - part['content-location'].body) || - part.sub_header("content-type", "name") || - part.sub_header("content-disposition", "filename") - - next if file_name.blank? || content.blank? - - attachment = Attachment.new(content) - attachment.original_filename = file_name.strip - attachment.content_type = part.content_type - attachment - end - }.flatten.compact - end - end - end -end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/base64.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/base64.rb deleted file mode 100644 index e294c62960..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/base64.rb +++ /dev/null @@ -1,46 +0,0 @@ -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ -#:stopdoc: -module TMail - module Base64 - - module_function - - def folding_encode( str, eol = "\n", limit = 60 ) - [str].pack('m') - end - - def encode( str ) - [str].pack('m').tr( "\r\n", '' ) - end - - def decode( str, strict = false ) - str.unpack('m').first - end - - end -end -#:startdoc: diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/compat.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/compat.rb deleted file mode 100644 index 1275df79a6..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/compat.rb +++ /dev/null @@ -1,41 +0,0 @@ -#:stopdoc: -unless Enumerable.method_defined?(:map) - module Enumerable #:nodoc: - alias map collect - end -end - -unless Enumerable.method_defined?(:select) - module Enumerable #:nodoc: - alias select find_all - end -end - -unless Enumerable.method_defined?(:reject) - module Enumerable #:nodoc: - def reject - result = [] - each do |i| - result.push i unless yield(i) - end - result - end - end -end - -unless Enumerable.method_defined?(:sort_by) - module Enumerable #:nodoc: - def sort_by - map {|i| [yield(i), i] }.sort.map {|val, i| i } - end - end -end - -unless File.respond_to?(:read) - def File.read(fname) #:nodoc: - File.open(fname) {|f| - return f.read - } - end -end -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/config.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/config.rb deleted file mode 100644 index 3a876dcdbd..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/config.rb +++ /dev/null @@ -1,67 +0,0 @@ -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ -#:stopdoc: -module TMail - - class Config - - def initialize( strict ) - @strict_parse = strict - @strict_base64decode = strict - end - - def strict_parse? - @strict_parse - end - - attr_writer :strict_parse - - def strict_base64decode? - @strict_base64decode - end - - attr_writer :strict_base64decode - - def new_body_port( mail ) - StringPort.new - end - - alias new_preamble_port new_body_port - alias new_part_port new_body_port - - end - - DEFAULT_CONFIG = Config.new(false) - DEFAULT_STRICT_CONFIG = Config.new(true) - - def Config.to_config( arg ) - return DEFAULT_STRICT_CONFIG if arg == true - return DEFAULT_CONFIG if arg == false - arg or DEFAULT_CONFIG - end - -end -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/core_extensions.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/core_extensions.rb deleted file mode 100644 index da62c33bbf..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/core_extensions.rb +++ /dev/null @@ -1,63 +0,0 @@ -#:stopdoc: -unless Object.respond_to?(:blank?) - class Object - # Check first to see if we are in a Rails environment, no need to - # define these methods if we are - - # An object is blank if it's nil, empty, or a whitespace string. - # For example, "", " ", nil, [], and {} are blank. - # - # This simplifies - # if !address.nil? && !address.empty? - # to - # if !address.blank? - def blank? - if respond_to?(:empty?) && respond_to?(:strip) - empty? or strip.empty? - elsif respond_to?(:empty?) - empty? - else - !self - end - end - end - - class NilClass - def blank? - true - end - end - - class FalseClass - def blank? - true - end - end - - class TrueClass - def blank? - false - end - end - - class Array - alias_method :blank?, :empty? - end - - class Hash - alias_method :blank?, :empty? - end - - class String - def blank? - empty? || strip.empty? - end - end - - class Numeric - def blank? - false - end - end -end -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/encode.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/encode.rb deleted file mode 100644 index 63bccce4fc..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/encode.rb +++ /dev/null @@ -1,561 +0,0 @@ -#-- -# = COPYRIGHT: -# -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ -#:stopdoc: -require 'nkf' -require 'tmail/base64' -require 'tmail/stringio' -require 'tmail/utils' -#:startdoc: - - -module TMail - - #:stopdoc: - class << self - attr_accessor :KCODE - end - self.KCODE = 'NONE' - - module StrategyInterface - - def create_dest( obj ) - case obj - when nil - StringOutput.new - when String - StringOutput.new(obj) - when IO, StringOutput - obj - else - raise TypeError, 'cannot handle this type of object for dest' - end - end - module_function :create_dest - - #:startdoc: - # Returns the TMail object encoded and ready to be sent via SMTP etc. - # You should call this before you are packaging up your email to - # correctly escape all the values that need escaping in the email, line - # wrap the email etc. - # - # It is also a good idea to call this before you marshal or serialize - # a TMail object. - # - # For Example: - # - # email = TMail::Load(my_email_file) - # email_to_send = email.encoded - def encoded( eol = "\r\n", charset = 'j', dest = nil ) - accept_strategy Encoder, eol, charset, dest - end - - # Returns the TMail object decoded and ready to be used by you, your - # program etc. - # - # You should call this before you are packaging up your email to - # correctly escape all the values that need escaping in the email, line - # wrap the email etc. - # - # For Example: - # - # email = TMail::Load(my_email_file) - # email_to_send = email.encoded - def decoded( eol = "\n", charset = 'e', dest = nil ) - # Turn the E-Mail into a string and return it with all - # encoded characters decoded. alias for to_s - accept_strategy Decoder, eol, charset, dest - end - - alias to_s decoded - - def accept_strategy( klass, eol, charset, dest = nil ) #:nodoc: - dest ||= '' - accept klass.new( create_dest(dest), charset, eol ) - dest - end - - end - - #:stopdoc: - - ### - ### MIME B encoding decoder - ### - - class Decoder - - include TextUtils - - encoded = '=\?(?:iso-2022-jp|euc-jp|shift_jis)\?[QB]\?[a-z0-9+/=]+\?=' - ENCODED_WORDS = /#{encoded}(?:\s+#{encoded})*/i - - OUTPUT_ENCODING = { - 'EUC' => 'e', - 'SJIS' => 's', - } - - def self.decode( str, encoding = nil ) - encoding ||= (OUTPUT_ENCODING[TMail.KCODE] || 'j') - opt = '-mS' + encoding - str.gsub(ENCODED_WORDS) {|s| NKF.nkf(opt, s) } - end - - def initialize( dest, encoding = nil, eol = "\n" ) - @f = StrategyInterface.create_dest(dest) - @encoding = (/\A[ejs]/ === encoding) ? encoding[0,1] : nil - @eol = eol - end - - def decode( str ) - self.class.decode(str, @encoding) - end - private :decode - - def terminate - end - - def header_line( str ) - @f << decode(str) - end - - def header_name( nm ) - @f << nm << ': ' - end - - def header_body( str ) - @f << decode(str) - end - - def space - @f << ' ' - end - - alias spc space - - def lwsp( str ) - @f << str - end - - def meta( str ) - @f << str - end - - def text( str ) - @f << decode(str) - end - - def phrase( str ) - @f << quote_phrase(decode(str)) - end - - def kv_pair( k, v ) - v = dquote(v) unless token_safe?(v) - @f << k << '=' << v - end - - def puts( str = nil ) - @f << str if str - @f << @eol - end - - def write( str ) - @f << str - end - - end - - - ### - ### MIME B-encoding encoder - ### - - # - # FIXME: This class can handle only (euc-jp/shift_jis -> iso-2022-jp). - # - class Encoder - - include TextUtils - - BENCODE_DEBUG = false unless defined?(BENCODE_DEBUG) - - def Encoder.encode( str ) - e = new() - e.header_body str - e.terminate - e.dest.string - end - - SPACER = "\t" - MAX_LINE_LEN = 78 - RFC_2822_MAX_LENGTH = 998 - - OPTIONS = { - 'EUC' => '-Ej -m0', - 'SJIS' => '-Sj -m0', - 'UTF8' => nil, # FIXME - 'NONE' => nil - } - - def initialize( dest = nil, encoding = nil, eol = "\r\n", limit = nil ) - @f = StrategyInterface.create_dest(dest) - @opt = OPTIONS[TMail.KCODE] - @eol = eol - @folded = false - @preserve_quotes = true - reset - end - - def preserve_quotes=( bool ) - @preserve_quotes - end - - def preserve_quotes - @preserve_quotes - end - - def normalize_encoding( str ) - if @opt - then NKF.nkf(@opt, str) - else str - end - end - - def reset - @text = '' - @lwsp = '' - @curlen = 0 - end - - def terminate - add_lwsp '' - reset - end - - def dest - @f - end - - def puts( str = nil ) - @f << str if str - @f << @eol - end - - def write( str ) - @f << str - end - - # - # add - # - - def header_line( line ) - scanadd line - end - - def header_name( name ) - add_text name.split(/-/).map {|i| i.capitalize }.join('-') - add_text ':' - add_lwsp ' ' - end - - def header_body( str ) - scanadd normalize_encoding(str) - end - - def space - add_lwsp ' ' - end - - alias spc space - - def lwsp( str ) - add_lwsp str.sub(/[\r\n]+[^\r\n]*\z/, '') - end - - def meta( str ) - add_text str - end - - def text( str ) - scanadd normalize_encoding(str) - end - - def phrase( str ) - str = normalize_encoding(str) - if CONTROL_CHAR === str - scanadd str - else - add_text quote_phrase(str) - end - end - - # FIXME: implement line folding - # - def kv_pair( k, v ) - return if v.nil? - v = normalize_encoding(v) - if token_safe?(v) - add_text k + '=' + v - elsif not CONTROL_CHAR === v - add_text k + '=' + quote_token(v) - else - # apply RFC2231 encoding - kv = k + '*=' + "iso-2022-jp'ja'" + encode_value(v) - add_text kv - end - end - - def encode_value( str ) - str.gsub(TOKEN_UNSAFE) {|s| '%%%02x' % s[0] } - end - - private - - def scanadd( str, force = false ) - types = '' - strs = [] - - until str.empty? - if m = /\A[^\e\t\r\n ]+/.match(str) - types << (force ? 'j' : 'a') - strs.push m[0] - - elsif m = /\A[\t\r\n ]+/.match(str) - types << 's' - strs.push m[0] - - elsif m = /\A\e../.match(str) - esc = m[0] - str = m.post_match - if esc != "\e(B" and m = /\A[^\e]+/.match(str) - types << 'j' - strs.push m[0] - end - - else - raise 'TMail FATAL: encoder scan fail' - end - (str = m.post_match) unless m.nil? - end - - do_encode types, strs - end - - def do_encode( types, strs ) - # - # result : (A|E)(S(A|E))* - # E : W(SW)* - # W : (J|A)+ but must contain J # (J|A)*J(J|A)* - # A : <> - # J : <> - # S : <> - # - # An encoding unit is `E'. - # Input (parameter `types') is (J|A)(J|A|S)*(J|A) - # - if BENCODE_DEBUG - puts - puts '-- do_encode ------------' - puts types.split(//).join(' ') - p strs - end - - e = /[ja]*j[ja]*(?:s[ja]*j[ja]*)*/ - - while m = e.match(types) - pre = m.pre_match - concat_A_S pre, strs[0, pre.size] unless pre.empty? - concat_E m[0], strs[m.begin(0) ... m.end(0)] - types = m.post_match - strs.slice! 0, m.end(0) - end - concat_A_S types, strs - end - - def concat_A_S( types, strs ) - if RUBY_VERSION < '1.9' - a = ?a; s = ?s - else - a = 'a'.ord; s = 's'.ord - end - i = 0 - types.each_byte do |t| - case t - when a then add_text strs[i] - when s then add_lwsp strs[i] - else - raise "TMail FATAL: unknown flag: #{t.chr}" - end - i += 1 - end - end - - METHOD_ID = { - ?j => :extract_J, - ?e => :extract_E, - ?a => :extract_A, - ?s => :extract_S - } - - def concat_E( types, strs ) - if BENCODE_DEBUG - puts '---- concat_E' - puts "types=#{types.split(//).join(' ')}" - puts "strs =#{strs.inspect}" - end - - flush() unless @text.empty? - - chunk = '' - strs.each_with_index do |s,i| - mid = METHOD_ID[types[i]] - until s.empty? - unless c = __send__(mid, chunk.size, s) - add_with_encode chunk unless chunk.empty? - flush - chunk = '' - fold - c = __send__(mid, 0, s) - raise 'TMail FATAL: extract fail' unless c - end - chunk << c - end - end - add_with_encode chunk unless chunk.empty? - end - - def extract_J( chunksize, str ) - size = max_bytes(chunksize, str.size) - 6 - size = (size % 2 == 0) ? (size) : (size - 1) - return nil if size <= 0 - "\e$B#{str.slice!(0, size)}\e(B" - end - - def extract_A( chunksize, str ) - size = max_bytes(chunksize, str.size) - return nil if size <= 0 - str.slice!(0, size) - end - - alias extract_S extract_A - - def max_bytes( chunksize, ssize ) - (restsize() - '=?iso-2022-jp?B??='.size) / 4 * 3 - chunksize - end - - # - # free length buffer - # - - def add_text( str ) - @text << str - # puts '---- text -------------------------------------' - # puts "+ #{str.inspect}" - # puts "txt >>>#{@text.inspect}<<<" - end - - def add_with_encode( str ) - @text << "=?iso-2022-jp?B?#{Base64.encode(str)}?=" - end - - def add_lwsp( lwsp ) - # puts '---- lwsp -------------------------------------' - # puts "+ #{lwsp.inspect}" - fold if restsize() <= 0 - flush(@folded) - @lwsp = lwsp - end - - def flush(folded = false) - # puts '---- flush ----' - # puts "spc >>>#{@lwsp.inspect}<<<" - # puts "txt >>>#{@text.inspect}<<<" - @f << @lwsp << @text - if folded - @curlen = 0 - else - @curlen += (@lwsp.size + @text.size) - end - @text = '' - @lwsp = '' - end - - def fold - # puts '---- fold ----' - unless @f.string =~ /^.*?:$/ - @f << @eol - @lwsp = SPACER - else - fold_header - @folded = true - end - @curlen = 0 - end - - def fold_header - # Called because line is too long - so we need to wrap. - # First look for whitespace in the text - # if it has text, fold there - # check the remaining text, if too long, fold again - # if it doesn't, then don't fold unless the line goes beyond 998 chars - - # Check the text to see if there is whitespace, or if not - @wrapped_text = [] - until @text.blank? - fold_the_string - end - @text = @wrapped_text.join("#{@eol}#{SPACER}") - end - - def fold_the_string - whitespace_location = @text =~ /\s/ || @text.length - # Is the location of the whitespace shorter than the RCF_2822_MAX_LENGTH? - # if there is no whitespace in the string, then this - unless mazsize(whitespace_location) <= 0 - @text.strip! - @wrapped_text << @text.slice!(0...whitespace_location) - # If it is not less, we have to wrap it destructively - else - slice_point = RFC_2822_MAX_LENGTH - @curlen - @lwsp.length - @text.strip! - @wrapped_text << @text.slice!(0...slice_point) - end - end - - def restsize - MAX_LINE_LEN - (@curlen + @lwsp.size + @text.size) - end - - def mazsize(whitespace_location) - # Per RFC2822, the maximum length of a line is 998 chars - RFC_2822_MAX_LENGTH - (@curlen + @lwsp.size + whitespace_location) - end - - end - #:startdoc: -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/header.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/header.rb deleted file mode 100644 index 9153dcd7c6..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/header.rb +++ /dev/null @@ -1,960 +0,0 @@ -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -require 'tmail/encode' -require 'tmail/address' -require 'tmail/parser' -require 'tmail/config' -require 'tmail/utils' - -#:startdoc: -module TMail - - # Provides methods to handle and manipulate headers in the email - class HeaderField - - include TextUtils - - class << self - - alias newobj new - - def new( name, body, conf = DEFAULT_CONFIG ) - klass = FNAME_TO_CLASS[name.downcase] || UnstructuredHeader - klass.newobj body, conf - end - - # Returns a HeaderField object matching the header you specify in the "name" param. - # Requires an initialized TMail::Port to be passed in. - # - # The method searches the header of the Port you pass into it to find a match on - # the header line you pass. Once a match is found, it will unwrap the matching line - # as needed to return an initialized HeaderField object. - # - # If you want to get the Envelope sender of the email object, pass in "EnvelopeSender", - # if you want the From address of the email itself, pass in 'From'. - # - # This is because a mailbox doesn't have the : after the From that designates the - # beginning of the envelope sender (which can be different to the from address of - # the emial) - # - # Other fields can be passed as normal, "Reply-To", "Received" etc. - # - # Note: Change of behaviour in 1.2.1 => returns nil if it does not find the specified - # header field, otherwise returns an instantiated object of the correct header class - # - # For example: - # port = TMail::FilePort.new("/test/fixtures/raw_email_simple") - # h = TMail::HeaderField.new_from_port(port, "From") - # h.addrs.to_s #=> "Mikel Lindsaar " - # h = TMail::HeaderField.new_from_port(port, "EvelopeSender") - # h.addrs.to_s #=> "mike@anotherplace.com.au" - # h = TMail::HeaderField.new_from_port(port, "SomeWeirdHeaderField") - # h #=> nil - def new_from_port( port, name, conf = DEFAULT_CONFIG ) - if name == "EnvelopeSender" - name = "From" - re = Regexp.new('\A(From) ', 'i') - else - re = Regexp.new('\A(' + Regexp.quote(name) + '):', 'i') - end - str = nil - port.ropen {|f| - f.each do |line| - if m = re.match(line) then str = m.post_match.strip - elsif str and /\A[\t ]/ === line then str << ' ' << line.strip - elsif /\A-*\s*\z/ === line then break - elsif str then break - end - end - } - new(name, str, Config.to_config(conf)) if str - end - - def internal_new( name, conf ) - FNAME_TO_CLASS[name].newobj('', conf, true) - end - - end # class << self - - def initialize( body, conf, intern = false ) - @body = body - @config = conf - - @illegal = false - @parsed = false - - if intern - @parsed = true - parse_init - end - end - - def inspect - "#<#{self.class} #{@body.inspect}>" - end - - def illegal? - @illegal - end - - def empty? - ensure_parsed - return true if @illegal - isempty? - end - - private - - def ensure_parsed - return if @parsed - @parsed = true - parse - end - - # defabstract parse - # end - - def clear_parse_status - @parsed = false - @illegal = false - end - - public - - def body - ensure_parsed - v = Decoder.new(s = '') - do_accept v - v.terminate - s - end - - def body=( str ) - @body = str - clear_parse_status - end - - include StrategyInterface - - def accept( strategy ) - ensure_parsed - do_accept strategy - strategy.terminate - end - - # abstract do_accept - - end - - - class UnstructuredHeader < HeaderField - - def body - ensure_parsed - @body - end - - def body=( arg ) - ensure_parsed - @body = arg - end - - private - - def parse_init - end - - def parse - @body = Decoder.decode(@body.gsub(/\n|\r\n|\r/, '')) - end - - def isempty? - not @body - end - - def do_accept( strategy ) - strategy.text @body - end - - end - - - class StructuredHeader < HeaderField - - def comments - ensure_parsed - if @comments[0] - [Decoder.decode(@comments[0])] - else - @comments - end - end - - private - - def parse - save = nil - - begin - parse_init - do_parse - rescue SyntaxError - if not save and mime_encoded? @body - save = @body - @body = Decoder.decode(save) - retry - elsif save - @body = save - end - - @illegal = true - raise if @config.strict_parse? - end - end - - def parse_init - @comments = [] - init - end - - def do_parse - quote_boundary - obj = Parser.parse(self.class::PARSE_TYPE, @body, @comments) - set obj if obj - end - - end - - - class DateTimeHeader < StructuredHeader - - PARSE_TYPE = :DATETIME - - def date - ensure_parsed - @date - end - - def date=( arg ) - ensure_parsed - @date = arg - end - - private - - def init - @date = nil - end - - def set( t ) - @date = t - end - - def isempty? - not @date - end - - def do_accept( strategy ) - strategy.meta time2str(@date) - end - - end - - - class AddressHeader < StructuredHeader - - PARSE_TYPE = :MADDRESS - - def addrs - ensure_parsed - @addrs - end - - private - - def init - @addrs = [] - end - - def set( a ) - @addrs = a - end - - def isempty? - @addrs.empty? - end - - def do_accept( strategy ) - first = true - @addrs.each do |a| - if first - first = false - else - strategy.meta ',' - strategy.space - end - a.accept strategy - end - - @comments.each do |c| - strategy.space - strategy.meta '(' - strategy.text c - strategy.meta ')' - end - end - - end - - - class ReturnPathHeader < AddressHeader - - PARSE_TYPE = :RETPATH - - def addr - addrs()[0] - end - - def spec - a = addr() or return nil - a.spec - end - - def routes - a = addr() or return nil - a.routes - end - - private - - def do_accept( strategy ) - a = addr() - - strategy.meta '<' - unless a.routes.empty? - strategy.meta a.routes.map {|i| '@' + i }.join(',') - strategy.meta ':' - end - spec = a.spec - strategy.meta spec if spec - strategy.meta '>' - end - - end - - - class SingleAddressHeader < AddressHeader - - def addr - addrs()[0] - end - - private - - def do_accept( strategy ) - a = addr() - a.accept strategy - @comments.each do |c| - strategy.space - strategy.meta '(' - strategy.text c - strategy.meta ')' - end - end - - end - - - class MessageIdHeader < StructuredHeader - - def id - ensure_parsed - @id - end - - def id=( arg ) - ensure_parsed - @id = arg - end - - private - - def init - @id = nil - end - - def isempty? - not @id - end - - def do_parse - @id = @body.slice(MESSAGE_ID) or - raise SyntaxError, "wrong Message-ID format: #{@body}" - end - - def do_accept( strategy ) - strategy.meta @id - end - - end - - - class ReferencesHeader < StructuredHeader - - def refs - ensure_parsed - @refs - end - - def each_id - self.refs.each do |i| - yield i if MESSAGE_ID === i - end - end - - def ids - ensure_parsed - @ids - end - - def each_phrase - self.refs.each do |i| - yield i unless MESSAGE_ID === i - end - end - - def phrases - ret = [] - each_phrase {|i| ret.push i } - ret - end - - private - - def init - @refs = [] - @ids = [] - end - - def isempty? - @ids.empty? - end - - def do_parse - str = @body - while m = MESSAGE_ID.match(str) - pre = m.pre_match.strip - @refs.push pre unless pre.empty? - @refs.push s = m[0] - @ids.push s - str = m.post_match - end - str = str.strip - @refs.push str unless str.empty? - end - - def do_accept( strategy ) - first = true - @ids.each do |i| - if first - first = false - else - strategy.space - end - strategy.meta i - end - end - - end - - - class ReceivedHeader < StructuredHeader - - PARSE_TYPE = :RECEIVED - - def from - ensure_parsed - @from - end - - def from=( arg ) - ensure_parsed - @from = arg - end - - def by - ensure_parsed - @by - end - - def by=( arg ) - ensure_parsed - @by = arg - end - - def via - ensure_parsed - @via - end - - def via=( arg ) - ensure_parsed - @via = arg - end - - def with - ensure_parsed - @with - end - - def id - ensure_parsed - @id - end - - def id=( arg ) - ensure_parsed - @id = arg - end - - def _for - ensure_parsed - @_for - end - - def _for=( arg ) - ensure_parsed - @_for = arg - end - - def date - ensure_parsed - @date - end - - def date=( arg ) - ensure_parsed - @date = arg - end - - private - - def init - @from = @by = @via = @with = @id = @_for = nil - @with = [] - @date = nil - end - - def set( args ) - @from, @by, @via, @with, @id, @_for, @date = *args - end - - def isempty? - @with.empty? and not (@from or @by or @via or @id or @_for or @date) - end - - def do_accept( strategy ) - list = [] - list.push 'from ' + @from if @from - list.push 'by ' + @by if @by - list.push 'via ' + @via if @via - @with.each do |i| - list.push 'with ' + i - end - list.push 'id ' + @id if @id - list.push 'for <' + @_for + '>' if @_for - - first = true - list.each do |i| - strategy.space unless first - strategy.meta i - first = false - end - if @date - strategy.meta ';' - strategy.space - strategy.meta time2str(@date) - end - end - - end - - - class KeywordsHeader < StructuredHeader - - PARSE_TYPE = :KEYWORDS - - def keys - ensure_parsed - @keys - end - - private - - def init - @keys = [] - end - - def set( a ) - @keys = a - end - - def isempty? - @keys.empty? - end - - def do_accept( strategy ) - first = true - @keys.each do |i| - if first - first = false - else - strategy.meta ',' - end - strategy.meta i - end - end - - end - - - class EncryptedHeader < StructuredHeader - - PARSE_TYPE = :ENCRYPTED - - def encrypter - ensure_parsed - @encrypter - end - - def encrypter=( arg ) - ensure_parsed - @encrypter = arg - end - - def keyword - ensure_parsed - @keyword - end - - def keyword=( arg ) - ensure_parsed - @keyword = arg - end - - private - - def init - @encrypter = nil - @keyword = nil - end - - def set( args ) - @encrypter, @keyword = args - end - - def isempty? - not (@encrypter or @keyword) - end - - def do_accept( strategy ) - if @key - strategy.meta @encrypter + ',' - strategy.space - strategy.meta @keyword - else - strategy.meta @encrypter - end - end - - end - - - class MimeVersionHeader < StructuredHeader - - PARSE_TYPE = :MIMEVERSION - - def major - ensure_parsed - @major - end - - def major=( arg ) - ensure_parsed - @major = arg - end - - def minor - ensure_parsed - @minor - end - - def minor=( arg ) - ensure_parsed - @minor = arg - end - - def version - sprintf('%d.%d', major, minor) - end - - private - - def init - @major = nil - @minor = nil - end - - def set( args ) - @major, @minor = *args - end - - def isempty? - not (@major or @minor) - end - - def do_accept( strategy ) - strategy.meta sprintf('%d.%d', @major, @minor) - end - - end - - - class ContentTypeHeader < StructuredHeader - - PARSE_TYPE = :CTYPE - - def main_type - ensure_parsed - @main - end - - def main_type=( arg ) - ensure_parsed - @main = arg.downcase - end - - def sub_type - ensure_parsed - @sub - end - - def sub_type=( arg ) - ensure_parsed - @sub = arg.downcase - end - - def content_type - ensure_parsed - @sub ? sprintf('%s/%s', @main, @sub) : @main - end - - def params - ensure_parsed - unless @params.blank? - @params.each do |k, v| - @params[k] = unquote(v) - end - end - @params - end - - def []( key ) - ensure_parsed - @params and unquote(@params[key]) - end - - def []=( key, val ) - ensure_parsed - (@params ||= {})[key] = val - end - - private - - def init - @main = @sub = @params = nil - end - - def set( args ) - @main, @sub, @params = *args - end - - def isempty? - not (@main or @sub) - end - - def do_accept( strategy ) - if @sub - strategy.meta sprintf('%s/%s', @main, @sub) - else - strategy.meta @main - end - @params.each do |k,v| - if v - strategy.meta ';' - strategy.space - strategy.kv_pair k, v - end - end - end - - end - - - class ContentTransferEncodingHeader < StructuredHeader - - PARSE_TYPE = :CENCODING - - def encoding - ensure_parsed - @encoding - end - - def encoding=( arg ) - ensure_parsed - @encoding = arg - end - - private - - def init - @encoding = nil - end - - def set( s ) - @encoding = s - end - - def isempty? - not @encoding - end - - def do_accept( strategy ) - strategy.meta @encoding.capitalize - end - - end - - - class ContentDispositionHeader < StructuredHeader - - PARSE_TYPE = :CDISPOSITION - - def disposition - ensure_parsed - @disposition - end - - def disposition=( str ) - ensure_parsed - @disposition = str.downcase - end - - def params - ensure_parsed - unless @params.blank? - @params.each do |k, v| - @params[k] = unquote(v) - end - end - @params - end - - def []( key ) - ensure_parsed - @params and unquote(@params[key]) - end - - def []=( key, val ) - ensure_parsed - (@params ||= {})[key] = val - end - - private - - def init - @disposition = @params = nil - end - - def set( args ) - @disposition, @params = *args - end - - def isempty? - not @disposition and (not @params or @params.empty?) - end - - def do_accept( strategy ) - strategy.meta @disposition - @params.each do |k,v| - strategy.meta ';' - strategy.space - strategy.kv_pair k, unquote(v) - end - end - - end - - - class HeaderField # redefine - - FNAME_TO_CLASS = { - 'date' => DateTimeHeader, - 'resent-date' => DateTimeHeader, - 'to' => AddressHeader, - 'cc' => AddressHeader, - 'bcc' => AddressHeader, - 'from' => AddressHeader, - 'reply-to' => AddressHeader, - 'resent-to' => AddressHeader, - 'resent-cc' => AddressHeader, - 'resent-bcc' => AddressHeader, - 'resent-from' => AddressHeader, - 'resent-reply-to' => AddressHeader, - 'sender' => SingleAddressHeader, - 'resent-sender' => SingleAddressHeader, - 'return-path' => ReturnPathHeader, - 'message-id' => MessageIdHeader, - 'resent-message-id' => MessageIdHeader, - 'in-reply-to' => ReferencesHeader, - 'received' => ReceivedHeader, - 'references' => ReferencesHeader, - 'keywords' => KeywordsHeader, - 'encrypted' => EncryptedHeader, - 'mime-version' => MimeVersionHeader, - 'content-type' => ContentTypeHeader, - 'content-transfer-encoding' => ContentTransferEncodingHeader, - 'content-disposition' => ContentDispositionHeader, - 'content-id' => MessageIdHeader, - 'subject' => UnstructuredHeader, - 'comments' => UnstructuredHeader, - 'content-description' => UnstructuredHeader - } - - end - -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/index.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/index.rb deleted file mode 100644 index 554e2fd696..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/index.rb +++ /dev/null @@ -1,9 +0,0 @@ -#:stopdoc: -# This is here for Rolls. -# Rolls uses this instead of lib/tmail.rb. - -require 'tmail/version' -require 'tmail/mail' -require 'tmail/mailbox' -require 'tmail/core_extensions' -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/interface.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/interface.rb deleted file mode 100644 index 206653bd5d..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/interface.rb +++ /dev/null @@ -1,1125 +0,0 @@ -=begin rdoc - -= interface.rb Provides an interface to the TMail object - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -# TMail::Mail objects get accessed primarily through the methods in this file. -# -# - -require 'tmail/utils' - -module TMail - - class Mail - - # Allows you to query the mail object with a string to get the contents - # of the field you want. - # - # Returns a string of the exact contnts of the field - # - # mail.from = "mikel " - # mail.header_string("From") #=> "mikel " - def header_string( name, default = nil ) - h = @header[name.downcase] or return default - h.to_s - end - - #:stopdoc: - #-- - #== Attributes - - include TextUtils - - def set_string_array_attr( key, strs ) - strs.flatten! - if strs.empty? - @header.delete key.downcase - else - store key, strs.join(', ') - end - strs - end - private :set_string_array_attr - - def set_string_attr( key, str ) - if str - store key, str - else - @header.delete key.downcase - end - str - end - private :set_string_attr - - def set_addrfield( name, arg ) - if arg - h = HeaderField.internal_new(name, @config) - h.addrs.replace [arg].flatten - @header[name] = h - else - @header.delete name - end - arg - end - private :set_addrfield - - def addrs2specs( addrs ) - return nil unless addrs - list = addrs.map {|addr| - if addr.address_group? - then addr.map {|a| a.spec } - else addr.spec - end - }.flatten - return nil if list.empty? - list - end - private :addrs2specs - - #:startdoc: - - #== Date and Time methods - - # Returns the date of the email message as per the "date" header value or returns - # nil by default (if no date field exists). - # - # You can also pass whatever default you want into this method and it will return - # that instead of nil if there is no date already set. - def date( default = nil ) - if h = @header['date'] - h.date - else - default - end - end - - # Destructively sets the date of the mail object with the passed Time instance, - # returns a Time instance set to the date/time of the mail - # - # Example: - # - # now = Time.now - # mail.date = now - # mail.date #=> Sat Nov 03 18:47:50 +1100 2007 - # mail.date.class #=> Time - def date=( time ) - if time - store 'Date', time2str(time) - else - @header.delete 'date' - end - time - end - - # Returns the time of the mail message formatted to your taste using a - # strftime format string. If no date set returns nil by default or whatever value - # you pass as the second optional parameter. - # - # time = Time.now # (on Nov 16 2007) - # mail.date = time - # mail.strftime("%D") #=> "11/16/07" - def strftime( fmt, default = nil ) - if t = date - t.strftime(fmt) - else - default - end - end - - #== Destination methods - - # Return a TMail::Addresses instance for each entry in the "To:" field of the mail object header. - # - # If the "To:" field does not exist, will return nil by default or the value you - # pass as the optional parameter. - # - # Example: - # - # mail = TMail::Mail.new - # mail.to_addrs #=> nil - # mail.to_addrs([]) #=> [] - # mail.to = "Mikel , another Mikel " - # mail.to_addrs #=> [#, #] - def to_addrs( default = nil ) - if h = @header['to'] - h.addrs - else - default - end - end - - # Return a TMail::Addresses instance for each entry in the "Cc:" field of the mail object header. - # - # If the "Cc:" field does not exist, will return nil by default or the value you - # pass as the optional parameter. - # - # Example: - # - # mail = TMail::Mail.new - # mail.cc_addrs #=> nil - # mail.cc_addrs([]) #=> [] - # mail.cc = "Mikel , another Mikel " - # mail.cc_addrs #=> [#, #] - def cc_addrs( default = nil ) - if h = @header['cc'] - h.addrs - else - default - end - end - - # Return a TMail::Addresses instance for each entry in the "Bcc:" field of the mail object header. - # - # If the "Bcc:" field does not exist, will return nil by default or the value you - # pass as the optional parameter. - # - # Example: - # - # mail = TMail::Mail.new - # mail.bcc_addrs #=> nil - # mail.bcc_addrs([]) #=> [] - # mail.bcc = "Mikel , another Mikel " - # mail.bcc_addrs #=> [#, #] - def bcc_addrs( default = nil ) - if h = @header['bcc'] - h.addrs - else - default - end - end - - # Destructively set the to field of the "To:" header to equal the passed in string. - # - # TMail will parse your contents and turn each valid email address into a TMail::Address - # object before assigning it to the mail message. - # - # Example: - # - # mail = TMail::Mail.new - # mail.to = "Mikel , another Mikel " - # mail.to_addrs #=> [#, #] - def to_addrs=( arg ) - set_addrfield 'to', arg - end - - # Destructively set the to field of the "Cc:" header to equal the passed in string. - # - # TMail will parse your contents and turn each valid email address into a TMail::Address - # object before assigning it to the mail message. - # - # Example: - # - # mail = TMail::Mail.new - # mail.cc = "Mikel , another Mikel " - # mail.cc_addrs #=> [#, #] - def cc_addrs=( arg ) - set_addrfield 'cc', arg - end - - # Destructively set the to field of the "Bcc:" header to equal the passed in string. - # - # TMail will parse your contents and turn each valid email address into a TMail::Address - # object before assigning it to the mail message. - # - # Example: - # - # mail = TMail::Mail.new - # mail.bcc = "Mikel , another Mikel " - # mail.bcc_addrs #=> [#, #] - def bcc_addrs=( arg ) - set_addrfield 'bcc', arg - end - - # Returns who the email is to as an Array of email addresses as opposed to an Array of - # TMail::Address objects which is what Mail#to_addrs returns - # - # Example: - # - # mail = TMail::Mail.new - # mail.to = "Mikel , another Mikel " - # mail.to #=> ["mikel@me.org", "mikel@you.org"] - def to( default = nil ) - addrs2specs(to_addrs(nil)) || default - end - - # Returns who the email cc'd as an Array of email addresses as opposed to an Array of - # TMail::Address objects which is what Mail#to_addrs returns - # - # Example: - # - # mail = TMail::Mail.new - # mail.cc = "Mikel , another Mikel " - # mail.cc #=> ["mikel@me.org", "mikel@you.org"] - def cc( default = nil ) - addrs2specs(cc_addrs(nil)) || default - end - - # Returns who the email bcc'd as an Array of email addresses as opposed to an Array of - # TMail::Address objects which is what Mail#to_addrs returns - # - # Example: - # - # mail = TMail::Mail.new - # mail.bcc = "Mikel , another Mikel " - # mail.bcc #=> ["mikel@me.org", "mikel@you.org"] - def bcc( default = nil ) - addrs2specs(bcc_addrs(nil)) || default - end - - # Destructively sets the "To:" field to the passed array of strings (which should be valid - # email addresses) - # - # Example: - # - # mail = TMail::Mail.new - # mail.to = ["mikel@abc.com", "Mikel "] - # mail.to #=> ["mikel@abc.org", "mikel@xyz.org"] - # mail['to'].to_s #=> "mikel@abc.com, Mikel " - def to=( *strs ) - set_string_array_attr 'To', strs - end - - # Destructively sets the "Cc:" field to the passed array of strings (which should be valid - # email addresses) - # - # Example: - # - # mail = TMail::Mail.new - # mail.cc = ["mikel@abc.com", "Mikel "] - # mail.cc #=> ["mikel@abc.org", "mikel@xyz.org"] - # mail['cc'].to_s #=> "mikel@abc.com, Mikel " - def cc=( *strs ) - set_string_array_attr 'Cc', strs - end - - # Destructively sets the "Bcc:" field to the passed array of strings (which should be valid - # email addresses) - # - # Example: - # - # mail = TMail::Mail.new - # mail.bcc = ["mikel@abc.com", "Mikel "] - # mail.bcc #=> ["mikel@abc.org", "mikel@xyz.org"] - # mail['bcc'].to_s #=> "mikel@abc.com, Mikel " - def bcc=( *strs ) - set_string_array_attr 'Bcc', strs - end - - #== Originator methods - - # Return a TMail::Addresses instance for each entry in the "From:" field of the mail object header. - # - # If the "From:" field does not exist, will return nil by default or the value you - # pass as the optional parameter. - # - # Example: - # - # mail = TMail::Mail.new - # mail.from_addrs #=> nil - # mail.from_addrs([]) #=> [] - # mail.from = "Mikel , another Mikel " - # mail.from_addrs #=> [#, #] - def from_addrs( default = nil ) - if h = @header['from'] - h.addrs - else - default - end - end - - # Destructively set the to value of the "From:" header to equal the passed in string. - # - # TMail will parse your contents and turn each valid email address into a TMail::Address - # object before assigning it to the mail message. - # - # Example: - # - # mail = TMail::Mail.new - # mail.from_addrs = "Mikel , another Mikel " - # mail.from_addrs #=> [#, #] - def from_addrs=( arg ) - set_addrfield 'from', arg - end - - # Returns who the email is from as an Array of email address strings instead to an Array of - # TMail::Address objects which is what Mail#from_addrs returns - # - # Example: - # - # mail = TMail::Mail.new - # mail.from = "Mikel , another Mikel " - # mail.from #=> ["mikel@me.org", "mikel@you.org"] - def from( default = nil ) - addrs2specs(from_addrs(nil)) || default - end - - # Destructively sets the "From:" field to the passed array of strings (which should be valid - # email addresses) - # - # Example: - # - # mail = TMail::Mail.new - # mail.from = ["mikel@abc.com", "Mikel "] - # mail.from #=> ["mikel@abc.org", "mikel@xyz.org"] - # mail['from'].to_s #=> "mikel@abc.com, Mikel " - def from=( *strs ) - set_string_array_attr 'From', strs - end - - # Returns the "friendly" human readable part of the address - # - # Example: - # - # mail = TMail::Mail.new - # mail.from = "Mikel Lindsaar " - # mail.friendly_from #=> "Mikel Lindsaar" - def friendly_from( default = nil ) - h = @header['from'] - a, = h.addrs - return default unless a - return a.phrase if a.phrase - return h.comments.join(' ') unless h.comments.empty? - a.spec - end - - # Return a TMail::Addresses instance for each entry in the "Reply-To:" field of the mail object header. - # - # If the "Reply-To:" field does not exist, will return nil by default or the value you - # pass as the optional parameter. - # - # Example: - # - # mail = TMail::Mail.new - # mail.reply_to_addrs #=> nil - # mail.reply_to_addrs([]) #=> [] - # mail.reply_to = "Mikel , another Mikel " - # mail.reply_to_addrs #=> [#, #] - def reply_to_addrs( default = nil ) - if h = @header['reply-to'] - h.addrs.blank? ? default : h.addrs - else - default - end - end - - # Destructively set the to value of the "Reply-To:" header to equal the passed in argument. - # - # TMail will parse your contents and turn each valid email address into a TMail::Address - # object before assigning it to the mail message. - # - # Example: - # - # mail = TMail::Mail.new - # mail.reply_to_addrs = "Mikel , another Mikel " - # mail.reply_to_addrs #=> [#, #] - def reply_to_addrs=( arg ) - set_addrfield 'reply-to', arg - end - - # Returns who the email is from as an Array of email address strings instead to an Array of - # TMail::Address objects which is what Mail#reply_to_addrs returns - # - # Example: - # - # mail = TMail::Mail.new - # mail.reply_to = "Mikel , another Mikel " - # mail.reply_to #=> ["mikel@me.org", "mikel@you.org"] - def reply_to( default = nil ) - addrs2specs(reply_to_addrs(nil)) || default - end - - # Destructively sets the "Reply-To:" field to the passed array of strings (which should be valid - # email addresses) - # - # Example: - # - # mail = TMail::Mail.new - # mail.reply_to = ["mikel@abc.com", "Mikel "] - # mail.reply_to #=> ["mikel@abc.org", "mikel@xyz.org"] - # mail['reply_to'].to_s #=> "mikel@abc.com, Mikel " - def reply_to=( *strs ) - set_string_array_attr 'Reply-To', strs - end - - # Return a TMail::Addresses instance of the "Sender:" field of the mail object header. - # - # If the "Sender:" field does not exist, will return nil by default or the value you - # pass as the optional parameter. - # - # Example: - # - # mail = TMail::Mail.new - # mail.sender #=> nil - # mail.sender([]) #=> [] - # mail.sender = "Mikel " - # mail.reply_to_addrs #=> [#] - def sender_addr( default = nil ) - f = @header['sender'] or return default - f.addr or return default - end - - # Destructively set the to value of the "Sender:" header to equal the passed in argument. - # - # TMail will parse your contents and turn each valid email address into a TMail::Address - # object before assigning it to the mail message. - # - # Example: - # - # mail = TMail::Mail.new - # mail.sender_addrs = "Mikel , another Mikel " - # mail.sender_addrs #=> [#, #] - def sender_addr=( addr ) - if addr - h = HeaderField.internal_new('sender', @config) - h.addr = addr - @header['sender'] = h - else - @header.delete 'sender' - end - addr - end - - # Returns who the sender of this mail is as string instead to an Array of - # TMail::Address objects which is what Mail#sender_addr returns - # - # Example: - # - # mail = TMail::Mail.new - # mail.sender = "Mikel " - # mail.sender #=> "mikel@me.org" - def sender( default = nil ) - f = @header['sender'] or return default - a = f.addr or return default - a.spec - end - - # Destructively sets the "Sender:" field to the passed string (which should be a valid - # email address) - # - # Example: - # - # mail = TMail::Mail.new - # mail.sender = "mikel@abc.com" - # mail.sender #=> "mikel@abc.org" - # mail['sender'].to_s #=> "mikel@abc.com" - def sender=( str ) - set_string_attr 'Sender', str - end - - #== Subject methods - - # Returns the subject of the mail instance. - # - # If the subject field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.subject #=> nil - # mail.subject("") #=> "" - # mail.subject = "Hello" - # mail.subject #=> "Hello" - def subject( default = nil ) - if h = @header['subject'] - h.body - else - default - end - end - alias quoted_subject subject - - # Destructively sets the passed string as the subject of the mail message. - # - # Example - # - # mail = TMail::Mail.new - # mail.subject #=> "This subject" - # mail.subject = "Another subject" - # mail.subject #=> "Another subject" - def subject=( str ) - set_string_attr 'Subject', str - end - - #== Message Identity & Threading Methods - - # Returns the message ID for this mail object instance. - # - # If the message_id field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.message_id #=> nil - # mail.message_id(TMail.new_message_id) #=> "<47404c5326d9c_2ad4fbb80161@baci.local.tmail>" - # mail.message_id = TMail.new_message_id - # mail.message_id #=> "<47404c5326d9c_2ad4fbb80161@baci.local.tmail>" - def message_id( default = nil ) - if h = @header['message-id'] - h.id || default - else - default - end - end - - # Destructively sets the message ID of the mail object instance to the passed in string - # - # Example: - # - # mail = TMail::Mail.new - # mail.message_id = "this_is_my_badly_formatted_message_id" - # mail.message_id #=> "this_is_my_badly_formatted_message_id" - def message_id=( str ) - set_string_attr 'Message-Id', str - end - - # Returns the "In-Reply-To:" field contents as an array of this mail instance if it exists - # - # If the in_reply_to field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.in_reply_to #=> nil - # mail.in_reply_to([]) #=> [] - # TMail::Mail.load("../test/fixtures/raw_email_reply") - # mail.in_reply_to #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] - def in_reply_to( default = nil ) - if h = @header['in-reply-to'] - h.ids - else - default - end - end - - # Destructively sets the value of the "In-Reply-To:" field of an email. - # - # Accepts an array of a single string of a message id - # - # Example: - # - # mail = TMail::Mail.new - # mail.in_reply_to = ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] - # mail.in_reply_to #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] - def in_reply_to=( *idstrs ) - set_string_array_attr 'In-Reply-To', idstrs - end - - # Returns the references of this email (prior messages relating to this message) - # as an array of message ID strings. Useful when you are trying to thread an - # email. - # - # If the references field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.references #=> nil - # mail.references([]) #=> [] - # mail = TMail::Mail.load("../test/fixtures/raw_email_reply") - # mail.references #=> ["<473FF3B8.9020707@xxx.org>", "<348F04F142D69C21-291E56D292BC@xxxx.net>"] - def references( default = nil ) - if h = @header['references'] - h.refs - else - default - end - end - - # Destructively sets the value of the "References:" field of an email. - # - # Accepts an array of strings of message IDs - # - # Example: - # - # mail = TMail::Mail.new - # mail.references = ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] - # mail.references #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] - def references=( *strs ) - set_string_array_attr 'References', strs - end - - #== MIME header methods - - # Returns the listed MIME version of this email from the "Mime-Version:" header field - # - # If the mime_version field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.mime_version #=> nil - # mail.mime_version([]) #=> [] - # mail = TMail::Mail.load("../test/fixtures/raw_email") - # mail.mime_version #=> "1.0" - def mime_version( default = nil ) - if h = @header['mime-version'] - h.version || default - else - default - end - end - - def mime_version=( m, opt = nil ) - if opt - if h = @header['mime-version'] - h.major = m - h.minor = opt - else - store 'Mime-Version', "#{m}.#{opt}" - end - else - store 'Mime-Version', m - end - m - end - - # Returns the current "Content-Type" of the mail instance. - # - # If the content_type field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.content_type #=> nil - # mail.content_type([]) #=> [] - # mail = TMail::Mail.load("../test/fixtures/raw_email") - # mail.content_type #=> "text/plain" - def content_type( default = nil ) - if h = @header['content-type'] - h.content_type || default - else - default - end - end - - # Returns the current main type of the "Content-Type" of the mail instance. - # - # If the content_type field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.main_type #=> nil - # mail.main_type([]) #=> [] - # mail = TMail::Mail.load("../test/fixtures/raw_email") - # mail.main_type #=> "text" - def main_type( default = nil ) - if h = @header['content-type'] - h.main_type || default - else - default - end - end - - # Returns the current sub type of the "Content-Type" of the mail instance. - # - # If the content_type field does not exist, returns nil by default or you can pass in as - # the parameter for what you want the default value to be. - # - # Example: - # - # mail = TMail::Mail.new - # mail.sub_type #=> nil - # mail.sub_type([]) #=> [] - # mail = TMail::Mail.load("../test/fixtures/raw_email") - # mail.sub_type #=> "plain" - def sub_type( default = nil ) - if h = @header['content-type'] - h.sub_type || default - else - default - end - end - - # Destructively sets the "Content-Type:" header field of this mail object - # - # Allows you to set the main type, sub type as well as parameters to the field. - # The main type and sub type need to be a string. - # - # The optional params hash can be passed with keys as symbols and values as a string, - # or strings as keys and values. - # - # Example: - # - # mail = TMail::Mail.new - # mail.set_content_type("text", "plain") - # mail.to_s #=> "Content-Type: text/plain\n\n" - # - # mail.set_content_type("text", "plain", {:charset => "EUC-KR", :format => "flowed"}) - # mail.to_s #=> "Content-Type: text/plain; charset=EUC-KR; format=flowed\n\n" - # - # mail.set_content_type("text", "plain", {"charset" => "EUC-KR", "format" => "flowed"}) - # mail.to_s #=> "Content-Type: text/plain; charset=EUC-KR; format=flowed\n\n" - 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 - else - store 'Content-Type', "#{main}/#{sub}" - end - @header['content-type'].params.replace param if param - str - end - - alias content_type= set_content_type - - # Returns the named type parameter as a string, from the "Content-Type:" header. - # - # Example: - # - # mail = TMail::Mail.new - # mail.type_param("charset") #=> nil - # mail.type_param("charset", []) #=> [] - # mail.set_content_type("text", "plain", {:charset => "EUC-KR", :format => "flowed"}) - # mail.type_param("charset") #=> "EUC-KR" - # mail.type_param("format") #=> "flowed" - def type_param( name, default = nil ) - if h = @header['content-type'] - h[name] || default - else - default - end - end - - # Returns the character set of the email. Returns nil if no encoding set or returns - # whatever default you pass as a parameter - note passing the parameter does NOT change - # the mail object in any way. - # - # Example: - # - # mail = TMail::Mail.load("path_to/utf8_email") - # mail.charset #=> "UTF-8" - # - # mail = TMail::Mail.new - # mail.charset #=> nil - # mail.charset("US-ASCII") #=> "US-ASCII" - def charset( default = nil ) - if h = @header['content-type'] - h['charset'] or default - else - default - end - end - - # Destructively sets the character set used by this mail object to the passed string, you - # should note though that this does nothing to the mail body, just changes the header - # value, you will need to transliterate the body as well to match whatever you put - # in this header value if you are changing character sets. - # - # Example: - # - # mail = TMail::Mail.new - # mail.charset #=> nil - # mail.charset = "UTF-8" - # mail.charset #=> "UTF-8" - def charset=( str ) - if str - if h = @header[ 'content-type' ] - h['charset'] = str - else - store 'Content-Type', "text/plain; charset=#{str}" - end - end - str - end - - # Returns the transfer encoding of the email. Returns nil if no encoding set or returns - # whatever default you pass as a parameter - note passing the parameter does NOT change - # the mail object in any way. - # - # Example: - # - # mail = TMail::Mail.load("path_to/base64_encoded_email") - # mail.transfer_encoding #=> "base64" - # - # mail = TMail::Mail.new - # mail.transfer_encoding #=> nil - # mail.transfer_encoding("base64") #=> "base64" - def transfer_encoding( default = nil ) - if h = @header['content-transfer-encoding'] - h.encoding || default - else - default - end - end - - # Destructively sets the transfer encoding of the mail object to the passed string, you - # should note though that this does nothing to the mail body, just changes the header - # value, you will need to encode or decode the body as well to match whatever you put - # in this header value. - # - # Example: - # - # mail = TMail::Mail.new - # mail.transfer_encoding #=> nil - # mail.transfer_encoding = "base64" - # mail.transfer_encoding #=> "base64" - def transfer_encoding=( str ) - set_string_attr 'Content-Transfer-Encoding', str - end - - alias encoding transfer_encoding - alias encoding= transfer_encoding= - alias content_transfer_encoding transfer_encoding - alias content_transfer_encoding= transfer_encoding= - - # Returns the content-disposition of the mail object, returns nil or the passed - # default value if given - # - # Example: - # - # mail = TMail::Mail.load("path_to/raw_mail_with_attachment") - # mail.disposition #=> "attachment" - # - # mail = TMail::Mail.load("path_to/plain_simple_email") - # mail.disposition #=> nil - # mail.disposition(false) #=> false - def disposition( default = nil ) - if h = @header['content-disposition'] - h.disposition || default - else - default - end - end - - alias content_disposition disposition - - # Allows you to set the content-disposition of the mail object. Accepts a type - # and a hash of parameters. - # - # Example: - # - # mail.set_disposition("attachment", {:filename => "test.rb"}) - # mail.disposition #=> "attachment" - # mail['content-disposition'].to_s #=> "attachment; filename=test.rb" - def set_disposition( str, params = nil ) - if h = @header['content-disposition'] - h.disposition = str - h.params.clear - else - store('Content-Disposition', str) - h = @header['content-disposition'] - end - h.params.replace params if params - end - - alias disposition= set_disposition - alias set_content_disposition set_disposition - alias content_disposition= set_disposition - - # Returns the value of a parameter in an existing content-disposition header - # - # Example: - # - # mail.set_disposition("attachment", {:filename => "test.rb"}) - # mail['content-disposition'].to_s #=> "attachment; filename=test.rb" - # mail.disposition_param("filename") #=> "test.rb" - # mail.disposition_param("missing_param_key") #=> nil - # mail.disposition_param("missing_param_key", false) #=> false - # mail.disposition_param("missing_param_key", "Nothing to see here") #=> "Nothing to see here" - def disposition_param( name, default = nil ) - if h = @header['content-disposition'] - h[name] || default - else - default - end - end - - # Convert the Mail object's body into a Base64 encoded email - # returning the modified Mail object - def base64_encode! - store 'Content-Transfer-Encoding', 'Base64' - self.body = base64_encode - end - - # Return the result of encoding the TMail::Mail object body - # without altering the current body - def base64_encode - Base64.folding_encode(self.body) - end - - # Convert the Mail object's body into a Base64 decoded email - # returning the modified Mail object - def base64_decode! - if /base64/i === self.transfer_encoding('') - store 'Content-Transfer-Encoding', '8bit' - self.body = base64_decode - end - end - - # Returns the result of decoding the TMail::Mail object body - # without altering the current body - def base64_decode - Base64.decode(self.body, @config.strict_base64decode?) - end - - # Returns an array of each destination in the email message including to: cc: or bcc: - # - # Example: - # - # mail.to = "Mikel " - # mail.cc = "Trans " - # mail.bcc = "bob " - # mail.destinations #=> ["mikel@lindsaar.net", "t@t.com", "bob@me.com"] - def destinations( default = nil ) - ret = [] - %w( to cc bcc ).each do |nm| - if h = @header[nm] - h.addrs.each {|i| ret.push i.address } - end - end - ret.empty? ? default : ret - end - - # Yields a block of destination, yielding each as a string. - # (from the destinations example) - # mail.each_destination { |d| puts "#{d.class}: #{d}" } - # String: mikel@lindsaar.net - # String: t@t.com - # String: bob@me.com - def each_destination( &block ) - destinations([]).each do |i| - if Address === i - yield i - else - i.each(&block) - end - end - end - - alias each_dest each_destination - - # Returns an array of reply to addresses that the Mail object has, - # or if the Mail message has no reply-to, returns an array of the - # Mail objects from addresses. Else returns the default which can - # either be passed as a parameter or defaults to nil - # - # Example: - # mail.from = "Mikel " - # mail.reply_to = nil - # mail.reply_addresses #=> [""] - # - def reply_addresses( default = nil ) - reply_to_addrs(nil) or from_addrs(nil) or default - end - - # Returns the "sender" field as an array -> useful to find out who to - # send an error email to. - def error_reply_addresses( default = nil ) - if s = sender(nil) - [s] - else - from_addrs(default) - end - end - - # Returns true if the Mail object is a multipart message - def multipart? - main_type('').downcase == 'multipart' - end - - # Creates a new email in reply to self. Sets the In-Reply-To and - # References headers for you automagically. - # - # Example: - # mail = TMail::Mail.load("my_email") - # reply_email = mail.create_reply - # reply_email.class #=> TMail::Mail - # reply_email.references #=> [""] - # reply_email.in_reply_to #=> [""] - def create_reply - setup_reply create_empty_mail() - end - - # Creates a new email in reply to self. Sets the In-Reply-To and - # References headers for you automagically. - # - # Example: - # mail = TMail::Mail.load("my_email") - # forward_email = mail.create_forward - # forward_email.class #=> TMail::Mail - # forward_email.content_type #=> "multipart/mixed" - # forward_email.body #=> "Attachment: (unnamed)" - # forward_email.encoded #=> Returns the original email as a MIME attachment - def create_forward - setup_forward create_empty_mail() - end - - #:stopdoc: - private - - def create_empty_mail - self.class.new(StringPort.new(''), @config) - end - - def setup_reply( mail ) - if tmp = reply_addresses(nil) - mail.to_addrs = tmp - end - - mid = message_id(nil) - tmp = references(nil) || [] - tmp.push mid if mid - mail.in_reply_to = [mid] if mid - mail.references = tmp unless tmp.empty? - mail.subject = 'Re: ' + subject('').sub(/\A(?:\[[^\]]+\])?(?:\s*Re:)*\s*/i, '') - mail.mime_version = '1.0' - mail - end - - def setup_forward( mail ) - m = Mail.new(StringPort.new('')) - m.body = decoded - m.set_content_type 'message', 'rfc822' - m.encoding = encoding('7bit') - mail.parts.push m - # call encoded to reparse the message - mail.encoded - mail - end - - #:startdoc: - end # class Mail - -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/loader.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/loader.rb deleted file mode 100644 index 6c0e251102..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/loader.rb +++ /dev/null @@ -1,3 +0,0 @@ -#:stopdoc: -require 'tmail/mailbox' -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mail.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mail.rb deleted file mode 100644 index fef6b01c39..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mail.rb +++ /dev/null @@ -1,578 +0,0 @@ -=begin rdoc - -= Mail class - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - - - -require 'tmail/interface' -require 'tmail/encode' -require 'tmail/header' -require 'tmail/port' -require 'tmail/config' -require 'tmail/utils' -require 'tmail/attachments' -require 'tmail/quoting' -require 'socket' - -module TMail - - # == Mail Class - # - # Accessing a TMail object done via the TMail::Mail class. As email can be fairly complex - # creatures, you will find a large amount of accessor and setter methods in this class! - # - # Most of the below methods handle the header, in fact, what TMail does best is handle the - # header of the email object. There are only a few methods that deal directly with the body - # of the email, such as base64_encode and base64_decode. - # - # === Using TMail inside your code - # - # The usual way is to install the gem (see the {README}[link:/README] on how to do this) and - # then put at the top of your class: - # - # require 'tmail' - # - # You can then create a new TMail object in your code with: - # - # @email = TMail::Mail.new - # - # Or if you have an email as a string, you can initialize a new TMail::Mail object and get it - # to parse that string for you like so: - # - # @email = TMail::Mail.parse(email_text) - # - # You can also read a single email off the disk, for example: - # - # @email = TMail::Mail.load('filename.txt') - # - # Also, you can read a mailbox (usual unix mbox format) and end up with an array of TMail - # objects by doing something like this: - # - # # Note, we pass true as the last variable to open the mailbox read only - # mailbox = TMail::UNIXMbox.new("mailbox", nil, true) - # @emails = [] - # mailbox.each_port { |m| @emails << TMail::Mail.new(m) } - # - class Mail - - class << self - - # Opens an email that has been saved out as a file by itself. - # - # This function will read a file non-destructively and then parse - # the contents and return a TMail::Mail object. - # - # Does not handle multiple email mailboxes (like a unix mbox) for that - # use the TMail::UNIXMbox class. - # - # Example: - # mail = TMail::Mail.load('filename') - # - def load( fname ) - new(FilePort.new(fname)) - end - - alias load_from load - alias loadfrom load - - # Parses an email from the supplied string and returns a TMail::Mail - # object. - # - # Example: - # require 'rubygems'; require 'tmail' - # email_string =< # bodyport=nil> - # mail.body - # #=> "Hello there Mikel!\n\n" - def parse( str ) - new(StringPort.new(str)) - end - - end - - def initialize( port = nil, conf = DEFAULT_CONFIG ) #:nodoc: - @port = port || StringPort.new - @config = Config.to_config(conf) - - @header = {} - @body_port = nil - @body_parsed = false - @epilogue = '' - @parts = [] - - @port.ropen {|f| - parse_header f - parse_body f unless @port.reproducible? - } - end - - # Provides access to the port this email is using to hold it's data - # - # Example: - # mail = TMail::Mail.parse(email_string) - # mail.port - # #=> # - attr_reader :port - - def inspect - "\#<#{self.class} port=#{@port.inspect} bodyport=#{@body_port.inspect}>" - end - - # - # to_s interfaces - # - - public - - include StrategyInterface - - def write_back( eol = "\n", charset = 'e' ) - parse_body - @port.wopen {|stream| encoded eol, charset, stream } - end - - def accept( strategy ) - with_multipart_encoding(strategy) { - ordered_each do |name, field| - next if field.empty? - strategy.header_name canonical(name) - field.accept strategy - strategy.puts - end - strategy.puts - body_port().ropen {|r| - strategy.write r.read - } - } - end - - private - - def canonical( name ) - name.split(/-/).map {|s| s.capitalize }.join('-') - end - - def with_multipart_encoding( strategy ) - if parts().empty? # DO NOT USE @parts - yield - - else - bound = ::TMail.new_boundary - if @header.key? 'content-type' - @header['content-type'].params['boundary'] = bound - else - store 'Content-Type', % - end - - yield - - parts().each do |tm| - strategy.puts - strategy.puts '--' + bound - tm.accept strategy - end - strategy.puts - strategy.puts '--' + bound + '--' - strategy.write epilogue() - end - end - - ### - ### header - ### - - public - - ALLOW_MULTIPLE = { - 'received' => true, - 'resent-date' => true, - 'resent-from' => true, - 'resent-sender' => true, - 'resent-to' => true, - 'resent-cc' => true, - 'resent-bcc' => true, - 'resent-message-id' => true, - 'comments' => true, - 'keywords' => true - } - USE_ARRAY = ALLOW_MULTIPLE - - def header - @header.dup - end - - # Returns a TMail::AddressHeader object of the field you are querying. - # Examples: - # @mail['from'] #=> # - # @mail['to'] #=> # - # - # You can get the string value of this by passing "to_s" to the query: - # Example: - # @mail['to'].to_s #=> "mikel@test.com.au" - def []( key ) - @header[key.downcase] - end - - def sub_header(key, param) - (hdr = self[key]) ? hdr[param] : nil - end - - alias fetch [] - - # Allows you to set or delete TMail header objects at will. - # Eamples: - # @mail = TMail::Mail.new - # @mail['to'].to_s # => 'mikel@test.com.au' - # @mail['to'] = 'mikel@elsewhere.org' - # @mail['to'].to_s # => 'mikel@elsewhere.org' - # @mail.encoded # => "To: mikel@elsewhere.org\r\n\r\n" - # @mail['to'] = nil - # @mail['to'].to_s # => nil - # @mail.encoded # => "\r\n" - # - # Note: setting mail[] = nil actualy deletes the header field in question from the object, - # it does not just set the value of the hash to nil - def []=( key, val ) - dkey = key.downcase - - if val.nil? - @header.delete dkey - return nil - end - - case val - when String - header = new_hf(key, val) - when HeaderField - ; - when Array - ALLOW_MULTIPLE.include? dkey or - raise ArgumentError, "#{key}: Header must not be multiple" - @header[dkey] = val - return val - else - header = new_hf(key, val.to_s) - end - if ALLOW_MULTIPLE.include? dkey - (@header[dkey] ||= []).push header - else - @header[dkey] = header - end - - val - end - - alias store []= - - # Allows you to loop through each header in the TMail::Mail object in a block - # Example: - # @mail['to'] = 'mikel@elsewhere.org' - # @mail['from'] = 'me@me.com' - # @mail.each_header { |k,v| puts "#{k} = #{v}" } - # # => from = me@me.com - # # => to = mikel@elsewhere.org - def each_header - @header.each do |key, val| - [val].flatten.each {|v| yield key, v } - end - end - - alias each_pair each_header - - def each_header_name( &block ) - @header.each_key(&block) - end - - alias each_key each_header_name - - def each_field( &block ) - @header.values.flatten.each(&block) - end - - alias each_value each_field - - FIELD_ORDER = %w( - return-path received - resent-date resent-from resent-sender resent-to - resent-cc resent-bcc resent-message-id - date from sender reply-to to cc bcc - message-id in-reply-to references - subject comments keywords - mime-version content-type content-transfer-encoding - content-disposition content-description - ) - - def ordered_each - list = @header.keys - FIELD_ORDER.each do |name| - if list.delete(name) - [@header[name]].flatten.each {|v| yield name, v } - end - end - list.each do |name| - [@header[name]].flatten.each {|v| yield name, v } - end - end - - def clear - @header.clear - end - - def delete( key ) - @header.delete key.downcase - end - - def delete_if - @header.delete_if do |key,val| - if Array === val - val.delete_if {|v| yield key, v } - val.empty? - else - yield key, val - end - end - end - - def keys - @header.keys - end - - def key?( key ) - @header.key? key.downcase - end - - def values_at( *args ) - args.map {|k| @header[k.downcase] }.flatten - end - - alias indexes values_at - alias indices values_at - - private - - def parse_header( f ) - name = field = nil - unixfrom = nil - - while line = f.gets - case line - when /\A[ \t]/ # continue from prev line - raise SyntaxError, 'mail is began by space' unless field - field << ' ' << line.strip - - when /\A([^\: \t]+):\s*/ # new header line - add_hf name, field if field - name = $1 - field = $' #.strip - - when /\A\-*\s*\z/ # end of header - add_hf name, field if field - name = field = nil - break - - when /\AFrom (\S+)/ - unixfrom = $1 - - when /^charset=.*/ - - else - raise SyntaxError, "wrong mail header: '#{line.inspect}'" - end - end - add_hf name, field if name - - if unixfrom - add_hf 'Return-Path', "<#{unixfrom}>" unless @header['return-path'] - end - end - - def add_hf( name, field ) - key = name.downcase - field = new_hf(name, field) - - if ALLOW_MULTIPLE.include? key - (@header[key] ||= []).push field - else - @header[key] = field - end - end - - def new_hf( name, field ) - HeaderField.new(name, field, @config) - end - - ### - ### body - ### - - public - - def body_port - parse_body - @body_port - end - - def each( &block ) - body_port().ropen {|f| f.each(&block) } - end - - def quoted_body - body_port.ropen {|f| return f.read } - end - - def quoted_body= str - body_port.wopen { |f| f.write str } - str - end - - def body=( str ) - # Sets the body of the email to a new (encoded) string. - # - # We also reparses the email if the body is ever reassigned, this is a performance hit, however when - # you assign the body, you usually want to be able to make sure that you can access the attachments etc. - # - # Usage: - # - # mail.body = "Hello, this is\nthe body text" - # # => "Hello, this is\nthe body" - # mail.body - # # => "Hello, this is\nthe body" - @body_parsed = false - parse_body(StringInput.new(str)) - parse_body - @body_port.wopen {|f| f.write str } - str - end - - alias preamble quoted_body - alias preamble= quoted_body= - - def epilogue - parse_body - @epilogue.dup - end - - def epilogue=( str ) - parse_body - @epilogue = str - str - end - - def parts - parse_body - @parts - end - - def each_part( &block ) - parts().each(&block) - end - - # Returns true if the content type of this part of the email is - # a disposition attachment - def disposition_is_attachment? - (self['content-disposition'] && self['content-disposition'].disposition == "attachment") - end - - # Returns true if this part's content main type is text, else returns false. - # By main type is meant "text/plain" is text. "text/html" is text - def content_type_is_text? - self.header['content-type'] && (self.header['content-type'].main_type != "text") - end - - private - - def parse_body( f = nil ) - return if @body_parsed - if f - parse_body_0 f - else - @port.ropen {|f| - skip_header f - parse_body_0 f - } - end - @body_parsed = true - end - - def skip_header( f ) - while line = f.gets - return if /\A[\r\n]*\z/ === line - end - end - - def parse_body_0( f ) - if multipart? - read_multipart f - else - @body_port = @config.new_body_port(self) - @body_port.wopen {|w| - w.write f.read - } - end - end - - def read_multipart( src ) - bound = @header['content-type'].params['boundary'] - is_sep = /\A--#{Regexp.quote bound}(?:--)?[ \t]*(?:\n|\r\n|\r)/ - lastbound = "--#{bound}--" - - ports = [ @config.new_preamble_port(self) ] - begin - f = ports.last.wopen - while line = src.gets - if is_sep === line - f.close - break if line.strip == lastbound - ports.push @config.new_part_port(self) - f = ports.last.wopen - else - f << line - end - end - @epilogue = (src.read || '') - ensure - f.close if f and not f.closed? - end - - @body_port = ports.shift - @parts = ports.map {|p| self.class.new(p, @config) } - end - - end # class Mail - -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mailbox.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mailbox.rb deleted file mode 100644 index b0bc6a7f74..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mailbox.rb +++ /dev/null @@ -1,495 +0,0 @@ -=begin rdoc - -= Mailbox and Mbox interaction class - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -require 'tmail/port' -require 'socket' -require 'mutex_m' - - -unless [].respond_to?(:sort_by) -module Enumerable#:nodoc: - def sort_by - map {|i| [yield(i), i] }.sort {|a,b| a.first <=> b.first }.map {|i| i[1] } - end -end -end - - -module TMail - - class MhMailbox - - PORT_CLASS = MhPort - - def initialize( dir ) - edir = File.expand_path(dir) - raise ArgumentError, "not directory: #{dir}"\ - unless FileTest.directory? edir - @dirname = edir - @last_file = nil - @last_atime = nil - end - - def directory - @dirname - end - - alias dirname directory - - attr_accessor :last_atime - - def inspect - "#<#{self.class} #{@dirname}>" - end - - def close - end - - def new_port - PORT_CLASS.new(next_file_name()) - end - - def each_port - mail_files().each do |path| - yield PORT_CLASS.new(path) - end - @last_atime = Time.now - end - - alias each each_port - - def reverse_each_port - mail_files().reverse_each do |path| - yield PORT_CLASS.new(path) - end - @last_atime = Time.now - end - - alias reverse_each reverse_each_port - - # old #each_mail returns Port - #def each_mail - # each_port do |port| - # yield Mail.new(port) - # end - #end - - def each_new_port( mtime = nil, &block ) - mtime ||= @last_atime - return each_port(&block) unless mtime - return unless File.mtime(@dirname) >= mtime - - mail_files().each do |path| - yield PORT_CLASS.new(path) if File.mtime(path) > mtime - end - @last_atime = Time.now - end - - private - - def mail_files - Dir.entries(@dirname)\ - .select {|s| /\A\d+\z/ === s }\ - .map {|s| s.to_i }\ - .sort\ - .map {|i| "#{@dirname}/#{i}" }\ - .select {|path| FileTest.file? path } - end - - def next_file_name - unless n = @last_file - n = 0 - Dir.entries(@dirname)\ - .select {|s| /\A\d+\z/ === s }\ - .map {|s| s.to_i }.sort\ - .each do |i| - next unless FileTest.file? "#{@dirname}/#{i}" - n = i - end - end - begin - n += 1 - end while FileTest.exist? "#{@dirname}/#{n}" - @last_file = n - - "#{@dirname}/#{n}" - end - - end # MhMailbox - - MhLoader = MhMailbox - - - class UNIXMbox - - class << self - alias newobj new - end - - # Creates a new mailbox object that you can iterate through to collect the - # emails from with "each_port". - # - # You need to pass it a filename of a unix mailbox format file, the format of this - # file can be researched at this page at {wikipedia}[link:http://en.wikipedia.org/wiki/Mbox] - # - # ==== Parameters - # - # +filename+: The filename of the mailbox you want to open - # - # +tmpdir+: Can be set to override TMail using the system environment's temp dir. TMail will first - # use the temp dir specified by you (if any) or then the temp dir specified in the Environment's TEMP - # value then the value in the Environment's TMP value or failing all of the above, '/tmp' - # - # +readonly+: If set to false, each email you take from the mail box will be removed from the mailbox. - # default is *false* - ie, it *WILL* truncate your mailbox file to ZERO once it has read the emails out. - # - # ==== Options: - # - # None - # - # ==== Examples: - # - # # First show using readonly true: - # - # require 'ftools' - # File.size("../test/fixtures/mailbox") - # #=> 20426 - # - # mailbox = TMail::UNIXMbox.new("../test/fixtures/mailbox", nil, true) - # #=> # - # - # mailbox.each_port do |port| - # mail = TMail::Mail.new(port) - # puts mail.subject - # end - # #Testing mailbox 1 - # #Testing mailbox 2 - # #Testing mailbox 3 - # #Testing mailbox 4 - # require 'ftools' - # File.size?("../test/fixtures/mailbox") - # #=> 20426 - # - # # Now show with readonly set to the default false - # - # mailbox = TMail::UNIXMbox.new("../test/fixtures/mailbox") - # #=> # - # - # mailbox.each_port do |port| - # mail = TMail::Mail.new(port) - # puts mail.subject - # end - # #Testing mailbox 1 - # #Testing mailbox 2 - # #Testing mailbox 3 - # #Testing mailbox 4 - # - # File.size?("../test/fixtures/mailbox") - # #=> nil - def UNIXMbox.new( filename, tmpdir = nil, readonly = false ) - tmpdir = ENV['TEMP'] || ENV['TMP'] || '/tmp' - newobj(filename, "#{tmpdir}/ruby_tmail_#{$$}_#{rand()}", readonly, false) - end - - def UNIXMbox.lock( fname ) - begin - f = File.open(fname, 'r+') - f.flock File::LOCK_EX - yield f - ensure - f.flock File::LOCK_UN - f.close if f and not f.closed? - end - end - - def UNIXMbox.static_new( fname, dir, readonly = false ) - newobj(fname, dir, readonly, true) - end - - def initialize( fname, mhdir, readonly, static ) - @filename = fname - @readonly = readonly - @closed = false - - Dir.mkdir mhdir - @real = MhMailbox.new(mhdir) - @finalizer = UNIXMbox.mkfinal(@real, @filename, !@readonly, !static) - ObjectSpace.define_finalizer self, @finalizer - end - - def UNIXMbox.mkfinal( mh, mboxfile, writeback_p, cleanup_p ) - lambda { - if writeback_p - lock(mboxfile) {|f| - mh.each_port do |port| - f.puts create_from_line(port) - port.ropen {|r| - f.puts r.read - } - end - } - end - if cleanup_p - Dir.foreach(mh.dirname) do |fname| - next if /\A\.\.?\z/ === fname - File.unlink "#{mh.dirname}/#{fname}" - end - Dir.rmdir mh.dirname - end - } - end - - # make _From line - def UNIXMbox.create_from_line( port ) - sprintf 'From %s %s', - fromaddr(), TextUtils.time2str(File.mtime(port.filename)) - end - - def UNIXMbox.fromaddr(port) - h = HeaderField.new_from_port(port, 'Return-Path') || - HeaderField.new_from_port(port, 'From') || - HeaderField.new_from_port(port, 'EnvelopeSender') or return 'nobody' - a = h.addrs[0] or return 'nobody' - a.spec - end - - def close - return if @closed - - ObjectSpace.undefine_finalizer self - @finalizer.call - @finalizer = nil - @real = nil - @closed = true - @updated = nil - end - - def each_port( &block ) - close_check - update - @real.each_port(&block) - end - - alias each each_port - - def reverse_each_port( &block ) - close_check - update - @real.reverse_each_port(&block) - end - - alias reverse_each reverse_each_port - - # old #each_mail returns Port - #def each_mail( &block ) - # each_port do |port| - # yield Mail.new(port) - # end - #end - - def each_new_port( mtime = nil ) - close_check - update - @real.each_new_port(mtime) {|p| yield p } - end - - def new_port - close_check - @real.new_port - end - - private - - def close_check - @closed and raise ArgumentError, 'accessing already closed mbox' - end - - def update - return if FileTest.zero?(@filename) - return if @updated and File.mtime(@filename) < @updated - w = nil - port = nil - time = nil - UNIXMbox.lock(@filename) {|f| - begin - f.each do |line| - if /\AFrom / === line - w.close if w - File.utime time, time, port.filename if time - - port = @real.new_port - w = port.wopen - time = fromline2time(line) - else - w.print line if w - end - end - ensure - if w and not w.closed? - w.close - File.utime time, time, port.filename if time - end - end - f.truncate(0) unless @readonly - @updated = Time.now - } - end - - def fromline2time( line ) - m = /\AFrom \S+ \w+ (\w+) (\d+) (\d+):(\d+):(\d+) (\d+)/.match(line) \ - or return nil - Time.local(m[6].to_i, m[1], m[2].to_i, m[3].to_i, m[4].to_i, m[5].to_i) - end - - end # UNIXMbox - - MboxLoader = UNIXMbox - - - class Maildir - - extend Mutex_m - - PORT_CLASS = MaildirPort - - @seq = 0 - def Maildir.unique_number - synchronize { - @seq += 1 - return @seq - } - end - - def initialize( dir = nil ) - @dirname = dir || ENV['MAILDIR'] - raise ArgumentError, "not directory: #{@dirname}"\ - unless FileTest.directory? @dirname - @new = "#{@dirname}/new" - @tmp = "#{@dirname}/tmp" - @cur = "#{@dirname}/cur" - end - - def directory - @dirname - end - - def inspect - "#<#{self.class} #{@dirname}>" - end - - def close - end - - def each_port - mail_files(@cur).each do |path| - yield PORT_CLASS.new(path) - end - end - - alias each each_port - - def reverse_each_port - mail_files(@cur).reverse_each do |path| - yield PORT_CLASS.new(path) - end - end - - alias reverse_each reverse_each_port - - def new_port - fname = nil - tmpfname = nil - newfname = nil - - begin - fname = "#{Time.now.to_i}.#{$$}_#{Maildir.unique_number}.#{Socket.gethostname}" - - tmpfname = "#{@tmp}/#{fname}" - newfname = "#{@new}/#{fname}" - end while FileTest.exist? tmpfname - - if block_given? - File.open(tmpfname, 'w') {|f| yield f } - File.rename tmpfname, newfname - PORT_CLASS.new(newfname) - else - File.open(tmpfname, 'w') {|f| f.write "\n\n" } - PORT_CLASS.new(tmpfname) - end - end - - def each_new_port - mail_files(@new).each do |path| - dest = @cur + '/' + File.basename(path) - File.rename path, dest - yield PORT_CLASS.new(dest) - end - - check_tmp - end - - TOO_OLD = 60 * 60 * 36 # 36 hour - - def check_tmp - old = Time.now.to_i - TOO_OLD - - each_filename(@tmp) do |full, fname| - if FileTest.file? full and - File.stat(full).mtime.to_i < old - File.unlink full - end - end - end - - private - - def mail_files( dir ) - Dir.entries(dir)\ - .select {|s| s[0] != ?. }\ - .sort_by {|s| s.slice(/\A\d+/).to_i }\ - .map {|s| "#{dir}/#{s}" }\ - .select {|path| FileTest.file? path } - end - - def each_filename( dir ) - Dir.foreach(dir) do |fname| - path = "#{dir}/#{fname}" - if fname[0] != ?. and FileTest.file? path - yield path, fname - end - end - end - - end # Maildir - - MaildirLoader = Maildir - -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/main.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/main.rb deleted file mode 100644 index e52772793f..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/main.rb +++ /dev/null @@ -1,6 +0,0 @@ -#:stopdoc: -require 'tmail/version' -require 'tmail/mail' -require 'tmail/mailbox' -require 'tmail/core_extensions' -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb deleted file mode 100644 index 6c0e251102..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/mbox.rb +++ /dev/null @@ -1,3 +0,0 @@ -#:stopdoc: -require 'tmail/mailbox' -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/net.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/net.rb deleted file mode 100644 index 65147228a1..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/net.rb +++ /dev/null @@ -1,248 +0,0 @@ -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -#:stopdoc: -require 'nkf' -#:startdoc: - -module TMail - - class Mail - - def send_to( smtp ) - do_send_to(smtp) do - ready_to_send - end - end - - def send_text_to( smtp ) - do_send_to(smtp) do - ready_to_send - mime_encode - end - end - - def do_send_to( smtp ) - from = from_address or raise ArgumentError, 'no from address' - (dests = destinations).empty? and raise ArgumentError, 'no receipient' - yield - send_to_0 smtp, from, dests - end - private :do_send_to - - def send_to_0( smtp, from, to ) - smtp.ready(from, to) do |f| - encoded "\r\n", 'j', f, '' - end - end - - def ready_to_send - delete_no_send_fields - add_message_id - add_date - end - - NOSEND_FIELDS = %w( - received - bcc - ) - - def delete_no_send_fields - NOSEND_FIELDS.each do |nm| - delete nm - end - delete_if {|n,v| v.empty? } - end - - def add_message_id( fqdn = nil ) - self.message_id = ::TMail::new_message_id(fqdn) - end - - def add_date - self.date = Time.now - end - - def mime_encode - if parts.empty? - mime_encode_singlepart - else - mime_encode_multipart true - end - end - - def mime_encode_singlepart - self.mime_version = '1.0' - b = body - if NKF.guess(b) != NKF::BINARY - mime_encode_text b - else - mime_encode_binary b - end - end - - def mime_encode_text( body ) - self.body = NKF.nkf('-j -m0', body) - self.set_content_type 'text', 'plain', {'charset' => 'iso-2022-jp'} - self.encoding = '7bit' - end - - def mime_encode_binary( body ) - self.body = [body].pack('m') - self.set_content_type 'application', 'octet-stream' - self.encoding = 'Base64' - end - - def mime_encode_multipart( top = true ) - self.mime_version = '1.0' if top - self.set_content_type 'multipart', 'mixed' - e = encoding(nil) - if e and not /\A(?:7bit|8bit|binary)\z/i === e - raise ArgumentError, - 'using C.T.Encoding with multipart mail is not permitted' - end - end - - end - - #:stopdoc: - class DeleteFields - - NOSEND_FIELDS = %w( - received - bcc - ) - - def initialize( nosend = nil, delempty = true ) - @no_send_fields = nosend || NOSEND_FIELDS.dup - @delete_empty_fields = delempty - end - - attr :no_send_fields - attr :delete_empty_fields, true - - def exec( mail ) - @no_send_fields.each do |nm| - delete nm - end - delete_if {|n,v| v.empty? } if @delete_empty_fields - end - - end - #:startdoc: - - #:stopdoc: - class AddMessageId - - def initialize( fqdn = nil ) - @fqdn = fqdn - end - - attr :fqdn, true - - def exec( mail ) - mail.message_id = ::TMail::new_msgid(@fqdn) - end - - end - #:startdoc: - - #:stopdoc: - class AddDate - - def exec( mail ) - mail.date = Time.now - end - - end - #:startdoc: - - #:stopdoc: - class MimeEncodeAuto - - def initialize( s = nil, m = nil ) - @singlepart_composer = s || MimeEncodeSingle.new - @multipart_composer = m || MimeEncodeMulti.new - end - - attr :singlepart_composer - attr :multipart_composer - - def exec( mail ) - if mail._builtin_multipart? - then @multipart_composer - else @singlepart_composer end.exec mail - end - - end - #:startdoc: - - #:stopdoc: - class MimeEncodeSingle - - def exec( mail ) - mail.mime_version = '1.0' - b = mail.body - if NKF.guess(b) != NKF::BINARY - on_text b - else - on_binary b - end - end - - def on_text( body ) - mail.body = NKF.nkf('-j -m0', body) - mail.set_content_type 'text', 'plain', {'charset' => 'iso-2022-jp'} - mail.encoding = '7bit' - end - - def on_binary( body ) - mail.body = [body].pack('m') - mail.set_content_type 'application', 'octet-stream' - mail.encoding = 'Base64' - end - - end - #:startdoc: - - #:stopdoc: - class MimeEncodeMulti - - def exec( mail, top = true ) - mail.mime_version = '1.0' if top - mail.set_content_type 'multipart', 'mixed' - e = encoding(nil) - if e and not /\A(?:7bit|8bit|binary)\z/i === e - raise ArgumentError, - 'using C.T.Encoding with multipart mail is not permitted' - end - mail.parts.each do |m| - exec m, false if m._builtin_multipart? - end - end - - end - #:startdoc: -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/obsolete.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/obsolete.rb deleted file mode 100644 index 22b0a126ca..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/obsolete.rb +++ /dev/null @@ -1,132 +0,0 @@ -=begin rdoc - -= Obsolete methods that are depriciated - -If you really want to see them, go to lib/tmail/obsolete.rb and view to your -heart's content. - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ -#:stopdoc: -module TMail #:nodoc: - - class Mail - alias include? key? - alias has_key? key? - - def values - ret = [] - each_field {|v| ret.push v } - ret - end - - def value?( val ) - HeaderField === val or return false - - [ @header[val.name.downcase] ].flatten.include? val - end - - alias has_value? value? - end - - class Mail - def from_addr( default = nil ) - addr, = from_addrs(nil) - addr || default - end - - def from_address( default = nil ) - if a = from_addr(nil) - a.spec - else - default - end - end - - alias from_address= from_addrs= - - def from_phrase( default = nil ) - if a = from_addr(nil) - a.phrase - else - default - end - end - - alias msgid message_id - alias msgid= message_id= - - alias each_dest each_destination - end - - class Address - alias route routes - alias addr spec - - def spec=( str ) - @local, @domain = str.split(/@/,2).map {|s| s.split(/\./) } - end - - alias addr= spec= - alias address= spec= - end - - class MhMailbox - alias new_mail new_port - alias each_mail each_port - alias each_newmail each_new_port - end - class UNIXMbox - alias new_mail new_port - alias each_mail each_port - alias each_newmail each_new_port - end - class Maildir - alias new_mail new_port - alias each_mail each_port - alias each_newmail each_new_port - end - - extend TextUtils - - class << self - alias msgid? message_id? - alias boundary new_boundary - alias msgid new_message_id - alias new_msgid new_message_id - end - - def Mail.boundary - ::TMail.new_boundary - end - - def Mail.msgid - ::TMail.new_message_id - end - -end # module TMail -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/parser.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/parser.rb deleted file mode 100644 index ab1a828471..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/parser.rb +++ /dev/null @@ -1,1476 +0,0 @@ -#:stopdoc: -# DO NOT MODIFY!!!! -# This file is automatically generated by racc 1.4.5 -# from racc grammer file "parser.y". -# -# -# parser.rb: generated by racc (runtime embedded) -# -###### racc/parser.rb begin -unless $".index 'racc/parser.rb' -$".push 'racc/parser.rb' - -self.class.module_eval <<'..end racc/parser.rb modeval..id8076474214', 'racc/parser.rb', 1 -# -# $Id: parser.rb,v 1.7 2005/11/20 17:31:32 aamine Exp $ -# -# Copyright (c) 1999-2005 Minero Aoki -# -# This program is free software. -# You can distribute/modify this program under the same terms of ruby. -# -# As a special exception, when this code is copied by Racc -# into a Racc output file, you may use that output file -# without restriction. -# - -unless defined?(NotImplementedError) - NotImplementedError = NotImplementError -end - -module Racc - class ParseError < StandardError; end -end -unless defined?(::ParseError) - ParseError = Racc::ParseError -end - -module Racc - - unless defined?(Racc_No_Extentions) - Racc_No_Extentions = false - end - - class Parser - - Racc_Runtime_Version = '1.4.5' - Racc_Runtime_Revision = '$Revision: 1.7 $'.split[1] - - Racc_Runtime_Core_Version_R = '1.4.5' - Racc_Runtime_Core_Revision_R = '$Revision: 1.7 $'.split[1] - begin - require 'racc/cparse' - # Racc_Runtime_Core_Version_C = (defined in extention) - Racc_Runtime_Core_Revision_C = Racc_Runtime_Core_Id_C.split[2] - unless new.respond_to?(:_racc_do_parse_c, true) - raise LoadError, 'old cparse.so' - end - if Racc_No_Extentions - raise LoadError, 'selecting ruby version of racc runtime core' - end - - Racc_Main_Parsing_Routine = :_racc_do_parse_c - Racc_YY_Parse_Method = :_racc_yyparse_c - Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C - Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_C - Racc_Runtime_Type = 'c' - rescue LoadError - Racc_Main_Parsing_Routine = :_racc_do_parse_rb - Racc_YY_Parse_Method = :_racc_yyparse_rb - Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R - Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_R - Racc_Runtime_Type = 'ruby' - end - - def Parser.racc_runtime_type - Racc_Runtime_Type - end - - private - - def _racc_setup - @yydebug = false unless self.class::Racc_debug_parser - @yydebug = false unless defined?(@yydebug) - if @yydebug - @racc_debug_out = $stderr unless defined?(@racc_debug_out) - @racc_debug_out ||= $stderr - end - arg = self.class::Racc_arg - arg[13] = true if arg.size < 14 - arg - end - - def _racc_init_sysvars - @racc_state = [0] - @racc_tstack = [] - @racc_vstack = [] - - @racc_t = nil - @racc_val = nil - - @racc_read_next = true - - @racc_user_yyerror = false - @racc_error_status = 0 - end - - ### - ### do_parse - ### - - def do_parse - __send__(Racc_Main_Parsing_Routine, _racc_setup(), false) - end - - def next_token - raise NotImplementedError, "#{self.class}\#next_token is not defined" - end - - def _racc_do_parse_rb(arg, in_debug) - action_table, action_check, action_default, action_pointer, - goto_table, goto_check, goto_default, goto_pointer, - nt_base, reduce_table, token_table, shift_n, - reduce_n, use_result, * = arg - - _racc_init_sysvars - tok = act = i = nil - nerr = 0 - - catch(:racc_end_parse) { - while true - if i = action_pointer[@racc_state[-1]] - if @racc_read_next - if @racc_t != 0 # not EOF - tok, @racc_val = next_token() - unless tok # EOF - @racc_t = 0 - else - @racc_t = (token_table[tok] or 1) # error token - end - racc_read_token(@racc_t, tok, @racc_val) if @yydebug - @racc_read_next = false - end - end - i += @racc_t - unless i >= 0 and - act = action_table[i] and - action_check[i] == @racc_state[-1] - act = action_default[@racc_state[-1]] - end - else - act = action_default[@racc_state[-1]] - end - while act = _racc_evalact(act, arg) - ; - end - end - } - end - - ### - ### yyparse - ### - - def yyparse(recv, mid) - __send__(Racc_YY_Parse_Method, recv, mid, _racc_setup(), true) - end - - def _racc_yyparse_rb(recv, mid, arg, c_debug) - action_table, action_check, action_default, action_pointer, - goto_table, goto_check, goto_default, goto_pointer, - nt_base, reduce_table, token_table, shift_n, - reduce_n, use_result, * = arg - - _racc_init_sysvars - tok = nil - act = nil - i = nil - nerr = 0 - - catch(:racc_end_parse) { - until i = action_pointer[@racc_state[-1]] - while act = _racc_evalact(action_default[@racc_state[-1]], arg) - ; - end - end - recv.__send__(mid) do |tok, val| - unless tok - @racc_t = 0 - else - @racc_t = (token_table[tok] or 1) # error token - end - @racc_val = val - @racc_read_next = false - - i += @racc_t - unless i >= 0 and - act = action_table[i] and - action_check[i] == @racc_state[-1] - act = action_default[@racc_state[-1]] - end - while act = _racc_evalact(act, arg) - ; - end - - while not (i = action_pointer[@racc_state[-1]]) or - not @racc_read_next or - @racc_t == 0 # $ - unless i and i += @racc_t and - i >= 0 and - act = action_table[i] and - action_check[i] == @racc_state[-1] - act = action_default[@racc_state[-1]] - end - while act = _racc_evalact(act, arg) - ; - end - end - end - } - end - - ### - ### common - ### - - def _racc_evalact(act, arg) - action_table, action_check, action_default, action_pointer, - goto_table, goto_check, goto_default, goto_pointer, - nt_base, reduce_table, token_table, shift_n, - reduce_n, use_result, * = arg - nerr = 0 # tmp - - if act > 0 and act < shift_n - # - # shift - # - if @racc_error_status > 0 - @racc_error_status -= 1 unless @racc_t == 1 # error token - end - @racc_vstack.push @racc_val - @racc_state.push act - @racc_read_next = true - if @yydebug - @racc_tstack.push @racc_t - racc_shift @racc_t, @racc_tstack, @racc_vstack - end - - elsif act < 0 and act > -reduce_n - # - # reduce - # - code = catch(:racc_jump) { - @racc_state.push _racc_do_reduce(arg, act) - false - } - if code - case code - when 1 # yyerror - @racc_user_yyerror = true # user_yyerror - return -reduce_n - when 2 # yyaccept - return shift_n - else - raise '[Racc Bug] unknown jump code' - end - end - - elsif act == shift_n - # - # accept - # - racc_accept if @yydebug - throw :racc_end_parse, @racc_vstack[0] - - elsif act == -reduce_n - # - # error - # - case @racc_error_status - when 0 - unless arg[21] # user_yyerror - nerr += 1 - on_error @racc_t, @racc_val, @racc_vstack - end - when 3 - if @racc_t == 0 # is $ - throw :racc_end_parse, nil - end - @racc_read_next = true - end - @racc_user_yyerror = false - @racc_error_status = 3 - while true - if i = action_pointer[@racc_state[-1]] - i += 1 # error token - if i >= 0 and - (act = action_table[i]) and - action_check[i] == @racc_state[-1] - break - end - end - throw :racc_end_parse, nil if @racc_state.size <= 1 - @racc_state.pop - @racc_vstack.pop - if @yydebug - @racc_tstack.pop - racc_e_pop @racc_state, @racc_tstack, @racc_vstack - end - end - return act - - else - raise "[Racc Bug] unknown action #{act.inspect}" - end - - racc_next_state(@racc_state[-1], @racc_state) if @yydebug - - nil - end - - def _racc_do_reduce(arg, act) - action_table, action_check, action_default, action_pointer, - goto_table, goto_check, goto_default, goto_pointer, - nt_base, reduce_table, token_table, shift_n, - reduce_n, use_result, * = arg - state = @racc_state - vstack = @racc_vstack - tstack = @racc_tstack - - i = act * -3 - len = reduce_table[i] - reduce_to = reduce_table[i+1] - method_id = reduce_table[i+2] - void_array = [] - - tmp_t = tstack[-len, len] if @yydebug - tmp_v = vstack[-len, len] - tstack[-len, len] = void_array if @yydebug - vstack[-len, len] = void_array - state[-len, len] = void_array - - # tstack must be updated AFTER method call - if use_result - vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0]) - else - vstack.push __send__(method_id, tmp_v, vstack) - end - tstack.push reduce_to - - racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug - - k1 = reduce_to - nt_base - if i = goto_pointer[k1] - i += state[-1] - if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1 - return curstate - end - end - goto_default[k1] - end - - def on_error(t, val, vstack) - raise ParseError, sprintf("\nparse error on value %s (%s)", - val.inspect, token_to_str(t) || '?') - end - - def yyerror - throw :racc_jump, 1 - end - - def yyaccept - throw :racc_jump, 2 - end - - def yyerrok - @racc_error_status = 0 - end - - # - # for debugging output - # - - def racc_read_token(t, tok, val) - @racc_debug_out.print 'read ' - @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') ' - @racc_debug_out.puts val.inspect - @racc_debug_out.puts - end - - def racc_shift(tok, tstack, vstack) - @racc_debug_out.puts "shift #{racc_token2str tok}" - racc_print_stacks tstack, vstack - @racc_debug_out.puts - end - - def racc_reduce(toks, sim, tstack, vstack) - out = @racc_debug_out - out.print 'reduce ' - if toks.empty? - out.print ' ' - else - toks.each {|t| out.print ' ', racc_token2str(t) } - end - out.puts " --> #{racc_token2str(sim)}" - - racc_print_stacks tstack, vstack - @racc_debug_out.puts - end - - def racc_accept - @racc_debug_out.puts 'accept' - @racc_debug_out.puts - end - - def racc_e_pop(state, tstack, vstack) - @racc_debug_out.puts 'error recovering mode: pop token' - racc_print_states state - racc_print_stacks tstack, vstack - @racc_debug_out.puts - end - - def racc_next_state(curstate, state) - @racc_debug_out.puts "goto #{curstate}" - racc_print_states state - @racc_debug_out.puts - end - - def racc_print_stacks(t, v) - out = @racc_debug_out - out.print ' [' - t.each_index do |i| - out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')' - end - out.puts ' ]' - end - - def racc_print_states(s) - out = @racc_debug_out - out.print ' [' - s.each {|st| out.print ' ', st } - out.puts ' ]' - end - - def racc_token2str(tok) - self.class::Racc_token_to_s_table[tok] or - raise "[Racc Bug] can't convert token #{tok} to string" - end - - def token_to_str(t) - self.class::Racc_token_to_s_table[t] - end - - end - -end -..end racc/parser.rb modeval..id8076474214 -end -###### racc/parser.rb end - - -# -# parser.rb -# -# Copyright (c) 1998-2007 Minero Aoki -# -# This program is free software. -# You can distribute/modify this program under the terms of -# the GNU Lesser General Public License version 2.1. -# - -require 'tmail/scanner' -require 'tmail/utils' - - -module TMail - - class Parser < Racc::Parser - -module_eval <<'..end parser.y modeval..id7b0b3dccb7', 'parser.y', 340 - - include TextUtils - - def self.parse( ident, str, cmt = nil ) - new.parse(ident, str, cmt) - end - - MAILP_DEBUG = false - - def initialize - self.debug = MAILP_DEBUG - end - - def debug=( flag ) - @yydebug = flag && Racc_debug_parser - @scanner_debug = flag - end - - def debug - @yydebug - end - - def parse( ident, str, comments = nil ) - @scanner = Scanner.new(str, ident, comments) - @scanner.debug = @scanner_debug - @first = [ident, ident] - result = yyparse(self, :parse_in) - comments.map! {|c| to_kcode(c) } if comments - result - end - - private - - def parse_in( &block ) - yield @first - @scanner.scan(&block) - end - - def on_error( t, val, vstack ) - raise SyntaxError, "parse error on token #{racc_token2str t}" - end - -..end parser.y modeval..id7b0b3dccb7 - -##### racc 1.4.5 generates ### - -racc_reduce_table = [ - 0, 0, :racc_error, - 2, 35, :_reduce_1, - 2, 35, :_reduce_2, - 2, 35, :_reduce_3, - 2, 35, :_reduce_4, - 2, 35, :_reduce_5, - 2, 35, :_reduce_6, - 2, 35, :_reduce_7, - 2, 35, :_reduce_8, - 2, 35, :_reduce_9, - 2, 35, :_reduce_10, - 2, 35, :_reduce_11, - 2, 35, :_reduce_12, - 6, 36, :_reduce_13, - 0, 48, :_reduce_none, - 2, 48, :_reduce_none, - 3, 49, :_reduce_16, - 5, 49, :_reduce_17, - 1, 50, :_reduce_18, - 7, 37, :_reduce_19, - 0, 51, :_reduce_none, - 2, 51, :_reduce_21, - 0, 52, :_reduce_none, - 2, 52, :_reduce_23, - 1, 58, :_reduce_24, - 3, 58, :_reduce_25, - 2, 58, :_reduce_26, - 0, 53, :_reduce_none, - 2, 53, :_reduce_28, - 0, 54, :_reduce_29, - 3, 54, :_reduce_30, - 0, 55, :_reduce_none, - 2, 55, :_reduce_32, - 2, 55, :_reduce_33, - 0, 56, :_reduce_none, - 2, 56, :_reduce_35, - 1, 61, :_reduce_36, - 1, 61, :_reduce_37, - 0, 57, :_reduce_none, - 2, 57, :_reduce_39, - 1, 38, :_reduce_none, - 1, 38, :_reduce_none, - 3, 38, :_reduce_none, - 1, 46, :_reduce_none, - 1, 46, :_reduce_none, - 1, 46, :_reduce_none, - 1, 39, :_reduce_none, - 2, 39, :_reduce_47, - 1, 64, :_reduce_48, - 3, 64, :_reduce_49, - 1, 68, :_reduce_none, - 1, 68, :_reduce_none, - 1, 69, :_reduce_52, - 3, 69, :_reduce_53, - 1, 47, :_reduce_none, - 1, 47, :_reduce_none, - 2, 47, :_reduce_56, - 2, 67, :_reduce_none, - 3, 65, :_reduce_58, - 2, 65, :_reduce_59, - 1, 70, :_reduce_60, - 2, 70, :_reduce_61, - 4, 62, :_reduce_62, - 3, 62, :_reduce_63, - 2, 72, :_reduce_none, - 2, 73, :_reduce_65, - 4, 73, :_reduce_66, - 3, 63, :_reduce_67, - 1, 63, :_reduce_68, - 1, 74, :_reduce_none, - 2, 74, :_reduce_70, - 1, 71, :_reduce_71, - 3, 71, :_reduce_72, - 1, 59, :_reduce_73, - 3, 59, :_reduce_74, - 1, 76, :_reduce_75, - 2, 76, :_reduce_76, - 1, 75, :_reduce_none, - 1, 75, :_reduce_none, - 1, 75, :_reduce_none, - 1, 77, :_reduce_none, - 1, 77, :_reduce_none, - 1, 77, :_reduce_none, - 1, 66, :_reduce_none, - 2, 66, :_reduce_none, - 3, 60, :_reduce_85, - 1, 40, :_reduce_86, - 3, 40, :_reduce_87, - 1, 79, :_reduce_none, - 2, 79, :_reduce_89, - 1, 41, :_reduce_90, - 2, 41, :_reduce_91, - 3, 42, :_reduce_92, - 5, 43, :_reduce_93, - 3, 43, :_reduce_94, - 0, 80, :_reduce_95, - 5, 80, :_reduce_96, - 5, 80, :_reduce_97, - 1, 44, :_reduce_98, - 3, 45, :_reduce_99, - 0, 81, :_reduce_none, - 1, 81, :_reduce_none, - 1, 78, :_reduce_none, - 1, 78, :_reduce_none, - 1, 78, :_reduce_none, - 1, 78, :_reduce_none, - 1, 78, :_reduce_none, - 1, 78, :_reduce_none, - 1, 78, :_reduce_none ] - -racc_reduce_n = 109 - -racc_shift_n = 167 - -racc_action_table = [ - -70, -69, 23, 25, 145, 146, 29, 31, 105, 106, - 16, 17, 20, 22, 136, 27, -70, -69, 32, 101, - -70, -69, 153, 100, 113, 115, -70, -69, -70, 109, - 75, 23, 25, 101, 154, 29, 31, 142, 143, 16, - 17, 20, 22, 107, 27, 23, 25, 32, 98, 29, - 31, 96, 94, 16, 17, 20, 22, 78, 27, 23, - 25, 32, 112, 29, 31, 74, 91, 16, 17, 20, - 22, 88, 117, 92, 81, 32, 23, 25, 80, 123, - 29, 31, 100, 125, 16, 17, 20, 22, 126, 23, - 25, 109, 32, 29, 31, 91, 128, 16, 17, 20, - 22, 129, 27, 23, 25, 32, 101, 29, 31, 101, - 130, 16, 17, 20, 22, 79, 52, 23, 25, 32, - 78, 29, 31, 133, 78, 16, 17, 20, 22, 77, - 23, 25, 75, 32, 29, 31, 65, 62, 16, 17, - 20, 22, 139, 23, 25, 101, 32, 29, 31, 60, - 100, 16, 17, 20, 22, 44, 27, 101, 147, 32, - 23, 25, 120, 148, 29, 31, 151, 152, 16, 17, - 20, 22, 42, 27, 156, 158, 32, 23, 25, 120, - 40, 29, 31, 15, 163, 16, 17, 20, 22, 40, - 27, 23, 25, 32, 68, 29, 31, 165, 166, 16, - 17, 20, 22, nil, 27, 23, 25, 32, nil, 29, - 31, 74, nil, 16, 17, 20, 22, nil, 23, 25, - nil, 32, 29, 31, nil, nil, 16, 17, 20, 22, - nil, 23, 25, nil, 32, 29, 31, nil, nil, 16, - 17, 20, 22, nil, 23, 25, nil, 32, 29, 31, - nil, nil, 16, 17, 20, 22, nil, 23, 25, nil, - 32, 29, 31, nil, nil, 16, 17, 20, 22, nil, - 27, 23, 25, 32, nil, 29, 31, nil, nil, 16, - 17, 20, 22, nil, 23, 25, nil, 32, 29, 31, - nil, nil, 16, 17, 20, 22, nil, 23, 25, nil, - 32, 29, 31, nil, nil, 16, 17, 20, 22, nil, - 84, 25, nil, 32, 29, 31, nil, 87, 16, 17, - 20, 22, 4, 6, 7, 8, 9, 10, 11, 12, - 13, 1, 2, 3, 84, 25, nil, nil, 29, 31, - nil, 87, 16, 17, 20, 22, 84, 25, nil, nil, - 29, 31, nil, 87, 16, 17, 20, 22, 84, 25, - nil, nil, 29, 31, nil, 87, 16, 17, 20, 22, - 84, 25, nil, nil, 29, 31, nil, 87, 16, 17, - 20, 22, 84, 25, nil, nil, 29, 31, nil, 87, - 16, 17, 20, 22, 84, 25, nil, nil, 29, 31, - nil, 87, 16, 17, 20, 22 ] - -racc_action_check = [ - 75, 28, 68, 68, 136, 136, 68, 68, 72, 72, - 68, 68, 68, 68, 126, 68, 75, 28, 68, 67, - 75, 28, 143, 66, 86, 86, 75, 28, 75, 75, - 28, 3, 3, 86, 143, 3, 3, 134, 134, 3, - 3, 3, 3, 73, 3, 151, 151, 3, 62, 151, - 151, 60, 56, 151, 151, 151, 151, 51, 151, 52, - 52, 151, 80, 52, 52, 52, 50, 52, 52, 52, - 52, 45, 89, 52, 42, 52, 71, 71, 41, 96, - 71, 71, 97, 98, 71, 71, 71, 71, 100, 7, - 7, 101, 71, 7, 7, 102, 104, 7, 7, 7, - 7, 105, 7, 8, 8, 7, 108, 8, 8, 111, - 112, 8, 8, 8, 8, 40, 8, 9, 9, 8, - 36, 9, 9, 117, 121, 9, 9, 9, 9, 33, - 10, 10, 70, 9, 10, 10, 13, 12, 10, 10, - 10, 10, 130, 2, 2, 131, 10, 2, 2, 11, - 135, 2, 2, 2, 2, 6, 2, 138, 139, 2, - 90, 90, 90, 140, 90, 90, 141, 142, 90, 90, - 90, 90, 5, 90, 147, 150, 90, 127, 127, 127, - 4, 127, 127, 1, 156, 127, 127, 127, 127, 158, - 127, 26, 26, 127, 26, 26, 26, 162, 163, 26, - 26, 26, 26, nil, 26, 27, 27, 26, nil, 27, - 27, 27, nil, 27, 27, 27, 27, nil, 154, 154, - nil, 27, 154, 154, nil, nil, 154, 154, 154, 154, - nil, 122, 122, nil, 154, 122, 122, nil, nil, 122, - 122, 122, 122, nil, 76, 76, nil, 122, 76, 76, - nil, nil, 76, 76, 76, 76, nil, 38, 38, nil, - 76, 38, 38, nil, nil, 38, 38, 38, 38, nil, - 38, 55, 55, 38, nil, 55, 55, nil, nil, 55, - 55, 55, 55, nil, 94, 94, nil, 55, 94, 94, - nil, nil, 94, 94, 94, 94, nil, 59, 59, nil, - 94, 59, 59, nil, nil, 59, 59, 59, 59, nil, - 114, 114, nil, 59, 114, 114, nil, 114, 114, 114, - 114, 114, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 77, 77, nil, nil, 77, 77, - nil, 77, 77, 77, 77, 77, 44, 44, nil, nil, - 44, 44, nil, 44, 44, 44, 44, 44, 113, 113, - nil, nil, 113, 113, nil, 113, 113, 113, 113, 113, - 88, 88, nil, nil, 88, 88, nil, 88, 88, 88, - 88, 88, 74, 74, nil, nil, 74, 74, nil, 74, - 74, 74, 74, 74, 129, 129, nil, nil, 129, 129, - nil, 129, 129, 129, 129, 129 ] - -racc_action_pointer = [ - 320, 152, 129, 17, 165, 172, 137, 75, 89, 103, - 116, 135, 106, 105, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, 177, 191, 1, nil, - nil, nil, nil, 109, nil, nil, 94, nil, 243, nil, - 99, 64, 74, nil, 332, 52, nil, nil, nil, nil, - 50, 31, 45, nil, nil, 257, 36, nil, nil, 283, - 22, nil, 16, nil, nil, nil, -3, -10, -12, nil, - 103, 62, -8, 15, 368, 0, 230, 320, nil, nil, - 47, nil, nil, nil, nil, nil, 4, nil, 356, 50, - 146, nil, nil, nil, 270, nil, 65, 56, 52, nil, - 57, 62, 79, nil, 68, 81, nil, nil, 77, nil, - nil, 80, 96, 344, 296, nil, nil, 108, nil, nil, - nil, 98, 217, nil, nil, nil, -19, 163, nil, 380, - 128, 116, nil, nil, 14, 124, -26, nil, 128, 141, - 148, 141, 152, 7, nil, nil, nil, 160, nil, nil, - 149, 31, nil, nil, 204, nil, 167, nil, 174, nil, - nil, nil, 169, 184, nil, nil, nil ] - -racc_action_default = [ - -109, -109, -109, -109, -14, -109, -20, -109, -109, -109, - -109, -109, -109, -109, -10, -95, -105, -106, -77, -44, - -107, -11, -108, -79, -43, -102, -109, -109, -60, -103, - -55, -104, -78, -68, -54, -71, -45, -12, -109, -1, - -109, -109, -109, -2, -109, -22, -51, -48, -50, -3, - -40, -41, -109, -46, -4, -86, -5, -88, -6, -90, - -109, -7, -95, -8, -9, -98, -100, -61, -59, -56, - -69, -109, -109, -109, -109, -75, -109, -109, -57, -15, - -109, 167, -73, -80, -82, -21, -24, -81, -109, -27, - -109, -83, -47, -89, -109, -91, -109, -100, -109, -99, - -101, -75, -58, -52, -109, -109, -64, -63, -65, -76, - -72, -67, -109, -109, -109, -26, -23, -109, -29, -49, - -84, -42, -87, -92, -94, -95, -109, -109, -62, -109, - -109, -25, -74, -28, -31, -100, -109, -53, -66, -109, - -109, -34, -109, -109, -93, -96, -97, -109, -18, -13, - -38, -109, -30, -33, -109, -32, -16, -19, -14, -35, - -36, -37, -109, -109, -39, -85, -17 ] - -racc_goto_table = [ - 39, 67, 70, 73, 38, 66, 69, 24, 37, 57, - 59, 36, 55, 67, 99, 90, 85, 157, 69, 108, - 83, 134, 111, 76, 49, 53, 141, 70, 73, 150, - 118, 89, 45, 155, 159, 149, 140, 21, 14, 19, - 119, 102, 64, 63, 61, 124, 70, 104, 58, 132, - 83, 56, 97, 83, 54, 93, 43, 5, 131, 95, - 116, nil, 76, nil, 83, 76, nil, 127, nil, 38, - nil, nil, nil, 103, 138, nil, 110, nil, nil, nil, - nil, nil, nil, 144, nil, nil, nil, nil, nil, 83, - 83, nil, nil, nil, 57, nil, nil, 122, nil, 121, - nil, nil, nil, nil, nil, 83, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 135, nil, nil, nil, nil, - nil, nil, 93, nil, nil, nil, 70, 161, 38, 70, - 162, 160, 137, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, 164 ] - -racc_goto_check = [ - 2, 37, 37, 29, 36, 46, 28, 13, 13, 41, - 41, 31, 45, 37, 47, 32, 24, 23, 28, 25, - 44, 20, 25, 42, 4, 4, 21, 37, 29, 22, - 19, 18, 17, 26, 27, 16, 15, 12, 11, 33, - 34, 35, 10, 9, 8, 47, 37, 29, 7, 43, - 44, 6, 46, 44, 5, 41, 3, 1, 25, 41, - 24, nil, 42, nil, 44, 42, nil, 32, nil, 36, - nil, nil, nil, 13, 25, nil, 41, nil, nil, nil, - nil, nil, nil, 47, nil, nil, nil, nil, nil, 44, - 44, nil, nil, nil, 41, nil, nil, 45, nil, 31, - nil, nil, nil, nil, nil, 44, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 46, nil, nil, nil, nil, - nil, nil, 41, nil, nil, nil, 37, 29, 36, 37, - 29, 28, 13, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, nil, 2 ] - -racc_goto_pointer = [ - nil, 57, -4, 50, 17, 46, 42, 38, 33, 31, - 29, 37, 35, 5, nil, -94, -105, 26, -14, -59, - -97, -108, -112, -133, -28, -55, -110, -117, -20, -24, - nil, 9, -35, 37, -50, -27, 1, -25, nil, nil, - nil, 0, -5, -65, -24, 3, -10, -52 ] - -racc_goto_default = [ - nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, - nil, nil, nil, 48, 41, nil, nil, nil, nil, nil, - nil, nil, nil, nil, nil, 86, nil, nil, 30, 34, - 50, 51, nil, 46, 47, nil, 26, 28, 71, 72, - 33, 35, 114, 82, 18, nil, nil, nil ] - -racc_token_table = { - false => 0, - Object.new => 1, - :DATETIME => 2, - :RECEIVED => 3, - :MADDRESS => 4, - :RETPATH => 5, - :KEYWORDS => 6, - :ENCRYPTED => 7, - :MIMEVERSION => 8, - :CTYPE => 9, - :CENCODING => 10, - :CDISPOSITION => 11, - :ADDRESS => 12, - :MAILBOX => 13, - :DIGIT => 14, - :ATOM => 15, - "," => 16, - ":" => 17, - :FROM => 18, - :BY => 19, - "@" => 20, - :DOMLIT => 21, - :VIA => 22, - :WITH => 23, - :ID => 24, - :FOR => 25, - ";" => 26, - "<" => 27, - ">" => 28, - "." => 29, - :QUOTED => 30, - :TOKEN => 31, - "/" => 32, - "=" => 33 } - -racc_use_result_var = false - -racc_nt_base = 34 - -Racc_arg = [ - racc_action_table, - racc_action_check, - racc_action_default, - racc_action_pointer, - racc_goto_table, - racc_goto_check, - racc_goto_default, - racc_goto_pointer, - racc_nt_base, - racc_reduce_table, - racc_token_table, - racc_shift_n, - racc_reduce_n, - racc_use_result_var ] - -Racc_token_to_s_table = [ -'$end', -'error', -'DATETIME', -'RECEIVED', -'MADDRESS', -'RETPATH', -'KEYWORDS', -'ENCRYPTED', -'MIMEVERSION', -'CTYPE', -'CENCODING', -'CDISPOSITION', -'ADDRESS', -'MAILBOX', -'DIGIT', -'ATOM', -'","', -'":"', -'FROM', -'BY', -'"@"', -'DOMLIT', -'VIA', -'WITH', -'ID', -'FOR', -'";"', -'"<"', -'">"', -'"."', -'QUOTED', -'TOKEN', -'"/"', -'"="', -'$start', -'content', -'datetime', -'received', -'addrs_TOP', -'retpath', -'keys', -'enc', -'version', -'ctype', -'cencode', -'cdisp', -'addr_TOP', -'mbox', -'day', -'hour', -'zone', -'from', -'by', -'via', -'with', -'id', -'for', -'received_datetime', -'received_domain', -'domain', -'msgid', -'received_addrspec', -'routeaddr', -'spec', -'addrs', -'group_bare', -'commas', -'group', -'addr', -'mboxes', -'addr_phrase', -'local_head', -'routes', -'at_domains', -'local', -'word', -'dots', -'domword', -'atom', -'phrase', -'params', -'opt_semicolon'] - -Racc_debug_parser = false - -##### racc system variables end ##### - - # reduce 0 omitted - -module_eval <<'.,.,', 'parser.y', 16 - def _reduce_1( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 17 - def _reduce_2( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 18 - def _reduce_3( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 19 - def _reduce_4( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 20 - def _reduce_5( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 21 - def _reduce_6( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 22 - def _reduce_7( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 23 - def _reduce_8( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 24 - def _reduce_9( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 25 - def _reduce_10( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 26 - def _reduce_11( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 27 - def _reduce_12( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 36 - def _reduce_13( val, _values) - t = Time.gm(val[3].to_i, val[2], val[1].to_i, 0, 0, 0) - (t + val[4] - val[5]).localtime - end -.,., - - # reduce 14 omitted - - # reduce 15 omitted - -module_eval <<'.,.,', 'parser.y', 45 - def _reduce_16( val, _values) - (val[0].to_i * 60 * 60) + - (val[2].to_i * 60) - end -.,., - -module_eval <<'.,.,', 'parser.y', 51 - def _reduce_17( val, _values) - (val[0].to_i * 60 * 60) + - (val[2].to_i * 60) + - (val[4].to_i) - end -.,., - -module_eval <<'.,.,', 'parser.y', 56 - def _reduce_18( val, _values) - timezone_string_to_unixtime(val[0]) - end -.,., - -module_eval <<'.,.,', 'parser.y', 61 - def _reduce_19( val, _values) - val - end -.,., - - # reduce 20 omitted - -module_eval <<'.,.,', 'parser.y', 67 - def _reduce_21( val, _values) - val[1] - end -.,., - - # reduce 22 omitted - -module_eval <<'.,.,', 'parser.y', 73 - def _reduce_23( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 79 - def _reduce_24( val, _values) - join_domain(val[0]) - end -.,., - -module_eval <<'.,.,', 'parser.y', 83 - def _reduce_25( val, _values) - join_domain(val[2]) - end -.,., - -module_eval <<'.,.,', 'parser.y', 87 - def _reduce_26( val, _values) - join_domain(val[0]) - end -.,., - - # reduce 27 omitted - -module_eval <<'.,.,', 'parser.y', 93 - def _reduce_28( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 98 - def _reduce_29( val, _values) - [] - end -.,., - -module_eval <<'.,.,', 'parser.y', 103 - def _reduce_30( val, _values) - val[0].push val[2] - val[0] - end -.,., - - # reduce 31 omitted - -module_eval <<'.,.,', 'parser.y', 109 - def _reduce_32( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 113 - def _reduce_33( val, _values) - val[1] - end -.,., - - # reduce 34 omitted - -module_eval <<'.,.,', 'parser.y', 119 - def _reduce_35( val, _values) - val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 125 - def _reduce_36( val, _values) - val[0].spec - end -.,., - -module_eval <<'.,.,', 'parser.y', 129 - def _reduce_37( val, _values) - val[0].spec - end -.,., - - # reduce 38 omitted - -module_eval <<'.,.,', 'parser.y', 136 - def _reduce_39( val, _values) - val[1] - end -.,., - - # reduce 40 omitted - - # reduce 41 omitted - - # reduce 42 omitted - - # reduce 43 omitted - - # reduce 44 omitted - - # reduce 45 omitted - - # reduce 46 omitted - -module_eval <<'.,.,', 'parser.y', 146 - def _reduce_47( val, _values) - [ Address.new(nil, nil) ] - end -.,., - -module_eval <<'.,.,', 'parser.y', 152 - def _reduce_48( val, _values) - val - end -.,., - -module_eval <<'.,.,', 'parser.y', 157 - def _reduce_49( val, _values) - val[0].push val[2] - val[0] - end -.,., - - # reduce 50 omitted - - # reduce 51 omitted - -module_eval <<'.,.,', 'parser.y', 165 - def _reduce_52( val, _values) - val - end -.,., - -module_eval <<'.,.,', 'parser.y', 170 - def _reduce_53( val, _values) - val[0].push val[2] - val[0] - end -.,., - - # reduce 54 omitted - - # reduce 55 omitted - -module_eval <<'.,.,', 'parser.y', 178 - def _reduce_56( val, _values) - val[1].phrase = Decoder.decode(val[0]) - val[1] - end -.,., - - # reduce 57 omitted - -module_eval <<'.,.,', 'parser.y', 185 - def _reduce_58( val, _values) - AddressGroup.new(val[0], val[2]) - end -.,., - -module_eval <<'.,.,', 'parser.y', 185 - def _reduce_59( val, _values) - AddressGroup.new(val[0], []) - end -.,., - -module_eval <<'.,.,', 'parser.y', 188 - def _reduce_60( val, _values) - val[0].join('.') - end -.,., - -module_eval <<'.,.,', 'parser.y', 189 - def _reduce_61( val, _values) - val[0] << ' ' << val[1].join('.') - end -.,., - -module_eval <<'.,.,', 'parser.y', 196 - def _reduce_62( val, _values) - val[2].routes.replace val[1] - val[2] - end -.,., - -module_eval <<'.,.,', 'parser.y', 200 - def _reduce_63( val, _values) - val[1] - end -.,., - - # reduce 64 omitted - -module_eval <<'.,.,', 'parser.y', 203 - def _reduce_65( val, _values) - [ val[1].join('.') ] - end -.,., - -module_eval <<'.,.,', 'parser.y', 204 - def _reduce_66( val, _values) - val[0].push val[3].join('.'); val[0] - end -.,., - -module_eval <<'.,.,', 'parser.y', 206 - def _reduce_67( val, _values) - Address.new( val[0], val[2] ) - end -.,., - -module_eval <<'.,.,', 'parser.y', 207 - def _reduce_68( val, _values) - Address.new( val[0], nil ) - end -.,., - - # reduce 69 omitted - -module_eval <<'.,.,', 'parser.y', 210 - def _reduce_70( val, _values) - val[0].push ''; val[0] - end -.,., - -module_eval <<'.,.,', 'parser.y', 213 - def _reduce_71( val, _values) - val - end -.,., - -module_eval <<'.,.,', 'parser.y', 222 - def _reduce_72( val, _values) - val[1].times do - val[0].push '' - end - val[0].push val[2] - val[0] - end -.,., - -module_eval <<'.,.,', 'parser.y', 224 - def _reduce_73( val, _values) - val - end -.,., - -module_eval <<'.,.,', 'parser.y', 233 - def _reduce_74( val, _values) - val[1].times do - val[0].push '' - end - val[0].push val[2] - val[0] - end -.,., - -module_eval <<'.,.,', 'parser.y', 234 - def _reduce_75( val, _values) - 0 - end -.,., - -module_eval <<'.,.,', 'parser.y', 235 - def _reduce_76( val, _values) - 1 - end -.,., - - # reduce 77 omitted - - # reduce 78 omitted - - # reduce 79 omitted - - # reduce 80 omitted - - # reduce 81 omitted - - # reduce 82 omitted - - # reduce 83 omitted - - # reduce 84 omitted - -module_eval <<'.,.,', 'parser.y', 253 - def _reduce_85( val, _values) - val[1] = val[1].spec - val.join('') - end -.,., - -module_eval <<'.,.,', 'parser.y', 254 - def _reduce_86( val, _values) - val - end -.,., - -module_eval <<'.,.,', 'parser.y', 255 - def _reduce_87( val, _values) - val[0].push val[2]; val[0] - end -.,., - - # reduce 88 omitted - -module_eval <<'.,.,', 'parser.y', 258 - def _reduce_89( val, _values) - val[0] << ' ' << val[1] - end -.,., - -module_eval <<'.,.,', 'parser.y', 265 - def _reduce_90( val, _values) - val.push nil - val - end -.,., - -module_eval <<'.,.,', 'parser.y', 269 - def _reduce_91( val, _values) - val - end -.,., - -module_eval <<'.,.,', 'parser.y', 274 - def _reduce_92( val, _values) - [ val[0].to_i, val[2].to_i ] - end -.,., - -module_eval <<'.,.,', 'parser.y', 279 - def _reduce_93( val, _values) - [ val[0].downcase, val[2].downcase, decode_params(val[3]) ] - end -.,., - -module_eval <<'.,.,', 'parser.y', 283 - def _reduce_94( val, _values) - [ val[0].downcase, nil, decode_params(val[1]) ] - end -.,., - -module_eval <<'.,.,', 'parser.y', 288 - def _reduce_95( val, _values) - {} - end -.,., - -module_eval <<'.,.,', 'parser.y', 293 - def _reduce_96( val, _values) - val[0][ val[2].downcase ] = ('"' + val[4].to_s + '"') - val[0] - end -.,., - -module_eval <<'.,.,', 'parser.y', 298 - def _reduce_97( val, _values) - val[0][ val[2].downcase ] = val[4] - val[0] - end -.,., - -module_eval <<'.,.,', 'parser.y', 303 - def _reduce_98( val, _values) - val[0].downcase - end -.,., - -module_eval <<'.,.,', 'parser.y', 308 - def _reduce_99( val, _values) - [ val[0].downcase, decode_params(val[1]) ] - end -.,., - - # reduce 100 omitted - - # reduce 101 omitted - - # reduce 102 omitted - - # reduce 103 omitted - - # reduce 104 omitted - - # reduce 105 omitted - - # reduce 106 omitted - - # reduce 107 omitted - - # reduce 108 omitted - - def _reduce_none( val, _values) - val[0] - end - - end # class Parser - -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/port.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/port.rb deleted file mode 100644 index 445f0e632b..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/port.rb +++ /dev/null @@ -1,379 +0,0 @@ -=begin rdoc - -= Port class - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -require 'tmail/stringio' - - -module TMail - - class Port - def reproducible? - false - end - end - - - ### - ### FilePort - ### - - class FilePort < Port - - def initialize( fname ) - @filename = File.expand_path(fname) - super() - end - - attr_reader :filename - - alias ident filename - - def ==( other ) - other.respond_to?(:filename) and @filename == other.filename - end - - alias eql? == - - def hash - @filename.hash - end - - def inspect - "#<#{self.class}:#{@filename}>" - end - - def reproducible? - true - end - - def size - File.size @filename - end - - - def ropen( &block ) - File.open(@filename, &block) - end - - def wopen( &block ) - File.open(@filename, 'w', &block) - end - - def aopen( &block ) - File.open(@filename, 'a', &block) - end - - - def read_all - ropen {|f| - return f.read - } - end - - - def remove - File.unlink @filename - end - - def move_to( port ) - begin - File.link @filename, port.filename - rescue Errno::EXDEV - copy_to port - end - File.unlink @filename - end - - alias mv move_to - - def copy_to( port ) - if FilePort === port - copy_file @filename, port.filename - else - File.open(@filename) {|r| - port.wopen {|w| - while s = r.sysread(4096) - w.write << s - end - } } - end - end - - alias cp copy_to - - private - - # from fileutils.rb - def copy_file( src, dest ) - st = r = w = nil - - File.open(src, 'rb') {|r| - File.open(dest, 'wb') {|w| - st = r.stat - begin - while true - w.write r.sysread(st.blksize) - end - rescue EOFError - end - } } - end - - end - - - module MailFlags - - def seen=( b ) - set_status 'S', b - end - - def seen? - get_status 'S' - end - - def replied=( b ) - set_status 'R', b - end - - def replied? - get_status 'R' - end - - def flagged=( b ) - set_status 'F', b - end - - def flagged? - get_status 'F' - end - - private - - def procinfostr( str, tag, true_p ) - a = str.upcase.split(//) - a.push true_p ? tag : nil - a.delete tag unless true_p - a.compact.sort.join('').squeeze - end - - end - - - class MhPort < FilePort - - include MailFlags - - private - - def set_status( tag, flag ) - begin - tmpfile = @filename + '.tmailtmp.' + $$.to_s - File.open(tmpfile, 'w') {|f| - write_status f, tag, flag - } - File.unlink @filename - File.link tmpfile, @filename - ensure - File.unlink tmpfile - end - end - - def write_status( f, tag, flag ) - stat = '' - File.open(@filename) {|r| - while line = r.gets - if line.strip.empty? - break - elsif m = /\AX-TMail-Status:/i.match(line) - stat = m.post_match.strip - else - f.print line - end - end - - s = procinfostr(stat, tag, flag) - f.puts 'X-TMail-Status: ' + s unless s.empty? - f.puts - - while s = r.read(2048) - f.write s - end - } - end - - def get_status( tag ) - File.foreach(@filename) {|line| - return false if line.strip.empty? - if m = /\AX-TMail-Status:/i.match(line) - return m.post_match.strip.include?(tag[0]) - end - } - false - end - - end - - - class MaildirPort < FilePort - - def move_to_new - new = replace_dir(@filename, 'new') - File.rename @filename, new - @filename = new - end - - def move_to_cur - new = replace_dir(@filename, 'cur') - File.rename @filename, new - @filename = new - end - - def replace_dir( path, dir ) - "#{File.dirname File.dirname(path)}/#{dir}/#{File.basename path}" - end - private :replace_dir - - - include MailFlags - - private - - MAIL_FILE = /\A(\d+\.[\d_]+\.[^:]+)(?:\:(\d),(\w+)?)?\z/ - - def set_status( tag, flag ) - if m = MAIL_FILE.match(File.basename(@filename)) - s, uniq, type, info, = m.to_a - return if type and type != '2' # do not change anything - newname = File.dirname(@filename) + '/' + - uniq + ':2,' + procinfostr(info.to_s, tag, flag) - else - newname = @filename + ':2,' + tag - end - - File.link @filename, newname - File.unlink @filename - @filename = newname - end - - def get_status( tag ) - m = MAIL_FILE.match(File.basename(@filename)) or return false - m[2] == '2' and m[3].to_s.include?(tag[0]) - end - - end - - - ### - ### StringPort - ### - - class StringPort < Port - - def initialize( str = '' ) - @buffer = str - super() - end - - def string - @buffer - end - - def to_s - @buffer.dup - end - - alias read_all to_s - - def size - @buffer.size - end - - def ==( other ) - StringPort === other and @buffer.equal? other.string - end - - alias eql? == - - def hash - @buffer.object_id.hash - end - - def inspect - "#<#{self.class}:id=#{sprintf '0x%x', @buffer.object_id}>" - end - - def reproducible? - true - end - - def ropen( &block ) - @buffer or raise Errno::ENOENT, "#{inspect} is already removed" - StringInput.open(@buffer, &block) - end - - def wopen( &block ) - @buffer = '' - StringOutput.new(@buffer, &block) - end - - def aopen( &block ) - @buffer ||= '' - StringOutput.new(@buffer, &block) - end - - def remove - @buffer = nil - end - - alias rm remove - - def copy_to( port ) - port.wopen {|f| - f.write @buffer - } - end - - alias cp copy_to - - def move_to( port ) - if StringPort === port - str = @buffer - port.instance_eval { @buffer = str } - else - copy_to port - end - remove - end - - end - -end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/quoting.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/quoting.rb deleted file mode 100644 index cb9f4288f1..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/quoting.rb +++ /dev/null @@ -1,118 +0,0 @@ -=begin rdoc - -= Quoting methods - -=end -module TMail - class Mail - def subject(to_charset = 'utf-8') - Unquoter.unquote_and_convert_to(quoted_subject, to_charset) - end - - def unquoted_body(to_charset = 'utf-8') - from_charset = sub_header("content-type", "charset") - case (content_transfer_encoding || "7bit").downcase - when "quoted-printable" - # the default charset is set to iso-8859-1 instead of 'us-ascii'. - # This is needed as many mailer do not set the charset but send in ISO. This is only used if no charset is set. - if !from_charset.blank? && from_charset.downcase == 'us-ascii' - from_charset = 'iso-8859-1' - end - - Unquoter.unquote_quoted_printable_and_convert_to(quoted_body, - to_charset, from_charset, true) - when "base64" - Unquoter.unquote_base64_and_convert_to(quoted_body, to_charset, - from_charset) - when "7bit", "8bit" - Unquoter.convert_to(quoted_body, to_charset, from_charset) - when "binary" - quoted_body - else - quoted_body - end - end - - def body(to_charset = 'utf-8', &block) - attachment_presenter = block || Proc.new { |file_name| "Attachment: #{file_name}\n" } - - if multipart? - parts.collect { |part| - header = part["content-type"] - - if part.multipart? - part.body(to_charset, &attachment_presenter) - elsif header.nil? - "" - elsif !attachment?(part) - part.unquoted_body(to_charset) - else - attachment_presenter.call(header["name"] || "(unnamed)") - end - }.join - else - unquoted_body(to_charset) - end - end - end - - class Unquoter - class << self - def unquote_and_convert_to(text, to_charset, from_charset = "iso-8859-1", preserve_underscores=false) - return "" if text.nil? - text.gsub(/(.*?)(?:(?:=\?(.*?)\?(.)\?(.*?)\?=)|$)/) do - before = $1 - from_charset = $2 - quoting_method = $3 - text = $4 - - before = convert_to(before, to_charset, from_charset) if before.length > 0 - before + case quoting_method - when "q", "Q" then - unquote_quoted_printable_and_convert_to(text, to_charset, from_charset, preserve_underscores) - when "b", "B" then - unquote_base64_and_convert_to(text, to_charset, from_charset) - when nil then - # will be nil at the end of the string, due to the nature of - # the regex used. - "" - else - raise "unknown quoting method #{quoting_method.inspect}" - end - end - end - - def unquote_quoted_printable_and_convert_to(text, to, from, preserve_underscores=false) - text = text.gsub(/_/, " ") unless preserve_underscores - text = text.gsub(/\r\n|\r/, "\n") # normalize newlines - convert_to(text.unpack("M*").first, to, from) - end - - def unquote_base64_and_convert_to(text, to, from) - convert_to(Base64.decode(text), to, from) - end - - begin - require 'iconv' - def convert_to(text, to, from) - return text unless to && from - text ? Iconv.iconv(to, from, text).first : "" - rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL - # the 'from' parameter specifies a charset other than what the text - # actually is...not much we can do in this case but just return the - # unconverted text. - # - # Ditto if either parameter represents an unknown charset, like - # X-UNKNOWN. - text - end - rescue LoadError - # Not providing quoting support - def convert_to(text, to, from) - warn "Action Mailer: iconv not loaded; ignoring conversion from #{from} to #{to} (#{__FILE__}:#{__LINE__})" - text - end - end - end - end -end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/require_arch.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/require_arch.rb deleted file mode 100644 index b4fffb8abb..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/require_arch.rb +++ /dev/null @@ -1,58 +0,0 @@ -#:stopdoc: -require 'rbconfig' - -# Attempts to require anative extension. -# Falls back to pure-ruby version, if it fails. -# -# This uses Config::CONFIG['arch'] from rbconfig. - -def require_arch(fname) - arch = Config::CONFIG['arch'] - begin - path = File.join("tmail", arch, fname) - require path - rescue LoadError => e - # try pre-built Windows binaries - if arch =~ /mswin/ - require File.join("tmail", 'mswin32', fname) - else - raise e - end - end -end - - -# def require_arch(fname) -# dext = Config::CONFIG['DLEXT'] -# begin -# if File.extname(fname) == dext -# path = fname -# else -# path = File.join("tmail","#{fname}.#{dext}") -# end -# require path -# rescue LoadError => e -# begin -# arch = Config::CONFIG['arch'] -# path = File.join("tmail", arch, "#{fname}.#{dext}") -# require path -# rescue LoadError -# case path -# when /i686/ -# path.sub!('i686', 'i586') -# when /i586/ -# path.sub!('i586', 'i486') -# when /i486/ -# path.sub!('i486', 'i386') -# else -# begin -# require fname + '.rb' -# rescue LoadError -# raise e -# end -# end -# retry -# end -# end -# end -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner.rb deleted file mode 100644 index a5d01396b8..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner.rb +++ /dev/null @@ -1,49 +0,0 @@ -=begin rdoc - -= Scanner for TMail - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ -#:stopdoc: -#require 'tmail/require_arch' -require 'tmail/utils' -require 'tmail/config' - -module TMail - # NOTE: It woiuld be nice if these two libs could boith be called "tmailscanner", and - # the native extension would have precedence. However RubyGems boffs that up b/c - # it does not gaurantee load_path order. - begin - raise LoadError, 'Turned off native extentions by user choice' if ENV['NORUBYEXT'] - require('tmail/tmailscanner') # c extension - Scanner = TMailScanner - rescue LoadError - require 'tmail/scanner_r' - Scanner = TMailScanner - end -end -#:stopdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner_r.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner_r.rb deleted file mode 100644 index f2075502d8..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/scanner_r.rb +++ /dev/null @@ -1,261 +0,0 @@ -# scanner_r.rb -# -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ -#:stopdoc: -require 'tmail/config' - -module TMail - - class TMailScanner - - Version = '1.2.3' - Version.freeze - - MIME_HEADERS = { - :CTYPE => true, - :CENCODING => true, - :CDISPOSITION => true - } - - alnum = 'a-zA-Z0-9' - atomsyms = %q[ _#!$%&`'*+-{|}~^/=? ].strip - tokensyms = %q[ _#!$%&`'*+-{|}~^@. ].strip - atomchars = alnum + Regexp.quote(atomsyms) - tokenchars = alnum + Regexp.quote(tokensyms) - iso2022str = '\e(?!\(B)..(?:[^\e]+|\e(?!\(B)..)*\e\(B' - - eucstr = "(?:[\xa1-\xfe][\xa1-\xfe])+" - sjisstr = "(?:[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc])+" - utf8str = "(?:[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf])+" - - quoted_with_iso2022 = /\A(?:[^\\\e"]+|#{iso2022str})+/n - domlit_with_iso2022 = /\A(?:[^\\\e\]]+|#{iso2022str})+/n - comment_with_iso2022 = /\A(?:[^\\\e()]+|#{iso2022str})+/n - - quoted_without_iso2022 = /\A[^\\"]+/n - domlit_without_iso2022 = /\A[^\\\]]+/n - comment_without_iso2022 = /\A[^\\()]+/n - - PATTERN_TABLE = {} - PATTERN_TABLE['EUC'] = - [ - /\A(?:[#{atomchars}]+|#{iso2022str}|#{eucstr})+/n, - /\A(?:[#{tokenchars}]+|#{iso2022str}|#{eucstr})+/n, - quoted_with_iso2022, - domlit_with_iso2022, - comment_with_iso2022 - ] - PATTERN_TABLE['SJIS'] = - [ - /\A(?:[#{atomchars}]+|#{iso2022str}|#{sjisstr})+/n, - /\A(?:[#{tokenchars}]+|#{iso2022str}|#{sjisstr})+/n, - quoted_with_iso2022, - domlit_with_iso2022, - comment_with_iso2022 - ] - PATTERN_TABLE['UTF8'] = - [ - /\A(?:[#{atomchars}]+|#{utf8str})+/n, - /\A(?:[#{tokenchars}]+|#{utf8str})+/n, - quoted_without_iso2022, - domlit_without_iso2022, - comment_without_iso2022 - ] - PATTERN_TABLE['NONE'] = - [ - /\A[#{atomchars}]+/n, - /\A[#{tokenchars}]+/n, - quoted_without_iso2022, - domlit_without_iso2022, - comment_without_iso2022 - ] - - - def initialize( str, scantype, comments ) - init_scanner str - @comments = comments || [] - @debug = false - - # fix scanner mode - @received = (scantype == :RECEIVED) - @is_mime_header = MIME_HEADERS[scantype] - - atom, token, @quoted_re, @domlit_re, @comment_re = PATTERN_TABLE[TMail.KCODE] - @word_re = (MIME_HEADERS[scantype] ? token : atom) - end - - attr_accessor :debug - - def scan( &block ) - if @debug - scan_main do |arr| - s, v = arr - printf "%7d %-10s %s\n", - rest_size(), - s.respond_to?(:id2name) ? s.id2name : s.inspect, - v.inspect - yield arr - end - else - scan_main(&block) - end - end - - private - - RECV_TOKEN = { - 'from' => :FROM, - 'by' => :BY, - 'via' => :VIA, - 'with' => :WITH, - 'id' => :ID, - 'for' => :FOR - } - - def scan_main - until eof? - if skip(/\A[\n\r\t ]+/n) # LWSP - break if eof? - end - - if s = readstr(@word_re) - if @is_mime_header - yield [:TOKEN, s] - else - # atom - if /\A\d+\z/ === s - yield [:DIGIT, s] - elsif @received - yield [RECV_TOKEN[s.downcase] || :ATOM, s] - else - yield [:ATOM, s] - end - end - - elsif skip(/\A"/) - yield [:QUOTED, scan_quoted_word()] - - elsif skip(/\A\[/) - yield [:DOMLIT, scan_domain_literal()] - - elsif skip(/\A\(/) - @comments.push scan_comment() - - else - c = readchar() - yield [c, c] - end - end - - yield [false, '$'] - end - - def scan_quoted_word - scan_qstr(@quoted_re, /\A"/, 'quoted-word') - end - - def scan_domain_literal - '[' + scan_qstr(@domlit_re, /\A\]/, 'domain-literal') + ']' - end - - def scan_qstr( pattern, terminal, type ) - result = '' - until eof? - if s = readstr(pattern) then result << s - elsif skip(terminal) then return result - elsif skip(/\A\\/) then result << readchar() - else - raise "TMail FATAL: not match in #{type}" - end - end - scan_error! "found unterminated #{type}" - end - - def scan_comment - result = '' - nest = 1 - content = @comment_re - - until eof? - if s = readstr(content) then result << s - elsif skip(/\A\)/) then nest -= 1 - return result if nest == 0 - result << ')' - elsif skip(/\A\(/) then nest += 1 - result << '(' - elsif skip(/\A\\/) then result << readchar() - else - raise 'TMail FATAL: not match in comment' - end - end - scan_error! 'found unterminated comment' - end - - # string scanner - - def init_scanner( str ) - @src = str - end - - def eof? - @src.empty? - end - - def rest_size - @src.size - end - - def readstr( re ) - if m = re.match(@src) - @src = m.post_match - m[0] - else - nil - end - end - - def readchar - readstr(/\A./) - end - - def skip( re ) - if m = re.match(@src) - @src = m.post_match - true - else - false - end - end - - def scan_error!( msg ) - raise SyntaxError, msg - end - - end - -end # module TMail -#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/stringio.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/stringio.rb deleted file mode 100644 index 8357398788..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/stringio.rb +++ /dev/null @@ -1,280 +0,0 @@ -# encoding: utf-8 -=begin rdoc - -= String handling class - -=end -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -class StringInput#:nodoc: - - include Enumerable - - class << self - - def new( str ) - if block_given? - begin - f = super - yield f - ensure - f.close if f - end - else - super - end - end - - alias open new - - end - - def initialize( str ) - @src = str - @pos = 0 - @closed = false - @lineno = 0 - end - - attr_reader :lineno - - def string - @src - end - - def inspect - "#<#{self.class}:#{@closed ? 'closed' : 'open'},src=#{@src[0,30].inspect}>" - end - - def close - stream_check! - @pos = nil - @closed = true - end - - def closed? - @closed - end - - def pos - stream_check! - [@pos, @src.size].min - end - - alias tell pos - - def seek( offset, whence = IO::SEEK_SET ) - stream_check! - case whence - when IO::SEEK_SET - @pos = offset - when IO::SEEK_CUR - @pos += offset - when IO::SEEK_END - @pos = @src.size - offset - else - raise ArgumentError, "unknown seek flag: #{whence}" - end - @pos = 0 if @pos < 0 - @pos = [@pos, @src.size + 1].min - offset - end - - def rewind - stream_check! - @pos = 0 - end - - def eof? - stream_check! - @pos > @src.size - end - - def each( &block ) - stream_check! - begin - @src.each(&block) - ensure - @pos = 0 - end - end - - def gets - stream_check! - if idx = @src.index(?\n, @pos) - idx += 1 # "\n".size - line = @src[ @pos ... idx ] - @pos = idx - @pos += 1 if @pos == @src.size - else - line = @src[ @pos .. -1 ] - @pos = @src.size + 1 - end - @lineno += 1 - - line - end - - def getc - stream_check! - ch = @src[@pos] - @pos += 1 - @pos += 1 if @pos == @src.size - ch - end - - def read( len = nil ) - stream_check! - return read_all unless len - str = @src[@pos, len] - @pos += len - @pos += 1 if @pos == @src.size - str - end - - alias sysread read - - def read_all - stream_check! - return nil if eof? - rest = @src[@pos ... @src.size] - @pos = @src.size + 1 - rest - end - - def stream_check! - @closed and raise IOError, 'closed stream' - end - -end - - -class StringOutput#:nodoc: - - class << self - - def new( str = '' ) - if block_given? - begin - f = super - yield f - ensure - f.close if f - end - else - super - end - end - - alias open new - - end - - def initialize( str = '' ) - @dest = str - @closed = false - end - - def close - @closed = true - end - - def closed? - @closed - end - - def string - @dest - end - - alias value string - alias to_str string - - def size - @dest.size - end - - alias pos size - - def inspect - "#<#{self.class}:#{@dest ? 'open' : 'closed'},#{object_id}>" - end - - def print( *args ) - stream_check! - raise ArgumentError, 'wrong # of argument (0 for >1)' if args.empty? - args.each do |s| - raise ArgumentError, 'nil not allowed' if s.nil? - @dest << s.to_s - end - nil - end - - def puts( *args ) - stream_check! - args.each do |str| - @dest << (s = str.to_s) - @dest << "\n" unless s[-1] == ?\n - end - @dest << "\n" if args.empty? - nil - end - - def putc( ch ) - stream_check! - @dest << ch.chr - nil - end - - def printf( *args ) - stream_check! - @dest << sprintf(*args) - nil - end - - def write( str ) - stream_check! - s = str.to_s - @dest << s - s.size - end - - alias syswrite write - - def <<( str ) - stream_check! - @dest << str.to_s - self - end - - private - - def stream_check! - @closed and raise IOError, 'closed stream' - end - -end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/utils.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/utils.rb deleted file mode 100644 index 9a3afe8985..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/utils.rb +++ /dev/null @@ -1,337 +0,0 @@ -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -# = TMail - The EMail Swiss Army Knife for Ruby -# -# The TMail library provides you with a very complete way to handle and manipulate EMails -# from within your Ruby programs. -# -# Used as the backbone for email handling by the Ruby on Rails and Nitro web frameworks as -# well as a bunch of other Ruby apps including the Ruby-Talk mailing list to newsgroup email -# gateway, it is a proven and reliable email handler that won't let you down. -# -# Originally created by Minero Aoki, TMail has been recently picked up by Mikel Lindsaar and -# is being actively maintained. Numerous backlogged bug fixes have been applied as well as -# Ruby 1.9 compatibility and a swath of documentation to boot. -# -# TMail allows you to treat an email totally as an object and allow you to get on with your -# own programming without having to worry about crafting the perfect email address validation -# parser, or assembling an email from all it's component parts. -# -# TMail handles the most complex part of the email - the header. It generates and parses -# headers and provides you with instant access to their innards through simple and logically -# named accessor and setter methods. -# -# TMail also provides a wrapper to Net/SMTP as well as Unix Mailbox handling methods to -# directly read emails from your unix mailbox, parse them and use them. -# -# Following is the comprehensive list of methods to access TMail::Mail objects. You can also -# check out TMail::Mail, TMail::Address and TMail::Headers for other lists. -module TMail - - # Provides an exception to throw on errors in Syntax within TMail's parsers - class SyntaxError < StandardError; end - - # Provides a new email boundary to separate parts of the email. This is a random - # string based off the current time, so should be fairly unique. - # - # For Example: - # - # TMail.new_boundary - # #=> "mimepart_47bf656968207_25a8fbb80114" - # TMail.new_boundary - # #=> "mimepart_47bf66051de4_25a8fbb80240" - def TMail.new_boundary - 'mimepart_' + random_tag - end - - # Provides a new email message ID. You can use this to generate unique email message - # id's for your email so you can track them. - # - # Optionally takes a fully qualified domain name (default to the current hostname - # returned by Socket.gethostname) that will be appended to the message ID. - # - # For Example: - # - # email.message_id = TMail.new_message_id - # #=> "<47bf66845380e_25a8fbb80332@baci.local.tmail>" - # email.to_s - # #=> "Message-Id: <47bf668b633f1_25a8fbb80475@baci.local.tmail>\n\n" - # email.message_id = TMail.new_message_id("lindsaar.net") - # #=> "<47bf668b633f1_25a8fbb80475@lindsaar.net.tmail>" - # email.to_s - # #=> "Message-Id: <47bf668b633f1_25a8fbb80475@lindsaar.net.tmail>\n\n" - def TMail.new_message_id( fqdn = nil ) - fqdn ||= ::Socket.gethostname - "<#{random_tag()}@#{fqdn}.tmail>" - end - - #:stopdoc: - def TMail.random_tag #:nodoc: - @uniq += 1 - t = Time.now - sprintf('%x%x_%x%x%d%x', - t.to_i, t.tv_usec, - $$, Thread.current.object_id, @uniq, rand(255)) - end - private_class_method :random_tag - - @uniq = 0 - - #:startdoc: - - # Text Utils provides a namespace to define TOKENs, ATOMs, PHRASEs and CONTROL characters that - # are OK per RFC 2822. - # - # It also provides methods you can call to determine if a string is safe - module TextUtils - - aspecial = %Q|()<>[]:;.\\,"| - tspecial = %Q|()<>[];:\\,"/?=| - lwsp = %Q| \t\r\n| - control = %Q|\x00-\x1f\x7f-\xff| - - CONTROL_CHAR = /[#{control}]/n - ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{lwsp}]/n - PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n - TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{lwsp}]/n - - # Returns true if the string supplied is free from characters not allowed as an ATOM - def atom_safe?( str ) - not ATOM_UNSAFE === str - end - - # If the string supplied has ATOM unsafe characters in it, will return the string quoted - # in double quotes, otherwise returns the string unmodified - def quote_atom( str ) - (ATOM_UNSAFE === str) ? dquote(str) : str - end - - # If the string supplied has PHRASE unsafe characters in it, will return the string quoted - # in double quotes, otherwise returns the string unmodified - def quote_phrase( str ) - (PHRASE_UNSAFE === str) ? dquote(str) : str - end - - # Returns true if the string supplied is free from characters not allowed as a TOKEN - def token_safe?( str ) - not TOKEN_UNSAFE === str - end - - # If the string supplied has TOKEN unsafe characters in it, will return the string quoted - # in double quotes, otherwise returns the string unmodified - def quote_token( str ) - (TOKEN_UNSAFE === str) ? dquote(str) : str - end - - # Wraps supplied string in double quotes unless it is already wrapped - # Returns double quoted string - def dquote( str ) #:nodoc: - unless str =~ /^".*?"$/ - '"' + str.gsub(/["\\]/n) {|s| '\\' + s } + '"' - else - str - end - end - private :dquote - - # Unwraps supplied string from inside double quotes - # Returns unquoted string - def unquote( str ) - str =~ /^"(.*?)"$/ ? $1 : str - end - - # Provides a method to join a domain name by it's parts and also makes it - # ATOM safe by quoting it as needed - def join_domain( arr ) - arr.map {|i| - if /\A\[.*\]\z/ === i - i - else - quote_atom(i) - end - }.join('.') - end - - #:stopdoc: - ZONESTR_TABLE = { - 'jst' => 9 * 60, - 'eet' => 2 * 60, - 'bst' => 1 * 60, - 'met' => 1 * 60, - 'gmt' => 0, - 'utc' => 0, - 'ut' => 0, - 'nst' => -(3 * 60 + 30), - 'ast' => -4 * 60, - 'edt' => -4 * 60, - 'est' => -5 * 60, - 'cdt' => -5 * 60, - 'cst' => -6 * 60, - 'mdt' => -6 * 60, - 'mst' => -7 * 60, - 'pdt' => -7 * 60, - 'pst' => -8 * 60, - 'a' => -1 * 60, - 'b' => -2 * 60, - 'c' => -3 * 60, - 'd' => -4 * 60, - 'e' => -5 * 60, - 'f' => -6 * 60, - 'g' => -7 * 60, - 'h' => -8 * 60, - 'i' => -9 * 60, - # j not use - 'k' => -10 * 60, - 'l' => -11 * 60, - 'm' => -12 * 60, - 'n' => 1 * 60, - 'o' => 2 * 60, - 'p' => 3 * 60, - 'q' => 4 * 60, - 'r' => 5 * 60, - 's' => 6 * 60, - 't' => 7 * 60, - 'u' => 8 * 60, - 'v' => 9 * 60, - 'w' => 10 * 60, - 'x' => 11 * 60, - 'y' => 12 * 60, - 'z' => 0 * 60 - } - #:startdoc: - - # Takes a time zone string from an EMail and converts it to Unix Time (seconds) - def timezone_string_to_unixtime( str ) - if m = /([\+\-])(\d\d?)(\d\d)/.match(str) - sec = (m[2].to_i * 60 + m[3].to_i) * 60 - m[1] == '-' ? -sec : sec - else - min = ZONESTR_TABLE[str.downcase] or - raise SyntaxError, "wrong timezone format '#{str}'" - min * 60 - end - end - - #:stopdoc: - WDAY = %w( Sun Mon Tue Wed Thu Fri Sat TMailBUG ) - MONTH = %w( TMailBUG Jan Feb Mar Apr May Jun - Jul Aug Sep Oct Nov Dec TMailBUG ) - - def time2str( tm ) - # [ruby-list:7928] - gmt = Time.at(tm.to_i) - gmt.gmtime - offset = tm.to_i - Time.local(*gmt.to_a[0,6].reverse).to_i - - # DO NOT USE strftime: setlocale() breaks it - sprintf '%s, %s %s %d %02d:%02d:%02d %+.2d%.2d', - WDAY[tm.wday], tm.mday, MONTH[tm.month], - tm.year, tm.hour, tm.min, tm.sec, - *(offset / 60).divmod(60) - end - - - MESSAGE_ID = /<[^\@>]+\@[^>\@]+>/ - - def message_id?( str ) - MESSAGE_ID === str - end - - - MIME_ENCODED = /=\?[^\s?=]+\?[QB]\?[^\s?=]+\?=/i - - def mime_encoded?( str ) - MIME_ENCODED === str - end - - - def decode_params( hash ) - new = Hash.new - encoded = nil - hash.each do |key, value| - if m = /\*(?:(\d+)\*)?\z/.match(key) - ((encoded ||= {})[m.pre_match] ||= [])[(m[1] || 0).to_i] = value - else - new[key] = to_kcode(value) - end - end - if encoded - encoded.each do |key, strings| - new[key] = decode_RFC2231(strings.join('')) - end - end - - new - end - - NKF_FLAGS = { - 'EUC' => '-e -m', - 'SJIS' => '-s -m' - } - - def to_kcode( str ) - flag = NKF_FLAGS[TMail.KCODE] or return str - NKF.nkf(flag, str) - end - - RFC2231_ENCODED = /\A(?:iso-2022-jp|euc-jp|shift_jis|us-ascii)?'[a-z]*'/in - - def decode_RFC2231( str ) - m = RFC2231_ENCODED.match(str) or return str - begin - to_kcode(m.post_match.gsub(/%[\da-f]{2}/in) {|s| s[1,2].hex.chr }) - rescue - m.post_match.gsub(/%[\da-f]{2}/in, "") - end - end - - def quote_boundary - # Make sure the Content-Type boundary= parameter is quoted if it contains illegal characters - # (to ensure any special characters in the boundary text are escaped from the parser - # (such as = in MS Outlook's boundary text)) - if @body =~ /^(.*)boundary=(.*)$/m - preamble = $1 - remainder = $2 - if remainder =~ /;/ - remainder =~ /^(.*?)(;.*)$/m - boundary_text = $1 - post = $2.chomp - else - boundary_text = remainder.chomp - end - if boundary_text =~ /[\/\?\=]/ - boundary_text = "\"#{boundary_text}\"" unless boundary_text =~ /^".*?"$/ - @body = "#{preamble}boundary=#{boundary_text}#{post}" - end - end - end - #:startdoc: - - - end - -end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/version.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/version.rb deleted file mode 100644 index 6bf8cc8061..0000000000 --- a/actionmailer/lib/action_mailer/vendor/tmail-1.2.2/tmail/version.rb +++ /dev/null @@ -1,39 +0,0 @@ -# -# version.rb -# -#-- -# Copyright (c) 1998-2003 Minero Aoki -# -# Permission is hereby granted, free of charge, to any person obtaining -# a copy of this software and associated documentation files (the -# "Software"), to deal in the Software without restriction, including -# without limitation the rights to use, copy, modify, merge, publish, -# distribute, sublicense, and/or sell copies of the Software, and to -# permit persons to whom the Software is furnished to do so, subject to -# the following conditions: -# -# The above copyright notice and this permission notice shall be -# included in all copies or substantial portions of the Software. -# -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, -# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND -# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE -# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION -# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION -# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -# -# Note: Originally licensed under LGPL v2+. Using MIT license for Rails -# with permission of Minero Aoki. -#++ - -#:stopdoc: -module TMail - module VERSION - MAJOR = 1 - MINOR = 2 - TINY = 2 - - STRING = [MAJOR, MINOR, TINY].join('.') - end -end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail.rb new file mode 100644 index 0000000000..18003659a6 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail.rb @@ -0,0 +1,5 @@ +require 'tmail/version' +require 'tmail/mail' +require 'tmail/mailbox' +require 'tmail/core_extensions' +require 'tmail/net' diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb new file mode 100644 index 0000000000..fa8e5bcd8c --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/address.rb @@ -0,0 +1,426 @@ +=begin rdoc + += Address handling class + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +require 'tmail/encode' +require 'tmail/parser' + + +module TMail + + # = Class Address + # + # Provides a complete handling library for email addresses. Can parse a string of an + # address directly or take in preformatted addresses themseleves. Allows you to add + # and remove phrases from the front of the address and provides a compare function for + # email addresses. + # + # == Parsing and Handling a Valid Address: + # + # Just pass the email address in as a string to Address.parse: + # + # email = TMail::Address.parse('Mikel Lindsaar ) + # #=> # + # email.address + # #=> "mikel@lindsaar.net" + # email.local + # #=> "mikel" + # email.domain + # #=> "lindsaar.net" + # email.name # Aliased as phrase as well + # #=> "Mikel Lindsaar" + # + # == Detecting an Invalid Address + # + # If you want to check the syntactical validity of an email address, just pass it to + # Address.parse and catch any SyntaxError: + # + # begin + # TMail::Mail.parse("mikel 2@@@@@ me .com") + # rescue TMail::SyntaxError + # puts("Invalid Email Address Detected") + # else + # puts("Address is valid") + # end + # #=> "Invalid Email Address Detected" + class Address + + include TextUtils #:nodoc: + + # Sometimes you need to parse an address, TMail can do it for you and provide you with + # a fairly robust method of detecting a valid address. + # + # Takes in a string, returns a TMail::Address object. + # + # Raises a TMail::SyntaxError on invalid email format + def Address.parse( str ) + Parser.parse :ADDRESS, special_quote_address(str) + end + + def Address.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(<.*?>)\Z/ + return "\"#{$1}\" #{$2}" + else + str + end + end + + def address_group? #:nodoc: + false + end + + # Address.new(local, domain) + # + # Accepts: + # + # * local - Left of the at symbol + # + # * domain - Array of the domain split at the periods. + # + # For example: + # + # Address.new("mikel", ["lindsaar", "net"]) + # #=> "#" + def initialize( local, domain ) + if domain + domain.each do |s| + raise SyntaxError, 'empty word in domain' if s.empty? + end + end + + # This is to catch an unquoted "@" symbol in the local part of the + # address. Handles addresses like <"@"@me.com> and makes sure they + # stay like <"@"@me.com> (previously were becomming <@@me.com>) + if local && (local.join == '@' || local.join =~ /\A[^"].*?@.*?[^"]\Z/) + @local = "\"#{local.join}\"" + else + @local = local + end + + @domain = domain + @name = nil + @routes = [] + end + + # Provides the name or 'phrase' of the email address. + # + # For Example: + # + # email = TMail::Address.parse("Mikel Lindsaar ") + # email.name + # #=> "Mikel Lindsaar" + def name + @name + end + + # Setter method for the name or phrase of the email + # + # For Example: + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.name + # #=> nil + # email.name = "Mikel Lindsaar" + # email.to_s + # #=> "Mikel Lindsaar " + def name=( str ) + @name = str + @name = nil if str and str.empty? + end + + #:stopdoc: + alias phrase name + alias phrase= name= + #:startdoc: + + # This is still here from RFC 822, and is now obsolete per RFC2822 Section 4. + # + # "When interpreting addresses, the route portion SHOULD be ignored." + # + # It is still here, so you can access it. + # + # Routes return the route portion at the front of the email address, if any. + # + # For Example: + # email = TMail::Address.parse( "<@sa,@another:Mikel@me.com>") + # => # + # email.to_s + # => "<@sa,@another:Mikel@me.com>" + # email.routes + # => ["sa", "another"] + def routes + @routes + end + + def inspect #:nodoc: + "#<#{self.class} #{address()}>" + end + + # Returns the local part of the email address + # + # For Example: + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.local + # #=> "mikel" + def local + return nil unless @local + return '""' if @local.size == 1 and @local[0].empty? + # Check to see if it is an array before trying to map it + if @local.respond_to?(:map) + @local.map {|i| quote_atom(i) }.join('.') + else + quote_atom(@local) + end + end + + # Returns the domain part of the email address + # + # For Example: + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.local + # #=> "lindsaar.net" + def domain + return nil unless @domain + join_domain(@domain) + end + + # Returns the full specific address itself + # + # For Example: + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.address + # #=> "mikel@lindsaar.net" + def spec + s = self.local + d = self.domain + if s and d + s + '@' + d + else + s + end + end + + alias address spec + + # Provides == function to the email. Only checks the actual address + # and ignores the name/phrase component + # + # For Example + # + # addr1 = TMail::Address.parse("My Address ") + # #=> "#" + # addr2 = TMail::Address.parse("Another ") + # #=> "#" + # addr1 == addr2 + # #=> true + def ==( other ) + other.respond_to? :spec and self.spec == other.spec + end + + alias eql? == + + # Provides a unique hash value for this record against the local and domain + # parts, ignores the name/phrase value + # + # email = TMail::Address.parse("mikel@lindsaar.net") + # email.hash + # #=> 18767598 + def hash + @local.hash ^ @domain.hash + end + + # Duplicates a TMail::Address object returning the duplicate + # + # addr1 = TMail::Address.parse("mikel@lindsaar.net") + # addr2 = addr1.dup + # addr1.id == addr2.id + # #=> false + def dup + obj = self.class.new(@local.dup, @domain.dup) + obj.name = @name.dup if @name + obj.routes.replace @routes + obj + end + + include StrategyInterface #:nodoc: + + def accept( strategy, dummy1 = nil, dummy2 = nil ) #:nodoc: + unless @local + strategy.meta '<>' # empty return-path + return + end + + spec_p = (not @name and @routes.empty?) + if @name + strategy.phrase @name + strategy.space + end + tmp = spec_p ? '' : '<' + unless @routes.empty? + tmp << @routes.map {|i| '@' + i }.join(',') << ':' + end + tmp << self.spec + tmp << '>' unless spec_p + strategy.meta tmp + strategy.lwsp '' + end + + end + + + class AddressGroup + + include Enumerable + + def address_group? + true + end + + def initialize( name, addrs ) + @name = name + @addresses = addrs + end + + attr_reader :name + + def ==( other ) + other.respond_to? :to_a and @addresses == other.to_a + end + + alias eql? == + + def hash + map {|i| i.hash }.hash + end + + def []( idx ) + @addresses[idx] + end + + def size + @addresses.size + end + + def empty? + @addresses.empty? + end + + def each( &block ) + @addresses.each(&block) + end + + def to_a + @addresses.dup + end + + alias to_ary to_a + + def include?( a ) + @addresses.include? a + end + + def flatten + set = [] + @addresses.each do |a| + if a.respond_to? :flatten + set.concat a.flatten + else + set.push a + end + end + set + end + + def each_address( &block ) + flatten.each(&block) + end + + def add( a ) + @addresses.push a + end + + alias push add + + def delete( a ) + @addresses.delete a + end + + include StrategyInterface + + def accept( strategy, dummy1 = nil, dummy2 = nil ) + strategy.phrase @name + strategy.meta ':' + strategy.space + first = true + each do |mbox| + if first + first = false + else + strategy.meta ',' + end + strategy.space + mbox.accept strategy + end + strategy.meta ';' + strategy.lwsp '' + end + + end + +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/attachments.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/attachments.rb new file mode 100644 index 0000000000..5dc5efae5e --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/attachments.rb @@ -0,0 +1,46 @@ +=begin rdoc + += Attachment handling file + +=end + +require 'stringio' + +module TMail + class Attachment < StringIO + attr_accessor :original_filename, :content_type + end + + class Mail + def has_attachments? + multipart? && parts.any? { |part| attachment?(part) } + end + + def attachment?(part) + part.disposition_is_attachment? || part.content_type_is_text? + end + + def attachments + if multipart? + parts.collect { |part| + if part.multipart? + part.attachments + elsif attachment?(part) + content = part.body # unquoted automatically by TMail#body + file_name = (part['content-location'] && + part['content-location'].body) || + part.sub_header("content-type", "name") || + part.sub_header("content-disposition", "filename") + + next if file_name.blank? || content.blank? + + attachment = Attachment.new(content) + attachment.original_filename = file_name.strip + attachment.content_type = part.content_type + attachment + end + }.flatten.compact + end + end + end +end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/base64.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/base64.rb new file mode 100644 index 0000000000..e294c62960 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/base64.rb @@ -0,0 +1,46 @@ +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ +#:stopdoc: +module TMail + module Base64 + + module_function + + def folding_encode( str, eol = "\n", limit = 60 ) + [str].pack('m') + end + + def encode( str ) + [str].pack('m').tr( "\r\n", '' ) + end + + def decode( str, strict = false ) + str.unpack('m').first + end + + end +end +#:startdoc: diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/compat.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/compat.rb new file mode 100644 index 0000000000..1275df79a6 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/compat.rb @@ -0,0 +1,41 @@ +#:stopdoc: +unless Enumerable.method_defined?(:map) + module Enumerable #:nodoc: + alias map collect + end +end + +unless Enumerable.method_defined?(:select) + module Enumerable #:nodoc: + alias select find_all + end +end + +unless Enumerable.method_defined?(:reject) + module Enumerable #:nodoc: + def reject + result = [] + each do |i| + result.push i unless yield(i) + end + result + end + end +end + +unless Enumerable.method_defined?(:sort_by) + module Enumerable #:nodoc: + def sort_by + map {|i| [yield(i), i] }.sort.map {|val, i| i } + end + end +end + +unless File.respond_to?(:read) + def File.read(fname) #:nodoc: + File.open(fname) {|f| + return f.read + } + end +end +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/config.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/config.rb new file mode 100644 index 0000000000..3a876dcdbd --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/config.rb @@ -0,0 +1,67 @@ +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ +#:stopdoc: +module TMail + + class Config + + def initialize( strict ) + @strict_parse = strict + @strict_base64decode = strict + end + + def strict_parse? + @strict_parse + end + + attr_writer :strict_parse + + def strict_base64decode? + @strict_base64decode + end + + attr_writer :strict_base64decode + + def new_body_port( mail ) + StringPort.new + end + + alias new_preamble_port new_body_port + alias new_part_port new_body_port + + end + + DEFAULT_CONFIG = Config.new(false) + DEFAULT_STRICT_CONFIG = Config.new(true) + + def Config.to_config( arg ) + return DEFAULT_STRICT_CONFIG if arg == true + return DEFAULT_CONFIG if arg == false + arg or DEFAULT_CONFIG + end + +end +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/core_extensions.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/core_extensions.rb new file mode 100644 index 0000000000..da62c33bbf --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/core_extensions.rb @@ -0,0 +1,63 @@ +#:stopdoc: +unless Object.respond_to?(:blank?) + class Object + # Check first to see if we are in a Rails environment, no need to + # define these methods if we are + + # An object is blank if it's nil, empty, or a whitespace string. + # For example, "", " ", nil, [], and {} are blank. + # + # This simplifies + # if !address.nil? && !address.empty? + # to + # if !address.blank? + def blank? + if respond_to?(:empty?) && respond_to?(:strip) + empty? or strip.empty? + elsif respond_to?(:empty?) + empty? + else + !self + end + end + end + + class NilClass + def blank? + true + end + end + + class FalseClass + def blank? + true + end + end + + class TrueClass + def blank? + false + end + end + + class Array + alias_method :blank?, :empty? + end + + class Hash + alias_method :blank?, :empty? + end + + class String + def blank? + empty? || strip.empty? + end + end + + class Numeric + def blank? + false + end + end +end +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/encode.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/encode.rb new file mode 100644 index 0000000000..458dbbfe6a --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/encode.rb @@ -0,0 +1,581 @@ +#-- +# = COPYRIGHT: +# +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ +#:stopdoc: +require 'nkf' +require 'tmail/base64' +require 'tmail/stringio' +require 'tmail/utils' +#:startdoc: + + +module TMail + + #:stopdoc: + class << self + attr_accessor :KCODE + end + self.KCODE = 'NONE' + + module StrategyInterface + + def create_dest( obj ) + case obj + when nil + StringOutput.new + when String + StringOutput.new(obj) + when IO, StringOutput + obj + else + raise TypeError, 'cannot handle this type of object for dest' + end + end + module_function :create_dest + + #:startdoc: + # Returns the TMail object encoded and ready to be sent via SMTP etc. + # You should call this before you are packaging up your email to + # correctly escape all the values that need escaping in the email, line + # wrap the email etc. + # + # It is also a good idea to call this before you marshal or serialize + # a TMail object. + # + # For Example: + # + # email = TMail::Load(my_email_file) + # email_to_send = email.encoded + def encoded( eol = "\r\n", charset = 'j', dest = nil ) + accept_strategy Encoder, eol, charset, dest + end + + # Returns the TMail object decoded and ready to be used by you, your + # program etc. + # + # You should call this before you are packaging up your email to + # correctly escape all the values that need escaping in the email, line + # wrap the email etc. + # + # For Example: + # + # email = TMail::Load(my_email_file) + # email_to_send = email.encoded + def decoded( eol = "\n", charset = 'e', dest = nil ) + # Turn the E-Mail into a string and return it with all + # encoded characters decoded. alias for to_s + accept_strategy Decoder, eol, charset, dest + end + + alias to_s decoded + + def accept_strategy( klass, eol, charset, dest = nil ) #:nodoc: + dest ||= '' + accept klass.new( create_dest(dest), charset, eol ) + dest + end + + end + + #:stopdoc: + + ### + ### MIME B encoding decoder + ### + + class Decoder + + include TextUtils + + encoded = '=\?(?:iso-2022-jp|euc-jp|shift_jis)\?[QB]\?[a-z0-9+/=]+\?=' + ENCODED_WORDS = /#{encoded}(?:\s+#{encoded})*/i + + OUTPUT_ENCODING = { + 'EUC' => 'e', + 'SJIS' => 's', + } + + def self.decode( str, encoding = nil ) + encoding ||= (OUTPUT_ENCODING[TMail.KCODE] || 'j') + opt = '-mS' + encoding + str.gsub(ENCODED_WORDS) {|s| NKF.nkf(opt, s) } + end + + def initialize( dest, encoding = nil, eol = "\n" ) + @f = StrategyInterface.create_dest(dest) + @encoding = (/\A[ejs]/ === encoding) ? encoding[0,1] : nil + @eol = eol + end + + def decode( str ) + self.class.decode(str, @encoding) + end + private :decode + + def terminate + end + + def header_line( str ) + @f << decode(str) + end + + def header_name( nm ) + @f << nm << ': ' + end + + def header_body( str ) + @f << decode(str) + end + + def space + @f << ' ' + end + + alias spc space + + def lwsp( str ) + @f << str + end + + def meta( str ) + @f << str + end + + def text( str ) + @f << decode(str) + end + + def phrase( str ) + @f << quote_phrase(decode(str)) + end + + def kv_pair( k, v ) + v = dquote(v) unless token_safe?(v) + @f << k << '=' << v + end + + def puts( str = nil ) + @f << str if str + @f << @eol + end + + def write( str ) + @f << str + end + + end + + + ### + ### MIME B-encoding encoder + ### + + # + # FIXME: This class can handle only (euc-jp/shift_jis -> iso-2022-jp). + # + class Encoder + + include TextUtils + + BENCODE_DEBUG = false unless defined?(BENCODE_DEBUG) + + def Encoder.encode( str ) + e = new() + e.header_body str + e.terminate + e.dest.string + end + + SPACER = "\t" + MAX_LINE_LEN = 78 + RFC_2822_MAX_LENGTH = 998 + + OPTIONS = { + 'EUC' => '-Ej -m0', + 'SJIS' => '-Sj -m0', + 'UTF8' => nil, # FIXME + 'NONE' => nil + } + + def initialize( dest = nil, encoding = nil, eol = "\r\n", limit = nil ) + @f = StrategyInterface.create_dest(dest) + @opt = OPTIONS[TMail.KCODE] + @eol = eol + @folded = false + @preserve_quotes = true + reset + end + + def preserve_quotes=( bool ) + @preserve_quotes + end + + def preserve_quotes + @preserve_quotes + end + + def normalize_encoding( str ) + if @opt + then NKF.nkf(@opt, str) + else str + end + end + + def reset + @text = '' + @lwsp = '' + @curlen = 0 + end + + def terminate + add_lwsp '' + reset + end + + def dest + @f + end + + def puts( str = nil ) + @f << str if str + @f << @eol + end + + def write( str ) + @f << str + end + + # + # add + # + + def header_line( line ) + scanadd line + end + + def header_name( name ) + add_text name.split(/-/).map {|i| i.capitalize }.join('-') + add_text ':' + add_lwsp ' ' + end + + def header_body( str ) + scanadd normalize_encoding(str) + end + + def space + add_lwsp ' ' + end + + alias spc space + + def lwsp( str ) + add_lwsp str.sub(/[\r\n]+[^\r\n]*\z/, '') + end + + def meta( str ) + add_text str + end + + def text( str ) + scanadd normalize_encoding(str) + end + + def phrase( str ) + str = normalize_encoding(str) + if CONTROL_CHAR === str + scanadd str + else + add_text quote_phrase(str) + end + end + + # FIXME: implement line folding + # + def kv_pair( k, v ) + return if v.nil? + v = normalize_encoding(v) + if token_safe?(v) + add_text k + '=' + v + elsif not CONTROL_CHAR === v + add_text k + '=' + quote_token(v) + else + # apply RFC2231 encoding + kv = k + '*=' + "iso-2022-jp'ja'" + encode_value(v) + add_text kv + end + end + + def encode_value( str ) + str.gsub(TOKEN_UNSAFE) {|s| '%%%02x' % s[0] } + end + + private + + def scanadd( str, force = false ) + types = '' + strs = [] + if str.respond_to?(:encoding) + enc = str.encoding + str.force_encoding(Encoding::ASCII_8BIT) + end + until str.empty? + if m = /\A[^\e\t\r\n ]+/.match(str) + types << (force ? 'j' : 'a') + if str.respond_to?(:encoding) + strs.push m[0].force_encoding(enc) + else + strs.push m[0] + end + elsif m = /\A[\t\r\n ]+/.match(str) + types << 's' + if str.respond_to?(:encoding) + strs.push m[0].force_encoding(enc) + else + strs.push m[0] + end + + elsif m = /\A\e../.match(str) + esc = m[0] + str = m.post_match + if esc != "\e(B" and m = /\A[^\e]+/.match(str) + types << 'j' + if str.respond_to?(:encoding) + strs.push m[0].force_encoding(enc) + else + strs.push m[0] + end + end + + else + raise 'TMail FATAL: encoder scan fail' + end + (str = m.post_match) unless m.nil? + end + + do_encode types, strs + end + + def do_encode( types, strs ) + # + # result : (A|E)(S(A|E))* + # E : W(SW)* + # W : (J|A)+ but must contain J # (J|A)*J(J|A)* + # A : <> + # J : <> + # S : <> + # + # An encoding unit is `E'. + # Input (parameter `types') is (J|A)(J|A|S)*(J|A) + # + if BENCODE_DEBUG + puts + puts '-- do_encode ------------' + puts types.split(//).join(' ') + p strs + end + + e = /[ja]*j[ja]*(?:s[ja]*j[ja]*)*/ + + while m = e.match(types) + pre = m.pre_match + concat_A_S pre, strs[0, pre.size] unless pre.empty? + concat_E m[0], strs[m.begin(0) ... m.end(0)] + types = m.post_match + strs.slice! 0, m.end(0) + end + concat_A_S types, strs + end + + def concat_A_S( types, strs ) + if RUBY_VERSION < '1.9' + a = ?a; s = ?s + else + a = 'a'.ord; s = 's'.ord + end + i = 0 + types.each_byte do |t| + case t + when a then add_text strs[i] + when s then add_lwsp strs[i] + else + raise "TMail FATAL: unknown flag: #{t.chr}" + end + i += 1 + end + end + + METHOD_ID = { + ?j => :extract_J, + ?e => :extract_E, + ?a => :extract_A, + ?s => :extract_S + } + + def concat_E( types, strs ) + if BENCODE_DEBUG + puts '---- concat_E' + puts "types=#{types.split(//).join(' ')}" + puts "strs =#{strs.inspect}" + end + + flush() unless @text.empty? + + chunk = '' + strs.each_with_index do |s,i| + mid = METHOD_ID[types[i]] + until s.empty? + unless c = __send__(mid, chunk.size, s) + add_with_encode chunk unless chunk.empty? + flush + chunk = '' + fold + c = __send__(mid, 0, s) + raise 'TMail FATAL: extract fail' unless c + end + chunk << c + end + end + add_with_encode chunk unless chunk.empty? + end + + def extract_J( chunksize, str ) + size = max_bytes(chunksize, str.size) - 6 + size = (size % 2 == 0) ? (size) : (size - 1) + return nil if size <= 0 + if str.respond_to?(:encoding) + enc = str.encoding + str.force_encoding(Encoding::ASCII_8BIT) + "\e$B#{str.slice!(0, size)}\e(B".force_encoding(enc) + else + "\e$B#{str.slice!(0, size)}\e(B" + end + end + + def extract_A( chunksize, str ) + size = max_bytes(chunksize, str.size) + return nil if size <= 0 + str.slice!(0, size) + end + + alias extract_S extract_A + + def max_bytes( chunksize, ssize ) + (restsize() - '=?iso-2022-jp?B??='.size) / 4 * 3 - chunksize + end + + # + # free length buffer + # + + def add_text( str ) + @text << str + # puts '---- text -------------------------------------' + # puts "+ #{str.inspect}" + # puts "txt >>>#{@text.inspect}<<<" + end + + def add_with_encode( str ) + @text << "=?iso-2022-jp?B?#{Base64.encode(str)}?=" + end + + def add_lwsp( lwsp ) + # puts '---- lwsp -------------------------------------' + # puts "+ #{lwsp.inspect}" + fold if restsize() <= 0 + flush(@folded) + @lwsp = lwsp + end + + def flush(folded = false) + # puts '---- flush ----' + # puts "spc >>>#{@lwsp.inspect}<<<" + # puts "txt >>>#{@text.inspect}<<<" + @f << @lwsp << @text + if folded + @curlen = 0 + else + @curlen += (@lwsp.size + @text.size) + end + @text = '' + @lwsp = '' + end + + def fold + # puts '---- fold ----' + unless @f.string =~ /^.*?:$/ + @f << @eol + @lwsp = SPACER + else + fold_header + @folded = true + end + @curlen = 0 + end + + def fold_header + # Called because line is too long - so we need to wrap. + # First look for whitespace in the text + # if it has text, fold there + # check the remaining text, if too long, fold again + # if it doesn't, then don't fold unless the line goes beyond 998 chars + + # Check the text to see if there is whitespace, or if not + @wrapped_text = [] + until @text.blank? + fold_the_string + end + @text = @wrapped_text.join("#{@eol}#{SPACER}") + end + + def fold_the_string + whitespace_location = @text =~ /\s/ || @text.length + # Is the location of the whitespace shorter than the RCF_2822_MAX_LENGTH? + # if there is no whitespace in the string, then this + unless mazsize(whitespace_location) <= 0 + @text.strip! + @wrapped_text << @text.slice!(0...whitespace_location) + # If it is not less, we have to wrap it destructively + else + slice_point = RFC_2822_MAX_LENGTH - @curlen - @lwsp.length + @text.strip! + @wrapped_text << @text.slice!(0...slice_point) + end + end + + def restsize + MAX_LINE_LEN - (@curlen + @lwsp.size + @text.size) + end + + def mazsize(whitespace_location) + # Per RFC2822, the maximum length of a line is 998 chars + RFC_2822_MAX_LENGTH - (@curlen + @lwsp.size + whitespace_location) + end + + end + #:startdoc: +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb new file mode 100644 index 0000000000..9153dcd7c6 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb @@ -0,0 +1,960 @@ +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +require 'tmail/encode' +require 'tmail/address' +require 'tmail/parser' +require 'tmail/config' +require 'tmail/utils' + +#:startdoc: +module TMail + + # Provides methods to handle and manipulate headers in the email + class HeaderField + + include TextUtils + + class << self + + alias newobj new + + def new( name, body, conf = DEFAULT_CONFIG ) + klass = FNAME_TO_CLASS[name.downcase] || UnstructuredHeader + klass.newobj body, conf + end + + # Returns a HeaderField object matching the header you specify in the "name" param. + # Requires an initialized TMail::Port to be passed in. + # + # The method searches the header of the Port you pass into it to find a match on + # the header line you pass. Once a match is found, it will unwrap the matching line + # as needed to return an initialized HeaderField object. + # + # If you want to get the Envelope sender of the email object, pass in "EnvelopeSender", + # if you want the From address of the email itself, pass in 'From'. + # + # This is because a mailbox doesn't have the : after the From that designates the + # beginning of the envelope sender (which can be different to the from address of + # the emial) + # + # Other fields can be passed as normal, "Reply-To", "Received" etc. + # + # Note: Change of behaviour in 1.2.1 => returns nil if it does not find the specified + # header field, otherwise returns an instantiated object of the correct header class + # + # For example: + # port = TMail::FilePort.new("/test/fixtures/raw_email_simple") + # h = TMail::HeaderField.new_from_port(port, "From") + # h.addrs.to_s #=> "Mikel Lindsaar " + # h = TMail::HeaderField.new_from_port(port, "EvelopeSender") + # h.addrs.to_s #=> "mike@anotherplace.com.au" + # h = TMail::HeaderField.new_from_port(port, "SomeWeirdHeaderField") + # h #=> nil + def new_from_port( port, name, conf = DEFAULT_CONFIG ) + if name == "EnvelopeSender" + name = "From" + re = Regexp.new('\A(From) ', 'i') + else + re = Regexp.new('\A(' + Regexp.quote(name) + '):', 'i') + end + str = nil + port.ropen {|f| + f.each do |line| + if m = re.match(line) then str = m.post_match.strip + elsif str and /\A[\t ]/ === line then str << ' ' << line.strip + elsif /\A-*\s*\z/ === line then break + elsif str then break + end + end + } + new(name, str, Config.to_config(conf)) if str + end + + def internal_new( name, conf ) + FNAME_TO_CLASS[name].newobj('', conf, true) + end + + end # class << self + + def initialize( body, conf, intern = false ) + @body = body + @config = conf + + @illegal = false + @parsed = false + + if intern + @parsed = true + parse_init + end + end + + def inspect + "#<#{self.class} #{@body.inspect}>" + end + + def illegal? + @illegal + end + + def empty? + ensure_parsed + return true if @illegal + isempty? + end + + private + + def ensure_parsed + return if @parsed + @parsed = true + parse + end + + # defabstract parse + # end + + def clear_parse_status + @parsed = false + @illegal = false + end + + public + + def body + ensure_parsed + v = Decoder.new(s = '') + do_accept v + v.terminate + s + end + + def body=( str ) + @body = str + clear_parse_status + end + + include StrategyInterface + + def accept( strategy ) + ensure_parsed + do_accept strategy + strategy.terminate + end + + # abstract do_accept + + end + + + class UnstructuredHeader < HeaderField + + def body + ensure_parsed + @body + end + + def body=( arg ) + ensure_parsed + @body = arg + end + + private + + def parse_init + end + + def parse + @body = Decoder.decode(@body.gsub(/\n|\r\n|\r/, '')) + end + + def isempty? + not @body + end + + def do_accept( strategy ) + strategy.text @body + end + + end + + + class StructuredHeader < HeaderField + + def comments + ensure_parsed + if @comments[0] + [Decoder.decode(@comments[0])] + else + @comments + end + end + + private + + def parse + save = nil + + begin + parse_init + do_parse + rescue SyntaxError + if not save and mime_encoded? @body + save = @body + @body = Decoder.decode(save) + retry + elsif save + @body = save + end + + @illegal = true + raise if @config.strict_parse? + end + end + + def parse_init + @comments = [] + init + end + + def do_parse + quote_boundary + obj = Parser.parse(self.class::PARSE_TYPE, @body, @comments) + set obj if obj + end + + end + + + class DateTimeHeader < StructuredHeader + + PARSE_TYPE = :DATETIME + + def date + ensure_parsed + @date + end + + def date=( arg ) + ensure_parsed + @date = arg + end + + private + + def init + @date = nil + end + + def set( t ) + @date = t + end + + def isempty? + not @date + end + + def do_accept( strategy ) + strategy.meta time2str(@date) + end + + end + + + class AddressHeader < StructuredHeader + + PARSE_TYPE = :MADDRESS + + def addrs + ensure_parsed + @addrs + end + + private + + def init + @addrs = [] + end + + def set( a ) + @addrs = a + end + + def isempty? + @addrs.empty? + end + + def do_accept( strategy ) + first = true + @addrs.each do |a| + if first + first = false + else + strategy.meta ',' + strategy.space + end + a.accept strategy + end + + @comments.each do |c| + strategy.space + strategy.meta '(' + strategy.text c + strategy.meta ')' + end + end + + end + + + class ReturnPathHeader < AddressHeader + + PARSE_TYPE = :RETPATH + + def addr + addrs()[0] + end + + def spec + a = addr() or return nil + a.spec + end + + def routes + a = addr() or return nil + a.routes + end + + private + + def do_accept( strategy ) + a = addr() + + strategy.meta '<' + unless a.routes.empty? + strategy.meta a.routes.map {|i| '@' + i }.join(',') + strategy.meta ':' + end + spec = a.spec + strategy.meta spec if spec + strategy.meta '>' + end + + end + + + class SingleAddressHeader < AddressHeader + + def addr + addrs()[0] + end + + private + + def do_accept( strategy ) + a = addr() + a.accept strategy + @comments.each do |c| + strategy.space + strategy.meta '(' + strategy.text c + strategy.meta ')' + end + end + + end + + + class MessageIdHeader < StructuredHeader + + def id + ensure_parsed + @id + end + + def id=( arg ) + ensure_parsed + @id = arg + end + + private + + def init + @id = nil + end + + def isempty? + not @id + end + + def do_parse + @id = @body.slice(MESSAGE_ID) or + raise SyntaxError, "wrong Message-ID format: #{@body}" + end + + def do_accept( strategy ) + strategy.meta @id + end + + end + + + class ReferencesHeader < StructuredHeader + + def refs + ensure_parsed + @refs + end + + def each_id + self.refs.each do |i| + yield i if MESSAGE_ID === i + end + end + + def ids + ensure_parsed + @ids + end + + def each_phrase + self.refs.each do |i| + yield i unless MESSAGE_ID === i + end + end + + def phrases + ret = [] + each_phrase {|i| ret.push i } + ret + end + + private + + def init + @refs = [] + @ids = [] + end + + def isempty? + @ids.empty? + end + + def do_parse + str = @body + while m = MESSAGE_ID.match(str) + pre = m.pre_match.strip + @refs.push pre unless pre.empty? + @refs.push s = m[0] + @ids.push s + str = m.post_match + end + str = str.strip + @refs.push str unless str.empty? + end + + def do_accept( strategy ) + first = true + @ids.each do |i| + if first + first = false + else + strategy.space + end + strategy.meta i + end + end + + end + + + class ReceivedHeader < StructuredHeader + + PARSE_TYPE = :RECEIVED + + def from + ensure_parsed + @from + end + + def from=( arg ) + ensure_parsed + @from = arg + end + + def by + ensure_parsed + @by + end + + def by=( arg ) + ensure_parsed + @by = arg + end + + def via + ensure_parsed + @via + end + + def via=( arg ) + ensure_parsed + @via = arg + end + + def with + ensure_parsed + @with + end + + def id + ensure_parsed + @id + end + + def id=( arg ) + ensure_parsed + @id = arg + end + + def _for + ensure_parsed + @_for + end + + def _for=( arg ) + ensure_parsed + @_for = arg + end + + def date + ensure_parsed + @date + end + + def date=( arg ) + ensure_parsed + @date = arg + end + + private + + def init + @from = @by = @via = @with = @id = @_for = nil + @with = [] + @date = nil + end + + def set( args ) + @from, @by, @via, @with, @id, @_for, @date = *args + end + + def isempty? + @with.empty? and not (@from or @by or @via or @id or @_for or @date) + end + + def do_accept( strategy ) + list = [] + list.push 'from ' + @from if @from + list.push 'by ' + @by if @by + list.push 'via ' + @via if @via + @with.each do |i| + list.push 'with ' + i + end + list.push 'id ' + @id if @id + list.push 'for <' + @_for + '>' if @_for + + first = true + list.each do |i| + strategy.space unless first + strategy.meta i + first = false + end + if @date + strategy.meta ';' + strategy.space + strategy.meta time2str(@date) + end + end + + end + + + class KeywordsHeader < StructuredHeader + + PARSE_TYPE = :KEYWORDS + + def keys + ensure_parsed + @keys + end + + private + + def init + @keys = [] + end + + def set( a ) + @keys = a + end + + def isempty? + @keys.empty? + end + + def do_accept( strategy ) + first = true + @keys.each do |i| + if first + first = false + else + strategy.meta ',' + end + strategy.meta i + end + end + + end + + + class EncryptedHeader < StructuredHeader + + PARSE_TYPE = :ENCRYPTED + + def encrypter + ensure_parsed + @encrypter + end + + def encrypter=( arg ) + ensure_parsed + @encrypter = arg + end + + def keyword + ensure_parsed + @keyword + end + + def keyword=( arg ) + ensure_parsed + @keyword = arg + end + + private + + def init + @encrypter = nil + @keyword = nil + end + + def set( args ) + @encrypter, @keyword = args + end + + def isempty? + not (@encrypter or @keyword) + end + + def do_accept( strategy ) + if @key + strategy.meta @encrypter + ',' + strategy.space + strategy.meta @keyword + else + strategy.meta @encrypter + end + end + + end + + + class MimeVersionHeader < StructuredHeader + + PARSE_TYPE = :MIMEVERSION + + def major + ensure_parsed + @major + end + + def major=( arg ) + ensure_parsed + @major = arg + end + + def minor + ensure_parsed + @minor + end + + def minor=( arg ) + ensure_parsed + @minor = arg + end + + def version + sprintf('%d.%d', major, minor) + end + + private + + def init + @major = nil + @minor = nil + end + + def set( args ) + @major, @minor = *args + end + + def isempty? + not (@major or @minor) + end + + def do_accept( strategy ) + strategy.meta sprintf('%d.%d', @major, @minor) + end + + end + + + class ContentTypeHeader < StructuredHeader + + PARSE_TYPE = :CTYPE + + def main_type + ensure_parsed + @main + end + + def main_type=( arg ) + ensure_parsed + @main = arg.downcase + end + + def sub_type + ensure_parsed + @sub + end + + def sub_type=( arg ) + ensure_parsed + @sub = arg.downcase + end + + def content_type + ensure_parsed + @sub ? sprintf('%s/%s', @main, @sub) : @main + end + + def params + ensure_parsed + unless @params.blank? + @params.each do |k, v| + @params[k] = unquote(v) + end + end + @params + end + + def []( key ) + ensure_parsed + @params and unquote(@params[key]) + end + + def []=( key, val ) + ensure_parsed + (@params ||= {})[key] = val + end + + private + + def init + @main = @sub = @params = nil + end + + def set( args ) + @main, @sub, @params = *args + end + + def isempty? + not (@main or @sub) + end + + def do_accept( strategy ) + if @sub + strategy.meta sprintf('%s/%s', @main, @sub) + else + strategy.meta @main + end + @params.each do |k,v| + if v + strategy.meta ';' + strategy.space + strategy.kv_pair k, v + end + end + end + + end + + + class ContentTransferEncodingHeader < StructuredHeader + + PARSE_TYPE = :CENCODING + + def encoding + ensure_parsed + @encoding + end + + def encoding=( arg ) + ensure_parsed + @encoding = arg + end + + private + + def init + @encoding = nil + end + + def set( s ) + @encoding = s + end + + def isempty? + not @encoding + end + + def do_accept( strategy ) + strategy.meta @encoding.capitalize + end + + end + + + class ContentDispositionHeader < StructuredHeader + + PARSE_TYPE = :CDISPOSITION + + def disposition + ensure_parsed + @disposition + end + + def disposition=( str ) + ensure_parsed + @disposition = str.downcase + end + + def params + ensure_parsed + unless @params.blank? + @params.each do |k, v| + @params[k] = unquote(v) + end + end + @params + end + + def []( key ) + ensure_parsed + @params and unquote(@params[key]) + end + + def []=( key, val ) + ensure_parsed + (@params ||= {})[key] = val + end + + private + + def init + @disposition = @params = nil + end + + def set( args ) + @disposition, @params = *args + end + + def isempty? + not @disposition and (not @params or @params.empty?) + end + + def do_accept( strategy ) + strategy.meta @disposition + @params.each do |k,v| + strategy.meta ';' + strategy.space + strategy.kv_pair k, unquote(v) + end + end + + end + + + class HeaderField # redefine + + FNAME_TO_CLASS = { + 'date' => DateTimeHeader, + 'resent-date' => DateTimeHeader, + 'to' => AddressHeader, + 'cc' => AddressHeader, + 'bcc' => AddressHeader, + 'from' => AddressHeader, + 'reply-to' => AddressHeader, + 'resent-to' => AddressHeader, + 'resent-cc' => AddressHeader, + 'resent-bcc' => AddressHeader, + 'resent-from' => AddressHeader, + 'resent-reply-to' => AddressHeader, + 'sender' => SingleAddressHeader, + 'resent-sender' => SingleAddressHeader, + 'return-path' => ReturnPathHeader, + 'message-id' => MessageIdHeader, + 'resent-message-id' => MessageIdHeader, + 'in-reply-to' => ReferencesHeader, + 'received' => ReceivedHeader, + 'references' => ReferencesHeader, + 'keywords' => KeywordsHeader, + 'encrypted' => EncryptedHeader, + 'mime-version' => MimeVersionHeader, + 'content-type' => ContentTypeHeader, + 'content-transfer-encoding' => ContentTransferEncodingHeader, + 'content-disposition' => ContentDispositionHeader, + 'content-id' => MessageIdHeader, + 'subject' => UnstructuredHeader, + 'comments' => UnstructuredHeader, + 'content-description' => UnstructuredHeader + } + + end + +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/index.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/index.rb new file mode 100644 index 0000000000..554e2fd696 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/index.rb @@ -0,0 +1,9 @@ +#:stopdoc: +# This is here for Rolls. +# Rolls uses this instead of lib/tmail.rb. + +require 'tmail/version' +require 'tmail/mail' +require 'tmail/mailbox' +require 'tmail/core_extensions' +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb new file mode 100644 index 0000000000..a6d428d7d6 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/interface.rb @@ -0,0 +1,1130 @@ +=begin rdoc + += interface.rb Provides an interface to the TMail object + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +# TMail::Mail objects get accessed primarily through the methods in this file. +# +# + +require 'tmail/utils' + +module TMail + + class Mail + + # Allows you to query the mail object with a string to get the contents + # of the field you want. + # + # Returns a string of the exact contnts of the field + # + # mail.from = "mikel " + # mail.header_string("From") #=> "mikel " + def header_string( name, default = nil ) + h = @header[name.downcase] or return default + h.to_s + end + + #:stopdoc: + #-- + #== Attributes + + include TextUtils + + def set_string_array_attr( key, strs ) + strs.flatten! + if strs.empty? + @header.delete key.downcase + else + store key, strs.join(', ') + end + strs + end + private :set_string_array_attr + + def set_string_attr( key, str ) + if str + store key, str + else + @header.delete key.downcase + end + str + end + private :set_string_attr + + def set_addrfield( name, arg ) + if arg + h = HeaderField.internal_new(name, @config) + h.addrs.replace [arg].flatten + @header[name] = h + else + @header.delete name + end + arg + end + private :set_addrfield + + def addrs2specs( addrs ) + return nil unless addrs + list = addrs.map {|addr| + if addr.address_group? + then addr.map {|a| a.spec } + else addr.spec + end + }.flatten + return nil if list.empty? + list + end + private :addrs2specs + + #:startdoc: + + #== Date and Time methods + + # Returns the date of the email message as per the "date" header value or returns + # nil by default (if no date field exists). + # + # You can also pass whatever default you want into this method and it will return + # that instead of nil if there is no date already set. + def date( default = nil ) + if h = @header['date'] + h.date + else + default + end + end + + # Destructively sets the date of the mail object with the passed Time instance, + # returns a Time instance set to the date/time of the mail + # + # Example: + # + # now = Time.now + # mail.date = now + # mail.date #=> Sat Nov 03 18:47:50 +1100 2007 + # mail.date.class #=> Time + def date=( time ) + if time + store 'Date', time2str(time) + else + @header.delete 'date' + end + time + end + + # Returns the time of the mail message formatted to your taste using a + # strftime format string. If no date set returns nil by default or whatever value + # you pass as the second optional parameter. + # + # time = Time.now # (on Nov 16 2007) + # mail.date = time + # mail.strftime("%D") #=> "11/16/07" + def strftime( fmt, default = nil ) + if t = date + t.strftime(fmt) + else + default + end + end + + #== Destination methods + + # Return a TMail::Addresses instance for each entry in the "To:" field of the mail object header. + # + # If the "To:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.to_addrs #=> nil + # mail.to_addrs([]) #=> [] + # mail.to = "Mikel , another Mikel " + # mail.to_addrs #=> [#, #] + def to_addrs( default = nil ) + if h = @header['to'] + h.addrs + else + default + end + end + + # Return a TMail::Addresses instance for each entry in the "Cc:" field of the mail object header. + # + # If the "Cc:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.cc_addrs #=> nil + # mail.cc_addrs([]) #=> [] + # mail.cc = "Mikel , another Mikel " + # mail.cc_addrs #=> [#, #] + def cc_addrs( default = nil ) + if h = @header['cc'] + h.addrs + else + default + end + end + + # Return a TMail::Addresses instance for each entry in the "Bcc:" field of the mail object header. + # + # If the "Bcc:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.bcc_addrs #=> nil + # mail.bcc_addrs([]) #=> [] + # mail.bcc = "Mikel , another Mikel " + # mail.bcc_addrs #=> [#, #] + def bcc_addrs( default = nil ) + if h = @header['bcc'] + h.addrs + else + default + end + end + + # Destructively set the to field of the "To:" header to equal the passed in string. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.to = "Mikel , another Mikel " + # mail.to_addrs #=> [#, #] + def to_addrs=( arg ) + set_addrfield 'to', arg + end + + # Destructively set the to field of the "Cc:" header to equal the passed in string. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.cc = "Mikel , another Mikel " + # mail.cc_addrs #=> [#, #] + def cc_addrs=( arg ) + set_addrfield 'cc', arg + end + + # Destructively set the to field of the "Bcc:" header to equal the passed in string. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.bcc = "Mikel , another Mikel " + # mail.bcc_addrs #=> [#, #] + def bcc_addrs=( arg ) + set_addrfield 'bcc', arg + end + + # Returns who the email is to as an Array of email addresses as opposed to an Array of + # TMail::Address objects which is what Mail#to_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.to = "Mikel , another Mikel " + # mail.to #=> ["mikel@me.org", "mikel@you.org"] + def to( default = nil ) + addrs2specs(to_addrs(nil)) || default + end + + # Returns who the email cc'd as an Array of email addresses as opposed to an Array of + # TMail::Address objects which is what Mail#to_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.cc = "Mikel , another Mikel " + # mail.cc #=> ["mikel@me.org", "mikel@you.org"] + def cc( default = nil ) + addrs2specs(cc_addrs(nil)) || default + end + + # Returns who the email bcc'd as an Array of email addresses as opposed to an Array of + # TMail::Address objects which is what Mail#to_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.bcc = "Mikel , another Mikel " + # mail.bcc #=> ["mikel@me.org", "mikel@you.org"] + def bcc( default = nil ) + addrs2specs(bcc_addrs(nil)) || default + end + + # Destructively sets the "To:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.to = ["mikel@abc.com", "Mikel "] + # mail.to #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['to'].to_s #=> "mikel@abc.com, Mikel " + def to=( *strs ) + set_string_array_attr 'To', strs + end + + # Destructively sets the "Cc:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.cc = ["mikel@abc.com", "Mikel "] + # mail.cc #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['cc'].to_s #=> "mikel@abc.com, Mikel " + def cc=( *strs ) + set_string_array_attr 'Cc', strs + end + + # Destructively sets the "Bcc:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.bcc = ["mikel@abc.com", "Mikel "] + # mail.bcc #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['bcc'].to_s #=> "mikel@abc.com, Mikel " + def bcc=( *strs ) + set_string_array_attr 'Bcc', strs + end + + #== Originator methods + + # Return a TMail::Addresses instance for each entry in the "From:" field of the mail object header. + # + # If the "From:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.from_addrs #=> nil + # mail.from_addrs([]) #=> [] + # mail.from = "Mikel , another Mikel " + # mail.from_addrs #=> [#, #] + def from_addrs( default = nil ) + if h = @header['from'] + h.addrs + else + default + end + end + + # Destructively set the to value of the "From:" header to equal the passed in string. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.from_addrs = "Mikel , another Mikel " + # mail.from_addrs #=> [#, #] + def from_addrs=( arg ) + set_addrfield 'from', arg + end + + # Returns who the email is from as an Array of email address strings instead to an Array of + # TMail::Address objects which is what Mail#from_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.from = "Mikel , another Mikel " + # mail.from #=> ["mikel@me.org", "mikel@you.org"] + def from( default = nil ) + addrs2specs(from_addrs(nil)) || default + end + + # Destructively sets the "From:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.from = ["mikel@abc.com", "Mikel "] + # mail.from #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['from'].to_s #=> "mikel@abc.com, Mikel " + def from=( *strs ) + set_string_array_attr 'From', strs + end + + # Returns the "friendly" human readable part of the address + # + # Example: + # + # mail = TMail::Mail.new + # mail.from = "Mikel Lindsaar " + # mail.friendly_from #=> "Mikel Lindsaar" + def friendly_from( default = nil ) + h = @header['from'] + a, = h.addrs + return default unless a + return a.phrase if a.phrase + return h.comments.join(' ') unless h.comments.empty? + a.spec + end + + # Return a TMail::Addresses instance for each entry in the "Reply-To:" field of the mail object header. + # + # If the "Reply-To:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.reply_to_addrs #=> nil + # mail.reply_to_addrs([]) #=> [] + # mail.reply_to = "Mikel , another Mikel " + # mail.reply_to_addrs #=> [#, #] + def reply_to_addrs( default = nil ) + if h = @header['reply-to'] + h.addrs.blank? ? default : h.addrs + else + default + end + end + + # Destructively set the to value of the "Reply-To:" header to equal the passed in argument. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.reply_to_addrs = "Mikel , another Mikel " + # mail.reply_to_addrs #=> [#, #] + def reply_to_addrs=( arg ) + set_addrfield 'reply-to', arg + end + + # Returns who the email is from as an Array of email address strings instead to an Array of + # TMail::Address objects which is what Mail#reply_to_addrs returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.reply_to = "Mikel , another Mikel " + # mail.reply_to #=> ["mikel@me.org", "mikel@you.org"] + def reply_to( default = nil ) + addrs2specs(reply_to_addrs(nil)) || default + end + + # Destructively sets the "Reply-To:" field to the passed array of strings (which should be valid + # email addresses) + # + # Example: + # + # mail = TMail::Mail.new + # mail.reply_to = ["mikel@abc.com", "Mikel "] + # mail.reply_to #=> ["mikel@abc.org", "mikel@xyz.org"] + # mail['reply_to'].to_s #=> "mikel@abc.com, Mikel " + def reply_to=( *strs ) + set_string_array_attr 'Reply-To', strs + end + + # Return a TMail::Addresses instance of the "Sender:" field of the mail object header. + # + # If the "Sender:" field does not exist, will return nil by default or the value you + # pass as the optional parameter. + # + # Example: + # + # mail = TMail::Mail.new + # mail.sender #=> nil + # mail.sender([]) #=> [] + # mail.sender = "Mikel " + # mail.reply_to_addrs #=> [#] + def sender_addr( default = nil ) + f = @header['sender'] or return default + f.addr or return default + end + + # Destructively set the to value of the "Sender:" header to equal the passed in argument. + # + # TMail will parse your contents and turn each valid email address into a TMail::Address + # object before assigning it to the mail message. + # + # Example: + # + # mail = TMail::Mail.new + # mail.sender_addrs = "Mikel , another Mikel " + # mail.sender_addrs #=> [#, #] + def sender_addr=( addr ) + if addr + h = HeaderField.internal_new('sender', @config) + h.addr = addr + @header['sender'] = h + else + @header.delete 'sender' + end + addr + end + + # Returns who the sender of this mail is as string instead to an Array of + # TMail::Address objects which is what Mail#sender_addr returns + # + # Example: + # + # mail = TMail::Mail.new + # mail.sender = "Mikel " + # mail.sender #=> "mikel@me.org" + def sender( default = nil ) + f = @header['sender'] or return default + a = f.addr or return default + a.spec + end + + # Destructively sets the "Sender:" field to the passed string (which should be a valid + # email address) + # + # Example: + # + # mail = TMail::Mail.new + # mail.sender = "mikel@abc.com" + # mail.sender #=> "mikel@abc.org" + # mail['sender'].to_s #=> "mikel@abc.com" + def sender=( str ) + set_string_attr 'Sender', str + end + + #== Subject methods + + # Returns the subject of the mail instance. + # + # If the subject field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.subject #=> nil + # mail.subject("") #=> "" + # mail.subject = "Hello" + # mail.subject #=> "Hello" + def subject( default = nil ) + if h = @header['subject'] + h.body + else + default + end + end + alias quoted_subject subject + + # Destructively sets the passed string as the subject of the mail message. + # + # Example + # + # mail = TMail::Mail.new + # mail.subject #=> "This subject" + # mail.subject = "Another subject" + # mail.subject #=> "Another subject" + def subject=( str ) + set_string_attr 'Subject', str + end + + #== Message Identity & Threading Methods + + # Returns the message ID for this mail object instance. + # + # If the message_id field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.message_id #=> nil + # mail.message_id(TMail.new_message_id) #=> "<47404c5326d9c_2ad4fbb80161@baci.local.tmail>" + # mail.message_id = TMail.new_message_id + # mail.message_id #=> "<47404c5326d9c_2ad4fbb80161@baci.local.tmail>" + def message_id( default = nil ) + if h = @header['message-id'] + h.id || default + else + default + end + end + + # Destructively sets the message ID of the mail object instance to the passed in string + # + # Invalid message IDs are ignored (silently, unless configured otherwise) and result in + # a nil message ID. Left and right angle brackets are required. + # + # Example: + # + # mail = TMail::Mail.new + # mail.message_id = "<348F04F142D69C21-291E56D292BC@xxxx.net>" + # mail.message_id #=> "<348F04F142D69C21-291E56D292BC@xxxx.net>" + # mail.message_id = "this_is_my_badly_formatted_message_id" + # mail.message_id #=> nil + def message_id=( str ) + set_string_attr 'Message-Id', str + end + + # Returns the "In-Reply-To:" field contents as an array of this mail instance if it exists + # + # If the in_reply_to field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.in_reply_to #=> nil + # mail.in_reply_to([]) #=> [] + # TMail::Mail.load("../test/fixtures/raw_email_reply") + # mail.in_reply_to #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + def in_reply_to( default = nil ) + if h = @header['in-reply-to'] + h.ids + else + default + end + end + + # Destructively sets the value of the "In-Reply-To:" field of an email. + # + # Accepts an array of a single string of a message id + # + # Example: + # + # mail = TMail::Mail.new + # mail.in_reply_to = ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + # mail.in_reply_to #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + def in_reply_to=( *idstrs ) + set_string_array_attr 'In-Reply-To', idstrs + end + + # Returns the references of this email (prior messages relating to this message) + # as an array of message ID strings. Useful when you are trying to thread an + # email. + # + # If the references field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.references #=> nil + # mail.references([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email_reply") + # mail.references #=> ["<473FF3B8.9020707@xxx.org>", "<348F04F142D69C21-291E56D292BC@xxxx.net>"] + def references( default = nil ) + if h = @header['references'] + h.refs + else + default + end + end + + # Destructively sets the value of the "References:" field of an email. + # + # Accepts an array of strings of message IDs + # + # Example: + # + # mail = TMail::Mail.new + # mail.references = ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + # mail.references #=> ["<348F04F142D69C21-291E56D292BC@xxxx.net>"] + def references=( *strs ) + set_string_array_attr 'References', strs + end + + #== MIME header methods + + # Returns the listed MIME version of this email from the "Mime-Version:" header field + # + # If the mime_version field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.mime_version #=> nil + # mail.mime_version([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email") + # mail.mime_version #=> "1.0" + def mime_version( default = nil ) + if h = @header['mime-version'] + h.version || default + else + default + end + end + + def mime_version=( m, opt = nil ) + if opt + if h = @header['mime-version'] + h.major = m + h.minor = opt + else + store 'Mime-Version', "#{m}.#{opt}" + end + else + store 'Mime-Version', m + end + m + end + + # Returns the current "Content-Type" of the mail instance. + # + # If the content_type field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.content_type #=> nil + # mail.content_type([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email") + # mail.content_type #=> "text/plain" + def content_type( default = nil ) + if h = @header['content-type'] + h.content_type || default + else + default + end + end + + # Returns the current main type of the "Content-Type" of the mail instance. + # + # If the content_type field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.main_type #=> nil + # mail.main_type([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email") + # mail.main_type #=> "text" + def main_type( default = nil ) + if h = @header['content-type'] + h.main_type || default + else + default + end + end + + # Returns the current sub type of the "Content-Type" of the mail instance. + # + # If the content_type field does not exist, returns nil by default or you can pass in as + # the parameter for what you want the default value to be. + # + # Example: + # + # mail = TMail::Mail.new + # mail.sub_type #=> nil + # mail.sub_type([]) #=> [] + # mail = TMail::Mail.load("../test/fixtures/raw_email") + # mail.sub_type #=> "plain" + def sub_type( default = nil ) + if h = @header['content-type'] + h.sub_type || default + else + default + end + end + + # Destructively sets the "Content-Type:" header field of this mail object + # + # Allows you to set the main type, sub type as well as parameters to the field. + # The main type and sub type need to be a string. + # + # The optional params hash can be passed with keys as symbols and values as a string, + # or strings as keys and values. + # + # Example: + # + # mail = TMail::Mail.new + # mail.set_content_type("text", "plain") + # mail.to_s #=> "Content-Type: text/plain\n\n" + # + # mail.set_content_type("text", "plain", {:charset => "EUC-KR", :format => "flowed"}) + # mail.to_s #=> "Content-Type: text/plain; charset=EUC-KR; format=flowed\n\n" + # + # mail.set_content_type("text", "plain", {"charset" => "EUC-KR", "format" => "flowed"}) + # mail.to_s #=> "Content-Type: text/plain; charset=EUC-KR; format=flowed\n\n" + 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 + else + store 'Content-Type', "#{main}/#{sub}" + end + @header['content-type'].params.replace param if param + str + end + + alias content_type= set_content_type + + # Returns the named type parameter as a string, from the "Content-Type:" header. + # + # Example: + # + # mail = TMail::Mail.new + # mail.type_param("charset") #=> nil + # mail.type_param("charset", []) #=> [] + # mail.set_content_type("text", "plain", {:charset => "EUC-KR", :format => "flowed"}) + # mail.type_param("charset") #=> "EUC-KR" + # mail.type_param("format") #=> "flowed" + def type_param( name, default = nil ) + if h = @header['content-type'] + h[name] || default + else + default + end + end + + # Returns the character set of the email. Returns nil if no encoding set or returns + # whatever default you pass as a parameter - note passing the parameter does NOT change + # the mail object in any way. + # + # Example: + # + # mail = TMail::Mail.load("path_to/utf8_email") + # mail.charset #=> "UTF-8" + # + # mail = TMail::Mail.new + # mail.charset #=> nil + # mail.charset("US-ASCII") #=> "US-ASCII" + def charset( default = nil ) + if h = @header['content-type'] + h['charset'] or default + else + default + end + end + + # Destructively sets the character set used by this mail object to the passed string, you + # should note though that this does nothing to the mail body, just changes the header + # value, you will need to transliterate the body as well to match whatever you put + # in this header value if you are changing character sets. + # + # Example: + # + # mail = TMail::Mail.new + # mail.charset #=> nil + # mail.charset = "UTF-8" + # mail.charset #=> "UTF-8" + def charset=( str ) + if str + if h = @header[ 'content-type' ] + h['charset'] = str + else + store 'Content-Type', "text/plain; charset=#{str}" + end + end + str + end + + # Returns the transfer encoding of the email. Returns nil if no encoding set or returns + # whatever default you pass as a parameter - note passing the parameter does NOT change + # the mail object in any way. + # + # Example: + # + # mail = TMail::Mail.load("path_to/base64_encoded_email") + # mail.transfer_encoding #=> "base64" + # + # mail = TMail::Mail.new + # mail.transfer_encoding #=> nil + # mail.transfer_encoding("base64") #=> "base64" + def transfer_encoding( default = nil ) + if h = @header['content-transfer-encoding'] + h.encoding || default + else + default + end + end + + # Destructively sets the transfer encoding of the mail object to the passed string, you + # should note though that this does nothing to the mail body, just changes the header + # value, you will need to encode or decode the body as well to match whatever you put + # in this header value. + # + # Example: + # + # mail = TMail::Mail.new + # mail.transfer_encoding #=> nil + # mail.transfer_encoding = "base64" + # mail.transfer_encoding #=> "base64" + def transfer_encoding=( str ) + set_string_attr 'Content-Transfer-Encoding', str + end + + alias encoding transfer_encoding + alias encoding= transfer_encoding= + alias content_transfer_encoding transfer_encoding + alias content_transfer_encoding= transfer_encoding= + + # Returns the content-disposition of the mail object, returns nil or the passed + # default value if given + # + # Example: + # + # mail = TMail::Mail.load("path_to/raw_mail_with_attachment") + # mail.disposition #=> "attachment" + # + # mail = TMail::Mail.load("path_to/plain_simple_email") + # mail.disposition #=> nil + # mail.disposition(false) #=> false + def disposition( default = nil ) + if h = @header['content-disposition'] + h.disposition || default + else + default + end + end + + alias content_disposition disposition + + # Allows you to set the content-disposition of the mail object. Accepts a type + # and a hash of parameters. + # + # Example: + # + # mail.set_disposition("attachment", {:filename => "test.rb"}) + # mail.disposition #=> "attachment" + # mail['content-disposition'].to_s #=> "attachment; filename=test.rb" + def set_disposition( str, params = nil ) + if h = @header['content-disposition'] + h.disposition = str + h.params.clear + else + store('Content-Disposition', str) + h = @header['content-disposition'] + end + h.params.replace params if params + end + + alias disposition= set_disposition + alias set_content_disposition set_disposition + alias content_disposition= set_disposition + + # Returns the value of a parameter in an existing content-disposition header + # + # Example: + # + # mail.set_disposition("attachment", {:filename => "test.rb"}) + # mail['content-disposition'].to_s #=> "attachment; filename=test.rb" + # mail.disposition_param("filename") #=> "test.rb" + # mail.disposition_param("missing_param_key") #=> nil + # mail.disposition_param("missing_param_key", false) #=> false + # mail.disposition_param("missing_param_key", "Nothing to see here") #=> "Nothing to see here" + def disposition_param( name, default = nil ) + if h = @header['content-disposition'] + h[name] || default + else + default + end + end + + # Convert the Mail object's body into a Base64 encoded email + # returning the modified Mail object + def base64_encode! + store 'Content-Transfer-Encoding', 'Base64' + self.body = base64_encode + end + + # Return the result of encoding the TMail::Mail object body + # without altering the current body + def base64_encode + Base64.folding_encode(self.body) + end + + # Convert the Mail object's body into a Base64 decoded email + # returning the modified Mail object + def base64_decode! + if /base64/i === self.transfer_encoding('') + store 'Content-Transfer-Encoding', '8bit' + self.body = base64_decode + end + end + + # Returns the result of decoding the TMail::Mail object body + # without altering the current body + def base64_decode + Base64.decode(self.body, @config.strict_base64decode?) + end + + # Returns an array of each destination in the email message including to: cc: or bcc: + # + # Example: + # + # mail.to = "Mikel " + # mail.cc = "Trans " + # mail.bcc = "bob " + # mail.destinations #=> ["mikel@lindsaar.net", "t@t.com", "bob@me.com"] + def destinations( default = nil ) + ret = [] + %w( to cc bcc ).each do |nm| + if h = @header[nm] + h.addrs.each {|i| ret.push i.address } + end + end + ret.empty? ? default : ret + end + + # Yields a block of destination, yielding each as a string. + # (from the destinations example) + # mail.each_destination { |d| puts "#{d.class}: #{d}" } + # String: mikel@lindsaar.net + # String: t@t.com + # String: bob@me.com + def each_destination( &block ) + destinations([]).each do |i| + if Address === i + yield i + else + i.each(&block) + end + end + end + + alias each_dest each_destination + + # Returns an array of reply to addresses that the Mail object has, + # or if the Mail message has no reply-to, returns an array of the + # Mail objects from addresses. Else returns the default which can + # either be passed as a parameter or defaults to nil + # + # Example: + # mail.from = "Mikel " + # mail.reply_to = nil + # mail.reply_addresses #=> [""] + # + def reply_addresses( default = nil ) + reply_to_addrs(nil) or from_addrs(nil) or default + end + + # Returns the "sender" field as an array -> useful to find out who to + # send an error email to. + def error_reply_addresses( default = nil ) + if s = sender(nil) + [s] + else + from_addrs(default) + end + end + + # Returns true if the Mail object is a multipart message + def multipart? + main_type('').downcase == 'multipart' + end + + # Creates a new email in reply to self. Sets the In-Reply-To and + # References headers for you automagically. + # + # Example: + # mail = TMail::Mail.load("my_email") + # reply_email = mail.create_reply + # reply_email.class #=> TMail::Mail + # reply_email.references #=> [""] + # reply_email.in_reply_to #=> [""] + def create_reply + setup_reply create_empty_mail() + end + + # Creates a new email in reply to self. Sets the In-Reply-To and + # References headers for you automagically. + # + # Example: + # mail = TMail::Mail.load("my_email") + # forward_email = mail.create_forward + # forward_email.class #=> TMail::Mail + # forward_email.content_type #=> "multipart/mixed" + # forward_email.body #=> "Attachment: (unnamed)" + # forward_email.encoded #=> Returns the original email as a MIME attachment + def create_forward + setup_forward create_empty_mail() + end + + #:stopdoc: + private + + def create_empty_mail + self.class.new(StringPort.new(''), @config) + end + + def setup_reply( mail ) + if tmp = reply_addresses(nil) + mail.to_addrs = tmp + end + + mid = message_id(nil) + tmp = references(nil) || [] + tmp.push mid if mid + mail.in_reply_to = [mid] if mid + mail.references = tmp unless tmp.empty? + mail.subject = 'Re: ' + subject('').sub(/\A(?:\[[^\]]+\])?(?:\s*Re:)*\s*/i, '') + mail.mime_version = '1.0' + mail + end + + def setup_forward( mail ) + m = Mail.new(StringPort.new('')) + m.body = decoded + m.set_content_type 'message', 'rfc822' + m.encoding = encoding('7bit') + mail.parts.push m + # call encoded to reparse the message + mail.encoded + mail + end + + #:startdoc: + end # class Mail + +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/loader.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/loader.rb new file mode 100644 index 0000000000..6c0e251102 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/loader.rb @@ -0,0 +1,3 @@ +#:stopdoc: +require 'tmail/mailbox' +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb new file mode 100644 index 0000000000..5a319907ae --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mail.rb @@ -0,0 +1,578 @@ +=begin rdoc + += Mail class + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + + + +require 'tmail/interface' +require 'tmail/encode' +require 'tmail/header' +require 'tmail/port' +require 'tmail/config' +require 'tmail/utils' +require 'tmail/attachments' +require 'tmail/quoting' +require 'socket' + +module TMail + + # == Mail Class + # + # Accessing a TMail object done via the TMail::Mail class. As email can be fairly complex + # creatures, you will find a large amount of accessor and setter methods in this class! + # + # Most of the below methods handle the header, in fact, what TMail does best is handle the + # header of the email object. There are only a few methods that deal directly with the body + # of the email, such as base64_encode and base64_decode. + # + # === Using TMail inside your code + # + # The usual way is to install the gem (see the {README}[link:/README] on how to do this) and + # then put at the top of your class: + # + # require 'tmail' + # + # You can then create a new TMail object in your code with: + # + # @email = TMail::Mail.new + # + # Or if you have an email as a string, you can initialize a new TMail::Mail object and get it + # to parse that string for you like so: + # + # @email = TMail::Mail.parse(email_text) + # + # You can also read a single email off the disk, for example: + # + # @email = TMail::Mail.load('filename.txt') + # + # Also, you can read a mailbox (usual unix mbox format) and end up with an array of TMail + # objects by doing something like this: + # + # # Note, we pass true as the last variable to open the mailbox read only + # mailbox = TMail::UNIXMbox.new("mailbox", nil, true) + # @emails = [] + # mailbox.each_port { |m| @emails << TMail::Mail.new(m) } + # + class Mail + + class << self + + # Opens an email that has been saved out as a file by itself. + # + # This function will read a file non-destructively and then parse + # the contents and return a TMail::Mail object. + # + # Does not handle multiple email mailboxes (like a unix mbox) for that + # use the TMail::UNIXMbox class. + # + # Example: + # mail = TMail::Mail.load('filename') + # + def load( fname ) + new(FilePort.new(fname)) + end + + alias load_from load + alias loadfrom load + + # Parses an email from the supplied string and returns a TMail::Mail + # object. + # + # Example: + # require 'rubygems'; require 'tmail' + # email_string =< # bodyport=nil> + # mail.body + # #=> "Hello there Mikel!\n\n" + def parse( str ) + new(StringPort.new(str)) + end + + end + + def initialize( port = nil, conf = DEFAULT_CONFIG ) #:nodoc: + @port = port || StringPort.new + @config = Config.to_config(conf) + + @header = {} + @body_port = nil + @body_parsed = false + @epilogue = '' + @parts = [] + + @port.ropen {|f| + parse_header f + parse_body f unless @port.reproducible? + } + end + + # Provides access to the port this email is using to hold it's data + # + # Example: + # mail = TMail::Mail.parse(email_string) + # mail.port + # #=> # + attr_reader :port + + def inspect + "\#<#{self.class} port=#{@port.inspect} bodyport=#{@body_port.inspect}>" + end + + # + # to_s interfaces + # + + public + + include StrategyInterface + + def write_back( eol = "\n", charset = 'e' ) + parse_body + @port.wopen {|stream| encoded eol, charset, stream } + end + + def accept( strategy ) + with_multipart_encoding(strategy) { + ordered_each do |name, field| + next if field.empty? + strategy.header_name canonical(name) + field.accept strategy + strategy.puts + end + strategy.puts + body_port().ropen {|r| + strategy.write r.read + } + } + end + + private + + def canonical( name ) + name.split(/-/).map {|s| s.capitalize }.join('-') + end + + def with_multipart_encoding( strategy ) + if parts().empty? # DO NOT USE @parts + yield + + else + bound = ::TMail.new_boundary + if @header.key? 'content-type' + @header['content-type'].params['boundary'] = bound + else + store 'Content-Type', % + end + + yield + + parts().each do |tm| + strategy.puts + strategy.puts '--' + bound + tm.accept strategy + end + strategy.puts + strategy.puts '--' + bound + '--' + strategy.write epilogue() + end + end + + ### + ### header + ### + + public + + ALLOW_MULTIPLE = { + 'received' => true, + 'resent-date' => true, + 'resent-from' => true, + 'resent-sender' => true, + 'resent-to' => true, + 'resent-cc' => true, + 'resent-bcc' => true, + 'resent-message-id' => true, + 'comments' => true, + 'keywords' => true + } + USE_ARRAY = ALLOW_MULTIPLE + + def header + @header.dup + end + + # Returns a TMail::AddressHeader object of the field you are querying. + # Examples: + # @mail['from'] #=> # + # @mail['to'] #=> # + # + # You can get the string value of this by passing "to_s" to the query: + # Example: + # @mail['to'].to_s #=> "mikel@test.com.au" + def []( key ) + @header[key.downcase] + end + + def sub_header(key, param) + (hdr = self[key]) ? hdr[param] : nil + end + + alias fetch [] + + # Allows you to set or delete TMail header objects at will. + # Eamples: + # @mail = TMail::Mail.new + # @mail['to'].to_s # => 'mikel@test.com.au' + # @mail['to'] = 'mikel@elsewhere.org' + # @mail['to'].to_s # => 'mikel@elsewhere.org' + # @mail.encoded # => "To: mikel@elsewhere.org\r\n\r\n" + # @mail['to'] = nil + # @mail['to'].to_s # => nil + # @mail.encoded # => "\r\n" + # + # Note: setting mail[] = nil actualy deletes the header field in question from the object, + # it does not just set the value of the hash to nil + def []=( key, val ) + dkey = key.downcase + + if val.nil? + @header.delete dkey + return nil + end + + case val + when String + header = new_hf(key, val) + when HeaderField + ; + when Array + ALLOW_MULTIPLE.include? dkey or + raise ArgumentError, "#{key}: Header must not be multiple" + @header[dkey] = val + return val + else + header = new_hf(key, val.to_s) + end + if ALLOW_MULTIPLE.include? dkey + (@header[dkey] ||= []).push header + else + @header[dkey] = header + end + + val + end + + alias store []= + + # Allows you to loop through each header in the TMail::Mail object in a block + # Example: + # @mail['to'] = 'mikel@elsewhere.org' + # @mail['from'] = 'me@me.com' + # @mail.each_header { |k,v| puts "#{k} = #{v}" } + # # => from = me@me.com + # # => to = mikel@elsewhere.org + def each_header + @header.each do |key, val| + [val].flatten.each {|v| yield key, v } + end + end + + alias each_pair each_header + + def each_header_name( &block ) + @header.each_key(&block) + end + + alias each_key each_header_name + + def each_field( &block ) + @header.values.flatten.each(&block) + end + + alias each_value each_field + + FIELD_ORDER = %w( + return-path received + resent-date resent-from resent-sender resent-to + resent-cc resent-bcc resent-message-id + date from sender reply-to to cc bcc + message-id in-reply-to references + subject comments keywords + mime-version content-type content-transfer-encoding + content-disposition content-description + ) + + def ordered_each + list = @header.keys + FIELD_ORDER.each do |name| + if list.delete(name) + [@header[name]].flatten.each {|v| yield name, v } + end + end + list.each do |name| + [@header[name]].flatten.each {|v| yield name, v } + end + end + + def clear + @header.clear + end + + def delete( key ) + @header.delete key.downcase + end + + def delete_if + @header.delete_if do |key,val| + if Array === val + val.delete_if {|v| yield key, v } + val.empty? + else + yield key, val + end + end + end + + def keys + @header.keys + end + + def key?( key ) + @header.key? key.downcase + end + + def values_at( *args ) + args.map {|k| @header[k.downcase] }.flatten + end + + alias indexes values_at + alias indices values_at + + private + + def parse_header( f ) + name = field = nil + unixfrom = nil + + while line = f.gets + case line + when /\A[ \t]/ # continue from prev line + raise SyntaxError, 'mail is began by space' unless field + field << ' ' << line.strip + + when /\A([^\: \t]+):\s*/ # new header line + add_hf name, field if field + name = $1 + field = $' #.strip + + when /\A\-*\s*\z/ # end of header + add_hf name, field if field + name = field = nil + break + + when /\AFrom (\S+)/ + unixfrom = $1 + + when /^charset=.*/ + + else + raise SyntaxError, "wrong mail header: '#{line.inspect}'" + end + end + add_hf name, field if name + + if unixfrom + add_hf 'Return-Path', "<#{unixfrom}>" unless @header['return-path'] + end + end + + def add_hf( name, field ) + key = name.downcase + field = new_hf(name, field) + + if ALLOW_MULTIPLE.include? key + (@header[key] ||= []).push field + else + @header[key] = field + end + end + + def new_hf( name, field ) + HeaderField.new(name, field, @config) + end + + ### + ### body + ### + + public + + def body_port + parse_body + @body_port + end + + def each( &block ) + body_port().ropen {|f| f.each(&block) } + end + + def quoted_body + body_port.ropen {|f| return f.read } + end + + def quoted_body= str + body_port.wopen { |f| f.write str } + str + end + + def body=( str ) + # Sets the body of the email to a new (encoded) string. + # + # We also reparses the email if the body is ever reassigned, this is a performance hit, however when + # you assign the body, you usually want to be able to make sure that you can access the attachments etc. + # + # Usage: + # + # mail.body = "Hello, this is\nthe body text" + # # => "Hello, this is\nthe body" + # mail.body + # # => "Hello, this is\nthe body" + @body_parsed = false + parse_body(StringInput.new(str)) + parse_body + @body_port.wopen {|f| f.write str } + str + end + + alias preamble quoted_body + alias preamble= quoted_body= + + def epilogue + parse_body + @epilogue.dup + end + + def epilogue=( str ) + parse_body + @epilogue = str + str + end + + def parts + parse_body + @parts + end + + def each_part( &block ) + parts().each(&block) + end + + # Returns true if the content type of this part of the email is + # a disposition attachment + def disposition_is_attachment? + (self['content-disposition'] && self['content-disposition'].disposition == "attachment") + end + + # Returns true if this part's content main type is text, else returns false. + # By main type is meant "text/plain" is text. "text/html" is text + def content_type_is_text? + self.header['content-type'] && (self.header['content-type'].main_type != "text") + end + + private + + def parse_body( f = nil ) + return if @body_parsed + if f + parse_body_0 f + else + @port.ropen {|f| + skip_header f + parse_body_0 f + } + end + @body_parsed = true + end + + def skip_header( f ) + while line = f.gets + return if /\A[\r\n]*\z/ === line + end + end + + def parse_body_0( f ) + if multipart? + read_multipart f + else + @body_port = @config.new_body_port(self) + @body_port.wopen {|w| + w.write f.read + } + end + end + + def read_multipart( src ) + bound = @header['content-type'].params['boundary'] + is_sep = /\A--#{Regexp.quote bound}(?:--)?[ \t]*(?:\n|\r\n|\r)/ + lastbound = "--#{bound}--" + + ports = [ @config.new_preamble_port(self) ] + begin + f = ports.last.wopen + while line = src.gets + if is_sep === line + f.close + break if line.strip == lastbound + ports.push @config.new_part_port(self) + f = ports.last.wopen + else + f << line + end + end + @epilogue = (src.read || '') + ensure + f.close if f and not f.closed? + end + + @body_port = ports.shift + @parts = ports.map {|p| self.class.new(p, @config) } + end + + end # class Mail + +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mailbox.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mailbox.rb new file mode 100644 index 0000000000..b0bc6a7f74 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mailbox.rb @@ -0,0 +1,495 @@ +=begin rdoc + += Mailbox and Mbox interaction class + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +require 'tmail/port' +require 'socket' +require 'mutex_m' + + +unless [].respond_to?(:sort_by) +module Enumerable#:nodoc: + def sort_by + map {|i| [yield(i), i] }.sort {|a,b| a.first <=> b.first }.map {|i| i[1] } + end +end +end + + +module TMail + + class MhMailbox + + PORT_CLASS = MhPort + + def initialize( dir ) + edir = File.expand_path(dir) + raise ArgumentError, "not directory: #{dir}"\ + unless FileTest.directory? edir + @dirname = edir + @last_file = nil + @last_atime = nil + end + + def directory + @dirname + end + + alias dirname directory + + attr_accessor :last_atime + + def inspect + "#<#{self.class} #{@dirname}>" + end + + def close + end + + def new_port + PORT_CLASS.new(next_file_name()) + end + + def each_port + mail_files().each do |path| + yield PORT_CLASS.new(path) + end + @last_atime = Time.now + end + + alias each each_port + + def reverse_each_port + mail_files().reverse_each do |path| + yield PORT_CLASS.new(path) + end + @last_atime = Time.now + end + + alias reverse_each reverse_each_port + + # old #each_mail returns Port + #def each_mail + # each_port do |port| + # yield Mail.new(port) + # end + #end + + def each_new_port( mtime = nil, &block ) + mtime ||= @last_atime + return each_port(&block) unless mtime + return unless File.mtime(@dirname) >= mtime + + mail_files().each do |path| + yield PORT_CLASS.new(path) if File.mtime(path) > mtime + end + @last_atime = Time.now + end + + private + + def mail_files + Dir.entries(@dirname)\ + .select {|s| /\A\d+\z/ === s }\ + .map {|s| s.to_i }\ + .sort\ + .map {|i| "#{@dirname}/#{i}" }\ + .select {|path| FileTest.file? path } + end + + def next_file_name + unless n = @last_file + n = 0 + Dir.entries(@dirname)\ + .select {|s| /\A\d+\z/ === s }\ + .map {|s| s.to_i }.sort\ + .each do |i| + next unless FileTest.file? "#{@dirname}/#{i}" + n = i + end + end + begin + n += 1 + end while FileTest.exist? "#{@dirname}/#{n}" + @last_file = n + + "#{@dirname}/#{n}" + end + + end # MhMailbox + + MhLoader = MhMailbox + + + class UNIXMbox + + class << self + alias newobj new + end + + # Creates a new mailbox object that you can iterate through to collect the + # emails from with "each_port". + # + # You need to pass it a filename of a unix mailbox format file, the format of this + # file can be researched at this page at {wikipedia}[link:http://en.wikipedia.org/wiki/Mbox] + # + # ==== Parameters + # + # +filename+: The filename of the mailbox you want to open + # + # +tmpdir+: Can be set to override TMail using the system environment's temp dir. TMail will first + # use the temp dir specified by you (if any) or then the temp dir specified in the Environment's TEMP + # value then the value in the Environment's TMP value or failing all of the above, '/tmp' + # + # +readonly+: If set to false, each email you take from the mail box will be removed from the mailbox. + # default is *false* - ie, it *WILL* truncate your mailbox file to ZERO once it has read the emails out. + # + # ==== Options: + # + # None + # + # ==== Examples: + # + # # First show using readonly true: + # + # require 'ftools' + # File.size("../test/fixtures/mailbox") + # #=> 20426 + # + # mailbox = TMail::UNIXMbox.new("../test/fixtures/mailbox", nil, true) + # #=> # + # + # mailbox.each_port do |port| + # mail = TMail::Mail.new(port) + # puts mail.subject + # end + # #Testing mailbox 1 + # #Testing mailbox 2 + # #Testing mailbox 3 + # #Testing mailbox 4 + # require 'ftools' + # File.size?("../test/fixtures/mailbox") + # #=> 20426 + # + # # Now show with readonly set to the default false + # + # mailbox = TMail::UNIXMbox.new("../test/fixtures/mailbox") + # #=> # + # + # mailbox.each_port do |port| + # mail = TMail::Mail.new(port) + # puts mail.subject + # end + # #Testing mailbox 1 + # #Testing mailbox 2 + # #Testing mailbox 3 + # #Testing mailbox 4 + # + # File.size?("../test/fixtures/mailbox") + # #=> nil + def UNIXMbox.new( filename, tmpdir = nil, readonly = false ) + tmpdir = ENV['TEMP'] || ENV['TMP'] || '/tmp' + newobj(filename, "#{tmpdir}/ruby_tmail_#{$$}_#{rand()}", readonly, false) + end + + def UNIXMbox.lock( fname ) + begin + f = File.open(fname, 'r+') + f.flock File::LOCK_EX + yield f + ensure + f.flock File::LOCK_UN + f.close if f and not f.closed? + end + end + + def UNIXMbox.static_new( fname, dir, readonly = false ) + newobj(fname, dir, readonly, true) + end + + def initialize( fname, mhdir, readonly, static ) + @filename = fname + @readonly = readonly + @closed = false + + Dir.mkdir mhdir + @real = MhMailbox.new(mhdir) + @finalizer = UNIXMbox.mkfinal(@real, @filename, !@readonly, !static) + ObjectSpace.define_finalizer self, @finalizer + end + + def UNIXMbox.mkfinal( mh, mboxfile, writeback_p, cleanup_p ) + lambda { + if writeback_p + lock(mboxfile) {|f| + mh.each_port do |port| + f.puts create_from_line(port) + port.ropen {|r| + f.puts r.read + } + end + } + end + if cleanup_p + Dir.foreach(mh.dirname) do |fname| + next if /\A\.\.?\z/ === fname + File.unlink "#{mh.dirname}/#{fname}" + end + Dir.rmdir mh.dirname + end + } + end + + # make _From line + def UNIXMbox.create_from_line( port ) + sprintf 'From %s %s', + fromaddr(), TextUtils.time2str(File.mtime(port.filename)) + end + + def UNIXMbox.fromaddr(port) + h = HeaderField.new_from_port(port, 'Return-Path') || + HeaderField.new_from_port(port, 'From') || + HeaderField.new_from_port(port, 'EnvelopeSender') or return 'nobody' + a = h.addrs[0] or return 'nobody' + a.spec + end + + def close + return if @closed + + ObjectSpace.undefine_finalizer self + @finalizer.call + @finalizer = nil + @real = nil + @closed = true + @updated = nil + end + + def each_port( &block ) + close_check + update + @real.each_port(&block) + end + + alias each each_port + + def reverse_each_port( &block ) + close_check + update + @real.reverse_each_port(&block) + end + + alias reverse_each reverse_each_port + + # old #each_mail returns Port + #def each_mail( &block ) + # each_port do |port| + # yield Mail.new(port) + # end + #end + + def each_new_port( mtime = nil ) + close_check + update + @real.each_new_port(mtime) {|p| yield p } + end + + def new_port + close_check + @real.new_port + end + + private + + def close_check + @closed and raise ArgumentError, 'accessing already closed mbox' + end + + def update + return if FileTest.zero?(@filename) + return if @updated and File.mtime(@filename) < @updated + w = nil + port = nil + time = nil + UNIXMbox.lock(@filename) {|f| + begin + f.each do |line| + if /\AFrom / === line + w.close if w + File.utime time, time, port.filename if time + + port = @real.new_port + w = port.wopen + time = fromline2time(line) + else + w.print line if w + end + end + ensure + if w and not w.closed? + w.close + File.utime time, time, port.filename if time + end + end + f.truncate(0) unless @readonly + @updated = Time.now + } + end + + def fromline2time( line ) + m = /\AFrom \S+ \w+ (\w+) (\d+) (\d+):(\d+):(\d+) (\d+)/.match(line) \ + or return nil + Time.local(m[6].to_i, m[1], m[2].to_i, m[3].to_i, m[4].to_i, m[5].to_i) + end + + end # UNIXMbox + + MboxLoader = UNIXMbox + + + class Maildir + + extend Mutex_m + + PORT_CLASS = MaildirPort + + @seq = 0 + def Maildir.unique_number + synchronize { + @seq += 1 + return @seq + } + end + + def initialize( dir = nil ) + @dirname = dir || ENV['MAILDIR'] + raise ArgumentError, "not directory: #{@dirname}"\ + unless FileTest.directory? @dirname + @new = "#{@dirname}/new" + @tmp = "#{@dirname}/tmp" + @cur = "#{@dirname}/cur" + end + + def directory + @dirname + end + + def inspect + "#<#{self.class} #{@dirname}>" + end + + def close + end + + def each_port + mail_files(@cur).each do |path| + yield PORT_CLASS.new(path) + end + end + + alias each each_port + + def reverse_each_port + mail_files(@cur).reverse_each do |path| + yield PORT_CLASS.new(path) + end + end + + alias reverse_each reverse_each_port + + def new_port + fname = nil + tmpfname = nil + newfname = nil + + begin + fname = "#{Time.now.to_i}.#{$$}_#{Maildir.unique_number}.#{Socket.gethostname}" + + tmpfname = "#{@tmp}/#{fname}" + newfname = "#{@new}/#{fname}" + end while FileTest.exist? tmpfname + + if block_given? + File.open(tmpfname, 'w') {|f| yield f } + File.rename tmpfname, newfname + PORT_CLASS.new(newfname) + else + File.open(tmpfname, 'w') {|f| f.write "\n\n" } + PORT_CLASS.new(tmpfname) + end + end + + def each_new_port + mail_files(@new).each do |path| + dest = @cur + '/' + File.basename(path) + File.rename path, dest + yield PORT_CLASS.new(dest) + end + + check_tmp + end + + TOO_OLD = 60 * 60 * 36 # 36 hour + + def check_tmp + old = Time.now.to_i - TOO_OLD + + each_filename(@tmp) do |full, fname| + if FileTest.file? full and + File.stat(full).mtime.to_i < old + File.unlink full + end + end + end + + private + + def mail_files( dir ) + Dir.entries(dir)\ + .select {|s| s[0] != ?. }\ + .sort_by {|s| s.slice(/\A\d+/).to_i }\ + .map {|s| "#{dir}/#{s}" }\ + .select {|path| FileTest.file? path } + end + + def each_filename( dir ) + Dir.foreach(dir) do |fname| + path = "#{dir}/#{fname}" + if fname[0] != ?. and FileTest.file? path + yield path, fname + end + end + end + + end # Maildir + + MaildirLoader = Maildir + +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/main.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/main.rb new file mode 100644 index 0000000000..e52772793f --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/main.rb @@ -0,0 +1,6 @@ +#:stopdoc: +require 'tmail/version' +require 'tmail/mail' +require 'tmail/mailbox' +require 'tmail/core_extensions' +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb new file mode 100644 index 0000000000..6c0e251102 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/mbox.rb @@ -0,0 +1,3 @@ +#:stopdoc: +require 'tmail/mailbox' +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/net.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/net.rb new file mode 100644 index 0000000000..65147228a1 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/net.rb @@ -0,0 +1,248 @@ +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +#:stopdoc: +require 'nkf' +#:startdoc: + +module TMail + + class Mail + + def send_to( smtp ) + do_send_to(smtp) do + ready_to_send + end + end + + def send_text_to( smtp ) + do_send_to(smtp) do + ready_to_send + mime_encode + end + end + + def do_send_to( smtp ) + from = from_address or raise ArgumentError, 'no from address' + (dests = destinations).empty? and raise ArgumentError, 'no receipient' + yield + send_to_0 smtp, from, dests + end + private :do_send_to + + def send_to_0( smtp, from, to ) + smtp.ready(from, to) do |f| + encoded "\r\n", 'j', f, '' + end + end + + def ready_to_send + delete_no_send_fields + add_message_id + add_date + end + + NOSEND_FIELDS = %w( + received + bcc + ) + + def delete_no_send_fields + NOSEND_FIELDS.each do |nm| + delete nm + end + delete_if {|n,v| v.empty? } + end + + def add_message_id( fqdn = nil ) + self.message_id = ::TMail::new_message_id(fqdn) + end + + def add_date + self.date = Time.now + end + + def mime_encode + if parts.empty? + mime_encode_singlepart + else + mime_encode_multipart true + end + end + + def mime_encode_singlepart + self.mime_version = '1.0' + b = body + if NKF.guess(b) != NKF::BINARY + mime_encode_text b + else + mime_encode_binary b + end + end + + def mime_encode_text( body ) + self.body = NKF.nkf('-j -m0', body) + self.set_content_type 'text', 'plain', {'charset' => 'iso-2022-jp'} + self.encoding = '7bit' + end + + def mime_encode_binary( body ) + self.body = [body].pack('m') + self.set_content_type 'application', 'octet-stream' + self.encoding = 'Base64' + end + + def mime_encode_multipart( top = true ) + self.mime_version = '1.0' if top + self.set_content_type 'multipart', 'mixed' + e = encoding(nil) + if e and not /\A(?:7bit|8bit|binary)\z/i === e + raise ArgumentError, + 'using C.T.Encoding with multipart mail is not permitted' + end + end + + end + + #:stopdoc: + class DeleteFields + + NOSEND_FIELDS = %w( + received + bcc + ) + + def initialize( nosend = nil, delempty = true ) + @no_send_fields = nosend || NOSEND_FIELDS.dup + @delete_empty_fields = delempty + end + + attr :no_send_fields + attr :delete_empty_fields, true + + def exec( mail ) + @no_send_fields.each do |nm| + delete nm + end + delete_if {|n,v| v.empty? } if @delete_empty_fields + end + + end + #:startdoc: + + #:stopdoc: + class AddMessageId + + def initialize( fqdn = nil ) + @fqdn = fqdn + end + + attr :fqdn, true + + def exec( mail ) + mail.message_id = ::TMail::new_msgid(@fqdn) + end + + end + #:startdoc: + + #:stopdoc: + class AddDate + + def exec( mail ) + mail.date = Time.now + end + + end + #:startdoc: + + #:stopdoc: + class MimeEncodeAuto + + def initialize( s = nil, m = nil ) + @singlepart_composer = s || MimeEncodeSingle.new + @multipart_composer = m || MimeEncodeMulti.new + end + + attr :singlepart_composer + attr :multipart_composer + + def exec( mail ) + if mail._builtin_multipart? + then @multipart_composer + else @singlepart_composer end.exec mail + end + + end + #:startdoc: + + #:stopdoc: + class MimeEncodeSingle + + def exec( mail ) + mail.mime_version = '1.0' + b = mail.body + if NKF.guess(b) != NKF::BINARY + on_text b + else + on_binary b + end + end + + def on_text( body ) + mail.body = NKF.nkf('-j -m0', body) + mail.set_content_type 'text', 'plain', {'charset' => 'iso-2022-jp'} + mail.encoding = '7bit' + end + + def on_binary( body ) + mail.body = [body].pack('m') + mail.set_content_type 'application', 'octet-stream' + mail.encoding = 'Base64' + end + + end + #:startdoc: + + #:stopdoc: + class MimeEncodeMulti + + def exec( mail, top = true ) + mail.mime_version = '1.0' if top + mail.set_content_type 'multipart', 'mixed' + e = encoding(nil) + if e and not /\A(?:7bit|8bit|binary)\z/i === e + raise ArgumentError, + 'using C.T.Encoding with multipart mail is not permitted' + end + mail.parts.each do |m| + exec m, false if m._builtin_multipart? + end + end + + end + #:startdoc: +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/obsolete.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/obsolete.rb new file mode 100644 index 0000000000..22b0a126ca --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/obsolete.rb @@ -0,0 +1,132 @@ +=begin rdoc + += Obsolete methods that are depriciated + +If you really want to see them, go to lib/tmail/obsolete.rb and view to your +heart's content. + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ +#:stopdoc: +module TMail #:nodoc: + + class Mail + alias include? key? + alias has_key? key? + + def values + ret = [] + each_field {|v| ret.push v } + ret + end + + def value?( val ) + HeaderField === val or return false + + [ @header[val.name.downcase] ].flatten.include? val + end + + alias has_value? value? + end + + class Mail + def from_addr( default = nil ) + addr, = from_addrs(nil) + addr || default + end + + def from_address( default = nil ) + if a = from_addr(nil) + a.spec + else + default + end + end + + alias from_address= from_addrs= + + def from_phrase( default = nil ) + if a = from_addr(nil) + a.phrase + else + default + end + end + + alias msgid message_id + alias msgid= message_id= + + alias each_dest each_destination + end + + class Address + alias route routes + alias addr spec + + def spec=( str ) + @local, @domain = str.split(/@/,2).map {|s| s.split(/\./) } + end + + alias addr= spec= + alias address= spec= + end + + class MhMailbox + alias new_mail new_port + alias each_mail each_port + alias each_newmail each_new_port + end + class UNIXMbox + alias new_mail new_port + alias each_mail each_port + alias each_newmail each_new_port + end + class Maildir + alias new_mail new_port + alias each_mail each_port + alias each_newmail each_new_port + end + + extend TextUtils + + class << self + alias msgid? message_id? + alias boundary new_boundary + alias msgid new_message_id + alias new_msgid new_message_id + end + + def Mail.boundary + ::TMail.new_boundary + end + + def Mail.msgid + ::TMail.new_message_id + end + +end # module TMail +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/parser.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/parser.rb new file mode 100644 index 0000000000..ab1a828471 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/parser.rb @@ -0,0 +1,1476 @@ +#:stopdoc: +# DO NOT MODIFY!!!! +# This file is automatically generated by racc 1.4.5 +# from racc grammer file "parser.y". +# +# +# parser.rb: generated by racc (runtime embedded) +# +###### racc/parser.rb begin +unless $".index 'racc/parser.rb' +$".push 'racc/parser.rb' + +self.class.module_eval <<'..end racc/parser.rb modeval..id8076474214', 'racc/parser.rb', 1 +# +# $Id: parser.rb,v 1.7 2005/11/20 17:31:32 aamine Exp $ +# +# Copyright (c) 1999-2005 Minero Aoki +# +# This program is free software. +# You can distribute/modify this program under the same terms of ruby. +# +# As a special exception, when this code is copied by Racc +# into a Racc output file, you may use that output file +# without restriction. +# + +unless defined?(NotImplementedError) + NotImplementedError = NotImplementError +end + +module Racc + class ParseError < StandardError; end +end +unless defined?(::ParseError) + ParseError = Racc::ParseError +end + +module Racc + + unless defined?(Racc_No_Extentions) + Racc_No_Extentions = false + end + + class Parser + + Racc_Runtime_Version = '1.4.5' + Racc_Runtime_Revision = '$Revision: 1.7 $'.split[1] + + Racc_Runtime_Core_Version_R = '1.4.5' + Racc_Runtime_Core_Revision_R = '$Revision: 1.7 $'.split[1] + begin + require 'racc/cparse' + # Racc_Runtime_Core_Version_C = (defined in extention) + Racc_Runtime_Core_Revision_C = Racc_Runtime_Core_Id_C.split[2] + unless new.respond_to?(:_racc_do_parse_c, true) + raise LoadError, 'old cparse.so' + end + if Racc_No_Extentions + raise LoadError, 'selecting ruby version of racc runtime core' + end + + Racc_Main_Parsing_Routine = :_racc_do_parse_c + Racc_YY_Parse_Method = :_racc_yyparse_c + Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_C + Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_C + Racc_Runtime_Type = 'c' + rescue LoadError + Racc_Main_Parsing_Routine = :_racc_do_parse_rb + Racc_YY_Parse_Method = :_racc_yyparse_rb + Racc_Runtime_Core_Version = Racc_Runtime_Core_Version_R + Racc_Runtime_Core_Revision = Racc_Runtime_Core_Revision_R + Racc_Runtime_Type = 'ruby' + end + + def Parser.racc_runtime_type + Racc_Runtime_Type + end + + private + + def _racc_setup + @yydebug = false unless self.class::Racc_debug_parser + @yydebug = false unless defined?(@yydebug) + if @yydebug + @racc_debug_out = $stderr unless defined?(@racc_debug_out) + @racc_debug_out ||= $stderr + end + arg = self.class::Racc_arg + arg[13] = true if arg.size < 14 + arg + end + + def _racc_init_sysvars + @racc_state = [0] + @racc_tstack = [] + @racc_vstack = [] + + @racc_t = nil + @racc_val = nil + + @racc_read_next = true + + @racc_user_yyerror = false + @racc_error_status = 0 + end + + ### + ### do_parse + ### + + def do_parse + __send__(Racc_Main_Parsing_Routine, _racc_setup(), false) + end + + def next_token + raise NotImplementedError, "#{self.class}\#next_token is not defined" + end + + def _racc_do_parse_rb(arg, in_debug) + action_table, action_check, action_default, action_pointer, + goto_table, goto_check, goto_default, goto_pointer, + nt_base, reduce_table, token_table, shift_n, + reduce_n, use_result, * = arg + + _racc_init_sysvars + tok = act = i = nil + nerr = 0 + + catch(:racc_end_parse) { + while true + if i = action_pointer[@racc_state[-1]] + if @racc_read_next + if @racc_t != 0 # not EOF + tok, @racc_val = next_token() + unless tok # EOF + @racc_t = 0 + else + @racc_t = (token_table[tok] or 1) # error token + end + racc_read_token(@racc_t, tok, @racc_val) if @yydebug + @racc_read_next = false + end + end + i += @racc_t + unless i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] + end + else + act = action_default[@racc_state[-1]] + end + while act = _racc_evalact(act, arg) + ; + end + end + } + end + + ### + ### yyparse + ### + + def yyparse(recv, mid) + __send__(Racc_YY_Parse_Method, recv, mid, _racc_setup(), true) + end + + def _racc_yyparse_rb(recv, mid, arg, c_debug) + action_table, action_check, action_default, action_pointer, + goto_table, goto_check, goto_default, goto_pointer, + nt_base, reduce_table, token_table, shift_n, + reduce_n, use_result, * = arg + + _racc_init_sysvars + tok = nil + act = nil + i = nil + nerr = 0 + + catch(:racc_end_parse) { + until i = action_pointer[@racc_state[-1]] + while act = _racc_evalact(action_default[@racc_state[-1]], arg) + ; + end + end + recv.__send__(mid) do |tok, val| + unless tok + @racc_t = 0 + else + @racc_t = (token_table[tok] or 1) # error token + end + @racc_val = val + @racc_read_next = false + + i += @racc_t + unless i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] + end + while act = _racc_evalact(act, arg) + ; + end + + while not (i = action_pointer[@racc_state[-1]]) or + not @racc_read_next or + @racc_t == 0 # $ + unless i and i += @racc_t and + i >= 0 and + act = action_table[i] and + action_check[i] == @racc_state[-1] + act = action_default[@racc_state[-1]] + end + while act = _racc_evalact(act, arg) + ; + end + end + end + } + end + + ### + ### common + ### + + def _racc_evalact(act, arg) + action_table, action_check, action_default, action_pointer, + goto_table, goto_check, goto_default, goto_pointer, + nt_base, reduce_table, token_table, shift_n, + reduce_n, use_result, * = arg + nerr = 0 # tmp + + if act > 0 and act < shift_n + # + # shift + # + if @racc_error_status > 0 + @racc_error_status -= 1 unless @racc_t == 1 # error token + end + @racc_vstack.push @racc_val + @racc_state.push act + @racc_read_next = true + if @yydebug + @racc_tstack.push @racc_t + racc_shift @racc_t, @racc_tstack, @racc_vstack + end + + elsif act < 0 and act > -reduce_n + # + # reduce + # + code = catch(:racc_jump) { + @racc_state.push _racc_do_reduce(arg, act) + false + } + if code + case code + when 1 # yyerror + @racc_user_yyerror = true # user_yyerror + return -reduce_n + when 2 # yyaccept + return shift_n + else + raise '[Racc Bug] unknown jump code' + end + end + + elsif act == shift_n + # + # accept + # + racc_accept if @yydebug + throw :racc_end_parse, @racc_vstack[0] + + elsif act == -reduce_n + # + # error + # + case @racc_error_status + when 0 + unless arg[21] # user_yyerror + nerr += 1 + on_error @racc_t, @racc_val, @racc_vstack + end + when 3 + if @racc_t == 0 # is $ + throw :racc_end_parse, nil + end + @racc_read_next = true + end + @racc_user_yyerror = false + @racc_error_status = 3 + while true + if i = action_pointer[@racc_state[-1]] + i += 1 # error token + if i >= 0 and + (act = action_table[i]) and + action_check[i] == @racc_state[-1] + break + end + end + throw :racc_end_parse, nil if @racc_state.size <= 1 + @racc_state.pop + @racc_vstack.pop + if @yydebug + @racc_tstack.pop + racc_e_pop @racc_state, @racc_tstack, @racc_vstack + end + end + return act + + else + raise "[Racc Bug] unknown action #{act.inspect}" + end + + racc_next_state(@racc_state[-1], @racc_state) if @yydebug + + nil + end + + def _racc_do_reduce(arg, act) + action_table, action_check, action_default, action_pointer, + goto_table, goto_check, goto_default, goto_pointer, + nt_base, reduce_table, token_table, shift_n, + reduce_n, use_result, * = arg + state = @racc_state + vstack = @racc_vstack + tstack = @racc_tstack + + i = act * -3 + len = reduce_table[i] + reduce_to = reduce_table[i+1] + method_id = reduce_table[i+2] + void_array = [] + + tmp_t = tstack[-len, len] if @yydebug + tmp_v = vstack[-len, len] + tstack[-len, len] = void_array if @yydebug + vstack[-len, len] = void_array + state[-len, len] = void_array + + # tstack must be updated AFTER method call + if use_result + vstack.push __send__(method_id, tmp_v, vstack, tmp_v[0]) + else + vstack.push __send__(method_id, tmp_v, vstack) + end + tstack.push reduce_to + + racc_reduce(tmp_t, reduce_to, tstack, vstack) if @yydebug + + k1 = reduce_to - nt_base + if i = goto_pointer[k1] + i += state[-1] + if i >= 0 and (curstate = goto_table[i]) and goto_check[i] == k1 + return curstate + end + end + goto_default[k1] + end + + def on_error(t, val, vstack) + raise ParseError, sprintf("\nparse error on value %s (%s)", + val.inspect, token_to_str(t) || '?') + end + + def yyerror + throw :racc_jump, 1 + end + + def yyaccept + throw :racc_jump, 2 + end + + def yyerrok + @racc_error_status = 0 + end + + # + # for debugging output + # + + def racc_read_token(t, tok, val) + @racc_debug_out.print 'read ' + @racc_debug_out.print tok.inspect, '(', racc_token2str(t), ') ' + @racc_debug_out.puts val.inspect + @racc_debug_out.puts + end + + def racc_shift(tok, tstack, vstack) + @racc_debug_out.puts "shift #{racc_token2str tok}" + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_reduce(toks, sim, tstack, vstack) + out = @racc_debug_out + out.print 'reduce ' + if toks.empty? + out.print ' ' + else + toks.each {|t| out.print ' ', racc_token2str(t) } + end + out.puts " --> #{racc_token2str(sim)}" + + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_accept + @racc_debug_out.puts 'accept' + @racc_debug_out.puts + end + + def racc_e_pop(state, tstack, vstack) + @racc_debug_out.puts 'error recovering mode: pop token' + racc_print_states state + racc_print_stacks tstack, vstack + @racc_debug_out.puts + end + + def racc_next_state(curstate, state) + @racc_debug_out.puts "goto #{curstate}" + racc_print_states state + @racc_debug_out.puts + end + + def racc_print_stacks(t, v) + out = @racc_debug_out + out.print ' [' + t.each_index do |i| + out.print ' (', racc_token2str(t[i]), ' ', v[i].inspect, ')' + end + out.puts ' ]' + end + + def racc_print_states(s) + out = @racc_debug_out + out.print ' [' + s.each {|st| out.print ' ', st } + out.puts ' ]' + end + + def racc_token2str(tok) + self.class::Racc_token_to_s_table[tok] or + raise "[Racc Bug] can't convert token #{tok} to string" + end + + def token_to_str(t) + self.class::Racc_token_to_s_table[t] + end + + end + +end +..end racc/parser.rb modeval..id8076474214 +end +###### racc/parser.rb end + + +# +# parser.rb +# +# Copyright (c) 1998-2007 Minero Aoki +# +# This program is free software. +# You can distribute/modify this program under the terms of +# the GNU Lesser General Public License version 2.1. +# + +require 'tmail/scanner' +require 'tmail/utils' + + +module TMail + + class Parser < Racc::Parser + +module_eval <<'..end parser.y modeval..id7b0b3dccb7', 'parser.y', 340 + + include TextUtils + + def self.parse( ident, str, cmt = nil ) + new.parse(ident, str, cmt) + end + + MAILP_DEBUG = false + + def initialize + self.debug = MAILP_DEBUG + end + + def debug=( flag ) + @yydebug = flag && Racc_debug_parser + @scanner_debug = flag + end + + def debug + @yydebug + end + + def parse( ident, str, comments = nil ) + @scanner = Scanner.new(str, ident, comments) + @scanner.debug = @scanner_debug + @first = [ident, ident] + result = yyparse(self, :parse_in) + comments.map! {|c| to_kcode(c) } if comments + result + end + + private + + def parse_in( &block ) + yield @first + @scanner.scan(&block) + end + + def on_error( t, val, vstack ) + raise SyntaxError, "parse error on token #{racc_token2str t}" + end + +..end parser.y modeval..id7b0b3dccb7 + +##### racc 1.4.5 generates ### + +racc_reduce_table = [ + 0, 0, :racc_error, + 2, 35, :_reduce_1, + 2, 35, :_reduce_2, + 2, 35, :_reduce_3, + 2, 35, :_reduce_4, + 2, 35, :_reduce_5, + 2, 35, :_reduce_6, + 2, 35, :_reduce_7, + 2, 35, :_reduce_8, + 2, 35, :_reduce_9, + 2, 35, :_reduce_10, + 2, 35, :_reduce_11, + 2, 35, :_reduce_12, + 6, 36, :_reduce_13, + 0, 48, :_reduce_none, + 2, 48, :_reduce_none, + 3, 49, :_reduce_16, + 5, 49, :_reduce_17, + 1, 50, :_reduce_18, + 7, 37, :_reduce_19, + 0, 51, :_reduce_none, + 2, 51, :_reduce_21, + 0, 52, :_reduce_none, + 2, 52, :_reduce_23, + 1, 58, :_reduce_24, + 3, 58, :_reduce_25, + 2, 58, :_reduce_26, + 0, 53, :_reduce_none, + 2, 53, :_reduce_28, + 0, 54, :_reduce_29, + 3, 54, :_reduce_30, + 0, 55, :_reduce_none, + 2, 55, :_reduce_32, + 2, 55, :_reduce_33, + 0, 56, :_reduce_none, + 2, 56, :_reduce_35, + 1, 61, :_reduce_36, + 1, 61, :_reduce_37, + 0, 57, :_reduce_none, + 2, 57, :_reduce_39, + 1, 38, :_reduce_none, + 1, 38, :_reduce_none, + 3, 38, :_reduce_none, + 1, 46, :_reduce_none, + 1, 46, :_reduce_none, + 1, 46, :_reduce_none, + 1, 39, :_reduce_none, + 2, 39, :_reduce_47, + 1, 64, :_reduce_48, + 3, 64, :_reduce_49, + 1, 68, :_reduce_none, + 1, 68, :_reduce_none, + 1, 69, :_reduce_52, + 3, 69, :_reduce_53, + 1, 47, :_reduce_none, + 1, 47, :_reduce_none, + 2, 47, :_reduce_56, + 2, 67, :_reduce_none, + 3, 65, :_reduce_58, + 2, 65, :_reduce_59, + 1, 70, :_reduce_60, + 2, 70, :_reduce_61, + 4, 62, :_reduce_62, + 3, 62, :_reduce_63, + 2, 72, :_reduce_none, + 2, 73, :_reduce_65, + 4, 73, :_reduce_66, + 3, 63, :_reduce_67, + 1, 63, :_reduce_68, + 1, 74, :_reduce_none, + 2, 74, :_reduce_70, + 1, 71, :_reduce_71, + 3, 71, :_reduce_72, + 1, 59, :_reduce_73, + 3, 59, :_reduce_74, + 1, 76, :_reduce_75, + 2, 76, :_reduce_76, + 1, 75, :_reduce_none, + 1, 75, :_reduce_none, + 1, 75, :_reduce_none, + 1, 77, :_reduce_none, + 1, 77, :_reduce_none, + 1, 77, :_reduce_none, + 1, 66, :_reduce_none, + 2, 66, :_reduce_none, + 3, 60, :_reduce_85, + 1, 40, :_reduce_86, + 3, 40, :_reduce_87, + 1, 79, :_reduce_none, + 2, 79, :_reduce_89, + 1, 41, :_reduce_90, + 2, 41, :_reduce_91, + 3, 42, :_reduce_92, + 5, 43, :_reduce_93, + 3, 43, :_reduce_94, + 0, 80, :_reduce_95, + 5, 80, :_reduce_96, + 5, 80, :_reduce_97, + 1, 44, :_reduce_98, + 3, 45, :_reduce_99, + 0, 81, :_reduce_none, + 1, 81, :_reduce_none, + 1, 78, :_reduce_none, + 1, 78, :_reduce_none, + 1, 78, :_reduce_none, + 1, 78, :_reduce_none, + 1, 78, :_reduce_none, + 1, 78, :_reduce_none, + 1, 78, :_reduce_none ] + +racc_reduce_n = 109 + +racc_shift_n = 167 + +racc_action_table = [ + -70, -69, 23, 25, 145, 146, 29, 31, 105, 106, + 16, 17, 20, 22, 136, 27, -70, -69, 32, 101, + -70, -69, 153, 100, 113, 115, -70, -69, -70, 109, + 75, 23, 25, 101, 154, 29, 31, 142, 143, 16, + 17, 20, 22, 107, 27, 23, 25, 32, 98, 29, + 31, 96, 94, 16, 17, 20, 22, 78, 27, 23, + 25, 32, 112, 29, 31, 74, 91, 16, 17, 20, + 22, 88, 117, 92, 81, 32, 23, 25, 80, 123, + 29, 31, 100, 125, 16, 17, 20, 22, 126, 23, + 25, 109, 32, 29, 31, 91, 128, 16, 17, 20, + 22, 129, 27, 23, 25, 32, 101, 29, 31, 101, + 130, 16, 17, 20, 22, 79, 52, 23, 25, 32, + 78, 29, 31, 133, 78, 16, 17, 20, 22, 77, + 23, 25, 75, 32, 29, 31, 65, 62, 16, 17, + 20, 22, 139, 23, 25, 101, 32, 29, 31, 60, + 100, 16, 17, 20, 22, 44, 27, 101, 147, 32, + 23, 25, 120, 148, 29, 31, 151, 152, 16, 17, + 20, 22, 42, 27, 156, 158, 32, 23, 25, 120, + 40, 29, 31, 15, 163, 16, 17, 20, 22, 40, + 27, 23, 25, 32, 68, 29, 31, 165, 166, 16, + 17, 20, 22, nil, 27, 23, 25, 32, nil, 29, + 31, 74, nil, 16, 17, 20, 22, nil, 23, 25, + nil, 32, 29, 31, nil, nil, 16, 17, 20, 22, + nil, 23, 25, nil, 32, 29, 31, nil, nil, 16, + 17, 20, 22, nil, 23, 25, nil, 32, 29, 31, + nil, nil, 16, 17, 20, 22, nil, 23, 25, nil, + 32, 29, 31, nil, nil, 16, 17, 20, 22, nil, + 27, 23, 25, 32, nil, 29, 31, nil, nil, 16, + 17, 20, 22, nil, 23, 25, nil, 32, 29, 31, + nil, nil, 16, 17, 20, 22, nil, 23, 25, nil, + 32, 29, 31, nil, nil, 16, 17, 20, 22, nil, + 84, 25, nil, 32, 29, 31, nil, 87, 16, 17, + 20, 22, 4, 6, 7, 8, 9, 10, 11, 12, + 13, 1, 2, 3, 84, 25, nil, nil, 29, 31, + nil, 87, 16, 17, 20, 22, 84, 25, nil, nil, + 29, 31, nil, 87, 16, 17, 20, 22, 84, 25, + nil, nil, 29, 31, nil, 87, 16, 17, 20, 22, + 84, 25, nil, nil, 29, 31, nil, 87, 16, 17, + 20, 22, 84, 25, nil, nil, 29, 31, nil, 87, + 16, 17, 20, 22, 84, 25, nil, nil, 29, 31, + nil, 87, 16, 17, 20, 22 ] + +racc_action_check = [ + 75, 28, 68, 68, 136, 136, 68, 68, 72, 72, + 68, 68, 68, 68, 126, 68, 75, 28, 68, 67, + 75, 28, 143, 66, 86, 86, 75, 28, 75, 75, + 28, 3, 3, 86, 143, 3, 3, 134, 134, 3, + 3, 3, 3, 73, 3, 151, 151, 3, 62, 151, + 151, 60, 56, 151, 151, 151, 151, 51, 151, 52, + 52, 151, 80, 52, 52, 52, 50, 52, 52, 52, + 52, 45, 89, 52, 42, 52, 71, 71, 41, 96, + 71, 71, 97, 98, 71, 71, 71, 71, 100, 7, + 7, 101, 71, 7, 7, 102, 104, 7, 7, 7, + 7, 105, 7, 8, 8, 7, 108, 8, 8, 111, + 112, 8, 8, 8, 8, 40, 8, 9, 9, 8, + 36, 9, 9, 117, 121, 9, 9, 9, 9, 33, + 10, 10, 70, 9, 10, 10, 13, 12, 10, 10, + 10, 10, 130, 2, 2, 131, 10, 2, 2, 11, + 135, 2, 2, 2, 2, 6, 2, 138, 139, 2, + 90, 90, 90, 140, 90, 90, 141, 142, 90, 90, + 90, 90, 5, 90, 147, 150, 90, 127, 127, 127, + 4, 127, 127, 1, 156, 127, 127, 127, 127, 158, + 127, 26, 26, 127, 26, 26, 26, 162, 163, 26, + 26, 26, 26, nil, 26, 27, 27, 26, nil, 27, + 27, 27, nil, 27, 27, 27, 27, nil, 154, 154, + nil, 27, 154, 154, nil, nil, 154, 154, 154, 154, + nil, 122, 122, nil, 154, 122, 122, nil, nil, 122, + 122, 122, 122, nil, 76, 76, nil, 122, 76, 76, + nil, nil, 76, 76, 76, 76, nil, 38, 38, nil, + 76, 38, 38, nil, nil, 38, 38, 38, 38, nil, + 38, 55, 55, 38, nil, 55, 55, nil, nil, 55, + 55, 55, 55, nil, 94, 94, nil, 55, 94, 94, + nil, nil, 94, 94, 94, 94, nil, 59, 59, nil, + 94, 59, 59, nil, nil, 59, 59, 59, 59, nil, + 114, 114, nil, 59, 114, 114, nil, 114, 114, 114, + 114, 114, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 77, 77, nil, nil, 77, 77, + nil, 77, 77, 77, 77, 77, 44, 44, nil, nil, + 44, 44, nil, 44, 44, 44, 44, 44, 113, 113, + nil, nil, 113, 113, nil, 113, 113, 113, 113, 113, + 88, 88, nil, nil, 88, 88, nil, 88, 88, 88, + 88, 88, 74, 74, nil, nil, 74, 74, nil, 74, + 74, 74, 74, 74, 129, 129, nil, nil, 129, 129, + nil, 129, 129, 129, 129, 129 ] + +racc_action_pointer = [ + 320, 152, 129, 17, 165, 172, 137, 75, 89, 103, + 116, 135, 106, 105, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, 177, 191, 1, nil, + nil, nil, nil, 109, nil, nil, 94, nil, 243, nil, + 99, 64, 74, nil, 332, 52, nil, nil, nil, nil, + 50, 31, 45, nil, nil, 257, 36, nil, nil, 283, + 22, nil, 16, nil, nil, nil, -3, -10, -12, nil, + 103, 62, -8, 15, 368, 0, 230, 320, nil, nil, + 47, nil, nil, nil, nil, nil, 4, nil, 356, 50, + 146, nil, nil, nil, 270, nil, 65, 56, 52, nil, + 57, 62, 79, nil, 68, 81, nil, nil, 77, nil, + nil, 80, 96, 344, 296, nil, nil, 108, nil, nil, + nil, 98, 217, nil, nil, nil, -19, 163, nil, 380, + 128, 116, nil, nil, 14, 124, -26, nil, 128, 141, + 148, 141, 152, 7, nil, nil, nil, 160, nil, nil, + 149, 31, nil, nil, 204, nil, 167, nil, 174, nil, + nil, nil, 169, 184, nil, nil, nil ] + +racc_action_default = [ + -109, -109, -109, -109, -14, -109, -20, -109, -109, -109, + -109, -109, -109, -109, -10, -95, -105, -106, -77, -44, + -107, -11, -108, -79, -43, -102, -109, -109, -60, -103, + -55, -104, -78, -68, -54, -71, -45, -12, -109, -1, + -109, -109, -109, -2, -109, -22, -51, -48, -50, -3, + -40, -41, -109, -46, -4, -86, -5, -88, -6, -90, + -109, -7, -95, -8, -9, -98, -100, -61, -59, -56, + -69, -109, -109, -109, -109, -75, -109, -109, -57, -15, + -109, 167, -73, -80, -82, -21, -24, -81, -109, -27, + -109, -83, -47, -89, -109, -91, -109, -100, -109, -99, + -101, -75, -58, -52, -109, -109, -64, -63, -65, -76, + -72, -67, -109, -109, -109, -26, -23, -109, -29, -49, + -84, -42, -87, -92, -94, -95, -109, -109, -62, -109, + -109, -25, -74, -28, -31, -100, -109, -53, -66, -109, + -109, -34, -109, -109, -93, -96, -97, -109, -18, -13, + -38, -109, -30, -33, -109, -32, -16, -19, -14, -35, + -36, -37, -109, -109, -39, -85, -17 ] + +racc_goto_table = [ + 39, 67, 70, 73, 38, 66, 69, 24, 37, 57, + 59, 36, 55, 67, 99, 90, 85, 157, 69, 108, + 83, 134, 111, 76, 49, 53, 141, 70, 73, 150, + 118, 89, 45, 155, 159, 149, 140, 21, 14, 19, + 119, 102, 64, 63, 61, 124, 70, 104, 58, 132, + 83, 56, 97, 83, 54, 93, 43, 5, 131, 95, + 116, nil, 76, nil, 83, 76, nil, 127, nil, 38, + nil, nil, nil, 103, 138, nil, 110, nil, nil, nil, + nil, nil, nil, 144, nil, nil, nil, nil, nil, 83, + 83, nil, nil, nil, 57, nil, nil, 122, nil, 121, + nil, nil, nil, nil, nil, 83, nil, nil, nil, nil, + nil, nil, nil, nil, nil, 135, nil, nil, nil, nil, + nil, nil, 93, nil, nil, nil, 70, 161, 38, 70, + 162, 160, 137, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 164 ] + +racc_goto_check = [ + 2, 37, 37, 29, 36, 46, 28, 13, 13, 41, + 41, 31, 45, 37, 47, 32, 24, 23, 28, 25, + 44, 20, 25, 42, 4, 4, 21, 37, 29, 22, + 19, 18, 17, 26, 27, 16, 15, 12, 11, 33, + 34, 35, 10, 9, 8, 47, 37, 29, 7, 43, + 44, 6, 46, 44, 5, 41, 3, 1, 25, 41, + 24, nil, 42, nil, 44, 42, nil, 32, nil, 36, + nil, nil, nil, 13, 25, nil, 41, nil, nil, nil, + nil, nil, nil, 47, nil, nil, nil, nil, nil, 44, + 44, nil, nil, nil, 41, nil, nil, 45, nil, 31, + nil, nil, nil, nil, nil, 44, nil, nil, nil, nil, + nil, nil, nil, nil, nil, 46, nil, nil, nil, nil, + nil, nil, 41, nil, nil, nil, 37, 29, 36, 37, + 29, 28, 13, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, nil, 2 ] + +racc_goto_pointer = [ + nil, 57, -4, 50, 17, 46, 42, 38, 33, 31, + 29, 37, 35, 5, nil, -94, -105, 26, -14, -59, + -97, -108, -112, -133, -28, -55, -110, -117, -20, -24, + nil, 9, -35, 37, -50, -27, 1, -25, nil, nil, + nil, 0, -5, -65, -24, 3, -10, -52 ] + +racc_goto_default = [ + nil, nil, nil, nil, nil, nil, nil, nil, nil, nil, + nil, nil, nil, 48, 41, nil, nil, nil, nil, nil, + nil, nil, nil, nil, nil, 86, nil, nil, 30, 34, + 50, 51, nil, 46, 47, nil, 26, 28, 71, 72, + 33, 35, 114, 82, 18, nil, nil, nil ] + +racc_token_table = { + false => 0, + Object.new => 1, + :DATETIME => 2, + :RECEIVED => 3, + :MADDRESS => 4, + :RETPATH => 5, + :KEYWORDS => 6, + :ENCRYPTED => 7, + :MIMEVERSION => 8, + :CTYPE => 9, + :CENCODING => 10, + :CDISPOSITION => 11, + :ADDRESS => 12, + :MAILBOX => 13, + :DIGIT => 14, + :ATOM => 15, + "," => 16, + ":" => 17, + :FROM => 18, + :BY => 19, + "@" => 20, + :DOMLIT => 21, + :VIA => 22, + :WITH => 23, + :ID => 24, + :FOR => 25, + ";" => 26, + "<" => 27, + ">" => 28, + "." => 29, + :QUOTED => 30, + :TOKEN => 31, + "/" => 32, + "=" => 33 } + +racc_use_result_var = false + +racc_nt_base = 34 + +Racc_arg = [ + racc_action_table, + racc_action_check, + racc_action_default, + racc_action_pointer, + racc_goto_table, + racc_goto_check, + racc_goto_default, + racc_goto_pointer, + racc_nt_base, + racc_reduce_table, + racc_token_table, + racc_shift_n, + racc_reduce_n, + racc_use_result_var ] + +Racc_token_to_s_table = [ +'$end', +'error', +'DATETIME', +'RECEIVED', +'MADDRESS', +'RETPATH', +'KEYWORDS', +'ENCRYPTED', +'MIMEVERSION', +'CTYPE', +'CENCODING', +'CDISPOSITION', +'ADDRESS', +'MAILBOX', +'DIGIT', +'ATOM', +'","', +'":"', +'FROM', +'BY', +'"@"', +'DOMLIT', +'VIA', +'WITH', +'ID', +'FOR', +'";"', +'"<"', +'">"', +'"."', +'QUOTED', +'TOKEN', +'"/"', +'"="', +'$start', +'content', +'datetime', +'received', +'addrs_TOP', +'retpath', +'keys', +'enc', +'version', +'ctype', +'cencode', +'cdisp', +'addr_TOP', +'mbox', +'day', +'hour', +'zone', +'from', +'by', +'via', +'with', +'id', +'for', +'received_datetime', +'received_domain', +'domain', +'msgid', +'received_addrspec', +'routeaddr', +'spec', +'addrs', +'group_bare', +'commas', +'group', +'addr', +'mboxes', +'addr_phrase', +'local_head', +'routes', +'at_domains', +'local', +'word', +'dots', +'domword', +'atom', +'phrase', +'params', +'opt_semicolon'] + +Racc_debug_parser = false + +##### racc system variables end ##### + + # reduce 0 omitted + +module_eval <<'.,.,', 'parser.y', 16 + def _reduce_1( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 17 + def _reduce_2( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 18 + def _reduce_3( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 19 + def _reduce_4( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 20 + def _reduce_5( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 21 + def _reduce_6( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 22 + def _reduce_7( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 23 + def _reduce_8( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 24 + def _reduce_9( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 25 + def _reduce_10( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 26 + def _reduce_11( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 27 + def _reduce_12( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 36 + def _reduce_13( val, _values) + t = Time.gm(val[3].to_i, val[2], val[1].to_i, 0, 0, 0) + (t + val[4] - val[5]).localtime + end +.,., + + # reduce 14 omitted + + # reduce 15 omitted + +module_eval <<'.,.,', 'parser.y', 45 + def _reduce_16( val, _values) + (val[0].to_i * 60 * 60) + + (val[2].to_i * 60) + end +.,., + +module_eval <<'.,.,', 'parser.y', 51 + def _reduce_17( val, _values) + (val[0].to_i * 60 * 60) + + (val[2].to_i * 60) + + (val[4].to_i) + end +.,., + +module_eval <<'.,.,', 'parser.y', 56 + def _reduce_18( val, _values) + timezone_string_to_unixtime(val[0]) + end +.,., + +module_eval <<'.,.,', 'parser.y', 61 + def _reduce_19( val, _values) + val + end +.,., + + # reduce 20 omitted + +module_eval <<'.,.,', 'parser.y', 67 + def _reduce_21( val, _values) + val[1] + end +.,., + + # reduce 22 omitted + +module_eval <<'.,.,', 'parser.y', 73 + def _reduce_23( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 79 + def _reduce_24( val, _values) + join_domain(val[0]) + end +.,., + +module_eval <<'.,.,', 'parser.y', 83 + def _reduce_25( val, _values) + join_domain(val[2]) + end +.,., + +module_eval <<'.,.,', 'parser.y', 87 + def _reduce_26( val, _values) + join_domain(val[0]) + end +.,., + + # reduce 27 omitted + +module_eval <<'.,.,', 'parser.y', 93 + def _reduce_28( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 98 + def _reduce_29( val, _values) + [] + end +.,., + +module_eval <<'.,.,', 'parser.y', 103 + def _reduce_30( val, _values) + val[0].push val[2] + val[0] + end +.,., + + # reduce 31 omitted + +module_eval <<'.,.,', 'parser.y', 109 + def _reduce_32( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 113 + def _reduce_33( val, _values) + val[1] + end +.,., + + # reduce 34 omitted + +module_eval <<'.,.,', 'parser.y', 119 + def _reduce_35( val, _values) + val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 125 + def _reduce_36( val, _values) + val[0].spec + end +.,., + +module_eval <<'.,.,', 'parser.y', 129 + def _reduce_37( val, _values) + val[0].spec + end +.,., + + # reduce 38 omitted + +module_eval <<'.,.,', 'parser.y', 136 + def _reduce_39( val, _values) + val[1] + end +.,., + + # reduce 40 omitted + + # reduce 41 omitted + + # reduce 42 omitted + + # reduce 43 omitted + + # reduce 44 omitted + + # reduce 45 omitted + + # reduce 46 omitted + +module_eval <<'.,.,', 'parser.y', 146 + def _reduce_47( val, _values) + [ Address.new(nil, nil) ] + end +.,., + +module_eval <<'.,.,', 'parser.y', 152 + def _reduce_48( val, _values) + val + end +.,., + +module_eval <<'.,.,', 'parser.y', 157 + def _reduce_49( val, _values) + val[0].push val[2] + val[0] + end +.,., + + # reduce 50 omitted + + # reduce 51 omitted + +module_eval <<'.,.,', 'parser.y', 165 + def _reduce_52( val, _values) + val + end +.,., + +module_eval <<'.,.,', 'parser.y', 170 + def _reduce_53( val, _values) + val[0].push val[2] + val[0] + end +.,., + + # reduce 54 omitted + + # reduce 55 omitted + +module_eval <<'.,.,', 'parser.y', 178 + def _reduce_56( val, _values) + val[1].phrase = Decoder.decode(val[0]) + val[1] + end +.,., + + # reduce 57 omitted + +module_eval <<'.,.,', 'parser.y', 185 + def _reduce_58( val, _values) + AddressGroup.new(val[0], val[2]) + end +.,., + +module_eval <<'.,.,', 'parser.y', 185 + def _reduce_59( val, _values) + AddressGroup.new(val[0], []) + end +.,., + +module_eval <<'.,.,', 'parser.y', 188 + def _reduce_60( val, _values) + val[0].join('.') + end +.,., + +module_eval <<'.,.,', 'parser.y', 189 + def _reduce_61( val, _values) + val[0] << ' ' << val[1].join('.') + end +.,., + +module_eval <<'.,.,', 'parser.y', 196 + def _reduce_62( val, _values) + val[2].routes.replace val[1] + val[2] + end +.,., + +module_eval <<'.,.,', 'parser.y', 200 + def _reduce_63( val, _values) + val[1] + end +.,., + + # reduce 64 omitted + +module_eval <<'.,.,', 'parser.y', 203 + def _reduce_65( val, _values) + [ val[1].join('.') ] + end +.,., + +module_eval <<'.,.,', 'parser.y', 204 + def _reduce_66( val, _values) + val[0].push val[3].join('.'); val[0] + end +.,., + +module_eval <<'.,.,', 'parser.y', 206 + def _reduce_67( val, _values) + Address.new( val[0], val[2] ) + end +.,., + +module_eval <<'.,.,', 'parser.y', 207 + def _reduce_68( val, _values) + Address.new( val[0], nil ) + end +.,., + + # reduce 69 omitted + +module_eval <<'.,.,', 'parser.y', 210 + def _reduce_70( val, _values) + val[0].push ''; val[0] + end +.,., + +module_eval <<'.,.,', 'parser.y', 213 + def _reduce_71( val, _values) + val + end +.,., + +module_eval <<'.,.,', 'parser.y', 222 + def _reduce_72( val, _values) + val[1].times do + val[0].push '' + end + val[0].push val[2] + val[0] + end +.,., + +module_eval <<'.,.,', 'parser.y', 224 + def _reduce_73( val, _values) + val + end +.,., + +module_eval <<'.,.,', 'parser.y', 233 + def _reduce_74( val, _values) + val[1].times do + val[0].push '' + end + val[0].push val[2] + val[0] + end +.,., + +module_eval <<'.,.,', 'parser.y', 234 + def _reduce_75( val, _values) + 0 + end +.,., + +module_eval <<'.,.,', 'parser.y', 235 + def _reduce_76( val, _values) + 1 + end +.,., + + # reduce 77 omitted + + # reduce 78 omitted + + # reduce 79 omitted + + # reduce 80 omitted + + # reduce 81 omitted + + # reduce 82 omitted + + # reduce 83 omitted + + # reduce 84 omitted + +module_eval <<'.,.,', 'parser.y', 253 + def _reduce_85( val, _values) + val[1] = val[1].spec + val.join('') + end +.,., + +module_eval <<'.,.,', 'parser.y', 254 + def _reduce_86( val, _values) + val + end +.,., + +module_eval <<'.,.,', 'parser.y', 255 + def _reduce_87( val, _values) + val[0].push val[2]; val[0] + end +.,., + + # reduce 88 omitted + +module_eval <<'.,.,', 'parser.y', 258 + def _reduce_89( val, _values) + val[0] << ' ' << val[1] + end +.,., + +module_eval <<'.,.,', 'parser.y', 265 + def _reduce_90( val, _values) + val.push nil + val + end +.,., + +module_eval <<'.,.,', 'parser.y', 269 + def _reduce_91( val, _values) + val + end +.,., + +module_eval <<'.,.,', 'parser.y', 274 + def _reduce_92( val, _values) + [ val[0].to_i, val[2].to_i ] + end +.,., + +module_eval <<'.,.,', 'parser.y', 279 + def _reduce_93( val, _values) + [ val[0].downcase, val[2].downcase, decode_params(val[3]) ] + end +.,., + +module_eval <<'.,.,', 'parser.y', 283 + def _reduce_94( val, _values) + [ val[0].downcase, nil, decode_params(val[1]) ] + end +.,., + +module_eval <<'.,.,', 'parser.y', 288 + def _reduce_95( val, _values) + {} + end +.,., + +module_eval <<'.,.,', 'parser.y', 293 + def _reduce_96( val, _values) + val[0][ val[2].downcase ] = ('"' + val[4].to_s + '"') + val[0] + end +.,., + +module_eval <<'.,.,', 'parser.y', 298 + def _reduce_97( val, _values) + val[0][ val[2].downcase ] = val[4] + val[0] + end +.,., + +module_eval <<'.,.,', 'parser.y', 303 + def _reduce_98( val, _values) + val[0].downcase + end +.,., + +module_eval <<'.,.,', 'parser.y', 308 + def _reduce_99( val, _values) + [ val[0].downcase, decode_params(val[1]) ] + end +.,., + + # reduce 100 omitted + + # reduce 101 omitted + + # reduce 102 omitted + + # reduce 103 omitted + + # reduce 104 omitted + + # reduce 105 omitted + + # reduce 106 omitted + + # reduce 107 omitted + + # reduce 108 omitted + + def _reduce_none( val, _values) + val[0] + end + + end # class Parser + +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/port.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/port.rb new file mode 100644 index 0000000000..445f0e632b --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/port.rb @@ -0,0 +1,379 @@ +=begin rdoc + += Port class + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +require 'tmail/stringio' + + +module TMail + + class Port + def reproducible? + false + end + end + + + ### + ### FilePort + ### + + class FilePort < Port + + def initialize( fname ) + @filename = File.expand_path(fname) + super() + end + + attr_reader :filename + + alias ident filename + + def ==( other ) + other.respond_to?(:filename) and @filename == other.filename + end + + alias eql? == + + def hash + @filename.hash + end + + def inspect + "#<#{self.class}:#{@filename}>" + end + + def reproducible? + true + end + + def size + File.size @filename + end + + + def ropen( &block ) + File.open(@filename, &block) + end + + def wopen( &block ) + File.open(@filename, 'w', &block) + end + + def aopen( &block ) + File.open(@filename, 'a', &block) + end + + + def read_all + ropen {|f| + return f.read + } + end + + + def remove + File.unlink @filename + end + + def move_to( port ) + begin + File.link @filename, port.filename + rescue Errno::EXDEV + copy_to port + end + File.unlink @filename + end + + alias mv move_to + + def copy_to( port ) + if FilePort === port + copy_file @filename, port.filename + else + File.open(@filename) {|r| + port.wopen {|w| + while s = r.sysread(4096) + w.write << s + end + } } + end + end + + alias cp copy_to + + private + + # from fileutils.rb + def copy_file( src, dest ) + st = r = w = nil + + File.open(src, 'rb') {|r| + File.open(dest, 'wb') {|w| + st = r.stat + begin + while true + w.write r.sysread(st.blksize) + end + rescue EOFError + end + } } + end + + end + + + module MailFlags + + def seen=( b ) + set_status 'S', b + end + + def seen? + get_status 'S' + end + + def replied=( b ) + set_status 'R', b + end + + def replied? + get_status 'R' + end + + def flagged=( b ) + set_status 'F', b + end + + def flagged? + get_status 'F' + end + + private + + def procinfostr( str, tag, true_p ) + a = str.upcase.split(//) + a.push true_p ? tag : nil + a.delete tag unless true_p + a.compact.sort.join('').squeeze + end + + end + + + class MhPort < FilePort + + include MailFlags + + private + + def set_status( tag, flag ) + begin + tmpfile = @filename + '.tmailtmp.' + $$.to_s + File.open(tmpfile, 'w') {|f| + write_status f, tag, flag + } + File.unlink @filename + File.link tmpfile, @filename + ensure + File.unlink tmpfile + end + end + + def write_status( f, tag, flag ) + stat = '' + File.open(@filename) {|r| + while line = r.gets + if line.strip.empty? + break + elsif m = /\AX-TMail-Status:/i.match(line) + stat = m.post_match.strip + else + f.print line + end + end + + s = procinfostr(stat, tag, flag) + f.puts 'X-TMail-Status: ' + s unless s.empty? + f.puts + + while s = r.read(2048) + f.write s + end + } + end + + def get_status( tag ) + File.foreach(@filename) {|line| + return false if line.strip.empty? + if m = /\AX-TMail-Status:/i.match(line) + return m.post_match.strip.include?(tag[0]) + end + } + false + end + + end + + + class MaildirPort < FilePort + + def move_to_new + new = replace_dir(@filename, 'new') + File.rename @filename, new + @filename = new + end + + def move_to_cur + new = replace_dir(@filename, 'cur') + File.rename @filename, new + @filename = new + end + + def replace_dir( path, dir ) + "#{File.dirname File.dirname(path)}/#{dir}/#{File.basename path}" + end + private :replace_dir + + + include MailFlags + + private + + MAIL_FILE = /\A(\d+\.[\d_]+\.[^:]+)(?:\:(\d),(\w+)?)?\z/ + + def set_status( tag, flag ) + if m = MAIL_FILE.match(File.basename(@filename)) + s, uniq, type, info, = m.to_a + return if type and type != '2' # do not change anything + newname = File.dirname(@filename) + '/' + + uniq + ':2,' + procinfostr(info.to_s, tag, flag) + else + newname = @filename + ':2,' + tag + end + + File.link @filename, newname + File.unlink @filename + @filename = newname + end + + def get_status( tag ) + m = MAIL_FILE.match(File.basename(@filename)) or return false + m[2] == '2' and m[3].to_s.include?(tag[0]) + end + + end + + + ### + ### StringPort + ### + + class StringPort < Port + + def initialize( str = '' ) + @buffer = str + super() + end + + def string + @buffer + end + + def to_s + @buffer.dup + end + + alias read_all to_s + + def size + @buffer.size + end + + def ==( other ) + StringPort === other and @buffer.equal? other.string + end + + alias eql? == + + def hash + @buffer.object_id.hash + end + + def inspect + "#<#{self.class}:id=#{sprintf '0x%x', @buffer.object_id}>" + end + + def reproducible? + true + end + + def ropen( &block ) + @buffer or raise Errno::ENOENT, "#{inspect} is already removed" + StringInput.open(@buffer, &block) + end + + def wopen( &block ) + @buffer = '' + StringOutput.new(@buffer, &block) + end + + def aopen( &block ) + @buffer ||= '' + StringOutput.new(@buffer, &block) + end + + def remove + @buffer = nil + end + + alias rm remove + + def copy_to( port ) + port.wopen {|f| + f.write @buffer + } + end + + alias cp copy_to + + def move_to( port ) + if StringPort === port + str = @buffer + port.instance_eval { @buffer = str } + else + copy_to port + end + remove + end + + end + +end # module TMail diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/quoting.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/quoting.rb new file mode 100644 index 0000000000..cb9f4288f1 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/quoting.rb @@ -0,0 +1,118 @@ +=begin rdoc + += Quoting methods + +=end +module TMail + class Mail + def subject(to_charset = 'utf-8') + Unquoter.unquote_and_convert_to(quoted_subject, to_charset) + end + + def unquoted_body(to_charset = 'utf-8') + from_charset = sub_header("content-type", "charset") + case (content_transfer_encoding || "7bit").downcase + when "quoted-printable" + # the default charset is set to iso-8859-1 instead of 'us-ascii'. + # This is needed as many mailer do not set the charset but send in ISO. This is only used if no charset is set. + if !from_charset.blank? && from_charset.downcase == 'us-ascii' + from_charset = 'iso-8859-1' + end + + Unquoter.unquote_quoted_printable_and_convert_to(quoted_body, + to_charset, from_charset, true) + when "base64" + Unquoter.unquote_base64_and_convert_to(quoted_body, to_charset, + from_charset) + when "7bit", "8bit" + Unquoter.convert_to(quoted_body, to_charset, from_charset) + when "binary" + quoted_body + else + quoted_body + end + end + + def body(to_charset = 'utf-8', &block) + attachment_presenter = block || Proc.new { |file_name| "Attachment: #{file_name}\n" } + + if multipart? + parts.collect { |part| + header = part["content-type"] + + if part.multipart? + part.body(to_charset, &attachment_presenter) + elsif header.nil? + "" + elsif !attachment?(part) + part.unquoted_body(to_charset) + else + attachment_presenter.call(header["name"] || "(unnamed)") + end + }.join + else + unquoted_body(to_charset) + end + end + end + + class Unquoter + class << self + def unquote_and_convert_to(text, to_charset, from_charset = "iso-8859-1", preserve_underscores=false) + return "" if text.nil? + text.gsub(/(.*?)(?:(?:=\?(.*?)\?(.)\?(.*?)\?=)|$)/) do + before = $1 + from_charset = $2 + quoting_method = $3 + text = $4 + + before = convert_to(before, to_charset, from_charset) if before.length > 0 + before + case quoting_method + when "q", "Q" then + unquote_quoted_printable_and_convert_to(text, to_charset, from_charset, preserve_underscores) + when "b", "B" then + unquote_base64_and_convert_to(text, to_charset, from_charset) + when nil then + # will be nil at the end of the string, due to the nature of + # the regex used. + "" + else + raise "unknown quoting method #{quoting_method.inspect}" + end + end + end + + def unquote_quoted_printable_and_convert_to(text, to, from, preserve_underscores=false) + text = text.gsub(/_/, " ") unless preserve_underscores + text = text.gsub(/\r\n|\r/, "\n") # normalize newlines + convert_to(text.unpack("M*").first, to, from) + end + + def unquote_base64_and_convert_to(text, to, from) + convert_to(Base64.decode(text), to, from) + end + + begin + require 'iconv' + def convert_to(text, to, from) + return text unless to && from + text ? Iconv.iconv(to, from, text).first : "" + rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL + # the 'from' parameter specifies a charset other than what the text + # actually is...not much we can do in this case but just return the + # unconverted text. + # + # Ditto if either parameter represents an unknown charset, like + # X-UNKNOWN. + text + end + rescue LoadError + # Not providing quoting support + def convert_to(text, to, from) + warn "Action Mailer: iconv not loaded; ignoring conversion from #{from} to #{to} (#{__FILE__}:#{__LINE__})" + text + end + end + end + end +end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/require_arch.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/require_arch.rb new file mode 100644 index 0000000000..b4fffb8abb --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/require_arch.rb @@ -0,0 +1,58 @@ +#:stopdoc: +require 'rbconfig' + +# Attempts to require anative extension. +# Falls back to pure-ruby version, if it fails. +# +# This uses Config::CONFIG['arch'] from rbconfig. + +def require_arch(fname) + arch = Config::CONFIG['arch'] + begin + path = File.join("tmail", arch, fname) + require path + rescue LoadError => e + # try pre-built Windows binaries + if arch =~ /mswin/ + require File.join("tmail", 'mswin32', fname) + else + raise e + end + end +end + + +# def require_arch(fname) +# dext = Config::CONFIG['DLEXT'] +# begin +# if File.extname(fname) == dext +# path = fname +# else +# path = File.join("tmail","#{fname}.#{dext}") +# end +# require path +# rescue LoadError => e +# begin +# arch = Config::CONFIG['arch'] +# path = File.join("tmail", arch, "#{fname}.#{dext}") +# require path +# rescue LoadError +# case path +# when /i686/ +# path.sub!('i686', 'i586') +# when /i586/ +# path.sub!('i586', 'i486') +# when /i486/ +# path.sub!('i486', 'i386') +# else +# begin +# require fname + '.rb' +# rescue LoadError +# raise e +# end +# end +# retry +# end +# end +# end +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner.rb new file mode 100644 index 0000000000..a5d01396b8 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner.rb @@ -0,0 +1,49 @@ +=begin rdoc + += Scanner for TMail + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ +#:stopdoc: +#require 'tmail/require_arch' +require 'tmail/utils' +require 'tmail/config' + +module TMail + # NOTE: It woiuld be nice if these two libs could boith be called "tmailscanner", and + # the native extension would have precedence. However RubyGems boffs that up b/c + # it does not gaurantee load_path order. + begin + raise LoadError, 'Turned off native extentions by user choice' if ENV['NORUBYEXT'] + require('tmail/tmailscanner') # c extension + Scanner = TMailScanner + rescue LoadError + require 'tmail/scanner_r' + Scanner = TMailScanner + end +end +#:stopdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner_r.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner_r.rb new file mode 100644 index 0000000000..f2075502d8 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/scanner_r.rb @@ -0,0 +1,261 @@ +# scanner_r.rb +# +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ +#:stopdoc: +require 'tmail/config' + +module TMail + + class TMailScanner + + Version = '1.2.3' + Version.freeze + + MIME_HEADERS = { + :CTYPE => true, + :CENCODING => true, + :CDISPOSITION => true + } + + alnum = 'a-zA-Z0-9' + atomsyms = %q[ _#!$%&`'*+-{|}~^/=? ].strip + tokensyms = %q[ _#!$%&`'*+-{|}~^@. ].strip + atomchars = alnum + Regexp.quote(atomsyms) + tokenchars = alnum + Regexp.quote(tokensyms) + iso2022str = '\e(?!\(B)..(?:[^\e]+|\e(?!\(B)..)*\e\(B' + + eucstr = "(?:[\xa1-\xfe][\xa1-\xfe])+" + sjisstr = "(?:[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc])+" + utf8str = "(?:[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf])+" + + quoted_with_iso2022 = /\A(?:[^\\\e"]+|#{iso2022str})+/n + domlit_with_iso2022 = /\A(?:[^\\\e\]]+|#{iso2022str})+/n + comment_with_iso2022 = /\A(?:[^\\\e()]+|#{iso2022str})+/n + + quoted_without_iso2022 = /\A[^\\"]+/n + domlit_without_iso2022 = /\A[^\\\]]+/n + comment_without_iso2022 = /\A[^\\()]+/n + + PATTERN_TABLE = {} + PATTERN_TABLE['EUC'] = + [ + /\A(?:[#{atomchars}]+|#{iso2022str}|#{eucstr})+/n, + /\A(?:[#{tokenchars}]+|#{iso2022str}|#{eucstr})+/n, + quoted_with_iso2022, + domlit_with_iso2022, + comment_with_iso2022 + ] + PATTERN_TABLE['SJIS'] = + [ + /\A(?:[#{atomchars}]+|#{iso2022str}|#{sjisstr})+/n, + /\A(?:[#{tokenchars}]+|#{iso2022str}|#{sjisstr})+/n, + quoted_with_iso2022, + domlit_with_iso2022, + comment_with_iso2022 + ] + PATTERN_TABLE['UTF8'] = + [ + /\A(?:[#{atomchars}]+|#{utf8str})+/n, + /\A(?:[#{tokenchars}]+|#{utf8str})+/n, + quoted_without_iso2022, + domlit_without_iso2022, + comment_without_iso2022 + ] + PATTERN_TABLE['NONE'] = + [ + /\A[#{atomchars}]+/n, + /\A[#{tokenchars}]+/n, + quoted_without_iso2022, + domlit_without_iso2022, + comment_without_iso2022 + ] + + + def initialize( str, scantype, comments ) + init_scanner str + @comments = comments || [] + @debug = false + + # fix scanner mode + @received = (scantype == :RECEIVED) + @is_mime_header = MIME_HEADERS[scantype] + + atom, token, @quoted_re, @domlit_re, @comment_re = PATTERN_TABLE[TMail.KCODE] + @word_re = (MIME_HEADERS[scantype] ? token : atom) + end + + attr_accessor :debug + + def scan( &block ) + if @debug + scan_main do |arr| + s, v = arr + printf "%7d %-10s %s\n", + rest_size(), + s.respond_to?(:id2name) ? s.id2name : s.inspect, + v.inspect + yield arr + end + else + scan_main(&block) + end + end + + private + + RECV_TOKEN = { + 'from' => :FROM, + 'by' => :BY, + 'via' => :VIA, + 'with' => :WITH, + 'id' => :ID, + 'for' => :FOR + } + + def scan_main + until eof? + if skip(/\A[\n\r\t ]+/n) # LWSP + break if eof? + end + + if s = readstr(@word_re) + if @is_mime_header + yield [:TOKEN, s] + else + # atom + if /\A\d+\z/ === s + yield [:DIGIT, s] + elsif @received + yield [RECV_TOKEN[s.downcase] || :ATOM, s] + else + yield [:ATOM, s] + end + end + + elsif skip(/\A"/) + yield [:QUOTED, scan_quoted_word()] + + elsif skip(/\A\[/) + yield [:DOMLIT, scan_domain_literal()] + + elsif skip(/\A\(/) + @comments.push scan_comment() + + else + c = readchar() + yield [c, c] + end + end + + yield [false, '$'] + end + + def scan_quoted_word + scan_qstr(@quoted_re, /\A"/, 'quoted-word') + end + + def scan_domain_literal + '[' + scan_qstr(@domlit_re, /\A\]/, 'domain-literal') + ']' + end + + def scan_qstr( pattern, terminal, type ) + result = '' + until eof? + if s = readstr(pattern) then result << s + elsif skip(terminal) then return result + elsif skip(/\A\\/) then result << readchar() + else + raise "TMail FATAL: not match in #{type}" + end + end + scan_error! "found unterminated #{type}" + end + + def scan_comment + result = '' + nest = 1 + content = @comment_re + + until eof? + if s = readstr(content) then result << s + elsif skip(/\A\)/) then nest -= 1 + return result if nest == 0 + result << ')' + elsif skip(/\A\(/) then nest += 1 + result << '(' + elsif skip(/\A\\/) then result << readchar() + else + raise 'TMail FATAL: not match in comment' + end + end + scan_error! 'found unterminated comment' + end + + # string scanner + + def init_scanner( str ) + @src = str + end + + def eof? + @src.empty? + end + + def rest_size + @src.size + end + + def readstr( re ) + if m = re.match(@src) + @src = m.post_match + m[0] + else + nil + end + end + + def readchar + readstr(/\A./) + end + + def skip( re ) + if m = re.match(@src) + @src = m.post_match + true + else + false + end + end + + def scan_error!( msg ) + raise SyntaxError, msg + end + + end + +end # module TMail +#:startdoc: \ No newline at end of file diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/stringio.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/stringio.rb new file mode 100644 index 0000000000..8357398788 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/stringio.rb @@ -0,0 +1,280 @@ +# encoding: utf-8 +=begin rdoc + += String handling class + +=end +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +class StringInput#:nodoc: + + include Enumerable + + class << self + + def new( str ) + if block_given? + begin + f = super + yield f + ensure + f.close if f + end + else + super + end + end + + alias open new + + end + + def initialize( str ) + @src = str + @pos = 0 + @closed = false + @lineno = 0 + end + + attr_reader :lineno + + def string + @src + end + + def inspect + "#<#{self.class}:#{@closed ? 'closed' : 'open'},src=#{@src[0,30].inspect}>" + end + + def close + stream_check! + @pos = nil + @closed = true + end + + def closed? + @closed + end + + def pos + stream_check! + [@pos, @src.size].min + end + + alias tell pos + + def seek( offset, whence = IO::SEEK_SET ) + stream_check! + case whence + when IO::SEEK_SET + @pos = offset + when IO::SEEK_CUR + @pos += offset + when IO::SEEK_END + @pos = @src.size - offset + else + raise ArgumentError, "unknown seek flag: #{whence}" + end + @pos = 0 if @pos < 0 + @pos = [@pos, @src.size + 1].min + offset + end + + def rewind + stream_check! + @pos = 0 + end + + def eof? + stream_check! + @pos > @src.size + end + + def each( &block ) + stream_check! + begin + @src.each(&block) + ensure + @pos = 0 + end + end + + def gets + stream_check! + if idx = @src.index(?\n, @pos) + idx += 1 # "\n".size + line = @src[ @pos ... idx ] + @pos = idx + @pos += 1 if @pos == @src.size + else + line = @src[ @pos .. -1 ] + @pos = @src.size + 1 + end + @lineno += 1 + + line + end + + def getc + stream_check! + ch = @src[@pos] + @pos += 1 + @pos += 1 if @pos == @src.size + ch + end + + def read( len = nil ) + stream_check! + return read_all unless len + str = @src[@pos, len] + @pos += len + @pos += 1 if @pos == @src.size + str + end + + alias sysread read + + def read_all + stream_check! + return nil if eof? + rest = @src[@pos ... @src.size] + @pos = @src.size + 1 + rest + end + + def stream_check! + @closed and raise IOError, 'closed stream' + end + +end + + +class StringOutput#:nodoc: + + class << self + + def new( str = '' ) + if block_given? + begin + f = super + yield f + ensure + f.close if f + end + else + super + end + end + + alias open new + + end + + def initialize( str = '' ) + @dest = str + @closed = false + end + + def close + @closed = true + end + + def closed? + @closed + end + + def string + @dest + end + + alias value string + alias to_str string + + def size + @dest.size + end + + alias pos size + + def inspect + "#<#{self.class}:#{@dest ? 'open' : 'closed'},#{object_id}>" + end + + def print( *args ) + stream_check! + raise ArgumentError, 'wrong # of argument (0 for >1)' if args.empty? + args.each do |s| + raise ArgumentError, 'nil not allowed' if s.nil? + @dest << s.to_s + end + nil + end + + def puts( *args ) + stream_check! + args.each do |str| + @dest << (s = str.to_s) + @dest << "\n" unless s[-1] == ?\n + end + @dest << "\n" if args.empty? + nil + end + + def putc( ch ) + stream_check! + @dest << ch.chr + nil + end + + def printf( *args ) + stream_check! + @dest << sprintf(*args) + nil + end + + def write( str ) + stream_check! + s = str.to_s + @dest << s + s.size + end + + alias syswrite write + + def <<( str ) + stream_check! + @dest << str.to_s + self + end + + private + + def stream_check! + @closed and raise IOError, 'closed stream' + end + +end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/utils.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/utils.rb new file mode 100644 index 0000000000..dc594a4229 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/utils.rb @@ -0,0 +1,337 @@ +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +# = TMail - The EMail Swiss Army Knife for Ruby +# +# The TMail library provides you with a very complete way to handle and manipulate EMails +# from within your Ruby programs. +# +# Used as the backbone for email handling by the Ruby on Rails and Nitro web frameworks as +# well as a bunch of other Ruby apps including the Ruby-Talk mailing list to newsgroup email +# gateway, it is a proven and reliable email handler that won't let you down. +# +# Originally created by Minero Aoki, TMail has been recently picked up by Mikel Lindsaar and +# is being actively maintained. Numerous backlogged bug fixes have been applied as well as +# Ruby 1.9 compatibility and a swath of documentation to boot. +# +# TMail allows you to treat an email totally as an object and allow you to get on with your +# own programming without having to worry about crafting the perfect email address validation +# parser, or assembling an email from all it's component parts. +# +# TMail handles the most complex part of the email - the header. It generates and parses +# headers and provides you with instant access to their innards through simple and logically +# named accessor and setter methods. +# +# TMail also provides a wrapper to Net/SMTP as well as Unix Mailbox handling methods to +# directly read emails from your unix mailbox, parse them and use them. +# +# Following is the comprehensive list of methods to access TMail::Mail objects. You can also +# check out TMail::Mail, TMail::Address and TMail::Headers for other lists. +module TMail + + # Provides an exception to throw on errors in Syntax within TMail's parsers + class SyntaxError < StandardError; end + + # Provides a new email boundary to separate parts of the email. This is a random + # string based off the current time, so should be fairly unique. + # + # For Example: + # + # TMail.new_boundary + # #=> "mimepart_47bf656968207_25a8fbb80114" + # TMail.new_boundary + # #=> "mimepart_47bf66051de4_25a8fbb80240" + def TMail.new_boundary + 'mimepart_' + random_tag + end + + # Provides a new email message ID. You can use this to generate unique email message + # id's for your email so you can track them. + # + # Optionally takes a fully qualified domain name (default to the current hostname + # returned by Socket.gethostname) that will be appended to the message ID. + # + # For Example: + # + # email.message_id = TMail.new_message_id + # #=> "<47bf66845380e_25a8fbb80332@baci.local.tmail>" + # email.to_s + # #=> "Message-Id: <47bf668b633f1_25a8fbb80475@baci.local.tmail>\n\n" + # email.message_id = TMail.new_message_id("lindsaar.net") + # #=> "<47bf668b633f1_25a8fbb80475@lindsaar.net.tmail>" + # email.to_s + # #=> "Message-Id: <47bf668b633f1_25a8fbb80475@lindsaar.net.tmail>\n\n" + def TMail.new_message_id( fqdn = nil ) + fqdn ||= ::Socket.gethostname + "<#{random_tag()}@#{fqdn}.tmail>" + end + + #:stopdoc: + def TMail.random_tag #:nodoc: + @uniq += 1 + t = Time.now + sprintf('%x%x_%x%x%d%x', + t.to_i, t.tv_usec, + $$, Thread.current.object_id, @uniq, rand(255)) + end + private_class_method :random_tag + + @uniq = 0 + + #:startdoc: + + # Text Utils provides a namespace to define TOKENs, ATOMs, PHRASEs and CONTROL characters that + # are OK per RFC 2822. + # + # It also provides methods you can call to determine if a string is safe + module TextUtils + + aspecial = %Q|()<>[]:;.\\,"| + tspecial = %Q|()<>[];:\\,"/?=| + lwsp = %Q| \t\r\n| + control = %Q|\x00-\x1f\x7f-\xff| + + CONTROL_CHAR = /[#{control}]/n + ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{lwsp}]/n + PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n + TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{lwsp}]/n + + # Returns true if the string supplied is free from characters not allowed as an ATOM + def atom_safe?( str ) + not ATOM_UNSAFE === str + end + + # If the string supplied has ATOM unsafe characters in it, will return the string quoted + # in double quotes, otherwise returns the string unmodified + def quote_atom( str ) + (ATOM_UNSAFE === str) ? dquote(str) : str + end + + # If the string supplied has PHRASE unsafe characters in it, will return the string quoted + # in double quotes, otherwise returns the string unmodified + def quote_phrase( str ) + (PHRASE_UNSAFE === str) ? dquote(str) : str + end + + # Returns true if the string supplied is free from characters not allowed as a TOKEN + def token_safe?( str ) + not TOKEN_UNSAFE === str + end + + # If the string supplied has TOKEN unsafe characters in it, will return the string quoted + # in double quotes, otherwise returns the string unmodified + def quote_token( str ) + (TOKEN_UNSAFE === str) ? dquote(str) : str + end + + # Wraps supplied string in double quotes unless it is already wrapped + # Returns double quoted string + def dquote( str ) #:nodoc: + unless str =~ /^".*?"$/ + '"' + str.gsub(/["\\]/n) {|s| '\\' + s } + '"' + else + str + end + end + private :dquote + + # Unwraps supplied string from inside double quotes + # Returns unquoted string + def unquote( str ) + str =~ /^"(.*?)"$/ ? $1 : str + end + + # Provides a method to join a domain name by it's parts and also makes it + # ATOM safe by quoting it as needed + def join_domain( arr ) + arr.map {|i| + if /\A\[.*\]\z/ === i + i + else + quote_atom(i) + end + }.join('.') + end + + #:stopdoc: + ZONESTR_TABLE = { + 'jst' => 9 * 60, + 'eet' => 2 * 60, + 'bst' => 1 * 60, + 'met' => 1 * 60, + 'gmt' => 0, + 'utc' => 0, + 'ut' => 0, + 'nst' => -(3 * 60 + 30), + 'ast' => -4 * 60, + 'edt' => -4 * 60, + 'est' => -5 * 60, + 'cdt' => -5 * 60, + 'cst' => -6 * 60, + 'mdt' => -6 * 60, + 'mst' => -7 * 60, + 'pdt' => -7 * 60, + 'pst' => -8 * 60, + 'a' => -1 * 60, + 'b' => -2 * 60, + 'c' => -3 * 60, + 'd' => -4 * 60, + 'e' => -5 * 60, + 'f' => -6 * 60, + 'g' => -7 * 60, + 'h' => -8 * 60, + 'i' => -9 * 60, + # j not use + 'k' => -10 * 60, + 'l' => -11 * 60, + 'm' => -12 * 60, + 'n' => 1 * 60, + 'o' => 2 * 60, + 'p' => 3 * 60, + 'q' => 4 * 60, + 'r' => 5 * 60, + 's' => 6 * 60, + 't' => 7 * 60, + 'u' => 8 * 60, + 'v' => 9 * 60, + 'w' => 10 * 60, + 'x' => 11 * 60, + 'y' => 12 * 60, + 'z' => 0 * 60 + } + #:startdoc: + + # Takes a time zone string from an EMail and converts it to Unix Time (seconds) + def timezone_string_to_unixtime( str ) + if m = /([\+\-])(\d\d?)(\d\d)/.match(str) + sec = (m[2].to_i * 60 + m[3].to_i) * 60 + m[1] == '-' ? -sec : sec + else + min = ZONESTR_TABLE[str.downcase] or + raise SyntaxError, "wrong timezone format '#{str}'" + min * 60 + end + end + + #:stopdoc: + WDAY = %w( Sun Mon Tue Wed Thu Fri Sat TMailBUG ) + MONTH = %w( TMailBUG Jan Feb Mar Apr May Jun + Jul Aug Sep Oct Nov Dec TMailBUG ) + + def time2str( tm ) + # [ruby-list:7928] + gmt = Time.at(tm.to_i) + gmt.gmtime + offset = tm.to_i - Time.local(*gmt.to_a[0,6].reverse).to_i + + # DO NOT USE strftime: setlocale() breaks it + sprintf '%s, %s %s %d %02d:%02d:%02d %+.2d%.2d', + WDAY[tm.wday], tm.mday, MONTH[tm.month], + tm.year, tm.hour, tm.min, tm.sec, + *(offset / 60).divmod(60) + end + + + MESSAGE_ID = /<[^\@>]+\@[^>\@]+>/ + + def message_id?( str ) + MESSAGE_ID === str + end + + + MIME_ENCODED = /=\?[^\s?=]+\?[QB]\?[^\s?=]+\?=/i + + def mime_encoded?( str ) + MIME_ENCODED === str + end + + + def decode_params( hash ) + new = Hash.new + encoded = nil + hash.each do |key, value| + if m = /\*(?:(\d+)\*)?\z/.match(key) + ((encoded ||= {})[m.pre_match] ||= [])[(m[1] || 0).to_i] = value + else + new[key] = to_kcode(value) + end + end + if encoded + encoded.each do |key, strings| + new[key] = decode_RFC2231(strings.join('')) + end + end + + new + end + + NKF_FLAGS = { + 'EUC' => '-e -m', + 'SJIS' => '-s -m' + } + + def to_kcode( str ) + flag = NKF_FLAGS[TMail.KCODE] or return str + NKF.nkf(flag, str) + end + + RFC2231_ENCODED = /\A(?:iso-2022-jp|euc-jp|shift_jis|us-ascii)?'[a-z]*'/in + + def decode_RFC2231( str ) + m = RFC2231_ENCODED.match(str) or return str + begin + to_kcode(m.post_match.gsub(/%[\da-f]{2}/in) {|s| s[1,2].hex.chr }) + rescue + m.post_match.gsub(/%[\da-f]{2}/in, "") + end + end + + def quote_boundary + # Make sure the Content-Type boundary= parameter is quoted if it contains illegal characters + # (to ensure any special characters in the boundary text are escaped from the parser + # (such as = in MS Outlook's boundary text)) + if @body =~ /^(.*)boundary=(.*)$/m + preamble = $1 + remainder = $2 + if remainder =~ /;/ + remainder =~ /^(.*?)(;.*)$/m + boundary_text = $1 + post = $2.chomp + else + boundary_text = remainder.chomp + end + if boundary_text =~ /[\/\?\=]/ + boundary_text = "\"#{boundary_text}\"" unless boundary_text =~ /^".*?"$/ + @body = "#{preamble}boundary=#{boundary_text}#{post}" + end + end + end + #:startdoc: + + + end + +end diff --git a/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/version.rb b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/version.rb new file mode 100644 index 0000000000..95228497c0 --- /dev/null +++ b/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/version.rb @@ -0,0 +1,39 @@ +# +# version.rb +# +#-- +# Copyright (c) 1998-2003 Minero Aoki +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +# +# Note: Originally licensed under LGPL v2+. Using MIT license for Rails +# with permission of Minero Aoki. +#++ + +#:stopdoc: +module TMail + module VERSION + MAJOR = 1 + MINOR = 2 + TINY = 3 + + STRING = [MAJOR, MINOR, TINY].join('.') + end +end -- cgit v1.2.3