nano-fast-tool 0.0.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 (138) hide show
  1. checksums.yaml +7 -0
  2. data/mail-2.9.1/MIT-LICENSE +20 -0
  3. data/mail-2.9.1/README.md +771 -0
  4. data/mail-2.9.1/lib/mail/attachments_list.rb +109 -0
  5. data/mail-2.9.1/lib/mail/body.rb +305 -0
  6. data/mail-2.9.1/lib/mail/configuration.rb +78 -0
  7. data/mail-2.9.1/lib/mail/constants.rb +79 -0
  8. data/mail-2.9.1/lib/mail/elements/address.rb +258 -0
  9. data/mail-2.9.1/lib/mail/elements/address_list.rb +34 -0
  10. data/mail-2.9.1/lib/mail/elements/content_disposition_element.rb +20 -0
  11. data/mail-2.9.1/lib/mail/elements/content_location_element.rb +17 -0
  12. data/mail-2.9.1/lib/mail/elements/content_transfer_encoding_element.rb +13 -0
  13. data/mail-2.9.1/lib/mail/elements/content_type_element.rb +25 -0
  14. data/mail-2.9.1/lib/mail/elements/date_time_element.rb +15 -0
  15. data/mail-2.9.1/lib/mail/elements/envelope_from_element.rb +39 -0
  16. data/mail-2.9.1/lib/mail/elements/message_ids_element.rb +31 -0
  17. data/mail-2.9.1/lib/mail/elements/mime_version_element.rb +15 -0
  18. data/mail-2.9.1/lib/mail/elements/phrase_list.rb +19 -0
  19. data/mail-2.9.1/lib/mail/elements/received_element.rb +35 -0
  20. data/mail-2.9.1/lib/mail/elements.rb +15 -0
  21. data/mail-2.9.1/lib/mail/encodings/7bit.rb +27 -0
  22. data/mail-2.9.1/lib/mail/encodings/8bit.rb +18 -0
  23. data/mail-2.9.1/lib/mail/encodings/base64.rb +38 -0
  24. data/mail-2.9.1/lib/mail/encodings/binary.rb +13 -0
  25. data/mail-2.9.1/lib/mail/encodings/identity.rb +24 -0
  26. data/mail-2.9.1/lib/mail/encodings/quoted_printable.rb +45 -0
  27. data/mail-2.9.1/lib/mail/encodings/transfer_encoding.rb +77 -0
  28. data/mail-2.9.1/lib/mail/encodings/unix_to_unix.rb +20 -0
  29. data/mail-2.9.1/lib/mail/encodings.rb +314 -0
  30. data/mail-2.9.1/lib/mail/envelope.rb +28 -0
  31. data/mail-2.9.1/lib/mail/field.rb +313 -0
  32. data/mail-2.9.1/lib/mail/field_list.rb +87 -0
  33. data/mail-2.9.1/lib/mail/fields/bcc_field.rb +49 -0
  34. data/mail-2.9.1/lib/mail/fields/cc_field.rb +33 -0
  35. data/mail-2.9.1/lib/mail/fields/comments_field.rb +31 -0
  36. data/mail-2.9.1/lib/mail/fields/common_address_field.rb +162 -0
  37. data/mail-2.9.1/lib/mail/fields/common_date_field.rb +56 -0
  38. data/mail-2.9.1/lib/mail/fields/common_field.rb +77 -0
  39. data/mail-2.9.1/lib/mail/fields/common_message_id_field.rb +41 -0
  40. data/mail-2.9.1/lib/mail/fields/content_description_field.rb +12 -0
  41. data/mail-2.9.1/lib/mail/fields/content_disposition_field.rb +44 -0
  42. data/mail-2.9.1/lib/mail/fields/content_id_field.rb +35 -0
  43. data/mail-2.9.1/lib/mail/fields/content_location_field.rb +28 -0
  44. data/mail-2.9.1/lib/mail/fields/content_transfer_encoding_field.rb +44 -0
  45. data/mail-2.9.1/lib/mail/fields/content_type_field.rb +171 -0
  46. data/mail-2.9.1/lib/mail/fields/date_field.rb +28 -0
  47. data/mail-2.9.1/lib/mail/fields/from_field.rb +33 -0
  48. data/mail-2.9.1/lib/mail/fields/in_reply_to_field.rb +45 -0
  49. data/mail-2.9.1/lib/mail/fields/keywords_field.rb +30 -0
  50. data/mail-2.9.1/lib/mail/fields/message_id_field.rb +36 -0
  51. data/mail-2.9.1/lib/mail/fields/mime_version_field.rb +42 -0
  52. data/mail-2.9.1/lib/mail/fields/named_structured_field.rb +10 -0
  53. data/mail-2.9.1/lib/mail/fields/named_unstructured_field.rb +10 -0
  54. data/mail-2.9.1/lib/mail/fields/optional_field.rb +15 -0
  55. data/mail-2.9.1/lib/mail/fields/parameter_hash.rb +61 -0
  56. data/mail-2.9.1/lib/mail/fields/received_field.rb +61 -0
  57. data/mail-2.9.1/lib/mail/fields/references_field.rb +42 -0
  58. data/mail-2.9.1/lib/mail/fields/reply_to_field.rb +33 -0
  59. data/mail-2.9.1/lib/mail/fields/resent_bcc_field.rb +33 -0
  60. data/mail-2.9.1/lib/mail/fields/resent_cc_field.rb +33 -0
  61. data/mail-2.9.1/lib/mail/fields/resent_date_field.rb +10 -0
  62. data/mail-2.9.1/lib/mail/fields/resent_from_field.rb +33 -0
  63. data/mail-2.9.1/lib/mail/fields/resent_message_id_field.rb +10 -0
  64. data/mail-2.9.1/lib/mail/fields/resent_sender_field.rb +32 -0
  65. data/mail-2.9.1/lib/mail/fields/resent_to_field.rb +33 -0
  66. data/mail-2.9.1/lib/mail/fields/return_path_field.rb +60 -0
  67. data/mail-2.9.1/lib/mail/fields/sender_field.rb +45 -0
  68. data/mail-2.9.1/lib/mail/fields/structured_field.rb +24 -0
  69. data/mail-2.9.1/lib/mail/fields/subject_field.rb +14 -0
  70. data/mail-2.9.1/lib/mail/fields/to_field.rb +33 -0
  71. data/mail-2.9.1/lib/mail/fields/unstructured_field.rb +189 -0
  72. data/mail-2.9.1/lib/mail/fields.rb +45 -0
  73. data/mail-2.9.1/lib/mail/header.rb +237 -0
  74. data/mail-2.9.1/lib/mail/indifferent_hash.rb +147 -0
  75. data/mail-2.9.1/lib/mail/mail.rb +267 -0
  76. data/mail-2.9.1/lib/mail/matchers/attachment_matchers.rb +44 -0
  77. data/mail-2.9.1/lib/mail/matchers/has_sent_mail.rb +201 -0
  78. data/mail-2.9.1/lib/mail/message.rb +2159 -0
  79. data/mail-2.9.1/lib/mail/multibyte/chars.rb +318 -0
  80. data/mail-2.9.1/lib/mail/multibyte/unicode.rb +405 -0
  81. data/mail-2.9.1/lib/mail/multibyte/utils.rb +44 -0
  82. data/mail-2.9.1/lib/mail/multibyte.rb +82 -0
  83. data/mail-2.9.1/lib/mail/network/delivery_methods/exim.rb +50 -0
  84. data/mail-2.9.1/lib/mail/network/delivery_methods/file_delivery.rb +43 -0
  85. data/mail-2.9.1/lib/mail/network/delivery_methods/logger_delivery.rb +34 -0
  86. data/mail-2.9.1/lib/mail/network/delivery_methods/sendmail.rb +87 -0
  87. data/mail-2.9.1/lib/mail/network/delivery_methods/smtp.rb +200 -0
  88. data/mail-2.9.1/lib/mail/network/delivery_methods/smtp_connection.rb +57 -0
  89. data/mail-2.9.1/lib/mail/network/delivery_methods/test_mailer.rb +44 -0
  90. data/mail-2.9.1/lib/mail/network/retriever_methods/base.rb +64 -0
  91. data/mail-2.9.1/lib/mail/network/retriever_methods/imap.rb +190 -0
  92. data/mail-2.9.1/lib/mail/network/retriever_methods/pop3.rb +143 -0
  93. data/mail-2.9.1/lib/mail/network/retriever_methods/test_retriever.rb +45 -0
  94. data/mail-2.9.1/lib/mail/network.rb +16 -0
  95. data/mail-2.9.1/lib/mail/parser_tools.rb +15 -0
  96. data/mail-2.9.1/lib/mail/parsers/address_lists_parser.rb +33245 -0
  97. data/mail-2.9.1/lib/mail/parsers/address_lists_parser.rl +183 -0
  98. data/mail-2.9.1/lib/mail/parsers/content_disposition_parser.rb +904 -0
  99. data/mail-2.9.1/lib/mail/parsers/content_disposition_parser.rl +93 -0
  100. data/mail-2.9.1/lib/mail/parsers/content_location_parser.rb +825 -0
  101. data/mail-2.9.1/lib/mail/parsers/content_location_parser.rl +82 -0
  102. data/mail-2.9.1/lib/mail/parsers/content_transfer_encoding_parser.rb +525 -0
  103. data/mail-2.9.1/lib/mail/parsers/content_transfer_encoding_parser.rl +75 -0
  104. data/mail-2.9.1/lib/mail/parsers/content_type_parser.rb +1051 -0
  105. data/mail-2.9.1/lib/mail/parsers/content_type_parser.rl +94 -0
  106. data/mail-2.9.1/lib/mail/parsers/date_time_parser.rb +894 -0
  107. data/mail-2.9.1/lib/mail/parsers/date_time_parser.rl +73 -0
  108. data/mail-2.9.1/lib/mail/parsers/envelope_from_parser.rb +3678 -0
  109. data/mail-2.9.1/lib/mail/parsers/envelope_from_parser.rl +93 -0
  110. data/mail-2.9.1/lib/mail/parsers/message_ids_parser.rb +5164 -0
  111. data/mail-2.9.1/lib/mail/parsers/message_ids_parser.rl +97 -0
  112. data/mail-2.9.1/lib/mail/parsers/mime_version_parser.rb +516 -0
  113. data/mail-2.9.1/lib/mail/parsers/mime_version_parser.rl +72 -0
  114. data/mail-2.9.1/lib/mail/parsers/phrase_lists_parser.rb +887 -0
  115. data/mail-2.9.1/lib/mail/parsers/phrase_lists_parser.rl +94 -0
  116. data/mail-2.9.1/lib/mail/parsers/received_parser.rb +8785 -0
  117. data/mail-2.9.1/lib/mail/parsers/received_parser.rl +95 -0
  118. data/mail-2.9.1/lib/mail/parsers/rfc2045_content_transfer_encoding.rl +13 -0
  119. data/mail-2.9.1/lib/mail/parsers/rfc2045_content_type.rl +25 -0
  120. data/mail-2.9.1/lib/mail/parsers/rfc2045_mime.rl +16 -0
  121. data/mail-2.9.1/lib/mail/parsers/rfc2183_content_disposition.rl +15 -0
  122. data/mail-2.9.1/lib/mail/parsers/rfc3629_utf8.rl +19 -0
  123. data/mail-2.9.1/lib/mail/parsers/rfc5234_abnf_core_rules.rl +22 -0
  124. data/mail-2.9.1/lib/mail/parsers/rfc5322.rl +74 -0
  125. data/mail-2.9.1/lib/mail/parsers/rfc5322_address.rl +72 -0
  126. data/mail-2.9.1/lib/mail/parsers/rfc5322_date_time.rl +37 -0
  127. data/mail-2.9.1/lib/mail/parsers/rfc5322_lexical_tokens.rl +60 -0
  128. data/mail-2.9.1/lib/mail/parsers.rb +13 -0
  129. data/mail-2.9.1/lib/mail/part.rb +119 -0
  130. data/mail-2.9.1/lib/mail/parts_list.rb +131 -0
  131. data/mail-2.9.1/lib/mail/smtp_envelope.rb +57 -0
  132. data/mail-2.9.1/lib/mail/utilities.rb +576 -0
  133. data/mail-2.9.1/lib/mail/values/unicode_tables.dat +0 -0
  134. data/mail-2.9.1/lib/mail/version.rb +17 -0
  135. data/mail-2.9.1/lib/mail/yaml.rb +30 -0
  136. data/mail-2.9.1/lib/mail.rb +65 -0
  137. data/nano-fast-tool.gemspec +12 -0
  138. metadata +177 -0
@@ -0,0 +1,313 @@
1
+ # frozen_string_literal: true
2
+ require 'mail/fields'
3
+ require 'mail/constants'
4
+
5
+ # encoding: utf-8
6
+ module Mail
7
+ # Provides a single class to call to create a new structured or unstructured
8
+ # field. Works out per RFC what field of field it is being given and returns
9
+ # the correct field of class back on new.
10
+ #
11
+ # ===Per RFC 2822
12
+ #
13
+ # 2.2. Header Fields
14
+ #
15
+ # Header fields are lines composed of a field name, followed by a colon
16
+ # (":"), followed by a field body, and terminated by CRLF. A field
17
+ # name MUST be composed of printable US-ASCII characters (i.e.,
18
+ # characters that have values between 33 and 126, inclusive), except
19
+ # colon. A field body may be composed of any US-ASCII characters,
20
+ # except for CR and LF. However, a field body may contain CRLF when
21
+ # used in header "folding" and "unfolding" as described in section
22
+ # 2.2.3. All field bodies MUST conform to the syntax described in
23
+ # sections 3 and 4 of this standard.
24
+ #
25
+ class Field
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 = {
71
+ "to" => "To",
72
+ "cc" => "Cc",
73
+ "bcc" => "Bcc",
74
+ "message-id" => "Message-ID",
75
+ "in-reply-to" => "In-Reply-To",
76
+ "references" => "References",
77
+ "subject" => "Subject",
78
+ "comments" => "Comments",
79
+ "keywords" => "Keywords",
80
+ "date" => "Date",
81
+ "from" => "From",
82
+ "sender" => "Sender",
83
+ "reply-to" => "Reply-To",
84
+ "resent-date" => "Resent-Date",
85
+ "resent-from" => "Resent-From",
86
+ "resent-sender" => "Resent-Sender",
87
+ "resent-to" => "Resent-To",
88
+ "resent-cc" => "Resent-Cc",
89
+ "resent-bcc" => "Resent-Bcc",
90
+ "resent-message-id" => "Resent-Message-ID",
91
+ "return-path" => "Return-Path",
92
+ "received" => "Received",
93
+ "mime-version" => "MIME-Version",
94
+ "content-transfer-encoding" => "Content-Transfer-Encoding",
95
+ "content-description" => "Content-Description",
96
+ "content-disposition" => "Content-Disposition",
97
+ "content-type" => "Content-Type",
98
+ "content-id" => "Content-ID",
99
+ "content-location" => "Content-Location",
100
+ }
101
+
102
+ # Generic Field Exception
103
+ class FieldError < StandardError
104
+ end
105
+
106
+ # Raised when a parsing error has occurred (ie, a StructuredField has tried
107
+ # to parse a field that is invalid or improperly written)
108
+ class ParseError < FieldError #:nodoc:
109
+ attr_accessor :element, :value, :reason
110
+
111
+ def initialize(element, value, reason)
112
+ @element = element
113
+ @value = to_utf8(value)
114
+ @reason = to_utf8(reason)
115
+ super("#{@element} can not parse |#{@value}|: #{@reason}")
116
+ end
117
+
118
+ private
119
+ def to_utf8(text)
120
+ if text.respond_to?(:force_encoding)
121
+ text.dup.force_encoding(Encoding::UTF_8)
122
+ else
123
+ text
124
+ end
125
+ end
126
+ end
127
+
128
+ class NilParseError < ParseError #:nodoc:
129
+ def initialize(element)
130
+ super element, nil, 'nil is invalid'
131
+ end
132
+ end
133
+
134
+ class IncompleteParseError < ParseError #:nodoc:
135
+ def initialize(element, original_text, unparsed_index)
136
+ parsed_text = to_utf8(original_text[0...unparsed_index])
137
+ super element, original_text, "Only able to parse up to #{parsed_text.inspect}"
138
+ end
139
+ end
140
+
141
+ # Raised when attempting to set a structured field's contents to an invalid syntax
142
+ class SyntaxError < FieldError #:nodoc:
143
+ end
144
+
145
+ class << self
146
+ # Parse a field from a raw header line:
147
+ #
148
+ # Mail::Field.parse("field-name: field data")
149
+ # # => #<Mail::Field …>
150
+ def parse(field, charset = 'utf-8')
151
+ name, value = split(field)
152
+ if name && value
153
+ new name, value, charset
154
+ end
155
+ end
156
+
157
+ def split(raw_field) #:nodoc:
158
+ if raw_field.index(Constants::COLON)
159
+ name, value = raw_field.split(Constants::COLON, 2)
160
+ name.rstrip!
161
+ if /\A#{Constants::FIELD_NAME}\z/.match?(name)
162
+ [ name.rstrip, value.strip ]
163
+ else
164
+ Kernel.warn "WARNING: Ignoring unparsable header #{raw_field.inspect}: invalid header name syntax: #{name.inspect}"
165
+ nil
166
+ end
167
+ else
168
+ raw_field.strip
169
+ end
170
+ rescue => error
171
+ warn "WARNING: Ignoring unparsable header #{raw_field.inspect}: #{error.class}: #{error.message}"
172
+ nil
173
+ end
174
+
175
+ def field_class_for(name) #:nodoc:
176
+ class_name = FIELDS_MAP[name.to_s.downcase]
177
+ Mail.const_get(class_name) if class_name
178
+ end
179
+ end
180
+
181
+ attr_reader :unparsed_value
182
+
183
+ # Create a field by name and optional value:
184
+ #
185
+ # Mail::Field.new("field-name", "value")
186
+ # # => #<Mail::Field …>
187
+ #
188
+ # Values that aren't strings or arrays are coerced to Strings with `#to_s`.
189
+ #
190
+ # Mail::Field.new("field-name", 1234)
191
+ # # => #<Mail::Field …>
192
+ #
193
+ # Mail::Field.new('content-type', ['text', 'plain', {:charset => 'UTF-8'}])
194
+ # # => #<Mail::Field …>
195
+ def initialize(name, value = nil, charset = 'utf-8')
196
+ case
197
+ when name.index(Constants::COLON)
198
+ raise ArgumentError, 'Passing an unparsed header field to Mail::Field.new is not supported in Mail 2.8.0+. Use Mail::Field.parse instead.'
199
+ when Utilities.blank?(value)
200
+ @name = name
201
+ @unparsed_value = nil
202
+ @charset = charset
203
+ else
204
+ @name = name
205
+ @unparsed_value = value
206
+ @charset = charset
207
+ end
208
+ klass = self.class.field_class_for(@name)
209
+ @name = klass ? klass::NAME : @name
210
+ end
211
+
212
+ def field=(field)
213
+ @field = field
214
+ end
215
+
216
+ def field
217
+ @field ||= create_field(@name, @unparsed_value, @charset)
218
+ end
219
+
220
+ def name
221
+ @name
222
+ end
223
+
224
+ def value
225
+ field.value
226
+ end
227
+
228
+ def value=(val)
229
+ @field = create_field(name, val, @charset)
230
+ end
231
+
232
+ def to_s
233
+ field.to_s
234
+ end
235
+
236
+ def inspect
237
+ "#<#{self.class.name} 0x#{(object_id * 2).to_s(16)} #{instance_variables.map do |ivar|
238
+ "#{ivar}=#{instance_variable_get(ivar).inspect}"
239
+ end.join(" ")}>"
240
+ end
241
+
242
+ def same(other)
243
+ other.kind_of?(self.class) && Utilities.match_to_s(other.name, name)
244
+ end
245
+
246
+ def ==(other)
247
+ same(other) && Utilities.match_to_s(other.value, value)
248
+ end
249
+
250
+ def responsible_for?(field_name)
251
+ name.to_s.casecmp(field_name.to_s) == 0
252
+ end
253
+
254
+ def <=>(other)
255
+ field_order_id <=> other.field_order_id
256
+ end
257
+
258
+ def field_order_id
259
+ @field_order_id ||= FIELD_ORDER_LOOKUP.fetch(self.name.to_s.downcase, 100)
260
+ end
261
+
262
+ def method_missing(name, *args, &block)
263
+ field.send(name, *args, &block)
264
+ end
265
+
266
+ def respond_to_missing?(method_name, include_private)
267
+ field.respond_to?(method_name, include_private) || super
268
+ end
269
+
270
+ FIELD_ORDER_LOOKUP = Hash[%w[
271
+ return-path received
272
+ resent-date resent-from resent-sender resent-to
273
+ resent-cc resent-bcc resent-message-id
274
+ date from sender reply-to to cc bcc
275
+ message-id in-reply-to references
276
+ subject comments keywords
277
+ mime-version content-type content-transfer-encoding
278
+ content-location content-disposition content-description
279
+ ].each_with_index.to_a]
280
+
281
+ private
282
+
283
+ def create_field(name, value, charset)
284
+ parse_field(name, value, charset)
285
+ rescue Mail::Field::ParseError => e
286
+ field = Mail::UnstructuredField.new(name, value)
287
+ field.errors << [name, value, e]
288
+ field
289
+ end
290
+
291
+ def parse_field(name, value, charset)
292
+ value = unfold(value) if value.is_a?(String)
293
+
294
+ if klass = self.class.field_class_for(name)
295
+ klass.parse(value, charset)
296
+ else
297
+ OptionalField.parse(name, value, charset)
298
+ end
299
+ end
300
+
301
+ # 2.2.3. Long Header Fields
302
+ #
303
+ # The process of moving from this folded multiple-line representation
304
+ # of a header field to its single line representation is called
305
+ # "unfolding". Unfolding is accomplished by simply removing any CRLF
306
+ # that is immediately followed by WSP. Each header field should be
307
+ # treated in its unfolded form for further syntactic and semantic
308
+ # evaluation.
309
+ def unfold(string)
310
+ string.gsub(Constants::UNFOLD_WS, '\1')
311
+ end
312
+ end
313
+ end
@@ -0,0 +1,87 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ module Mail
4
+
5
+ # Field List class provides an enhanced array that keeps a list of
6
+ # email fields in order. And allows you to insert new fields without
7
+ # having to worry about the order they will appear in.
8
+ class FieldList < Array
9
+ def has_field?(field_name)
10
+ any? { |f| f.responsible_for? field_name }
11
+ end
12
+
13
+ def get_field(field_name)
14
+ fields = select_fields(field_name)
15
+ case fields.size
16
+ when 0; nil
17
+ when 1; fields.first
18
+ else fields
19
+ end
20
+ end
21
+
22
+ def add_field(field)
23
+ if field.singular?
24
+ replace_field field
25
+ else
26
+ insert_field field
27
+ end
28
+ end
29
+ alias_method :<<, :add_field
30
+
31
+ def replace_field(field)
32
+ if first_offset = index { |f| f.responsible_for? field.name }
33
+ delete_field field.name
34
+ insert first_offset, field
35
+ else
36
+ insert_field field
37
+ end
38
+ end
39
+
40
+ # Insert the field in sorted order.
41
+ #
42
+ # Heavily based on bisect.insort from Python, which is:
43
+ # Copyright (C) 2001-2013 Python Software Foundation.
44
+ # Licensed under <http://docs.python.org/license.html>
45
+ # From <http://hg.python.org/cpython/file/2.7/Lib/bisect.py>
46
+ def insert_field(field)
47
+ lo, hi = 0, size
48
+ while lo < hi
49
+ mid = (lo + hi).div(2)
50
+ if field < self[mid]
51
+ hi = mid
52
+ else
53
+ lo = mid + 1
54
+ end
55
+ end
56
+
57
+ insert lo, field
58
+ end
59
+
60
+ def delete_field(name)
61
+ delete_if { |f| f.responsible_for? name }
62
+ end
63
+
64
+ def summary
65
+ map { |f| "<#{f.name}: #{f.value}>" }.join(", ")
66
+ end
67
+
68
+ private
69
+
70
+ def select_fields(field_name)
71
+ fields = select { |f| f.responsible_for? field_name }
72
+ if fields.size > 1 && singular?(field_name)
73
+ Array(fields.detect { |f| f.errors.size == 0 } || fields.first)
74
+ else
75
+ fields
76
+ end
77
+ end
78
+
79
+ def singular?(field_name)
80
+ if klass = Mail::Field.field_class_for(field_name)
81
+ klass.singular?
82
+ else
83
+ false
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,49 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Mail
5
+ # = Blind Carbon Copy Field
6
+ #
7
+ # The Bcc field inherits from StructuredField and handles the Bcc: header
8
+ # field in the email.
9
+ #
10
+ # Sending bcc to a mail message will instantiate a Mail::Field object that
11
+ # has a BccField as its field type. This includes all Mail::CommonAddress
12
+ # module instance metods.
13
+ #
14
+ # Only one Bcc field can appear in a header, though it can have multiple
15
+ # addresses and groups of addresses.
16
+ #
17
+ # == Examples:
18
+ #
19
+ # mail = Mail.new
20
+ # mail.bcc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
21
+ # mail.bcc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
22
+ # mail[:bcc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
23
+ # mail['bcc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
24
+ # mail['Bcc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::BccField:0x180e1c4
25
+ #
26
+ # mail[:bcc].encoded #=> '' # Bcc field does not get output into an email
27
+ # mail[:bcc].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
28
+ # mail[:bcc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
29
+ # mail[:bcc].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
30
+ class BccField < CommonAddressField #:nodoc:
31
+ NAME = 'Bcc'
32
+
33
+ attr_accessor :include_in_headers
34
+
35
+ def initialize(value = nil, charset = nil)
36
+ super
37
+ self.include_in_headers = false
38
+ end
39
+
40
+ # Bcc field should not be :encoded by default
41
+ def encoded
42
+ if include_in_headers
43
+ super
44
+ else
45
+ ''
46
+ end
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Mail
5
+ # = Carbon Copy Field
6
+ #
7
+ # The Cc field inherits from StructuredField and handles the Cc: header
8
+ # field in the email.
9
+ #
10
+ # Sending cc to a mail message will instantiate a Mail::Field object that
11
+ # has a CcField as its field type. This includes all Mail::CommonAddress
12
+ # module instance metods.
13
+ #
14
+ # Only one Cc field can appear in a header, though it can have multiple
15
+ # addresses and groups of addresses.
16
+ #
17
+ # == Examples:
18
+ #
19
+ # mail = Mail.new
20
+ # mail.cc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
21
+ # mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
22
+ # mail[:cc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
23
+ # mail['cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
24
+ # mail['Cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
25
+ #
26
+ # mail[:cc].encoded #=> 'Cc: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
27
+ # mail[:cc].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
28
+ # mail[:cc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
29
+ # mail[:cc].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
30
+ class CcField < CommonAddressField #:nodoc:
31
+ NAME = 'Cc'
32
+ end
33
+ end
@@ -0,0 +1,31 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Mail
5
+ # = Comments Field
6
+ #
7
+ # The Comments field inherits from UnstructuredField and handles the Comments:
8
+ # header field in the email.
9
+ #
10
+ # Sending comments to a mail message will instantiate a Mail::Field object that
11
+ # has a CommentsField as its field type.
12
+ #
13
+ # An email header can have as many comments fields as it wants. There is no upper
14
+ # limit, the comments field is also optional (that is, no comment is needed)
15
+ #
16
+ # == Examples:
17
+ #
18
+ # mail = Mail.new
19
+ # mail.comments = 'This is a comment'
20
+ # mail.comments #=> 'This is a comment'
21
+ # mail[:comments] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
22
+ # mail['comments'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
23
+ # mail['comments'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
24
+ #
25
+ # mail.comments = "This is another comment"
26
+ # mail[:comments].map { |c| c.to_s }
27
+ # #=> ['This is a comment', "This is another comment"]
28
+ class CommentsField < NamedUnstructuredField #:nodoc:
29
+ NAME = 'Comments'
30
+ end
31
+ end
@@ -0,0 +1,162 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ module Mail
5
+ class AddressContainer < Array #:nodoc:
6
+ def initialize(field, list = nil)
7
+ @field = field
8
+ super list if list
9
+ end
10
+
11
+ def <<(address)
12
+ @field << address
13
+ end
14
+ end
15
+
16
+ class CommonAddressField < NamedStructuredField #:nodoc:
17
+ def self.singular?
18
+ true
19
+ end
20
+
21
+ def initialize(value = nil, charset = nil)
22
+ super encode_if_needed(value, charset), charset
23
+ end
24
+
25
+ def element # :nodoc:
26
+ @element ||= AddressList.new(value)
27
+ end
28
+
29
+ # Allows you to iterate through each address object in the address_list
30
+ def each
31
+ element.addresses.each do |address|
32
+ yield(address)
33
+ end
34
+ end
35
+
36
+ def default
37
+ addresses
38
+ end
39
+
40
+ def address
41
+ addresses.first
42
+ end
43
+
44
+ # Returns the address string of all the addresses in the address list
45
+ def addresses
46
+ list = element.addresses.map { |a| a.address }
47
+ Mail::AddressContainer.new(self, list)
48
+ end
49
+
50
+ # Returns the formatted string of all the addresses in the address list
51
+ def formatted
52
+ list = element.addresses.map { |a| a.format }
53
+ Mail::AddressContainer.new(self, list)
54
+ end
55
+
56
+ # Returns the display name of all the addresses in the address list
57
+ def display_names
58
+ list = element.addresses.map { |a| a.display_name }
59
+ Mail::AddressContainer.new(self, list)
60
+ end
61
+
62
+ # Returns the actual address objects in the address list
63
+ def addrs
64
+ list = element.addresses
65
+ Mail::AddressContainer.new(self, list)
66
+ end
67
+
68
+ # Returns a hash of group name => address strings for the address list
69
+ def groups
70
+ element.addresses_grouped_by_group
71
+ end
72
+
73
+ # Returns the addresses that are part of groups
74
+ def group_addresses
75
+ decoded_group_addresses
76
+ end
77
+
78
+ # Returns a list of decoded group addresses
79
+ def decoded_group_addresses
80
+ groups.map { |k,v| v.map { |a| a.decoded } }.flatten
81
+ end
82
+
83
+ # Returns a list of encoded group addresses
84
+ def encoded_group_addresses
85
+ groups.map { |k,v| v.map { |a| a.encoded } }.flatten
86
+ end
87
+
88
+ # Returns the name of all the groups in a string
89
+ def group_names # :nodoc:
90
+ element.group_names
91
+ end
92
+
93
+ def <<(val)
94
+ case
95
+ when val.nil?
96
+ raise ArgumentError, "Need to pass an address to <<"
97
+ when Utilities.blank?(val)
98
+ self
99
+ else
100
+ self.value = [self.value, encode_if_needed(val)].reject { |a| Utilities.blank?(a) }.join(", ")
101
+ end
102
+ end
103
+
104
+ def encode_if_needed(val, val_charset = charset) #:nodoc:
105
+ case val
106
+ when nil
107
+ val
108
+
109
+ # Need to join arrays of addresses into a single value
110
+ when Array
111
+ val.compact.map { |a| encode_if_needed a, val_charset }.join(', ')
112
+
113
+ # Pass through UTF-8; encode non-UTF-8.
114
+ else
115
+ utf8_if_needed(val, val_charset) || Encodings.encode_non_usascii(val, val_charset)
116
+ end
117
+ end
118
+
119
+ private
120
+
121
+ # Pass through UTF-8 addresses
122
+ def utf8_if_needed(val, val_charset)
123
+ if /\AUTF-?8\z/i.match?(val_charset)
124
+ val
125
+ elsif val.encoding == Encoding::UTF_8
126
+ val
127
+ elsif (utf8 = val.dup.force_encoding(Encoding::UTF_8)).valid_encoding?
128
+ utf8
129
+ end
130
+ end
131
+
132
+ def do_encode
133
+ return '' if Utilities.blank?(value)
134
+ address_array = element.addresses.reject { |a| encoded_group_addresses.include?(a.encoded) }.compact.map { |a| a.encoded }
135
+ address_text = address_array.join(", \r\n\s")
136
+ group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.encoded }.join(", \r\n\s")};" }
137
+ group_text = group_array.join(" \r\n\s")
138
+ return_array = [address_text, group_text].reject { |a| Utilities.blank?(a) }
139
+ "#{name}: #{return_array.join(", \r\n\s")}\r\n"
140
+ end
141
+
142
+ def do_decode
143
+ return nil if Utilities.blank?(value)
144
+ address_array = element.addresses.reject { |a| decoded_group_addresses.include?(a.decoded) }.map { |a| a.decoded }
145
+ address_text = address_array.join(", ")
146
+ group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.decoded }.join(", ")};" }
147
+ group_text = group_array.join(" ")
148
+ return_array = [address_text, group_text].reject { |a| Utilities.blank?(a) }
149
+ return_array.join(", ")
150
+ end
151
+
152
+ def get_group_addresses(group_list)
153
+ if group_list.respond_to?(:addresses)
154
+ group_list.addresses.map do |address|
155
+ Mail::Address.new(address)
156
+ end
157
+ else
158
+ []
159
+ end
160
+ end
161
+ end
162
+ end