mail 2.6.3 → 2.6.4.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rdoc +22 -0
  3. data/Gemfile +1 -4
  4. data/MIT-LICENSE +1 -1
  5. data/README.md +38 -2
  6. data/Rakefile +2 -2
  7. data/lib/mail.rb +8 -2
  8. data/lib/mail/body.rb +4 -4
  9. data/lib/mail/check_delivery_params.rb +3 -3
  10. data/lib/mail/constants.rb +2 -1
  11. data/lib/mail/core_extensions/nil.rb +0 -6
  12. data/lib/mail/core_extensions/string.rb +0 -6
  13. data/lib/mail/elements/address.rb +7 -7
  14. data/lib/mail/encodings.rb +25 -28
  15. data/lib/mail/encodings/8bit.rb +5 -0
  16. data/lib/mail/encodings/base64.rb +5 -0
  17. data/lib/mail/encodings/quoted_printable.rb +6 -1
  18. data/lib/mail/encodings/transfer_encoding.rb +26 -17
  19. data/lib/mail/field.rb +18 -4
  20. data/lib/mail/fields/bcc_field.rb +14 -3
  21. data/lib/mail/fields/cc_field.rb +0 -1
  22. data/lib/mail/fields/common/common_address.rb +7 -7
  23. data/lib/mail/fields/common/common_date.rb +1 -1
  24. data/lib/mail/fields/common/common_field.rb +1 -1
  25. data/lib/mail/fields/common/common_message_id.rb +2 -2
  26. data/lib/mail/fields/content_disposition_field.rb +11 -11
  27. data/lib/mail/fields/content_id_field.rb +2 -2
  28. data/lib/mail/fields/content_location_field.rb +1 -1
  29. data/lib/mail/fields/content_transfer_encoding_field.rb +1 -1
  30. data/lib/mail/fields/content_type_field.rb +1 -1
  31. data/lib/mail/fields/date_field.rb +1 -1
  32. data/lib/mail/fields/from_field.rb +0 -1
  33. data/lib/mail/fields/keywords_field.rb +1 -2
  34. data/lib/mail/fields/message_id_field.rb +1 -1
  35. data/lib/mail/fields/mime_version_field.rb +2 -2
  36. data/lib/mail/fields/received_field.rb +3 -3
  37. data/lib/mail/fields/reply_to_field.rb +0 -1
  38. data/lib/mail/fields/resent_bcc_field.rb +0 -1
  39. data/lib/mail/fields/resent_cc_field.rb +0 -1
  40. data/lib/mail/fields/resent_date_field.rb +1 -1
  41. data/lib/mail/fields/resent_from_field.rb +0 -1
  42. data/lib/mail/fields/resent_sender_field.rb +0 -1
  43. data/lib/mail/fields/resent_to_field.rb +0 -1
  44. data/lib/mail/fields/return_path_field.rb +0 -1
  45. data/lib/mail/fields/sender_field.rb +0 -1
  46. data/lib/mail/fields/to_field.rb +0 -1
  47. data/lib/mail/fields/unstructured_field.rb +1 -1
  48. data/lib/mail/header.rb +3 -3
  49. data/lib/mail/matchers/attachment_matchers.rb +28 -0
  50. data/lib/mail/matchers/has_sent_mail.rb +30 -7
  51. data/lib/mail/message.rb +15 -21
  52. data/lib/mail/multibyte/unicode.rb +20 -16
  53. data/lib/mail/parsers/address_lists_parser.rb +1 -1
  54. data/lib/mail/parsers/content_disposition_parser.rb +1 -1
  55. data/lib/mail/parsers/content_location_parser.rb +1 -1
  56. data/lib/mail/parsers/content_transfer_encoding_parser.rb +1 -1
  57. data/lib/mail/parsers/envelope_from_parser.rb +1 -1
  58. data/lib/mail/parsers/message_ids_parser.rb +1 -1
  59. data/lib/mail/parsers/mime_version_parser.rb +1 -1
  60. data/lib/mail/part.rb +4 -2
  61. data/lib/mail/parts_list.rb +25 -8
  62. data/lib/mail/utilities.rb +15 -0
  63. data/lib/mail/values/unicode_tables.dat +0 -0
  64. data/lib/mail/version.rb +2 -2
  65. data/lib/mail/version_specific/ruby_1_8.rb +10 -4
  66. data/lib/mail/version_specific/ruby_1_9.rb +39 -10
  67. metadata +8 -8
  68. data/lib/mail/core_extensions/object.rb +0 -13
@@ -23,30 +23,39 @@ module Mail
23
23
  raise "Unimplemented"
24
24
  end
25
25
 
26
+ def self.compatible_input?(str)
27
+ true
28
+ end
29
+
26
30
  def self.to_s
27
31
  self::NAME
28
32
  end
29
33
 
30
34
  def self.get_best_compatible(source_encoding, str)
31
- if self.can_transport? source_encoding then
32
- source_encoding
35
+ if self.can_transport?(source_encoding) && self.compatible_input?(str)
36
+ source_encoding
33
37
  else
34
- choices = []
35
- Encodings.get_all.each do |enc|
36
- choices << enc if self.can_transport? enc and enc.can_encode? source_encoding
37
- end
38
- best = nil
39
- best_cost = 100
40
- choices.each do |enc|
41
- this_cost = enc.cost str
42
- if this_cost < best_cost then
43
- best_cost = this_cost
44
- best = enc
45
- elsif this_cost == best_cost then
46
- best = enc if enc::PRIORITY < best::PRIORITY
47
- end
38
+ choices = Encodings.get_all.select do |enc|
39
+ self.can_transport?(enc) && enc.can_encode?(source_encoding)
40
+ end
41
+
42
+ best = nil
43
+ best_cost = nil
44
+
45
+ choices.each do |enc|
46
+ # If the current choice cannot be transported safely,
47
+ # give priority to other choices but allow it to be used as a fallback.
48
+ this_cost = enc.cost(str) if enc.compatible_input?(str)
49
+
50
+ if !best_cost || (this_cost && this_cost < best_cost)
51
+ best_cost = this_cost
52
+ best = enc
53
+ elsif this_cost == best_cost
54
+ best = enc if enc::PRIORITY < best::PRIORITY
48
55
  end
49
- best
56
+ end
57
+
58
+ best
50
59
  end
51
60
  end
52
61
 
@@ -114,11 +114,11 @@ module Mail
114
114
  def initialize(name, value = nil, charset = 'utf-8')
115
115
  case
116
116
  when name.index(COLON) # Field.new("field-name: field data")
117
- @charset = value.blank? ? charset : value
117
+ @charset = Utilities.blank?(value) ? charset : value
118
118
  @name = name[FIELD_PREFIX]
119
119
  @raw_value = name
120
120
  @value = nil
121
- when value.blank? # Field.new("field-name")
121
+ when Utilities.blank?(value) # Field.new("field-name")
122
122
  @name = name
123
123
  @value = nil
124
124
  @raw_value = nil
@@ -168,15 +168,19 @@ module Mail
168
168
  end
169
169
 
170
170
  def same( other )
171
+ return false unless other.kind_of?(self.class)
171
172
  match_to_s(other.name, self.name)
172
173
  end
173
174
 
175
+ def ==( other )
176
+ return false unless other.kind_of?(self.class)
177
+ match_to_s(other.name, self.name) && match_to_s(other.value, self.value)
178
+ end
179
+
174
180
  def responsible_for?( val )
175
181
  name.to_s.casecmp(val.to_s) == 0
176
182
  end
177
183
 
178
- alias_method :==, :same
179
-
180
184
  def <=>( other )
181
185
  self.field_order_id <=> other.field_order_id
182
186
  end
@@ -189,6 +193,16 @@ module Mail
189
193
  field.send(name, *args, &block)
190
194
  end
191
195
 
196
+ if RUBY_VERSION >= '1.9.2'
197
+ def respond_to_missing?(method_name, include_private)
198
+ field.respond_to?(method_name, include_private) || super
199
+ end
200
+ else
201
+ def respond_to?(method_name, include_private = false)
202
+ field.respond_to?(method_name, include_private) || super
203
+ end
204
+ end
205
+
192
206
  FIELD_ORDER = %w[ return-path received
193
207
  resent-date resent-from resent-sender resent-to
194
208
  resent-cc resent-bcc resent-message-id
@@ -39,13 +39,24 @@ module Mail
39
39
  def initialize(value = '', charset = 'utf-8')
40
40
  @charset = charset
41
41
  super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
42
- self.parse
43
42
  self
44
43
  end
45
44
 
46
- # Bcc field should never be :encoded
45
+ def include_in_headers=(include_in_headers)
46
+ @include_in_headers = include_in_headers
47
+ end
48
+
49
+ def include_in_headers
50
+ defined?(@include_in_headers) ? @include_in_headers : self.include_in_headers = false
51
+ end
52
+
53
+ # Bcc field should not be :encoded by default
47
54
  def encoded
48
- ''
55
+ if include_in_headers
56
+ do_encode(CAPITALIZED_FIELD)
57
+ else
58
+ ''
59
+ end
49
60
  end
50
61
 
51
62
  def decoded
@@ -39,7 +39,6 @@ module Mail
39
39
  def initialize(value = nil, charset = 'utf-8')
40
40
  self.charset = charset
41
41
  super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
42
- self.parse
43
42
  self
44
43
  end
45
44
 
@@ -5,7 +5,7 @@ module Mail
5
5
  module CommonAddress # :nodoc:
6
6
 
7
7
  def parse(val = value)
8
- unless val.blank?
8
+ unless Utilities.blank?(val)
9
9
  @address_list = AddressList.new(encode_if_needed(val))
10
10
  else
11
11
  nil
@@ -84,10 +84,10 @@ module Mail
84
84
  case
85
85
  when val.nil?
86
86
  raise ArgumentError, "Need to pass an address to <<"
87
- when val.blank?
87
+ when Utilities.blank?(val)
88
88
  parse(encoded)
89
89
  else
90
- self.value = [self.value, val].reject {|a| a.blank? }.join(", ")
90
+ self.value = [self.value, val].reject {|a| Utilities.blank?(a) }.join(", ")
91
91
  end
92
92
  end
93
93
 
@@ -99,22 +99,22 @@ module Mail
99
99
  private
100
100
 
101
101
  def do_encode(field_name)
102
- return '' if value.blank?
102
+ return '' if Utilities.blank?(value)
103
103
  address_array = address_list.addresses.reject { |a| encoded_group_addresses.include?(a.encoded) }.compact.map { |a| a.encoded }
104
104
  address_text = address_array.join(", \r\n\s")
105
105
  group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.encoded }.join(", \r\n\s")};" }
106
106
  group_text = group_array.join(" \r\n\s")
107
- return_array = [address_text, group_text].reject { |a| a.blank? }
107
+ return_array = [address_text, group_text].reject { |a| Utilities.blank?(a) }
108
108
  "#{field_name}: #{return_array.join(", \r\n\s")}\r\n"
109
109
  end
110
110
 
111
111
  def do_decode
112
- return nil if value.blank?
112
+ return nil if Utilities.blank?(value)
113
113
  address_array = address_list.addresses.reject { |a| decoded_group_addresses.include?(a.decoded) }.map { |a| a.decoded }
114
114
  address_text = address_array.join(", ")
115
115
  group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.decoded }.join(", ")};" }
116
116
  group_text = group_array.join(" ")
117
- return_array = [address_text, group_text].reject { |a| a.blank? }
117
+ return_array = [address_text, group_text].reject { |a| Utilities.blank?(a) }
118
118
  return_array.join(", ")
119
119
  end
120
120
 
@@ -11,7 +11,7 @@ module Mail
11
11
  end
12
12
 
13
13
  def parse(val = value)
14
- unless val.blank?
14
+ unless Utilities.blank?(val)
15
15
  @element = Mail::DateTimeElement.new(val)
16
16
  else
17
17
  nil
@@ -44,7 +44,7 @@ module Mail
44
44
  if value.is_a?(Array)
45
45
  value
46
46
  else
47
- value.to_s.sub(/#{field_name}:\s+/i, EMPTY)
47
+ value.to_s.sub(/\A#{field_name}:\s+/i, EMPTY)
48
48
  end
49
49
  end
50
50
 
@@ -2,11 +2,11 @@
2
2
  module Mail
3
3
  module CommonMessageId # :nodoc:
4
4
  def element
5
- @element ||= Mail::MessageIdsElement.new(value) unless value.blank?
5
+ @element ||= Mail::MessageIdsElement.new(value) unless Utilities.blank?(value)
6
6
  end
7
7
 
8
8
  def parse(val = value)
9
- unless val.blank?
9
+ unless Utilities.blank?(val)
10
10
  @element = Mail::MessageIdsElement.new(val)
11
11
  else
12
12
  nil
@@ -3,10 +3,10 @@ require 'mail/fields/common/parameter_hash'
3
3
 
4
4
  module Mail
5
5
  class ContentDispositionField < StructuredField
6
-
6
+
7
7
  FIELD_NAME = 'content-disposition'
8
8
  CAPITALIZED_FIELD = 'Content-Disposition'
9
-
9
+
10
10
  def initialize(value = nil, charset = 'utf-8')
11
11
  self.charset = charset
12
12
  ensure_filename_quoted(value)
@@ -14,13 +14,13 @@ module Mail
14
14
  self.parse
15
15
  self
16
16
  end
17
-
17
+
18
18
  def parse(val = value)
19
- unless val.blank?
19
+ unless Utilities.blank?(val)
20
20
  @element = Mail::ContentDispositionElement.new(val)
21
21
  end
22
22
  end
23
-
23
+
24
24
  def element
25
25
  @element ||= Mail::ContentDispositionElement.new(value)
26
26
  end
@@ -28,20 +28,20 @@ module Mail
28
28
  def disposition_type
29
29
  element.disposition_type
30
30
  end
31
-
31
+
32
32
  def parameters
33
33
  @parameters = ParameterHash.new
34
- element.parameters.each { |p| @parameters.merge!(p) }
34
+ element.parameters.each { |p| @parameters.merge!(p) } unless element.parameters.nil?
35
35
  @parameters
36
36
  end
37
37
 
38
38
  def filename
39
39
  case
40
- when !parameters['filename'].blank?
40
+ when !Utilities.blank?(parameters['filename'])
41
41
  @filename = parameters['filename']
42
- when !parameters['name'].blank?
42
+ when !Utilities.blank?(parameters['name'])
43
43
  @filename = parameters['name']
44
- else
44
+ else
45
45
  @filename = nil
46
46
  end
47
47
  @filename
@@ -56,7 +56,7 @@ module Mail
56
56
  end
57
57
  "#{CAPITALIZED_FIELD}: #{disposition_type}" + p
58
58
  end
59
-
59
+
60
60
  def decoded
61
61
  if parameters.length > 0
62
62
  p = "; #{parameters.decoded}"
@@ -11,7 +11,7 @@ module Mail
11
11
  def initialize(value = nil, charset = 'utf-8')
12
12
  self.charset = charset
13
13
  @uniq = 1
14
- if value.blank?
14
+ if Utilities.blank?(value)
15
15
  value = generate_content_id
16
16
  else
17
17
  value = strip_field(FIELD_NAME, value)
@@ -22,7 +22,7 @@ module Mail
22
22
  end
23
23
 
24
24
  def parse(val = value)
25
- unless val.blank?
25
+ unless Utilities.blank?(val)
26
26
  @element = Mail::MessageIdsElement.new(val)
27
27
  end
28
28
  end
@@ -16,7 +16,7 @@ module Mail
16
16
  end
17
17
 
18
18
  def parse(val = value)
19
- unless val.blank?
19
+ unless Utilities.blank?(val)
20
20
  @element = Mail::ContentLocationElement.new(val)
21
21
  end
22
22
  end
@@ -18,7 +18,7 @@ module Mail
18
18
  end
19
19
 
20
20
  def parse(val = value)
21
- unless val.blank?
21
+ unless Utilities.blank?(val)
22
22
  @element = Mail::ContentTransferEncodingElement.new(val)
23
23
  end
24
24
  end
@@ -26,7 +26,7 @@ module Mail
26
26
  end
27
27
 
28
28
  def parse(val = value)
29
- unless val.blank?
29
+ unless Utilities.blank?(val)
30
30
  self.value = val
31
31
  @element = nil
32
32
  element
@@ -33,7 +33,7 @@ module Mail
33
33
 
34
34
  def initialize(value = nil, charset = 'utf-8')
35
35
  self.charset = charset
36
- if value.blank?
36
+ if Utilities.blank?(value)
37
37
  value = ::DateTime.now.strftime('%a, %d %b %Y %H:%M:%S %z')
38
38
  else
39
39
  value = strip_field(FIELD_NAME, value)
@@ -39,7 +39,6 @@ module Mail
39
39
  def initialize(value = nil, charset = 'utf-8')
40
40
  self.charset = charset
41
41
  super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
42
- self.parse
43
42
  self
44
43
  end
45
44
 
@@ -10,12 +10,11 @@ module Mail
10
10
  def initialize(value = nil, charset = 'utf-8')
11
11
  self.charset = charset
12
12
  super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
13
- self.parse
14
13
  self
15
14
  end
16
15
 
17
16
  def parse(val = value)
18
- unless val.blank?
17
+ unless Utilities.blank?(val)
19
18
  @phrase_list ||= PhraseList.new(value)
20
19
  end
21
20
  end
@@ -41,7 +41,7 @@ module Mail
41
41
  def initialize(value = nil, charset = 'utf-8')
42
42
  self.charset = charset
43
43
  @uniq = 1
44
- if value.blank?
44
+ if Utilities.blank?(value)
45
45
  self.name = CAPITALIZED_FIELD
46
46
  self.value = generate_message_id
47
47
  else
@@ -10,7 +10,7 @@ module Mail
10
10
 
11
11
  def initialize(value = nil, charset = 'utf-8')
12
12
  self.charset = charset
13
- if value.blank?
13
+ if Utilities.blank?(value)
14
14
  value = '1.0'
15
15
  end
16
16
  super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
@@ -20,7 +20,7 @@ module Mail
20
20
  end
21
21
 
22
22
  def parse(val = value)
23
- unless val.blank?
23
+ unless Utilities.blank?(val)
24
24
  @element = Mail::MimeVersionElement.new(val)
25
25
  end
26
26
  end
@@ -34,7 +34,7 @@ module Mail
34
34
  end
35
35
 
36
36
  def parse(val = value)
37
- unless val.blank?
37
+ unless Utilities.blank?(val)
38
38
  @element = Mail::ReceivedElement.new(val)
39
39
  end
40
40
  end
@@ -56,7 +56,7 @@ module Mail
56
56
  end
57
57
 
58
58
  def encoded
59
- if value.blank?
59
+ if Utilities.blank?(value)
60
60
  "#{CAPITALIZED_FIELD}: \r\n"
61
61
  else
62
62
  "#{CAPITALIZED_FIELD}: #{info}; #{formatted_date}\r\n"
@@ -64,7 +64,7 @@ module Mail
64
64
  end
65
65
 
66
66
  def decoded
67
- if value.blank?
67
+ if Utilities.blank?(value)
68
68
  ""
69
69
  else
70
70
  "#{info}; #{formatted_date}"
@@ -39,7 +39,6 @@ module Mail
39
39
  def initialize(value = nil, charset = 'utf-8')
40
40
  self.charset = charset
41
41
  super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
42
- self.parse
43
42
  self
44
43
  end
45
44
 
@@ -39,7 +39,6 @@ module Mail
39
39
  def initialize(value = nil, charset = 'utf-8')
40
40
  self.charset = charset
41
41
  super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
42
- self.parse
43
42
  self
44
43
  end
45
44