tmail 1.1.1

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 (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