tmail 1.2.3.1 → 1.2.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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