mms2r 1.0.0

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 (55) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +54 -0
  3. data/README.txt +81 -0
  4. data/Rakefile +30 -0
  5. data/conf/mms2r_cingularmedia_transform.yml +6 -0
  6. data/conf/mms2r_sprintmedia_ignore.yml +10 -0
  7. data/conf/mms2r_tmobilemedia_ignore.yml +17 -0
  8. data/conf/mms2r_verizonmedia_ignore.yml +3 -0
  9. data/lib/mms2r.rb +3 -0
  10. data/lib/mms2r/cingular_media.rb +11 -0
  11. data/lib/mms2r/media.rb +345 -0
  12. data/lib/mms2r/mmode_media.rb +13 -0
  13. data/lib/mms2r/sprint_media.rb +50 -0
  14. data/lib/mms2r/tmobile_media.rb +11 -0
  15. data/lib/mms2r/verizon_media.rb +11 -0
  16. data/lib/mms2r/version.rb +12 -0
  17. data/lib/vendor/text/format.rb +1466 -0
  18. data/lib/vendor/tmail.rb +3 -0
  19. data/lib/vendor/tmail/address.rb +242 -0
  20. data/lib/vendor/tmail/attachments.rb +39 -0
  21. data/lib/vendor/tmail/base64.rb +71 -0
  22. data/lib/vendor/tmail/config.rb +69 -0
  23. data/lib/vendor/tmail/encode.rb +467 -0
  24. data/lib/vendor/tmail/facade.rb +552 -0
  25. data/lib/vendor/tmail/header.rb +914 -0
  26. data/lib/vendor/tmail/info.rb +35 -0
  27. data/lib/vendor/tmail/loader.rb +1 -0
  28. data/lib/vendor/tmail/mail.rb +447 -0
  29. data/lib/vendor/tmail/mailbox.rb +433 -0
  30. data/lib/vendor/tmail/mbox.rb +1 -0
  31. data/lib/vendor/tmail/net.rb +280 -0
  32. data/lib/vendor/tmail/obsolete.rb +135 -0
  33. data/lib/vendor/tmail/parser.rb +1522 -0
  34. data/lib/vendor/tmail/port.rb +377 -0
  35. data/lib/vendor/tmail/quoting.rb +131 -0
  36. data/lib/vendor/tmail/scanner.rb +41 -0
  37. data/lib/vendor/tmail/scanner_r.rb +263 -0
  38. data/lib/vendor/tmail/stringio.rb +277 -0
  39. data/lib/vendor/tmail/tmail.rb +1 -0
  40. data/lib/vendor/tmail/utils.rb +238 -0
  41. data/test/files/dot.jpg +0 -0
  42. data/test/files/sprint-image-01.mail +195 -0
  43. data/test/files/sprint-text-01.mail +8 -0
  44. data/test/files/sprint-video-01.mail +195 -0
  45. data/test/files/sprint.mov +0 -0
  46. data/test/files/verizon-image-01.mail +815 -0
  47. data/test/files/verizon-text-01.mail +11 -0
  48. data/test/files/verizon-video-01.mail +336 -0
  49. data/test/test_mms2r_cingular.rb +52 -0
  50. data/test/test_mms2r_media.rb +311 -0
  51. data/test/test_mms2r_mmode.rb +52 -0
  52. data/test/test_mms2r_sprint.rb +154 -0
  53. data/test/test_mms2r_tmobile.rb +169 -0
  54. data/test/test_mms2r_verizon.rb +74 -0
  55. metadata +130 -0
@@ -0,0 +1,377 @@
1
+ #
2
+ # port.rb
3
+ #
4
+ #--
5
+ # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining
8
+ # a copy of this software and associated documentation files (the
9
+ # "Software"), to deal in the Software without restriction, including
10
+ # without limitation the rights to use, copy, modify, merge, publish,
11
+ # distribute, sublicense, and/or sell copies of the Software, and to
12
+ # permit persons to whom the Software is furnished to do so, subject to
13
+ # the following conditions:
14
+ #
15
+ # The above copyright notice and this permission notice shall be
16
+ # included in all copies or substantial portions of the Software.
17
+ #
18
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
+ #
26
+ # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
27
+ # with permission of Minero Aoki.
28
+ #++
29
+
30
+ require 'tmail/stringio'
31
+
32
+
33
+ module TMail
34
+
35
+ class Port
36
+ def reproducible?
37
+ false
38
+ end
39
+ end
40
+
41
+
42
+ ###
43
+ ### FilePort
44
+ ###
45
+
46
+ class FilePort < Port
47
+
48
+ def initialize( fname )
49
+ @filename = File.expand_path(fname)
50
+ super()
51
+ end
52
+
53
+ attr_reader :filename
54
+
55
+ alias ident filename
56
+
57
+ def ==( other )
58
+ other.respond_to?(:filename) and @filename == other.filename
59
+ end
60
+
61
+ alias eql? ==
62
+
63
+ def hash
64
+ @filename.hash
65
+ end
66
+
67
+ def inspect
68
+ "#<#{self.class}:#{@filename}>"
69
+ end
70
+
71
+ def reproducible?
72
+ true
73
+ end
74
+
75
+ def size
76
+ File.size @filename
77
+ end
78
+
79
+
80
+ def ropen( &block )
81
+ File.open(@filename, &block)
82
+ end
83
+
84
+ def wopen( &block )
85
+ File.open(@filename, 'w', &block)
86
+ end
87
+
88
+ def aopen( &block )
89
+ File.open(@filename, 'a', &block)
90
+ end
91
+
92
+
93
+ def read_all
94
+ ropen {|f|
95
+ return f.read
96
+ }
97
+ end
98
+
99
+
100
+ def remove
101
+ File.unlink @filename
102
+ end
103
+
104
+ def move_to( port )
105
+ begin
106
+ File.link @filename, port.filename
107
+ rescue Errno::EXDEV
108
+ copy_to port
109
+ end
110
+ File.unlink @filename
111
+ end
112
+
113
+ alias mv move_to
114
+
115
+ def copy_to( port )
116
+ if FilePort === port
117
+ copy_file @filename, port.filename
118
+ else
119
+ File.open(@filename) {|r|
120
+ port.wopen {|w|
121
+ while s = r.sysread(4096)
122
+ w.write << s
123
+ end
124
+ } }
125
+ end
126
+ end
127
+
128
+ alias cp copy_to
129
+
130
+ private
131
+
132
+ # from fileutils.rb
133
+ def copy_file( src, dest )
134
+ st = r = w = nil
135
+
136
+ File.open(src, 'rb') {|r|
137
+ File.open(dest, 'wb') {|w|
138
+ st = r.stat
139
+ begin
140
+ while true
141
+ w.write r.sysread(st.blksize)
142
+ end
143
+ rescue EOFError
144
+ end
145
+ } }
146
+ end
147
+
148
+ end
149
+
150
+
151
+ module MailFlags
152
+
153
+ def seen=( b )
154
+ set_status 'S', b
155
+ end
156
+
157
+ def seen?
158
+ get_status 'S'
159
+ end
160
+
161
+ def replied=( b )
162
+ set_status 'R', b
163
+ end
164
+
165
+ def replied?
166
+ get_status 'R'
167
+ end
168
+
169
+ def flagged=( b )
170
+ set_status 'F', b
171
+ end
172
+
173
+ def flagged?
174
+ get_status 'F'
175
+ end
176
+
177
+ private
178
+
179
+ def procinfostr( str, tag, true_p )
180
+ a = str.upcase.split(//)
181
+ a.push true_p ? tag : nil
182
+ a.delete tag unless true_p
183
+ a.compact.sort.join('').squeeze
184
+ end
185
+
186
+ end
187
+
188
+
189
+ class MhPort < FilePort
190
+
191
+ include MailFlags
192
+
193
+ private
194
+
195
+ def set_status( tag, flag )
196
+ begin
197
+ tmpfile = @filename + '.tmailtmp.' + $$.to_s
198
+ File.open(tmpfile, 'w') {|f|
199
+ write_status f, tag, flag
200
+ }
201
+ File.unlink @filename
202
+ File.link tmpfile, @filename
203
+ ensure
204
+ File.unlink tmpfile
205
+ end
206
+ end
207
+
208
+ def write_status( f, tag, flag )
209
+ stat = ''
210
+ File.open(@filename) {|r|
211
+ while line = r.gets
212
+ if line.strip.empty?
213
+ break
214
+ elsif m = /\AX-TMail-Status:/i.match(line)
215
+ stat = m.post_match.strip
216
+ else
217
+ f.print line
218
+ end
219
+ end
220
+
221
+ s = procinfostr(stat, tag, flag)
222
+ f.puts 'X-TMail-Status: ' + s unless s.empty?
223
+ f.puts
224
+
225
+ while s = r.read(2048)
226
+ f.write s
227
+ end
228
+ }
229
+ end
230
+
231
+ def get_status( tag )
232
+ File.foreach(@filename) {|line|
233
+ return false if line.strip.empty?
234
+ if m = /\AX-TMail-Status:/i.match(line)
235
+ return m.post_match.strip.include?(tag[0])
236
+ end
237
+ }
238
+ false
239
+ end
240
+
241
+ end
242
+
243
+
244
+ class MaildirPort < FilePort
245
+
246
+ def move_to_new
247
+ new = replace_dir(@filename, 'new')
248
+ File.rename @filename, new
249
+ @filename = new
250
+ end
251
+
252
+ def move_to_cur
253
+ new = replace_dir(@filename, 'cur')
254
+ File.rename @filename, new
255
+ @filename = new
256
+ end
257
+
258
+ def replace_dir( path, dir )
259
+ "#{File.dirname File.dirname(path)}/#{dir}/#{File.basename path}"
260
+ end
261
+ private :replace_dir
262
+
263
+
264
+ include MailFlags
265
+
266
+ private
267
+
268
+ MAIL_FILE = /\A(\d+\.[\d_]+\.[^:]+)(?:\:(\d),(\w+)?)?\z/
269
+
270
+ def set_status( tag, flag )
271
+ if m = MAIL_FILE.match(File.basename(@filename))
272
+ s, uniq, type, info, = m.to_a
273
+ return if type and type != '2' # do not change anything
274
+ newname = File.dirname(@filename) + '/' +
275
+ uniq + ':2,' + procinfostr(info.to_s, tag, flag)
276
+ else
277
+ newname = @filename + ':2,' + tag
278
+ end
279
+
280
+ File.link @filename, newname
281
+ File.unlink @filename
282
+ @filename = newname
283
+ end
284
+
285
+ def get_status( tag )
286
+ m = MAIL_FILE.match(File.basename(@filename)) or return false
287
+ m[2] == '2' and m[3].to_s.include?(tag[0])
288
+ end
289
+
290
+ end
291
+
292
+
293
+ ###
294
+ ### StringPort
295
+ ###
296
+
297
+ class StringPort < Port
298
+
299
+ def initialize( str = '' )
300
+ @buffer = str
301
+ super()
302
+ end
303
+
304
+ def string
305
+ @buffer
306
+ end
307
+
308
+ def to_s
309
+ @buffer.dup
310
+ end
311
+
312
+ alias read_all to_s
313
+
314
+ def size
315
+ @buffer.size
316
+ end
317
+
318
+ def ==( other )
319
+ StringPort === other and @buffer.equal? other.string
320
+ end
321
+
322
+ alias eql? ==
323
+
324
+ def hash
325
+ @buffer.object_id.hash
326
+ end
327
+
328
+ def inspect
329
+ "#<#{self.class}:id=#{sprintf '0x%x', @buffer.object_id}>"
330
+ end
331
+
332
+ def reproducible?
333
+ true
334
+ end
335
+
336
+ def ropen( &block )
337
+ @buffer or raise Errno::ENOENT, "#{inspect} is already removed"
338
+ StringInput.open(@buffer, &block)
339
+ end
340
+
341
+ def wopen( &block )
342
+ @buffer = ''
343
+ StringOutput.new(@buffer, &block)
344
+ end
345
+
346
+ def aopen( &block )
347
+ @buffer ||= ''
348
+ StringOutput.new(@buffer, &block)
349
+ end
350
+
351
+ def remove
352
+ @buffer = nil
353
+ end
354
+
355
+ alias rm remove
356
+
357
+ def copy_to( port )
358
+ port.wopen {|f|
359
+ f.write @buffer
360
+ }
361
+ end
362
+
363
+ alias cp copy_to
364
+
365
+ def move_to( port )
366
+ if StringPort === port
367
+ str = @buffer
368
+ port.instance_eval { @buffer = str }
369
+ else
370
+ copy_to port
371
+ end
372
+ remove
373
+ end
374
+
375
+ end
376
+
377
+ end # module TMail
@@ -0,0 +1,131 @@
1
+ module TMail
2
+ class Mail
3
+ def subject(to_charset = 'utf-8')
4
+ Unquoter.unquote_and_convert_to(quoted_subject, to_charset)
5
+ end
6
+
7
+ def unquoted_body(to_charset = 'utf-8')
8
+ from_charset = sub_header("content-type", "charset")
9
+ case (content_transfer_encoding || "7bit").downcase
10
+ when "quoted-printable"
11
+ Unquoter.unquote_quoted_printable_and_convert_to(quoted_body,
12
+ to_charset, from_charset, true)
13
+ when "base64"
14
+ Unquoter.unquote_base64_and_convert_to(quoted_body, to_charset,
15
+ from_charset)
16
+ when "7bit", "8bit"
17
+ Unquoter.convert_to(quoted_body, to_charset, from_charset)
18
+ when "binary"
19
+ quoted_body
20
+ else
21
+ quoted_body
22
+ end
23
+ end
24
+
25
+ def body(to_charset = 'utf-8', &block)
26
+ attachment_presenter = block || Proc.new { |file_name| "Attachment: #{file_name}\n" }
27
+
28
+ if multipart?
29
+ parts.collect { |part|
30
+ header = part["content-type"]
31
+
32
+ if part.multipart?
33
+ part.body(to_charset, &attachment_presenter)
34
+ elsif header.nil?
35
+ ""
36
+ elsif !attachment?(part)
37
+ part.unquoted_body(to_charset)
38
+ else
39
+ attachment_presenter.call(header["name"] || "(unnamed)")
40
+ end
41
+ }.join
42
+ else
43
+ unquoted_body(to_charset)
44
+ end
45
+ end
46
+ end
47
+
48
+ class Unquoter
49
+ class << self
50
+ def unquote_and_convert_to(text, to_charset, from_charset = "iso-8859-1", preserve_underscores=false)
51
+ return "" if text.nil?
52
+ text.gsub(/(.*?)(?:(?:=\?(.*?)\?(.)\?(.*?)\?=)|$)/) do
53
+ before = $1
54
+ from_charset = $2
55
+ quoting_method = $3
56
+ text = $4
57
+
58
+ before = convert_to(before, to_charset, from_charset) if before.length > 0
59
+ before + case quoting_method
60
+ when "q", "Q" then
61
+ unquote_quoted_printable_and_convert_to(text, to_charset, from_charset, preserve_underscores)
62
+ when "b", "B" then
63
+ unquote_base64_and_convert_to(text, to_charset, from_charset)
64
+ when nil then
65
+ # will be nil at the end of the string, due to the nature of
66
+ # the regex used.
67
+ ""
68
+ else
69
+ raise "unknown quoting method #{quoting_method.inspect}"
70
+ end
71
+ end
72
+ end
73
+
74
+ def unquote_quoted_printable_and_convert_to(text, to, from, preserve_underscores=false)
75
+ text = text.gsub(/_/, " ") unless preserve_underscores
76
+ text = text.gsub(/\r\n|\r/, "\n") # normalize newlines
77
+ convert_to(text.unpack("M*").first, to, from)
78
+ end
79
+
80
+ def unquote_base64_and_convert_to(text, to, from)
81
+ convert_to(Base64.decode(text).first, to, from)
82
+ end
83
+
84
+ begin
85
+ require 'iconv'
86
+ def convert_to(text, to, from)
87
+ return text unless to && from
88
+ text ? Iconv.iconv(to, from, text).first : ""
89
+ rescue Iconv::IllegalSequence, Iconv::InvalidEncoding, Errno::EINVAL
90
+ # the 'from' parameter specifies a charset other than what the text
91
+ # actually is...not much we can do in this case but just return the
92
+ # unconverted text.
93
+ #
94
+ # Ditto if either parameter represents an unknown charset, like
95
+ # X-UNKNOWN.
96
+ text
97
+ end
98
+ rescue LoadError
99
+ # Not providing quoting support
100
+ def convert_to(text, to, from)
101
+ warn "Action Mailer: iconv not loaded; ignoring conversion from #{from} to #{to} (#{__FILE__}:#{__LINE__})"
102
+ text
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end
108
+
109
+ if __FILE__ == $0
110
+ require 'test/unit'
111
+
112
+ class TC_Unquoter < Test::Unit::TestCase
113
+ def test_unquote_quoted_printable
114
+ a ="=?ISO-8859-1?Q?[166417]_Bekr=E6ftelse_fra_Rejsefeber?="
115
+ b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
116
+ assert_equal "[166417] Bekr\303\246ftelse fra Rejsefeber", b
117
+ end
118
+
119
+ def test_unquote_base64
120
+ a ="=?ISO-8859-1?B?WzE2NjQxN10gQmVrcuZmdGVsc2UgZnJhIFJlanNlZmViZXI=?="
121
+ b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
122
+ assert_equal "[166417] Bekr\303\246ftelse fra Rejsefeber", b
123
+ end
124
+
125
+ def test_unquote_without_charset
126
+ a ="[166417]_Bekr=E6ftelse_fra_Rejsefeber"
127
+ b = TMail::Unquoter.unquote_and_convert_to(a, 'utf-8')
128
+ assert_equal "[166417]_Bekr=E6ftelse_fra_Rejsefeber", b
129
+ end
130
+ end
131
+ end