kbaum-mail 2.1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. data/CHANGELOG.rdoc +289 -0
  2. data/README.rdoc +575 -0
  3. data/Rakefile +72 -0
  4. data/TODO.rdoc +19 -0
  5. data/lib/mail.rb +113 -0
  6. data/lib/mail/attachments_list.rb +76 -0
  7. data/lib/mail/body.rb +243 -0
  8. data/lib/mail/configuration.rb +69 -0
  9. data/lib/mail/core_extensions/nil.rb +11 -0
  10. data/lib/mail/core_extensions/string.rb +19 -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 +21 -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/encodings/base64.rb +18 -0
  24. data/lib/mail/encodings/encodings.rb +201 -0
  25. data/lib/mail/encodings/quoted_printable.rb +26 -0
  26. data/lib/mail/envelope.rb +35 -0
  27. data/lib/mail/field.rb +219 -0
  28. data/lib/mail/field_list.rb +33 -0
  29. data/lib/mail/fields/bcc_field.rb +53 -0
  30. data/lib/mail/fields/cc_field.rb +52 -0
  31. data/lib/mail/fields/comments_field.rb +41 -0
  32. data/lib/mail/fields/common/address_container.rb +16 -0
  33. data/lib/mail/fields/common/common_address.rb +128 -0
  34. data/lib/mail/fields/common/common_date.rb +51 -0
  35. data/lib/mail/fields/common/common_field.rb +64 -0
  36. data/lib/mail/fields/common/common_message_id.rb +57 -0
  37. data/lib/mail/fields/common/parameter_hash.rb +39 -0
  38. data/lib/mail/fields/content_description_field.rb +19 -0
  39. data/lib/mail/fields/content_disposition_field.rb +60 -0
  40. data/lib/mail/fields/content_id_field.rb +63 -0
  41. data/lib/mail/fields/content_location_field.rb +42 -0
  42. data/lib/mail/fields/content_transfer_encoding_field.rb +45 -0
  43. data/lib/mail/fields/content_type_field.rb +175 -0
  44. data/lib/mail/fields/date_field.rb +53 -0
  45. data/lib/mail/fields/from_field.rb +53 -0
  46. data/lib/mail/fields/in_reply_to_field.rb +52 -0
  47. data/lib/mail/fields/keywords_field.rb +43 -0
  48. data/lib/mail/fields/message_id_field.rb +80 -0
  49. data/lib/mail/fields/mime_version_field.rb +54 -0
  50. data/lib/mail/fields/optional_field.rb +11 -0
  51. data/lib/mail/fields/received_field.rb +62 -0
  52. data/lib/mail/fields/references_field.rb +53 -0
  53. data/lib/mail/fields/reply_to_field.rb +53 -0
  54. data/lib/mail/fields/resent_bcc_field.rb +53 -0
  55. data/lib/mail/fields/resent_cc_field.rb +53 -0
  56. data/lib/mail/fields/resent_date_field.rb +33 -0
  57. data/lib/mail/fields/resent_from_field.rb +53 -0
  58. data/lib/mail/fields/resent_message_id_field.rb +32 -0
  59. data/lib/mail/fields/resent_sender_field.rb +60 -0
  60. data/lib/mail/fields/resent_to_field.rb +53 -0
  61. data/lib/mail/fields/return_path_field.rb +62 -0
  62. data/lib/mail/fields/sender_field.rb +65 -0
  63. data/lib/mail/fields/structured_field.rb +36 -0
  64. data/lib/mail/fields/subject_field.rb +15 -0
  65. data/lib/mail/fields/to_field.rb +53 -0
  66. data/lib/mail/fields/unstructured_field.rb +117 -0
  67. data/lib/mail/header.rb +235 -0
  68. data/lib/mail/mail.rb +194 -0
  69. data/lib/mail/message.rb +1780 -0
  70. data/lib/mail/network/delivery_methods/file_delivery.rb +40 -0
  71. data/lib/mail/network/delivery_methods/sendmail.rb +62 -0
  72. data/lib/mail/network/delivery_methods/smtp.rb +110 -0
  73. data/lib/mail/network/delivery_methods/test_mailer.rb +40 -0
  74. data/lib/mail/network/retriever_methods/imap.rb +31 -0
  75. data/lib/mail/network/retriever_methods/pop3.rb +149 -0
  76. data/lib/mail/parsers/address_lists.rb +61 -0
  77. data/lib/mail/parsers/address_lists.treetop +19 -0
  78. data/lib/mail/parsers/content_disposition.rb +369 -0
  79. data/lib/mail/parsers/content_disposition.treetop +46 -0
  80. data/lib/mail/parsers/content_location.rb +133 -0
  81. data/lib/mail/parsers/content_location.treetop +20 -0
  82. data/lib/mail/parsers/content_transfer_encoding.rb +179 -0
  83. data/lib/mail/parsers/content_transfer_encoding.treetop +25 -0
  84. data/lib/mail/parsers/content_type.rb +512 -0
  85. data/lib/mail/parsers/content_type.treetop +58 -0
  86. data/lib/mail/parsers/date_time.rb +111 -0
  87. data/lib/mail/parsers/date_time.treetop +11 -0
  88. data/lib/mail/parsers/envelope_from.rb +188 -0
  89. data/lib/mail/parsers/envelope_from.treetop +32 -0
  90. data/lib/mail/parsers/message_ids.rb +42 -0
  91. data/lib/mail/parsers/message_ids.treetop +15 -0
  92. data/lib/mail/parsers/mime_version.rb +141 -0
  93. data/lib/mail/parsers/mime_version.treetop +19 -0
  94. data/lib/mail/parsers/phrase_lists.rb +42 -0
  95. data/lib/mail/parsers/phrase_lists.treetop +15 -0
  96. data/lib/mail/parsers/received.rb +68 -0
  97. data/lib/mail/parsers/received.treetop +11 -0
  98. data/lib/mail/parsers/rfc2045.rb +406 -0
  99. data/lib/mail/parsers/rfc2045.treetop +35 -0
  100. data/lib/mail/parsers/rfc2822.rb +5081 -0
  101. data/lib/mail/parsers/rfc2822.treetop +410 -0
  102. data/lib/mail/parsers/rfc2822_obsolete.rb +3607 -0
  103. data/lib/mail/parsers/rfc2822_obsolete.treetop +241 -0
  104. data/lib/mail/part.rb +82 -0
  105. data/lib/mail/parts_list.rb +34 -0
  106. data/lib/mail/patterns.rb +43 -0
  107. data/lib/mail/utilities.rb +163 -0
  108. data/lib/mail/vendor/treetop.rb +4 -0
  109. data/lib/mail/version.rb +10 -0
  110. data/lib/mail/version_specific/ruby_1_8.rb +84 -0
  111. data/lib/mail/version_specific/ruby_1_9.rb +77 -0
  112. data/lib/tasks/corpus.rake +125 -0
  113. data/lib/tasks/treetop.rake +10 -0
  114. metadata +188 -0
@@ -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(*args)
12
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, args.last))
13
+ self.parse
14
+ self
15
+
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}: #{value}\r\n"
35
+ end
36
+
37
+ def decoded
38
+ value
39
+ end
40
+
41
+ end
42
+ end
@@ -0,0 +1,45 @@
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(*args)
12
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, args.last.to_s.downcase))
13
+ end
14
+
15
+ def parse(val = value)
16
+ unless val.blank?
17
+ @element = Mail::ContentTransferEncodingElement.new(val)
18
+ @tree = @element.tree
19
+ end
20
+ end
21
+
22
+ def tree
23
+ @element ||= Mail::ContentTransferEncodingElement.new(value)
24
+ @tree ||= @element.tree
25
+ end
26
+
27
+ def element
28
+ @element ||= Mail::ContentTransferEncodingElement.new(value)
29
+ end
30
+
31
+ def encoding
32
+ element.encoding
33
+ end
34
+
35
+ # TODO: Fix this up
36
+ def encoded
37
+ "#{CAPITALIZED_FIELD}: #{value}\r\n"
38
+ end
39
+
40
+ def decoded
41
+ value
42
+ end
43
+
44
+ end
45
+ end
@@ -0,0 +1,175 @@
1
+ # encoding: utf-8
2
+ #
3
+ #
4
+ #
5
+ module Mail
6
+ class ContentTypeField < StructuredField
7
+
8
+ FIELD_NAME = 'content-type'
9
+ CAPITALIZED_FIELD = 'Content-Type'
10
+
11
+ def initialize(*args)
12
+ if args.last.class == Array
13
+ @main_type = args.last[0]
14
+ @sub_type = args.last[1]
15
+ @parameters = ParameterHash.new.merge!(args.last.last)
16
+ super(CAPITALIZED_FIELD, args.last)
17
+ else
18
+ @main_type = nil
19
+ @sub_type = nil
20
+ @parameters = nil
21
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, args.last))
22
+ end
23
+ self.parse
24
+ self
25
+ end
26
+
27
+ def parse(val = value)
28
+ unless val.blank?
29
+ self.value = val
30
+ @element = nil
31
+ element
32
+ end
33
+ end
34
+
35
+ def element
36
+ begin
37
+ @element ||= Mail::ContentTypeElement.new(value)
38
+ rescue
39
+ attempt_to_clean
40
+ end
41
+ end
42
+
43
+ def attempt_to_clean
44
+ # Sanitize the value, handle special cases
45
+ @element ||= Mail::ContentTypeElement.new(sanatize(value))
46
+ rescue
47
+ # All else fails, just get the mime type
48
+ @element ||= Mail::ContentTypeElement.new(get_mime_type(value))
49
+ end
50
+
51
+ def main_type
52
+ @main_type ||= element.main_type
53
+ end
54
+
55
+ def sub_type
56
+ @sub_type ||= element.sub_type
57
+ end
58
+
59
+ def string
60
+ "#{main_type}/#{sub_type}"
61
+ end
62
+
63
+ def default
64
+ decoded
65
+ end
66
+
67
+ alias :content_type :string
68
+
69
+ def parameters
70
+ unless @parameters
71
+ @parameters = ParameterHash.new
72
+ element.parameters.each { |p| @parameters.merge!(p) }
73
+ end
74
+ @parameters
75
+ end
76
+
77
+ def ContentTypeField.with_boundary(type)
78
+ new("#{type}; boundary=#{generate_boundary}")
79
+ end
80
+
81
+ def ContentTypeField.generate_boundary
82
+ "--==_mimepart_#{Mail.random_tag}"
83
+ end
84
+
85
+ def value
86
+ if @value.class == Array
87
+ "#{@main_type}/#{@sub_type}; #{stringify(parameters)}"
88
+ else
89
+ @value
90
+ end
91
+ end
92
+
93
+ def stringify(params)
94
+ params.map { |k,v| "#{k}=#{Encodings.param_encode(v)}" }.join("; ")
95
+ end
96
+
97
+ def filename
98
+ case
99
+ when parameters['filename']
100
+ @filename = parameters['filename']
101
+ when parameters['name']
102
+ @filename = parameters['name']
103
+ else
104
+ @filename = nil
105
+ end
106
+ @filename
107
+ end
108
+
109
+ # TODO: Fix this up
110
+ def encoded
111
+ "#{CAPITALIZED_FIELD}: #{content_type};\r\n\t#{parameters.encoded};\r\n"
112
+ end
113
+
114
+ def decoded
115
+ value
116
+ end
117
+
118
+ private
119
+
120
+ def method_missing(name, *args, &block)
121
+ if name.to_s =~ /([\w_]+)=/
122
+ self.parameters[$1] = args.first
123
+ @value = "#{content_type}; #{stringify(parameters)}"
124
+ else
125
+ super
126
+ end
127
+ end
128
+
129
+ # Various special cases from random emails found that I am not going to change
130
+ # the parser for
131
+ def sanatize( val )
132
+ case
133
+ when val.chomp =~ /^\s*([\w\d\-_]+)\/([\w\d\-_]+)\s*;;+(.*)$/i
134
+ # Handles 'text/plain;; format="flowed"' (double semi colon)
135
+ "#{$1}/#{$2}; #{$3}"
136
+ when val.chomp =~ /^\s*([\w\d\-_]+)\/([\w\d\-_]+)\s*;(ISO[\w\d\-_]+)$/i
137
+ # Microsoft helper:
138
+ # Handles 'mime/type;ISO-8559-1'
139
+ "#{$1}/#{$2}; charset=#{quote_atom($3)}"
140
+ when val.chomp =~ /^text;?$/i
141
+ # Handles 'text;' and 'text'
142
+ "text/plain;"
143
+ when val.chomp =~ /^(\w+);\s(.*)$/i
144
+ # Handles 'text; <parameters>'
145
+ "text/plain; #{$2}"
146
+ when val =~ /([\w\d\-_]+\/[\w\d\-_]+);\scharset="charset="(\w+)""/i
147
+ # Handles text/html; charset="charset="GB2312""
148
+ "#{$1}; charset=#{quote_atom($2)}"
149
+ when val =~ /([\w\d\-_]+\/[\w\d\-_]+);\s+(.*)/i
150
+ type = $1
151
+ # Handles misquoted param values
152
+ # e.g: application/octet-stream; name=archiveshelp1[1].htm
153
+ # and: audio/x-midi;\r\n\tname=Part .exe
154
+ params = $2.to_s.split(/\s+/)
155
+ params = params.map { |i| i.to_s.chomp.strip }
156
+ params = params.map { |i| i.split(/\s*\=\s*/) }
157
+ params = params.map { |i| "#{i[0]}=#{dquote(i[1].to_s)}" }.join('; ')
158
+ "#{type}; #{params}"
159
+ when val =~ /^\s*$/
160
+ 'text/plain'
161
+ else
162
+ ''
163
+ end
164
+ end
165
+
166
+ def get_mime_type( val )
167
+ case
168
+ when val =~ /^([\w\d\-_]+)\/([\w\d\-_]+);.+$/i
169
+ "#{$1}/#{$2}"
170
+ else
171
+ 'text/plain'
172
+ end
173
+ end
174
+ end
175
+ end
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+ #
3
+ # = Date Field
4
+ #
5
+ # The Date field inherits from StructuredField and handles the Date: header
6
+ # field in the email.
7
+ #
8
+ # Sending date to a mail message will instantiate a Mail::Field object that
9
+ # has a DateField as it's field type. This includes all Mail::CommonAddress
10
+ # module instance methods.
11
+ #
12
+ # There must be excatly one Date field in an RFC2822 email.
13
+ #
14
+ # == Examples:
15
+ #
16
+ # mail = Mail.new
17
+ # mail.date = 'Mon, 24 Nov 1997 14:22:01 -0800'
18
+ # mail.date #=> #<DateTime: 211747170121/86400,-1/3,2299161>
19
+ # mail.date.to_s #=> 'Mon, 24 Nov 1997 14:22:01 -0800'
20
+ # mail[:date] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::DateField:0x180e1c4
21
+ # mail['date'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::DateField:0x180e1c4
22
+ # mail['Date'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::DateField:0x180e1c4
23
+ #
24
+ module Mail
25
+ class DateField < StructuredField
26
+
27
+ include Mail::CommonDate
28
+
29
+ FIELD_NAME = 'date'
30
+ CAPITALIZED_FIELD = "Date"
31
+
32
+ def initialize(*args)
33
+ if args.last.blank?
34
+ self.name = CAPITALIZED_FIELD
35
+ self.value = Time.now.strftime('%a, %d %b %Y %H:%M:%S %z')
36
+ self
37
+ else
38
+ value = strip_field(FIELD_NAME, args.last)
39
+ value = ::DateTime.parse(value.to_s).strftime('%a, %d %b %Y %H:%M:%S %z')
40
+ super(CAPITALIZED_FIELD, value)
41
+ end
42
+ end
43
+
44
+ def encoded
45
+ do_encode(CAPITALIZED_FIELD)
46
+ end
47
+
48
+ def decoded
49
+ do_decode
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,53 @@
1
+ # encoding: utf-8
2
+ #
3
+ # = From Field
4
+ #
5
+ # The From field inherits from StructuredField and handles the From: header
6
+ # field in the email.
7
+ #
8
+ # Sending from to a mail message will instantiate a Mail::Field object that
9
+ # has a FromField as it's field type. This includes all Mail::CommonAddress
10
+ # module instance metods.
11
+ #
12
+ # Only one From 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.from = 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
19
+ # mail.from #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
20
+ # mail[:from] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::FromField:0x180e1c4
21
+ # mail['from'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::FromField:0x180e1c4
22
+ # mail['From'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::FromField:0x180e1c4
23
+ #
24
+ # mail[:from].encoded #=> 'from: Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net\r\n'
25
+ # mail[:from].decoded #=> 'Mikel Lindsaar <mikel@test.lindsaar.net>, ada@test.lindsaar.net'
26
+ # mail[:from].addresses #=> ['mikel@test.lindsaar.net', 'ada@test.lindsaar.net']
27
+ # mail[:from].formatted #=> ['Mikel Lindsaar <mikel@test.lindsaar.net>', 'ada@test.lindsaar.net']
28
+ #
29
+ module Mail
30
+ class FromField < StructuredField
31
+
32
+ include Mail::CommonAddress
33
+
34
+ FIELD_NAME = 'from'
35
+ CAPITALIZED_FIELD = 'From'
36
+
37
+ def initialize(*args)
38
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, args.last))
39
+ self.parse
40
+ self
41
+
42
+ end
43
+
44
+ def encoded
45
+ do_encode(CAPITALIZED_FIELD)
46
+ end
47
+
48
+ def decoded
49
+ do_decode
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,52 @@
1
+ # encoding: utf-8
2
+ #
3
+ # = In-Reply-To Field
4
+ #
5
+ # The In-Reply-To field inherits from StructuredField and handles the
6
+ # In-Reply-To: header field in the email.
7
+ #
8
+ # Sending in_reply_to to a mail message will instantiate a Mail::Field object that
9
+ # has a InReplyToField as it's field type. This includes all Mail::CommonMessageId
10
+ # module instance metods.
11
+ #
12
+ # Note that, the #message_ids method will return an array of message IDs without the
13
+ # enclosing angle brackets which per RFC are not syntactically part of the message id.
14
+ #
15
+ # Only one InReplyTo field can appear in a header, though it can have multiple
16
+ # Message IDs.
17
+ #
18
+ # == Examples:
19
+ #
20
+ # mail = Mail.new
21
+ # mail.in_reply_to = '<F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom>'
22
+ # mail.in_reply_to #=> '<F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom>'
23
+ # mail[:in_reply_to] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::InReplyToField:0x180e1c4
24
+ # mail['in_reply_to'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::InReplyToField:0x180e1c4
25
+ # mail['In-Reply-To'] #=> '#<Mail::Field:0x180e5e8 @field=#<Mail::InReplyToField:0x180e1c4
26
+ #
27
+ # mail[:in_reply_to].message_ids #=> ['F6E2D0B4-CC35-4A91-BA4C-C7C712B10C13@test.me.dom']
28
+ #
29
+ module Mail
30
+ class InReplyToField < StructuredField
31
+
32
+ include Mail::CommonMessageId
33
+
34
+ FIELD_NAME = 'in-reply-to'
35
+ CAPITALIZED_FIELD = 'In-Reply-To'
36
+
37
+ def initialize(*args)
38
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, args.last))
39
+ self.parse
40
+ self
41
+ end
42
+
43
+ def encoded
44
+ do_encode(CAPITALIZED_FIELD)
45
+ end
46
+
47
+ def decoded
48
+ do_decode
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+ #
3
+ # keywords = "Keywords:" phrase *("," phrase) CRLF
4
+ module Mail
5
+ class KeywordsField < StructuredField
6
+
7
+ FIELD_NAME = 'keywords'
8
+ CAPITALIZED_FIELD = 'Keywords'
9
+
10
+ def initialize(*args)
11
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, args.last))
12
+ self.parse
13
+ self
14
+ end
15
+
16
+ def parse(val = value)
17
+ unless val.blank?
18
+ @phrase_list ||= PhraseList.new(value)
19
+ end
20
+ end
21
+
22
+ def phrase_list
23
+ @phrase_list ||= PhraseList.new(value)
24
+ end
25
+
26
+ def keywords
27
+ phrase_list.phrases
28
+ end
29
+
30
+ def encoded
31
+ "#{CAPITALIZED_FIELD}: #{keywords.join(', ')}\r\n"
32
+ end
33
+
34
+ def decoded
35
+ keywords.join(', ')
36
+ end
37
+
38
+ def default
39
+ keywords
40
+ end
41
+
42
+ end
43
+ end