mail 2.2.5 → 2.2.19

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (152) hide show
  1. data/CHANGELOG.rdoc +163 -7
  2. data/README.rdoc +56 -65
  3. data/Rakefile +31 -6
  4. data/lib/VERSION +2 -2
  5. data/lib/mail/attachments_list.rb +4 -4
  6. data/lib/mail/body.rb +6 -2
  7. data/lib/mail/configuration.rb +7 -1
  8. data/lib/mail/core_extensions/shellwords.rb +55 -0
  9. data/lib/mail/core_extensions/smtp.rb +24 -0
  10. data/lib/mail/elements/address.rb +6 -6
  11. data/lib/mail/elements/content_disposition_element.rb +1 -1
  12. data/lib/mail/elements/content_type_element.rb +2 -2
  13. data/lib/mail/encodings.rb +55 -57
  14. data/lib/mail/field.rb +2 -1
  15. data/lib/mail/field_list.rb +1 -1
  16. data/lib/mail/fields/common/common_field.rb +10 -9
  17. data/lib/mail/fields/common/common_message_id.rb +6 -5
  18. data/lib/mail/fields/common/parameter_hash.rb +14 -4
  19. data/lib/mail/fields/content_disposition_field.rb +1 -1
  20. data/lib/mail/fields/content_type_field.rb +41 -28
  21. data/lib/mail/fields/date_field.rb +3 -1
  22. data/lib/mail/fields/received_field.rb +11 -3
  23. data/lib/mail/fields/resent_date_field.rb +1 -1
  24. data/lib/mail/fields/return_path_field.rb +1 -0
  25. data/lib/mail/fields/unstructured_field.rb +4 -1
  26. data/lib/mail/header.rb +8 -5
  27. data/lib/mail/mail.rb +71 -57
  28. data/lib/mail/message.rb +518 -391
  29. data/lib/mail/network/delivery_methods/sendmail.rb +15 -15
  30. data/lib/mail/network/delivery_methods/smtp.rb +33 -6
  31. data/lib/mail/network/delivery_methods/smtp_connection.rb +74 -0
  32. data/lib/mail/network/retriever_methods/base.rb +63 -0
  33. data/lib/mail/network/retriever_methods/imap.rb +147 -7
  34. data/lib/mail/network/retriever_methods/pop3.rb +25 -44
  35. data/lib/mail/network/retriever_methods/test_retriever.rb +40 -0
  36. data/lib/mail/network.rb +4 -0
  37. data/lib/mail/parsers/address_lists.rb +2 -2
  38. data/lib/mail/parsers/address_lists.treetop +2 -2
  39. data/lib/mail/parsers/content_disposition.rb +166 -18
  40. data/lib/mail/parsers/content_disposition.treetop +1 -1
  41. data/lib/mail/parsers/content_type.rb +477 -49
  42. data/lib/mail/parsers/content_type.treetop +12 -2
  43. data/lib/mail/parsers/rfc2822.rb +58 -35
  44. data/lib/mail/parsers/rfc2822.treetop +2 -2
  45. data/lib/mail/part.rb +2 -2
  46. data/lib/mail/parts_list.rb +16 -8
  47. data/lib/mail/patterns.rb +7 -2
  48. data/lib/mail/utilities.rb +31 -1
  49. data/lib/mail/version.rb +10 -8
  50. data/lib/mail/version_specific/ruby_1_8.rb +2 -2
  51. data/lib/mail/version_specific/ruby_1_9.rb +29 -8
  52. data/lib/mail.rb +8 -4
  53. metadata +44 -110
  54. data/lib/mail/attachments_list.rbc +0 -1983
  55. data/lib/mail/body.rbc +0 -3809
  56. data/lib/mail/configuration.rbc +0 -1112
  57. data/lib/mail/core_extensions/nil.rbc +0 -244
  58. data/lib/mail/core_extensions/string.rbc +0 -0
  59. data/lib/mail/elements/address.rbc +0 -4112
  60. data/lib/mail/elements/address_list.rbc +0 -1309
  61. data/lib/mail/elements/content_disposition_element.rbc +0 -701
  62. data/lib/mail/elements/content_location_element.rbc +0 -573
  63. data/lib/mail/elements/content_transfer_encoding_element.rbc +0 -535
  64. data/lib/mail/elements/content_type_element.rbc +0 -786
  65. data/lib/mail/elements/date_time_element.rbc +0 -583
  66. data/lib/mail/elements/envelope_from_element.rbc +0 -771
  67. data/lib/mail/elements/message_ids_element.rbc +0 -740
  68. data/lib/mail/elements/mime_version_element.rbc +0 -583
  69. data/lib/mail/elements/phrase_list.rbc +0 -562
  70. data/lib/mail/elements/received_element.rbc +0 -725
  71. data/lib/mail/elements.rbc +0 -362
  72. data/lib/mail/encodings/7bit.rbc +0 -538
  73. data/lib/mail/encodings/8bit.rbc +0 -541
  74. data/lib/mail/encodings/base64.rbc +0 -629
  75. data/lib/mail/encodings/binary.rbc +0 -529
  76. data/lib/mail/encodings/quoted_printable.rbc +0 -766
  77. data/lib/mail/encodings/transfer_encoding.rbc +0 -1134
  78. data/lib/mail/encodings.rbc +0 -0
  79. data/lib/mail/envelope.rbc +0 -719
  80. data/lib/mail/field.rbc +0 -4708
  81. data/lib/mail/field_list.rbc +0 -518
  82. data/lib/mail/fields/bcc_field.rbc +0 -564
  83. data/lib/mail/fields/cc_field.rbc +0 -579
  84. data/lib/mail/fields/comments_field.rbc +0 -383
  85. data/lib/mail/fields/common/address_container.rbc +0 -363
  86. data/lib/mail/fields/common/common_address.rbc +0 -3550
  87. data/lib/mail/fields/common/common_date.rbc +0 -908
  88. data/lib/mail/fields/common/common_field.rbc +0 -973
  89. data/lib/mail/fields/common/common_message_id.rbc +0 -1051
  90. data/lib/mail/fields/common/parameter_hash.rbc +0 -1335
  91. data/lib/mail/fields/content_description_field.rbc +0 -396
  92. data/lib/mail/fields/content_disposition_field.rbc +0 -1440
  93. data/lib/mail/fields/content_id_field.rbc +0 -1236
  94. data/lib/mail/fields/content_location_field.rbc +0 -892
  95. data/lib/mail/fields/content_transfer_encoding_field.rbc +0 -1184
  96. data/lib/mail/fields/content_type_field.rbc +0 -3958
  97. data/lib/mail/fields/date_field.rbc +0 -712
  98. data/lib/mail/fields/from_field.rbc +0 -579
  99. data/lib/mail/fields/in_reply_to_field.rbc +0 -579
  100. data/lib/mail/fields/keywords_field.rbc +0 -979
  101. data/lib/mail/fields/message_id_field.rbc +0 -1008
  102. data/lib/mail/fields/mime_version_field.rbc +0 -1107
  103. data/lib/mail/fields/optional_field.rbc +0 -153
  104. data/lib/mail/fields/received_field.rbc +0 -1137
  105. data/lib/mail/fields/references_field.rbc +0 -574
  106. data/lib/mail/fields/reply_to_field.rbc +0 -579
  107. data/lib/mail/fields/resent_bcc_field.rbc +0 -579
  108. data/lib/mail/fields/resent_cc_field.rbc +0 -579
  109. data/lib/mail/fields/resent_date_field.rbc +0 -656
  110. data/lib/mail/fields/resent_from_field.rbc +0 -579
  111. data/lib/mail/fields/resent_message_id_field.rbc +0 -639
  112. data/lib/mail/fields/resent_sender_field.rbc +0 -731
  113. data/lib/mail/fields/resent_to_field.rbc +0 -579
  114. data/lib/mail/fields/return_path_field.rbc +0 -737
  115. data/lib/mail/fields/sender_field.rbc +0 -799
  116. data/lib/mail/fields/structured_field.rbc +0 -671
  117. data/lib/mail/fields/subject_field.rbc +0 -378
  118. data/lib/mail/fields/to_field.rbc +0 -579
  119. data/lib/mail/fields/unstructured_field.rbc +0 -2292
  120. data/lib/mail/fields.rbc +0 -782
  121. data/lib/mail/header.rbc +0 -3720
  122. data/lib/mail/mail.rbc +0 -2168
  123. data/lib/mail/message.rbc +0 -19034
  124. data/lib/mail/network/delivery_methods/file_delivery.rbc +0 -722
  125. data/lib/mail/network/delivery_methods/sendmail.rbc +0 -800
  126. data/lib/mail/network/delivery_methods/smtp.rbc +0 -1081
  127. data/lib/mail/network/delivery_methods/test_mailer.rbc +0 -552
  128. data/lib/mail/network/retriever_methods/pop3.rbc +0 -2447
  129. data/lib/mail/network.rbc +0 -236
  130. data/lib/mail/parsers/address_lists.rbc +0 -1307
  131. data/lib/mail/parsers/content_disposition.rbc +0 -5968
  132. data/lib/mail/parsers/content_location.rbc +0 -2166
  133. data/lib/mail/parsers/content_transfer_encoding.rbc +0 -2591
  134. data/lib/mail/parsers/content_type.rbc +0 -7949
  135. data/lib/mail/parsers/date_time.rbc +0 -1836
  136. data/lib/mail/parsers/envelope_from.rbc +0 -3106
  137. data/lib/mail/parsers/message_ids.rbc +0 -989
  138. data/lib/mail/parsers/mime_version.rbc +0 -2254
  139. data/lib/mail/parsers/phrase_lists.rbc +0 -989
  140. data/lib/mail/parsers/received.rbc +0 -1267
  141. data/lib/mail/parsers/rfc2045.rbc +0 -5614
  142. data/lib/mail/parsers/rfc2822.rbc +0 -74848
  143. data/lib/mail/parsers/rfc2822_obsolete.rbc +0 -55220
  144. data/lib/mail/part.rbc +0 -2314
  145. data/lib/mail/parts_list.rbc +0 -832
  146. data/lib/mail/patterns.rbc +0 -0
  147. data/lib/mail/utilities.rbc +0 -2377
  148. data/lib/mail/version.rbc +0 -450
  149. data/lib/mail/version_specific/ruby_1_8.rbc +0 -2496
  150. data/lib/mail.rbc +0 -1151
  151. data/lib/tasks/corpus.rake.compiled.rbc +0 -2195
  152. data/lib/tasks/treetop.rake.compiled.rbc +0 -297
@@ -35,6 +35,8 @@ module Mail
35
35
  Mail::Sendmail
36
36
  when :file
37
37
  Mail::FileDelivery
38
+ when :smtp_connection
39
+ Mail::SMTPConnection
38
40
  when :test
39
41
  Mail::TestMailer
40
42
  else
@@ -53,6 +55,10 @@ module Mail
53
55
  Mail::POP3
54
56
  when :pop3
55
57
  Mail::POP3
58
+ when :imap
59
+ Mail::IMAP
60
+ when :test
61
+ Mail::TestRetriever
56
62
  else
57
63
  method
58
64
  end
@@ -64,4 +70,4 @@ module Mail
64
70
 
65
71
  end
66
72
 
67
- end
73
+ end
@@ -0,0 +1,55 @@
1
+ # The following is imported from ruby 1.9.2 shellwords.rb
2
+ #
3
+ module Shellwords
4
+ # Escapes a string so that it can be safely used in a Bourne shell
5
+ # command line.
6
+ #
7
+ # Note that a resulted string should be used unquoted and is not
8
+ # intended for use in double quotes nor in single quotes.
9
+ #
10
+ # open("| grep #{Shellwords.escape(pattern)} file") { |pipe|
11
+ # # ...
12
+ # }
13
+ #
14
+ # +String#shellescape+ is a shorthand for this function.
15
+ #
16
+ # open("| grep #{pattern.shellescape} file") { |pipe|
17
+ # # ...
18
+ # }
19
+ #
20
+ def shellescape(str)
21
+ # An empty argument will be skipped, so return empty quotes.
22
+ return "''" if str.empty?
23
+
24
+ str = str.dup
25
+
26
+ # Process as a single byte sequence because not all shell
27
+ # implementations are multibyte aware.
28
+ str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/n, "\\\\\\1")
29
+
30
+ # A LF cannot be escaped with a backslash because a backslash + LF
31
+ # combo is regarded as line continuation and simply ignored.
32
+ str.gsub!(/\n/, "'\n'")
33
+
34
+ return str
35
+ end
36
+
37
+ module_function :shellescape
38
+
39
+ class << self
40
+ alias escape shellescape
41
+ end
42
+
43
+ end
44
+
45
+ class String
46
+ # call-seq:
47
+ # str.shellescape => string
48
+ #
49
+ # Escapes +str+ so that it can be safely used in a Bourne shell
50
+ # command line. See +Shellwords::shellescape+ for details.
51
+ #
52
+ def shellescape
53
+ Shellwords.escape(self)
54
+ end
55
+ end
@@ -0,0 +1,24 @@
1
+ module Net
2
+ class SMTP
3
+ # This is a backport of r30294 from ruby trunk because of a bug in net/smtp.
4
+ # http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&amp;revision=30294
5
+ #
6
+ # Fixed in what will be Ruby 1.9.3 - tlsconnect also does not exist in some early versions of ruby
7
+ remove_method :tlsconnect if defined?(Net::SMTP.new.tlsconnect)
8
+
9
+ def tlsconnect(s)
10
+ verified = false
11
+ s = OpenSSL::SSL::SSLSocket.new s, @ssl_context
12
+ logging "TLS connection started"
13
+ s.sync_close = true
14
+ s.connect
15
+ if @ssl_context.verify_mode != OpenSSL::SSL::VERIFY_NONE
16
+ s.post_connection_check(@address)
17
+ end
18
+ verified = true
19
+ s
20
+ ensure
21
+ s.close unless verified
22
+ end
23
+ end
24
+ end
@@ -104,7 +104,7 @@ module Mail
104
104
  # a.local #=> 'mikel'
105
105
  def local
106
106
  parse unless @parsed
107
- "#{obs_domain_list}#{get_local.strip}"
107
+ "#{obs_domain_list}#{get_local.strip}" if get_local
108
108
  end
109
109
 
110
110
  # Returns the domain part (the right hand side of the @ sign in the email address) of
@@ -184,11 +184,11 @@ module Mail
184
184
 
185
185
 
186
186
  def get_domain
187
- if tree.respond_to?(:angle_addr)
187
+ if tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:domain)
188
188
  @domain_text ||= tree.angle_addr.addr_spec.domain.text_value.strip
189
189
  elsif tree.respond_to?(:domain)
190
190
  @domain_text ||= tree.domain.text_value.strip
191
- elsif tree.respond_to?(:addr_spec)
191
+ elsif tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:domain)
192
192
  tree.addr_spec.domain.text_value.strip
193
193
  else
194
194
  nil
@@ -292,12 +292,12 @@ module Mail
292
292
  case
293
293
  when tree.respond_to?(:local_dot_atom_text)
294
294
  tree.local_dot_atom_text.text_value
295
- when tree.respond_to?(:angle_addr)
295
+ when tree.respond_to?(:angle_addr) && tree.angle_addr.respond_to?(:addr_spec) && tree.angle_addr.addr_spec.respond_to?(:local_part)
296
296
  tree.angle_addr.addr_spec.local_part.text_value
297
- when tree.respond_to?(:addr_spec)
297
+ when tree.respond_to?(:addr_spec) && tree.addr_spec.respond_to?(:local_part)
298
298
  tree.addr_spec.local_part.text_value
299
299
  else
300
- tree.local_part.text_value
300
+ tree && tree.respond_to?(:local_part) ? tree.local_part.text_value : nil
301
301
  end
302
302
  end
303
303
 
@@ -7,7 +7,7 @@ module Mail
7
7
  def initialize( string )
8
8
  parser = Mail::ContentDispositionParser.new
9
9
  if tree = parser.parse(cleaned(string))
10
- @disposition_type = tree.disposition_type.text_value
10
+ @disposition_type = tree.disposition_type.text_value.downcase
11
11
  @parameters = tree.parameters
12
12
  else
13
13
  raise Mail::Field::ParseError, "ContentDispositionElement can not parse |#{string}|\nReason was: #{parser.failure_reason}\n"
@@ -7,8 +7,8 @@ module Mail
7
7
  def initialize( string )
8
8
  parser = Mail::ContentTypeParser.new
9
9
  if tree = parser.parse(cleaned(string))
10
- @main_type = tree.main_type.text_value
11
- @sub_type = tree.sub_type.text_value
10
+ @main_type = tree.main_type.text_value.downcase
11
+ @sub_type = tree.sub_type.text_value.downcase
12
12
  @parameters = tree.parameters
13
13
  else
14
14
  raise Mail::Field::ParseError, "ContentTypeElement can not parse |#{string}|\nReason was: #{parser.failure_reason}\n"
@@ -6,12 +6,12 @@ module Mail
6
6
  end
7
7
 
8
8
  module Encodings
9
-
9
+
10
10
  include Mail::Patterns
11
11
  extend Mail::Utilities
12
12
 
13
13
  @transfer_encodings = {}
14
-
14
+
15
15
  # Register transfer encoding
16
16
  #
17
17
  # Example
@@ -20,23 +20,23 @@ module Mail
20
20
  def Encodings.register(name, cls)
21
21
  @transfer_encodings[get_name(name)] = cls
22
22
  end
23
-
23
+
24
24
  # Is the encoding we want defined?
25
- #
25
+ #
26
26
  # Example:
27
- #
27
+ #
28
28
  # Encodings.defined?(:base64) #=> true
29
29
  def Encodings.defined?( str )
30
30
  @transfer_encodings.include? get_name(str)
31
31
  end
32
-
32
+
33
33
  # Gets a defined encoding type, QuotedPrintable or Base64 for now.
34
- #
35
- # Each encoding needs to be defined as a Mail::Encodings::ClassName for
34
+ #
35
+ # Each encoding needs to be defined as a Mail::Encodings::ClassName for
36
36
  # this to work, allows us to add other encodings in the future.
37
- #
37
+ #
38
38
  # Example:
39
- #
39
+ #
40
40
  # Encodings.get_encoding(:base64) #=> Mail::Encodings::Base64
41
41
  def Encodings.get_encoding( str )
42
42
  @transfer_encodings[get_name(str)]
@@ -52,16 +52,16 @@ module Mail
52
52
 
53
53
  # Encodes a parameter value using URI Escaping, note the language field 'en' can
54
54
  # be set using Mail::Configuration, like so:
55
- #
55
+ #
56
56
  # Mail.defaults.do
57
57
  # param_encode_language 'jp'
58
58
  # end
59
59
  #
60
- # The character set used for encoding will either be the value of $KCODE for
60
+ # The character set used for encoding will either be the value of $KCODE for
61
61
  # Ruby < 1.9 or the encoding on the string passed in.
62
- #
62
+ #
63
63
  # Example:
64
- #
64
+ #
65
65
  # Mail::Encodings.param_encode("This is fun") #=> "us-ascii'en'This%20is%20fun"
66
66
  def Encodings.param_encode(str)
67
67
  case
@@ -75,9 +75,9 @@ module Mail
75
75
  end
76
76
 
77
77
  # Decodes a parameter value using URI Escaping.
78
- #
78
+ #
79
79
  # Example:
80
- #
80
+ #
81
81
  # Mail::Encodings.param_decode("This%20is%20fun", 'us-ascii') #=> "This is fun"
82
82
  #
83
83
  # str = Mail::Encodings.param_decode("This%20is%20fun", 'iso-8559-1')
@@ -86,14 +86,14 @@ module Mail
86
86
  def Encodings.param_decode(str, encoding)
87
87
  RubyVer.param_decode(str, encoding)
88
88
  end
89
-
89
+
90
90
  # Decodes or encodes a string as needed for either Base64 or QP encoding types in
91
91
  # the =?<encoding>?[QB]?<string>?=" format.
92
- #
92
+ #
93
93
  # The output type needs to be :decode to decode the input string or :encode to
94
94
  # encode the input string. The character set used for encoding will either be
95
95
  # the value of $KCODE for Ruby < 1.9 or the encoding on the string passed in.
96
- #
96
+ #
97
97
  # On encoding, will only send out Base64 encoded strings.
98
98
  def Encodings.decode_encode(str, output_type)
99
99
  case
@@ -110,39 +110,33 @@ module Mail
110
110
 
111
111
  # Decodes a given string as Base64 or Quoted Printable, depending on what
112
112
  # type it is.
113
- #
113
+ #
114
114
  # String has to be of the format =?<encoding>?[QB]?<string>?=
115
115
  def Encodings.value_decode(str)
116
116
  # Optimization: If there's no encoded-words in the string, just return it
117
117
  return str unless str.index("=?")
118
-
118
+
119
119
  str = str.gsub(/\?=(\s*)=\?/, '?==?') # Remove whitespaces between 'encoded-word's
120
120
 
121
121
  # Split on white-space boundaries with capture, so we capture the white-space as well
122
122
  str.split(/([ \t])/).map do |text|
123
- if text.index('=?') != 0
123
+ if text.index('=?') .nil?
124
124
  text
125
125
  else
126
126
  # Join QP encoded-words that are adjacent to avoid decoding partial chars
127
127
  text.gsub!(/\?\=\=\?.+?\?[Qq]\?/m, '') if text =~ /\?==\?/
128
-
128
+
129
129
  # Separate encoded-words with a space, so we can treat them one by one
130
130
  text.gsub!(/\?\=\=\?/, '?= =?')
131
-
132
131
  text.split(/ /).map do |word|
133
- case
134
- when word.to_str =~ /=\?.+\?[Bb]\?/m
135
- b_value_decode(word)
136
- when text.to_str =~ /=\?.+\?[Qq]\?/m
137
- q_value_decode(word)
138
- else
139
- word.to_str
132
+ word.to_str.
133
+ gsub( /=\?.+\?[Bb]\?.+\?=/m ) { |substr| b_value_decode(substr) }.
134
+ gsub( /=\?.+\?[Qq]\?.+\?=/m ) { |substr| q_value_decode(substr) }
140
135
  end
141
- end
142
136
  end
143
137
  end.join("")
144
138
  end
145
-
139
+
146
140
  # Takes an encoded string of the format =?<encoding>?[QB]?<string>?=
147
141
  def Encodings.unquote_and_convert_to(str, to_encoding)
148
142
  original_encoding, string = split_encoding_from_string( str )
@@ -153,8 +147,12 @@ module Mail
153
147
  output
154
148
  elsif original_encoding && to_encoding
155
149
  begin
156
- require 'iconv'
157
- Iconv.iconv(to_encoding, original_encoding, output).first
150
+ if RUBY_VERSION >= '1.9'
151
+ output.encode(to_encoding)
152
+ else
153
+ require 'iconv'
154
+ Iconv.iconv(to_encoding, original_encoding, output).first
155
+ end
158
156
  rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL
159
157
  # the 'from' parameter specifies a charset other than what the text
160
158
  # actually is...not much we can do in this case but just return the
@@ -168,7 +166,7 @@ module Mail
168
166
  output
169
167
  end
170
168
  end
171
-
169
+
172
170
  def Encodings.address_encode(address, charset = 'utf-8')
173
171
  if address.is_a?(Array)
174
172
  # loop back through for each element
@@ -180,13 +178,13 @@ module Mail
180
178
  end
181
179
 
182
180
  def Encodings.encode_non_usascii(address, charset)
183
- return address if address.ascii_only?
181
+ return address if address.ascii_only? or charset.nil?
184
182
  us_ascii = %Q{\x00-\x7f}
185
183
  # Encode any non usascii strings embedded inside of quotes
186
184
  address.gsub!(/(".*?[^#{us_ascii}].+?")/) { |s| Encodings.b_value_encode(unquote(s), charset) }
187
185
  # Then loop through all remaining items and encode as needed
188
186
  tokens = address.split(/\s/)
189
- tokens.each_with_index.map do |word, i|
187
+ map_with_index(tokens) do |word, i|
190
188
  if word.ascii_only?
191
189
  word
192
190
  else
@@ -198,60 +196,60 @@ module Mail
198
196
  end
199
197
  end.join(' ')
200
198
  end
201
-
199
+
202
200
  # Encode a string with Base64 Encoding and returns it ready to be inserted
203
201
  # as a value for a field, that is, in the =?<charset>?B?<string>?= format
204
202
  #
205
203
  # Example:
206
- #
207
- # Encodings.b_value_encode('This is あ string', 'UTF-8')
204
+ #
205
+ # Encodings.b_value_encode('This is あ string', 'UTF-8')
208
206
  # #=> "=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?="
209
207
  def Encodings.b_value_encode(str, encoding = nil)
210
208
  return str if str.to_s.ascii_only?
211
209
  string, encoding = RubyVer.b_value_encode(str, encoding)
212
- string.each_line.map do |str|
210
+ map_lines(string) do |str|
213
211
  "=?#{encoding}?B?#{str.chomp}?="
214
212
  end.join(" ")
215
213
  end
216
-
214
+
217
215
  # Encode a string with Quoted-Printable Encoding and returns it ready to be inserted
218
216
  # as a value for a field, that is, in the =?<charset>?Q?<string>?= format
219
217
  #
220
218
  # Example:
221
- #
222
- # Encodings.q_value_encode('This is あ string', 'UTF-8')
219
+ #
220
+ # Encodings.q_value_encode('This is あ string', 'UTF-8')
223
221
  # #=> "=?UTF-8?Q?This_is_=E3=81=82_string?="
224
222
  def Encodings.q_value_encode(str, encoding = nil)
225
223
  return str if str.to_s.ascii_only?
226
224
  string, encoding = RubyVer.q_value_encode(str, encoding)
227
225
  string.gsub!("=\r\n", '') # We already have limited the string to the length we want
228
- string.each_line.map do |str|
226
+ map_lines(string) do |str|
229
227
  "=?#{encoding}?Q?#{str.chomp.gsub(/ /, '_')}?="
230
228
  end.join(" ")
231
229
  end
232
-
230
+
233
231
  private
234
-
232
+
235
233
  # Decodes a Base64 string from the "=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=" format
236
- #
234
+ #
237
235
  # Example:
238
- #
239
- # Encodings.b_value_encode("=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=")
236
+ #
237
+ # Encodings.b_value_decode("=?UTF-8?B?VGhpcyBpcyDjgYIgc3RyaW5n?=")
240
238
  # #=> 'This is あ string'
241
239
  def Encodings.b_value_decode(str)
242
240
  RubyVer.b_value_decode(str)
243
241
  end
244
-
242
+
245
243
  # Decodes a Quoted-Printable string from the "=?UTF-8?Q?This_is_=E3=81=82_string?=" format
246
- #
244
+ #
247
245
  # Example:
248
- #
249
- # Encodings.b_value_encode("=?UTF-8?Q?This_is_=E3=81=82_string?=")
246
+ #
247
+ # Encodings.q_value_decode("=?UTF-8?Q?This_is_=E3=81=82_string?=")
250
248
  # #=> 'This is あ string'
251
249
  def Encodings.q_value_decode(str)
252
250
  RubyVer.q_value_decode(str).gsub(/_/, ' ')
253
251
  end
254
-
252
+
255
253
  def Encodings.split_encoding_from_string( str )
256
254
  match = str.match(/\=\?([^?]+)?\?[QB]\?(.+)?\?\=/mi)
257
255
  if match
@@ -260,7 +258,7 @@ module Mail
260
258
  nil
261
259
  end
262
260
  end
263
-
261
+
264
262
  def Encodings.find_encoding(str)
265
263
  RUBY_VERSION >= '1.9' ? str.encoding : $KCODE
266
264
  end
data/lib/mail/field.rb CHANGED
@@ -69,7 +69,8 @@ module Mail
69
69
  # Field.new('content-type', ['text', 'plain', {:charset => 'UTF-8'}])
70
70
  def initialize(name, value = nil, charset = 'utf-8')
71
71
  case
72
- when name =~ /:/ && value.blank? # Field.new("field-name: field data")
72
+ when name =~ /:/ # Field.new("field-name: field data")
73
+ charset = value unless value.blank?
73
74
  name, value = split(name)
74
75
  create_field(name, value, charset)
75
76
  when name !~ /:/ && value.blank? # Field.new("field-name")
@@ -9,7 +9,7 @@ module Mail
9
9
  include Enumerable
10
10
 
11
11
  def <<( new_field )
12
- current_entry = self.rindex(new_field.name)
12
+ current_entry = self.rindex(new_field)
13
13
  if current_entry
14
14
  self.insert((current_entry + 1), new_field)
15
15
  else
@@ -1,41 +1,42 @@
1
1
  # encoding: utf-8
2
2
  module Mail
3
3
  module CommonField # :nodoc:
4
+
4
5
  def name=(value)
5
6
  @name = value
6
7
  end
7
-
8
+
8
9
  def name
9
- @name
10
+ @name ||= nil
10
11
  end
11
-
12
+
12
13
  def value=(value)
13
14
  @length = nil
14
15
  @tree = nil
15
16
  @element = nil
16
17
  @value = value
17
18
  end
18
-
19
+
19
20
  def value
20
21
  @value
21
22
  end
22
-
23
+
23
24
  def to_s
24
25
  decoded
25
26
  end
26
-
27
+
27
28
  def default
28
29
  decoded
29
30
  end
30
-
31
+
31
32
  def field_length
32
33
  @length ||= "#{name}: #{encode(decoded)}".length
33
34
  end
34
-
35
+
35
36
  def responsible_for?( val )
36
37
  name.to_s.downcase == val.to_s.downcase
37
38
  end
38
-
39
+
39
40
  private
40
41
 
41
42
  def strip_field(field_name, value)
@@ -2,7 +2,7 @@
2
2
  module Mail
3
3
  module CommonMessageId # :nodoc:
4
4
  def element
5
- @element ||= Mail::MessageIdsElement.new(value)
5
+ @element ||= Mail::MessageIdsElement.new(value) unless value.blank?
6
6
  end
7
7
 
8
8
  def parse(val = value)
@@ -14,14 +14,15 @@ module Mail
14
14
  end
15
15
 
16
16
  def message_id
17
- element.message_id
17
+ element.message_id if element
18
18
  end
19
19
 
20
20
  def message_ids
21
- element.message_ids
21
+ element.message_ids if element
22
22
  end
23
23
 
24
24
  def default
25
+ return nil unless message_ids
25
26
  if message_ids.length == 1
26
27
  message_ids[0]
27
28
  else
@@ -32,11 +33,11 @@ module Mail
32
33
  private
33
34
 
34
35
  def do_encode(field_name)
35
- %Q{#{field_name}: #{message_ids.map { |m| "<#{m}>" }.join(', ')}\r\n}
36
+ %Q{#{field_name}: #{do_decode}\r\n}
36
37
  end
37
38
 
38
39
  def do_decode
39
- "#{message_ids.map { |m| "<#{m}>" }.join(', ')}"
40
+ "#{message_ids.map { |m| "<#{m}>" }.join(' ')}" if message_ids
40
41
  end
41
42
 
42
43
  end
@@ -13,13 +13,23 @@ module Mail
13
13
  include Mail::Utilities
14
14
 
15
15
  def [](key_name)
16
- pairs = select { |k,v| k =~ /^#{key_name}\*/ }
17
- pairs = pairs.to_a if RUBY_VERSION >= '1.9'
16
+ key_pattern = Regexp.escape(key_name.to_s)
17
+ pairs = []
18
+ exact = nil
19
+ each do |k,v|
20
+ if k =~ /^#{key_pattern}(\*|$)/i
21
+ if $1 == '*'
22
+ pairs << [k, v]
23
+ else
24
+ exact = k
25
+ end
26
+ end
27
+ end
18
28
  if pairs.empty? # Just dealing with a single value pair
19
- super(key_name)
29
+ super(exact || key_name)
20
30
  else # Dealing with a multiple value pair or a single encoded value pair
21
31
  string = pairs.sort { |a,b| a.first <=> b.first }.map { |v| v.last }.join('')
22
- if mt = string.match(/([\w\d\-]+)'(\w\w)'(.*)/)
32
+ if mt = string.match(/([\w\-]+)'(\w\w)'(.*)/)
23
33
  string = mt[3]
24
34
  encoding = mt[1]
25
35
  else
@@ -51,7 +51,7 @@ module Mail
51
51
  if parameters.length > 0
52
52
  p = ";\r\n\s#{parameters.encoded}\r\n"
53
53
  else
54
- p = ""
54
+ p = "\r\n"
55
55
  end
56
56
  "#{CAPITALIZED_FIELD}: #{disposition_type}" + p
57
57
  end