mail-portertech 2.6.2.edge

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 (153) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.rdoc +753 -0
  3. data/CONTRIBUTING.md +60 -0
  4. data/Dependencies.txt +2 -0
  5. data/Gemfile +15 -0
  6. data/MIT-LICENSE +20 -0
  7. data/README.md +683 -0
  8. data/Rakefile +29 -0
  9. data/TODO.rdoc +9 -0
  10. data/lib/mail.rb +91 -0
  11. data/lib/mail/attachments_list.rb +104 -0
  12. data/lib/mail/body.rb +291 -0
  13. data/lib/mail/check_delivery_params.rb +20 -0
  14. data/lib/mail/configuration.rb +75 -0
  15. data/lib/mail/core_extensions/nil.rb +19 -0
  16. data/lib/mail/core_extensions/object.rb +13 -0
  17. data/lib/mail/core_extensions/smtp.rb +24 -0
  18. data/lib/mail/core_extensions/string.rb +43 -0
  19. data/lib/mail/core_extensions/string/access.rb +145 -0
  20. data/lib/mail/core_extensions/string/multibyte.rb +78 -0
  21. data/lib/mail/elements.rb +14 -0
  22. data/lib/mail/elements/address.rb +270 -0
  23. data/lib/mail/elements/address_list.rb +51 -0
  24. data/lib/mail/elements/content_disposition_element.rb +26 -0
  25. data/lib/mail/elements/content_location_element.rb +21 -0
  26. data/lib/mail/elements/content_transfer_encoding_element.rb +17 -0
  27. data/lib/mail/elements/content_type_element.rb +31 -0
  28. data/lib/mail/elements/date_time_element.rb +22 -0
  29. data/lib/mail/elements/envelope_from_element.rb +39 -0
  30. data/lib/mail/elements/message_ids_element.rb +24 -0
  31. data/lib/mail/elements/mime_version_element.rb +22 -0
  32. data/lib/mail/elements/phrase_list.rb +16 -0
  33. data/lib/mail/elements/received_element.rb +26 -0
  34. data/lib/mail/encodings.rb +304 -0
  35. data/lib/mail/encodings/7bit.rb +31 -0
  36. data/lib/mail/encodings/8bit.rb +31 -0
  37. data/lib/mail/encodings/base64.rb +33 -0
  38. data/lib/mail/encodings/binary.rb +31 -0
  39. data/lib/mail/encodings/quoted_printable.rb +39 -0
  40. data/lib/mail/encodings/transfer_encoding.rb +58 -0
  41. data/lib/mail/envelope.rb +30 -0
  42. data/lib/mail/field.rb +247 -0
  43. data/lib/mail/field_list.rb +33 -0
  44. data/lib/mail/fields.rb +35 -0
  45. data/lib/mail/fields/bcc_field.rb +56 -0
  46. data/lib/mail/fields/cc_field.rb +55 -0
  47. data/lib/mail/fields/comments_field.rb +41 -0
  48. data/lib/mail/fields/common/address_container.rb +16 -0
  49. data/lib/mail/fields/common/common_address.rb +135 -0
  50. data/lib/mail/fields/common/common_date.rb +35 -0
  51. data/lib/mail/fields/common/common_field.rb +57 -0
  52. data/lib/mail/fields/common/common_message_id.rb +48 -0
  53. data/lib/mail/fields/common/parameter_hash.rb +58 -0
  54. data/lib/mail/fields/content_description_field.rb +19 -0
  55. data/lib/mail/fields/content_disposition_field.rb +70 -0
  56. data/lib/mail/fields/content_id_field.rb +62 -0
  57. data/lib/mail/fields/content_location_field.rb +42 -0
  58. data/lib/mail/fields/content_transfer_encoding_field.rb +44 -0
  59. data/lib/mail/fields/content_type_field.rb +201 -0
  60. data/lib/mail/fields/date_field.rb +57 -0
  61. data/lib/mail/fields/from_field.rb +55 -0
  62. data/lib/mail/fields/in_reply_to_field.rb +56 -0
  63. data/lib/mail/fields/keywords_field.rb +44 -0
  64. data/lib/mail/fields/message_id_field.rb +82 -0
  65. data/lib/mail/fields/mime_version_field.rb +53 -0
  66. data/lib/mail/fields/optional_field.rb +13 -0
  67. data/lib/mail/fields/received_field.rb +75 -0
  68. data/lib/mail/fields/references_field.rb +56 -0
  69. data/lib/mail/fields/reply_to_field.rb +55 -0
  70. data/lib/mail/fields/resent_bcc_field.rb +55 -0
  71. data/lib/mail/fields/resent_cc_field.rb +55 -0
  72. data/lib/mail/fields/resent_date_field.rb +35 -0
  73. data/lib/mail/fields/resent_from_field.rb +55 -0
  74. data/lib/mail/fields/resent_message_id_field.rb +34 -0
  75. data/lib/mail/fields/resent_sender_field.rb +62 -0
  76. data/lib/mail/fields/resent_to_field.rb +55 -0
  77. data/lib/mail/fields/return_path_field.rb +65 -0
  78. data/lib/mail/fields/sender_field.rb +67 -0
  79. data/lib/mail/fields/structured_field.rb +51 -0
  80. data/lib/mail/fields/subject_field.rb +16 -0
  81. data/lib/mail/fields/to_field.rb +55 -0
  82. data/lib/mail/fields/unstructured_field.rb +204 -0
  83. data/lib/mail/header.rb +274 -0
  84. data/lib/mail/indifferent_hash.rb +146 -0
  85. data/lib/mail/mail.rb +267 -0
  86. data/lib/mail/matchers/has_sent_mail.rb +157 -0
  87. data/lib/mail/message.rb +2160 -0
  88. data/lib/mail/multibyte.rb +42 -0
  89. data/lib/mail/multibyte/chars.rb +474 -0
  90. data/lib/mail/multibyte/exceptions.rb +8 -0
  91. data/lib/mail/multibyte/unicode.rb +400 -0
  92. data/lib/mail/multibyte/utils.rb +60 -0
  93. data/lib/mail/network.rb +14 -0
  94. data/lib/mail/network/delivery_methods/exim.rb +52 -0
  95. data/lib/mail/network/delivery_methods/file_delivery.rb +45 -0
  96. data/lib/mail/network/delivery_methods/sendmail.rb +89 -0
  97. data/lib/mail/network/delivery_methods/smtp.rb +142 -0
  98. data/lib/mail/network/delivery_methods/smtp_connection.rb +61 -0
  99. data/lib/mail/network/delivery_methods/test_mailer.rb +44 -0
  100. data/lib/mail/network/retriever_methods/base.rb +63 -0
  101. data/lib/mail/network/retriever_methods/imap.rb +173 -0
  102. data/lib/mail/network/retriever_methods/pop3.rb +140 -0
  103. data/lib/mail/network/retriever_methods/test_retriever.rb +43 -0
  104. data/lib/mail/parsers.rb +26 -0
  105. data/lib/mail/parsers/address_lists_parser.rb +132 -0
  106. data/lib/mail/parsers/content_disposition_parser.rb +67 -0
  107. data/lib/mail/parsers/content_location_parser.rb +35 -0
  108. data/lib/mail/parsers/content_transfer_encoding_parser.rb +33 -0
  109. data/lib/mail/parsers/content_type_parser.rb +64 -0
  110. data/lib/mail/parsers/date_time_parser.rb +36 -0
  111. data/lib/mail/parsers/envelope_from_parser.rb +45 -0
  112. data/lib/mail/parsers/message_ids_parser.rb +39 -0
  113. data/lib/mail/parsers/mime_version_parser.rb +41 -0
  114. data/lib/mail/parsers/phrase_lists_parser.rb +33 -0
  115. data/lib/mail/parsers/ragel.rb +17 -0
  116. data/lib/mail/parsers/ragel/common.rl +184 -0
  117. data/lib/mail/parsers/ragel/date_time.rl +30 -0
  118. data/lib/mail/parsers/ragel/parser_info.rb +61 -0
  119. data/lib/mail/parsers/ragel/ruby.rb +39 -0
  120. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb +14864 -0
  121. data/lib/mail/parsers/ragel/ruby/machines/address_lists_machine.rb.rl +37 -0
  122. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb +751 -0
  123. data/lib/mail/parsers/ragel/ruby/machines/content_disposition_machine.rb.rl +37 -0
  124. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb +614 -0
  125. data/lib/mail/parsers/ragel/ruby/machines/content_location_machine.rb.rl +37 -0
  126. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb +447 -0
  127. data/lib/mail/parsers/ragel/ruby/machines/content_transfer_encoding_machine.rb.rl +37 -0
  128. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb +825 -0
  129. data/lib/mail/parsers/ragel/ruby/machines/content_type_machine.rb.rl +37 -0
  130. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb +817 -0
  131. data/lib/mail/parsers/ragel/ruby/machines/date_time_machine.rb.rl +37 -0
  132. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb +2129 -0
  133. data/lib/mail/parsers/ragel/ruby/machines/envelope_from_machine.rb.rl +37 -0
  134. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb +1570 -0
  135. data/lib/mail/parsers/ragel/ruby/machines/message_ids_machine.rb.rl +37 -0
  136. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb +440 -0
  137. data/lib/mail/parsers/ragel/ruby/machines/mime_version_machine.rb.rl +37 -0
  138. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb +564 -0
  139. data/lib/mail/parsers/ragel/ruby/machines/phrase_lists_machine.rb.rl +37 -0
  140. data/lib/mail/parsers/ragel/ruby/machines/rb_actions.rl +51 -0
  141. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb +5144 -0
  142. data/lib/mail/parsers/ragel/ruby/machines/received_machine.rb.rl +37 -0
  143. data/lib/mail/parsers/ragel/ruby/parser.rb.rl.erb +37 -0
  144. data/lib/mail/parsers/received_parser.rb +47 -0
  145. data/lib/mail/part.rb +120 -0
  146. data/lib/mail/parts_list.rb +57 -0
  147. data/lib/mail/patterns.rb +37 -0
  148. data/lib/mail/utilities.rb +225 -0
  149. data/lib/mail/values/unicode_tables.dat +0 -0
  150. data/lib/mail/version.rb +4 -0
  151. data/lib/mail/version_specific/ruby_1_8.rb +119 -0
  152. data/lib/mail/version_specific/ruby_1_9.rb +159 -0
  153. metadata +276 -0
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ module CommonMessageId # :nodoc:
4
+ def element
5
+ @element ||= Mail::MessageIdsElement.new(value) unless value.blank?
6
+ end
7
+
8
+ def parse(val = value)
9
+ unless val.blank?
10
+ @element = Mail::MessageIdsElement.new(val)
11
+ else
12
+ nil
13
+ end
14
+ end
15
+
16
+ def message_id
17
+ element.message_id if element
18
+ end
19
+
20
+ def message_ids
21
+ element.message_ids if element
22
+ end
23
+
24
+ def default
25
+ return nil unless message_ids
26
+ if message_ids.length == 1
27
+ message_ids[0]
28
+ else
29
+ message_ids
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def do_encode(field_name)
36
+ %Q{#{field_name}: #{formated_message_ids("\r\n ")}\r\n}
37
+ end
38
+
39
+ def do_decode
40
+ formated_message_ids(' ')
41
+ end
42
+
43
+ def formated_message_ids(join)
44
+ message_ids.map{ |m| "<#{m}>" }.join(join) if message_ids
45
+ end
46
+
47
+ end
48
+ end
@@ -0,0 +1,58 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+
4
+ # ParameterHash is an intelligent Hash that allows you to add
5
+ # parameter values including the MIME extension paramaters that
6
+ # have the name*0="blah", name*1="bleh" keys, and will just return
7
+ # a single key called name="blahbleh" and do any required un-encoding
8
+ # to make that happen
9
+ # Parameters are defined in RFC2045, split keys are in RFC2231
10
+
11
+ class ParameterHash < IndifferentHash
12
+
13
+ include Mail::Utilities
14
+
15
+ def [](key_name)
16
+ key_pattern = Regexp.escape(key_name.to_s)
17
+ pairs = []
18
+ exact = nil
19
+ each do |k,v|
20
+ if k =~ /^#{key_pattern}(\*|$)/i
21
+ if $1 == '*'
22
+ pairs << [k, v]
23
+ else
24
+ exact = k
25
+ end
26
+ end
27
+ end
28
+ if pairs.empty? # Just dealing with a single value pair
29
+ super(exact || key_name)
30
+ else # Dealing with a multiple value pair or a single encoded value pair
31
+ string = pairs.sort { |a,b| a.first.to_s <=> b.first.to_s }.map { |v| v.last }.join('')
32
+ if mt = string.match(/([\w\-]+)'(\w\w)'(.*)/)
33
+ string = mt[3]
34
+ encoding = mt[1]
35
+ else
36
+ encoding = nil
37
+ end
38
+ Mail::Encodings.param_decode(string, encoding)
39
+ end
40
+ end
41
+
42
+ def encoded
43
+ map.sort { |a,b| a.first.to_s <=> b.first.to_s }.map do |key_name, value|
44
+ unless value.ascii_only?
45
+ value = Mail::Encodings.param_encode(value)
46
+ key_name = "#{key_name}*"
47
+ end
48
+ %Q{#{key_name}=#{quote_token(value)}}
49
+ end.join(";\r\n\s")
50
+ end
51
+
52
+ def decoded
53
+ map.sort { |a,b| a.first.to_s <=> b.first.to_s }.map do |key_name, value|
54
+ %Q{#{key_name}=#{quote_token(value)}}
55
+ end.join("; ")
56
+ end
57
+ end
58
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+ #
3
+ #
4
+ #
5
+ module Mail
6
+ class ContentDescriptionField < UnstructuredField
7
+
8
+ FIELD_NAME = 'content-description'
9
+ CAPITALIZED_FIELD = 'Content-Description'
10
+
11
+ def initialize(value = nil, charset = 'utf-8')
12
+ self.charset = charset
13
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
14
+ self.parse
15
+ self
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,70 @@
1
+ # encoding: utf-8
2
+ require 'mail/fields/common/parameter_hash'
3
+
4
+ module Mail
5
+ class ContentDispositionField < StructuredField
6
+
7
+ FIELD_NAME = 'content-disposition'
8
+ CAPITALIZED_FIELD = 'Content-Disposition'
9
+
10
+ def initialize(value = nil, charset = 'utf-8')
11
+ self.charset = charset
12
+ ensure_filename_quoted(value)
13
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
14
+ self.parse
15
+ self
16
+ end
17
+
18
+ def parse(val = value)
19
+ unless val.blank?
20
+ @element = Mail::ContentDispositionElement.new(val)
21
+ end
22
+ end
23
+
24
+ def element
25
+ @element ||= Mail::ContentDispositionElement.new(value)
26
+ end
27
+
28
+ def disposition_type
29
+ element.disposition_type
30
+ end
31
+
32
+ def parameters
33
+ @parameters = ParameterHash.new
34
+ element.parameters.each { |p| @parameters.merge!(p) }
35
+ @parameters
36
+ end
37
+
38
+ def filename
39
+ case
40
+ when !parameters['filename'].blank?
41
+ @filename = parameters['filename']
42
+ when !parameters['name'].blank?
43
+ @filename = parameters['name']
44
+ else
45
+ @filename = nil
46
+ end
47
+ @filename
48
+ end
49
+
50
+ # TODO: Fix this up
51
+ def encoded
52
+ if parameters.length > 0
53
+ p = ";\r\n\s#{parameters.encoded}\r\n"
54
+ else
55
+ p = "\r\n"
56
+ end
57
+ "#{CAPITALIZED_FIELD}: #{disposition_type}" + p
58
+ end
59
+
60
+ def decoded
61
+ if parameters.length > 0
62
+ p = "; #{parameters.decoded}"
63
+ else
64
+ p = ""
65
+ end
66
+ "#{disposition_type}" + p
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,62 @@
1
+ # encoding: utf-8
2
+ #
3
+ #
4
+ #
5
+ module Mail
6
+ class ContentIdField < StructuredField
7
+
8
+ FIELD_NAME = 'content-id'
9
+ CAPITALIZED_FIELD = "Content-ID"
10
+
11
+ def initialize(value = nil, charset = 'utf-8')
12
+ self.charset = charset
13
+ @uniq = 1
14
+ if value.blank?
15
+ value = generate_content_id
16
+ else
17
+ value = strip_field(FIELD_NAME, value)
18
+ end
19
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
20
+ self.parse
21
+ self
22
+ end
23
+
24
+ def parse(val = value)
25
+ unless val.blank?
26
+ @element = Mail::MessageIdsElement.new(val)
27
+ end
28
+ end
29
+
30
+ def element
31
+ @element ||= Mail::MessageIdsElement.new(value)
32
+ end
33
+
34
+ def name
35
+ 'Content-ID'
36
+ end
37
+
38
+ def content_id
39
+ element.message_id
40
+ end
41
+
42
+ def to_s
43
+ "<#{content_id}>"
44
+ end
45
+
46
+ # TODO: Fix this up
47
+ def encoded
48
+ "#{CAPITALIZED_FIELD}: #{to_s}\r\n"
49
+ end
50
+
51
+ def decoded
52
+ "#{to_s}"
53
+ end
54
+
55
+ private
56
+
57
+ def generate_content_id
58
+ "<#{Mail.random_tag}@#{::Socket.gethostname}.mail>"
59
+ end
60
+
61
+ end
62
+ end
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+ #
3
+ #
4
+ #
5
+ module Mail
6
+ class ContentLocationField < StructuredField
7
+
8
+ FIELD_NAME = 'content-location'
9
+ CAPITALIZED_FIELD = 'Content-Location'
10
+
11
+ def initialize(value = nil, charset = 'utf-8')
12
+ self.charset = charset
13
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
14
+ self.parse
15
+ self
16
+ end
17
+
18
+ def parse(val = value)
19
+ unless val.blank?
20
+ @element = Mail::ContentLocationElement.new(val)
21
+ end
22
+ end
23
+
24
+ def element
25
+ @element ||= Mail::ContentLocationElement.new(value)
26
+ end
27
+
28
+ def location
29
+ element.location
30
+ end
31
+
32
+ # TODO: Fix this up
33
+ def encoded
34
+ "#{CAPITALIZED_FIELD}: #{location}\r\n"
35
+ end
36
+
37
+ def decoded
38
+ location
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+ #
3
+ #
4
+ #
5
+ module Mail
6
+ class ContentTransferEncodingField < StructuredField
7
+
8
+ FIELD_NAME = 'content-transfer-encoding'
9
+ CAPITALIZED_FIELD = 'Content-Transfer-Encoding'
10
+
11
+ def initialize(value = nil, charset = 'utf-8')
12
+ self.charset = charset
13
+ value = '7bit' if value.to_s =~ /7-?bits?/i
14
+ value = '8bit' if value.to_s =~ /8-?bits?/i
15
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, value), charset)
16
+ self.parse
17
+ self
18
+ end
19
+
20
+ def parse(val = value)
21
+ unless val.blank?
22
+ @element = Mail::ContentTransferEncodingElement.new(val)
23
+ end
24
+ end
25
+
26
+ def element
27
+ @element ||= Mail::ContentTransferEncodingElement.new(value)
28
+ end
29
+
30
+ def encoding
31
+ element.encoding
32
+ end
33
+
34
+ # TODO: Fix this up
35
+ def encoded
36
+ "#{CAPITALIZED_FIELD}: #{encoding}\r\n"
37
+ end
38
+
39
+ def decoded
40
+ encoding
41
+ end
42
+
43
+ end
44
+ end
@@ -0,0 +1,201 @@
1
+ # encoding: utf-8
2
+ require 'mail/fields/common/parameter_hash'
3
+
4
+ module Mail
5
+ class ContentTypeField < StructuredField
6
+
7
+ FIELD_NAME = 'content-type'
8
+ CAPITALIZED_FIELD = 'Content-Type'
9
+
10
+ def initialize(value = nil, charset = 'utf-8')
11
+ self.charset = charset
12
+ if value.class == Array
13
+ @main_type = value[0]
14
+ @sub_type = value[1]
15
+ @parameters = ParameterHash.new.merge!(value.last)
16
+ else
17
+ @main_type = nil
18
+ @sub_type = nil
19
+ @parameters = nil
20
+ value = strip_field(FIELD_NAME, value)
21
+ end
22
+ ensure_filename_quoted(value)
23
+ super(CAPITALIZED_FIELD, value, charset)
24
+ self.parse
25
+ self
26
+ end
27
+
28
+ def parse(val = value)
29
+ unless val.blank?
30
+ self.value = val
31
+ @element = nil
32
+ element
33
+ end
34
+ end
35
+
36
+ def element
37
+ begin
38
+ @element ||= Mail::ContentTypeElement.new(value)
39
+ rescue
40
+ attempt_to_clean
41
+ end
42
+ end
43
+
44
+ def attempt_to_clean
45
+ # Sanitize the value, handle special cases
46
+ @element ||= Mail::ContentTypeElement.new(sanatize(value))
47
+ rescue
48
+ # All else fails, just get the MIME media type
49
+ @element ||= Mail::ContentTypeElement.new(get_mime_type(value))
50
+ end
51
+
52
+ def main_type
53
+ @main_type ||= element.main_type
54
+ end
55
+
56
+ def sub_type
57
+ @sub_type ||= element.sub_type
58
+ end
59
+
60
+ def string
61
+ "#{main_type}/#{sub_type}"
62
+ end
63
+
64
+ def default
65
+ decoded
66
+ end
67
+
68
+ alias :content_type :string
69
+
70
+ def parameters
71
+ unless @parameters
72
+ @parameters = ParameterHash.new
73
+ element.parameters.each { |p| @parameters.merge!(p) }
74
+ end
75
+ @parameters
76
+ end
77
+
78
+ def ContentTypeField.with_boundary(type)
79
+ new("#{type}; boundary=#{generate_boundary}")
80
+ end
81
+
82
+ def ContentTypeField.generate_boundary
83
+ "--==_mimepart_#{Mail.random_tag}"
84
+ end
85
+
86
+ def value
87
+ if @value.class == Array
88
+ "#{@main_type}/#{@sub_type}; #{stringify(parameters)}"
89
+ else
90
+ @value
91
+ end
92
+ end
93
+
94
+ def stringify(params)
95
+ params.map { |k,v| "#{k}=#{Encodings.param_encode(v)}" }.join("; ")
96
+ end
97
+
98
+ def filename
99
+ case
100
+ when parameters['filename']
101
+ @filename = parameters['filename']
102
+ when parameters['name']
103
+ @filename = parameters['name']
104
+ else
105
+ @filename = nil
106
+ end
107
+ @filename
108
+ end
109
+
110
+ # TODO: Fix this up
111
+ def encoded
112
+ if parameters.length > 0
113
+ p = ";\r\n\s#{parameters.encoded}"
114
+ else
115
+ p = ""
116
+ end
117
+ "#{CAPITALIZED_FIELD}: #{content_type}#{p}\r\n"
118
+ end
119
+
120
+ def decoded
121
+ if parameters.length > 0
122
+ p = "; #{parameters.decoded}"
123
+ else
124
+ p = ""
125
+ end
126
+ "#{content_type}" + p
127
+ end
128
+
129
+ private
130
+
131
+ def method_missing(name, *args, &block)
132
+ if name.to_s =~ /(\w+)=/
133
+ self.parameters[$1] = args.first
134
+ @value = "#{content_type}; #{stringify(parameters)}"
135
+ else
136
+ super
137
+ end
138
+ end
139
+
140
+ # Various special cases from random emails found that I am not going to change
141
+ # the parser for
142
+ def sanatize( val )
143
+
144
+ # TODO: check if there are cases where whitespace is not a separator
145
+ val = val.
146
+ gsub(/\s*=\s*/,'='). # remove whitespaces around equal sign
147
+ tr(' ',';').
148
+ squeeze(';').
149
+ gsub(';', '; '). #use '; ' as a separator (or EOL)
150
+ gsub(/;\s*$/,'') #remove trailing to keep examples below
151
+
152
+ if val =~ /(boundary=(\S*))/i
153
+ val = "#{$`.downcase}boundary=#{$2}#{$'.downcase}"
154
+ else
155
+ val.downcase!
156
+ end
157
+
158
+ case
159
+ when val.chomp =~ /^\s*([\w\-]+)\/([\w\-]+)\s*;;+(.*)$/i
160
+ # Handles 'text/plain;; format="flowed"' (double semi colon)
161
+ "#{$1}/#{$2}; #{$3}"
162
+ when val.chomp =~ /^\s*([\w\-]+)\/([\w\-]+)\s*;\s?(ISO[\w\-]+)$/i
163
+ # Microsoft helper:
164
+ # Handles 'type/subtype;ISO-8559-1'
165
+ "#{$1}/#{$2}; charset=#{quote_atom($3)}"
166
+ when val.chomp =~ /^text;?$/i
167
+ # Handles 'text;' and 'text'
168
+ "text/plain;"
169
+ when val.chomp =~ /^(\w+);\s(.*)$/i
170
+ # Handles 'text; <parameters>'
171
+ "text/plain; #{$2}"
172
+ when val =~ /([\w\-]+\/[\w\-]+);\scharset="charset="(\w+)""/i
173
+ # Handles text/html; charset="charset="GB2312""
174
+ "#{$1}; charset=#{quote_atom($2)}"
175
+ when val =~ /([\w\-]+\/[\w\-]+);\s+(.*)/i
176
+ type = $1
177
+ # Handles misquoted param values
178
+ # e.g: application/octet-stream; name=archiveshelp1[1].htm
179
+ # and: audio/x-midi;\r\n\sname=Part .exe
180
+ params = $2.to_s.split(/\s+/)
181
+ params = params.map { |i| i.to_s.chomp.strip }
182
+ params = params.map { |i| i.split(/\s*\=\s*/) }
183
+ params = params.map { |i| "#{i[0]}=#{dquote(i[1].to_s.gsub(/;$/,""))}" }.join('; ')
184
+ "#{type}; #{params}"
185
+ when val =~ /^\s*$/
186
+ 'text/plain'
187
+ else
188
+ ''
189
+ end
190
+ end
191
+
192
+ def get_mime_type( val )
193
+ case
194
+ when val =~ /^([\w\-]+)\/([\w\-]+);.+$/i
195
+ "#{$1}/#{$2}"
196
+ else
197
+ 'text/plain'
198
+ end
199
+ end
200
+ end
201
+ end