mime 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (35) hide show
  1. data/README.rdoc +192 -140
  2. data/lib/mime/composite_media.rb +230 -0
  3. data/lib/mime/content_formats/text_flowed.rb +6 -6
  4. data/lib/mime/discrete_media.rb +73 -0
  5. data/lib/mime/discrete_media_factory.rb +19 -13
  6. data/lib/mime/header.rb +48 -0
  7. data/lib/mime/headers/internet.rb +124 -27
  8. data/lib/mime/headers/mime.rb +38 -27
  9. data/lib/mime/mail.rb +51 -0
  10. data/lib/mime/media.rb +30 -0
  11. data/lib/mime/parser.rb +1 -1
  12. data/lib/mime.rb +27 -9
  13. data/test/scaffold/application.msg +2 -5
  14. data/test/scaffold/audio.msg +2 -5
  15. data/test/scaffold/image.msg +0 -0
  16. data/test/scaffold/multipart_alternative.msg +7 -7
  17. data/test/scaffold/multipart_alternative_related.msg +0 -0
  18. data/test/scaffold/multipart_form_data_file_and_text.msg +0 -0
  19. data/test/scaffold/multipart_form_data_mixed.msg +0 -0
  20. data/test/scaffold/multipart_form_data_text.msg +12 -12
  21. data/test/scaffold/multipart_mixed_inline_and_attachment.msg +0 -0
  22. data/test/scaffold/multipart_mixed_inline_and_attachment2.msg +0 -0
  23. data/test/scaffold/multipart_related.msg +0 -0
  24. data/test/scaffold/rfc822_composite.msg +0 -0
  25. data/test/scaffold/{plain_text_email.msg → rfc822_discrete.msg} +5 -5
  26. data/test/scaffold/text.msg +2 -5
  27. data/test/scaffold/video.msg +2 -5
  28. data/test/test_mime.rb +323 -150
  29. data/test/test_text_flowed.rb +1 -1
  30. metadata +13 -12
  31. data/lib/mime/composite_media_type.rb +0 -169
  32. data/lib/mime/discrete_media_type.rb +0 -78
  33. data/lib/mime/header_container.rb +0 -32
  34. data/lib/mime/media_type.rb +0 -51
  35. data/lib/mime/message.rb +0 -61
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mime
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-02-28 00:00:00.000000000 Z
12
+ date: 2014-04-18 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description: ! 'A library for building RFC compliant Multipurpose Internet Mail Extensions
15
15
 
@@ -32,14 +32,14 @@ files:
32
32
  - lib/mime/headers/internet.rb
33
33
  - lib/mime/discrete_media_factory.rb
34
34
  - lib/mime/error.rb
35
- - lib/mime/header_container.rb
36
35
  - lib/mime/parser.rb
37
36
  - lib/mime/content_types.rb
38
- - lib/mime/media_type.rb
39
- - lib/mime/composite_media_type.rb
40
- - lib/mime/discrete_media_type.rb
41
- - lib/mime/message.rb
37
+ - lib/mime/media.rb
38
+ - lib/mime/composite_media.rb
42
39
  - lib/mime/content_formats/text_flowed.rb
40
+ - lib/mime/header.rb
41
+ - lib/mime/mail.rb
42
+ - lib/mime/discrete_media.rb
43
43
  - lib/mime.rb
44
44
  - test/scaffold/application.msg
45
45
  - test/scaffold/unknown.yyy
@@ -47,23 +47,24 @@ files:
47
47
  - test/scaffold/mini.mov
48
48
  - test/scaffold/image.jpg
49
49
  - test/scaffold/book.pdf
50
- - test/scaffold/plain_text_email.msg
51
50
  - test/scaffold/song.mp3
52
51
  - test/scaffold/ruby.png
53
52
  - test/scaffold/multipart_alternative.msg
54
- - test/scaffold/multipart_alternative_related.msg
55
- - test/scaffold/multipart_related.msg
56
53
  - test/scaffold/multipart_mixed_inline_and_attachment2.msg
57
54
  - test/scaffold/image.msg
58
55
  - test/scaffold/multipart_form_data_file_and_text.msg
59
56
  - test/scaffold/data.xml
60
- - test/scaffold/multipart_form_data_mixed.msg
57
+ - test/scaffold/rfc822_composite.msg
61
58
  - test/scaffold/text.msg
62
59
  - test/scaffold/main.css
63
- - test/scaffold/multipart_mixed_inline_and_attachment.msg
60
+ - test/scaffold/multipart_alternative_related.msg
64
61
  - test/scaffold/multipart_form_data_text.msg
65
62
  - test/scaffold/audio.msg
63
+ - test/scaffold/multipart_related.msg
64
+ - test/scaffold/rfc822_discrete.msg
66
65
  - test/scaffold/data.htm
66
+ - test/scaffold/multipart_form_data_mixed.msg
67
+ - test/scaffold/multipart_mixed_inline_and_attachment.msg
67
68
  - test/test_mime.rb-try
68
69
  - test/test_mime.rb
69
70
  - test/test_text_flowed.rb
@@ -1,169 +0,0 @@
1
- module MIME
2
-
3
- #
4
- # Composite entities are handled using MIME mechanisms. A MIME processor must
5
- # handle the body directly. A CompositeMediaType object is composed of one or
6
- # more CompositeMediaType and/or DiscreteMediaType objects.
7
- #
8
- # This class is abstract.
9
- #
10
- class CompositeMediaType < MediaType
11
-
12
- def initialize content_type
13
- AbstractClassError.no_instantiation(self, CompositeMediaType)
14
-
15
- super(nil, content_type)
16
- @entities = Array.new
17
- end
18
-
19
- #
20
- # Add a MediaType object to the message.
21
- #
22
- def add_entity entity
23
- raise Error.new('can only add MediaType objects') unless entity.is_a? MediaType
24
- @entities.unshift(entity)
25
- end
26
-
27
- #
28
- # Attach a MediaType object to the message.
29
- #
30
- def attach_entity entity, params = {}
31
- entity.set_content_disposition('attachment', params)
32
- add_entity(entity)
33
- end
34
-
35
- #
36
- # Inline a MediaType object in the message.
37
- #
38
- def inline_entity entity, params = {}
39
- entity.set_content_disposition('inline', params)
40
- add_entity(entity)
41
- end
42
-
43
- end
44
-
45
- #
46
- # MessageMedia is intended to encapsulate another message. In particular,
47
- # the <em>message/rfc822</em> content type is used to encapsulate RFC 822
48
- # messages.
49
- #
50
- # TODO Implement
51
- #
52
- class MessageMedia < CompositeMediaType
53
- end
54
-
55
- #
56
- # The abstract base class for all multipart message subtypes. The entities of
57
- # a multipart message are delimited by a unique boundary.
58
- #
59
- class MultipartMedia < CompositeMediaType
60
-
61
- def initialize content_type
62
- AbstractClassError.no_instantiation(self, MultipartMedia)
63
- super
64
- end
65
-
66
- #
67
- # The boundary used to separate the message entities.
68
- #
69
- def boundary
70
- @boundary ||= "Boundary_#{unique_id}"
71
- end
72
-
73
- #
74
- # Return the multipart representation of the body.
75
- #
76
- def body
77
- all_entities = @entities.join("\r\n--#{boundary}\r\n")
78
- "--#{boundary}\r\n#{all_entities}\r\n--#{boundary}--\r\n"
79
- end
80
-
81
- end
82
-
83
- #
84
- # The Alternative subtype indicates that each contained entity is an
85
- # alternatively formatted version of the same content. The most complex
86
- # version should be added to the message first, i.e. it will be sequentially
87
- # last in the message.
88
- #
89
- class MultipartMedia::Alternative < MultipartMedia
90
-
91
- #
92
- # Returns a MultipartMedia::Alternative object with a content type of
93
- # multipart/alternative.
94
- #
95
- def initialize
96
- super("multipart/alternative; boundary=#{boundary}")
97
- end
98
-
99
- end
100
-
101
- #
102
- # The FormData subtype expresses values for HTML form data submissions.
103
- # ---
104
- # RFCs consulted during implementation:
105
- #
106
- # * RFC-1867 Form-based File Upload in HTML
107
- # * RFC-2388 Returning Values from Forms: multipart/form-data
108
- #
109
- class MultipartMedia::FormData < MultipartMedia
110
-
111
- #
112
- # Returns a MultipartMedia::FormData object with a content type of
113
- # multipart/form-data.
114
- #
115
- def initialize
116
- super("multipart/form-data; boundary=#{boundary}")
117
- end
118
-
119
- #
120
- # Add the MediaType object, +entity+, to the FormData object. +name+ is
121
- # typically an HTML input tag variable name. If the input tag is of type
122
- # _file_, then +filename+ must be specified to indicate a file upload.
123
- #
124
- def add_entity entity, name, filename = nil
125
- entity.set_content_disposition('form-data', 'name' => name, 'filename' => filename)
126
- super(entity)
127
- end
128
-
129
- end
130
-
131
- #
132
- # The Mixed subtype aggregates contextually independent entities.
133
- #
134
- class MultipartMedia::Mixed < MultipartMedia
135
-
136
- #
137
- # Returns a MultipartMedia::Mixed object with a content type of
138
- # multipart/mixed.
139
- #
140
- def initialize
141
- super("multipart/mixed; boundary=#{boundary}")
142
- end
143
-
144
- end
145
-
146
- #
147
- # The Related subtype aggregates multiple related entities. The message
148
- # consists of a root (the first entity) which references subsequent inline
149
- # entities. Message entities should be referenced by their Content-ID header.
150
- # The syntax of a reference is unspecified and is instead dictated by the
151
- # encoding or protocol used in the entity.
152
- # ---
153
- # RFC consulted during implementation:
154
- #
155
- # * RFC-2387 The MIME Multipart/Related Content-type
156
- #
157
- class MultipartMedia::Related < MultipartMedia
158
-
159
- #
160
- # Returns a MultipartMedia::Related object with a content type of
161
- # multipart/related.
162
- #
163
- def initialize
164
- super("multipart/related; boundary=#{boundary}")
165
- end
166
-
167
- end
168
-
169
- end
@@ -1,78 +0,0 @@
1
- module MIME
2
-
3
- #
4
- # Discrete media types must be handled by non-MIME mechanisms; they are
5
- # opaque to MIME processors. Therefore, the body of a DiscreteMediaType
6
- # object does not need further MIME processing.
7
- #
8
- # This class is abstract.
9
- #
10
- class DiscreteMediaType < MediaType
11
- def initialize(body, media_subtype, content_params)
12
- AbstractClassError.no_instantiation(self, DiscreteMediaType)
13
- super(body, "#{@media_type}/#{media_subtype}", content_params)
14
- end
15
- end
16
-
17
- #
18
- # ApplicationMedia is intended for discrete data that is to be processed by
19
- # some type of application program. The body contains information which must
20
- # be processed by an application before it is viewable or usable by a user.
21
- #
22
- # ApplicationMedia is the catch all class. If your content cannot be
23
- # identified as another DiscreteMediaType, then it is application media.
24
- #
25
- class ApplicationMedia < DiscreteMediaType
26
- def initialize(body, subtype = 'octet-stream', params = {})
27
- @media_type = 'application'
28
- super
29
- end
30
- end
31
-
32
- #
33
- # AudioMedia is intended for discrete audio content. The +subtype+ indicates
34
- # the specific audio format, such as *mpeg* or *midi*.
35
- #
36
- class AudioMedia < DiscreteMediaType
37
- def initialize(body, subtype = 'basic', params = {})
38
- @media_type = 'audio'
39
- super
40
- end
41
- end
42
-
43
- #
44
- # ImageMedia is intented for discrete image content. The +subtype+ indicates
45
- # the specific image format, such as *jpeg* or *gif*.
46
- #
47
- class ImageMedia < DiscreteMediaType
48
- def initialize(body, subtype = 'jpeg', params = {})
49
- @media_type = 'image'
50
- super
51
- end
52
- end
53
-
54
- #
55
- # TextMedia is intended for content which is principally textual in form. The
56
- # +subtype+ indicates the specific text type, such as *plain* or *html*.
57
- #
58
- class TextMedia < DiscreteMediaType
59
- def initialize(body, subtype = 'plain', params = {})
60
- @media_type = 'text'
61
- super
62
- end
63
- end
64
-
65
- #
66
- # VideoMedia is intended for discrete video content. The content +subtype+
67
- # indicates the specific video format. The RFC describes video media as
68
- # content that contains a time-varying-picture image, possibly with color and
69
- # coordinated sound.
70
- #
71
- class VideoMedia < DiscreteMediaType
72
- def initialize(body, subtype = 'mpeg', params = {})
73
- @media_type = 'video'
74
- super
75
- end
76
- end
77
-
78
- end
@@ -1,32 +0,0 @@
1
- module MIME
2
-
3
- #
4
- # Storage for RFC 2822 headers.
5
- #
6
- class HeaderContainer
7
-
8
- #
9
- # Return a new header container object.
10
- #
11
- def initialize
12
- @headers = Hash.new
13
- end
14
-
15
- #
16
- # Convert all headers to their string equivalents and join them using the
17
- # RFC 2822 CRLF line separator.
18
- #
19
- def to_s
20
- @headers.to_a.map {|kv| kv.join(": ")}.join("\r\n")
21
- end
22
-
23
- #
24
- # Add the +name+/+value+ pair to the header container.
25
- #
26
- def add name, value
27
- @headers.store(name, value)
28
- end
29
-
30
- end
31
-
32
- end
@@ -1,51 +0,0 @@
1
- require 'mime/error'
2
- require 'mime/header_container'
3
- require 'mime/headers/mime'
4
-
5
- module MIME
6
-
7
- #
8
- # Abstract top-level media type class.
9
- #
10
- class MediaType
11
-
12
- include Headers::MIME
13
-
14
- attr_reader :headers
15
- attr_accessor :body
16
- protected :body, :body=
17
-
18
- def initialize body, content_type, content_params = {}
19
- AbstractClassError.no_instantiation(self, MediaType)
20
-
21
- @headers = HeaderContainer.new
22
- @body = body
23
- self.content_id = unique_id
24
- self.content_type =
25
- if content_params.empty?
26
- content_type
27
- else
28
- params = content_params.to_a.map {|kv| kv.join('=')}.join('; ')
29
- "#{content_type}; #{params}"
30
- end
31
- end
32
-
33
- #
34
- # Transform the the MediaType object into a MIME message.
35
- #
36
- def to_s
37
- "#{headers}\r\n\r\n#{body}"
38
- end
39
-
40
- private
41
-
42
- #
43
- # Generate a globally unique identifier for use in boundaries and IDs.
44
- #
45
- def unique_id
46
- "#{object_id.abs}#{rand}"
47
- end
48
-
49
- end
50
-
51
- end
data/lib/mime/message.rb DELETED
@@ -1,61 +0,0 @@
1
- require 'time'
2
- require 'mime/headers/internet'
3
- require 'mime/headers/mime'
4
-
5
-
6
- module MIME
7
-
8
- #
9
- # Construct textual messages using the RFC 2822 Internet message format.
10
- #
11
- class Message
12
-
13
- include Headers::Internet
14
- include Headers::MIME
15
-
16
- # HeaderContainer access
17
- attr_reader :headers
18
-
19
- attr_accessor :body
20
-
21
- #
22
- # Return a Message object with body optionally set to +body+.
23
- #
24
- def initialize body = nil
25
- @body = body
26
- @headers = HeaderContainer.new
27
- self.date = Time.now.rfc2822
28
- self.message_id = "#{rand(1E9)}@#{__id__.abs}"
29
- self.mime_version = "1.0 (Ruby MIME v#{VERSION})"
30
- end
31
-
32
- #
33
- # Return the Internet message formatted representation of the instance.
34
- #
35
- def to_s
36
- #--
37
- # In an RFC 2822 message, the header and body sections must be separated
38
- # by two line breaks (CRLF). One line break is deliberately missing,
39
- # allowing a body supplier to append headers to the top-level message
40
- # header section. Consequently, the body supplier is responsible for
41
- # handling the body-header separation. Furthermore, if the +body+ is
42
- # empty, the header section will be properly terminated, creating a
43
- # standards compliant message.
44
- #++
45
-
46
- # FIXME writing directly to body VS setting body with a MediaType gives an
47
- # imbalance of "\r\n". Setting body directly with string requires a CRLF
48
- # prepended, but not the case for TextMedia for instance. So where do we
49
- # handle this? Perhaps HeaderContainer#to_s should append a CRLF, or
50
- # self#body should detect String and automatically prepend CRLF??? Then we
51
- # remove the CRLF here between the headers and body.
52
- #
53
- # Also, TextMedia adds the Content-ID and Content-Type headers, which we
54
- # don't get if body is set directly with String. Does this matter?
55
-
56
- "#{headers}\r\n#{body}\r\n"
57
- end
58
-
59
- end
60
-
61
- end