mail 2.7.1 → 2.8.0.rc1

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. checksums.yaml +4 -4
  2. data/README.md +45 -28
  3. data/lib/mail/attachments_list.rb +2 -5
  4. data/lib/mail/body.rb +24 -47
  5. data/lib/mail/constants.rb +27 -5
  6. data/lib/mail/elements/address.rb +27 -27
  7. data/lib/mail/elements/address_list.rb +1 -1
  8. data/lib/mail/elements/content_disposition_element.rb +1 -1
  9. data/lib/mail/elements/content_location_element.rb +1 -1
  10. data/lib/mail/elements/content_transfer_encoding_element.rb +1 -1
  11. data/lib/mail/elements/content_type_element.rb +8 -4
  12. data/lib/mail/elements/date_time_element.rb +1 -1
  13. data/lib/mail/elements/envelope_from_element.rb +13 -7
  14. data/lib/mail/elements/message_ids_element.rb +14 -5
  15. data/lib/mail/elements/mime_version_element.rb +1 -1
  16. data/lib/mail/elements/phrase_list.rb +7 -2
  17. data/lib/mail/elements/received_element.rb +20 -6
  18. data/lib/mail/encodings/7bit.rb +5 -0
  19. data/lib/mail/encodings/base64.rb +2 -2
  20. data/lib/mail/encodings/quoted_printable.rb +2 -2
  21. data/lib/mail/encodings.rb +30 -59
  22. data/lib/mail/envelope.rb +11 -14
  23. data/lib/mail/field.rb +37 -53
  24. data/lib/mail/field_list.rb +60 -7
  25. data/lib/mail/fields/bcc_field.rb +34 -52
  26. data/lib/mail/fields/cc_field.rb +28 -49
  27. data/lib/mail/fields/comments_field.rb +27 -37
  28. data/lib/mail/fields/common_address_field.rb +170 -0
  29. data/lib/mail/fields/common_date_field.rb +58 -0
  30. data/lib/mail/fields/common_field.rb +77 -0
  31. data/lib/mail/fields/common_message_id_field.rb +42 -0
  32. data/lib/mail/fields/content_description_field.rb +7 -14
  33. data/lib/mail/fields/content_disposition_field.rb +13 -38
  34. data/lib/mail/fields/content_id_field.rb +24 -51
  35. data/lib/mail/fields/content_location_field.rb +11 -25
  36. data/lib/mail/fields/content_transfer_encoding_field.rb +31 -31
  37. data/lib/mail/fields/content_type_field.rb +46 -71
  38. data/lib/mail/fields/date_field.rb +23 -51
  39. data/lib/mail/fields/from_field.rb +28 -49
  40. data/lib/mail/fields/in_reply_to_field.rb +38 -49
  41. data/lib/mail/fields/keywords_field.rb +18 -31
  42. data/lib/mail/fields/message_id_field.rb +25 -71
  43. data/lib/mail/fields/mime_version_field.rb +19 -30
  44. data/lib/mail/fields/named_structured_field.rb +11 -0
  45. data/lib/mail/fields/named_unstructured_field.rb +11 -0
  46. data/lib/mail/fields/optional_field.rb +5 -6
  47. data/lib/mail/fields/{common/parameter_hash.rb → parameter_hash.rb} +12 -10
  48. data/lib/mail/fields/received_field.rb +43 -57
  49. data/lib/mail/fields/references_field.rb +35 -49
  50. data/lib/mail/fields/reply_to_field.rb +28 -49
  51. data/lib/mail/fields/resent_bcc_field.rb +28 -49
  52. data/lib/mail/fields/resent_cc_field.rb +28 -49
  53. data/lib/mail/fields/resent_date_field.rb +5 -29
  54. data/lib/mail/fields/resent_from_field.rb +28 -49
  55. data/lib/mail/fields/resent_message_id_field.rb +5 -29
  56. data/lib/mail/fields/resent_sender_field.rb +27 -56
  57. data/lib/mail/fields/resent_to_field.rb +28 -49
  58. data/lib/mail/fields/return_path_field.rb +50 -54
  59. data/lib/mail/fields/sender_field.rb +34 -55
  60. data/lib/mail/fields/structured_field.rb +3 -30
  61. data/lib/mail/fields/subject_field.rb +9 -11
  62. data/lib/mail/fields/to_field.rb +28 -49
  63. data/lib/mail/fields/unstructured_field.rb +16 -48
  64. data/lib/mail/header.rb +69 -110
  65. data/lib/mail/matchers/attachment_matchers.rb +15 -0
  66. data/lib/mail/message.rb +46 -64
  67. data/lib/mail/multibyte/chars.rb +8 -166
  68. data/lib/mail/multibyte/utils.rb +26 -43
  69. data/lib/mail/multibyte.rb +1 -11
  70. data/lib/mail/network/delivery_methods/exim.rb +5 -4
  71. data/lib/mail/network/delivery_methods/file_delivery.rb +11 -10
  72. data/lib/mail/network/delivery_methods/logger_delivery.rb +2 -5
  73. data/lib/mail/network/delivery_methods/sendmail.rb +27 -35
  74. data/lib/mail/network/delivery_methods/smtp.rb +3 -3
  75. data/lib/mail/network/delivery_methods/smtp_connection.rb +3 -12
  76. data/lib/mail/network/delivery_methods/test_mailer.rb +4 -2
  77. data/lib/mail/network/retriever_methods/base.rb +8 -8
  78. data/lib/mail/network/retriever_methods/imap.rb +2 -2
  79. data/lib/mail/network/retriever_methods/pop3.rb +2 -2
  80. data/lib/mail/network/retriever_methods/test_retriever.rb +2 -1
  81. data/lib/mail/parsers/address_lists_parser.rb +33070 -33064
  82. data/lib/mail/parsers/address_lists_parser.rl +7 -0
  83. data/lib/mail/parsers/content_disposition_parser.rb +833 -827
  84. data/lib/mail/parsers/content_disposition_parser.rl +7 -0
  85. data/lib/mail/parsers/content_location_parser.rb +770 -764
  86. data/lib/mail/parsers/content_location_parser.rl +7 -0
  87. data/lib/mail/parsers/content_transfer_encoding_parser.rb +474 -468
  88. data/lib/mail/parsers/content_transfer_encoding_parser.rl +7 -0
  89. data/lib/mail/parsers/content_type_parser.rb +971 -965
  90. data/lib/mail/parsers/content_type_parser.rl +7 -0
  91. data/lib/mail/parsers/date_time_parser.rb +838 -832
  92. data/lib/mail/parsers/date_time_parser.rl +7 -0
  93. data/lib/mail/parsers/envelope_from_parser.rb +3623 -3529
  94. data/lib/mail/parsers/envelope_from_parser.rl +7 -0
  95. data/lib/mail/parsers/message_ids_parser.rb +5107 -2800
  96. data/lib/mail/parsers/message_ids_parser.rl +12 -1
  97. data/lib/mail/parsers/mime_version_parser.rb +463 -457
  98. data/lib/mail/parsers/mime_version_parser.rl +7 -0
  99. data/lib/mail/parsers/phrase_lists_parser.rb +836 -830
  100. data/lib/mail/parsers/phrase_lists_parser.rl +8 -1
  101. data/lib/mail/parsers/received_parser.rb +8688 -8682
  102. data/lib/mail/parsers/received_parser.rl +7 -0
  103. data/lib/mail/parsers/rfc5322.rl +28 -13
  104. data/lib/mail/parsers.rb +11 -17
  105. data/lib/mail/part.rb +5 -9
  106. data/lib/mail/parts_list.rb +57 -0
  107. data/lib/mail/smtp_envelope.rb +57 -0
  108. data/lib/mail/utilities.rb +307 -69
  109. data/lib/mail/version.rb +3 -3
  110. data/lib/mail/yaml.rb +30 -0
  111. data/lib/mail.rb +0 -20
  112. metadata +74 -21
  113. data/lib/mail/check_delivery_params.rb +0 -60
  114. data/lib/mail/core_extensions/smtp.rb +0 -28
  115. data/lib/mail/core_extensions/string.rb +0 -17
  116. data/lib/mail/fields/common/address_container.rb +0 -17
  117. data/lib/mail/fields/common/common_address.rb +0 -161
  118. data/lib/mail/fields/common/common_date.rb +0 -36
  119. data/lib/mail/fields/common/common_field.rb +0 -52
  120. data/lib/mail/fields/common/common_message_id.rb +0 -49
  121. data/lib/mail/version_specific/ruby_1_8.rb +0 -163
  122. data/lib/mail/version_specific/ruby_1_9.rb +0 -278
@@ -1,55 +1,34 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
- #
4
- # = Carbon Copy Field
5
- #
6
- # The Cc field inherits from StructuredField and handles the Cc: header
7
- # field in the email.
8
- #
9
- # Sending cc to a mail message will instantiate a Mail::Field object that
10
- # has a CcField as its field type. This includes all Mail::CommonAddress
11
- # module instance metods.
12
- #
13
- # Only one Cc field can appear in a header, though it can have multiple
14
- # addresses and groups of addresses.
15
- #
16
- # == Examples:
17
- #
18
- # mail = Mail.new
19
- # mail.cc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
20
- # mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
21
- # mail[:cc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
22
- # mail['cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
23
- # mail['Cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
24
- #
25
- # mail[:cc].encoded #=> 'Cc: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
26
- # mail[:cc].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
27
- # mail[:cc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
28
- # mail[:cc].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
29
- #
30
- require 'mail/fields/common/common_address'
3
+ require 'mail/fields/common_address_field'
31
4
 
32
5
  module Mail
33
- class CcField < StructuredField
34
-
35
- include Mail::CommonAddress
36
-
37
- FIELD_NAME = 'cc'
38
- CAPITALIZED_FIELD = 'Cc'
39
-
40
- def initialize(value = nil, charset = 'utf-8')
41
- self.charset = charset
42
- super(CAPITALIZED_FIELD, value, charset)
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
-
6
+ # = Carbon Copy Field
7
+ #
8
+ # The Cc field inherits from StructuredField and handles the Cc: header
9
+ # field in the email.
10
+ #
11
+ # Sending cc to a mail message will instantiate a Mail::Field object that
12
+ # has a CcField as its field type. This includes all Mail::CommonAddress
13
+ # module instance metods.
14
+ #
15
+ # Only one Cc field can appear in a header, though it can have multiple
16
+ # addresses and groups of addresses.
17
+ #
18
+ # == Examples:
19
+ #
20
+ # mail = Mail.new
21
+ # mail.cc = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
22
+ # mail.cc #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
23
+ # mail[:cc] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
24
+ # mail['cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
25
+ # mail['Cc'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CcField:0x180e1c4
26
+ #
27
+ # mail[:cc].encoded #=> 'Cc: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
28
+ # mail[:cc].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
29
+ # mail[:cc].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
30
+ # mail[:cc].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
31
+ class CcField < CommonAddressField #:nodoc:
32
+ NAME = 'Cc'
54
33
  end
55
34
  end
@@ -1,42 +1,32 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
- #
4
- # = Comments Field
5
- #
6
- # The Comments field inherits from UnstructuredField and handles the Comments:
7
- # header field in the email.
8
- #
9
- # Sending comments to a mail message will instantiate a Mail::Field object that
10
- # has a CommentsField as its field type.
11
- #
12
- # An email header can have as many comments fields as it wants. There is no upper
13
- # limit, the comments field is also optional (that is, no comment is needed)
14
- #
15
- # == Examples:
16
- #
17
- # mail = Mail.new
18
- # mail.comments = 'This is a comment'
19
- # mail.comments #=> 'This is a comment'
20
- # mail[:comments] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
21
- # mail['comments'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
22
- # mail['comments'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
23
- #
24
- # mail.comments = "This is another comment"
25
- # mail[:comments].map { |c| c.to_s }
26
- # #=> ['This is a comment', "This is another comment"]
27
- #
3
+ require 'mail/fields/named_unstructured_field'
4
+
28
5
  module Mail
29
- class CommentsField < UnstructuredField
30
-
31
- FIELD_NAME = 'comments'
32
- CAPITALIZED_FIELD = 'Comments'
33
-
34
- def initialize(value = nil, charset = 'utf-8')
35
- @charset = charset
36
- super(CAPITALIZED_FIELD, value)
37
- self.parse
38
- self
39
- end
40
-
6
+ # = Comments Field
7
+ #
8
+ # The Comments field inherits from UnstructuredField and handles the Comments:
9
+ # header field in the email.
10
+ #
11
+ # Sending comments to a mail message will instantiate a Mail::Field object that
12
+ # has a CommentsField as its field type.
13
+ #
14
+ # An email header can have as many comments fields as it wants. There is no upper
15
+ # limit, the comments field is also optional (that is, no comment is needed)
16
+ #
17
+ # == Examples:
18
+ #
19
+ # mail = Mail.new
20
+ # mail.comments = 'This is a comment'
21
+ # mail.comments #=> 'This is a comment'
22
+ # mail[:comments] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
23
+ # mail['comments'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
24
+ # mail['comments'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::CommentsField:0x180e1c4
25
+ #
26
+ # mail.comments = "This is another comment"
27
+ # mail[:comments].map { |c| c.to_s }
28
+ # #=> ['This is a comment', "This is another comment"]
29
+ class CommentsField < NamedUnstructuredField #:nodoc:
30
+ NAME = 'Comments'
41
31
  end
42
32
  end
@@ -0,0 +1,170 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/fields/named_structured_field'
4
+
5
+ module Mail
6
+ class AddressContainer < Array #:nodoc:
7
+ def initialize(field, list = nil)
8
+ @field = field
9
+ super list if list
10
+ end
11
+
12
+ def <<(address)
13
+ @field << address
14
+ end
15
+ end
16
+
17
+ class CommonAddressField < NamedStructuredField #:nodoc:
18
+ def self.singular?
19
+ true
20
+ end
21
+
22
+ def initialize(value = nil, charset = nil)
23
+ super encode_if_needed(value, charset), charset
24
+ end
25
+
26
+ def element # :nodoc:
27
+ @element ||= AddressList.new(value)
28
+ end
29
+
30
+ # Allows you to iterate through each address object in the address_list
31
+ def each
32
+ element.addresses.each do |address|
33
+ yield(address)
34
+ end
35
+ end
36
+
37
+ def default
38
+ addresses
39
+ end
40
+
41
+ def address
42
+ addresses.first
43
+ end
44
+
45
+ # Returns the address string of all the addresses in the address list
46
+ def addresses
47
+ list = element.addresses.map { |a| a.address }
48
+ Mail::AddressContainer.new(self, list)
49
+ end
50
+
51
+ # Returns the formatted string of all the addresses in the address list
52
+ def formatted
53
+ list = element.addresses.map { |a| a.format }
54
+ Mail::AddressContainer.new(self, list)
55
+ end
56
+
57
+ # Returns the display name of all the addresses in the address list
58
+ def display_names
59
+ list = element.addresses.map { |a| a.display_name }
60
+ Mail::AddressContainer.new(self, list)
61
+ end
62
+
63
+ # Returns the actual address objects in the address list
64
+ def addrs
65
+ list = element.addresses
66
+ Mail::AddressContainer.new(self, list)
67
+ end
68
+
69
+ # Returns a hash of group name => address strings for the address list
70
+ def groups
71
+ element.addresses_grouped_by_group
72
+ end
73
+
74
+ # Returns the addresses that are part of groups
75
+ def group_addresses
76
+ decoded_group_addresses
77
+ end
78
+
79
+ # Returns a list of decoded group addresses
80
+ def decoded_group_addresses
81
+ groups.map { |k,v| v.map { |a| a.decoded } }.flatten
82
+ end
83
+
84
+ # Returns a list of encoded group addresses
85
+ def encoded_group_addresses
86
+ groups.map { |k,v| v.map { |a| a.encoded } }.flatten
87
+ end
88
+
89
+ # Returns the name of all the groups in a string
90
+ def group_names # :nodoc:
91
+ element.group_names
92
+ end
93
+
94
+ def <<(val)
95
+ case
96
+ when val.nil?
97
+ raise ArgumentError, "Need to pass an address to <<"
98
+ when Utilities.blank?(val)
99
+ self
100
+ else
101
+ self.value = [self.value, encode_if_needed(val)].reject { |a| Utilities.blank?(a) }.join(", ")
102
+ end
103
+ end
104
+
105
+ def encode_if_needed(val, val_charset = charset) #:nodoc:
106
+ case val
107
+ when nil
108
+ val
109
+
110
+ # Need to join arrays of addresses into a single value
111
+ when Array
112
+ val.compact.map { |a| encode_if_needed a, val_charset }.join(', ')
113
+
114
+ # Pass through UTF-8; encode non-UTF-8.
115
+ else
116
+ utf8_if_needed(val, val_charset) || Encodings.encode_non_usascii(val, val_charset)
117
+ end
118
+ end
119
+
120
+ private
121
+ if 'string'.respond_to?(:encoding)
122
+ # Pass through UTF-8 addresses
123
+ def utf8_if_needed(val, val_charset)
124
+ if val_charset =~ /\AUTF-?8\z/i
125
+ val
126
+ elsif val.encoding == Encoding::UTF_8
127
+ val
128
+ elsif (utf8 = val.dup.force_encoding(Encoding::UTF_8)).valid_encoding?
129
+ utf8
130
+ end
131
+ end
132
+ else
133
+ def utf8_if_needed(val, val_charset)
134
+ if val_charset =~ /\AUTF-?8\z/i
135
+ val
136
+ end
137
+ end
138
+ end
139
+
140
+ def do_encode
141
+ return '' if Utilities.blank?(value)
142
+ address_array = element.addresses.reject { |a| encoded_group_addresses.include?(a.encoded) }.compact.map { |a| a.encoded }
143
+ address_text = address_array.join(", \r\n\s")
144
+ group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.encoded }.join(", \r\n\s")};" }
145
+ group_text = group_array.join(" \r\n\s")
146
+ return_array = [address_text, group_text].reject { |a| Utilities.blank?(a) }
147
+ "#{name}: #{return_array.join(", \r\n\s")}\r\n"
148
+ end
149
+
150
+ def do_decode
151
+ return nil if Utilities.blank?(value)
152
+ address_array = element.addresses.reject { |a| decoded_group_addresses.include?(a.decoded) }.map { |a| a.decoded }
153
+ address_text = address_array.join(", ")
154
+ group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.decoded }.join(", ")};" }
155
+ group_text = group_array.join(" ")
156
+ return_array = [address_text, group_text].reject { |a| Utilities.blank?(a) }
157
+ return_array.join(", ")
158
+ end
159
+
160
+ def get_group_addresses(group_list)
161
+ if group_list.respond_to?(:addresses)
162
+ group_list.addresses.map do |address|
163
+ Mail::Address.new(address)
164
+ end
165
+ else
166
+ []
167
+ end
168
+ end
169
+ end
170
+ end
@@ -0,0 +1,58 @@
1
+ require 'mail/fields/named_structured_field'
2
+ require 'mail/elements/date_time_element'
3
+ require 'mail/utilities'
4
+
5
+ module Mail
6
+ class CommonDateField < NamedStructuredField #:nodoc:
7
+ def self.singular?
8
+ true
9
+ end
10
+
11
+ def self.normalize_datetime(string)
12
+ if Utilities.blank?(string)
13
+ datetime = ::DateTime.now
14
+ else
15
+ stripped = string.to_s.gsub(/\(.*?\)/, '').squeeze(' ')
16
+ begin
17
+ datetime = ::DateTime.parse(stripped)
18
+ rescue ArgumentError => e
19
+ raise unless 'invalid date' == e.message
20
+ end
21
+ end
22
+
23
+ if datetime
24
+ datetime.strftime('%a, %d %b %Y %H:%M:%S %z')
25
+ else
26
+ string
27
+ end
28
+ end
29
+
30
+ def initialize(value = nil, charset = nil)
31
+ super self.class.normalize_datetime(value), charset
32
+ end
33
+
34
+ # Returns a date time object of the parsed date
35
+ def date_time
36
+ ::DateTime.parse("#{element.date_string} #{element.time_string}")
37
+ rescue ArgumentError => e
38
+ raise e unless e.message == 'invalid date'
39
+ end
40
+
41
+ def default
42
+ date_time
43
+ end
44
+
45
+ def element
46
+ @element ||= Mail::DateTimeElement.new(value)
47
+ end
48
+
49
+ private
50
+ def do_encode
51
+ "#{name}: #{value}\r\n"
52
+ end
53
+
54
+ def do_decode
55
+ value.to_s
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/constants'
4
+
5
+ module Mail
6
+ class CommonField #:nodoc:
7
+ def self.singular?
8
+ false
9
+ end
10
+
11
+ def self.parse(*args)
12
+ new(*args).tap(&:parse)
13
+ end
14
+
15
+ attr_accessor :name
16
+ attr_reader :value
17
+ attr_accessor :charset
18
+ attr_reader :errors
19
+
20
+ def initialize(name = nil, value = nil, charset = nil)
21
+ @errors = []
22
+
23
+ self.name = name
24
+ self.value = value
25
+ self.charset = charset || 'utf-8'
26
+ end
27
+
28
+ def singular?
29
+ self.class.singular?
30
+ end
31
+
32
+ def value=(value)
33
+ @element = nil
34
+ @value = value.is_a?(Array) ? value : value.to_s
35
+ parse
36
+ end
37
+
38
+ def parse
39
+ tap(&:element)
40
+ end
41
+
42
+ def element
43
+ nil
44
+ end
45
+
46
+ def to_s
47
+ decoded.to_s
48
+ end
49
+
50
+ def default
51
+ decoded
52
+ end
53
+
54
+ def decoded
55
+ do_decode
56
+ end
57
+
58
+ def encoded
59
+ do_encode
60
+ end
61
+
62
+ def responsible_for?(field_name)
63
+ name.to_s.casecmp(field_name.to_s) == 0
64
+ end
65
+
66
+ private
67
+
68
+ FILENAME_RE = /\b(filename|name)=([^;"\r\n]+\s[^;"\r\n]+)/
69
+ def ensure_filename_quoted(value)
70
+ if value.is_a?(String)
71
+ value.sub FILENAME_RE, '\1="\2"'
72
+ else
73
+ value
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+ # frozen_string_literal: true
3
+ require 'mail/fields/named_structured_field'
4
+ require 'mail/utilities'
5
+
6
+ module Mail
7
+ class CommonMessageIdField < NamedStructuredField #:nodoc:
8
+ def element
9
+ @element ||= Mail::MessageIdsElement.new(value)
10
+ end
11
+
12
+ def message_id
13
+ element.message_id
14
+ end
15
+
16
+ def message_ids
17
+ element.message_ids
18
+ end
19
+
20
+ def default
21
+ ids = message_ids
22
+ ids.one? ? ids.first : ids
23
+ end
24
+
25
+ def to_s
26
+ decoded.to_s
27
+ end
28
+
29
+ private
30
+ def do_encode
31
+ %Q{#{name}: #{formatted_message_ids("\r\n ")}\r\n}
32
+ end
33
+
34
+ def do_decode
35
+ formatted_message_ids
36
+ end
37
+
38
+ def formatted_message_ids(join = ' ')
39
+ message_ids.map { |m| "<#{m}>" }.join(join) if message_ids.any?
40
+ end
41
+ end
42
+ end
@@ -1,20 +1,13 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
- #
4
- #
5
- #
3
+ require 'mail/fields/named_unstructured_field'
4
+
6
5
  module Mail
7
- class ContentDescriptionField < UnstructuredField
8
-
9
- FIELD_NAME = 'content-description'
10
- CAPITALIZED_FIELD = 'Content-Description'
11
-
12
- def initialize(value = nil, charset = 'utf-8')
13
- self.charset = charset
14
- super(CAPITALIZED_FIELD, value, charset)
15
- self.parse
16
- self
6
+ class ContentDescriptionField < NamedUnstructuredField #:nodoc:
7
+ NAME = 'Content-Description'
8
+
9
+ def self.singular?
10
+ true
17
11
  end
18
-
19
12
  end
20
13
  end
@@ -1,25 +1,18 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
- require 'mail/fields/common/parameter_hash'
3
+ require 'mail/fields/named_structured_field'
4
+ require 'mail/fields/parameter_hash'
4
5
 
5
6
  module Mail
6
- class ContentDispositionField < StructuredField
7
+ class ContentDispositionField < NamedStructuredField #:nodoc:
8
+ NAME = 'Content-Disposition'
7
9
 
8
- FIELD_NAME = 'content-disposition'
9
- CAPITALIZED_FIELD = 'Content-Disposition'
10
-
11
- def initialize(value = nil, charset = 'utf-8')
12
- self.charset = charset
13
- value = ensure_filename_quoted(value)
14
- super(CAPITALIZED_FIELD, value, charset)
15
- self.parse
16
- self
10
+ def self.singular?
11
+ true
17
12
  end
18
13
 
19
- def parse(val = value)
20
- unless Utilities.blank?(val)
21
- @element = Mail::ContentDispositionElement.new(val)
22
- end
14
+ def initialize(value = nil, charset = nil)
15
+ super ensure_filename_quoted(value), charset
23
16
  end
24
17
 
25
18
  def element
@@ -37,35 +30,17 @@ module Mail
37
30
  end
38
31
 
39
32
  def filename
40
- case
41
- when parameters['filename']
42
- @filename = parameters['filename']
43
- when parameters['name']
44
- @filename = parameters['name']
45
- else
46
- @filename = nil
47
- end
48
- @filename
33
+ @filename ||= parameters['filename'] || parameters['name']
49
34
  end
50
35
 
51
- # TODO: Fix this up
52
36
  def encoded
53
- if parameters.length > 0
54
- p = ";\r\n\s#{parameters.encoded}\r\n"
55
- else
56
- p = "\r\n"
57
- end
58
- "#{CAPITALIZED_FIELD}: #{disposition_type}" + p
37
+ p = ";\r\n\s#{parameters.encoded}" if parameters.length > 0
38
+ "#{name}: #{disposition_type}#{p}\r\n"
59
39
  end
60
40
 
61
41
  def decoded
62
- if parameters.length > 0
63
- p = "; #{parameters.decoded}"
64
- else
65
- p = ""
66
- end
67
- "#{disposition_type}" + p
42
+ p = "; #{parameters.decoded}" if parameters.length > 0
43
+ "#{disposition_type}#{p}"
68
44
  end
69
-
70
45
  end
71
46
  end
@@ -1,63 +1,36 @@
1
1
  # encoding: utf-8
2
2
  # frozen_string_literal: true
3
- #
4
- #
5
- #
3
+ require 'mail/fields/named_structured_field'
4
+ require 'mail/utilities'
5
+
6
6
  module Mail
7
- class ContentIdField < StructuredField
8
-
9
- FIELD_NAME = 'content-id'
10
- CAPITALIZED_FIELD = "Content-ID"
11
-
12
- def initialize(value = nil, charset = 'utf-8')
13
- self.charset = charset
14
- @uniq = 1
15
- if Utilities.blank?(value)
16
- value = generate_content_id
17
- else
18
- value = value.to_s
19
- end
20
- super(CAPITALIZED_FIELD, value, charset)
21
- self.parse
22
- self
23
- end
24
-
25
- def parse(val = value)
26
- unless Utilities.blank?(val)
27
- @element = Mail::MessageIdsElement.new(val)
28
- end
29
- end
30
-
7
+ class ContentIdField < NamedStructuredField #:nodoc:
8
+ NAME = 'Content-ID'
9
+
10
+ def self.singular?
11
+ true
12
+ end
13
+
14
+ def initialize(value = nil, charset = nil)
15
+ value = Mail::Utilities.generate_message_id if Utilities.blank?(value)
16
+ super value, charset
17
+ end
18
+
31
19
  def element
32
20
  @element ||= Mail::MessageIdsElement.new(value)
33
21
  end
34
-
35
- def name
36
- 'Content-ID'
37
- end
38
-
22
+
39
23
  def content_id
40
24
  element.message_id
41
25
  end
42
-
43
- def to_s
44
- "<#{content_id}>"
45
- end
46
-
47
- # TODO: Fix this up
48
- def encoded
49
- "#{CAPITALIZED_FIELD}: #{to_s}\r\n"
50
- end
51
-
52
- def decoded
53
- "#{to_s}"
54
- end
55
-
26
+
56
27
  private
57
-
58
- def generate_content_id
59
- "<#{Mail.random_tag}@#{::Socket.gethostname}.mail>"
60
- end
61
-
28
+ def do_decode
29
+ "<#{content_id}>"
30
+ end
31
+
32
+ def do_encode
33
+ "#{name}: #{do_decode}\r\n"
34
+ end
62
35
  end
63
36
  end