mms2r 2.2.0 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
1
  .DS_Store
2
2
  coverage/
3
3
  pkg/
4
+ email.txt
@@ -1,3 +1,24 @@
1
+ ### 2.3.0 / 2008-08-30 (Snakes 'n' Barrels Greatest Hits)
2
+ * 5 new features
3
+ * detect smartphone status/type based on model metadata from jpeg and tiff
4
+ exif data using exifr gem, access exif data with MMS2R::Media#exif
5
+ * make MMS2R Rails gem packaging friendly with an init.rb - Scott Taylor,
6
+ smtlaissezfaire
7
+ * delegate missing methods to mms2r's tmail object so that mms2r behaves as
8
+ if it were a tmail object - Sai Emrys, saizai
9
+ * default_media can return an attachment of application content type -
10
+ Brendan Lim, brendanlim
11
+ * MMS2R.parse(raw_mail) convenience class method that parses and returns an
12
+ mms2r from a mail file - saizai
13
+
14
+ * 4 minor enhancements
15
+ * make examples more 'mail' specific to enforce the fact that an mms is a
16
+ multipart email - saizai
17
+ * update for text in vzwpix.com default carrier message
18
+ * detecting smartphone (blackberries and iphones for now) is more versatile
19
+ from reading mail headers
20
+ * expanded filtering of carrier advertising text in mms from smartphones
21
+
1
22
  ### 2.2.0 / 2009-01-04 (Rikki Kixx - owner of a franchise of rehab centers)
2
23
 
3
24
  * 3 new features
@@ -40,6 +40,7 @@ conf/waw.plspictures.com.yml
40
40
  dev_tools/anonymizer.rb
41
41
  dev_tools/debug_sprint_hpricot_parsing.rb
42
42
  dev_tools/github.rb
43
+ init.rb
43
44
  lib/mms2r.rb
44
45
  lib/mms2r/media.rb
45
46
  lib/mms2r/media/sprint.rb
@@ -74,6 +75,7 @@ test/fixtures/iconv-fr-text-01.mail
74
75
  test/fixtures/indosat-image-01.mail
75
76
  test/fixtures/indosat-image-02.mail
76
77
  test/fixtures/info2go-image-01.mail
78
+ test/fixtures/iphone-image-01.mail
77
79
  test/fixtures/luxgsm-image-01.mail
78
80
  test/fixtures/maroctelecom-france-mms-01.mail
79
81
  test/fixtures/mediamessaging_o2_co_uk-image-01.mail
@@ -129,6 +131,7 @@ test/fixtures/vodacom4me-co-za-02.mail
129
131
  test/fixtures/vodacom4me-southafrica-mms-01.mail
130
132
  test/fixtures/vodacom4me-southafrica-mms-04.mail
131
133
  test/fixtures/vtext-text-01.mail
134
+ test/fixtures/vzwpix.com-image-01.mail
132
135
  test/fixtures/waw.plspictures.com-image-01.mail
133
136
  test/test_1nbox_net.rb
134
137
  test/test_bell_canada.rb
data/README.txt CHANGED
@@ -1,23 +1,23 @@
1
1
  = mms2r
2
2
 
3
+ http://mms2r.rubyforge.org/
3
4
  by Mike Mondragon
4
- http://mms2r.rubyforge.org/
5
- http://rubyforge.org/tracker/?group_id=3065
5
+ http://rubyforge.org/tracker/?group_id=3065
6
6
  http://github.com/monde/mms2r/tree/master
7
7
  http://peepcode.com/products/mms2r-pdf
8
8
 
9
9
  == DESCRIPTION
10
-
11
- MMS2R is a library that decodes the parts of an MMS message to disk while
12
- stripping out advertising injected by the mobile carriers. MMS messages are
10
+
11
+ MMS2R is a library that decodes the parts of an MMS message to disk while
12
+ stripping out advertising injected by the mobile carriers. MMS messages are
13
13
  multipart email and the carriers often inject branding into these messages. Use
14
14
  MMS2R if you want to get at the real user generated content from a MMS without
15
15
  having to deal with the cruft from the carriers.
16
16
 
17
- If MMS2R is not aware of a particular carrier no extra processing is done to the
17
+ If MMS2R is not aware of a particular carrier no extra processing is done to the
18
18
  MMS other than decoding and consolidating its media.
19
19
 
20
- Contact the author to add additional carriers to be processed by the library.
20
+ Contact the author to add additional carriers to be processed by the library.
21
21
  Suggestions and patches appreciated and welcomed!
22
22
 
23
23
  Corpus of carriers currently processed by MMS2R:
@@ -25,7 +25,7 @@ Corpus of carriers currently processed by MMS2R:
25
25
  * 1nbox/Idea: 1nbox.net
26
26
  * 3 Ireland: mms.3ireland.ie
27
27
  * Alltel: mms.alltel.com
28
- * AT&T/Cingular/Legacy: mms.att.net, txt.att.net, mmode.com, mms.mycingular.com,
28
+ * AT&T/Cingular/Legacy: mms.att.net, txt.att.net, mmode.com, mms.mycingular.com,
29
29
  cingularme.com, mobile.mycingular.com pics.cingularme.com
30
30
  * Bell Canada: txt.bell.ca
31
31
  * Bell South / Suncom: bellsouth.net
@@ -50,7 +50,7 @@ Corpus of carriers currently processed by MMS2R:
50
50
  * T-Mobile: tmomail.net, mmsreply.t-mobile.co.uk, tmo.blackberry.net
51
51
  * TELUS Corporation (Canada): mms.telusmobility.com, msg.telus.com
52
52
  * UAE MMS: mms.ae
53
- * Unicel: unicel.com, info2go.com
53
+ * Unicel: unicel.com, info2go.com
54
54
  (note: mobile number is tucked away in a text/plain part for unicel.com)
55
55
  * Verizon: vzwpix.com, vtext.com
56
56
  * Virgin Mobile: vmpix.com
@@ -59,8 +59,8 @@ Corpus of carriers currently processed by MMS2R:
59
59
 
60
60
  == FEATURES
61
61
 
62
- * #default_media and #default_text methods return a File that can be used in
63
- attachment_fu
62
+ * #default_media and #default_text methods return a File that can be used in
63
+ attachment_fu
64
64
  * #process supports blocks to for enumerating over the content of the MMS
65
65
  * #process can be made lazy when :process => :lazy is passed to new
66
66
  * logging is enabled when :logger => your_logger is passed to new
@@ -79,59 +79,75 @@ http://peepcode.com/products/mms2r-pdf
79
79
  require 'tmail'
80
80
  require 'fileutils'
81
81
 
82
- mail = TMail::Mail.parse(IO.readlines("sample-MMS.file").join)
83
- mms = MMS2R::Media.new(mail)
82
+ mail = MMS2R.parse mail
83
+ # mail = MMS2R.parse File.read('some_saved_mail.file')
84
84
 
85
- puts "MMS has default carrier subject" if mms.subject.empty?
85
+ puts "mail has default carrier subject" if mail.subject.empty?
86
86
 
87
87
  # access the sender's phone number
88
- puts "MMS was from phone #{mms.number}"
88
+ puts "mail was from phone #{mail.number}"
89
89
 
90
- # most MMS are either image or video, default_media will return the largest
90
+ # most mail are either image or video, default_media will return the largest
91
91
  # (non-advertising) video or image found
92
- file = mms.default_media
93
- puts "MMS had a media: #{file.inspect}" unless file.nil?
92
+ file = mail.default_media
93
+ puts "mail had a media: #{file.inspect}" unless file.nil?
94
94
 
95
95
  # finds the largest (non-advertising) text found
96
- file = mms.default_text
97
- puts "MMS had some text: #{file.inspect}" unless file.nil?
96
+ file = mail.default_text
97
+ puts "mail had some text: #{file.inspect}" unless file.nil?
98
98
 
99
- # mms.media is a hash that is indexed by mime-type.
99
+ # mail.media is a hash that is indexed by mime-type.
100
100
  # The mime-type key returns an array of filepaths
101
- # to media that were extract from the MMS and
101
+ # to media that were extract from the mail and
102
102
  # are of that type
103
- mms.media['image/jpeg'].each {|f| puts "#{f}"}
104
- mms.media['text/plain'].each {|f| puts "#{f}"}
103
+ mail.media['image/jpeg'].each {|f| puts "#{f}"}
104
+ mail.media['text/plain'].each {|f| puts "#{f}"}
105
105
 
106
- # print the text (assumes MMS had text)
107
- text = IO.readlines(mms.media['text/plain'].first).join
106
+ # print the text (assumes mail had text)
107
+ text = IO.readlines(mail.media['text/plain'].first).join
108
108
  puts text
109
109
 
110
- # save the image (assumes MMS had a jpeg)
111
- FileUtils.cp mms.media['image/jpeg'].first, '/some/where/useful', :verbose => true
110
+ # save the image (assumes mail had a jpeg)
111
+ FileUtils.cp mail.media['image/jpeg'].first, '/some/where/useful', :verbose => true
112
+
113
+ puts "does the mail have quicktime video? #{!mail.media['video/quicktime'].nil?}"
114
+
115
+ puts "plus run anything that TMail provides, e.g. #{mail.to.inspect}"
116
+
117
+ # check if the mail is from a mobile phone
118
+ puts "mail is from a mobile phone #{mail.is_mobile?}"
112
119
 
113
- puts "does the MMS have quicktime video? #{!mms.media['video/quicktime'].nil?}"
120
+ # inspect default media's exif data if exifr gem is installed and default
121
+ # media is a jpeg or tiff
122
+ puts "mail is from a mobile phone #{mail.is_mobile?}"
123
+ puts "mail's default media's exif data is:"
124
+ puts mms.exif.inspect
114
125
 
115
126
  # Block support, process and receive all media types of video.
116
- mms.process do |media_type, files|
127
+ mail.process do |media_type, files|
117
128
  # assumes a Clip model that is an AttachmentFu
118
129
  Clip.create(:uploaded_data => files.first, :title => "From phone") if media_type =~ /video/
119
130
  end
120
131
 
121
132
  # Another AttachmentFu example, Picture model is an AttachmentFu
122
133
  picture = Picture.new
123
- picture.title = mms.subject
124
- picture.uploaded_data = mms.default_media
134
+ picture.title = mail.subject
135
+ picture.uploaded_data = mail.default_media
125
136
  picture.save!
126
137
 
127
138
  #remove all the media that was put to temporary disk
128
- mms.purge
139
+ mail.purge
129
140
 
130
141
  == REQUIREMENTS
131
142
 
132
143
  * Hpricot
133
144
  * TMail
134
145
 
146
+ == OPTIONAL
147
+
148
+ * exifr - install exifr for exif access on default jpeg or tiff media, and
149
+ smart phone detection
150
+
135
151
  == INSTALL
136
152
 
137
153
  conventional
@@ -146,13 +162,6 @@ github
146
162
  git clone git://github.com/monde/mms2r.git
147
163
  svn co svn://rubyforge.org/var/svn/mms2r/trunk mms2r
148
164
 
149
- == CONTRIBUTE
150
-
151
- If you contribute a patch that is accepted then you'll get developer rights
152
- for the project on RubyForge. Please ensure your work includes 100% test
153
- converage. The library is ZenTest autotest discovery enabled so running
154
- autotest in the root of the project is very helpful during development.
155
-
156
165
  == AUTHORS
157
166
 
158
167
  Copyright (c) 2007-2008 by Mike Mondragon (blog[http://blog.mondragon.cc/])
@@ -174,6 +183,8 @@ MMS2R's Flickr page[http://www.flickr.com/photos/8627919@N05/]
174
183
  * Matt Conway
175
184
  * Kai Kai
176
185
  * Michael DelGaudio
186
+ * Sai Emrys (blog[http://saizai.com])
187
+ * Brendan Lim (github profile[http://github.com/brendanlim])
177
188
 
178
189
  == LICENSE
179
190
 
data/Rakefile CHANGED
@@ -16,11 +16,11 @@ Hoe.new('mms2r', MMS2R::Media::VERSION) do |p|
16
16
  p.author = 'Mike Mondragon'
17
17
  p.email = 'mikemondragon@gmail.com'
18
18
  p.summary = 'Extract user media from MMS (and not carrier cruft)'
19
- p.description = p.paragraphs_of('README.txt', 2..6).join("\n\n")
19
+ p.description = p.paragraphs_of('README.txt', 2..7).join("\n\n")
20
20
  p.url = p.paragraphs_of('README.txt', 1).first.strip
21
- p.changes = p.paragraphs_of('History.txt', 0..3).join("\n\n")
22
- p.extra_deps << ['hpricot', '>= 0.6.0']
23
- p.extra_deps << ['tmail', '>= 1.2.1']
21
+ p.changes = p.paragraphs_of('History.txt', 0..1).join("\n\n")
22
+ p.extra_deps << ['hpricot']
23
+ p.extra_deps << ['tmail']
24
24
  p.clean_globs << 'coverage'
25
25
  end
26
26
 
@@ -1,9 +1,13 @@
1
1
  ---
2
2
  ignore:
3
- text/plain:
4
- - /^\(no subject\)$/i
5
- multipart/mixed:
6
- - "/^Attachment: /i"
3
+ text/plain:
4
+ - /^\(no subject\)$/i
5
+ - /\ASent via BlackBerry (from|by) .*$/im
6
+ - /\ASent from my Verizon Wireless BlackBerry$/im
7
+ - /\ASent from (my|your) iPhone.?$/im
8
+ - /\ASent on the Sprint.* Now Network.*$/im
9
+ multipart/mixed:
10
+ - "/^Attachment: /i"
7
11
  transform:
8
12
  text/plain:
9
13
  - - /\A(.*?)Sent via BlackBerry (from|by) .*$/im
@@ -14,11 +18,14 @@ transform:
14
18
  - "\1"
15
19
  - - /\A(.*?)\s+image\/jpeg$/im
16
20
  - "\1"
21
+ - - /\A(.*?)Sent on the Sprint.* Now Network.*$/im
22
+ - "\1"
17
23
  device_types:
18
- headers:
19
- X-Mailer:
20
- - !ruby/regexp /^iPhone Mail/i
21
- - :iphone
22
- X-rim-org-msg-ref-id:
23
- - !ruby/regexp /.+/
24
- - :blackberry
24
+ headers:
25
+ x-mailer:
26
+ :iphone: !ruby/regexp /iPhone Mail/i
27
+ :blackberry: !ruby/regexp /Palm webOS/i
28
+ mime-version:
29
+ :iphone: !ruby/regexp /iPhone Mail/i
30
+ x-rim-org-msg-ref-id:
31
+ :blackberry: !ruby/regexp /.+/
@@ -1,8 +1,8 @@
1
1
  ---
2
2
  ignore:
3
3
  text/plain:
4
- - /\AThis message was sent using (the Picture and Video|PIX-FLIX) Messaging service from Verizon Wireless!.*/m
4
+ - /\AThis message was sent using .* from Verizon Wireless!.*/m
5
5
  transform:
6
6
  text/plain:
7
- - - /\A(.+?)\s+This message was sent using (the Picture and Video|PIX-FLIX) Messaging service from Verizon Wireless!.*/m
7
+ - - /\A(.+?)\s+This message was sent using .* from Verizon Wireless!.*/m
8
8
  - "\1"
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require File.dirname(__FILE__) + "/lib/mms2r"
@@ -1,5 +1,5 @@
1
1
  #--
2
- # Copyright (c) 2007, 2008 by Mike Mondragon (mikemondragon@gmail.com)
2
+ # Copyright (c) 2007-2010 by Mike Mondragon (mikemondragon@gmail.com)
3
3
  #
4
4
  # Please see the LICENSE file for licensing information.
5
5
  #++
@@ -39,14 +39,21 @@ module MMS2R
39
39
  ##
40
40
  # MMS2R library version
41
41
 
42
- VERSION = '2.2.0'
42
+ VERSION = '2.3.0'
43
43
 
44
44
  end
45
45
 
46
+ # Simple convenience function to make it a one-liner:
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.
49
+ def self.parse raw_mail
50
+ mail = TMail::Mail.parse raw_mail
51
+ MMS2R::Media.new(mail)
52
+ end
53
+
46
54
  end
47
55
 
48
56
  require 'rubygems'
49
- gem 'tmail', '>= 1.2.3'
50
57
  require 'tmail/mail'
51
58
  require 'fileutils'
52
59
  require 'pathname'
@@ -1,22 +1,22 @@
1
1
  #--
2
- # Copyright (c) 2007, 2008 by Mike Mondragon (mikemondragon@gmail.com)
2
+ # Copyright (c) 2007-2010 by Mike Mondragon (mikemondragon@gmail.com)
3
3
  #
4
- # Please see the LICENSE file for licensing information
4
+ # Please see the LICENSE file for licensing information.
5
5
  #++
6
6
 
7
7
  ##
8
8
  # = Synopsis
9
9
  #
10
- # MMS2R is a library to collect media files from MMS messages. MMS messages
11
- # are multipart emails and mobile carriers often inject branding into these
12
- # messages. MMS2R strips the advertising from an MMS leaving the actual user
10
+ # MMS2R is a library to collect media files from MMS messages. MMS messages
11
+ # are multipart emails and mobile carriers often inject branding into these
12
+ # messages. MMS2R strips the advertising from an MMS leaving the actual user
13
13
  # generated media.
14
14
  #
15
- # The Tracker for MMS2R is located at
15
+ # The Tracker for MMS2R is located at
16
16
  # http://rubyforge.org/tracker/?group_id=3065
17
17
  # Please submit bugs and feature requests using the Tracker.
18
18
  #
19
- # If MMS from a carrier not known by MMS2R is encountered please submit a
19
+ # If MMS from a carrier not known by MMS2R is encountered please submit a
20
20
  # sample to the author for inclusion in this project.
21
21
  #
22
22
  # == Stand Alone Example
@@ -48,31 +48,31 @@
48
48
  # == Built In Configuration
49
49
  #
50
50
  # A custom configuration can be created for processing the MMS from carriers
51
- # that are not currently known by MMS2R. In the conf/ directory create a
52
- # YAML file named by combining the domain name of the MMS sender plus a .yml
53
- # extension. For instance the configuration of senders from AT&T's cellular
54
- # service with a Sender pattern of 2065551212@mms.att.net have a configuration
51
+ # that are not currently known by MMS2R. In the conf/ directory create a
52
+ # YAML file named by combining the domain name of the MMS sender plus a .yml
53
+ # extension. For instance the configuration of senders from AT&T's cellular
54
+ # service with a Sender pattern of 2065551212@mms.att.net have a configuration
55
55
  # named conf/mms.att.net.yml
56
56
  #
57
57
  # The YAML configuration contains a Hash with instructions for determining what
58
58
  # is content generated by the user and what is content inserted by the carrier.
59
59
  #
60
- # The root hash itself has two hashes under the keys 'ignore' and 'transform',
60
+ # The root hash itself has two hashes under the keys 'ignore' and 'transform',
61
61
  # and an array under the 'number' key.
62
62
  # Each hash is itself keyed by mime-type. The value pointed to by the mime-type
63
- # key is an array. The ignore arrays are first evaluated as a regular expressions
63
+ # key is an array. The ignore arrays are first evaluated as a regular expressions
64
64
  # and if the evaluation fails as a equality for a string filename. Ignores
65
65
  # work by filename for the multi-part of the MMS that is being inspected. The
66
- # array pointed to by the 'number' key represents an alternate mail header where
67
- # the sender's number can be found with a regular expression and replacement
66
+ # array pointed to by the 'number' key represents an alternate mail header where
67
+ # the sender's number can be found with a regular expression and replacement
68
68
  # value for a gsub eval.
69
69
  #
70
70
  # The transform arrays are themselves an array of two element arrays. The elements
71
71
  # are parameters for gsub and will be evaluated from within the ruby code.
72
72
  #
73
- # Ignore instructions are honored first then transform instructions. In the sample,
74
- # masthead.jpg is ignored as a regular expression, and spacer.gif is ignored as a
75
- # filename comparison. The transform has a match and a replacement, see the gsub
73
+ # Ignore instructions are honored first then transform instructions. In the sample,
74
+ # masthead.jpg is ignored as a regular expression, and spacer.gif is ignored as a
75
+ # filename comparison. The transform has a match and a replacement, see the gsub
76
76
  # documentation for more information about match and replace.
77
77
  #
78
78
  # --
@@ -92,9 +92,9 @@
92
92
  # - /^([^\s]+)\s.*/
93
93
  # - "\1"
94
94
  #
95
- # Carriers often provide their services under many different domain names.
96
- # The conf/aliases.yml is a YAML file with a hash that maps alternative or
97
- # legacy carrier names to the most common name of their service. For example
95
+ # Carriers often provide their services under many different domain names.
96
+ # The conf/aliases.yml is a YAML file with a hash that maps alternative or
97
+ # legacy carrier names to the most common name of their service. For example
98
98
  # in terms of MMS2R txt.att.net is an alias for mms.att.net. Therefore when
99
99
  # an MMS with a Sender of txt.att.net is processed MMS2R will use the
100
100
  # mms.att.net configuration to process the message.
@@ -114,20 +114,26 @@ module MMS2R
114
114
  end
115
115
  end
116
116
 
117
+ # Pass off everything we don't do to the TMail object
118
+ # TODO: refactor to explicit addition a la http://blog.jayfields.com/2008/02/ruby-replace-methodmissing-with-dynamic.html
119
+ def method_missing method, *args, &block
120
+ mail.send method, *args, &block
121
+ end
122
+
117
123
  ##
118
124
  # TMail object that the media files were derived from.
119
125
 
120
126
  attr_reader :mail
121
127
 
122
128
  ##
123
- # media returns the hash of media. The media hash is keyed by mime-type
124
- # such as 'text/plain' and the value mapped to the key is an array of
129
+ # media returns the hash of media. The media hash is keyed by mime-type
130
+ # such as 'text/plain' and the value mapped to the key is an array of
125
131
  # media that are of that type.
126
132
 
127
133
  attr_reader :media
128
134
 
129
135
  ##
130
- # Carrier is the domain name of the carrier. If the carrier is not known
136
+ # Carrier is the domain name of the carrier. If the carrier is not known
131
137
  # the carrier will be set to 'mms2r.media'
132
138
 
133
139
  attr_reader :carrier
@@ -143,14 +149,14 @@ module MMS2R
143
149
  MULTIPARTS_TO_SPLIT = [ 'multipart/related', 'multipart/alternative', 'multipart/mixed', 'multipart/appledouble' ]
144
150
 
145
151
  ##
146
- # Factory method that creates MMS2R::Media products based on the domain
147
- # name of the carrier from which the MMS originated. mail is a TMail
152
+ # 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
154
  # object.
149
155
 
150
156
  def self.create(mail)
151
157
  d = lambda{ ['mms2r.media', MMS2R::Media] } #sets a default to detect
152
158
  from_domain = self.domain(mail)
153
- processor = MMS2R::CARRIERS.detect(d) do |domain, klass|
159
+ processor = MMS2R::CARRIERS.detect(d) do |domain, klass|
154
160
  return klass, domain if from_domain == domain
155
161
  end
156
162
  [MMS2R::Media, from_domain]
@@ -158,8 +164,8 @@ module MMS2R
158
164
 
159
165
  ##
160
166
  # Determine if return-path or from is going to be used to desiginate the
161
- # origin carrier. If the domain in the From header is listed in
162
- # conf/from.yaml then that is the carrier domain. Else if there is a
167
+ # origin carrier. If the domain in the From header is listed in
168
+ # conf/from.yaml then that is the carrier domain. Else if there is a
163
169
  # Return-Path header its address's domain is the carrier doamin, else
164
170
  # use From header's address domain.
165
171
 
@@ -211,7 +217,7 @@ module MMS2R
211
217
  log("#{self.class} created", :info)
212
218
  @carrier = opts[:domain]
213
219
  @dir_count = 0
214
- @media_dir = File.join(self.tmp_dir(),
220
+ @media_dir = File.join(self.tmp_dir(),
215
221
  self.safe_message_id(@mail.message_id))
216
222
  @media = {}
217
223
  @was_processed = false
@@ -220,7 +226,7 @@ module MMS2R
220
226
  @body = nil
221
227
  @default_media = nil
222
228
  @default_text = nil
223
-
229
+
224
230
  f = File.join(self.conf_dir(), "aliases.yml")
225
231
  @aliases = YAML::load_file(f) rescue {}
226
232
 
@@ -234,9 +240,9 @@ module MMS2R
234
240
  end
235
241
 
236
242
  ##
237
- # Get the phone number associated with this MMS if it exists. The value
238
- # returned is simplistic, it is just the user name of the from address
239
- # before the @ symbol. Validation of the number is left to you. Most
243
+ # Get the phone number associated with this MMS if it exists. The value
244
+ # returned is simplistic, it is just the user name of the from address
245
+ # before the @ symbol. Validation of the number is left to you. Most
240
246
  # carriers are using the real phone number as the username.
241
247
 
242
248
  def number
@@ -268,8 +274,8 @@ module MMS2R
268
274
  @subject
269
275
  end
270
276
 
271
- # Convenience method that returns a string including all the text of the
272
- # first text/plain file found. Returns empty string if no body text
277
+ # Convenience method that returns a string including all the text of the
278
+ # first text/plain file found. Returns empty string if no body text
273
279
  # is found.
274
280
 
275
281
  def body
@@ -279,22 +285,22 @@ module MMS2R
279
285
  end
280
286
 
281
287
  # Returns a File with the most likely candidate for the user-submitted
282
- # media. Given that most MMS messages only have one file attached, this
283
- # method will try to return that file. Singleton methods are added to
284
- # the File object so it can be used in place of a CGI upload (local_path,
288
+ # media. Given that most MMS messages only have one file attached, this
289
+ # method will try to return that file. Singleton methods are added to
290
+ # the File object so it can be used in place of a CGI upload (local_path,
285
291
  # original_filename, size, and content_type) such as in conjunction with
286
292
  # AttachementFu. The largest file found in terms of bytes is returned.
287
293
  #
288
294
  # Returns nil if there are not any video or image Files found.
289
295
 
290
296
  def default_media
291
- @default_media ||= attachment(['video', 'image', 'text'])
297
+ @default_media ||= attachment(['video', 'image', 'application', 'text'])
292
298
  end
293
299
 
294
300
  # Returns a File with the most likely candidate that is text, or nil
295
- # otherwise. It also adds singleton methods to the File object so it can be
296
- # used in place of a CGI upload (local_path, original_filename, size, and
297
- # content_type) such as in conjunction with AttachmentFu. The largest file
301
+ # otherwise. It also adds singleton methods to the File object so it can be
302
+ # used in place of a CGI upload (local_path, original_filename, size, and
303
+ # content_type) such as in conjunction with AttachmentFu. The largest file
298
304
  # found in terms of bytes is returned.
299
305
  #
300
306
  # Returns nil if there are not any text Files found
@@ -305,9 +311,9 @@ module MMS2R
305
311
 
306
312
  ##
307
313
  # process is a template method and collects all the media in a MMS.
308
- # Override helper methods to this template to clean out advertising and/or
309
- # ignore media that are advertising. This method should not be overridden
310
- # unless there is an extreme special case in processing the media of a MMS
314
+ # Override helper methods to this template to clean out advertising and/or
315
+ # ignore media that are advertising. This method should not be overridden
316
+ # unless there is an extreme special case in processing the media of a MMS
311
317
  # (like Sprint)
312
318
  #
313
319
  # Helper methods for the process template:
@@ -315,7 +321,7 @@ module MMS2R
315
321
  # * process_media -- retrieves media to temporary file, returns path to file.
316
322
  # * transform_text -- called by process_media, strips out advertising.
317
323
  # * temp_file -- creates a temporary filepath based on information from the part.
318
- #
324
+ #
319
325
  # Block support:
320
326
  # Call process() with a block to automatically iterate through media.
321
327
  # For example, to process and receive only media of video type:
@@ -329,11 +335,11 @@ module MMS2R
329
335
  def process() # :yields: media_type, file
330
336
  unless @was_processed
331
337
  log("#{self.class} processing", :info)
332
-
338
+
333
339
  parts = mail.multipart? ? mail.parts : [mail]
334
-
335
- # Double check for multipart/related, if it exists replace it with its
336
- # children parts. Do this twice as multipart/alternative can have
340
+
341
+ # Double check for multipart/related, if it exists replace it with its
342
+ # children parts. Do this twice as multipart/alternative can have
337
343
  # children and we want to fold everything down
338
344
  for i in 1..2
339
345
  flat = []
@@ -343,10 +349,10 @@ module MMS2R
343
349
  else
344
350
  flat << p
345
351
  end
346
- end
352
+ end
347
353
  parts = flat.dup
348
- end
349
-
354
+ end
355
+
350
356
  # get to work
351
357
  parts.each do |p|
352
358
  t = p.part_type?
@@ -369,8 +375,8 @@ module MMS2R
369
375
  end
370
376
 
371
377
  ##
372
- # Helper for process template method to determine if media contained in a
373
- # part should be ignored. Producers should override this method to return
378
+ # Helper for process template method to determine if media contained in a
379
+ # part should be ignored. Producers should override this method to return
374
380
  # true for media such as images that are advertising, carrier logos, etc.
375
381
  # See the ignore section in the discussion of the built-in configuration.
376
382
 
@@ -379,18 +385,18 @@ module MMS2R
379
385
  ignore = ignores.detect{|test| filename?(part) == test}
380
386
  ignore ||= ignores.detect{|test| filename?(part) =~ eval(test) if test.index('/') == 0 }
381
387
  ignore ||= ignores.detect{|test| part.body.strip =~ eval(test) if test.index('/') == 0 }
382
- ignore ||= (part.body.strip.size == 0 ? true : nil)
388
+ ignore ||= (part.body.strip.size == 0 ? true : nil)
383
389
  ignore.nil? ? false : true
384
390
  end
385
391
 
386
392
  ##
387
- # Helper for process template method to decode the part based on its type
388
- # and write its content to a temporary file. Returns path to temporary
389
- # file that holds the content. Parts with a main type of text will have
393
+ # Helper for process template method to decode the part based on its type
394
+ # and write its content to a temporary file. Returns path to temporary
395
+ # file that holds the content. Parts with a main type of text will have
390
396
  # their contents transformed with a call to transform_text
391
397
  #
392
- # Producers should only override this method if the parts of the MMS need
393
- # special treatment besides what is expected for a normal mime part (like
398
+ # Producers should only override this method if the parts of the MMS need
399
+ # special treatment besides what is expected for a normal mime part (like
394
400
  # Sprint).
395
401
  #
396
402
  # Returns a tuple of content type, file path
@@ -399,7 +405,7 @@ module MMS2R
399
405
  # TMail body auto-magically decodes quoted
400
406
  # printable for text/html type.
401
407
  file = temp_file(part)
402
- if part.main_type('text') == 'text' ||
408
+ if part.main_type('text') == 'text' ||
403
409
  part.content_type == 'application/smil'
404
410
  type, content = transform_text_part(part)
405
411
  mode = 'w'
@@ -421,11 +427,11 @@ module MMS2R
421
427
 
422
428
  ##
423
429
  # Helper for process_media template method to transform text.
424
- # See the transform section in the discussion of the built-in
430
+ # See the transform section in the discussion of the built-in
425
431
  # configuration.
426
432
 
427
433
  def transform_text(type, text, original_nencoding = 'ISO-8859-1')
428
- return type, text unless transforms = config['transform'][type]
434
+ return type, text unless transforms = config['transform'][type]
429
435
 
430
436
  #convert to UTF-8
431
437
  begin
@@ -441,7 +447,7 @@ module MMS2R
441
447
  r = transform.last
442
448
  utf_t = utf_t.gsub(eval(p), r) rescue utf_t
443
449
  end
444
-
450
+
445
451
  return type, utf_t
446
452
  end
447
453
 
@@ -455,12 +461,12 @@ module MMS2R
455
461
  end
456
462
 
457
463
  ##
458
- # Helper for process template method to name a temporary filepath based on
459
- # information in the part. This version attempts to honor the name of the
460
- # media as labeled in the part header and creates a unique temporary
464
+ # Helper for process template method to name a temporary filepath based on
465
+ # information in the part. This version attempts to honor the name of the
466
+ # media as labeled in the part header and creates a unique temporary
461
467
  # directory for writing the file so filename collision does not occur.
462
- # Consumers of this method expect the directory structure to the file
463
- # exists, if the method is overridden it is mandatory that this behavior is
468
+ # Consumers of this method expect the directory structure to the file
469
+ # exists, if the method is overridden it is mandatory that this behavior is
464
470
  # retained.
465
471
 
466
472
  def temp_file(part)
@@ -469,7 +475,7 @@ module MMS2R
469
475
  end
470
476
 
471
477
  ##
472
- # Purges the unique MMS2R::Media.media_dir directory created
478
+ # Purges the unique MMS2R::Media.media_dir directory created
473
479
  # for this producer and all of the media that it contains.
474
480
 
475
481
  def purge()
@@ -486,7 +492,7 @@ module MMS2R
486
492
  end
487
493
 
488
494
  ##
489
- # Helper to temp_file to create a unique temporary directory that is a
495
+ # Helper to temp_file to create a unique temporary directory that is a
490
496
  # child of tmp_dir This version is based on the message_id of the mail.
491
497
 
492
498
  def msg_tmp_dir()
@@ -519,7 +525,7 @@ module MMS2R
519
525
  base = File.basename(name, ext)
520
526
  name = "#{base[0, 255 - ext.size]}#{ext}"
521
527
  end
522
-
528
+
523
529
  name
524
530
  end
525
531
 
@@ -528,28 +534,76 @@ module MMS2R
528
534
  end
529
535
 
530
536
  ##
531
- # Best guess of the mobile device type. Simple heuristics thus far for
532
- # :iphone :blackberry :handset :unknown . Could be expanded for exif
537
+ # Best guess of the mobile device type. Simple heuristics thus far for
538
+ # :iphone :blackberry :handset :unknown . Could be expanded for exif
533
539
  # probing or shifting mail header schemes
534
540
 
535
541
  def device_type?
542
+ begin
543
+ # rely on native exif first with exifr gem if its loaded
544
+ require 'exifr'
545
+ file = attachment(['image'])
546
+ if file
547
+ original = file.original_filename
548
+ @exif = case original
549
+ when /\.jpg$/i
550
+ EXIFR::JPEG.new(file)
551
+ when /\.jepg$/i
552
+ EXIFR::JPEG.new(file)
553
+ when /\.tif$/i
554
+ EXIFR::TIFF.new(file)
555
+ when /\.tiff$/i
556
+ EXIFR::TIFF.new(file)
557
+ end
558
+ if @exif
559
+ # TODO do something about the assortment of camera models that have
560
+ # been seen:
561
+ # 1.3 Megapixel, 2.0 Megapixel, BlackBerry, CU920, G'z One TYPE-S,
562
+ # Hermes, iPhone, LG8700, LSI_S5K4AAFA, Micron MT9M113 1.3MP YUV,
563
+ # Motorola Phone, Omni_vision-9650, Pre,
564
+ # Seoul Electronics & Telecom SIM120B 1.3M, SGH-T729, SGH-T819,
565
+ # SPH-M540, SPH-M800, SYSTEMLSI S5K4BAFB 2.0 MP, VX-9700
566
+ case @exif.model
567
+ when/iPhone/i
568
+ return :iphone
569
+ when/BlackBerry/i
570
+ return :blackberry
571
+ end
572
+ end
573
+ end
574
+ rescue LoadError => err
575
+ end
576
+
536
577
  headers = config['device_types']['headers'] rescue {}
537
578
  headers.keys.each do |header|
538
579
  if mail.header[header.downcase]
539
- regex, type = headers[header]
540
- return type if mail.header[header.downcase].to_s =~ regex
580
+ # headers[header] refers to a hash of smart phone types with regex values
581
+ # that if they match the header signals the type should be returned
582
+ headers[header].each do |type, regex|
583
+ # HACK to get at the full value of the header before TMail parses according to spec
584
+ # see @body in and ensure_parsed in lib/tmail/header.rb
585
+ return type if mail.header[header.downcase].instance_variable_get(:@body) =~ regex
586
+ end
541
587
  end
542
588
  end
543
589
 
544
590
  return :handset if File.exist?(File.join(self.conf_dir,
545
591
  "#{self.aliases[self.carrier] || self.carrier}.yml"))
546
-
592
+
547
593
  :unknown
548
594
  end
549
595
 
596
+ ##
597
+ # exif object on default image from exifr gem
598
+
599
+ def exif
600
+ device_type? unless @exif
601
+ @exif
602
+ end
603
+
550
604
  ##
551
605
  # The source of the MMS was some sort of mobile or smart phone
552
-
606
+
553
607
  def is_mobile?
554
608
  self.device_type? != :unknown
555
609
  end
@@ -596,7 +650,7 @@ module MMS2R
596
650
  if MMS2R::EXT[content_type]
597
651
  MMS2R::EXT[content_type]
598
652
  elsif content_type
599
- content_type.split('/').last
653
+ content_type.split('/').last
600
654
  end
601
655
  end
602
656
 
@@ -633,7 +687,7 @@ module MMS2R
633
687
 
634
688
  ##
635
689
  # convenience accessor for self.class.conf_dir
636
-
690
+
637
691
  def conf_dir
638
692
  self.class.conf_dir
639
693
  end
@@ -654,14 +708,14 @@ module MMS2R
654
708
 
655
709
  ##
656
710
  # convenience accessor for self.class.safe_message_id
657
-
711
+
658
712
  def safe_message_id(message_id)
659
713
  self.class.safe_message_id(message_id)
660
714
  end
661
715
 
662
716
  ##
663
717
  # convenience accessor for self.class.initialize_confg
664
-
718
+
665
719
  def initialize_config(config)
666
720
  self.class.initialize_config(config)
667
721
  end
@@ -686,13 +740,13 @@ module MMS2R
686
740
 
687
741
  ##
688
742
  # used by #default_media and #text to return the biggest attachment type
689
- # listed in the types array
743
+ # listed in the types array
690
744
 
691
745
  def attachment(types)
692
746
 
693
747
  # get all the files that are of the major types passed in
694
748
  files = []
695
-
749
+
696
750
  types.each do |type|
697
751
  media.keys.find_all{|k| type.include?("/") ? k == type : k.index(type) == 0 }.each do |key|
698
752
  files += media[key]
@@ -710,7 +764,7 @@ module MMS2R
710
764
  if File.size(f) > size
711
765
  size = File.size(f)
712
766
  file = File.new(f)
713
- mime_type = media.detect{|type,files| files.detect{|fl| fl == f}}[0]
767
+ mime_type = media.detect{|type,files| files.detect{|fl| fl == f}}[0]
714
768
  end
715
769
  end
716
770