tmail 1.2.3.1 → 1.2.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. data/README +10 -0
  2. data/ext/tmailscanner/tmail/tmailscanner.c +39 -8
  3. data/lib/tmail.rb +1 -0
  4. data/lib/tmail/address.rb +6 -40
  5. data/lib/tmail/attachments.rb +41 -22
  6. data/lib/tmail/encode.rb +9 -0
  7. data/lib/tmail/header.rb +5 -3
  8. data/lib/tmail/interface.rb +40 -3
  9. data/lib/tmail/mail.rb +3 -3
  10. data/lib/tmail/mailbox.rb +3 -2
  11. data/lib/tmail/net.rb +3 -1
  12. data/lib/tmail/parser.rb +204 -620
  13. data/lib/tmail/parser.y +38 -3
  14. data/lib/tmail/quoting.rb +38 -1
  15. data/lib/tmail/utils.rb +28 -4
  16. data/lib/tmail/vendor/rchardet-1.3/COPYING +504 -0
  17. data/lib/tmail/vendor/rchardet-1.3/README +12 -0
  18. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet.rb +67 -0
  19. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/big5freq.rb +927 -0
  20. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/big5prober.rb +42 -0
  21. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/chardistribution.rb +237 -0
  22. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/charsetgroupprober.rb +112 -0
  23. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/charsetprober.rb +75 -0
  24. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/codingstatemachine.rb +64 -0
  25. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/constants.rb +42 -0
  26. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/escprober.rb +90 -0
  27. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/escsm.rb +244 -0
  28. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/eucjpprober.rb +88 -0
  29. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/euckrfreq.rb +596 -0
  30. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/euckrprober.rb +42 -0
  31. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/euctwfreq.rb +430 -0
  32. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/euctwprober.rb +42 -0
  33. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/gb2312freq.rb +474 -0
  34. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/gb2312prober.rb +42 -0
  35. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/hebrewprober.rb +289 -0
  36. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/jisfreq.rb +570 -0
  37. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/jpcntx.rb +229 -0
  38. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/langbulgarianmodel.rb +229 -0
  39. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/langcyrillicmodel.rb +330 -0
  40. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/langgreekmodel.rb +227 -0
  41. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/langhebrewmodel.rb +202 -0
  42. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/langhungarianmodel.rb +226 -0
  43. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/langthaimodel.rb +201 -0
  44. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/latin1prober.rb +147 -0
  45. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/mbcharsetprober.rb +89 -0
  46. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/mbcsgroupprober.rb +47 -0
  47. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/mbcssm.rb +542 -0
  48. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/sbcharsetprober.rb +124 -0
  49. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/sbcsgroupprober.rb +58 -0
  50. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/sjisprober.rb +88 -0
  51. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/universaldetector.rb +166 -0
  52. data/lib/tmail/vendor/rchardet-1.3/lib/rchardet/utf8prober.rb +87 -0
  53. data/lib/tmail/version.rb +1 -1
  54. data/setup.rb +2 -2
  55. data/test/fixtures/apple_unquoted_content_type +44 -0
  56. data/test/fixtures/inline_attachment.txt +2095 -0
  57. data/test/fixtures/iso_8859_1_email_without_encoding_and_message_id.txt +16 -0
  58. data/test/fixtures/mailbox.zip +0 -0
  59. data/test/fixtures/marked_as_iso_8859_1_but_it_is_utf_8.txt +33 -0
  60. data/test/fixtures/marked_as_utf_8_but_it_is_iso_8859_1.txt +56 -0
  61. data/test/fixtures/raw_email_bad_time +62 -0
  62. data/test/fixtures/raw_email_double_at_in_header +14 -0
  63. data/test/fixtures/raw_email_only_attachment +17 -0
  64. data/test/fixtures/raw_email_string_in_date_field +17 -0
  65. data/test/fixtures/raw_email_trailing_dot +21 -0
  66. data/test/fixtures/raw_email_with_quoted_attachment_filename +60 -0
  67. data/test/fixtures/raw_email_with_wrong_splitted_multibyte_encoded_word_subject +15 -0
  68. data/test/fixtures/the_only_part_is_a_word_document.txt +425 -0
  69. data/test/fixtures/unquoted_filename_in_attachment +177 -0
  70. data/test/test_address.rb +114 -92
  71. data/test/test_attachments.rb +84 -1
  72. data/test/test_encode.rb +54 -0
  73. data/test/test_header.rb +60 -2
  74. data/test/test_mail.rb +22 -15
  75. data/test/test_mbox.rb +12 -3
  76. data/test/test_port.rb +13 -9
  77. data/test/test_quote.rb +9 -0
  78. data/tmail.gemspec +34 -0
  79. metadata +68 -167
  80. data/MANIFEST +0 -191
  81. data/log/BugTrackingLog.txt +0 -1231
  82. data/log/Changelog.txt +0 -534
  83. data/log/Fixme.txt +0 -6
  84. data/log/Testlog.txt +0 -2340
  85. data/log/Todo.txt +0 -30
  86. data/log/fixme.rdoc +0 -6
  87. data/meta/MANIFEST +0 -128
  88. data/meta/VERSION +0 -1
  89. data/meta/project.yaml +0 -30
  90. data/meta/unixname +0 -1
  91. data/sample/bench_base64.rb +0 -48
  92. data/sample/data/multipart +0 -23
  93. data/sample/data/normal +0 -29
  94. data/sample/data/sendtest +0 -5
  95. data/sample/data/simple +0 -14
  96. data/sample/data/test +0 -27
  97. data/sample/extract-attachements.rb +0 -33
  98. data/sample/from-check.rb +0 -26
  99. data/sample/multipart.rb +0 -26
  100. data/sample/parse-bench.rb +0 -68
  101. data/sample/parse-test.rb +0 -19
  102. data/sample/sendmail.rb +0 -94
  103. data/site/contributing/index.html +0 -183
  104. data/site/css/clean.css +0 -27
  105. data/site/css/layout.css +0 -31
  106. data/site/css/style.css +0 -60
  107. data/site/download/index.html +0 -61
  108. data/site/img/envelope.jpg +0 -0
  109. data/site/img/mailman.gif +0 -0
  110. data/site/img/stamp-sm.jpg +0 -0
  111. data/site/img/stamp.jpg +0 -0
  112. data/site/img/stampborder.jpg +0 -0
  113. data/site/img/tfire.jpg +0 -0
  114. data/site/img/tmail.png +0 -0
  115. data/site/index.html +0 -270
  116. data/site/js/jquery.js +0 -31
  117. data/site/log/Changelog.xsl +0 -33
  118. data/site/log/changelog.xml +0 -1677
  119. data/site/outdated/BUGS +0 -3
  120. data/site/outdated/DEPENDS +0 -1
  121. data/site/outdated/Incompatibilities +0 -89
  122. data/site/outdated/Incompatibilities.ja +0 -102
  123. data/site/outdated/NEWS +0 -9
  124. data/site/outdated/README.ja +0 -73
  125. data/site/outdated/doc.ja/address.html +0 -275
  126. data/site/outdated/doc.ja/basics.html +0 -405
  127. data/site/outdated/doc.ja/config.html +0 -49
  128. data/site/outdated/doc.ja/details.html +0 -146
  129. data/site/outdated/doc.ja/index.html +0 -39
  130. data/site/outdated/doc.ja/mail.html +0 -793
  131. data/site/outdated/doc.ja/mailbox.html +0 -265
  132. data/site/outdated/doc.ja/port.html +0 -95
  133. data/site/outdated/doc.ja/tmail.html +0 -58
  134. data/site/outdated/doc.ja/usage.html +0 -202
  135. data/site/outdated/rdd/address.rrd.m +0 -229
  136. data/site/outdated/rdd/basics.rd.m +0 -275
  137. data/site/outdated/rdd/config.rrd.m +0 -26
  138. data/site/outdated/rdd/details.rd.m +0 -117
  139. data/site/outdated/rdd/index.rhtml.m +0 -54
  140. data/site/outdated/rdd/mail.rrd.m +0 -701
  141. data/site/outdated/rdd/mailbox.rrd.m +0 -228
  142. data/site/outdated/rdd/port.rrd.m +0 -69
  143. data/site/outdated/rdd/tmail.rrd.m +0 -33
  144. data/site/outdated/rdd/usage.rd.m +0 -247
  145. data/site/quickstart/index.html +0 -69
  146. data/site/quickstart/quickstart.html +0 -52
  147. data/site/quickstart/usage.html +0 -193
  148. data/site/reference/address.html +0 -247
  149. data/site/reference/config.html +0 -30
  150. data/site/reference/index.html +0 -101
  151. data/site/reference/mail.html +0 -726
  152. data/site/reference/mailbox.html +0 -245
  153. data/site/reference/port.html +0 -75
  154. data/site/reference/tmail.html +0 -35
  155. data/work/script/make +0 -26
  156. data/work/script/rdoc +0 -39
  157. data/work/script/setup +0 -1616
  158. data/work/script/test +0 -30
data/README CHANGED
@@ -6,6 +6,16 @@
6
6
  Trans assitant developer
7
7
  Minero Aoki original developer
8
8
 
9
+ == RUBY 1.9 COMPATIBILITY
10
+
11
+ Note... as of 1.2.5, TMail is not compatible with Ruby 1.9.1. We are now using rchardet
12
+ to compare encodings and there is work to do for Ruby 1.9.1 due to it's encoding
13
+ capability.
14
+
15
+ For 1.9.1 + compatibility, I suggest you look at Mail (https://github.com/mikel/mail/tree)
16
+ while this is a work in progress, it is what I am working on to replace TMail for Ruby
17
+ 1.9 and beyond.
18
+
9
19
  == DESCRIPTION:
10
20
 
11
21
  TMail is a mail handling library for Ruby. It abstracts a mail message into a usable object allowing you to read, set, add and delete headers and the mail body.
@@ -15,9 +15,27 @@
15
15
  # include <stdlib.h>
16
16
  #endif
17
17
 
18
+
18
19
  #include "ruby.h"
20
+ #ifndef RSTRING_PTR
21
+ #define RSTRING_PTR(obj) RSTRING(obj)->ptr
22
+ #endif
23
+
24
+ #ifndef RSTRING_LEN
25
+ #define RSTRING_LEN(obj) RSTRING(obj)->len
26
+ #endif
27
+
28
+ #ifdef HAVE_RUBY_VM_H
29
+ #include "ruby/re.h"
30
+ #include "ruby/encoding.h"
31
+ #else
19
32
  #include "re.h"
33
+ #endif
20
34
 
35
+ #ifdef HAVE_RUBY_VM_H
36
+ const unsigned char *re_mbctab;
37
+ #define ismbchar(c) re_mbctab[(unsigned char)(c)]
38
+ #endif
21
39
 
22
40
  #define TMAIL_VERSION "1.2.3"
23
41
 
@@ -72,9 +90,9 @@ mails_s_new(klass, str, ident, cmt)
72
90
  sc = ALLOC_N(struct scanner, 1);
73
91
 
74
92
  StringValue(str);
75
- sc->pbeg = RSTRING(str)->ptr;
93
+ sc->pbeg = RSTRING_PTR(str);
76
94
  sc->p = sc->pbeg;
77
- sc->pend = sc->p + RSTRING(str)->len;
95
+ sc->pend = sc->p + RSTRING_LEN(str);
78
96
 
79
97
  sc->flags = 0;
80
98
  Check_Type(ident, T_SYMBOL);
@@ -180,6 +198,18 @@ skip_iso2022jp_string(sc)
180
198
  }
181
199
  }
182
200
 
201
+ #ifdef HAVE_RUBY_VM_H
202
+ static void
203
+ skip_japanese_string(sc)
204
+ struct scanner *sc;
205
+ {
206
+ while(sc->p < sc->pend) {
207
+ if (! ismbchar(*sc->p)) return;
208
+ rb_encoding *enc = rb_enc_get(sc);
209
+ sc->p += mbclen(sc->p, sc->pend, enc);
210
+ }
211
+ }
212
+ #else
183
213
  static void
184
214
  skip_japanese_string(sc)
185
215
  struct scanner *sc;
@@ -189,6 +219,7 @@ skip_japanese_string(sc)
189
219
  sc->p += mbclen(*sc->p);
190
220
  }
191
221
  }
222
+ #endif
192
223
 
193
224
 
194
225
  #define scan_atom(sc) scan_word(sc, ATOM_SYMBOLS)
@@ -376,9 +407,9 @@ digit_p(str)
376
407
  char *p;
377
408
  int i;
378
409
 
379
- p = RSTRING(str)->ptr;
380
- for (i = 0; i < RSTRING(str)->len; i++) {
381
- if (! IS_DIGIT(RSTRING(str)->ptr[i]))
410
+ p = RSTRING_PTR(str);
411
+ for (i = 0; i < RSTRING_LEN(str); i++) {
412
+ if (! IS_DIGIT(RSTRING_PTR(str)[i]))
382
413
  return 0;
383
414
  }
384
415
  return 1;
@@ -396,7 +427,7 @@ atomsym(sc, str)
396
427
  return tok_digit;
397
428
  }
398
429
  else if (RECV_MODE_P(sc)) {
399
- char *p = RSTRING(str)->ptr;
430
+ char *p = RSTRING_PTR(str);
400
431
  if (nccmp(p, "from")) return tok_from;
401
432
  else if (nccmp(p, "by")) return tok_by;
402
433
  else if (nccmp(p, "via")) return tok_via;
@@ -417,8 +448,8 @@ debug_print(sc, sym, val)
417
448
  s = rb_funcall(sym, rb_intern("inspect"), 0),
418
449
  printf("%7ld %-10s token=<%s>\n",
419
450
  (unsigned long)(sc->pend - sc->p),
420
- RSTRING(s)->ptr,
421
- RSTRING(val)->ptr);
451
+ RSTRING_PTR(s),
452
+ RSTRING_PTR(val));
422
453
  }
423
454
 
424
455
  #define D(expr) do {\
@@ -3,3 +3,4 @@ require 'tmail/mail'
3
3
  require 'tmail/mailbox'
4
4
  require 'tmail/core_extensions'
5
5
  require 'tmail/net'
6
+ require 'tmail/vendor/rchardet-1.3/lib/rchardet'
@@ -38,7 +38,7 @@ module TMail
38
38
  # = Class Address
39
39
  #
40
40
  # Provides a complete handling library for email addresses. Can parse a string of an
41
- # address directly or take in preformatted addresses themseleves. Allows you to add
41
+ # address directly or take in preformatted addresses themselves. Allows you to add
42
42
  # and remove phrases from the front of the address and provides a compare function for
43
43
  # email addresses.
44
44
  #
@@ -46,7 +46,7 @@ module TMail
46
46
  #
47
47
  # Just pass the email address in as a string to Address.parse:
48
48
  #
49
- # email = TMail::Address.parse('Mikel Lindsaar <mikel@lindsaar.net>)
49
+ # email = TMail::Address.parse('Mikel Lindsaar <mikel@lindsaar.net>')
50
50
  # #=> #<TMail::Address mikel@lindsaar.net>
51
51
  # email.address
52
52
  # #=> "mikel@lindsaar.net"
@@ -63,7 +63,7 @@ module TMail
63
63
  # Address.parse and catch any SyntaxError:
64
64
  #
65
65
  # begin
66
- # TMail::Mail.parse("mikel 2@@@@@ me .com")
66
+ # TMail::Address.parse("mikel 2@@@@@ me .com")
67
67
  # rescue TMail::SyntaxError
68
68
  # puts("Invalid Email Address Detected")
69
69
  # else
@@ -81,41 +81,7 @@ module TMail
81
81
  #
82
82
  # Raises a TMail::SyntaxError on invalid email format
83
83
  def Address.parse( str )
84
- Parser.parse :ADDRESS, special_quote_address(str)
85
- end
86
-
87
- def Address.special_quote_address(str) #:nodoc:
88
- # Takes a string which is an address and adds quotation marks to special
89
- # edge case methods that the RACC parser can not handle.
90
- #
91
- # Right now just handles two edge cases:
92
- #
93
- # Full stop as the last character of the display name:
94
- # Mikel L. <mikel@me.com>
95
- # Returns:
96
- # "Mikel L." <mikel@me.com>
97
- #
98
- # Unquoted @ symbol in the display name:
99
- # mikel@me.com <mikel@me.com>
100
- # Returns:
101
- # "mikel@me.com" <mikel@me.com>
102
- #
103
- # Any other address not matching these patterns just gets returned as is.
104
- case
105
- # This handles the missing "" in an older version of Apple Mail.app
106
- # around the display name when the display name contains a '@'
107
- # like 'mikel@me.com <mikel@me.com>'
108
- # Just quotes it to: '"mikel@me.com" <mikel@me.com>'
109
- when str =~ /\A([^"].+@.+[^"])\s(<.*?>)\Z/
110
- return "\"#{$1}\" #{$2}"
111
- # This handles cases where 'Mikel A. <mikel@me.com>' which is a trailing
112
- # full stop before the address section. Just quotes it to
113
- # '"Mikel A. <mikel@me.com>"
114
- when str =~ /\A(.*?\.)\s(<.*?>)\Z/
115
- return "\"#{$1}\" #{$2}"
116
- else
117
- str
118
- end
84
+ Parser.parse :ADDRESS, str
119
85
  end
120
86
 
121
87
  def address_group? #:nodoc:
@@ -143,7 +109,7 @@ module TMail
143
109
 
144
110
  # This is to catch an unquoted "@" symbol in the local part of the
145
111
  # address. Handles addresses like <"@"@me.com> and makes sure they
146
- # stay like <"@"@me.com> (previously were becomming <@@me.com>)
112
+ # stay like <"@"@me.com> (previously were becoming <@@me.com>)
147
113
  if local && (local.join == '@' || local.join =~ /\A[^"].*?@.*?[^"]\Z/)
148
114
  @local = "\"#{local.join}\""
149
115
  else
@@ -412,7 +378,7 @@ module TMail
412
378
  if first
413
379
  first = false
414
380
  else
415
- strategy.meta ','
381
+ strategy.puts_meta ','
416
382
  end
417
383
  strategy.space
418
384
  mbox.accept strategy
@@ -4,43 +4,62 @@
4
4
 
5
5
  =end
6
6
 
7
+ require 'kconv'
7
8
  require 'stringio'
8
9
 
9
10
  module TMail
10
11
  class Attachment < StringIO
11
12
  attr_accessor :original_filename, :content_type
13
+ alias quoted_filename original_filename
12
14
  end
13
15
 
14
16
  class Mail
15
17
  def has_attachments?
16
- multipart? && parts.any? { |part| attachment?(part) }
18
+ attachment?(self) || multipart? && parts.any? { |part| attachment?(part) }
17
19
  end
18
20
 
21
+ # Returns true if this part's content main type is text, else returns false.
22
+ # By main type is meant "text/plain" is text. "text/html" is text
23
+ def text_content_type?
24
+ self.header['content-type'] && (self.header['content-type'].main_type == 'text')
25
+ end
26
+
27
+ def inline_attachment?(part)
28
+ part['content-id'] || (part['content-disposition'] && part['content-disposition'].disposition == 'inline' && !part.text_content_type?)
29
+ end
30
+
19
31
  def attachment?(part)
20
- part.disposition_is_attachment? || part.content_type_is_text?
32
+ part.disposition_is_attachment? || (!part.content_type.nil? && !part.text_content_type?) unless part.multipart?
21
33
  end
22
-
34
+
23
35
  def attachments
24
36
  if multipart?
25
- parts.collect { |part|
26
- if part.multipart?
27
- part.attachments
28
- elsif attachment?(part)
29
- content = part.body # unquoted automatically by TMail#body
30
- file_name = (part['content-location'] &&
31
- part['content-location'].body) ||
32
- part.sub_header("content-type", "name") ||
33
- part.sub_header("content-disposition", "filename")
34
-
35
- next if file_name.blank? || content.blank?
36
-
37
- attachment = Attachment.new(content)
38
- attachment.original_filename = file_name.strip
39
- attachment.content_type = part.content_type
40
- attachment
41
- end
42
- }.flatten.compact
43
- end
37
+ parts.collect { |part| attachment(part) }.flatten.compact
38
+ elsif attachment?(self)
39
+ [attachment(self)]
40
+ end
44
41
  end
42
+
43
+ private
44
+
45
+ def attachment(part)
46
+ if part.multipart?
47
+ part.attachments
48
+ elsif attachment?(part)
49
+ content = part.body # unquoted automatically by TMail#body
50
+ file_name = (part['content-location'] && part['content-location'].body) ||
51
+ part.sub_header('content-type', 'name') ||
52
+ part.sub_header('content-disposition', 'filename') ||
53
+ 'noname'
54
+
55
+ return if content.blank?
56
+
57
+ attachment = TMail::Attachment.new(content)
58
+ attachment.original_filename = file_name.strip unless file_name.blank?
59
+ attachment.content_type = part.content_type
60
+ attachment
61
+ end
62
+ end
63
+
45
64
  end
46
65
  end
@@ -113,6 +113,7 @@ module TMail
113
113
 
114
114
  encoded = '=\?(?:iso-2022-jp|euc-jp|shift_jis)\?[QB]\?[a-z0-9+/=]+\?='
115
115
  ENCODED_WORDS = /#{encoded}(?:\s+#{encoded})*/i
116
+ SPACER = "\t"
116
117
 
117
118
  OUTPUT_ENCODING = {
118
119
  'EUC' => 'e',
@@ -165,6 +166,10 @@ module TMail
165
166
  @f << str
166
167
  end
167
168
 
169
+ def puts_meta( str )
170
+ @f << str
171
+ end
172
+
168
173
  def text( str )
169
174
  @f << decode(str)
170
175
  end
@@ -301,6 +306,10 @@ module TMail
301
306
  add_text str
302
307
  end
303
308
 
309
+ def puts_meta( str )
310
+ add_text str + @eol + SPACER
311
+ end
312
+
304
313
  def text( str )
305
314
  scanadd normalize_encoding(str)
306
315
  end
@@ -59,7 +59,7 @@ module TMail
59
59
  #
60
60
  # This is because a mailbox doesn't have the : after the From that designates the
61
61
  # beginning of the envelope sender (which can be different to the from address of
62
- # the emial)
62
+ # the email)
63
63
  #
64
64
  # Other fields can be passed as normal, "Reply-To", "Received" etc.
65
65
  #
@@ -243,6 +243,8 @@ module TMail
243
243
 
244
244
  def do_parse
245
245
  quote_boundary
246
+ quote_unquoted_name
247
+ quote_unquoted_bencode
246
248
  obj = Parser.parse(self.class::PARSE_TYPE, @body, @comments)
247
249
  set obj if obj
248
250
  end
@@ -314,7 +316,7 @@ module TMail
314
316
  if first
315
317
  first = false
316
318
  else
317
- strategy.meta ','
319
+ strategy.puts_meta ','
318
320
  strategy.space
319
321
  end
320
322
  a.accept strategy
@@ -817,7 +819,7 @@ module TMail
817
819
  if v
818
820
  strategy.meta ';'
819
821
  strategy.space
820
- strategy.kv_pair k, v
822
+ strategy.kv_pair k, unquote(v)
821
823
  end
822
824
  end
823
825
  end
@@ -42,7 +42,7 @@ module TMail
42
42
  # Allows you to query the mail object with a string to get the contents
43
43
  # of the field you want.
44
44
  #
45
- # Returns a string of the exact contnts of the field
45
+ # Returns a string of the exact contents of the field
46
46
  #
47
47
  # mail.from = "mikel <mikel@lindsaar.net>"
48
48
  # mail.header_string("From") #=> "mikel <mikel@lindsaar.net>"
@@ -591,16 +591,43 @@ module TMail
591
591
  end
592
592
 
593
593
  # Destructively sets the message ID of the mail object instance to the passed in string
594
+ #
595
+ # Invalid message IDs are ignored (silently, unless configured otherwise) and result in
596
+ # a nil message ID. Left and right angle brackets are required.
594
597
  #
598
+ # Be warned however, that calling mail.ready_to_send will overwrite whatever value you
599
+ # have in this field with an automatically generated unique value.
600
+ #
601
+ # If you really want to set your own message ID and know what you are doing per the
602
+ # various RFCs, you can do so with the enforced_message_id= command
603
+ #
595
604
  # Example:
596
605
  #
597
606
  # mail = TMail::Mail.new
607
+ # mail.message_id = "<348F04F142D69C21-291E56D292BC@xxxx.net>"
608
+ # mail.message_id #=> "<348F04F142D69C21-291E56D292BC@xxxx.net>"
598
609
  # mail.message_id = "this_is_my_badly_formatted_message_id"
599
- # mail.message_id #=> "this_is_my_badly_formatted_message_id"
610
+ # mail.message_id #=> nil
600
611
  def message_id=( str )
601
612
  set_string_attr 'Message-Id', str
602
613
  end
603
614
 
615
+ # Destructively sets the message ID of the mail object instance to the passed in string
616
+ # and also guarantees that calling #ready_to_send will not destroy what you set as the
617
+ # message_id
618
+ #
619
+ # Example:
620
+ #
621
+ # mail = TMail::Mail.new
622
+ # mail.message_id = "<348F04F142D69C21-291E56D292BC@xxxx.net>"
623
+ # mail.message_id #=> "<348F04F142D69C21-291E56D292BC@xxxx.net>"
624
+ # mail.ready_to_send
625
+ # mail.message_id #=> "<348F04F142D69C21-291E56D292BC@xxxx.net>"
626
+ def enforced_message_id=( str )
627
+ @message_id_enforced = true
628
+ self.message_id = ( str )
629
+ end
630
+
604
631
  # Returns the "In-Reply-To:" field contents as an array of this mail instance if it exists
605
632
  #
606
633
  # If the in_reply_to field does not exist, returns nil by default or you can pass in as
@@ -838,7 +865,17 @@ module TMail
838
865
  if h = @header['content-type']
839
866
  h['charset'] or default
840
867
  else
841
- default
868
+ mime_version_charset || default
869
+ end
870
+ end
871
+
872
+ # some weird emails come with the charset specified in the mime-version header:
873
+ #
874
+ # #<TMail::MimeVersionHeader "1.0\n charset=\"gb2312\"">
875
+ #
876
+ def mime_version_charset
877
+ if header['mime-version'].inspect =~ /charset=('|\\")?([^\\"']+)/
878
+ $2
842
879
  end
843
880
  end
844
881
 
@@ -255,7 +255,7 @@ module TMail
255
255
  alias fetch []
256
256
 
257
257
  # Allows you to set or delete TMail header objects at will.
258
- # Eamples:
258
+ # Examples:
259
259
  # @mail = TMail::Mail.new
260
260
  # @mail['to'].to_s # => 'mikel@test.com.au'
261
261
  # @mail['to'] = 'mikel@elsewhere.org'
@@ -265,7 +265,7 @@ module TMail
265
265
  # @mail['to'].to_s # => nil
266
266
  # @mail.encoded # => "\r\n"
267
267
  #
268
- # Note: setting mail[] = nil actualy deletes the header field in question from the object,
268
+ # Note: setting mail[] = nil actually deletes the header field in question from the object,
269
269
  # it does not just set the value of the hash to nil
270
270
  def []=( key, val )
271
271
  dkey = key.downcase
@@ -547,7 +547,7 @@ module TMail
547
547
  end
548
548
 
549
549
  def read_multipart( src )
550
- bound = @header['content-type'].params['boundary']
550
+ bound = @header['content-type'].params['boundary'] || ::TMail.new_boundary
551
551
  is_sep = /\A--#{Regexp.quote bound}(?:--)?[ \t]*(?:\n|\r\n|\r)/
552
552
  lastbound = "--#{bound}--"
553
553