kbaum-mail 2.1.2.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 (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,16 @@
1
+ module Mail
2
+
3
+ class AddressContainer < Array
4
+
5
+ def initialize(field, list = [])
6
+ @field = field
7
+ super(list)
8
+ end
9
+
10
+ def << (address)
11
+ @field << address
12
+ end
13
+
14
+ end
15
+
16
+ end
@@ -0,0 +1,128 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ module CommonAddress # :nodoc:
4
+
5
+ module ClassMethods # :nodoc:
6
+
7
+ end
8
+
9
+ module InstanceMethods # :doc:
10
+
11
+ def parse(val = value)
12
+ unless val.blank?
13
+ @tree = AddressList.new(val)
14
+ else
15
+ nil
16
+ end
17
+ end
18
+
19
+ # Allows you to iterate through each address object in the syntax tree
20
+ def each
21
+ tree.addresses.each do |address|
22
+ yield(address)
23
+ end
24
+ end
25
+
26
+ # Returns the address string of all the addresses in the address list
27
+ def addresses
28
+ list = tree.addresses.map { |a| a.address }
29
+ Mail::AddressContainer.new(self, list)
30
+ end
31
+
32
+ # Returns the formatted string of all the addresses in the address list
33
+ def formatted
34
+ list = tree.addresses.map { |a| a.format }
35
+ Mail::AddressContainer.new(self, list)
36
+ end
37
+
38
+ # Returns the display name of all the addresses in the address list
39
+ def display_names
40
+ list = tree.addresses.map { |a| a.display_name }
41
+ Mail::AddressContainer.new(self, list)
42
+ end
43
+
44
+ # Returns the actual address objects in the address list
45
+ def addrs
46
+ list = tree.addresses
47
+ Mail::AddressContainer.new(self, list)
48
+ end
49
+
50
+ # Returns a hash of group name => address strings for the address list
51
+ def groups
52
+ @groups = Hash.new
53
+ tree.group_recipients.each do |group|
54
+ @groups[group.group_name.text_value] = get_group_addresses(group.group_list)
55
+ end
56
+ @groups
57
+ end
58
+
59
+ # Returns the addresses that are part of groups
60
+ def group_addresses
61
+ groups.map { |k,v| v.map { |a| a.format } }.flatten
62
+ end
63
+
64
+ # Returns the name of all the groups in a string
65
+ def group_names # :nodoc:
66
+ tree.group_names
67
+ end
68
+
69
+ def default
70
+ addresses
71
+ end
72
+
73
+ def <<(val)
74
+ case
75
+ when val.nil?
76
+ raise ArgumentError, "Need to pass an address to <<"
77
+ when val.blank?
78
+ parse(encoded)
79
+ else
80
+ parse((formatted + [val]).join(", "))
81
+ end
82
+ end
83
+
84
+ private
85
+
86
+ def do_encode(field_name)
87
+ return '' if value.blank?
88
+ address_array = tree.addresses.reject { |a| group_addresses.include?(a.encoded) }.compact.map { |a| a.encoded }
89
+ address_text = address_array.join(", \r\n\t")
90
+ group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.encoded }.join(", \r\n\t")};" }
91
+ group_text = group_array.join(" \r\n\t")
92
+ return_array = [address_text, group_text].reject { |a| a.blank? }
93
+ "#{field_name}: #{return_array.join(", \r\n\t")}\r\n"
94
+ end
95
+
96
+ def do_decode
97
+ return nil if value.blank?
98
+ address_array = tree.addresses.reject { |a| group_addresses.include?(a.decoded) }.map { |a| a.decoded }
99
+ address_text = address_array.join(", ")
100
+ group_array = groups.map { |k,v| "#{k}: #{v.map { |a| a.decoded }.join(", ")};" }
101
+ group_text = group_array.join(" ")
102
+ return_array = [address_text, group_text].reject { |a| a.blank? }
103
+ return_array.join(", ")
104
+ end
105
+
106
+ # Returns the syntax tree of the Addresses
107
+ def tree # :nodoc:
108
+ @tree ||= AddressList.new(value)
109
+ end
110
+
111
+ def get_group_addresses(group_list)
112
+ if group_list.respond_to?(:addresses)
113
+ group_list.addresses.map do |address_tree|
114
+ Mail::Address.new(address_tree)
115
+ end
116
+ else
117
+ []
118
+ end
119
+ end
120
+
121
+ end
122
+
123
+ def self.included(receiver) # :nodoc:
124
+ receiver.send :include, InstanceMethods
125
+ end
126
+
127
+ end
128
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ module CommonDate # :nodoc:
4
+
5
+ module InstanceMethods # :doc:
6
+
7
+ # Returns a date time object of the parsed date
8
+ def date_time
9
+ ::DateTime.parse("#{element.date_string} #{element.time_string}")
10
+ end
11
+
12
+ def default
13
+ date_time
14
+ end
15
+
16
+ def parse(val = value)
17
+ unless val.blank?
18
+ @element = Mail::DateTimeElement.new(val)
19
+ @tree = @element.tree
20
+ else
21
+ nil
22
+ end
23
+ end
24
+
25
+ private
26
+
27
+ def do_encode(field_name)
28
+ "#{field_name}: #{value}\r\n"
29
+ end
30
+
31
+ def do_decode
32
+ "#{value}"
33
+ end
34
+
35
+ def element
36
+ @element ||= Mail::DateTimeElement.new(value)
37
+ end
38
+
39
+ # Returns the syntax tree of the Date
40
+ def tree
41
+ @tree ||= element.tree
42
+ end
43
+
44
+ end
45
+
46
+ def self.included(receiver) # :nodoc:
47
+ receiver.send :include, InstanceMethods
48
+ end
49
+
50
+ end
51
+ end
@@ -0,0 +1,64 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ module CommonField # :nodoc:
4
+
5
+ module ClassMethods # :nodoc:
6
+
7
+ end
8
+
9
+ module InstanceMethods # :doc:
10
+
11
+ def name=(value)
12
+ @name = value
13
+ end
14
+
15
+ def name
16
+ @name
17
+ end
18
+
19
+ def value=(value)
20
+ @length = nil
21
+ @tree = nil
22
+ @element = nil
23
+ @value = value
24
+ end
25
+
26
+ def value
27
+ @value
28
+ end
29
+
30
+ def to_s
31
+ decoded
32
+ end
33
+
34
+ def default
35
+ decoded
36
+ end
37
+
38
+ def field_length
39
+ @length ||= name.length + value.length + ': '.length
40
+ end
41
+
42
+ def responsible_for?( val )
43
+ name.to_s.downcase == val.to_s.downcase
44
+ end
45
+
46
+ private
47
+
48
+ def strip_field(field_name, string)
49
+ if string.is_a?(Array)
50
+ string.join(', ')
51
+ else
52
+ string.to_s.gsub(/#{field_name}:\s+/i, '')
53
+ end
54
+ end
55
+
56
+ end
57
+
58
+ def self.included(receiver) # :nodoc:
59
+ receiver.extend ClassMethods
60
+ receiver.send :include, InstanceMethods
61
+ end
62
+
63
+ end
64
+ end
@@ -0,0 +1,57 @@
1
+ # encoding: utf-8
2
+ module Mail
3
+ module CommonMessageId # :nodoc:
4
+
5
+ module ClassMethods # :nodoc:
6
+
7
+ end
8
+
9
+ module InstanceMethods # :doc:
10
+
11
+ def element
12
+ @element ||= Mail::MessageIdsElement.new(value)
13
+ end
14
+
15
+ def parse(val = value)
16
+ unless val.blank?
17
+ @element = Mail::MessageIdsElement.new(val)
18
+ else
19
+ nil
20
+ end
21
+ end
22
+
23
+ def message_id
24
+ element.message_id
25
+ end
26
+
27
+ def message_ids
28
+ element.message_ids
29
+ end
30
+
31
+ def default
32
+ if message_ids.length == 1
33
+ message_ids[0]
34
+ else
35
+ message_ids
36
+ end
37
+ end
38
+
39
+ private
40
+
41
+ def do_encode(field_name)
42
+ %Q{#{field_name}: #{message_ids.map { |m| "<#{m}>" }.join(', ')}\r\n}
43
+ end
44
+
45
+ def do_decode
46
+ "#{message_ids.map { |m| "<#{m}>" }.join(', ')}"
47
+ end
48
+
49
+ end
50
+
51
+ def self.included(receiver) # :nodoc:
52
+ receiver.extend ClassMethods
53
+ receiver.send :include, InstanceMethods
54
+ end
55
+
56
+ end
57
+ end
@@ -0,0 +1,39 @@
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
+ class ParameterHash < HashWithIndifferentAccess
10
+
11
+ def [](key_name)
12
+ pairs = select { |k,v| k =~ /^#{key_name}\*/ }
13
+ pairs = pairs.to_a if RUBY_VERSION >= '1.9'
14
+ if pairs.empty? # Just dealing with a single value pair
15
+ super(key_name)
16
+ else # Dealing with a multiple value pair or a single encoded value pair
17
+ string = pairs.sort { |a,b| a.first <=> b.first }.map { |v| v.last }.join('')
18
+ if mt = string.match(/([\w\d\-]+)'(\w\w)'(.*)/)
19
+ string = mt[3]
20
+ encoding = mt[1]
21
+ else
22
+ encoding = nil
23
+ end
24
+ Mail::Encodings.param_decode(string, encoding)
25
+ end
26
+ end
27
+
28
+ def encoded
29
+ map.sort { |a,b| a.first <=> b.first }.map do |key_name, value|
30
+ unless value.ascii_only?
31
+ value = Mail::Encodings.param_encode(value)
32
+ key_name = "#{key_name}*"
33
+ end
34
+ %Q{#{key_name}="#{value}"}
35
+ end.join(";\r\n\t")
36
+ end
37
+
38
+ end
39
+ 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(*args)
12
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, args.last))
13
+ self.parse
14
+ self
15
+
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,60 @@
1
+ # encoding: utf-8
2
+ #
3
+ #
4
+ #
5
+ module Mail
6
+ class ContentDispositionField < StructuredField
7
+
8
+ FIELD_NAME = 'content-disposition'
9
+ CAPITALIZED_FIELD = 'Content-Disposition'
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::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
+ "#{CAPITALIZED_FIELD}: #{value}\r\n"
53
+ end
54
+
55
+ def decoded
56
+ value
57
+ end
58
+
59
+ end
60
+ end
@@ -0,0 +1,63 @@
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(*args)
12
+ @uniq = 1
13
+ if args.last.blank?
14
+ self.name = CAPITALIZED_FIELD
15
+ self.value = generate_content_id
16
+ else
17
+ super(CAPITALIZED_FIELD, strip_field(FIELD_NAME, args.last))
18
+ end
19
+ self.parse
20
+ self
21
+
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
+ fqdn = ::Socket.gethostname
59
+ "<#{Mail.random_tag}@#{fqdn}.mail>"
60
+ end
61
+
62
+ end
63
+ end