mail 2.2.0 → 2.2.1
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 +18 -0
- data/README.rdoc +15 -15
- data/Rakefile +3 -31
- data/lib/mail/attachments_list.rb +15 -10
- data/lib/mail/body.rb +14 -0
- data/lib/mail/core_extensions/string.rb +12 -0
- data/lib/mail/encodings.rb +31 -19
- data/lib/mail/fields/unstructured_field.rb +58 -45
- data/lib/mail/message.rb +2 -0
- data/lib/mail/part.rb +6 -1
- data/lib/mail/patterns.rb +1 -0
- data/lib/mail/utilities.rb +29 -1
- data/lib/mail/version.rb +1 -1
- data/lib/mail/version_specific/ruby_1_8.rb +15 -0
- data/lib/mail/version_specific/ruby_1_9.rb +11 -0
- metadata +16 -16
data/CHANGELOG.rdoc
CHANGED
@@ -1,3 +1,21 @@
|
|
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)
|
18
|
+
|
1
19
|
== Sun Apr 11 07:49:15 UTC 2010 Mikel Lindsaar <raasdnil@gmail.com>
|
2
20
|
|
3
21
|
* Lots of updates on encoding and decoding of headers and unstructured fields. This
|
data/README.rdoc
CHANGED
@@ -27,17 +27,15 @@ you are doing, you can fiddle with every last bit of your email directly.
|
|
27
27
|
|
28
28
|
Mail is tested and works on the following platforms:
|
29
29
|
|
30
|
-
*
|
31
|
-
*
|
32
|
-
* ruby-1.8.7-
|
33
|
-
* ruby-1.9.1-head [ x86_64 ]
|
34
|
-
* ruby-1.9.
|
30
|
+
* jruby-1.4.0 [ [x86_64-java] ]
|
31
|
+
* ree-1.8.7-2010.01 [ x86_64 ]
|
32
|
+
* ruby-1.8.7-p249 [ x86_64 ]
|
33
|
+
* ruby-1.9.1-head [ x86_64 ] (10 April 2010)
|
34
|
+
* ruby-1.9.2-head [ x86_64 ] (10 April 2010)
|
35
35
|
|
36
|
-
Mail seems to work fine on JRuby as well, however
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
* jruby-1.4.0 [x86_64-java]
|
36
|
+
Mail seems to work fine on JRuby as well, however there is some weird QP
|
37
|
+
problem that only shows up while running the specs, running it directly
|
38
|
+
works fine.... weird. Any jRuby gurus who want to help out, please do.
|
41
39
|
|
42
40
|
== Discussion
|
43
41
|
|
@@ -52,6 +50,8 @@ the Google Group http://groups.google.com/group/mail-ruby
|
|
52
50
|
* Support for reading multipart/report emails & getting details from such
|
53
51
|
* Support for multibyte emails - needs quite a lot of work and testing
|
54
52
|
* Wrappers for File, Net/POP3, Net/SMTP
|
53
|
+
* Auto encoding of non US-ASCII header fields
|
54
|
+
* Auto encoding of non US-ASCII bodies
|
55
55
|
|
56
56
|
Mail is RFC2822 compliant now, that is, it can parse and generate valid US-ASCII
|
57
57
|
emails. There are a few obsoleted syntax emails that it will have problems with, but
|
@@ -108,7 +108,7 @@ may or may not be a problem for you.
|
|
108
108
|
|
109
109
|
If you want to install mail manually, you can download the gem from github and do:
|
110
110
|
|
111
|
-
# gem install mail-
|
111
|
+
# gem install mail-2.2.0.gem
|
112
112
|
|
113
113
|
== Encodings
|
114
114
|
|
@@ -512,7 +512,7 @@ sending emails, the TestMailer can do this for you.
|
|
512
512
|
delivery_method :test
|
513
513
|
end
|
514
514
|
=> #<Mail::Configuration:0x19345a8 @delivery_method=Mail::TestMailer>
|
515
|
-
Mail.deliveries
|
515
|
+
Mail::TestMailer.deliveries
|
516
516
|
=> []
|
517
517
|
Mail.deliver do
|
518
518
|
to 'mikel@me.com'
|
@@ -521,11 +521,11 @@ sending emails, the TestMailer can do this for you.
|
|
521
521
|
body 'hello'
|
522
522
|
end
|
523
523
|
=> #<Mail::Message:0x19284ec ...
|
524
|
-
Mail.deliveries.length
|
524
|
+
Mail::TestMailer.deliveries.length
|
525
525
|
=> 1
|
526
|
-
Mail.deliveries.first
|
526
|
+
Mail::TestMailer.deliveries.first
|
527
527
|
=> #<Mail::Message:0x19284ec ...
|
528
|
-
Mail.deliveries.clear
|
528
|
+
Mail::TestMailer.deliveries.clear
|
529
529
|
=> []
|
530
530
|
|
531
531
|
== Excerpts from TREC Spam Corpus 2005
|
data/Rakefile
CHANGED
@@ -1,34 +1,13 @@
|
|
1
1
|
require File.expand_path('../spec/environment', __FILE__)
|
2
2
|
|
3
3
|
require 'rake/rdoctask'
|
4
|
-
require 'rake/gempackagetask'
|
5
4
|
require 'rake/testtask'
|
6
5
|
require 'spec/rake/spectask'
|
7
6
|
require 'cucumber/rake/task'
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
s.author = "Mike Lindsaar"
|
13
|
-
s.email = "raasdnil@gmail.com"
|
14
|
-
s.homepage = "http://github.com/mikel/mail"
|
15
|
-
s.description = "A really Ruby Mail handler."
|
16
|
-
s.summary = "Mail provides a nice Ruby DSL for making, sending and reading emails."
|
17
|
-
|
18
|
-
s.platform = Gem::Platform::RUBY
|
19
|
-
s.has_rdoc = true
|
20
|
-
s.extra_rdoc_files = ["README.rdoc", "CHANGELOG.rdoc", "TODO.rdoc"]
|
21
|
-
|
22
|
-
s.add_dependency('activesupport', ">= 2.3.4")
|
23
|
-
s.add_dependency('mime-types')
|
24
|
-
s.add_dependency('treetop', '>= 1.4.5')
|
25
|
-
|
26
|
-
s.require_path = 'lib'
|
27
|
-
s.files = %w(README.rdoc Rakefile TODO.rdoc) + Dir.glob("lib/**/*")
|
28
|
-
end
|
29
|
-
|
30
|
-
Rake::GemPackageTask.new(spec) do |pkg|
|
31
|
-
pkg.gem_spec = spec
|
8
|
+
desc "Build a gem file"
|
9
|
+
task :build do
|
10
|
+
system "gem build mail.gemspec"
|
32
11
|
end
|
33
12
|
|
34
13
|
task :default => :spec
|
@@ -50,13 +29,6 @@ Spec::Rake::SpecTask.new(:spec) do |t|
|
|
50
29
|
t.libs << "#{File.dirname(__FILE__)}/spec/mail"
|
51
30
|
end
|
52
31
|
|
53
|
-
Rake::TestTask.new(:test) do |t|
|
54
|
-
t.libs << 'test'
|
55
|
-
t.pattern = 'test/**/tc_*.rb'
|
56
|
-
t.verbose = true
|
57
|
-
t.warning = false
|
58
|
-
end
|
59
|
-
|
60
32
|
Rake::RDocTask.new(:rdoc) do |rdoc|
|
61
33
|
rdoc.rdoc_dir = 'rdoc'
|
62
34
|
rdoc.title = 'Mail'
|
@@ -1,10 +1,12 @@
|
|
1
1
|
module Mail
|
2
2
|
class AttachmentsList < Array
|
3
|
-
|
3
|
+
|
4
4
|
def initialize(parts_list)
|
5
5
|
@parts_list = parts_list
|
6
6
|
parts_list.map { |p|
|
7
|
-
if p.
|
7
|
+
if p.content_type == "message/rfc822"
|
8
|
+
Mail.new(p.body).attachments
|
9
|
+
elsif p.parts.empty?
|
8
10
|
p if p.attachment?
|
9
11
|
else
|
10
12
|
p.attachments
|
@@ -12,12 +14,12 @@ module Mail
|
|
12
14
|
}.flatten.compact.each { |a| self << a }
|
13
15
|
self
|
14
16
|
end
|
15
|
-
|
17
|
+
|
16
18
|
# Returns the attachment by filename or at index.
|
17
|
-
#
|
19
|
+
#
|
18
20
|
# mail.attachments['test.png'] = File.read('test.png')
|
19
21
|
# mail.attachments['test.jpg'] = File.read('test.jpg')
|
20
|
-
#
|
22
|
+
#
|
21
23
|
# mail.attachments['test.png'].filename #=> 'test.png'
|
22
24
|
# mail.attachments[1].filename #=> 'test.jpg'
|
23
25
|
def [](index_value)
|
@@ -65,10 +67,13 @@ module Mail
|
|
65
67
|
hash[:body].force_encoding("BINARY")
|
66
68
|
end
|
67
69
|
end
|
70
|
+
|
71
|
+
attachment = Part.new(hash)
|
72
|
+
attachment.add_content_id(hash[:content_id])
|
68
73
|
|
69
|
-
@parts_list <<
|
74
|
+
@parts_list << attachment
|
70
75
|
end
|
71
|
-
|
76
|
+
|
72
77
|
# Uses the mime type to try and guess the encoding, if it is a binary type, or unknown, then we
|
73
78
|
# set it to binary, otherwise as set to plain text
|
74
79
|
def guess_encoding
|
@@ -77,8 +82,8 @@ module Mail
|
|
77
82
|
else
|
78
83
|
"binary"
|
79
84
|
end
|
80
|
-
end
|
81
|
-
|
85
|
+
end
|
86
|
+
|
82
87
|
def set_mime_type(filename)
|
83
88
|
# Have to do this because MIME::Types is not Ruby 1.9 safe yet
|
84
89
|
if RUBY_VERSION >= '1.9'
|
@@ -88,7 +93,7 @@ module Mail
|
|
88
93
|
end
|
89
94
|
@mime_type = MIME::Types.type_for(filename).first
|
90
95
|
end
|
91
|
-
|
96
|
+
|
92
97
|
end
|
93
98
|
end
|
94
99
|
|
data/lib/mail/body.rb
CHANGED
@@ -99,6 +99,20 @@ module Mail
|
|
99
99
|
self.decoded.match(regexp)
|
100
100
|
end
|
101
101
|
|
102
|
+
# Accepts anything that responds to #to_s and checks if it's a substring of the decoded text
|
103
|
+
#
|
104
|
+
# Examples:
|
105
|
+
#
|
106
|
+
# body = Mail::Body.new('The body')
|
107
|
+
# body.include?('The') #=> true
|
108
|
+
#
|
109
|
+
# body = Mail::Body.new("VGhlIGJvZHk=\n")
|
110
|
+
# body.encoding = 'base64'
|
111
|
+
# body.include?('The') #=> true
|
112
|
+
def include?(other)
|
113
|
+
self.decoded.include?(other.to_s)
|
114
|
+
end
|
115
|
+
|
102
116
|
# Allows you to set the sort order of the parts, overriding the default sort order.
|
103
117
|
# Defaults to 'text/plain', then 'text/enriched', then 'text/html' with any other content
|
104
118
|
# type coming after.
|
data/lib/mail/encodings.rb
CHANGED
@@ -7,6 +7,7 @@ module Mail
|
|
7
7
|
|
8
8
|
module Encodings
|
9
9
|
|
10
|
+
require "enumerator"
|
10
11
|
include Mail::Patterns
|
11
12
|
extend Mail::Utilities
|
12
13
|
|
@@ -113,24 +114,34 @@ module Mail
|
|
113
114
|
#
|
114
115
|
# String has to be of the format =?<encoding>?[QB]?<string>?=
|
115
116
|
def Encodings.value_decode(str)
|
116
|
-
|
117
|
-
|
118
|
-
# Join QP encoded-words that are adjacent to avoid decoding partial chars
|
119
|
-
str.gsub!( /=\?==\?.+?\?[Qq]\?/m, '' ) if str =~ /\?==\?/
|
117
|
+
# Optimization: If there's no encoded-words in the string, just return it
|
118
|
+
return str unless str.index("=?")
|
120
119
|
|
121
|
-
str.gsub(
|
122
|
-
before = $1.to_s
|
123
|
-
text = $2.to_s
|
120
|
+
str = str.gsub(/\?=(\s*)=\?/, '?==?') # Remove whitespaces between 'encoded-word's
|
124
121
|
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
before + q_value_decode(text)
|
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
|
130
126
|
else
|
131
|
-
|
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!(/\?\=\=\?/, '?= =?')
|
132
|
+
|
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
|
132
143
|
end
|
133
|
-
end
|
144
|
+
end.join("")
|
134
145
|
end
|
135
146
|
|
136
147
|
# Takes an encoded string of the format =?<encoding>?[QB]?<string>?=
|
@@ -176,7 +187,8 @@ module Mail
|
|
176
187
|
address.gsub!(/(".*?[^#{us_ascii}].+?")/) { |s| Encodings.b_value_encode(unquote(s), charset) }
|
177
188
|
# Then loop through all remaining items and encode as needed
|
178
189
|
tokens = address.split(/\s/)
|
179
|
-
|
190
|
+
# Need to use enum_for to stay 1.8.6 compatible
|
191
|
+
tokens.enum_for(:each_with_index).map do |word, i|
|
180
192
|
if word.ascii_only?
|
181
193
|
word
|
182
194
|
else
|
@@ -199,7 +211,7 @@ module Mail
|
|
199
211
|
def Encodings.b_value_encode(str, encoding = nil)
|
200
212
|
return str if str.to_s.ascii_only?
|
201
213
|
string, encoding = RubyVer.b_value_encode(str, encoding)
|
202
|
-
string.
|
214
|
+
string.lines.map do |str|
|
203
215
|
"=?#{encoding}?B?#{str.chomp}?="
|
204
216
|
end.join(" ")
|
205
217
|
end
|
@@ -214,8 +226,8 @@ module Mail
|
|
214
226
|
def Encodings.q_value_encode(str, encoding = nil)
|
215
227
|
return str if str.to_s.ascii_only?
|
216
228
|
string, encoding = RubyVer.q_value_encode(str, encoding)
|
217
|
-
string.gsub!("=\r\n
|
218
|
-
string.
|
229
|
+
string.gsub!("=\r\n", '') # We already have limited the string to the length we want
|
230
|
+
string.lines.map do |str|
|
219
231
|
"=?#{encoding}?Q?#{str.chomp.gsub(/ /, '_')}?="
|
220
232
|
end.join(" ")
|
221
233
|
end
|
@@ -243,7 +255,7 @@ module Mail
|
|
243
255
|
end
|
244
256
|
|
245
257
|
def Encodings.split_encoding_from_string( str )
|
246
|
-
match = str.match(/\=\?(
|
258
|
+
match = str.match(/\=\?([^?]+)?\?[QB]\?(.+)?\?\=/mi)
|
247
259
|
if match
|
248
260
|
[match[1], match[2]]
|
249
261
|
else
|
@@ -102,64 +102,77 @@ module Mail
|
|
102
102
|
# it is allowed elsewhere.
|
103
103
|
def wrapped_value # :nodoc:
|
104
104
|
@folded_line = []
|
105
|
-
@unfolded_line = decoded.to_s.
|
105
|
+
@unfolded_line = decoded.to_s.split(/[ \t]/)
|
106
106
|
fold("#{name}: ".length)
|
107
107
|
wrap_lines(name, @folded_line)
|
108
108
|
end
|
109
|
-
|
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.)
|
110
118
|
def wrap_lines(name, folded_lines)
|
111
119
|
result = []
|
112
120
|
index = 0
|
113
121
|
result[index] = "#{name}: #{folded_lines.shift}"
|
114
|
-
folded_lines
|
115
|
-
|
116
|
-
result[index] << " " + line
|
117
|
-
else
|
118
|
-
result[index] << "\r\n\t"
|
119
|
-
index += 1
|
120
|
-
result[index] = line
|
121
|
-
end
|
122
|
-
end
|
123
|
-
result.join
|
122
|
+
result.concat(folded_lines)
|
123
|
+
result.join("\r\n\t")
|
124
124
|
end
|
125
125
|
|
126
126
|
def fold(prepend = 0) # :nodoc:
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
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
|
156
163
|
end
|
157
164
|
end
|
158
|
-
|
165
|
+
|
159
166
|
def encode(value)
|
160
|
-
value.gsub
|
161
|
-
|
162
|
-
|
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')
|
163
176
|
end
|
164
177
|
|
165
178
|
end
|
data/lib/mail/message.rb
CHANGED
data/lib/mail/part.rb
CHANGED
@@ -17,7 +17,12 @@ module Mail
|
|
17
17
|
def has_content_id?
|
18
18
|
header.has_content_id?
|
19
19
|
end
|
20
|
-
|
20
|
+
|
21
|
+
def inline_content_id
|
22
|
+
add_content_id unless has_content_id?
|
23
|
+
uri_escape(unbracket(content_id))
|
24
|
+
end
|
25
|
+
|
21
26
|
def add_required_fields
|
22
27
|
add_content_id unless has_content_id?
|
23
28
|
super
|
data/lib/mail/patterns.rb
CHANGED
data/lib/mail/utilities.rb
CHANGED
@@ -69,7 +69,7 @@ module Mail
|
|
69
69
|
#
|
70
70
|
# Example:
|
71
71
|
#
|
72
|
-
# string
|
72
|
+
# paren( 'This is a string' ) #=> '(This is a string)'
|
73
73
|
def paren( str )
|
74
74
|
RubyVer.paren( str )
|
75
75
|
end
|
@@ -85,6 +85,26 @@ module Mail
|
|
85
85
|
match ? match[1] : str
|
86
86
|
end
|
87
87
|
|
88
|
+
# Wraps a string in angle brackets and escapes any that are in the string itself
|
89
|
+
#
|
90
|
+
# Example:
|
91
|
+
#
|
92
|
+
# bracket( 'This is a string' ) #=> '<This is a string>'
|
93
|
+
def bracket( str )
|
94
|
+
RubyVer.bracket( str )
|
95
|
+
end
|
96
|
+
|
97
|
+
# Unwraps a string from being wrapped in parenthesis
|
98
|
+
#
|
99
|
+
# Example:
|
100
|
+
#
|
101
|
+
# str = '<This is a string>'
|
102
|
+
# unbracket( str ) #=> 'This is a string'
|
103
|
+
def unbracket( str )
|
104
|
+
match = str.match(/^\<(.*?)\>$/)
|
105
|
+
match ? match[1] : str
|
106
|
+
end
|
107
|
+
|
88
108
|
# Escape parenthesies in a string
|
89
109
|
#
|
90
110
|
# Example:
|
@@ -95,6 +115,14 @@ module Mail
|
|
95
115
|
RubyVer.escape_paren( str )
|
96
116
|
end
|
97
117
|
|
118
|
+
def uri_escape( str )
|
119
|
+
URI.escape(str)
|
120
|
+
end
|
121
|
+
|
122
|
+
def uri_unescape( str )
|
123
|
+
URI.unescape(str)
|
124
|
+
end
|
125
|
+
|
98
126
|
# Matches two objects with their to_s values case insensitively
|
99
127
|
#
|
100
128
|
# Example:
|
data/lib/mail/version.rb
CHANGED
@@ -21,6 +21,21 @@ module Mail
|
|
21
21
|
'(' + str + ')'
|
22
22
|
end
|
23
23
|
|
24
|
+
def Ruby18.escape_bracket( str )
|
25
|
+
re = /\\\>/
|
26
|
+
str = str.gsub(re) { |s| '>'}
|
27
|
+
re = /\\\</
|
28
|
+
str = str.gsub(re) { |s| '<'}
|
29
|
+
re = /([\<\>])/ # Only match unescaped parens
|
30
|
+
str.gsub(re) { |s| '\\' + s }
|
31
|
+
end
|
32
|
+
|
33
|
+
def Ruby18.bracket( str )
|
34
|
+
str = $1 if str =~ /^\<(.*)?\>$/
|
35
|
+
str = escape_bracket( str )
|
36
|
+
'<' + str + '>'
|
37
|
+
end
|
38
|
+
|
24
39
|
def Ruby18.decode_base64(str)
|
25
40
|
Base64.decode64(str)
|
26
41
|
end
|
@@ -15,6 +15,17 @@ module Mail
|
|
15
15
|
'(' + str + ')'
|
16
16
|
end
|
17
17
|
|
18
|
+
def Ruby19.escape_bracket( str )
|
19
|
+
re = /(?<!\\)([\<\>])/ # Only match unescaped brackets
|
20
|
+
str.gsub(re) { |s| '\\' + s }
|
21
|
+
end
|
22
|
+
|
23
|
+
def Ruby19.bracket( str )
|
24
|
+
str = $1 if str =~ /^\<(.*)?\>$/
|
25
|
+
str = escape_bracket( str )
|
26
|
+
'<' + str + '>'
|
27
|
+
end
|
28
|
+
|
18
29
|
def Ruby19.decode_base64(str)
|
19
30
|
str.unpack( 'm' ).first.force_encoding(Encoding::BINARY)
|
20
31
|
end
|
metadata
CHANGED
@@ -5,22 +5,22 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 2
|
7
7
|
- 2
|
8
|
-
-
|
9
|
-
version: 2.2.
|
8
|
+
- 1
|
9
|
+
version: 2.2.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
|
-
-
|
12
|
+
- Mikel Lindsaar
|
13
13
|
autorequire:
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-
|
17
|
+
date: 2010-05-13 00:00:00 +10:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
21
|
-
type: :runtime
|
22
21
|
name: activesupport
|
23
|
-
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
@@ -29,24 +29,24 @@ dependencies:
|
|
29
29
|
- 3
|
30
30
|
- 4
|
31
31
|
version: 2.3.4
|
32
|
-
requirement: *id001
|
33
|
-
prerelease: false
|
34
|
-
- !ruby/object:Gem::Dependency
|
35
32
|
type: :runtime
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
36
35
|
name: mime-types
|
37
|
-
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
38
|
requirements:
|
39
39
|
- - ">="
|
40
40
|
- !ruby/object:Gem::Version
|
41
41
|
segments:
|
42
42
|
- 0
|
43
43
|
version: "0"
|
44
|
-
requirement: *id002
|
45
|
-
prerelease: false
|
46
|
-
- !ruby/object:Gem::Dependency
|
47
44
|
type: :runtime
|
45
|
+
version_requirements: *id002
|
46
|
+
- !ruby/object:Gem::Dependency
|
48
47
|
name: treetop
|
49
|
-
|
48
|
+
prerelease: false
|
49
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
51
|
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
@@ -55,8 +55,8 @@ dependencies:
|
|
55
55
|
- 4
|
56
56
|
- 5
|
57
57
|
version: 1.4.5
|
58
|
-
|
59
|
-
|
58
|
+
type: :runtime
|
59
|
+
version_requirements: *id003
|
60
60
|
description: A really Ruby Mail handler.
|
61
61
|
email: raasdnil@gmail.com
|
62
62
|
executables: []
|