dball-mail 2.2.9.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 (122) hide show
  1. data/CHANGELOG.rdoc +459 -0
  2. data/README.rdoc +582 -0
  3. data/Rakefile +66 -0
  4. data/TODO.rdoc +9 -0
  5. data/lib/VERSION +4 -0
  6. data/lib/mail/attachments_list.rb +105 -0
  7. data/lib/mail/body.rb +286 -0
  8. data/lib/mail/configuration.rb +71 -0
  9. data/lib/mail/core_extensions/nil.rb +11 -0
  10. data/lib/mail/core_extensions/string.rb +27 -0
  11. data/lib/mail/elements/address.rb +306 -0
  12. data/lib/mail/elements/address_list.rb +74 -0
  13. data/lib/mail/elements/content_disposition_element.rb +30 -0
  14. data/lib/mail/elements/content_location_element.rb +25 -0
  15. data/lib/mail/elements/content_transfer_encoding_element.rb +24 -0
  16. data/lib/mail/elements/content_type_element.rb +35 -0
  17. data/lib/mail/elements/date_time_element.rb +26 -0
  18. data/lib/mail/elements/envelope_from_element.rb +34 -0
  19. data/lib/mail/elements/message_ids_element.rb +29 -0
  20. data/lib/mail/elements/mime_version_element.rb +26 -0
  21. data/lib/mail/elements/phrase_list.rb +21 -0
  22. data/lib/mail/elements/received_element.rb +30 -0
  23. data/lib/mail/elements.rb +14 -0
  24. data/lib/mail/encodings/7bit.rb +31 -0
  25. data/lib/mail/encodings/8bit.rb +31 -0
  26. data/lib/mail/encodings/base64.rb +33 -0
  27. data/lib/mail/encodings/binary.rb +31 -0
  28. data/lib/mail/encodings/quoted_printable.rb +38 -0
  29. data/lib/mail/encodings/transfer_encoding.rb +58 -0
  30. data/lib/mail/encodings.rb +268 -0
  31. data/lib/mail/envelope.rb +35 -0
  32. data/lib/mail/field.rb +223 -0
  33. data/lib/mail/field_list.rb +33 -0
  34. data/lib/mail/fields/bcc_field.rb +56 -0
  35. data/lib/mail/fields/cc_field.rb +55 -0
  36. data/lib/mail/fields/comments_field.rb +41 -0
  37. data/lib/mail/fields/common/address_container.rb +16 -0
  38. data/lib/mail/fields/common/common_address.rb +125 -0
  39. data/lib/mail/fields/common/common_date.rb +42 -0
  40. data/lib/mail/fields/common/common_field.rb +50 -0
  41. data/lib/mail/fields/common/common_message_id.rb +44 -0
  42. data/lib/mail/fields/common/parameter_hash.rb +58 -0
  43. data/lib/mail/fields/content_description_field.rb +19 -0
  44. data/lib/mail/fields/content_disposition_field.rb +69 -0
  45. data/lib/mail/fields/content_id_field.rb +63 -0
  46. data/lib/mail/fields/content_location_field.rb +42 -0
  47. data/lib/mail/fields/content_transfer_encoding_field.rb +50 -0
  48. data/lib/mail/fields/content_type_field.rb +198 -0
  49. data/lib/mail/fields/date_field.rb +55 -0
  50. data/lib/mail/fields/from_field.rb +55 -0
  51. data/lib/mail/fields/in_reply_to_field.rb +55 -0
  52. data/lib/mail/fields/keywords_field.rb +44 -0
  53. data/lib/mail/fields/message_id_field.rb +83 -0
  54. data/lib/mail/fields/mime_version_field.rb +53 -0
  55. data/lib/mail/fields/optional_field.rb +13 -0
  56. data/lib/mail/fields/received_field.rb +67 -0
  57. data/lib/mail/fields/references_field.rb +55 -0
  58. data/lib/mail/fields/reply_to_field.rb +55 -0
  59. data/lib/mail/fields/resent_bcc_field.rb +55 -0
  60. data/lib/mail/fields/resent_cc_field.rb +55 -0
  61. data/lib/mail/fields/resent_date_field.rb +35 -0
  62. data/lib/mail/fields/resent_from_field.rb +55 -0
  63. data/lib/mail/fields/resent_message_id_field.rb +34 -0
  64. data/lib/mail/fields/resent_sender_field.rb +62 -0
  65. data/lib/mail/fields/resent_to_field.rb +55 -0
  66. data/lib/mail/fields/return_path_field.rb +64 -0
  67. data/lib/mail/fields/sender_field.rb +67 -0
  68. data/lib/mail/fields/structured_field.rb +51 -0
  69. data/lib/mail/fields/subject_field.rb +16 -0
  70. data/lib/mail/fields/to_field.rb +55 -0
  71. data/lib/mail/fields/unstructured_field.rb +179 -0
  72. data/lib/mail/fields.rb +35 -0
  73. data/lib/mail/header.rb +264 -0
  74. data/lib/mail/mail.rb +255 -0
  75. data/lib/mail/message.rb +1972 -0
  76. data/lib/mail/network/delivery_methods/file_delivery.rb +40 -0
  77. data/lib/mail/network/delivery_methods/sendmail.rb +62 -0
  78. data/lib/mail/network/delivery_methods/smtp.rb +136 -0
  79. data/lib/mail/network/delivery_methods/test_mailer.rb +40 -0
  80. data/lib/mail/network/retriever_methods/imap.rb +213 -0
  81. data/lib/mail/network/retriever_methods/pop3.rb +194 -0
  82. data/lib/mail/network/retriever_methods/test_retriever.rb +31 -0
  83. data/lib/mail/network.rb +10 -0
  84. data/lib/mail/parsers/address_lists.rb +64 -0
  85. data/lib/mail/parsers/address_lists.treetop +19 -0
  86. data/lib/mail/parsers/content_disposition.rb +535 -0
  87. data/lib/mail/parsers/content_disposition.treetop +46 -0
  88. data/lib/mail/parsers/content_location.rb +139 -0
  89. data/lib/mail/parsers/content_location.treetop +20 -0
  90. data/lib/mail/parsers/content_transfer_encoding.rb +162 -0
  91. data/lib/mail/parsers/content_transfer_encoding.treetop +20 -0
  92. data/lib/mail/parsers/content_type.rb +967 -0
  93. data/lib/mail/parsers/content_type.treetop +68 -0
  94. data/lib/mail/parsers/date_time.rb +114 -0
  95. data/lib/mail/parsers/date_time.treetop +11 -0
  96. data/lib/mail/parsers/envelope_from.rb +194 -0
  97. data/lib/mail/parsers/envelope_from.treetop +32 -0
  98. data/lib/mail/parsers/message_ids.rb +45 -0
  99. data/lib/mail/parsers/message_ids.treetop +15 -0
  100. data/lib/mail/parsers/mime_version.rb +144 -0
  101. data/lib/mail/parsers/mime_version.treetop +19 -0
  102. data/lib/mail/parsers/phrase_lists.rb +45 -0
  103. data/lib/mail/parsers/phrase_lists.treetop +15 -0
  104. data/lib/mail/parsers/received.rb +71 -0
  105. data/lib/mail/parsers/received.treetop +11 -0
  106. data/lib/mail/parsers/rfc2045.rb +464 -0
  107. data/lib/mail/parsers/rfc2045.treetop +36 -0
  108. data/lib/mail/parsers/rfc2822.rb +5318 -0
  109. data/lib/mail/parsers/rfc2822.treetop +410 -0
  110. data/lib/mail/parsers/rfc2822_obsolete.rb +3757 -0
  111. data/lib/mail/parsers/rfc2822_obsolete.treetop +241 -0
  112. data/lib/mail/part.rb +116 -0
  113. data/lib/mail/parts_list.rb +43 -0
  114. data/lib/mail/patterns.rb +34 -0
  115. data/lib/mail/utilities.rb +211 -0
  116. data/lib/mail/version.rb +24 -0
  117. data/lib/mail/version_specific/ruby_1_8.rb +97 -0
  118. data/lib/mail/version_specific/ruby_1_9.rb +87 -0
  119. data/lib/mail.rb +80 -0
  120. data/lib/tasks/corpus.rake +125 -0
  121. data/lib/tasks/treetop.rake +10 -0
  122. metadata +255 -0
data/lib/mail/field.rb ADDED
@@ -0,0 +1,223 @@
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 Patterns
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
+ # Generic Field Exception
39
+ class FieldError < StandardError
40
+ end
41
+
42
+ # Raised when a parsing error has occurred (ie, a StructuredField has tried
43
+ # to parse a field that is invalid or improperly written)
44
+ class ParseError < FieldError #:nodoc:
45
+ end
46
+
47
+ # Raised when attempting to set a structured field's contents to an invalid syntax
48
+ class SyntaxError < FieldError #:nodoc:
49
+ end
50
+
51
+ # Accepts a string:
52
+ #
53
+ # Field.new("field-name: field data")
54
+ #
55
+ # Or name, value pair:
56
+ #
57
+ # Field.new("field-name", "value")
58
+ #
59
+ # Or a name by itself:
60
+ #
61
+ # Field.new("field-name")
62
+ #
63
+ # Note, does not want a terminating carriage return. Returns
64
+ # self appropriately parsed. If value is not a string, then
65
+ # it will be passed through as is, for example, content-type
66
+ # field can accept an array with the type and a hash of
67
+ # parameters:
68
+ #
69
+ # Field.new('content-type', ['text', 'plain', {:charset => 'UTF-8'}])
70
+ def initialize(name, value = nil, charset = 'utf-8')
71
+ case
72
+ when name =~ /:/ && value.blank? # Field.new("field-name: field data")
73
+ name, value = split(name)
74
+ create_field(name, value, charset)
75
+ when name !~ /:/ && value.blank? # Field.new("field-name")
76
+ create_field(name, nil, charset)
77
+ else # Field.new("field-name", "value")
78
+ create_field(name, value, charset)
79
+ end
80
+ return self
81
+ end
82
+
83
+ def field=(value)
84
+ @field = value
85
+ end
86
+
87
+ def field
88
+ @field
89
+ end
90
+
91
+ def name
92
+ field.name
93
+ end
94
+
95
+ def value
96
+ field.value
97
+ end
98
+
99
+ def value=(val)
100
+ create_field(name, val, charset)
101
+ end
102
+
103
+ def to_s
104
+ field.to_s
105
+ end
106
+
107
+ def update(name, value)
108
+ create_field(name, value, charset)
109
+ end
110
+
111
+ def same( other )
112
+ match_to_s(other.name, field.name)
113
+ end
114
+
115
+ def <=>( other )
116
+ self_order = FIELD_ORDER.rindex(self.name.to_s.downcase) || 100
117
+ other_order = FIELD_ORDER.rindex(other.name.to_s.downcase) || 100
118
+ self_order <=> other_order
119
+ end
120
+
121
+ def method_missing(name, *args, &block)
122
+ field.send(name, *args, &block)
123
+ end
124
+
125
+ FIELD_ORDER = %w[ return-path received
126
+ resent-date resent-from resent-sender resent-to
127
+ resent-cc resent-bcc resent-message-id
128
+ date from sender reply-to to cc bcc
129
+ message-id in-reply-to references
130
+ subject comments keywords
131
+ mime-version content-type content-transfer-encoding
132
+ content-location content-disposition content-description ]
133
+
134
+ private
135
+
136
+ def split(raw_field)
137
+ match_data = raw_field.mb_chars.match(/^(#{FIELD_NAME})\s*:\s*(#{FIELD_BODY})?$/)
138
+ [match_data[1].to_s.mb_chars.strip, match_data[2].to_s.mb_chars.strip]
139
+ rescue
140
+ STDERR.puts "WARNING: Could not parse (and so ignorning) '#{raw_field}'"
141
+ end
142
+
143
+ def create_field(name, value, charset)
144
+ begin
145
+ self.field = new_field(name, value, charset)
146
+ rescue Mail::Field::ParseError => e
147
+ self.field = Mail::UnstructuredField.new(name, value)
148
+ self.field.errors << [name, value, e]
149
+ self.field
150
+ end
151
+ end
152
+
153
+ def new_field(name, value, charset)
154
+ # Could do this with constantize and make it "as DRY as", but a simple case
155
+ # statement is, well, simpler...
156
+ case name.to_s.downcase
157
+ when /^to$/i
158
+ ToField.new(value, charset)
159
+ when /^cc$/i
160
+ CcField.new(value, charset)
161
+ when /^bcc$/i
162
+ BccField.new(value, charset)
163
+ when /^message-id$/i
164
+ MessageIdField.new(value, charset)
165
+ when /^in-reply-to$/i
166
+ InReplyToField.new(value, charset)
167
+ when /^references$/i
168
+ ReferencesField.new(value, charset)
169
+ when /^subject$/i
170
+ SubjectField.new(value, charset)
171
+ when /^comments$/i
172
+ CommentsField.new(value, charset)
173
+ when /^keywords$/i
174
+ KeywordsField.new(value, charset)
175
+ when /^date$/i
176
+ DateField.new(value, charset)
177
+ when /^from$/i
178
+ FromField.new(value, charset)
179
+ when /^sender$/i
180
+ SenderField.new(value, charset)
181
+ when /^reply-to$/i
182
+ ReplyToField.new(value, charset)
183
+ when /^resent-date$/i
184
+ ResentDateField.new(value, charset)
185
+ when /^resent-from$/i
186
+ ResentFromField.new(value, charset)
187
+ when /^resent-sender$/i
188
+ ResentSenderField.new(value, charset)
189
+ when /^resent-to$/i
190
+ ResentToField.new(value, charset)
191
+ when /^resent-cc$/i
192
+ ResentCcField.new(value, charset)
193
+ when /^resent-bcc$/i
194
+ ResentBccField.new(value, charset)
195
+ when /^resent-message-id$/i
196
+ ResentMessageIdField.new(value, charset)
197
+ when /^return-path$/i
198
+ ReturnPathField.new(value, charset)
199
+ when /^received$/i
200
+ ReceivedField.new(value, charset)
201
+ when /^mime-version$/i
202
+ MimeVersionField.new(value, charset)
203
+ when /^content-transfer-encoding$/i
204
+ ContentTransferEncodingField.new(value, charset)
205
+ when /^content-description$/i
206
+ ContentDescriptionField.new(value, charset)
207
+ when /^content-disposition$/i
208
+ ContentDispositionField.new(value, charset)
209
+ when /^content-type$/i
210
+ ContentTypeField.new(value, charset)
211
+ when /^content-id$/i
212
+ ContentIdField.new(value, charset)
213
+ when /^content-location$/i
214
+ ContentLocationField.new(value, charset)
215
+ else
216
+ OptionalField.new(name, value, charset)
217
+ end
218
+
219
+ end
220
+
221
+ end
222
+
223
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+
4
+ # Field List class provides an enhanced array that keeps a list of
5
+ # email fields in order. And allows you to insert new fields without
6
+ # having to worry about the order they will appear in.
7
+ class FieldList < Array
8
+
9
+ include Enumerable
10
+
11
+ def <<( new_field )
12
+ current_entry = self.rindex(new_field)
13
+ if current_entry
14
+ self.insert((current_entry + 1), new_field)
15
+ else
16
+ insert_idx = -1
17
+ self.each_with_index do |item, idx|
18
+ case item <=> new_field
19
+ when -1
20
+ next
21
+ when 0
22
+ next
23
+ when 1
24
+ insert_idx = idx
25
+ break
26
+ end
27
+ end
28
+ insert(insert_idx, new_field)
29
+ end
30
+ end
31
+
32
+ end
33
+ end
@@ -0,0 +1,56 @@
1
+ # encoding: utf-8
2
+ #
3
+ # = Blind Carbon Copy Field
4
+ #
5
+ # The Bcc field inherits from StructuredField and handles the Bcc: header
6
+ # field in the email.
7
+ #
8
+ # Sending bcc to a mail message will instantiate a Mail::Field object that
9
+ # has a BccField as it's field type. This includes all Mail::CommonAddress
10
+ # module instance metods.
11
+ #
12
+ # Only one Bcc field can appear in a header, though it can have multiple
13
+ # addresses and groups of addresses.
14
+ #
15
+ # == Examples:
16
+ #
17
+ # mail = Mail.new
18
+ # mail.bcc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
+ # mail.bcc #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
20
+ # mail[:bcc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
21
+ # mail['bcc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
22
+ # mail['Bcc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
23
+ #
24
+ # mail[:bcc].encoded #=> '' # Bcc field does not get output into an email
25
+ # mail[:bcc].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
26
+ # mail[:bcc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
27
+ # mail[:bcc].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
28
+ #
29
+ require 'mail/fields/common/common_address'
30
+
31
+ module Mail
32
+ class BccField < StructuredField
33
+
34
+ include Mail::CommonAddress
35
+
36
+ FIELD_NAME = 'bcc'
37
+ CAPITALIZED_FIELD = 'Bcc'
38
+
39
+ def initialize(value = '', charset = 'utf-8')
40
+ @charset = charset
41
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
42
+ self.parse
43
+ self
44
+ end
45
+
46
+ # Bcc field should never be :encoded
47
+ def encoded
48
+ ''
49
+ end
50
+
51
+ def decoded
52
+ do_decode
53
+ end
54
+
55
+ end
56
+ end
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+ #
3
+ # = Carbon Copy Field
4
+ #
5
+ # The Cc field inherits from StructuredField and handles the Cc: header
6
+ # field in the email.
7
+ #
8
+ # Sending cc to a mail message will instantiate a Mail::Field object that
9
+ # has a CcField as it's field type. This includes all Mail::CommonAddress
10
+ # module instance metods.
11
+ #
12
+ # Only one Cc field can appear in a header, though it can have multiple
13
+ # addresses and groups of addresses.
14
+ #
15
+ # == Examples:
16
+ #
17
+ # mail = Mail.new
18
+ # mail.cc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
+ # mail.cc #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
20
+ # mail[:cc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
21
+ # mail['cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
22
+ # mail['Cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
23
+ #
24
+ # mail[:cc].encoded #=> 'Cc: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
25
+ # mail[:cc].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
26
+ # mail[:cc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
27
+ # mail[:cc].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
28
+ #
29
+ require 'mail/fields/common/common_address'
30
+
31
+ module Mail
32
+ class CcField < StructuredField
33
+
34
+ include Mail::CommonAddress
35
+
36
+ FIELD_NAME = 'cc'
37
+ CAPITALIZED_FIELD = 'Cc'
38
+
39
+ def initialize(value = nil, charset = 'utf-8')
40
+ self.charset = charset
41
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
42
+ self.parse
43
+ self
44
+ end
45
+
46
+ def encoded
47
+ do_encode(CAPITALIZED_FIELD)
48
+ end
49
+
50
+ def decoded
51
+ do_decode
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ #
3
+ # = Comments Field
4
+ #
5
+ # The Comments field inherits from UnstructuredField and handles the Comments:
6
+ # header field in the email.
7
+ #
8
+ # Sending comments to a mail message will instantiate a Mail::Field object that
9
+ # has a CommentsField as it's field type.
10
+ #
11
+ # An email header can have as many comments fields as it wants. There is no upper
12
+ # limit, the comments field is also optional (that is, no comment is needed)
13
+ #
14
+ # == Examples:
15
+ #
16
+ # mail = Mail.new
17
+ # mail.comments = 'This is a comment'
18
+ # mail.comments #=> 'This is a comment'
19
+ # mail[:comments] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
20
+ # mail['comments'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
21
+ # mail['comments'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
22
+ #
23
+ # mail.comments = "This is another comment"
24
+ # mail[:comments].map { |c| c.to_s }
25
+ # #=> ['This is a comment', "This is another comment"]
26
+ #
27
+ module Mail
28
+ class CommentsField < UnstructuredField
29
+
30
+ FIELD_NAME = 'comments'
31
+ CAPITALIZED_FIELD = 'Comments'
32
+
33
+ def initialize(value = nil, charset = 'utf-8')
34
+ @charset = charset
35
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value))
36
+ self.parse
37
+ self
38
+ end
39
+
40
+ end
41
+ end
@@ -0,0 +1,16 @@
1
+ module Mail
2
+
3
+ class AddressContainer < Array
4
+
5
+ def initialize(field, list = [])
6
+ @field = field
7
+ super(list)
8
+ end
9
+
10
+ def << (address)
11
+ @field << address
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,125 @@
1
+ # encoding: utf-8
2
+ require 'mail/fields/common/address_container'
3
+
4
+ module Mail
5
+ module CommonAddress # :nodoc:
6
+
7
+ def parse(val = value)
8
+ unless val.blank?
9
+ @tree = AddressList.new(encode_if_needed(val))
10
+ else
11
+ nil
12
+ end
13
+ end
14
+
15
+ def charset
16
+ @charset
17
+ end
18
+
19
+ def encode_if_needed(val)
20
+ Encodings.address_encode(val, charset)
21
+ end
22
+
23
+ # Allows you to iterate through each address object in the syntax tree
24
+ def each
25
+ tree.addresses.each do |address|
26
+ yield(address)
27
+ end
28
+ end
29
+
30
+ # Returns the address string of all the addresses in the address list
31
+ def addresses
32
+ list = tree.addresses.map { |a| a.address }
33
+ Mail::AddressContainer.new(self, list)
34
+ end
35
+
36
+ # Returns the formatted string of all the addresses in the address list
37
+ def formatted
38
+ list = tree.addresses.map { |a| a.format }
39
+ Mail::AddressContainer.new(self, list)
40
+ end
41
+
42
+ # Returns the display name of all the addresses in the address list
43
+ def display_names
44
+ list = tree.addresses.map { |a| a.display_name }
45
+ Mail::AddressContainer.new(self, list)
46
+ end
47
+
48
+ # Returns the actual address objects in the address list
49
+ def addrs
50
+ list = tree.addresses
51
+ Mail::AddressContainer.new(self, list)
52
+ end
53
+
54
+ # Returns a hash of group name => address strings for the address list
55
+ def groups
56
+ @groups = Hash.new
57
+ tree.group_recipients.each do |group|
58
+ @groups[group.group_name.text_value.to_str] = get_group_addresses(group.group_list)
59
+ end
60
+ @groups
61
+ end
62
+
63
+ # Returns the addresses that are part of groups
64
+ def group_addresses
65
+ groups.map { |k,v| v.map { |a| a.format } }.flatten
66
+ end
67
+
68
+ # Returns the name of all the groups in a string
69
+ def group_names # :nodoc:
70
+ tree.group_names
71
+ end
72
+
73
+ def default
74
+ addresses
75
+ end
76
+
77
+ def <<(val)
78
+ case
79
+ when val.nil?
80
+ raise ArgumentError, "Need to pass an address to <<"
81
+ when val.blank?
82
+ parse(encoded)
83
+ else
84
+ parse((formatted + [val]).join(", "))
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ def do_encode(field_name)
91
+ return '' if value.blank?
92
+ address_array = tree.addresses.reject { |a| group_addresses.include?(a.encoded) }.compact.map { |a| a.encoded }
93
+ address_text = address_array.join(", \r\n\s")
94
+ group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.encoded }.join(", \r\n\s")};" }
95
+ group_text = group_array.join(" \r\n\s")
96
+ return_array = [address_text, group_text].reject { |a| a.blank? }
97
+ "#{field_name}: #{return_array.join(", \r\n\s")}\r\n"
98
+ end
99
+
100
+ def do_decode
101
+ return nil if value.blank?
102
+ address_array = tree.addresses.reject { |a| group_addresses.include?(a.decoded) }.map { |a| a.decoded }
103
+ address_text = address_array.join(", ")
104
+ group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.decoded }.join(", ")};" }
105
+ group_text = group_array.join(" ")
106
+ return_array = [address_text, group_text].reject { |a| a.blank? }
107
+ return_array.join(", ")
108
+ end
109
+
110
+ # Returns the syntax tree of the Addresses
111
+ def tree # :nodoc:
112
+ @tree ||= AddressList.new(value)
113
+ end
114
+
115
+ def get_group_addresses(group_list)
116
+ if group_list.respond_to?(:addresses)
117
+ group_list.addresses.map do |address_tree|
118
+ Mail::Address.new(address_tree)
119
+ end
120
+ else
121
+ []
122
+ end
123
+ end
124
+ end
125
+ end
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ module CommonDate # :nodoc:
4
+ # Returns a date time object of the parsed date
5
+ def date_time
6
+ ::DateTime.parse("#{element.date_string} #{element.time_string}")
7
+ end
8
+
9
+ def default
10
+ date_time
11
+ end
12
+
13
+ def parse(val = value)
14
+ unless val.blank?
15
+ @element = Mail::DateTimeElement.new(val)
16
+ @tree = @element.tree
17
+ else
18
+ nil
19
+ end
20
+ end
21
+
22
+ private
23
+
24
+ def do_encode(field_name)
25
+ "#{field_name}: #{value}\r\n"
26
+ end
27
+
28
+ def do_decode
29
+ "#{value}"
30
+ end
31
+
32
+ def element
33
+ @element ||= Mail::DateTimeElement.new(value)
34
+ end
35
+
36
+ # Returns the syntax tree of the Date
37
+ def tree
38
+ @tree ||= element.tree
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,50 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ module CommonField # :nodoc:
4
+ def name=(value)
5
+ @name = value
6
+ end
7
+
8
+ def name
9
+ @name
10
+ end
11
+
12
+ def value=(value)
13
+ @length = nil
14
+ @tree = nil
15
+ @element = nil
16
+ @value = value
17
+ end
18
+
19
+ def value
20
+ @value
21
+ end
22
+
23
+ def to_s
24
+ decoded
25
+ end
26
+
27
+ def default
28
+ decoded
29
+ end
30
+
31
+ def field_length
32
+ @length ||= "#{name}: #{encode(decoded)}".length
33
+ end
34
+
35
+ def responsible_for?( val )
36
+ name.to_s.downcase == val.to_s.downcase
37
+ end
38
+
39
+ private
40
+
41
+ def strip_field(field_name, value)
42
+ if value.is_a?(Array)
43
+ value
44
+ else
45
+ value.to_s.gsub(/#{field_name}:\s+/i, '')
46
+ end
47
+ end
48
+
49
+ end
50
+ end
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ module CommonMessageId # :nodoc:
4
+ def element
5
+ @element ||= Mail::MessageIdsElement.new(value) unless value.blank?
6
+ end
7
+
8
+ def parse(val = value)
9
+ unless val.blank?
10
+ @element = Mail::MessageIdsElement.new(val)
11
+ else
12
+ nil
13
+ end
14
+ end
15
+
16
+ def message_id
17
+ element.message_id if element
18
+ end
19
+
20
+ def message_ids
21
+ element.message_ids if element
22
+ end
23
+
24
+ def default
25
+ return nil unless message_ids
26
+ if message_ids.length == 1
27
+ message_ids[0]
28
+ else
29
+ message_ids
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def do_encode(field_name)
36
+ %Q{#{field_name}: #{do_decode}\r\n}
37
+ end
38
+
39
+ def do_decode
40
+ "#{message_ids.map { |m| "<#{m}>" }.join(' ')}"
41
+ end
42
+
43
+ end
44
+ end