mail 2.2.1 → 2.2.2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mail might be problematic. Click here for more details.

data/CHANGELOG.rdoc CHANGED
@@ -1,20 +1,18 @@
1
- == Thu May 13 02:49:47 UTC 2010 Mikel Lindsaar <raasdnil@gmail.com>
2
-
3
- * Fixed Ruby 1.8.6 and 1.9.x incompatibilities because we were using each_with_index and each_line
4
- * Redid the folding to make it much much faster for long strings (the old one really crumbled with headers longer than 100,000 characters (Lars Pind <lars@pinds.com>)
5
- * Mail now only returns one encoded-word per line (Lars Pind <lars@pinds.com>)
6
- * Fixed all the previous issues with extra white-space and an extra = at the end of the encoded-words. (Lars Pind <lars@pinds.com>)
7
- * Make sure we can handle decoding of very long strings efficiently (Lars Pind <lars@pinds.com>)
8
- * Handle setting of charset through []= method, so we don't get the warning (Lars Pind <lars@pinds.com>)
9
- * Remove the trailing =\n that pack('M') adds (Lars Pind <lars@pinds.com>)
10
- * Handle multiple quoted words in Encodings.unquote_and_convert_to (Eric Kidd <git@randomhacks.net>)
11
- * Ruby 1.9: mark source encoding so it's usable with -Ks, -Ke, etc (Jeremy Kemper <jeremy@bitsweat.net>)
12
- * Add #include? to mail body for convenience (Maxim Chernyak <max@bitsonnet.com>)
13
- * Use Mail::TestMailer.deliveries in README example (John Trupiano <jtrupiano@gmail.com>)
14
- * Allow bundler to automatically build a gem directly from git (Eric Kidd <git@randomhacks.net>)
15
- * Added recursive parsing of attachments inside message/rfc822 parts (Ubiratan Pires Alberton <u.alberton@gmail.com>)
16
- * Adding #inline_content_id for attachments and parts (mikel)
17
- * Updating readme (mikel)
1
+ == Mon Jun 7 18:00:39 UTC 2010 Mikel Lindsaar <mikel@rubyx.com>
2
+
3
+ * Updating versioning so we only have one source, VERSION.yml (mikel)
4
+ * Changed activesupport dependency to 2.3.6 to fix #53, #64, and def #67. (Artem Titoulenko)
5
+ * Fixing typo in break_down_to.rb. (mikel)
6
+
7
+ == Mon Jun 7 18:07:16 UTC 2010 Mikel Lindsaar <mikel@rubyx.com>
8
+
9
+ * fixing a typo when generating docs. (Andrew Bloom)
10
+ * Changing \r\n\t to \r\n\s throughout mail (mikel)
11
+ * Handle multiple quoted words in Encodings.unquote_and_convert_to (Eric Kidd)
12
+ * Ruby 1.9: mark source encoding so it's usable with -Ks, -Ke, etc (Jeremy Kemper)
13
+ * Add #include? to mail body for convenience (Maxim Chernyak)
14
+ * Use Mail::TestMailer.deliveries in README example (John Trupiano)
15
+ * Allow bundler to automatically build a gem directly from git (Eric Kidd)
18
16
 
19
17
  == Sun Apr 11 07:49:15 UTC 2010 Mikel Lindsaar <raasdnil@gmail.com>
20
18
 
data/Rakefile CHANGED
@@ -33,7 +33,7 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
33
33
  rdoc.rdoc_dir = 'rdoc'
34
34
  rdoc.title = 'Mail'
35
35
  rdoc.options << '--line-numbers' << '--inline-source'
36
- rdoc.rdoc_files.include('README')
36
+ rdoc.rdoc_files.include('README.rdoc')
37
37
  rdoc.rdoc_files.include('lib/**/*.rb')
38
38
  end
39
39
 
data/VERSION.yml ADDED
@@ -0,0 +1,5 @@
1
+ ---
2
+ :patch: 2
3
+ :major: 2
4
+ :build:
5
+ :minor: 2
@@ -24,16 +24,4 @@ class String #:nodoc:
24
24
  unless method_defined?(:bytesize)
25
25
  alias :bytesize :length
26
26
  end
27
-
28
- unless ''.respond_to?(:lines)
29
- require "enumerator"
30
-
31
- def lines
32
- to_a.enum_for(:each)
33
- end
34
-
35
- end
36
-
37
27
  end
38
-
39
-
@@ -7,7 +7,6 @@ module Mail
7
7
 
8
8
  module Encodings
9
9
 
10
- require "enumerator"
11
10
  include Mail::Patterns
12
11
  extend Mail::Utilities
13
12
 
@@ -114,34 +113,24 @@ module Mail
114
113
  #
115
114
  # String has to be of the format =?<encoding>?[QB]?<string>?=
116
115
  def Encodings.value_decode(str)
117
- # Optimization: If there's no encoded-words in the string, just return it
118
- return str unless str.index("=?")
119
-
120
116
  str = str.gsub(/\?=(\s*)=\?/, '?==?') # Remove whitespaces between 'encoded-word's
121
117
 
122
- # Split on white-space boundaries with capture, so we capture the white-space as well
123
- str.split(/([ \t])/).map do |text|
124
- if text.index('=?') != 0
125
- text
126
- else
127
- # Join QP encoded-words that are adjacent to avoid decoding partial chars
128
- text.gsub!(/\?\=\=\?.+?\?[Qq]\?/m, '') if text =~ /\?==\?/
129
-
130
- # Separate encoded-words with a space, so we can treat them one by one
131
- text.gsub!(/\?\=\=\?/, '?= =?')
118
+ # Join QP encoded-words that are adjacent to avoid decoding partial chars
119
+ str.gsub!( /=\?==\?.+?\?[Qq]\?/m, '' ) if str =~ /\?==\?/
120
+
121
+ str.gsub(/(.*?)(=\?.*?\?.\?.*?\?=)|$/m) do # Grab the insides of each encoded-word
122
+ before = $1.to_s
123
+ text = $2.to_s
132
124
 
133
- text.split(/ /).map do |word|
134
- case
135
- when word.to_str =~ /=\?.+\?[Bb]\?/m
136
- b_value_decode(word)
137
- when text.to_str =~ /=\?.+\?[Qq]\?/m
138
- q_value_decode(word)
139
- else
140
- word.to_str
141
- end
142
- end
125
+ case
126
+ when text.to_str =~ /=\?.+\?[Bb]\?/m
127
+ before + b_value_decode(text)
128
+ when text.to_str =~ /=\?.+\?[Qq]\?/m
129
+ before + q_value_decode(text)
130
+ else
131
+ before + text
143
132
  end
144
- end.join("")
133
+ end
145
134
  end
146
135
 
147
136
  # Takes an encoded string of the format =?<encoding>?[QB]?<string>?=
@@ -187,8 +176,7 @@ module Mail
187
176
  address.gsub!(/(".*?[^#{us_ascii}].+?")/) { |s| Encodings.b_value_encode(unquote(s), charset) }
188
177
  # Then loop through all remaining items and encode as needed
189
178
  tokens = address.split(/\s/)
190
- # Need to use enum_for to stay 1.8.6 compatible
191
- tokens.enum_for(:each_with_index).map do |word, i|
179
+ tokens.each_with_index.map do |word, i|
192
180
  if word.ascii_only?
193
181
  word
194
182
  else
@@ -211,7 +199,7 @@ module Mail
211
199
  def Encodings.b_value_encode(str, encoding = nil)
212
200
  return str if str.to_s.ascii_only?
213
201
  string, encoding = RubyVer.b_value_encode(str, encoding)
214
- string.lines.map do |str|
202
+ string.each_line.map do |str|
215
203
  "=?#{encoding}?B?#{str.chomp}?="
216
204
  end.join(" ")
217
205
  end
@@ -226,8 +214,8 @@ module Mail
226
214
  def Encodings.q_value_encode(str, encoding = nil)
227
215
  return str if str.to_s.ascii_only?
228
216
  string, encoding = RubyVer.q_value_encode(str, encoding)
229
- string.gsub!("=\r\n", '') # We already have limited the string to the length we want
230
- string.lines.map do |str|
217
+ string.gsub!("=\r\n=", '=') # We already have limited the string to the length we want
218
+ string.each_line.map do |str|
231
219
  "=?#{encoding}?Q?#{str.chomp.gsub(/ /, '_')}?="
232
220
  end.join(" ")
233
221
  end
@@ -90,11 +90,11 @@ module Mail
90
90
  def do_encode(field_name)
91
91
  return '' if value.blank?
92
92
  address_array = tree.addresses.reject { |a| group_addresses.include?(a.encoded) }.compact.map { |a| a.encoded }
93
- address_text = address_array.join(", \r\n\t")
94
- group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.encoded }.join(", \r\n\t")};" }
95
- group_text = group_array.join(" \r\n\t")
93
+ address_text = address_array.join(", \r\n\s")
94
+ group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.encoded }.join(", \r\n\s")};" }
95
+ group_text = group_array.join(" \r\n\s")
96
96
  return_array = [address_text, group_text].reject { |a| a.blank? }
97
- "#{field_name}: #{return_array.join(", \r\n\t")}\r\n"
97
+ "#{field_name}: #{return_array.join(", \r\n\s")}\r\n"
98
98
  end
99
99
 
100
100
  def do_decode
@@ -36,7 +36,7 @@ module Mail
36
36
  key_name = "#{key_name}*"
37
37
  end
38
38
  %Q{#{key_name}=#{quote_token(value)}}
39
- end.join(";\r\n\t")
39
+ end.join(";\r\n\s")
40
40
  end
41
41
 
42
42
  def decoded
@@ -49,7 +49,7 @@ module Mail
49
49
  # TODO: Fix this up
50
50
  def encoded
51
51
  if parameters.length > 0
52
- p = ";\r\n\t#{parameters.encoded}\r\n"
52
+ p = ";\r\n\s#{parameters.encoded}\r\n"
53
53
  else
54
54
  p = ""
55
55
  end
@@ -109,7 +109,7 @@ module Mail
109
109
  # TODO: Fix this up
110
110
  def encoded
111
111
  if parameters.length > 0
112
- p = ";\r\n\t#{parameters.encoded}\r\n"
112
+ p = ";\r\n\s#{parameters.encoded}\r\n"
113
113
  else
114
114
  p = ""
115
115
  end
@@ -160,7 +160,7 @@ module Mail
160
160
  type = $1
161
161
  # Handles misquoted param values
162
162
  # e.g: application/octet-stream; name=archiveshelp1[1].htm
163
- # and: audio/x-midi;\r\n\tname=Part .exe
163
+ # and: audio/x-midi;\r\n\sname=Part .exe
164
164
  params = $2.to_s.split(/\s+/)
165
165
  params = params.map { |i| i.to_s.chomp.strip }
166
166
  params = params.map { |i| i.split(/\s*\=\s*/) }
@@ -102,77 +102,64 @@ module Mail
102
102
  # it is allowed elsewhere.
103
103
  def wrapped_value # :nodoc:
104
104
  @folded_line = []
105
- @unfolded_line = decoded.to_s.split(/[ \t]/)
105
+ @unfolded_line = decoded.to_s.clone
106
106
  fold("#{name}: ".length)
107
107
  wrap_lines(name, @folded_line)
108
108
  end
109
-
110
- # 6.2. Display of 'encoded-word's
111
- #
112
- # When displaying a particular header field that contains multiple
113
- # 'encoded-word's, any 'linear-white-space' that separates a pair of
114
- # adjacent 'encoded-word's is ignored. (This is to allow the use of
115
- # multiple 'encoded-word's to represent long strings of unencoded text,
116
- # without having to separate 'encoded-word's where spaces occur in the
117
- # unencoded text.)
109
+
118
110
  def wrap_lines(name, folded_lines)
119
111
  result = []
120
112
  index = 0
121
113
  result[index] = "#{name}: #{folded_lines.shift}"
122
- result.concat(folded_lines)
123
- result.join("\r\n\t")
114
+ folded_lines.each do |line|
115
+ if (result[index] + line).length < 77
116
+ result[index] << " " + line
117
+ else
118
+ result[index] << "\r\n\s"
119
+ index += 1
120
+ result[index] = line
121
+ end
122
+ end
123
+ result.join
124
124
  end
125
125
 
126
126
  def fold(prepend = 0) # :nodoc:
127
- encoding = @charset.to_s.upcase.gsub('_', '-')
128
- while !@unfolded_line.empty?
129
- encoded = false
130
- limit = 78 - prepend
131
- line = ""
132
- while !@unfolded_line.empty?
133
- break unless word = @unfolded_line.first.dup
134
- # Remember whether it was non-ascii before we encode it ('cause then we can't tell anymore)
135
- non_ascii = word.not_ascii_only?
136
- encoded_word = encode(word)
137
- # Skip to next line if we're going to go past the limit
138
- # Unless this is the first word, in which case we're going to add it anyway
139
- # Note: This means that a word that's longer than 998 characters is going to break the spec. Please fix if this is a problem for you.
140
- # (The fix, it seems, would be to use encoded-word encoding on it, because that way you can break it across multiple lines and
141
- # the linebreak will be ignored)
142
- break if !line.empty? && (line.length + encoded_word.length + 1 > limit)
143
- # If word was the first non-ascii word, we're going to make the entire line encoded and we're going to reduce the limit accordingly
144
- if non_ascii && !encoded
145
- encoded = true
146
- encoded_word_safify!(line)
147
- limit = limit - 8 - encoding.length # minus the =?...?Q?...?= part, the possible leading white-space, and the name of the encoding
148
- end
149
- # Remove the word from the queue ...
150
- @unfolded_line.shift
151
- # ... add it in encoded form to the current line
152
- line << " " unless line.empty?
153
- encoded_word_safify!(encoded_word) if encoded
154
- line << encoded_word
155
- end
156
- # Add leading whitespace if both this and the last line were encoded, because whitespace between two encoded-words is ignored when decoding
157
- line = " " + line if encoded && @folded_line.last && @folded_line.last.index('=?') == 0
158
- # Encode the line if necessary
159
- line = "=?#{encoding}?Q?#{line.gsub(/ /, '_')}?=" if encoded
160
- # Add the line to the output and reset the prepend
161
- @folded_line << line
162
- prepend = 0
127
+ # Get the last whitespace character, OR we'll just choose
128
+ # 78 if there is no whitespace, or 23 for non ascii:
129
+ # Each QP byte is 6 chars (=0A)
130
+ # Plus 18 for the =?encoding?Q?= ... ?=
131
+ # Plus 2 for the \r\n and 1 for the \s
132
+ # 80 - 2 - 1 - 18 = 59 / 6 ~= 10
133
+ @unfolded_line.ascii_only? ? (limit = 78 - prepend) : (limit = 10 - prepend)
134
+ # find the last white space character within the limit
135
+ if wspp = @unfolded_line.mb_chars.slice(0..limit) =~ /[ \t][^ \t]*$/
136
+ wrap = true
137
+ wspp = limit if wspp == 0
138
+ @folded_line << encode(@unfolded_line.mb_chars.slice!(0...wspp).strip.to_str)
139
+ @folded_line.flatten!
140
+ # if no last whitespace before the limit, find the first
141
+ elsif wspp = @unfolded_line.mb_chars =~ /[ \t][^ \t]/
142
+ wrap = true
143
+ wspp = limit if wspp == 0
144
+ @folded_line << encode(@unfolded_line.mb_chars.slice!(0...wspp).strip.to_str)
145
+ @folded_line.flatten!
146
+ # if no whitespace, don't wrap
147
+ else
148
+ wrap = false
149
+ end
150
+
151
+ if wrap && @unfolded_line.length > limit
152
+ fold
153
+ else
154
+ @folded_line << encode(@unfolded_line)
155
+ @folded_line.flatten!
163
156
  end
164
157
  end
165
-
158
+
166
159
  def encode(value)
167
- (value.not_ascii_only? ? [value].pack("M").gsub("=\n", '') : value).gsub("\r", "=0D").gsub("\n", "=0A")
168
- end
169
-
170
- def encoded_word_safify!(value)
171
- value.gsub!(/"/, '=22')
172
- value.gsub!(/\(/, '=28')
173
- value.gsub!(/\)/, '=29')
174
- value.gsub!(/\?/, '=3F')
175
- value.gsub!(/_/, '=5F')
160
+ value.gsub!("\r", "=0D")
161
+ value.gsub!("\n", "=0A")
162
+ Encodings.q_value_encode(value, @charset).split(" ")
176
163
  end
177
164
 
178
165
  end
data/lib/mail/message.rb CHANGED
@@ -1180,8 +1180,6 @@ module Mail
1180
1180
  self.body = value
1181
1181
  elsif name.to_s =~ /content[-_]type/i
1182
1182
  header[name] = value
1183
- elsif name.to_s == 'charset'
1184
- self.charset = value
1185
1183
  else
1186
1184
  header[name] = value
1187
1185
  end
data/lib/mail/version.rb CHANGED
@@ -1,10 +1,16 @@
1
1
  # encoding: utf-8
2
2
  module Mail
3
3
  module VERSION
4
- MAJOR = 2
5
- MINOR = 2
6
- TINY = 1
4
+
5
+ def self.version
6
+ YAML.load_file(File.join(File.dirname(__FILE__), '../../', 'VERSION.yml'))
7
+ end
8
+
9
+ MAJOR = version[:major]
10
+ MINOR = version[:minor]
11
+ PATCH = version[:patch]
12
+ BUILD = version[:build]
7
13
 
8
- STRING = [MAJOR, MINOR, TINY].join('.')
14
+ STRING = [MAJOR, MINOR, PATCH, BUILD].compact.join('.')
9
15
  end
10
16
  end
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 2
7
7
  - 2
8
- - 1
9
- version: 2.2.1
8
+ - 2
9
+ version: 2.2.2
10
10
  platform: ruby
11
11
  authors:
12
12
  - Mikel Lindsaar
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-05-13 00:00:00 +10:00
17
+ date: 2010-06-07 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -27,8 +27,8 @@ dependencies:
27
27
  segments:
28
28
  - 2
29
29
  - 3
30
- - 4
31
- version: 2.3.4
30
+ - 6
31
+ version: 2.3.6
32
32
  type: :runtime
33
33
  version_requirements: *id001
34
34
  - !ruby/object:Gem::Dependency
@@ -71,6 +71,7 @@ files:
71
71
  - README.rdoc
72
72
  - Rakefile
73
73
  - TODO.rdoc
74
+ - VERSION.yml
74
75
  - lib/mail/attachments_list.rb
75
76
  - lib/mail/body.rb
76
77
  - lib/mail/configuration.rb