mail-portertech 2.6.2.edge

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 (153) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.rdoc +753 -0
  3. data/CONTRIBUTING.md +60 -0
  4. data/Dependencies.txt +2 -0
  5. data/Gemfile +15 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +683 -0
  8. data/Rakefile +29 -0
  9. data/TODO.rdoc +9 -0
  10. data/lib/mail.rb +91 -0
  11. data/lib/mail/attachments_list.rb +104 -0
  12. data/lib/mail/body.rb +291 -0
  13. data/lib/mail/check_delivery_params.rb +20 -0
  14. data/lib/mail/configuration.rb +75 -0
  15. data/lib/mail/core_extensions/nil.rb +19 -0
  16. data/lib/mail/core_extensions/object.rb +13 -0
  17. data/lib/mail/core_extensions/smtp.rb +24 -0
  18. data/lib/mail/core_extensions/string.rb +43 -0
  19. data/lib/mail/core_extensions/string/access.rb +145 -0
  20. data/lib/mail/core_extensions/string/multibyte.rb +78 -0
  21. data/lib/mail/elements.rb +14 -0
  22. data/lib/mail/elements/address.rb +270 -0
  23. data/lib/mail/elements/address_list.rb +51 -0
  24. data/lib/mail/elements/content_disposition_element.rb +26 -0
  25. data/lib/mail/elements/content_location_element.rb +21 -0
  26. data/lib/mail/elements/content_transfer_encoding_element.rb +17 -0
  27. data/lib/mail/elements/content_type_element.rb +31 -0
  28. data/lib/mail/elements/date_time_element.rb +22 -0
  29. data/lib/mail/elements/envelope_from_element.rb +39 -0
  30. data/lib/mail/elements/message_ids_element.rb +24 -0
  31. data/lib/mail/elements/mime_version_element.rb +22 -0
  32. data/lib/mail/elements/phrase_list.rb +16 -0
  33. data/lib/mail/elements/received_element.rb +26 -0
  34. data/lib/mail/encodings.rb +304 -0
  35. data/lib/mail/encodings/7bit.rb +31 -0
  36. data/lib/mail/encodings/8bit.rb +31 -0
  37. data/lib/mail/encodings/base64.rb +33 -0
  38. data/lib/mail/encodings/binary.rb +31 -0
  39. data/lib/mail/encodings/quoted_printable.rb +39 -0
  40. data/lib/mail/encodings/transfer_encoding.rb +58 -0
  41. data/lib/mail/envelope.rb +30 -0
  42. data/lib/mail/field.rb +247 -0
  43. data/lib/mail/field_list.rb +33 -0
  44. data/lib/mail/fields.rb +35 -0
  45. data/lib/mail/fields/bcc_field.rb +56 -0
  46. data/lib/mail/fields/cc_field.rb +55 -0
  47. data/lib/mail/fields/comments_field.rb +41 -0
  48. data/lib/mail/fields/common/address_container.rb +16 -0
  49. data/lib/mail/fields/common/common_address.rb +135 -0
  50. data/lib/mail/fields/common/common_date.rb +35 -0
  51. data/lib/mail/fields/common/common_field.rb +57 -0
  52. data/lib/mail/fields/common/common_message_id.rb +48 -0
  53. data/lib/mail/fields/common/parameter_hash.rb +58 -0
  54. data/lib/mail/fields/content_description_field.rb +19 -0
  55. data/lib/mail/fields/content_disposition_field.rb +70 -0
  56. data/lib/mail/fields/content_id_field.rb +62 -0
  57. data/lib/mail/fields/content_location_field.rb +42 -0
  58. data/lib/mail/fields/content_transfer_encoding_field.rb +44 -0
  59. data/lib/mail/fields/content_type_field.rb +201 -0
  60. data/lib/mail/fields/date_field.rb +57 -0
  61. data/lib/mail/fields/from_field.rb +55 -0
  62. data/lib/mail/fields/in_reply_to_field.rb +56 -0
  63. data/lib/mail/fields/keywords_field.rb +44 -0
  64. data/lib/mail/fields/message_id_field.rb +82 -0
  65. data/lib/mail/fields/mime_version_field.rb +53 -0
  66. data/lib/mail/fields/optional_field.rb +13 -0
  67. data/lib/mail/fields/received_field.rb +75 -0
  68. data/lib/mail/fields/references_field.rb +56 -0
  69. data/lib/mail/fields/reply_to_field.rb +55 -0
  70. data/lib/mail/fields/resent_bcc_field.rb +55 -0
  71. data/lib/mail/fields/resent_cc_field.rb +55 -0
  72. data/lib/mail/fields/resent_date_field.rb +35 -0
  73. data/lib/mail/fields/resent_from_field.rb +55 -0
  74. data/lib/mail/fields/resent_message_id_field.rb +34 -0
  75. data/lib/mail/fields/resent_sender_field.rb +62 -0
  76. data/lib/mail/fields/resent_to_field.rb +55 -0
  77. data/lib/mail/fields/return_path_field.rb +65 -0
  78. data/lib/mail/fields/sender_field.rb +67 -0
  79. data/lib/mail/fields/structured_field.rb +51 -0
  80. data/lib/mail/fields/subject_field.rb +16 -0
  81. data/lib/mail/fields/to_field.rb +55 -0
  82. data/lib/mail/fields/unstructured_field.rb +204 -0
  83. data/lib/mail/header.rb +274 -0
  84. data/lib/mail/indifferent_hash.rb +146 -0
  85. data/lib/mail/mail.rb +267 -0
  86. data/lib/mail/matchers/has_sent_mail.rb +157 -0
  87. data/lib/mail/message.rb +2160 -0
  88. data/lib/mail/multibyte.rb +42 -0
  89. data/lib/mail/multibyte/chars.rb +474 -0
  90. data/lib/mail/multibyte/exceptions.rb +8 -0
  91. data/lib/mail/multibyte/unicode.rb +400 -0
  92. data/lib/mail/multibyte/utils.rb +60 -0
  93. data/lib/mail/network.rb +14 -0
  94. data/lib/mail/network/delivery_methods/exim.rb +52 -0
  95. data/lib/mail/network/delivery_methods/file_delivery.rb +45 -0
  96. data/lib/mail/network/delivery_methods/sendmail.rb +89 -0
  97. data/lib/mail/network/delivery_methods/smtp.rb +142 -0
  98. data/lib/mail/network/delivery_methods/smtp_connection.rb +61 -0
  99. data/lib/mail/network/delivery_methods/test_mailer.rb +44 -0
  100. data/lib/mail/network/retriever_methods/base.rb +63 -0
  101. data/lib/mail/network/retriever_methods/imap.rb +173 -0
  102. data/lib/mail/network/retriever_methods/pop3.rb +140 -0
  103. data/lib/mail/network/retriever_methods/test_retriever.rb +43 -0
  104. data/lib/mail/parsers.rb +26 -0
  105. data/lib/mail/parsers/address_lists_parser.rb +132 -0
  106. data/lib/mail/parsers/content_disposition_parser.rb +67 -0
  107. data/lib/mail/parsers/content_location_parser.rb +35 -0
  108. data/lib/mail/parsers/content_transfer_encoding_parser.rb +33 -0
  109. data/lib/mail/parsers/content_type_parser.rb +64 -0
  110. data/lib/mail/parsers/date_time_parser.rb +36 -0
  111. data/lib/mail/parsers/envelope_from_parser.rb +45 -0
  112. data/lib/mail/parsers/message_ids_parser.rb +39 -0
  113. data/lib/mail/parsers/mime_version_parser.rb +41 -0
  114. data/lib/mail/parsers/phrase_lists_parser.rb +33 -0
  115. data/lib/mail/parsers/ragel.rb +17 -0
  116. data/lib/mail/parsers/ragel/common.rl +184 -0
  117. data/lib/mail/parsers/ragel/date_time.rl +30 -0
  118. data/lib/mail/parsers/ragel/parser_info.rb +61 -0
  119. data/lib/mail/parsers/ragel/ruby.rb +39 -0
  120. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
  121. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
  122. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
  123. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
  124. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
  125. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
  126. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
  127. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
  128. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
  129. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
  130. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
  131. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
  132. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2129 -0
  133. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
  134. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
  135. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
  136. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
  137. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
  138. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
  139. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
  140. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
  141. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
  142. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
  143. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
  144. data/lib/mail/parsers/received_parser.rb +47 -0
  145. data/lib/mail/part.rb +120 -0
  146. data/lib/mail/parts_list.rb +57 -0
  147. data/lib/mail/patterns.rb +37 -0
  148. data/lib/mail/utilities.rb +225 -0
  149. data/lib/mail/values/unicode_tables.dat +0 -0
  150. data/lib/mail/version.rb +4 -0
  151. data/lib/mail/version_specific/ruby_1_8.rb +119 -0
  152. data/lib/mail/version_specific/ruby_1_9.rb +159 -0
  153. metadata +276 -0
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+ require 'mail/encodings/8bit'
3
+
4
+ module Mail
5
+ module Encodings
6
+ class SevenBit < EightBit
7
+ NAME = '7bit'
8
+
9
+ PRIORITY = 1
10
+
11
+ # 7bit and 8bit operate the same
12
+
13
+ # Decode the string
14
+ def self.decode(str)
15
+ super
16
+ end
17
+
18
+ # Encode the string
19
+ def self.encode(str)
20
+ super
21
+ end
22
+
23
+ # Idenity encodings have a fixed cost, 1 byte out per 1 byte in
24
+ def self.cost(str)
25
+ super
26
+ end
27
+
28
+ Encodings.register(NAME, self)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+ require 'mail/encodings/binary'
3
+
4
+ module Mail
5
+ module Encodings
6
+ class EightBit < Binary
7
+ NAME = '8bit'
8
+
9
+ PRIORITY = 4
10
+
11
+ # 8bit is an identiy encoding, meaning nothing to do
12
+
13
+ # Decode the string
14
+ def self.decode(str)
15
+ str.to_lf
16
+ end
17
+
18
+ # Encode the string
19
+ def self.encode(str)
20
+ str.to_crlf
21
+ end
22
+
23
+ # Idenity encodings have a fixed cost, 1 byte out per 1 byte in
24
+ def self.cost(str)
25
+ 1.0
26
+ end
27
+
28
+ Encodings.register(NAME, self)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ require 'mail/encodings/7bit'
3
+
4
+ module Mail
5
+ module Encodings
6
+ class Base64 < SevenBit
7
+ NAME = 'base64'
8
+
9
+ PRIORITY = 3
10
+
11
+ def self.can_encode?(enc)
12
+ true
13
+ end
14
+
15
+ # Decode the string from Base64
16
+ def self.decode(str)
17
+ RubyVer.decode_base64( str )
18
+ end
19
+
20
+ # Encode the string to Base64
21
+ def self.encode(str)
22
+ RubyVer.encode_base64( str ).to_crlf
23
+ end
24
+
25
+ # Base64 has a fixed cost, 4 bytes out per 3 bytes in
26
+ def self.cost(str)
27
+ 4.0/3
28
+ end
29
+
30
+ Encodings.register(NAME, self)
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+ require 'mail/encodings/transfer_encoding'
3
+
4
+ module Mail
5
+ module Encodings
6
+ class Binary < TransferEncoding
7
+ NAME = 'binary'
8
+
9
+ PRIORITY = 5
10
+
11
+ # Binary is an identiy encoding, meaning nothing to do
12
+
13
+ # Decode the string
14
+ def self.decode(str)
15
+ str
16
+ end
17
+
18
+ # Encode the string
19
+ def self.encode(str)
20
+ str
21
+ end
22
+
23
+ # Idenity encodings have a fixed cost, 1 byte out per 1 byte in
24
+ def self.cost(str)
25
+ 1.0
26
+ end
27
+
28
+ Encodings.register(NAME, self)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ require 'mail/encodings/7bit'
3
+
4
+ module Mail
5
+ module Encodings
6
+ class QuotedPrintable < SevenBit
7
+ NAME='quoted-printable'
8
+
9
+ PRIORITY = 2
10
+
11
+ def self.can_encode?(str)
12
+ EightBit.can_encode? str
13
+ end
14
+
15
+ # Decode the string from Quoted-Printable. Cope with hard line breaks
16
+ # that were incorrectly encoded as hex instead of literal CRLF.
17
+ def self.decode(str)
18
+ str.gsub(/(?:=0D=0A|=0D|=0A)\r\n/, "\r\n").unpack("M*").first.to_lf
19
+ end
20
+
21
+ def self.encode(str)
22
+ [str.to_lf].pack("M").to_crlf
23
+ end
24
+
25
+ def self.cost(str)
26
+ # These bytes probably do not need encoding
27
+ c = str.count("\x9\xA\xD\x20-\x3C\x3E-\x7E")
28
+ # Everything else turns into =XX where XX is a
29
+ # two digit hex number (taking 3 bytes)
30
+ total = (str.bytesize - c)*3 + c
31
+ total.to_f/str.bytesize
32
+ end
33
+
34
+ private
35
+
36
+ Encodings.register(NAME, self)
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ module Encodings
4
+ class TransferEncoding
5
+ NAME = ''
6
+
7
+ PRIORITY = -1
8
+
9
+ def self.can_transport?(enc)
10
+ enc = Encodings.get_name(enc)
11
+ if Encodings.defined? enc
12
+ Encodings.get_encoding(enc).new.is_a? self
13
+ else
14
+ false
15
+ end
16
+ end
17
+
18
+ def self.can_encode?(enc)
19
+ can_transport? enc
20
+ end
21
+
22
+ def self.cost(str)
23
+ raise "Unimplemented"
24
+ end
25
+
26
+ def self.to_s
27
+ self::NAME
28
+ end
29
+
30
+ def self.get_best_compatible(source_encoding, str)
31
+ if self.can_transport? source_encoding then
32
+ source_encoding
33
+ else
34
+ choices = []
35
+ Encodings.get_all.each do |enc|
36
+ choices << enc if self.can_transport? enc and enc.can_encode? source_encoding
37
+ end
38
+ best = nil
39
+ best_cost = 100
40
+ choices.each do |enc|
41
+ this_cost = enc.cost str
42
+ if this_cost < best_cost then
43
+ best_cost = this_cost
44
+ best = enc
45
+ elsif this_cost == best_cost then
46
+ best = enc if enc::PRIORITY < best::PRIORITY
47
+ end
48
+ end
49
+ best
50
+ end
51
+ end
52
+
53
+ def to_s
54
+ self.class.to_s
55
+ end
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+ #
3
+ # = Mail Envelope
4
+ #
5
+ # The Envelope class provides a field for the first line in an
6
+ # mbox file, that looks like "From mikel@test.lindsaar.net DATETIME"
7
+ #
8
+ # This envelope class reads that line, and turns it into an
9
+ # Envelope.from and Envelope.date for your use.
10
+ module Mail
11
+ class Envelope < StructuredField
12
+
13
+ def initialize(*args)
14
+ super(FIELD_NAME, strip_field(FIELD_NAME, args.last))
15
+ end
16
+
17
+ def element
18
+ @element ||= Mail::EnvelopeFromElement.new(value)
19
+ end
20
+
21
+ def date
22
+ ::DateTime.parse("#{element.date_time}")
23
+ end
24
+
25
+ def from
26
+ element.address
27
+ end
28
+
29
+ end
30
+ end
@@ -0,0 +1,247 @@
1
+ require 'mail/fields'
2
+
3
+ # encoding: utf-8
4
+ module Mail
5
+ # Provides a single class to call to create a new structured or unstructured
6
+ # field. Works out per RFC what field of field it is being given and returns
7
+ # the correct field of class back on new.
8
+ #
9
+ # ===Per RFC 2822
10
+ #
11
+ # 2.2. Header Fields
12
+ #
13
+ # Header fields are lines composed of a field name, followed by a colon
14
+ # (":"), followed by a field body, and terminated by CRLF. A field
15
+ # name MUST be composed of printable US-ASCII characters (i.e.,
16
+ # characters that have values between 33 and 126, inclusive), except
17
+ # colon. A field body may be composed of any US-ASCII characters,
18
+ # except for CR and LF. However, a field body may contain CRLF when
19
+ # used in header "folding" and "unfolding" as described in section
20
+ # 2.2.3. All field bodies MUST conform to the syntax described in
21
+ # sections 3 and 4 of this standard.
22
+ #
23
+ class Field
24
+
25
+ include Utilities
26
+ include Comparable
27
+
28
+ STRUCTURED_FIELDS = %w[ bcc cc content-description content-disposition
29
+ content-id content-location content-transfer-encoding
30
+ content-type date from in-reply-to keywords message-id
31
+ mime-version received references reply-to
32
+ resent-bcc resent-cc resent-date resent-from
33
+ resent-message-id resent-sender resent-to
34
+ return-path sender to ]
35
+
36
+ KNOWN_FIELDS = STRUCTURED_FIELDS + ['comments', 'subject']
37
+
38
+ FIELDS_MAP = {
39
+ "to" => ToField,
40
+ "cc" => CcField,
41
+ "bcc" => BccField,
42
+ "message-id" => MessageIdField,
43
+ "in-reply-to" => InReplyToField,
44
+ "references" => ReferencesField,
45
+ "subject" => SubjectField,
46
+ "comments" => CommentsField,
47
+ "keywords" => KeywordsField,
48
+ "date" => DateField,
49
+ "from" => FromField,
50
+ "sender" => SenderField,
51
+ "reply-to" => ReplyToField,
52
+ "resent-date" => ResentDateField,
53
+ "resent-from" => ResentFromField,
54
+ "resent-sender" => ResentSenderField,
55
+ "resent-to" => ResentToField,
56
+ "resent-cc" => ResentCcField,
57
+ "resent-bcc" => ResentBccField,
58
+ "resent-message-id" => ResentMessageIdField,
59
+ "return-path" => ReturnPathField,
60
+ "received" => ReceivedField,
61
+ "mime-version" => MimeVersionField,
62
+ "content-transfer-encoding" => ContentTransferEncodingField,
63
+ "content-description" => ContentDescriptionField,
64
+ "content-disposition" => ContentDispositionField,
65
+ "content-type" => ContentTypeField,
66
+ "content-id" => ContentIdField,
67
+ "content-location" => ContentLocationField,
68
+ }
69
+
70
+ FIELD_NAME_MAP = FIELDS_MAP.inject({}) do |map, (field, field_klass)|
71
+ map.update(field => field_klass::CAPITALIZED_FIELD)
72
+ end
73
+
74
+ # Generic Field Exception
75
+ class FieldError < StandardError
76
+ end
77
+
78
+ # Raised when a parsing error has occurred (ie, a StructuredField has tried
79
+ # to parse a field that is invalid or improperly written)
80
+ class ParseError < FieldError #:nodoc:
81
+ attr_accessor :element, :value, :reason
82
+
83
+ def initialize(element, value, reason)
84
+ @element = element
85
+ @value = value
86
+ @reason = reason
87
+ super("#{element} can not parse |#{value}|\nReason was: #{reason}")
88
+ end
89
+ end
90
+
91
+ # Raised when attempting to set a structured field's contents to an invalid syntax
92
+ class SyntaxError < FieldError #:nodoc:
93
+ end
94
+
95
+ # Accepts a string:
96
+ #
97
+ # Field.new("field-name: field data")
98
+ #
99
+ # Or name, value pair:
100
+ #
101
+ # Field.new("field-name", "value")
102
+ #
103
+ # Or a name by itself:
104
+ #
105
+ # Field.new("field-name")
106
+ #
107
+ # Note, does not want a terminating carriage return. Returns
108
+ # self appropriately parsed. If value is not a string, then
109
+ # it will be passed through as is, for example, content-type
110
+ # field can accept an array with the type and a hash of
111
+ # parameters:
112
+ #
113
+ # Field.new('content-type', ['text', 'plain', {:charset => 'UTF-8'}])
114
+ def initialize(name, value = nil, charset = 'utf-8')
115
+ case
116
+ when name =~ /:/ # Field.new("field-name: field data")
117
+ @charset = value.blank? ? charset : value
118
+ @name = name[FIELD_PREFIX]
119
+ @raw_value = name
120
+ @value = nil
121
+ when name !~ /:/ && value.blank? # Field.new("field-name")
122
+ @name = name
123
+ @value = nil
124
+ @raw_value = nil
125
+ @charset = charset
126
+ else # Field.new("field-name", "value")
127
+ @name = name
128
+ @value = value
129
+ @raw_value = nil
130
+ @charset = charset
131
+ end
132
+ @name = FIELD_NAME_MAP[@name.to_s.downcase] || @name
133
+ end
134
+
135
+ def field=(value)
136
+ @field = value
137
+ end
138
+
139
+ def field
140
+ _, @value = split(@raw_value) if @raw_value && !@value
141
+ @field ||= create_field(@name, @value, @charset)
142
+ end
143
+
144
+ def name
145
+ @name
146
+ end
147
+
148
+ def value
149
+ field.value
150
+ end
151
+
152
+ def value=(val)
153
+ @field = create_field(name, val, @charset)
154
+ end
155
+
156
+ def to_s
157
+ field.to_s
158
+ end
159
+
160
+ def inspect
161
+ "#<#{self.class.name} 0x#{(object_id * 2).to_s(16)} #{instance_variables.map do |ivar|
162
+ "#{ivar}=#{instance_variable_get(ivar).inspect}"
163
+ end.join(" ")}>"
164
+ end
165
+
166
+ def update(name, value)
167
+ @field = create_field(name, value, @charset)
168
+ end
169
+
170
+ def same( other )
171
+ match_to_s(other.name, self.name)
172
+ end
173
+
174
+ def responsible_for?( val )
175
+ name.to_s.casecmp(val.to_s) == 0
176
+ end
177
+
178
+ alias_method :==, :same
179
+
180
+ def <=>( other )
181
+ self.field_order_id <=> other.field_order_id
182
+ end
183
+
184
+ def field_order_id
185
+ @field_order_id ||= (FIELD_ORDER_LOOKUP[self.name.to_s.downcase] || 100)
186
+ end
187
+
188
+ def method_missing(name, *args, &block)
189
+ field.send(name, *args, &block)
190
+ end
191
+
192
+ FIELD_ORDER = %w[ return-path received
193
+ resent-date resent-from resent-sender resent-to
194
+ resent-cc resent-bcc resent-message-id
195
+ date from sender reply-to to cc bcc
196
+ message-id in-reply-to references
197
+ subject comments keywords
198
+ mime-version content-type content-transfer-encoding
199
+ content-location content-disposition content-description ]
200
+
201
+ FIELD_ORDER_LOOKUP = Hash[FIELD_ORDER.each_with_index.to_a]
202
+
203
+ private
204
+
205
+ def split(raw_field)
206
+ match_data = raw_field.mb_chars.match(FIELD_SPLIT)
207
+ [match_data[1].to_s.mb_chars.strip, match_data[2].to_s.mb_chars.strip.to_s]
208
+ rescue
209
+ STDERR.puts "WARNING: Could not parse (and so ignoring) '#{raw_field}'"
210
+ end
211
+
212
+ # 2.2.3. Long Header Fields
213
+ #
214
+ # The process of moving from this folded multiple-line representation
215
+ # of a header field to its single line representation is called
216
+ # "unfolding". Unfolding is accomplished by simply removing any CRLF
217
+ # that is immediately followed by WSP. Each header field should be
218
+ # treated in its unfolded form for further syntactic and semantic
219
+ # evaluation.
220
+ def unfold(string)
221
+ string.gsub(/[\r\n \t]+/m, ' ')
222
+ end
223
+
224
+ def create_field(name, value, charset)
225
+ value = unfold(value) if value.is_a?(String)
226
+
227
+ begin
228
+ new_field(name, value, charset)
229
+ rescue Mail::Field::ParseError => e
230
+ field = Mail::UnstructuredField.new(name, value)
231
+ field.errors << [name, value, e]
232
+ field
233
+ end
234
+ end
235
+
236
+ def new_field(name, value, charset)
237
+ lower_case_name = name.to_s.downcase
238
+ if field_klass = FIELDS_MAP[lower_case_name]
239
+ field_klass.new(value, charset)
240
+ else
241
+ OptionalField.new(name, value, charset)
242
+ end
243
+ end
244
+
245
+ end
246
+
247
+ end