mms2r 2.4.1 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (61) hide show
  1. data/.gitignore +1 -0
  2. data/History.txt +5 -0
  3. data/Manifest.txt +1 -1
  4. data/README.txt +12 -9
  5. data/Rakefile +11 -10
  6. data/conf/mobile.indosat.net.id.yml +1 -1
  7. data/conf/waw.plspictures.com.yml +1 -1
  8. data/lib/mail_ext.rb +37 -0
  9. data/lib/mms2r.rb +7 -5
  10. data/lib/mms2r/media.rb +29 -35
  11. data/lib/mms2r/media/sprint.rb +19 -19
  12. data/mms2r.gemspec +23 -17
  13. data/test/fixtures/att-blackberry-02.mail +5 -6
  14. data/test/fixtures/att-iphone-01.mail +3 -3
  15. data/test/fixtures/dobson-image-01.mail +3 -3
  16. data/test/fixtures/maroctelecom-france-mms-01.mail +4 -4
  17. data/test/fixtures/mycingular-image-01.mail +3 -3
  18. data/test/fixtures/nextel-image-02.mail +2 -2
  19. data/test/fixtures/orangepoland-text-01.mail +2 -1
  20. data/test/fixtures/orangepoland-text-02.mail +2 -1
  21. data/test/fixtures/pics.cingularme.com-image-01.mail +0 -1
  22. data/test/fixtures/sasktel-image-01.mail +4 -4
  23. data/test/fixtures/sprint-broken-image-01.mail +1 -1
  24. data/test/fixtures/sprint-text-01.mail +1 -1
  25. data/test/fixtures/tmobile-blackberry-02.mail +4 -4
  26. data/test/test_1nbox_net.rb +16 -19
  27. data/test/test_bell_canada.rb +8 -13
  28. data/test/test_bellsouth_net.rb +5 -10
  29. data/test/test_helper.rb +16 -11
  30. data/test/test_mediamessaging_o2_co_uk.rb +21 -17
  31. data/test/test_messaging_nextel_com.rb +18 -12
  32. data/test/test_messaging_sprintpcs_com.rb +4 -8
  33. data/test/test_mms2r_media.rb +153 -143
  34. data/test/test_mms_3ireland_ie.rb +4 -9
  35. data/test/test_mms_ae.rb +12 -12
  36. data/test/test_mms_alltel_com.rb +14 -15
  37. data/test/test_mms_att_net.rb +35 -27
  38. data/test/test_mms_dobson_net.rb +9 -11
  39. data/test/test_mms_luxgsm_lu.rb +23 -17
  40. data/test/test_mms_mobileiam_ma.rb +4 -10
  41. data/test/test_mms_mtn_co_za.rb +4 -9
  42. data/test/test_mms_mycricket_com.rb +9 -9
  43. data/test/test_mms_myhelio_com.rb +18 -14
  44. data/test/test_mms_netcom_no.rb +19 -17
  45. data/test/test_mms_o2online_de.rb +20 -18
  46. data/test/test_mms_three_co_uk.rb +14 -14
  47. data/test/test_mms_vodacom4me_co_za.rb +24 -24
  48. data/test/test_mobile_indosat_net_id.rb +6 -9
  49. data/test/test_msg_telus_com.rb +5 -10
  50. data/test/test_orangemms_net.rb +25 -17
  51. data/test/test_pm_sprint_com.rb +37 -22
  52. data/test/test_pxt_vodafone_net_nz.rb +7 -11
  53. data/test/test_rci_rogers_com.rb +3 -8
  54. data/test/test_sms_sasktel_com.rb +2 -7
  55. data/test/test_tmomail_net.rb +25 -23
  56. data/test/test_unicel_com.rb +8 -12
  57. data/test/test_vmpix_com.rb +14 -13
  58. data/test/test_vzwpix_com.rb +24 -14
  59. data/test/test_waw_plspictures_com.rb +2 -7
  60. metadata +77 -26
  61. data/lib/tmail_ext.rb +0 -22
data/.gitignore CHANGED
@@ -3,4 +3,5 @@ coverage/
3
3
  pkg/
4
4
  email.txt
5
5
  coverage.info
6
+ mkmf.log
6
7
  doc/
data/History.txt CHANGED
@@ -1,3 +1,8 @@
1
+ ### 3.0.0 / 2010-02-24 (General Crozier - Chairman of the Joint Chiefs of Staff)
2
+
3
+ * 1 new feature
4
+ * dependence upon Mail gem rather than TMail gem
5
+
1
6
  ### 2.4.1 / 2010-02-07 (Vater Orlaag - political and spiritual specialist)
2
7
 
3
8
  * 3 minor enhancements
data/Manifest.txt CHANGED
@@ -44,7 +44,7 @@ init.rb
44
44
  lib/mms2r.rb
45
45
  lib/mms2r/media.rb
46
46
  lib/mms2r/media/sprint.rb
47
- lib/tmail_ext.rb
47
+ lib/mail_ext.rb
48
48
  mms2r.gemspec
49
49
  test/fixtures/1nbox-2images-01.mail
50
50
  test/fixtures/1nbox-2images-02.mail
data/README.txt CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  http://mms2r.rubyforge.org/
4
4
  by Mike Mondragon
5
- http://rubyforge.org/tracker/?group_id=3065
6
5
  http://github.com/monde/mms2r
6
+ http://github.com/monde/mms2r/issues
7
7
  http://peepcode.com/products/mms2r-pdf
8
8
 
9
9
  == DESCRIPTION
@@ -60,6 +60,12 @@ Corpus of carriers currently processed by MMS2R:
60
60
  * Virgin Mobile of Canada: vmobile.ca
61
61
  * Vodacom: mms.vodacom4me.co.za
62
62
 
63
+ Corpus of smart phones known to MMS2R:
64
+ * Blackberry variants
65
+ * Droid variants
66
+ * HTC variants (T-Mobile Dash, Sprint HERO)
67
+ * Apple iPhone variants
68
+
63
69
  == FEATURES
64
70
 
65
71
  * #default_media and #default_text methods return a File that can be used in
@@ -67,8 +73,8 @@ Corpus of carriers currently processed by MMS2R:
67
73
  * #process supports blocks to for enumerating over the content of the MMS
68
74
  * #process can be made lazy when :process => :lazy is passed to new
69
75
  * logging is enabled when :logger => your_logger is passed to new
70
- * an mms instance acts like a tmail object, any methods not defined on the
71
- instance are delegated to its underlying tmail object
76
+ * an mms instance acts like a Mail object, any methods not defined on the
77
+ instance are delegated to its underlying Mail object
72
78
  * #device_type? returns a symbol representing a device or smartphone type
73
79
  Known smartphones thus far: iPhone, BlackBerry, T-Mobile Dash, Droid
74
80
 
@@ -83,12 +89,9 @@ http://peepcode.com/products/mms2r-pdf
83
89
  require 'mms2r'
84
90
 
85
91
  # required for the example
86
- require 'tmail'
87
92
  require 'fileutils'
88
93
 
89
- mail = MMS2R.parse mail
90
- # mail = MMS2R.parse File.read('some_saved_mail.file')
91
-
94
+ mail = MMS2R.new(Mail.read('some_saved_mail.file'))
92
95
  puts "mail has default carrier subject" if mail.subject.empty?
93
96
 
94
97
  # access the sender's phone number
@@ -119,7 +122,7 @@ http://peepcode.com/products/mms2r-pdf
119
122
 
120
123
  puts "does the mail have quicktime video? #{!mail.media['video/quicktime'].nil?}"
121
124
 
122
- puts "plus run anything that TMail provides, e.g. #{mail.to.inspect}"
125
+ puts "plus run anything that Mail provides, e.g. #{mail.to.inspect}"
123
126
 
124
127
  # check if the mail is from a mobile phone
125
128
  puts "mail is from a mobile phone #{mail.is_mobile?}"
@@ -149,7 +152,7 @@ http://peepcode.com/products/mms2r-pdf
149
152
 
150
153
  == REQUIREMENTS
151
154
 
152
- * TMail
155
+ * Mail
153
156
  * Nokogiri (for mms from Sprint)
154
157
  * UUIDTools
155
158
 
data/Rakefile CHANGED
@@ -11,17 +11,18 @@ end
11
11
  $LOAD_PATH.unshift File.join(File.dirname(__FILE__), "lib")
12
12
  require 'mms2r'
13
13
 
14
- Hoe.new('mms2r', MMS2R::Media::VERSION) do |p|
14
+ Hoe.spec('mms2r') do |p|
15
+ p.version = MMS2R::Media::VERSION
15
16
  p.rubyforge_name = 'mms2r'
16
- p.author = ['Mike Mondragon']
17
- p.email = ['mikemondragon@gmail.com']
18
- p.summary = 'Extract user media from MMS (and not carrier cruft)'
19
- p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
20
- p.url = p.paragraphs_of('README.txt', 1).first.strip
21
- p.changes = p.paragraphs_of('History.txt', 0..2).join("\n\n")
22
- p.extra_deps << ['nokogiri']
23
- p.extra_deps << ['tmail']
24
- p.extra_deps << ['uuidtools']
17
+ p.author = ['Mike Mondragon']
18
+ p.email = ['mikemondragon@gmail.com']
19
+ p.summary = 'Extract user media from MMS (and not carrier cruft)'
20
+ p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
21
+ p.url = p.paragraphs_of('README.txt', 1).first.strip
22
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
23
+ p.extra_deps << ['nokogiri', '>= 1.4.0']
24
+ p.extra_deps << ['mail', '>= 2.1.0']
25
+ p.extra_deps << ['uuidtools', '>= 2.1.0']
25
26
  p.clean_globs << 'coverage'
26
27
  end
27
28
 
@@ -9,6 +9,6 @@ ignore:
9
9
  - cp__newBanner.jpg
10
10
  number:
11
11
  - return-path
12
- - /^<([^@]+)@.*/
12
+ - /^([^@]+)@.*/
13
13
  - "\1"
14
14
 
@@ -5,7 +5,7 @@ transform:
5
5
  - ""
6
6
  number:
7
7
  - return-path
8
- - /^<([^@]+)@.*/
8
+ - /^([^@]+)@.*/
9
9
  - "\1"
10
10
  ignore:
11
11
  text/html:
data/lib/mail_ext.rb ADDED
@@ -0,0 +1,37 @@
1
+ #--
2
+ # Copyright (c) 2010 by Mike Mondragon (mikemondragon@gmail.com)
3
+ #
4
+ # Please see the LICENSE file for licensing information.
5
+ #++
6
+
7
+ class Mail::Message
8
+
9
+ ##
10
+ # Generically determines the mime-type of a message used in mms2r processing.
11
+ # Guarantees a type is returned.
12
+
13
+ def part_type?
14
+ if self.content_type
15
+ self.content_type.split(';').first.downcase
16
+ else
17
+ 'text/plain'
18
+ end
19
+ end
20
+
21
+ ##
22
+ # override #filename to account for the true filename in the content_type
23
+ # returns foo.jpg #content_type is 'image/jpeg; filename="foo.jpg"; name="foo.jpg"'
24
+ # returns foo.jpg #content_type is 'image/jpeg;Name=foo.jpg'
25
+
26
+ def filename
27
+ if self.content_type && names = Hash[self.content_type.split(';').map{|t| t.strip.split('=')}]
28
+ if name = names.detect{|key,val| key.downcase == 'filename'} || names.detect{|key,val| key.downcase == 'name'}
29
+ return (name.last.match(/^"?(.+?)"?$/))[1]
30
+ end
31
+ end
32
+
33
+ find_attachment
34
+ end
35
+
36
+
37
+ end
data/lib/mms2r.rb CHANGED
@@ -39,29 +39,31 @@ module MMS2R
39
39
  ##
40
40
  # MMS2R library version
41
41
 
42
- VERSION = '2.4.1'
42
+ VERSION = '3.0.0'
43
43
 
44
44
  end
45
45
 
46
46
  # Simple convenience function to make it a one-liner:
47
47
  # MMS2R.parse raw_mail or MMS2R.parse File.load(raw_mail)
48
- # Combined w/ the method_missing delegation, this should behave as an enhanced TMail object, more or less.
48
+ # Combined w/ the method_missing delegation, this should behave as an enhanced Mail object, more or less.
49
49
  def self.parse raw_mail
50
- mail = TMail::Mail.parse raw_mail
50
+ mail = Mail.new raw_mail
51
51
  MMS2R::Media.new(mail)
52
52
  end
53
53
 
54
54
  end
55
55
 
56
56
  require 'rubygems'
57
- require 'tmail/mail'
57
+ require 'mail'
58
+ gem 'mail', '>= 2.1.2'
58
59
  require 'fileutils'
59
60
  require 'pathname'
60
61
  require 'tmpdir'
61
62
  require 'yaml'
62
63
  require 'uuidtools'
64
+ require 'iconv'
63
65
 
64
- require File.join(File.dirname(__FILE__), 'tmail_ext')
66
+ require File.join(File.dirname(__FILE__), 'mail_ext')
65
67
  require File.join(File.dirname(__FILE__), 'mms2r', 'media')
66
68
  require File.join(File.dirname(__FILE__), 'mms2r', 'media', 'sprint')
67
69
  MMS2R.register('pm.sprint.com', MMS2R::Media::Sprint)
data/lib/mms2r/media.rb CHANGED
@@ -23,7 +23,7 @@
23
23
  #
24
24
  # require 'rubygems'
25
25
  # require 'mms2r'
26
- # mail = TMail::Mail.parse(IO.readlines("sample-MMS.file").join)
26
+ # mail = Mail.read("sample-MMS.file")
27
27
  # mms = MMS2R::Media.new(mail)
28
28
  # subject = mms.subject
29
29
  # number = mms.number
@@ -114,14 +114,14 @@ module MMS2R
114
114
  end
115
115
  end
116
116
 
117
- # Pass off everything we don't do to the TMail object
117
+ # Pass off everything we don't do to the Mail object
118
118
  # TODO: refactor to explicit addition a la http://blog.jayfields.com/2008/02/ruby-replace-methodmissing-with-dynamic.html
119
119
  def method_missing method, *args, &block
120
120
  mail.send method, *args, &block
121
121
  end
122
122
 
123
123
  ##
124
- # TMail object that the media files were derived from.
124
+ # Mail object that the media files were derived from.
125
125
 
126
126
  attr_reader :mail
127
127
 
@@ -143,14 +143,9 @@ module MMS2R
143
143
 
144
144
  attr_reader :media_dir
145
145
 
146
- ##
147
- # Various multi-parts that are bundled into mail
148
-
149
- MULTIPARTS_TO_SPLIT = [ 'multipart/related', 'multipart/alternative', 'multipart/mixed', 'multipart/appledouble' ]
150
-
151
146
  ##
152
147
  # Factory method that creates MMS2R::Media products based on the domain
153
- # name of the carrier from which the MMS originated. mail is a TMail
148
+ # name of the carrier from which the MMS originated. mail is a Mail
154
149
  # object.
155
150
 
156
151
  def self.create(mail)
@@ -171,9 +166,8 @@ module MMS2R
171
166
 
172
167
  def self.domain(mail)
173
168
  return_path = case
174
- when mail.header['return-path']
175
- matched = /^<.+@([^@]+)>$/.match(mail.header['return-path'].to_s.strip)
176
- matched ? matched[1] : ''
169
+ when mail.return_path
170
+ mail.return_path ? mail.return_path.split('@').last : ''
177
171
  else
178
172
  ''
179
173
  end
@@ -248,11 +242,15 @@ module MMS2R
248
242
  def number
249
243
  unless @number
250
244
  params = config['number']
251
- if params && (header = mail.header[params[0]])
245
+ if params && params.any? && (header = mail.header[params[0]])
252
246
  @number = header.to_s.gsub(eval(params[1]), params[2])
253
247
  end
248
+ if @number.nil? || @number.blank?
249
+ @number = mail.from.first.split(/@|\//).first rescue ""
250
+ end
254
251
  end
255
- @number ||= mail.from.first.split('@').first rescue ""
252
+
253
+ @number
256
254
  end
257
255
 
258
256
  ##
@@ -344,7 +342,7 @@ module MMS2R
344
342
  for i in 1..2
345
343
  flat = []
346
344
  parts.each do |p|
347
- if MULTIPARTS_TO_SPLIT.include?(p.part_type?)
345
+ if p.multipart?
348
346
  p.parts.each {|mp| flat << mp }
349
347
  else
350
348
  flat << p
@@ -380,12 +378,12 @@ module MMS2R
380
378
  # true for media such as images that are advertising, carrier logos, etc.
381
379
  # See the ignore section in the discussion of the built-in configuration.
382
380
 
383
- def ignore_media?(type,part)
381
+ def ignore_media?(type, part)
384
382
  ignores = config['ignore'][type] || []
385
- ignore = ignores.detect{|test| filename?(part) == test}
386
- ignore ||= ignores.detect{|test| filename?(part) =~ eval(test) if test.index('/') == 0 }
387
- ignore ||= ignores.detect{|test| part.body.strip =~ eval(test) if test.index('/') == 0 }
388
- ignore ||= (part.body.strip.size == 0 ? true : nil)
383
+ ignore = ignores.detect{ |test| filename?(part) == test}
384
+ ignore ||= ignores.detect{ |test| filename?(part) =~ eval(test) if test.index('/') == 0 }
385
+ ignore ||= ignores.detect{ |test| part.body.decoded.strip =~ eval(test) if test.index('/') == 0 }
386
+ ignore ||= (part.body.decoded.strip.size == 0 ? true : nil)
389
387
  ignore.nil? ? false : true
390
388
  end
391
389
 
@@ -402,20 +400,20 @@ module MMS2R
402
400
  # Returns a tuple of content type, file path
403
401
 
404
402
  def process_media(part)
405
- # TMail body auto-magically decodes quoted
403
+ # Mail body auto-magically decodes quoted
406
404
  # printable for text/html type.
407
405
  file = temp_file(part)
408
- if part.main_type('text') == 'text' ||
409
- part.content_type == 'application/smil'
406
+ if part.part_type? =~ /^text\// ||
407
+ part.part_type? == 'application/smil'
410
408
  type, content = transform_text_part(part)
411
409
  mode = 'w'
412
410
  else
413
- if part.content_type == 'application/octet-stream'
411
+ if part.part_type? == 'application/octet-stream'
414
412
  type = type_from_filename(filename?(part))
415
413
  else
416
- type = part.content_type
414
+ type = part.part_type?
417
415
  end
418
- content = part.body
416
+ content = part.body.decoded
419
417
  mode = 'wb' # open with binary bit for Windows for non text
420
418
  end
421
419
  return type, nil if content.nil? || content.empty?
@@ -456,7 +454,7 @@ module MMS2R
456
454
 
457
455
  def transform_text_part(part)
458
456
  type = part.part_type?
459
- text = part.body.strip
457
+ text = part.body.decoded.strip
460
458
  transform_text(type, text)
461
459
  end
462
460
 
@@ -506,11 +504,9 @@ module MMS2R
506
504
  # returns a filename declared for a part, or a default if its not defined
507
505
 
508
506
  def filename?(part)
509
- name = part.sub_header("content-type", "name") ||
510
- part.sub_header("content-disposition", "filename") ||
511
- (part['content-location'] && part['content-location'].to_s.strip)
507
+ name = part.filename
512
508
  if (name.nil? || name.empty?)
513
- if part['content-id'] && part['content-id'].real_body.strip =~ /^<(.+)>$/
509
+ if part.content_id && part.content_id.strip =~ /^<(.+)>$/
514
510
  name = $1
515
511
  else
516
512
  name = "#{Time.now.to_f}.#{self.default_ext(part.part_type?)}"
@@ -570,11 +566,9 @@ module MMS2R
570
566
  headers.keys.each do |header|
571
567
  if mail.header[header.downcase]
572
568
  # headers[header] refers to a hash of smart phone types with regex values
573
- # that if they match the header signals the type should be returned
569
+ # that if they match, the header signals the type should be returned
574
570
  headers[header].each do |type, regex|
575
- # HACK to get at the full value of the header before TMail parses according to spec
576
- # see @body in and ensure_parsed in lib/tmail/header.rb
577
- return type if mail.header[header.downcase].instance_variable_get(:@body) =~ regex
571
+ return type if mail.header[header.downcase].decoded =~ regex
578
572
  end
579
573
  end
580
574
  end
@@ -15,12 +15,12 @@ module MMS2R
15
15
  ##
16
16
  # Sprint version of MMS2R::Media
17
17
  #
18
- # Sprint is an annoying carrier because they don't actually transmit user
19
- # generated content (like images or videos) directly in the MMS message.
20
- # Instead, they hijack the media that is sent from the cellular subscriber
21
- # and place that content on a content server. In place of the media
22
- # the recipient receives a HTML message with unsolicited Sprint
23
- # advertising and links back to their content server. The recipient has
18
+ # Sprint is an annoying carrier because they don't actually transmit user
19
+ # generated content (like images or videos) directly in the MMS message.
20
+ # Instead, they hijack the media that is sent from the cellular subscriber
21
+ # and place that content on a content server. In place of the media
22
+ # the recipient receives a HTML message with unsolicited Sprint
23
+ # advertising and links back to their content server. The recipient has
24
24
  # to click through Sprint more pages to view the content.
25
25
  #
26
26
  # The default subject on these messages from the
@@ -29,11 +29,11 @@ module MMS2R
29
29
  class Sprint < MMS2R::Media
30
30
 
31
31
  ##
32
- # Override process() because Sprint doesn't attach media (images, video,
33
- # etc.) to its MMS. Media such as images and videos are hosted on a
34
- # Sprint content server. MMS2R::Media::Sprint has to pick apart an
35
- # HTML attachment to find the URL to the media on Sprint's content
36
- # server and download each piece of content. Any text message part of
32
+ # Override process() because Sprint doesn't attach media (images, video,
33
+ # etc.) to its MMS. Media such as images and videos are hosted on a
34
+ # Sprint content server. MMS2R::Media::Sprint has to pick apart an
35
+ # HTML attachment to find the URL to the media on Sprint's content
36
+ # server and download each piece of content. Any text message part of
37
37
  # the MMS if it exists is embedded in the html.
38
38
 
39
39
  def process
@@ -46,21 +46,21 @@ module MMS2R
46
46
  doc = nil
47
47
  parts.each do |p|
48
48
  next unless p.part_type? == 'text/html'
49
- d = Nokogiri(p.body)
49
+ d = Nokogiri(p.body.decoded)
50
50
  title = d.at('title').inner_html
51
51
  if title =~ /You have new Picture Mail!/
52
52
  doc = d
53
- @is_video = (p.body =~ /type=&quot;VIDEO&quot;&gt;/m ? true : false)
53
+ @is_video = (p.body.decoded =~ /type=&quot;VIDEO&quot;&gt;/m ? true : false)
54
54
  end
55
55
  end
56
56
  return if doc.nil? # it was a dud
57
57
  @is_video ||= false
58
-
58
+
59
59
  # break it down
60
60
  sprint_phone_number(doc)
61
61
  sprint_process_text(doc)
62
62
  sprint_process_media(doc)
63
-
63
+
64
64
  @was_processed = true
65
65
  end
66
66
 
@@ -90,8 +90,8 @@ module MMS2R
90
90
 
91
91
  def sprint_process_text(doc)
92
92
  # there is at least one <pre> with MMS text if text has been included by
93
- # the user. (note) we'll have to verify that if they attach multiple texts
94
- # to the MMS then Sprint stacks it up in multiple <pre>'s. The only <pre>
93
+ # the user. (note) we'll have to verify that if they attach multiple texts
94
+ # to the MMS then Sprint stacks it up in multiple <pre>'s. The only <pre>
95
95
  # tag in the document is for text from the user.
96
96
  doc.search("/html/body//pre").each do |pre|
97
97
  type = 'text/plain'
@@ -110,7 +110,7 @@ module MMS2R
110
110
  srcs = Array.new
111
111
  # collect all the images in the document, even though
112
112
  # they are <img> tag some might actually refer to video.
113
- # To know the link refers to vide one must look at the
113
+ # To know the link refers to vide one must look at the
114
114
  # content type on the http GET response.
115
115
  imgs = doc.search("/html/body//img")
116
116
  imgs.each do |i|
@@ -130,7 +130,7 @@ module MMS2R
130
130
  cnt = 0
131
131
  srcs.each do |src|
132
132
  begin
133
-
133
+
134
134
  url = URI.parse(CGI.unescapeHTML(src))
135
135
  unless @is_video
136
136
  query={}