~michaelforrest/use-case-mapper/trunk

« back to all changes in this revision

Viewing changes to vendor/rails/actionmailer/lib/action_mailer/vendor/tmail-1.2.3/tmail/header.rb

  • Committer: Michael Forrest
  • Date: 2010-10-15 16:28:50 UTC
  • Revision ID: michael.forrest@canonical.com-20101015162850-tj2vchanv0kr0dun
refrozeĀ gems

Show diffs side-by-side

added added

removed removed

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