Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Mon Oct 24 17:50:00 2007 Mikel Lindsaar <raasdnil@gmail.com>

	* Remaining failing tests are one encoding problem with
		relating to RFC 2231 and another problem where special
		characters are not properly quoted if they are the name
		portion of an email address (ie, TMail does not handle
		the address <"@"@example.com> properly)

	* Closed #14964 - The TMail from ActionMailer Preview Release
		2.0 is now fully merged into TMail branch 0.11.
		All previous tests and examples relating to TMail that
		were part of ActionMailer 2.0 Preview Release	now pass.

	* Closed #15008 - Fixed handling of multipart content type
		headers.  Now tested against many types of email.
		TMails' behaviour now is to take any boundary type, if
		it contains illegal characters, it will wrap it in ""
		when requesting the content type by mail['content-type]
		you will receive it unquoted, when outputting the email
		to_s as a whole you will receive the content-type field
		with the boundary section quoted if it contains illegal
		characters.

  * Replaced id with object_id line 221 in stringio.rb
  • Loading branch information...
commit c2e1a5a8131a88f9f7594ec2f69732daeb462d24 1 parent a986977
@mikel authored
View
25 ChangeLog
@@ -1,3 +1,28 @@
+Mon Oct 24 17:50:00 2007 Mikel Lindsaar <raasdnil@gmail.com>
+
+ * Remaining failing tests are one encoding problem with
+ relating to RFC 2231 and another problem where special
+ characters are not properly quoted if they are the name
+ portion of an email address (ie, TMail does not handle
+ the address <"@"@example.com> properly)
+
+ * Closed #14964 - The TMail from ActionMailer Preview Release
+ 2.0 is now fully merged into TMail branch 0.11.
+ All previous tests and examples relating to TMail that
+ were part of ActionMailer 2.0 Preview Release now pass.
+
+ * Closed #15008 - Fixed handling of multipart content type
+ headers. Now tested against many types of email.
+ TMails' behaviour now is to take any boundary type, if
+ it contains illegal characters, it will wrap it in ""
+ when requesting the content type by mail['content-type]
+ you will receive it unquoted, when outputting the email
+ to_s as a whole you will receive the content-type field
+ with the boundary section quoted if it contains illegal
+ characters.
+
+ * Replaced id with object_id line 221 in stringio.rb
+
Mon Oct 24 15:35:00 2007 Mikel Lindsaar <raasdnil@gmail.com>
* Copied over the TMail/*.rb files from the TRUNK version of Rails
View
1  TODO
@@ -1,6 +1,5 @@
- RFC2231 decode
- delete File*Stream
-- do not output empty/illegal header on to_s
- simplify field.rb
- allow raw JIS string in quoted word
- unify character encoding of japanese strings in header
View
28 lib/tmail/header.rb
@@ -215,22 +215,6 @@ def do_parse
set obj if obj
end
- def quote_boundary
- # Make sure the boundary is quoted (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=(.*$)/
- preamble = $1
- boundary_text = $2
- # Find out if it contains any of the RFC 2045 'specials' and needs
- # to be quoted
- if boundary_text =~ /[\/\?\=]/
- boundary_text = "\"#{boundary_text}\"" unless boundary_text =~ /^".*?"$/
- @body = "#{preamble}boundary=#{boundary_text}"
- end
- end
- end
-
end
@@ -759,8 +743,10 @@ def content_type
def params
ensure_parsed
- @params.each do |k, v|
- @params[k] = unquote(v)
+ unless @params.blank?
+ @params.each do |k, v|
+ @params[k] = unquote(v)
+ end
end
@params
end
@@ -858,8 +844,10 @@ def disposition=( str )
def params
ensure_parsed
- @params.each do |k, v|
- @params[k] = unquote(v)
+ unless @params.blank?
+ @params.each do |k, v|
+ @params[k] = unquote(v)
+ end
end
@params
end
View
2  lib/tmail/info.rb
@@ -29,7 +29,7 @@
module TMail
- Version = '0.10.7'
+ Version = '0.11'
Copyright = 'Copyright (c) 1998-2002 Minero Aoki'
end
View
2  lib/tmail/stringio.rb
@@ -218,7 +218,7 @@ def size
alias pos size
def inspect
- "#<#{self.class}:#{@dest ? 'open' : 'closed'},#{id}>"
+ "#<#{self.class}:#{@dest ? 'open' : 'closed'},#{object_id}>"
end
def print( *args )
View
197 lib/tmail/textutils.rb
@@ -1,197 +0,0 @@
-#
-# textutils.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.
-#
-
-module TMail
-
- class SyntaxError < StandardError; end
-
-
- module TextUtils
-
- private
-
- def new_boundary
- 'mimepart_' + random_tag()
- end
-
- @@uniq = 0
-
- def random_tag
- @@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
-
- aspecial = '()<>[]:;.@\\,"'
- tspecial = '()<>[];:@\\,"/?='
- lwsp = " \t\r\n"
- control = '\x00-\x1f\x7f-\xff'
-
- ATOM_UNSAFE = /[#{Regexp.quote aspecial}#{control}#{lwsp}]/n
- PHRASE_UNSAFE = /[#{Regexp.quote aspecial}#{control}]/n
- TOKEN_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{lwsp}]/n
- CONTROL_CHAR = /[#{control}]/n
- RFC2231_UNSAFE = /[#{Regexp.quote tspecial}#{control}#{lwsp}\*\'\%]/n
-
- def atom_safe?(str)
- ATOM_UNSAFE !~ str
- end
-
- def quote_atom(str)
- (ATOM_UNSAFE =~ str) ? dquote(str) : str
- end
-
- def quote_phrase(str)
- (PHRASE_UNSAFE =~ str) ? dquote(str) : str
- end
-
- def token_safe?(str)
- TOKEN_UNSAFE !~ str
- end
-
- def quote_token(str)
- (TOKEN_UNSAFE =~ str) ? dquote(str) : str
- end
-
- def dquote(str)
- '"' + str.gsub(/["\\]/n) {|s| '\\' + s } + '"'
- end
- private :dquote
-
- def join_domain(arr)
- arr.map {|i| (/\A\[.*\]\z/ =~ i) ? i : quote_atom(i) }.join('.')
- end
-
- 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
- }
-
- 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
-
- 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
-
- def mime_encoded?(str)
- /=\?[^\s?=]+\?[QB]\?[^\s?=]+\?=/i =~ 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[$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
- NKF.nkf(NKF_FLAGS[$KCODE],
- m.post_match.gsub(/%[\da-f]{2}/in) {|s| s[1,2].hex.chr })
- end
-
- end
-
-end
View
21 lib/tmail/utils.rb
@@ -240,6 +240,27 @@ def unquote( str )
end
end
+ def quote_boundary
+ # Make sure the boundary is quoted (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
+
end
end
View
50 test/fixtures/raw_email_with_multipart_mixed_quoted_boundary
@@ -0,0 +1,50 @@
+From email_test@me.nowhere
+Return-Path: <email_test@me.nowhere>
+Received: from omta05sl.mx.bigpond.com by me.nowhere.else with ESMTP id 632BD5758 for <mikel@me.nowhere.else>; Sun, 21 Oct 2007 19:38:21 +1000
+Received: from oaamta05sl.mx.bigpond.com by omta05sl.mx.bigpond.com with ESMTP id <20071021093820.HSPC16667.omta05sl.mx.bigpond.com@oaamta05sl.mx.bigpond.com> for <mikel@me.nowhere.else>; Sun, 21 Oct 2007 19:38:20 +1000
+Received: from mikel091a by oaamta05sl.mx.bigpond.com with SMTP id <20071021093820.JFMT24025.oaamta05sl.mx.bigpond.com@mikel091a> for <mikel@me.nowhere.else>; Sun, 21 Oct 2007 19:38:20 +1000
+Date: Sun, 21 Oct 2007 19:38:13 +1000
+From: Mikel Lindsaar <email_test@me.nowhere>
+Reply-To: Mikel Lindsaar <email_test@me.nowhere>
+To: mikel@me.nowhere
+Message-Id: <009601c813c6$19df3510$0437d30a@mikel091a>
+Subject: Testing outlook
+Subject: Another PDF
+Mime-Version: 1.0
+Content-Type: multipart/mixed;
+ boundary="----=_Part_2192_32400445.1115745999735"
+X-Virus-Scanned: amavisd-new at textdrive.com
+
+------=_Part_2192_32400445.1115745999735
+Content-Type: text/plain; charset=ISO-8859-1
+Content-Transfer-Encoding: quoted-printable
+Content-Disposition: inline
+
+Just attaching another PDF, here, to see what the message looks like,
+and to see if I can figure out what is going wrong here.
+
+------=_Part_2192_32400445.1115745999735
+Content-Type: application/pdf; name="broken.pdf"
+Content-Transfer-Encoding: base64
+Content-Disposition: attachment; filename="broken.pdf"
+
+JVBERi0xLjQNCiXk9tzfDQoxIDAgb2JqDQo8PCAvTGVuZ3RoIDIgMCBSDQogICAvRmlsdGVyIC9G
+bGF0ZURlY29kZQ0KPj4NCnN0cmVhbQ0KeJy9Wt2KJbkNvm/od6jrhZxYln9hWEh2p+8HBvICySaE
+ycLuTV4/1ifJ9qnq09NpSBimu76yLUuy/qzqcPz7+em3Ixx/CDc6CsXxs3b5+fvfjr/8cPz6/BRu
+rbfAx/n3739/fuJylJ5u5fjX81OuDr4deK4Bz3z/aDP+8fz0yw8g0Ofq7ktr1Mn+u28rvhy/jVeD
+QSa+9YNKHP/pxjvDNfVAx/m3MFz54FhvTbaseaxiDoN2LeMVMw+yA7RbHSCDzxZuaYB2E1Yay7QU
+x89vz0+tyFDKMlAHK5yqLmnjF+c4RjEiQIUeKwblXMe+AsZjN1J5yGQL5DHpDHksurM81rF6PKab
+gK6zAarIDzIiUY23rJsN9iorAE816aIu6lsgAdQFsuhhkHOUFgVjp2GjMqSewITXNQ27jrMeamkg
+1rPI3iLWG2CIaSBB+V1245YVRICGbbpYKHc2USFDl6M09acQVQYhlwIrkBNLISvXhGlF1wi5FHCw
+wxZkoGNJlVeJCEsqKA+3YAV5AMb6KkeaqEJQmFKKQU8T1pRi2ihE1Y4CDrqoYFFXYjJJOatsyzuI
+8SIlykuxKTMibWK8H1PgEvqYgs4GmQSrEjJAalgGirIhik+p4ZQN9E3ETFPAHE1b8pp1l/0Rc1gl
+fQs0ABWvyoZZzU8VnPXwVVcO9BEsyjEJaO6eBoZRyKGlrKoYoOygA8BGIzgwN3RQ15ouigG5idZQ
+fx2U4Db2CqiLO0WHAZoylGiCAqhniNQjFjQPSkmjwfNTgQ6M1Ih+eWo36wFmjIxDJZiGUBiWsAyR
+xX3EekGOizkGI96Ol9zVZTAivikURhRsHh2E3JhWMpSTZCnnonrLhMCodgrNcgo4uyJUJc6qnVss
+nrGd1Ptr0YwisCOYyIbUwVjV4xBUNLbguSO2YHujonAMJkMdSI7bIw91Akq2AUlMUWGFTMAOamjU
+OvZQCxIkY2pCpMFo/IwLdVLHs6nddwTRrgoVbvLU9eB0G4EMndV0TNoxHbt3JBWwK6hhv3iHfDtF
+yokB302IpEBTnWICde4uYc/1khDbSIkQopO6lcqamGBu1OSE3N5IPSsZX00CkSHRiiyx6HQIShsS
+HSVNswdVsaOUSAWq9aYhDtGDaoG5a3lBGkYt/lFlBFt1UqrYnzVtUpUQnLiZeouKgf1KhRBViRRk
+ExepJCzTwEmFDalIRbLEGtw0gfpESOpIAF/NnpPzcVCG86s0g2DuSyd41uhNGbEgaSrWEXORErbw
+------=_Part_2192_32400445.1115745999735--
+
View
9 test/test_header.rb
@@ -1,4 +1,5 @@
$:.unshift File.dirname(__FILE__)
+require 'tmail'
require 'tmail/header'
require 'kcode'
require 'extctrl'
@@ -697,7 +698,7 @@ def _test_ATTRS
assert_equal 'attachment', h.disposition
assert_equal 1, h.params.size
assert_equal 'README.txt.pif', h.params['filename']
-
+
h = TMail::HeaderField.new('Content-Disposition',
'attachment; filename=')
assert_equal true, h.empty?
@@ -727,13 +728,13 @@ def _test_rfc2231_encode
h = TMail::HeaderField.new('Content-Disposition', 'a; n=a')
h['n'] = "\245\265\245\363\245\327\245\353.txt"
- assert_equal "a; n*=iso-2022-jp'ja'%1B$B%255%25s%25W%25k%1B%28B.txt",
- h.encoded
+ assert_equal "a; n*=iso-2022-jp'ja'%1B$B%255%25s%25W%25k%1B%28B.txt",
+ h.encoded
h = TMail::HeaderField.new('Content-Disposition', 'a; n=a')
h['n'] = "\245\265()<>[];:@\\,\"/?=%*'"
assert_equal "a;\r\n\tn*=iso-2022-jp'ja'%1B$B%255%1B%28B%28%29%3C%3E%5B%5D%3B%3A%40%5C%2C%22%2F%3F%3D%25%2A%27",
- h.encoded
+ h.encoded
end
def _test_raw_iso2022jp
View
25 test/test_mail.rb
@@ -444,13 +444,25 @@ def test_content_type
def test_mail_to_s_with_illegal_content_type_boundary_preserves_quotes
msg = <<EOF
From: mikel@example.com
-Subject: =?utf-8?Q?testing_testing_=D6=A4?=
-Content-Type: multipart/alternative; boundary="----=_=NextPart_000_0093_01C81419.EB75E850"
+Subject: Hello
+Content-Type: multipart/signed;
+ micalg=sha1;
+ boundary=Apple-Mail-42-587703407;
+ protocol="application/pkcs7-signature"
+
+The body
+EOF
+
+ output = <<EOF
+From: mikel@example.com
+Subject: Hello
+Content-Type: multipart/signed; protocol="application/pkcs7-signature"; boundary=Apple-Mail-42-587703407; micalg=sha1
The body
EOF
+
mail = TMail::Mail.parse(msg)
- assert_equal(msg, mail.to_s)
+ assert_equal(output, mail.to_s)
end
def test_mail_to_s_with_filename_preserves_quotes
@@ -567,4 +579,11 @@ def test_quoted_illegal_boundary_when_doing_mail_to_s
assert_equal('multipart/alternative; boundary="----=_NextPart_000_0093_01C81419.EB75E850"', mail['content-type'].to_s)
end
+ def test_quoted_illegal_boundary_with_multipart_mixed_when_doing_mail_to_s
+ fixture = File.read(File.dirname(__FILE__) + "/fixtures/raw_email_with_multipart_mixed_quoted_boundary")
+ mail = TMail::Mail.parse(fixture)
+ assert_equal(true, mail.multipart?)
+ assert_equal('multipart/mixed; boundary="----=_Part_2192_32400445.1115745999735"', mail['content-type'].to_s)
+ end
+
end
View
18 test/testtextutils.rb
@@ -1,18 +0,0 @@
-require 'tmail'
-require 'test/unit'
-
-class TextUtilsTester < Test::Unit::TestCase
- include TMail::TextUtils
-
- def test_new_boundary
- a = new_boundary()
- b = new_boundary()
- c = new_boundary()
- assert_instance_of String, a
- assert_instance_of String, b
- assert_instance_of String, c
- assert(a != b)
- assert(b != c)
- assert(c != a)
- end
-end
Please sign in to comment.
Something went wrong with that request. Please try again.