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
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+ #
3
+ # = Resent-To Field
4
+ #
5
+ # The Resent-To field inherits resent-to StructuredField and handles the Resent-To: header
6
+ # field in the email.
7
+ #
8
+ # Sending resent_to to a mail message will instantiate a Mail::Field object that
9
+ # has a ResentToField as it's field type. This includes all Mail::CommonAddress
10
+ # module instance metods.
11
+ #
12
+ # Only one Resent-To 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.resent_to = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
+ # mail.resent_to #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
20
+ # mail[:resent_to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentToField:0x180e1c4
21
+ # mail['resent-to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentToField:0x180e1c4
22
+ # mail['Resent-To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ResentToField:0x180e1c4
23
+ #
24
+ # mail[:resent_to].encoded #=> 'Resent-To: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
25
+ # mail[:resent_to].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
26
+ # mail[:resent_to].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
27
+ # mail[:resent_to].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 ResentToField < StructuredField
33
+
34
+ include Mail::CommonAddress
35
+
36
+ FIELD_NAME = 'resent-to'
37
+ CAPITALIZED_FIELD = 'Resent-To'
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,64 @@
1
+ # encoding: utf-8
2
+ #
3
+ # 4.4.3. REPLY-TO / RESENT-REPLY-TO
4
+ #
5
+ # Note: The "Return-Path" field is added by the mail transport
6
+ # service, at the time of final deliver. It is intended
7
+ # to identify a path back to the orginator of the mes-
8
+ # sage. The "Reply-To" field is added by the message
9
+ # originator and is intended to direct replies.
10
+ #
11
+ # trace = [return]
12
+ # 1*received
13
+ #
14
+ # return = "Return-Path:" path CRLF
15
+ #
16
+ # path = ([CFWS] "<" ([CFWS] / addr-spec) ">" [CFWS]) /
17
+ # obs-path
18
+ #
19
+ # received = "Received:" name-val-list ";" date-time CRLF
20
+ #
21
+ # name-val-list = [CFWS] [name-val-pair *(CFWS name-val-pair)]
22
+ #
23
+ # name-val-pair = item-name CFWS item-value
24
+ #
25
+ # item-name = ALPHA *(["-"] (ALPHA / DIGIT))
26
+ #
27
+ # item-value = 1*angle-addr / addr-spec /
28
+ # atom / domain / msg-id
29
+ #
30
+ require 'mail/fields/common/common_address'
31
+
32
+ module Mail
33
+ class ReturnPathField < StructuredField
34
+
35
+ include Mail::CommonAddress
36
+
37
+ FIELD_NAME = 'return-path'
38
+ CAPITALIZED_FIELD = 'Return-Path'
39
+
40
+ def initialize(value = nil, charset = 'utf-8')
41
+ self.charset = charset
42
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
43
+ self.parse
44
+ self
45
+ end
46
+
47
+ def encoded
48
+ "#{CAPITALIZED_FIELD}: <#{address}>\r\n"
49
+ end
50
+
51
+ def decoded
52
+ do_decode
53
+ end
54
+
55
+ def address
56
+ addresses.first
57
+ end
58
+
59
+ def default
60
+ address
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,67 @@
1
+ # encoding: utf-8
2
+ #
3
+ # = Sender Field
4
+ #
5
+ # The Sender field inherits sender StructuredField and handles the Sender: header
6
+ # field in the email.
7
+ #
8
+ # Sending sender to a mail message will instantiate a Mail::Field object that
9
+ # has a SenderField as it's field type. This includes all Mail::CommonAddress
10
+ # module instance metods.
11
+ #
12
+ # Only one Sender 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.sender = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
+ # mail.sender #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
20
+ # mail[:sender] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
21
+ # mail['sender'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
22
+ # mail['Sender'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::SenderField:0x180e1c4
23
+ #
24
+ # mail[:sender].encoded #=> 'Sender: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
25
+ # mail[:sender].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
26
+ # mail[:sender].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
27
+ # mail[:sender].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 SenderField < StructuredField
33
+
34
+ include Mail::CommonAddress
35
+
36
+ FIELD_NAME = 'sender'
37
+ CAPITALIZED_FIELD = 'Sender'
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 addresses
47
+ [address.address]
48
+ end
49
+
50
+ def address
51
+ result = tree.addresses.first
52
+ end
53
+
54
+ def encoded
55
+ do_encode(CAPITALIZED_FIELD)
56
+ end
57
+
58
+ def decoded
59
+ do_decode
60
+ end
61
+
62
+ def default
63
+ address.address
64
+ end
65
+
66
+ end
67
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+ require 'mail/fields/common/common_field'
3
+
4
+ module Mail
5
+ # Provides access to a structured header field
6
+ #
7
+ # ===Per RFC 2822:
8
+ # 2.2.2. Structured Header Field Bodies
9
+ #
10
+ # Some field bodies in this standard have specific syntactical
11
+ # structure more restrictive than the unstructured field bodies
12
+ # described above. These are referred to as "structured" field bodies.
13
+ # Structured field bodies are sequences of specific lexical tokens as
14
+ # described in sections 3 and 4 of this standard. Many of these tokens
15
+ # are allowed (according to their syntax) to be introduced or end with
16
+ # comments (as described in section 3.2.3) as well as the space (SP,
17
+ # ASCII value 32) and horizontal tab (HTAB, ASCII value 9) characters
18
+ # (together known as the white space characters, WSP), and those WSP
19
+ # characters are subject to header "folding" and "unfolding" as
20
+ # described in section 2.2.3. Semantic analysis of structured field
21
+ # bodies is given along with their syntax.
22
+ class StructuredField
23
+
24
+ include Mail::CommonField
25
+ include Mail::Utilities
26
+
27
+ def initialize(name = nil, value = nil, charset = nil)
28
+ self.name = name
29
+ self.value = value
30
+ self.charset = charset
31
+ self
32
+ end
33
+
34
+ def charset
35
+ @charset
36
+ end
37
+
38
+ def charset=(val)
39
+ @charset = val
40
+ end
41
+
42
+ def default
43
+ decoded
44
+ end
45
+
46
+ def errors
47
+ []
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,16 @@
1
+ # encoding: utf-8
2
+ #
3
+ # subject = "Subject:" unstructured CRLF
4
+ module Mail
5
+ class SubjectField < UnstructuredField
6
+
7
+ FIELD_NAME = 'subject'
8
+ CAPITALIZED_FIELD = "Subject"
9
+
10
+ def initialize(value = nil, charset = 'utf-8')
11
+ self.charset = charset
12
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
13
+ end
14
+
15
+ end
16
+ end
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+ #
3
+ # = To Field
4
+ #
5
+ # The To field inherits to StructuredField and handles the To: header
6
+ # field in the email.
7
+ #
8
+ # Sending to to a mail message will instantiate a Mail::Field object that
9
+ # has a ToField as it's field type. This includes all Mail::CommonAddress
10
+ # module instance metods.
11
+ #
12
+ # Only one To 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.to = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
+ # mail.to #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
20
+ # mail[:to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
21
+ # mail['to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
22
+ # mail['To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::ToField:0x180e1c4
23
+ #
24
+ # mail[:to].encoded #=> 'To: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
25
+ # mail[:to].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
26
+ # mail[:to].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
27
+ # mail[:to].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 ToField < StructuredField
33
+
34
+ include Mail::CommonAddress
35
+
36
+ FIELD_NAME = 'to'
37
+ CAPITALIZED_FIELD = 'To'
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,179 @@
1
+ # encoding: utf-8
2
+ require 'mail/fields/common/common_field'
3
+
4
+ module Mail
5
+ # Provides access to an unstructured header field
6
+ #
7
+ # ===Per RFC 2822:
8
+ # 2.2.1. Unstructured Header Field Bodies
9
+ #
10
+ # Some field bodies in this standard are defined simply as
11
+ # "unstructured" (which is specified below as any US-ASCII characters,
12
+ # except for CR and LF) with no further restrictions. These are
13
+ # referred to as unstructured field bodies. Semantically, unstructured
14
+ # field bodies are simply to be treated as a single line of characters
15
+ # with no further processing (except for header "folding" and
16
+ # "unfolding" as described in section 2.2.3).
17
+ class UnstructuredField
18
+
19
+ include Mail::CommonField
20
+ include Mail::Utilities
21
+
22
+ def initialize(name, value, charset = nil)
23
+ self.charset = charset
24
+ @errors = []
25
+ if charset
26
+ self.charset = charset
27
+ else
28
+ if value.to_s.respond_to?(:encoding)
29
+ self.charset = value.to_s.encoding
30
+ else
31
+ self.charset = $KCODE
32
+ end
33
+ end
34
+ self.name = name
35
+ self.value = value
36
+ self
37
+ end
38
+
39
+ def charset
40
+ @charset
41
+ end
42
+
43
+ def charset=(val)
44
+ @charset = val
45
+ end
46
+
47
+ def errors
48
+ @errors
49
+ end
50
+
51
+ def encoded
52
+ do_encode(self.name)
53
+ end
54
+
55
+ def decoded
56
+ do_decode
57
+ end
58
+
59
+ def default
60
+ decoded
61
+ end
62
+
63
+ def parse # An unstructured field does not parse
64
+ self
65
+ end
66
+
67
+ private
68
+
69
+ def do_encode(name)
70
+ value.nil? ? '' : "#{wrapped_value}\r\n"
71
+ end
72
+
73
+ def do_decode
74
+ value.blank? ? nil : Encodings.decode_encode(value, :decode)
75
+ end
76
+
77
+ # 2.2.3. Long Header Fields
78
+ #
79
+ # Each header field is logically a single line of characters comprising
80
+ # the field name, the colon, and the field body. For convenience
81
+ # however, and to deal with the 998/78 character limitations per line,
82
+ # the field body portion of a header field can be split into a multiple
83
+ # line representation; this is called "folding". The general rule is
84
+ # that wherever this standard allows for folding white space (not
85
+ # simply WSP characters), a CRLF may be inserted before any WSP. For
86
+ # example, the header field:
87
+ #
88
+ # Subject: This is a test
89
+ #
90
+ # can be represented as:
91
+ #
92
+ # Subject: This
93
+ # is a test
94
+ #
95
+ # Note: Though structured field bodies are defined in such a way that
96
+ # folding can take place between many of the lexical tokens (and even
97
+ # within some of the lexical tokens), folding SHOULD be limited to
98
+ # placing the CRLF at higher-level syntactic breaks. For instance, if
99
+ # a field body is defined as comma-separated values, it is recommended
100
+ # that folding occur after the comma separating the structured items in
101
+ # preference to other places where the field could be folded, even if
102
+ # it is allowed elsewhere.
103
+ def wrapped_value # :nodoc:
104
+ @folded_line = []
105
+ @unfolded_line = decoded.to_s.split(/[ \t]/)
106
+ fold("#{name}: ".length)
107
+ wrap_lines(name, @folded_line)
108
+ end
109
+
110
+ # 6.2. Display of 'encoded-word's
111
+ #
112
+ # When displaying a particular header field that contains multiple
113
+ # 'encoded-word's, any 'linear-white-space' that separates a pair of
114
+ # adjacent 'encoded-word's is ignored. (This is to allow the use of
115
+ # multiple 'encoded-word's to represent long strings of unencoded text,
116
+ # without having to separate 'encoded-word's where spaces occur in the
117
+ # unencoded text.)
118
+ def wrap_lines(name, folded_lines)
119
+ result = []
120
+ index = 0
121
+ result[index] = "#{name}: #{folded_lines.shift}"
122
+ result.concat(folded_lines)
123
+ result.join("\r\n\s")
124
+ end
125
+
126
+ def fold(prepend = 0) # :nodoc:
127
+ encoding = @charset.to_s.upcase.gsub('_', '-')
128
+ while !@unfolded_line.empty?
129
+ encoded = false
130
+ limit = 78 - prepend
131
+ line = ""
132
+ while !@unfolded_line.empty?
133
+ break unless word = @unfolded_line.first.dup
134
+ # Remember whether it was non-ascii before we encode it ('cause then we can't tell anymore)
135
+ non_ascii = word.not_ascii_only?
136
+ encoded_word = encode(word)
137
+ # Skip to next line if we're going to go past the limit
138
+ # Unless this is the first word, in which case we're going to add it anyway
139
+ # Note: This means that a word that's longer than 998 characters is going to break the spec. Please fix if this is a problem for you.
140
+ # (The fix, it seems, would be to use encoded-word encoding on it, because that way you can break it across multiple lines and
141
+ # the linebreak will be ignored)
142
+ break if !line.empty? && (line.length + encoded_word.length + 1 > limit)
143
+ # If word was the first non-ascii word, we're going to make the entire line encoded and we're going to reduce the limit accordingly
144
+ if non_ascii && !encoded
145
+ encoded = true
146
+ encoded_word_safify!(line)
147
+ limit = limit - 8 - encoding.length # minus the =?...?Q?...?= part, the possible leading white-space, and the name of the encoding
148
+ end
149
+ # Remove the word from the queue ...
150
+ @unfolded_line.shift
151
+ # ... add it in encoded form to the current line
152
+ line << " " unless line.empty?
153
+ encoded_word_safify!(encoded_word) if encoded
154
+ line << encoded_word
155
+ end
156
+ # Add leading whitespace if both this and the last line were encoded, because whitespace between two encoded-words is ignored when decoding
157
+ line = " " + line if encoded && @folded_line.last && @folded_line.last.index('=?') == 0
158
+ # Encode the line if necessary
159
+ line = "=?#{encoding}?Q?#{line.gsub(/ /, '_')}?=" if encoded
160
+ # Add the line to the output and reset the prepend
161
+ @folded_line << line
162
+ prepend = 0
163
+ end
164
+ end
165
+
166
+ def encode(value)
167
+ (value.not_ascii_only? ? [value].pack("M").gsub("=\n", '') : value).gsub("\r", "=0D").gsub("\n", "=0A")
168
+ end
169
+
170
+ def encoded_word_safify!(value)
171
+ value.gsub!(/"/, '=22')
172
+ value.gsub!(/\(/, '=28')
173
+ value.gsub!(/\)/, '=29')
174
+ value.gsub!(/\?/, '=3F')
175
+ value.gsub!(/_/, '=5F')
176
+ end
177
+
178
+ end
179
+ end
@@ -0,0 +1,35 @@
1
+ module Mail
2
+ autoload :UnstructuredField, 'mail/fields/unstructured_field'
3
+ autoload :StructuredField, 'mail/fields/structured_field'
4
+ autoload :OptionalField, 'mail/fields/optional_field'
5
+
6
+ autoload :BccField, 'mail/fields/bcc_field'
7
+ autoload :CcField, 'mail/fields/cc_field'
8
+ autoload :CommentsField, 'mail/fields/comments_field'
9
+ autoload :ContentDescriptionField, 'mail/fields/content_description_field'
10
+ autoload :ContentDispositionField, 'mail/fields/content_disposition_field'
11
+ autoload :ContentIdField, 'mail/fields/content_id_field'
12
+ autoload :ContentLocationField, 'mail/fields/content_location_field'
13
+ autoload :ContentTransferEncodingField, 'mail/fields/content_transfer_encoding_field'
14
+ autoload :ContentTypeField, 'mail/fields/content_type_field'
15
+ autoload :DateField, 'mail/fields/date_field'
16
+ autoload :FromField, 'mail/fields/from_field'
17
+ autoload :InReplyToField, 'mail/fields/in_reply_to_field'
18
+ autoload :KeywordsField, 'mail/fields/keywords_field'
19
+ autoload :MessageIdField, 'mail/fields/message_id_field'
20
+ autoload :MimeVersionField, 'mail/fields/mime_version_field'
21
+ autoload :ReceivedField, 'mail/fields/received_field'
22
+ autoload :ReferencesField, 'mail/fields/references_field'
23
+ autoload :ReplyToField, 'mail/fields/reply_to_field'
24
+ autoload :ResentBccField, 'mail/fields/resent_bcc_field'
25
+ autoload :ResentCcField, 'mail/fields/resent_cc_field'
26
+ autoload :ResentDateField, 'mail/fields/resent_date_field'
27
+ autoload :ResentFromField, 'mail/fields/resent_from_field'
28
+ autoload :ResentMessageIdField, 'mail/fields/resent_message_id_field'
29
+ autoload :ResentSenderField, 'mail/fields/resent_sender_field'
30
+ autoload :ResentToField, 'mail/fields/resent_to_field'
31
+ autoload :ReturnPathField, 'mail/fields/return_path_field'
32
+ autoload :SenderField, 'mail/fields/sender_field'
33
+ autoload :SubjectField, 'mail/fields/subject_field'
34
+ autoload :ToField, 'mail/fields/to_field'
35
+ end