tmail 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data/LICENSE +21 -0
  2. data/README +157 -0
  3. data/bat/changelog +19 -0
  4. data/bat/clobber/package +10 -0
  5. data/bat/compile +42 -0
  6. data/bat/config.yaml +8 -0
  7. data/bat/prepare +8 -0
  8. data/bat/publish +51 -0
  9. data/bat/rdoc +42 -0
  10. data/bat/release +12 -0
  11. data/bat/setup +1616 -0
  12. data/bat/stats +138 -0
  13. data/bat/tag +25 -0
  14. data/bat/test +25 -0
  15. data/ext/tmail/Makefile +25 -0
  16. data/ext/tmail/base64/MANIFEST +4 -0
  17. data/ext/tmail/base64/base64.c +264 -0
  18. data/ext/tmail/base64/depend +1 -0
  19. data/ext/tmail/base64/extconf.rb +38 -0
  20. data/ext/tmail/scanner_c/MANIFEST +4 -0
  21. data/ext/tmail/scanner_c/depend +1 -0
  22. data/ext/tmail/scanner_c/extconf.rb +38 -0
  23. data/ext/tmail/scanner_c/scanner_c.c +582 -0
  24. data/lib/tmail.rb +4 -0
  25. data/lib/tmail/Makefile +19 -0
  26. data/lib/tmail/address.rb +245 -0
  27. data/lib/tmail/attachments.rb +47 -0
  28. data/lib/tmail/base64.rb +75 -0
  29. data/lib/tmail/compat.rb +39 -0
  30. data/lib/tmail/config.rb +71 -0
  31. data/lib/tmail/core_extensions.rb +67 -0
  32. data/lib/tmail/encode.rb +524 -0
  33. data/lib/tmail/header.rb +931 -0
  34. data/lib/tmail/index.rb +8 -0
  35. data/lib/tmail/interface.rb +540 -0
  36. data/lib/tmail/loader.rb +1 -0
  37. data/lib/tmail/mail.rb +507 -0
  38. data/lib/tmail/mailbox.rb +435 -0
  39. data/lib/tmail/mbox.rb +1 -0
  40. data/lib/tmail/net.rb +282 -0
  41. data/lib/tmail/obsolete.rb +137 -0
  42. data/lib/tmail/parser.rb +1475 -0
  43. data/lib/tmail/parser.y +381 -0
  44. data/lib/tmail/port.rb +379 -0
  45. data/lib/tmail/quoting.rb +142 -0
  46. data/lib/tmail/require_arch.rb +56 -0
  47. data/lib/tmail/scanner.rb +44 -0
  48. data/lib/tmail/scanner_r.rb +263 -0
  49. data/lib/tmail/stringio.rb +279 -0
  50. data/lib/tmail/tmail.rb +1 -0
  51. data/lib/tmail/utils.rb +281 -0
  52. data/lib/tmail/version.rb +38 -0
  53. data/meta/icli.yaml +16 -0
  54. data/meta/tmail-1.1.1.roll +24 -0
  55. data/sample/data/multipart +23 -0
  56. data/sample/data/normal +29 -0
  57. data/sample/data/sendtest +5 -0
  58. data/sample/data/simple +14 -0
  59. data/sample/data/test +27 -0
  60. data/sample/extract-attachements.rb +33 -0
  61. data/sample/from-check.rb +26 -0
  62. data/sample/multipart.rb +26 -0
  63. data/sample/parse-bench.rb +68 -0
  64. data/sample/parse-test.rb +19 -0
  65. data/sample/sendmail.rb +94 -0
  66. data/test/extctrl.rb +6 -0
  67. data/test/fixtures/raw_base64_decoded_string +0 -0
  68. data/test/fixtures/raw_base64_email +83 -0
  69. data/test/fixtures/raw_base64_encoded_string +1 -0
  70. data/test/fixtures/raw_email +14 -0
  71. data/test/fixtures/raw_email10 +20 -0
  72. data/test/fixtures/raw_email11 +34 -0
  73. data/test/fixtures/raw_email12 +32 -0
  74. data/test/fixtures/raw_email13 +29 -0
  75. data/test/fixtures/raw_email2 +114 -0
  76. data/test/fixtures/raw_email3 +70 -0
  77. data/test/fixtures/raw_email4 +59 -0
  78. data/test/fixtures/raw_email5 +19 -0
  79. data/test/fixtures/raw_email6 +20 -0
  80. data/test/fixtures/raw_email7 +66 -0
  81. data/test/fixtures/raw_email8 +47 -0
  82. data/test/fixtures/raw_email9 +28 -0
  83. data/test/fixtures/raw_email_quoted_with_0d0a +14 -0
  84. data/test/fixtures/raw_email_simple +11 -0
  85. data/test/fixtures/raw_email_with_illegal_boundary +58 -0
  86. data/test/fixtures/raw_email_with_multipart_mixed_quoted_boundary +50 -0
  87. data/test/fixtures/raw_email_with_nested_attachment +100 -0
  88. data/test/fixtures/raw_email_with_partially_quoted_subject +14 -0
  89. data/test/fixtures/raw_email_with_quoted_illegal_boundary +58 -0
  90. data/test/kcode.rb +14 -0
  91. data/test/test_address.rb +1128 -0
  92. data/test/test_attachments.rb +35 -0
  93. data/test/test_base64.rb +63 -0
  94. data/test/test_encode.rb +77 -0
  95. data/test/test_header.rb +885 -0
  96. data/test/test_helper.rb +2 -0
  97. data/test/test_mail.rb +623 -0
  98. data/test/test_mbox.rb +126 -0
  99. data/test/test_port.rb +430 -0
  100. data/test/test_scanner.rb +209 -0
  101. data/test/test_utils.rb +37 -0
  102. metadata +205 -0
@@ -0,0 +1,931 @@
1
+ =begin rdoc
2
+
3
+ = Header handling class
4
+
5
+ =end
6
+ # RFC #822 ftp://ftp.isi.edu/in-notes/rfc822.txt
7
+ #
8
+ #
9
+ #--
10
+ # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
11
+ #
12
+ # Permission is hereby granted, free of charge, to any person obtaining
13
+ # a copy of this software and associated documentation files (the
14
+ # "Software"), to deal in the Software without restriction, including
15
+ # without limitation the rights to use, copy, modify, merge, publish,
16
+ # distribute, sublicense, and/or sell copies of the Software, and to
17
+ # permit persons to whom the Software is furnished to do so, subject to
18
+ # the following conditions:
19
+ #
20
+ # The above copyright notice and this permission notice shall be
21
+ # included in all copies or substantial portions of the Software.
22
+ #
23
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30
+ #
31
+ # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
32
+ # with permission of Minero Aoki.
33
+ #++
34
+
35
+ require 'tmail/encode'
36
+ require 'tmail/address'
37
+ require 'tmail/parser'
38
+ require 'tmail/config'
39
+ require 'tmail/utils'
40
+
41
+
42
+ module TMail
43
+
44
+ class HeaderField
45
+
46
+ include TextUtils
47
+
48
+ class << self
49
+
50
+ alias newobj new
51
+
52
+ def new( name, body, conf = DEFAULT_CONFIG )
53
+ klass = FNAME_TO_CLASS[name.downcase] || UnstructuredHeader
54
+ klass.newobj body, conf
55
+ end
56
+
57
+ def new_from_port( port, name, conf = DEFAULT_CONFIG )
58
+ re = Regep.new('\A(' + Regexp.quote(name) + '):', 'i')
59
+ str = nil
60
+ port.ropen {|f|
61
+ f.each do |line|
62
+ if m = re.match(line) then str = m.post_match.strip
63
+ elsif str and /\A[\t ]/ === line then str << ' ' << line.strip
64
+ elsif /\A-*\s*\z/ === line then break
65
+ elsif str then break
66
+ end
67
+ end
68
+ }
69
+ new(name, str, Config.to_config(conf))
70
+ end
71
+
72
+ def internal_new( name, conf )
73
+ FNAME_TO_CLASS[name].newobj('', conf, true)
74
+ end
75
+
76
+ end # class << self
77
+
78
+ def initialize( body, conf, intern = false )
79
+ @body = body
80
+ @config = conf
81
+
82
+ @illegal = false
83
+ @parsed = false
84
+
85
+ if intern
86
+ @parsed = true
87
+ parse_init
88
+ end
89
+ end
90
+
91
+ def inspect
92
+ "#<#{self.class} #{@body.inspect}>"
93
+ end
94
+
95
+ def illegal?
96
+ @illegal
97
+ end
98
+
99
+ def empty?
100
+ ensure_parsed
101
+ return true if @illegal
102
+ isempty?
103
+ end
104
+
105
+ private
106
+
107
+ def ensure_parsed
108
+ return if @parsed
109
+ @parsed = true
110
+ parse
111
+ end
112
+
113
+ # defabstract parse
114
+ # end
115
+
116
+ def clear_parse_status
117
+ @parsed = false
118
+ @illegal = false
119
+ end
120
+
121
+ public
122
+
123
+ def body
124
+ ensure_parsed
125
+ v = Decoder.new(s = '')
126
+ do_accept v
127
+ v.terminate
128
+ s
129
+ end
130
+
131
+ def body=( str )
132
+ @body = str
133
+ clear_parse_status
134
+ end
135
+
136
+ include StrategyInterface
137
+
138
+ def accept( strategy )
139
+ ensure_parsed
140
+ do_accept strategy
141
+ strategy.terminate
142
+ end
143
+
144
+ # abstract do_accept
145
+
146
+ end
147
+
148
+
149
+ class UnstructuredHeader < HeaderField
150
+
151
+ def body
152
+ ensure_parsed
153
+ @body
154
+ end
155
+
156
+ def body=( arg )
157
+ ensure_parsed
158
+ @body = arg
159
+ end
160
+
161
+ private
162
+
163
+ def parse_init
164
+ end
165
+
166
+ def parse
167
+ @body = Decoder.decode(@body.gsub(/\n|\r\n|\r/, ''))
168
+ end
169
+
170
+ def isempty?
171
+ not @body
172
+ end
173
+
174
+ def do_accept( strategy )
175
+ strategy.text @body
176
+ end
177
+
178
+ end
179
+
180
+
181
+ class StructuredHeader < HeaderField
182
+
183
+ def comments
184
+ ensure_parsed
185
+ @comments
186
+ end
187
+
188
+ private
189
+
190
+ def parse
191
+ save = nil
192
+
193
+ begin
194
+ parse_init
195
+ do_parse
196
+ rescue SyntaxError
197
+ if not save and mime_encoded? @body
198
+ save = @body
199
+ @body = Decoder.decode(save)
200
+ retry
201
+ elsif save
202
+ @body = save
203
+ end
204
+
205
+ @illegal = true
206
+ raise if @config.strict_parse?
207
+ end
208
+ end
209
+
210
+ def parse_init
211
+ @comments = []
212
+ init
213
+ end
214
+
215
+ def do_parse
216
+ quote_boundary
217
+ obj = Parser.parse(self.class::PARSE_TYPE, @body, @comments)
218
+ set obj if obj
219
+ end
220
+
221
+ end
222
+
223
+
224
+ class DateTimeHeader < StructuredHeader
225
+
226
+ PARSE_TYPE = :DATETIME
227
+
228
+ def date
229
+ ensure_parsed
230
+ @date
231
+ end
232
+
233
+ def date=( arg )
234
+ ensure_parsed
235
+ @date = arg
236
+ end
237
+
238
+ private
239
+
240
+ def init
241
+ @date = nil
242
+ end
243
+
244
+ def set( t )
245
+ @date = t
246
+ end
247
+
248
+ def isempty?
249
+ not @date
250
+ end
251
+
252
+ def do_accept( strategy )
253
+ strategy.meta time2str(@date)
254
+ end
255
+
256
+ end
257
+
258
+
259
+ class AddressHeader < StructuredHeader
260
+
261
+ PARSE_TYPE = :MADDRESS
262
+
263
+ def addrs
264
+ ensure_parsed
265
+ @addrs
266
+ end
267
+
268
+ private
269
+
270
+ def init
271
+ @addrs = []
272
+ end
273
+
274
+ def set( a )
275
+ @addrs = a
276
+ end
277
+
278
+ def isempty?
279
+ @addrs.empty?
280
+ end
281
+
282
+ def do_accept( strategy )
283
+ first = true
284
+ @addrs.each do |a|
285
+ if first
286
+ first = false
287
+ else
288
+ strategy.meta ','
289
+ strategy.space
290
+ end
291
+ a.accept strategy
292
+ end
293
+
294
+ @comments.each do |c|
295
+ strategy.space
296
+ strategy.meta '('
297
+ strategy.text c
298
+ strategy.meta ')'
299
+ end
300
+ end
301
+
302
+ end
303
+
304
+
305
+ class ReturnPathHeader < AddressHeader
306
+
307
+ PARSE_TYPE = :RETPATH
308
+
309
+ def addr
310
+ addrs()[0]
311
+ end
312
+
313
+ def spec
314
+ a = addr() or return nil
315
+ a.spec
316
+ end
317
+
318
+ def routes
319
+ a = addr() or return nil
320
+ a.routes
321
+ end
322
+
323
+ private
324
+
325
+ def do_accept( strategy )
326
+ a = addr()
327
+
328
+ strategy.meta '<'
329
+ unless a.routes.empty?
330
+ strategy.meta a.routes.map {|i| '@' + i }.join(',')
331
+ strategy.meta ':'
332
+ end
333
+ spec = a.spec
334
+ strategy.meta spec if spec
335
+ strategy.meta '>'
336
+ end
337
+
338
+ end
339
+
340
+
341
+ class SingleAddressHeader < AddressHeader
342
+
343
+ def addr
344
+ addrs()[0]
345
+ end
346
+
347
+ private
348
+
349
+ def do_accept( strategy )
350
+ a = addr()
351
+ a.accept strategy
352
+ @comments.each do |c|
353
+ strategy.space
354
+ strategy.meta '('
355
+ strategy.text c
356
+ strategy.meta ')'
357
+ end
358
+ end
359
+
360
+ end
361
+
362
+
363
+ class MessageIdHeader < StructuredHeader
364
+
365
+ def id
366
+ ensure_parsed
367
+ @id
368
+ end
369
+
370
+ def id=( arg )
371
+ ensure_parsed
372
+ @id = arg
373
+ end
374
+
375
+ private
376
+
377
+ def init
378
+ @id = nil
379
+ end
380
+
381
+ def isempty?
382
+ not @id
383
+ end
384
+
385
+ def do_parse
386
+ @id = @body.slice(MESSAGE_ID) or
387
+ raise SyntaxError, "wrong Message-ID format: #{@body}"
388
+ end
389
+
390
+ def do_accept( strategy )
391
+ strategy.meta @id
392
+ end
393
+
394
+ end
395
+
396
+
397
+ class ReferencesHeader < StructuredHeader
398
+
399
+ def refs
400
+ ensure_parsed
401
+ @refs
402
+ end
403
+
404
+ def each_id
405
+ self.refs.each do |i|
406
+ yield i if MESSAGE_ID === i
407
+ end
408
+ end
409
+
410
+ def ids
411
+ ensure_parsed
412
+ @ids
413
+ end
414
+
415
+ def each_phrase
416
+ self.refs.each do |i|
417
+ yield i unless MESSAGE_ID === i
418
+ end
419
+ end
420
+
421
+ def phrases
422
+ ret = []
423
+ each_phrase {|i| ret.push i }
424
+ ret
425
+ end
426
+
427
+ private
428
+
429
+ def init
430
+ @refs = []
431
+ @ids = []
432
+ end
433
+
434
+ def isempty?
435
+ @ids.empty?
436
+ end
437
+
438
+ def do_parse
439
+ str = @body
440
+ while m = MESSAGE_ID.match(str)
441
+ pre = m.pre_match.strip
442
+ @refs.push pre unless pre.empty?
443
+ @refs.push s = m[0]
444
+ @ids.push s
445
+ str = m.post_match
446
+ end
447
+ str = str.strip
448
+ @refs.push str unless str.empty?
449
+ end
450
+
451
+ def do_accept( strategy )
452
+ first = true
453
+ @ids.each do |i|
454
+ if first
455
+ first = false
456
+ else
457
+ strategy.space
458
+ end
459
+ strategy.meta i
460
+ end
461
+ end
462
+
463
+ end
464
+
465
+
466
+ class ReceivedHeader < StructuredHeader
467
+
468
+ PARSE_TYPE = :RECEIVED
469
+
470
+ def from
471
+ ensure_parsed
472
+ @from
473
+ end
474
+
475
+ def from=( arg )
476
+ ensure_parsed
477
+ @from = arg
478
+ end
479
+
480
+ def by
481
+ ensure_parsed
482
+ @by
483
+ end
484
+
485
+ def by=( arg )
486
+ ensure_parsed
487
+ @by = arg
488
+ end
489
+
490
+ def via
491
+ ensure_parsed
492
+ @via
493
+ end
494
+
495
+ def via=( arg )
496
+ ensure_parsed
497
+ @via = arg
498
+ end
499
+
500
+ def with
501
+ ensure_parsed
502
+ @with
503
+ end
504
+
505
+ def id
506
+ ensure_parsed
507
+ @id
508
+ end
509
+
510
+ def id=( arg )
511
+ ensure_parsed
512
+ @id = arg
513
+ end
514
+
515
+ def _for
516
+ ensure_parsed
517
+ @_for
518
+ end
519
+
520
+ def _for=( arg )
521
+ ensure_parsed
522
+ @_for = arg
523
+ end
524
+
525
+ def date
526
+ ensure_parsed
527
+ @date
528
+ end
529
+
530
+ def date=( arg )
531
+ ensure_parsed
532
+ @date = arg
533
+ end
534
+
535
+ private
536
+
537
+ def init
538
+ @from = @by = @via = @with = @id = @_for = nil
539
+ @with = []
540
+ @date = nil
541
+ end
542
+
543
+ def set( args )
544
+ @from, @by, @via, @with, @id, @_for, @date = *args
545
+ end
546
+
547
+ def isempty?
548
+ @with.empty? and not (@from or @by or @via or @id or @_for or @date)
549
+ end
550
+
551
+ def do_accept( strategy )
552
+ list = []
553
+ list.push 'from ' + @from if @from
554
+ list.push 'by ' + @by if @by
555
+ list.push 'via ' + @via if @via
556
+ @with.each do |i|
557
+ list.push 'with ' + i
558
+ end
559
+ list.push 'id ' + @id if @id
560
+ list.push 'for <' + @_for + '>' if @_for
561
+
562
+ first = true
563
+ list.each do |i|
564
+ strategy.space unless first
565
+ strategy.meta i
566
+ first = false
567
+ end
568
+ if @date
569
+ strategy.meta ';'
570
+ strategy.space
571
+ strategy.meta time2str(@date)
572
+ end
573
+ end
574
+
575
+ end
576
+
577
+
578
+ class KeywordsHeader < StructuredHeader
579
+
580
+ PARSE_TYPE = :KEYWORDS
581
+
582
+ def keys
583
+ ensure_parsed
584
+ @keys
585
+ end
586
+
587
+ private
588
+
589
+ def init
590
+ @keys = []
591
+ end
592
+
593
+ def set( a )
594
+ @keys = a
595
+ end
596
+
597
+ def isempty?
598
+ @keys.empty?
599
+ end
600
+
601
+ def do_accept( strategy )
602
+ first = true
603
+ @keys.each do |i|
604
+ if first
605
+ first = false
606
+ else
607
+ strategy.meta ','
608
+ end
609
+ strategy.meta i
610
+ end
611
+ end
612
+
613
+ end
614
+
615
+
616
+ class EncryptedHeader < StructuredHeader
617
+
618
+ PARSE_TYPE = :ENCRYPTED
619
+
620
+ def encrypter
621
+ ensure_parsed
622
+ @encrypter
623
+ end
624
+
625
+ def encrypter=( arg )
626
+ ensure_parsed
627
+ @encrypter = arg
628
+ end
629
+
630
+ def keyword
631
+ ensure_parsed
632
+ @keyword
633
+ end
634
+
635
+ def keyword=( arg )
636
+ ensure_parsed
637
+ @keyword = arg
638
+ end
639
+
640
+ private
641
+
642
+ def init
643
+ @encrypter = nil
644
+ @keyword = nil
645
+ end
646
+
647
+ def set( args )
648
+ @encrypter, @keyword = args
649
+ end
650
+
651
+ def isempty?
652
+ not (@encrypter or @keyword)
653
+ end
654
+
655
+ def do_accept( strategy )
656
+ if @key
657
+ strategy.meta @encrypter + ','
658
+ strategy.space
659
+ strategy.meta @keyword
660
+ else
661
+ strategy.meta @encrypter
662
+ end
663
+ end
664
+
665
+ end
666
+
667
+
668
+ class MimeVersionHeader < StructuredHeader
669
+
670
+ PARSE_TYPE = :MIMEVERSION
671
+
672
+ def major
673
+ ensure_parsed
674
+ @major
675
+ end
676
+
677
+ def major=( arg )
678
+ ensure_parsed
679
+ @major = arg
680
+ end
681
+
682
+ def minor
683
+ ensure_parsed
684
+ @minor
685
+ end
686
+
687
+ def minor=( arg )
688
+ ensure_parsed
689
+ @minor = arg
690
+ end
691
+
692
+ def version
693
+ sprintf('%d.%d', major, minor)
694
+ end
695
+
696
+ private
697
+
698
+ def init
699
+ @major = nil
700
+ @minor = nil
701
+ end
702
+
703
+ def set( args )
704
+ @major, @minor = *args
705
+ end
706
+
707
+ def isempty?
708
+ not (@major or @minor)
709
+ end
710
+
711
+ def do_accept( strategy )
712
+ strategy.meta sprintf('%d.%d', @major, @minor)
713
+ end
714
+
715
+ end
716
+
717
+
718
+ class ContentTypeHeader < StructuredHeader
719
+
720
+ PARSE_TYPE = :CTYPE
721
+
722
+ def main_type
723
+ ensure_parsed
724
+ @main
725
+ end
726
+
727
+ def main_type=( arg )
728
+ ensure_parsed
729
+ @main = arg.downcase
730
+ end
731
+
732
+ def sub_type
733
+ ensure_parsed
734
+ @sub
735
+ end
736
+
737
+ def sub_type=( arg )
738
+ ensure_parsed
739
+ @sub = arg.downcase
740
+ end
741
+
742
+ def content_type
743
+ ensure_parsed
744
+ @sub ? sprintf('%s/%s', @main, @sub) : @main
745
+ end
746
+
747
+ def params
748
+ ensure_parsed
749
+ unless @params.blank?
750
+ @params.each do |k, v|
751
+ @params[k] = unquote(v)
752
+ end
753
+ end
754
+ @params
755
+ end
756
+
757
+ def []( key )
758
+ ensure_parsed
759
+ @params and unquote(@params[key])
760
+ end
761
+
762
+ def []=( key, val )
763
+ ensure_parsed
764
+ (@params ||= {})[key] = val
765
+ end
766
+
767
+ private
768
+
769
+ def init
770
+ @main = @sub = @params = nil
771
+ end
772
+
773
+ def set( args )
774
+ @main, @sub, @params = *args
775
+ end
776
+
777
+ def isempty?
778
+ not (@main or @sub)
779
+ end
780
+
781
+ def do_accept( strategy )
782
+ if @sub
783
+ strategy.meta sprintf('%s/%s', @main, @sub)
784
+ else
785
+ strategy.meta @main
786
+ end
787
+ @params.each do |k,v|
788
+ if v
789
+ strategy.meta ';'
790
+ strategy.space
791
+ strategy.kv_pair k, v
792
+ end
793
+ end
794
+ end
795
+
796
+ end
797
+
798
+
799
+ class ContentTransferEncodingHeader < StructuredHeader
800
+
801
+ PARSE_TYPE = :CENCODING
802
+
803
+ def encoding
804
+ ensure_parsed
805
+ @encoding
806
+ end
807
+
808
+ def encoding=( arg )
809
+ ensure_parsed
810
+ @encoding = arg
811
+ end
812
+
813
+ private
814
+
815
+ def init
816
+ @encoding = nil
817
+ end
818
+
819
+ def set( s )
820
+ @encoding = s
821
+ end
822
+
823
+ def isempty?
824
+ not @encoding
825
+ end
826
+
827
+ def do_accept( strategy )
828
+ strategy.meta @encoding.capitalize
829
+ end
830
+
831
+ end
832
+
833
+
834
+ class ContentDispositionHeader < StructuredHeader
835
+
836
+ PARSE_TYPE = :CDISPOSITION
837
+
838
+ def disposition
839
+ ensure_parsed
840
+ @disposition
841
+ end
842
+
843
+ def disposition=( str )
844
+ ensure_parsed
845
+ @disposition = str.downcase
846
+ end
847
+
848
+ def params
849
+ ensure_parsed
850
+ unless @params.blank?
851
+ @params.each do |k, v|
852
+ @params[k] = unquote(v)
853
+ end
854
+ end
855
+ @params
856
+ end
857
+
858
+ def []( key )
859
+ ensure_parsed
860
+ @params and unquote(@params[key])
861
+ end
862
+
863
+ def []=( key, val )
864
+ ensure_parsed
865
+ (@params ||= {})[key] = val
866
+ end
867
+
868
+ private
869
+
870
+ def init
871
+ @disposition = @params = nil
872
+ end
873
+
874
+ def set( args )
875
+ @disposition, @params = *args
876
+ end
877
+
878
+ def isempty?
879
+ not @disposition and (not @params or @params.empty?)
880
+ end
881
+
882
+ def do_accept( strategy )
883
+ strategy.meta @disposition
884
+ @params.each do |k,v|
885
+ strategy.meta ';'
886
+ strategy.space
887
+ strategy.kv_pair k, unquote(v)
888
+ end
889
+ end
890
+
891
+ end
892
+
893
+
894
+ class HeaderField # redefine
895
+
896
+ FNAME_TO_CLASS = {
897
+ 'date' => DateTimeHeader,
898
+ 'resent-date' => DateTimeHeader,
899
+ 'to' => AddressHeader,
900
+ 'cc' => AddressHeader,
901
+ 'bcc' => AddressHeader,
902
+ 'from' => AddressHeader,
903
+ 'reply-to' => AddressHeader,
904
+ 'resent-to' => AddressHeader,
905
+ 'resent-cc' => AddressHeader,
906
+ 'resent-bcc' => AddressHeader,
907
+ 'resent-from' => AddressHeader,
908
+ 'resent-reply-to' => AddressHeader,
909
+ 'sender' => SingleAddressHeader,
910
+ 'resent-sender' => SingleAddressHeader,
911
+ 'return-path' => ReturnPathHeader,
912
+ 'message-id' => MessageIdHeader,
913
+ 'resent-message-id' => MessageIdHeader,
914
+ 'in-reply-to' => ReferencesHeader,
915
+ 'received' => ReceivedHeader,
916
+ 'references' => ReferencesHeader,
917
+ 'keywords' => KeywordsHeader,
918
+ 'encrypted' => EncryptedHeader,
919
+ 'mime-version' => MimeVersionHeader,
920
+ 'content-type' => ContentTypeHeader,
921
+ 'content-transfer-encoding' => ContentTransferEncodingHeader,
922
+ 'content-disposition' => ContentDispositionHeader,
923
+ 'content-id' => MessageIdHeader,
924
+ 'subject' => UnstructuredHeader,
925
+ 'comments' => UnstructuredHeader,
926
+ 'content-description' => UnstructuredHeader
927
+ }
928
+
929
+ end
930
+
931
+ end # module TMail