net-imap 0.2.1 → 0.2.2

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.

Potentially problematic release.


This version of net-imap might be problematic. Click here for more details.

@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Net
4
+ class IMAP < Protocol
5
+
6
+ # Decode a string from modified UTF-7 format to UTF-8.
7
+ #
8
+ # UTF-7 is a 7-bit encoding of Unicode [UTF7]. IMAP uses a
9
+ # slightly modified version of this to encode mailbox names
10
+ # containing non-ASCII characters; see [IMAP] section 5.1.3.
11
+ #
12
+ # Net::IMAP does _not_ automatically encode and decode
13
+ # mailbox names to and from UTF-7.
14
+ def self.decode_utf7(s)
15
+ return s.gsub(/&([^-]+)?-/n) {
16
+ if $1
17
+ ($1.tr(",", "/") + "===").unpack1("m").encode(Encoding::UTF_8, Encoding::UTF_16BE)
18
+ else
19
+ "&"
20
+ end
21
+ }
22
+ end
23
+
24
+ # Encode a string from UTF-8 format to modified UTF-7.
25
+ def self.encode_utf7(s)
26
+ return s.gsub(/(&)|[^\x20-\x7e]+/) {
27
+ if $1
28
+ "&-"
29
+ else
30
+ base64 = [$&.encode(Encoding::UTF_16BE)].pack("m0")
31
+ "&" + base64.delete("=").tr("/", ",") + "-"
32
+ end
33
+ }.force_encoding("ASCII-8BIT")
34
+ end
35
+
36
+ # Formats +time+ as an IMAP-style date.
37
+ def self.format_date(time)
38
+ return time.strftime('%d-%b-%Y')
39
+ end
40
+
41
+ # Formats +time+ as an IMAP-style date-time.
42
+ def self.format_datetime(time)
43
+ return time.strftime('%d-%b-%Y %H:%M %z')
44
+ end
45
+
46
+ end
47
+ end
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Net
4
+ class IMAP < Protocol
5
+
6
+ # :category: Message Flags
7
+ #
8
+ # Flag indicating a message has been seen.
9
+ SEEN = :Seen
10
+
11
+ # :category: Message Flags
12
+ #
13
+ # Flag indicating a message has been answered.
14
+ ANSWERED = :Answered
15
+
16
+ # :category: Message Flags
17
+ #
18
+ # Flag indicating a message has been flagged for special or urgent
19
+ # attention.
20
+ FLAGGED = :Flagged
21
+
22
+ # :category: Message Flags
23
+ #
24
+ # Flag indicating a message has been marked for deletion. This
25
+ # will occur when the mailbox is closed or expunged.
26
+ DELETED = :Deleted
27
+
28
+ # :category: Message Flags
29
+ #
30
+ # Flag indicating a message is only a draft or work-in-progress version.
31
+ DRAFT = :Draft
32
+
33
+ # :category: Message Flags
34
+ #
35
+ # Flag indicating that the message is "recent," meaning that this
36
+ # session is the first session in which the client has been notified
37
+ # of this message.
38
+ RECENT = :Recent
39
+
40
+ # :category: Mailbox Flags
41
+ #
42
+ # Flag indicating that a mailbox context name cannot contain
43
+ # children.
44
+ NOINFERIORS = :Noinferiors
45
+
46
+ # :category: Mailbox Flags
47
+ #
48
+ # Flag indicating that a mailbox is not selected.
49
+ NOSELECT = :Noselect
50
+
51
+ # :category: Mailbox Flags
52
+ #
53
+ # Flag indicating that a mailbox has been marked "interesting" by
54
+ # the server; this commonly indicates that the mailbox contains
55
+ # new messages.
56
+ MARKED = :Marked
57
+
58
+ # :category: Mailbox Flags
59
+ #
60
+ # Flag indicating that the mailbox does not contains new messages.
61
+ UNMARKED = :Unmarked
62
+
63
+ @@max_flag_count = 10000
64
+
65
+ # Returns the max number of flags interned to symbols.
66
+ def self.max_flag_count
67
+ return @@max_flag_count
68
+ end
69
+
70
+ # Sets the max number of flags interned to symbols.
71
+ def self.max_flag_count=(count)
72
+ @@max_flag_count = count
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,527 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Net
4
+ class IMAP < Protocol
5
+
6
+ # Net::IMAP::ContinuationRequest represents command continuation requests.
7
+ #
8
+ # The command continuation request response is indicated by a "+" token
9
+ # instead of a tag. This form of response indicates that the server is
10
+ # ready to accept the continuation of a command from the client. The
11
+ # remainder of this response is a line of text.
12
+ #
13
+ # continue_req ::= "+" SPACE (resp_text / base64)
14
+ #
15
+ # ==== Fields:
16
+ #
17
+ # data:: Returns the data (Net::IMAP::ResponseText).
18
+ #
19
+ # raw_data:: Returns the raw data string.
20
+ class ContinuationRequest < Struct.new(:data, :raw_data)
21
+ end
22
+
23
+ # Net::IMAP::UntaggedResponse represents untagged responses.
24
+ #
25
+ # Data transmitted by the server to the client and status responses
26
+ # that do not indicate command completion are prefixed with the token
27
+ # "*", and are called untagged responses.
28
+ #
29
+ # response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye /
30
+ # mailbox_data / message_data / capability_data)
31
+ #
32
+ # ==== Fields:
33
+ #
34
+ # name:: Returns the name, such as "FLAGS", "LIST", or "FETCH".
35
+ #
36
+ # data:: Returns the data such as an array of flag symbols,
37
+ # a ((<Net::IMAP::MailboxList>)) object.
38
+ #
39
+ # raw_data:: Returns the raw data string.
40
+ class UntaggedResponse < Struct.new(:name, :data, :raw_data)
41
+ end
42
+
43
+ # Net::IMAP::IgnoredResponse represents intentionally ignored responses.
44
+ #
45
+ # This includes untagged response "NOOP" sent by eg. Zimbra to avoid some
46
+ # clients to close the connection.
47
+ #
48
+ # It matches no IMAP standard.
49
+ #
50
+ # ==== Fields:
51
+ #
52
+ # raw_data:: Returns the raw data string.
53
+ class IgnoredResponse < Struct.new(:raw_data)
54
+ end
55
+
56
+ # Net::IMAP::TaggedResponse represents tagged responses.
57
+ #
58
+ # The server completion result response indicates the success or
59
+ # failure of the operation. It is tagged with the same tag as the
60
+ # client command which began the operation.
61
+ #
62
+ # response_tagged ::= tag SPACE resp_cond_state CRLF
63
+ #
64
+ # tag ::= 1*<any ATOM_CHAR except "+">
65
+ #
66
+ # resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text
67
+ #
68
+ # ==== Fields:
69
+ #
70
+ # tag:: Returns the tag.
71
+ #
72
+ # name:: Returns the name, one of "OK", "NO", or "BAD".
73
+ #
74
+ # data:: Returns the data. See ((<Net::IMAP::ResponseText>)).
75
+ #
76
+ # raw_data:: Returns the raw data string.
77
+ #
78
+ class TaggedResponse < Struct.new(:tag, :name, :data, :raw_data)
79
+ end
80
+
81
+ # Net::IMAP::ResponseText represents texts of responses.
82
+ # The text may be prefixed by the response code.
83
+ #
84
+ # resp_text ::= ["[" resp-text-code "]" SP] text
85
+ #
86
+ # ==== Fields:
87
+ #
88
+ # code:: Returns the response code. See ((<Net::IMAP::ResponseCode>)).
89
+ #
90
+ # text:: Returns the text.
91
+ #
92
+ class ResponseText < Struct.new(:code, :text)
93
+ end
94
+
95
+ # Net::IMAP::ResponseCode represents response codes.
96
+ #
97
+ # resp_text_code ::= "ALERT" /
98
+ # "BADCHARSET" [SP "(" astring *(SP astring) ")" ] /
99
+ # capability_data / "PARSE" /
100
+ # "PERMANENTFLAGS" SP "("
101
+ # [flag_perm *(SP flag_perm)] ")" /
102
+ # "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
103
+ # "UIDNEXT" SP nz_number / "UIDVALIDITY" SP nz_number /
104
+ # "UNSEEN" SP nz_number /
105
+ # atom [SP 1*<any TEXT-CHAR except "]">]
106
+ #
107
+ # ==== Fields:
108
+ #
109
+ # name:: Returns the name, such as "ALERT", "PERMANENTFLAGS", or "UIDVALIDITY".
110
+ #
111
+ # data:: Returns the data, if it exists.
112
+ #
113
+ class ResponseCode < Struct.new(:name, :data)
114
+ end
115
+
116
+ # Net::IMAP::MailboxList represents contents of the LIST response.
117
+ #
118
+ # mailbox_list ::= "(" #("\Marked" / "\Noinferiors" /
119
+ # "\Noselect" / "\Unmarked" / flag_extension) ")"
120
+ # SPACE (<"> QUOTED_CHAR <"> / nil) SPACE mailbox
121
+ #
122
+ # ==== Fields:
123
+ #
124
+ # attr:: Returns the name attributes. Each name attribute is a symbol
125
+ # capitalized by String#capitalize, such as :Noselect (not :NoSelect).
126
+ #
127
+ # delim:: Returns the hierarchy delimiter.
128
+ #
129
+ # name:: Returns the mailbox name.
130
+ #
131
+ class MailboxList < Struct.new(:attr, :delim, :name)
132
+ end
133
+
134
+ # Net::IMAP::MailboxQuota represents contents of GETQUOTA response.
135
+ # This object can also be a response to GETQUOTAROOT. In the syntax
136
+ # specification below, the delimiter used with the "#" construct is a
137
+ # single space (SPACE).
138
+ #
139
+ # quota_list ::= "(" #quota_resource ")"
140
+ #
141
+ # quota_resource ::= atom SPACE number SPACE number
142
+ #
143
+ # quota_response ::= "QUOTA" SPACE astring SPACE quota_list
144
+ #
145
+ # ==== Fields:
146
+ #
147
+ # mailbox:: The mailbox with the associated quota.
148
+ #
149
+ # usage:: Current storage usage of the mailbox.
150
+ #
151
+ # quota:: Quota limit imposed on the mailbox.
152
+ #
153
+ class MailboxQuota < Struct.new(:mailbox, :usage, :quota)
154
+ end
155
+
156
+ # Net::IMAP::MailboxQuotaRoot represents part of the GETQUOTAROOT
157
+ # response. (GETQUOTAROOT can also return Net::IMAP::MailboxQuota.)
158
+ #
159
+ # quotaroot_response ::= "QUOTAROOT" SPACE astring *(SPACE astring)
160
+ #
161
+ # ==== Fields:
162
+ #
163
+ # mailbox:: The mailbox with the associated quota.
164
+ #
165
+ # quotaroots:: Zero or more quotaroots that affect the quota on the
166
+ # specified mailbox.
167
+ #
168
+ class MailboxQuotaRoot < Struct.new(:mailbox, :quotaroots)
169
+ end
170
+
171
+ # Net::IMAP::MailboxACLItem represents the response from GETACL.
172
+ #
173
+ # acl_data ::= "ACL" SPACE mailbox *(SPACE identifier SPACE rights)
174
+ #
175
+ # identifier ::= astring
176
+ #
177
+ # rights ::= astring
178
+ #
179
+ # ==== Fields:
180
+ #
181
+ # user:: Login name that has certain rights to the mailbox
182
+ # that was specified with the getacl command.
183
+ #
184
+ # rights:: The access rights the indicated user has to the
185
+ # mailbox.
186
+ #
187
+ class MailboxACLItem < Struct.new(:user, :rights, :mailbox)
188
+ end
189
+
190
+ # Net::IMAP::Namespace represents a single [RFC-2342] namespace.
191
+ #
192
+ # Namespace = nil / "(" 1*( "(" string SP (<"> QUOTED_CHAR <"> /
193
+ # nil) *(Namespace_Response_Extension) ")" ) ")"
194
+ #
195
+ # Namespace_Response_Extension = SP string SP "(" string *(SP string)
196
+ # ")"
197
+ #
198
+ # ==== Fields:
199
+ #
200
+ # prefix:: Returns the namespace prefix string.
201
+ # delim:: Returns nil or the hierarchy delimiter character.
202
+ # extensions:: Returns a hash of extension names to extension flag arrays.
203
+ #
204
+ class Namespace < Struct.new(:prefix, :delim, :extensions)
205
+ end
206
+
207
+ # Net::IMAP::Namespaces represents the response from [RFC-2342] NAMESPACE.
208
+ #
209
+ # Namespace_Response = "*" SP "NAMESPACE" SP Namespace SP Namespace SP
210
+ # Namespace
211
+ #
212
+ # ; The first Namespace is the Personal Namespace(s)
213
+ # ; The second Namespace is the Other Users' Namespace(s)
214
+ # ; The third Namespace is the Shared Namespace(s)
215
+ #
216
+ # ==== Fields:
217
+ #
218
+ # personal:: Returns an array of Personal Net::IMAP::Namespace objects.
219
+ # other:: Returns an array of Other Users' Net::IMAP::Namespace objects.
220
+ # shared:: Returns an array of Shared Net::IMAP::Namespace objects.
221
+ #
222
+ class Namespaces < Struct.new(:personal, :other, :shared)
223
+ end
224
+
225
+ # Net::IMAP::StatusData represents the contents of the STATUS response.
226
+ #
227
+ # ==== Fields:
228
+ #
229
+ # mailbox:: Returns the mailbox name.
230
+ #
231
+ # attr:: Returns a hash. Each key is one of "MESSAGES", "RECENT", "UIDNEXT",
232
+ # "UIDVALIDITY", "UNSEEN". Each value is a number.
233
+ #
234
+ class StatusData < Struct.new(:mailbox, :attr)
235
+ end
236
+
237
+ # Net::IMAP::FetchData represents the contents of the FETCH response.
238
+ #
239
+ # ==== Fields:
240
+ #
241
+ # seqno:: Returns the message sequence number.
242
+ # (Note: not the unique identifier, even for the UID command response.)
243
+ #
244
+ # attr:: Returns a hash. Each key is a data item name, and each value is
245
+ # its value.
246
+ #
247
+ # The current data items are:
248
+ #
249
+ # [BODY]
250
+ # A form of BODYSTRUCTURE without extension data.
251
+ # [BODY[<section>]<<origin_octet>>]
252
+ # A string expressing the body contents of the specified section.
253
+ # [BODYSTRUCTURE]
254
+ # An object that describes the [MIME-IMB] body structure of a message.
255
+ # See Net::IMAP::BodyTypeBasic, Net::IMAP::BodyTypeText,
256
+ # Net::IMAP::BodyTypeMessage, Net::IMAP::BodyTypeMultipart.
257
+ # [ENVELOPE]
258
+ # A Net::IMAP::Envelope object that describes the envelope
259
+ # structure of a message.
260
+ # [FLAGS]
261
+ # A array of flag symbols that are set for this message. Flag symbols
262
+ # are capitalized by String#capitalize.
263
+ # [INTERNALDATE]
264
+ # A string representing the internal date of the message.
265
+ # [RFC822]
266
+ # Equivalent to +BODY[]+.
267
+ # [RFC822.HEADER]
268
+ # Equivalent to +BODY.PEEK[HEADER]+.
269
+ # [RFC822.SIZE]
270
+ # A number expressing the [RFC-822] size of the message.
271
+ # [RFC822.TEXT]
272
+ # Equivalent to +BODY[TEXT]+.
273
+ # [UID]
274
+ # A number expressing the unique identifier of the message.
275
+ #
276
+ class FetchData < Struct.new(:seqno, :attr)
277
+ end
278
+
279
+ # Net::IMAP::Envelope represents envelope structures of messages.
280
+ #
281
+ # ==== Fields:
282
+ #
283
+ # date:: Returns a string that represents the date.
284
+ #
285
+ # subject:: Returns a string that represents the subject.
286
+ #
287
+ # from:: Returns an array of Net::IMAP::Address that represents the from.
288
+ #
289
+ # sender:: Returns an array of Net::IMAP::Address that represents the sender.
290
+ #
291
+ # reply_to:: Returns an array of Net::IMAP::Address that represents the reply-to.
292
+ #
293
+ # to:: Returns an array of Net::IMAP::Address that represents the to.
294
+ #
295
+ # cc:: Returns an array of Net::IMAP::Address that represents the cc.
296
+ #
297
+ # bcc:: Returns an array of Net::IMAP::Address that represents the bcc.
298
+ #
299
+ # in_reply_to:: Returns a string that represents the in-reply-to.
300
+ #
301
+ # message_id:: Returns a string that represents the message-id.
302
+ #
303
+ class Envelope < Struct.new(:date, :subject, :from, :sender, :reply_to,
304
+ :to, :cc, :bcc, :in_reply_to, :message_id)
305
+ end
306
+
307
+ #
308
+ # Net::IMAP::Address represents electronic mail addresses.
309
+ #
310
+ # ==== Fields:
311
+ #
312
+ # name:: Returns the phrase from [RFC-822] mailbox.
313
+ #
314
+ # route:: Returns the route from [RFC-822] route-addr.
315
+ #
316
+ # mailbox:: nil indicates end of [RFC-822] group.
317
+ # If non-nil and host is nil, returns [RFC-822] group name.
318
+ # Otherwise, returns [RFC-822] local-part.
319
+ #
320
+ # host:: nil indicates [RFC-822] group syntax.
321
+ # Otherwise, returns [RFC-822] domain name.
322
+ #
323
+ class Address < Struct.new(:name, :route, :mailbox, :host)
324
+ end
325
+
326
+ #
327
+ # Net::IMAP::ContentDisposition represents Content-Disposition fields.
328
+ #
329
+ # ==== Fields:
330
+ #
331
+ # dsp_type:: Returns the disposition type.
332
+ #
333
+ # param:: Returns a hash that represents parameters of the Content-Disposition
334
+ # field.
335
+ #
336
+ class ContentDisposition < Struct.new(:dsp_type, :param)
337
+ end
338
+
339
+ # Net::IMAP::ThreadMember represents a thread-node returned
340
+ # by Net::IMAP#thread.
341
+ #
342
+ # ==== Fields:
343
+ #
344
+ # seqno:: The sequence number of this message.
345
+ #
346
+ # children:: An array of Net::IMAP::ThreadMember objects for mail
347
+ # items that are children of this in the thread.
348
+ #
349
+ class ThreadMember < Struct.new(:seqno, :children)
350
+ end
351
+
352
+ # Net::IMAP::BodyTypeBasic represents basic body structures of messages.
353
+ #
354
+ # ==== Fields:
355
+ #
356
+ # media_type:: Returns the content media type name as defined in [MIME-IMB].
357
+ #
358
+ # subtype:: Returns the content subtype name as defined in [MIME-IMB].
359
+ #
360
+ # param:: Returns a hash that represents parameters as defined in [MIME-IMB].
361
+ #
362
+ # content_id:: Returns a string giving the content id as defined in [MIME-IMB].
363
+ #
364
+ # description:: Returns a string giving the content description as defined in
365
+ # [MIME-IMB].
366
+ #
367
+ # encoding:: Returns a string giving the content transfer encoding as defined in
368
+ # [MIME-IMB].
369
+ #
370
+ # size:: Returns a number giving the size of the body in octets.
371
+ #
372
+ # md5:: Returns a string giving the body MD5 value as defined in [MD5].
373
+ #
374
+ # disposition:: Returns a Net::IMAP::ContentDisposition object giving
375
+ # the content disposition.
376
+ #
377
+ # language:: Returns a string or an array of strings giving the body
378
+ # language value as defined in [LANGUAGE-TAGS].
379
+ #
380
+ # extension:: Returns extension data.
381
+ #
382
+ # multipart?:: Returns false.
383
+ #
384
+ class BodyTypeBasic < Struct.new(:media_type, :subtype,
385
+ :param, :content_id,
386
+ :description, :encoding, :size,
387
+ :md5, :disposition, :language,
388
+ :extension)
389
+ def multipart?
390
+ return false
391
+ end
392
+
393
+ # Obsolete: use +subtype+ instead. Calling this will
394
+ # generate a warning message to +stderr+, then return
395
+ # the value of +subtype+.
396
+ def media_subtype
397
+ warn("media_subtype is obsolete, use subtype instead.\n", uplevel: 1)
398
+ return subtype
399
+ end
400
+ end
401
+
402
+ # Net::IMAP::BodyTypeText represents TEXT body structures of messages.
403
+ #
404
+ # ==== Fields:
405
+ #
406
+ # lines:: Returns the size of the body in text lines.
407
+ #
408
+ # And Net::IMAP::BodyTypeText has all fields of Net::IMAP::BodyTypeBasic.
409
+ #
410
+ class BodyTypeText < Struct.new(:media_type, :subtype,
411
+ :param, :content_id,
412
+ :description, :encoding, :size,
413
+ :lines,
414
+ :md5, :disposition, :language,
415
+ :extension)
416
+ def multipart?
417
+ return false
418
+ end
419
+
420
+ # Obsolete: use +subtype+ instead. Calling this will
421
+ # generate a warning message to +stderr+, then return
422
+ # the value of +subtype+.
423
+ def media_subtype
424
+ warn("media_subtype is obsolete, use subtype instead.\n", uplevel: 1)
425
+ return subtype
426
+ end
427
+ end
428
+
429
+ # Net::IMAP::BodyTypeMessage represents MESSAGE/RFC822 body structures of messages.
430
+ #
431
+ # ==== Fields:
432
+ #
433
+ # envelope:: Returns a Net::IMAP::Envelope giving the envelope structure.
434
+ #
435
+ # body:: Returns an object giving the body structure.
436
+ #
437
+ # And Net::IMAP::BodyTypeMessage has all methods of Net::IMAP::BodyTypeText.
438
+ #
439
+ class BodyTypeMessage < Struct.new(:media_type, :subtype,
440
+ :param, :content_id,
441
+ :description, :encoding, :size,
442
+ :envelope, :body, :lines,
443
+ :md5, :disposition, :language,
444
+ :extension)
445
+ def multipart?
446
+ return false
447
+ end
448
+
449
+ # Obsolete: use +subtype+ instead. Calling this will
450
+ # generate a warning message to +stderr+, then return
451
+ # the value of +subtype+.
452
+ def media_subtype
453
+ warn("media_subtype is obsolete, use subtype instead.\n", uplevel: 1)
454
+ return subtype
455
+ end
456
+ end
457
+
458
+ # Net::IMAP::BodyTypeAttachment represents attachment body structures
459
+ # of messages.
460
+ #
461
+ # ==== Fields:
462
+ #
463
+ # media_type:: Returns the content media type name.
464
+ #
465
+ # subtype:: Returns +nil+.
466
+ #
467
+ # param:: Returns a hash that represents parameters.
468
+ #
469
+ # multipart?:: Returns false.
470
+ #
471
+ class BodyTypeAttachment < Struct.new(:media_type, :subtype,
472
+ :param)
473
+ def multipart?
474
+ return false
475
+ end
476
+ end
477
+
478
+ # Net::IMAP::BodyTypeMultipart represents multipart body structures
479
+ # of messages.
480
+ #
481
+ # ==== Fields:
482
+ #
483
+ # media_type:: Returns the content media type name as defined in [MIME-IMB].
484
+ #
485
+ # subtype:: Returns the content subtype name as defined in [MIME-IMB].
486
+ #
487
+ # parts:: Returns multiple parts.
488
+ #
489
+ # param:: Returns a hash that represents parameters as defined in [MIME-IMB].
490
+ #
491
+ # disposition:: Returns a Net::IMAP::ContentDisposition object giving
492
+ # the content disposition.
493
+ #
494
+ # language:: Returns a string or an array of strings giving the body
495
+ # language value as defined in [LANGUAGE-TAGS].
496
+ #
497
+ # extension:: Returns extension data.
498
+ #
499
+ # multipart?:: Returns true.
500
+ #
501
+ class BodyTypeMultipart < Struct.new(:media_type, :subtype,
502
+ :parts,
503
+ :param, :disposition, :language,
504
+ :extension)
505
+ def multipart?
506
+ return true
507
+ end
508
+
509
+ # Obsolete: use +subtype+ instead. Calling this will
510
+ # generate a warning message to +stderr+, then return
511
+ # the value of +subtype+.
512
+ def media_subtype
513
+ warn("media_subtype is obsolete, use subtype instead.\n", uplevel: 1)
514
+ return subtype
515
+ end
516
+ end
517
+
518
+ class BodyTypeExtension < Struct.new(:media_type, :subtype,
519
+ :params, :content_id,
520
+ :description, :encoding, :size)
521
+ def multipart?
522
+ return false
523
+ end
524
+ end
525
+
526
+ end
527
+ end