mms2r 1.0.7 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. data/History.txt +19 -1
  2. data/Manifest.txt +38 -19
  3. data/README.txt +40 -8
  4. data/Rakefile +2 -2
  5. data/conf/mms2r_cingular_me_media_subject.yml +3 -0
  6. data/conf/{mms2r_cingularmedia_transform.yml → mms2r_cingular_me_media_transform.yml} +1 -0
  7. data/conf/mms2r_dobson_media_ignore.yml +4 -0
  8. data/conf/mms2r_media_ignore.yml +4 -0
  9. data/conf/mms2r_media_subject.yml +3 -0
  10. data/conf/mms2r_my_cingular_media_subject.yml +3 -0
  11. data/conf/mms2r_nextel_media_ignore.yml +11 -0
  12. data/conf/mms2r_sprint_media_ignore.yml +5 -0
  13. data/conf/mms2r_sprint_media_subject.yml +3 -0
  14. data/conf/{mms2r_tmobilemedia_ignore.yml → mms2r_t_mobile_media_ignore.yml} +2 -5
  15. data/conf/mms2r_verizon_media_ignore.yml +4 -0
  16. data/conf/mms2r_verizon_media_transform.yml +6 -0
  17. data/dev_tools/debug_sprint_hpricot_parsing.rb +82 -0
  18. data/lib/mms2r.rb +61 -0
  19. data/lib/mms2r/cingular_me_media.rb +23 -0
  20. data/lib/mms2r/dobson_media.rb +4 -5
  21. data/lib/mms2r/{mmode_media.rb → m_mode_media.rb} +4 -4
  22. data/lib/mms2r/media.rb +283 -160
  23. data/lib/mms2r/my_cingular_media.rb +15 -0
  24. data/lib/mms2r/nextel_media.rb +9 -3
  25. data/lib/mms2r/sprint_media.rb +137 -29
  26. data/lib/mms2r/sprint_pcs_media.rb +16 -0
  27. data/lib/mms2r/t_mobile_media.rb +21 -0
  28. data/lib/mms2r/verizon_media.rb +11 -3
  29. data/lib/mms2r/vtext_media.rb +16 -0
  30. data/test/files/cingularme-text-02.mail +14 -0
  31. data/test/files/hello_world_empty_text.mail +6 -0
  32. data/test/files/hello_world_mail_multipart.mail +7 -0
  33. data/test/files/{cingular-image-01.mail → mycingular-image-01.mail} +0 -0
  34. data/test/files/simple-with-two-images-two-texts.mail +49 -0
  35. data/test/files/{sprint-image-02.mail → sprint-broken-image-01.mail} +1 -1
  36. data/test/files/sprint-image-01.mail +1 -1
  37. data/test/files/sprint-pcs-text-01.mail +8 -0
  38. data/test/files/sprint-text-01.mail +195 -8
  39. data/test/files/sprint-two-images-01.mail +198 -0
  40. data/test/files/sprint-video-01.mail +1 -1
  41. data/test/files/verizon-image-02.mail +1 -1
  42. data/test/files/vtext-text-01.mail +1 -1
  43. data/test/test_mms2r_cingular_me_media.rb +51 -0
  44. data/test/test_mms2r_dobson_media.rb +46 -0
  45. data/test/{test_mms2r_mmode.rb → test_mms2r_m_mode_media.rb} +1 -1
  46. data/test/test_mms2r_media.rb +160 -74
  47. data/test/test_mms2r_my_cingular_media.rb +31 -0
  48. data/test/test_mms2r_nextel_media.rb +100 -0
  49. data/test/test_mms2r_sprint_media.rb +221 -0
  50. data/test/test_mms2r_sprint_pcs_media.rb +27 -0
  51. data/test/{test_mms2r_tmobile.rb → test_mms2r_t_mobile_media.rb} +13 -13
  52. data/test/test_mms2r_verizon_media.rb +96 -0
  53. data/test/test_mms2r_vtext_media.rb +28 -0
  54. data/vendor/plugins/mms2r/lib/autotest/discover.rb +3 -0
  55. data/vendor/plugins/mms2r/lib/autotest/mms2r.rb +33 -0
  56. metadata +62 -37
  57. data/conf/mms2r_nextelmedia_ignore.yml +0 -10
  58. data/conf/mms2r_sprintmedia_ignore.yml +0 -10
  59. data/conf/mms2r_verizonmedia_ignore.yml +0 -3
  60. data/conf/mms2r_verizonmedia_transform.yml +0 -3
  61. data/lib/mms2r/cingular_media.rb +0 -11
  62. data/lib/mms2r/tmobile_media.rb +0 -11
  63. data/lib/mms2r/version.rb +0 -12
  64. data/test/test_mms2r_cingular.rb +0 -58
  65. data/test/test_mms2r_dobson.rb +0 -36
  66. data/test/test_mms2r_nextel.rb +0 -132
  67. data/test/test_mms2r_sprint.rb +0 -174
  68. data/test/test_mms2r_verizon.rb +0 -102
@@ -0,0 +1,23 @@
1
+ module MMS2R
2
+
3
+ ##
4
+ # Cingular Me version of MMS2R::Media
5
+ #
6
+ # The characteristics of Cingular Me is that its the
7
+ # MMS version of a SMS, essentially just a non-multipart
8
+ # (plain) email.
9
+ #
10
+ # The default Subject from the carrier these messages
11
+ # is just an empty string
12
+ #
13
+ # There is often a text footer in these messages:
14
+ #
15
+ # --
16
+ # ===============================================
17
+ # Brought to you by, Cingular Wireless Messaging
18
+ # http://www.CingularMe.COM/
19
+ #
20
+
21
+ class MMS2R::CingularMeMedia < MMS2R::Media
22
+ end
23
+ end
@@ -1,13 +1,12 @@
1
- require 'mms2r'
2
- require 'mms2r/media'
3
-
4
1
  module MMS2R
5
2
 
6
3
  ##
7
4
  # Dobson/Cellular One version version of MMS2R::Media
5
+ #
8
6
  # So far, Dobson MMS messages do not contain advertising
9
- # They do, however, have a weird SMIL file attachment. It
10
- # can be safely ignored.
7
+ # They do, however, have a SMIL part that gives markup
8
+ # structure to any user generated content the MMS may
9
+ # contain and can be safely ignored.
11
10
 
12
11
  class MMS2R::DobsonMedia < MMS2R::Media
13
12
  end
@@ -1,12 +1,12 @@
1
- require 'mms2r'
2
- require 'mms2r/media'
3
-
4
1
  module MMS2R
5
2
 
6
3
  ##
7
4
  # MMode version of MMS2R::Media
5
+ #
8
6
  # The only examples of MMode seen so far do not
9
- # contain advertising.
7
+ # contain advertising and the subject of the
8
+ # message is the file name of the media attached
9
+ # to the MMS.
10
10
 
11
11
  class MMS2R::MModeMedia < MMS2R::Media
12
12
  end
data/lib/mms2r/media.rb CHANGED
@@ -1,20 +1,13 @@
1
- # Copyright (c) 2007 by Mike Mondragon ()
1
+ #--
2
+ # Copyright (c) 2007 by Mike Mondragon (mikemondragon@gmail.com)
2
3
  #
3
- # Please see the LICENSE file for licensing.
4
+ # Please see the LICENSE file for licensing information
5
+ #++
4
6
 
5
7
  require 'fileutils'
6
8
  require 'pathname'
7
9
  require 'tmpdir'
8
10
  require 'yaml'
9
- require 'mms2r'
10
- require 'mms2r/version'
11
- require 'mms2r/cingular_media'
12
- require 'mms2r/mmode_media'
13
- require 'mms2r/nextel_media'
14
- require 'mms2r/sprint_media'
15
- require 'mms2r/tmobile_media'
16
- require 'mms2r/verizon_media'
17
- require 'mms2r/dobson_media'
18
11
 
19
12
  ##
20
13
  # MMS2R is a library to collect media files from MMS messages. MMS messages
@@ -22,11 +15,11 @@ require 'mms2r/dobson_media'
22
15
  # messages. MMS2R strips the advertising from an MMS leaving the actual user
23
16
  # generated media.
24
17
  #
25
- # If you encounter MMS from a carrier that contains advertising other non-
26
- # standard media features submit a sample to the author for inclusion in this
18
+ # If you encounter MMS from a carrier that contains advertising and other non-
19
+ # standard media, submit a sample to the author for inclusion in this
27
20
  # project.
28
21
  #
29
- # The create method is a factory method to create MMS2R::Media
22
+ # The create method is a factory method to create MMS2R::Media .
30
23
  # Custom media producers can be pushed into the factory via the
31
24
  # MMS2R::CARRIER_CLASSES Hash, e.g.
32
25
  #
@@ -37,38 +30,6 @@ require 'mms2r/dobson_media'
37
30
 
38
31
  module MMS2R
39
32
 
40
- ##
41
- # A hash of file extentions for common mimetypes
42
- EXT = {
43
- 'text/plain' => 'txt',
44
- 'text/html' => 'html',
45
- 'image/png' => 'png',
46
- 'image/gif' => 'gif',
47
- 'image/jpeg' => 'jpg',
48
- 'video/quicktime' => 'mov',
49
- 'video/3gpp2' => '3g2'
50
- }
51
-
52
- ##
53
- # A hash of carriers that MMS2r is currently aware of.
54
- # The factory create method uses the hostname portion
55
- # of an MMS's from to select the correct type of MMS2R::Media
56
- # product. If a specific media product is not available
57
- # MMS2R::Media should be used.
58
-
59
- CARRIER_CLASSES = {
60
- 'mms.mycingular.com' => MMS2R::CingularMedia,
61
- 'cingularme.com' => MMS2R::CingularMedia,
62
- 'mmode.com' => MMS2R::MModeMedia,
63
- 'messaging.nextel.com' => MMS2R::NextelMedia,
64
- 'pm.sprint.com' => MMS2R::SprintMedia,
65
- 'messaging.sprintpcs.com' => MMS2R::SprintMedia,
66
- 'tmomail.net' => MMS2R::TMobileMedia,
67
- 'vtext.com' => MMS2R::VerizonMedia,
68
- 'vzwpix.com' => MMS2R::VerizonMedia,
69
- 'mms.dobson.net' => MMS2R::DobsonMedia
70
- }
71
-
72
33
  class MMS2R::Media
73
34
  ##
74
35
  # TMail object that the media files were derived from.
@@ -94,7 +55,24 @@ module MMS2R
94
55
  attr_reader :media_dir
95
56
 
96
57
  ##
97
- # Creates a new Media comprised of a mail
58
+ # Factory method that creates MMS2R::Media products.
59
+ #
60
+ # Returns a MMS2R::Media product based on the characteristics
61
+ # of the carrier from which the MMS originated.
62
+ # mail is a TMail object, logger is a Logger and can be
63
+ # nil.
64
+
65
+ def self.create(mail, logger=nil)
66
+ d = lambda{['mms2r.media',MMS2R::Media]} #sets a default to detect
67
+ cc = MMS2R::CARRIER_CLASSES.detect(d) do |n, c|
68
+ /[^@]+@(.+)/.match(mail.from[0])[1] =~ /^#{Regexp.escape("#{n}")}$/
69
+ end
70
+ cls = cc[1]
71
+ cls.new(mail, cc[0], logger)
72
+ end
73
+
74
+ ##
75
+ # Intialize a new Media comprised of a mail and
98
76
  # a logger. Logger is an instance attribute allowing
99
77
  # for a logging strategy per carrier type
100
78
 
@@ -107,19 +85,63 @@ module MMS2R
107
85
  @dir_count = 0
108
86
  @media_dir = File.join(self.class.tmp_dir(),
109
87
  self.class.safe_message_id(@mail.message_id))
88
+ # get warnings out of our hair ...
89
+ @number = nil
90
+ @subject = nil
91
+ @body = nil
92
+ @default_media = nil
93
+ @default_text = nil
110
94
  end
111
95
 
96
+ ##
97
+ # Get the phone number associated with this MMS if it exists.
98
+ # The value returned is simplistic it, is just the user name of
99
+ # the from address before the @ symbol. Validate the number by
100
+ # your application on your own. Most carriers are using the real
101
+ # phone number as the username.
102
+
103
+ def get_number
104
+ # override this method in a child if the number exists elsewhere (like Sprint)
105
+ @number ||= /^([^@]+)@/.match(mail.from[0])[1]
106
+ end
107
+
108
+ ##
112
109
  # Filter some common place holder subjects from MMS messages and replace
113
- # them with nil.
110
+ # them with ""
114
111
 
115
112
  def get_subject
113
+ return @subject if @subject
114
+
116
115
  subject = @mail.subject
117
- if subject.nil? || subject.strip.length == 0 ||
118
- subject =~ /^(Multimedia message|\(no subject\)|You have new Picture Mail!)$/
119
- return nil
120
- end
116
+ return @subject ||= "" if subject.nil? || subject.strip.length == 0
121
117
 
122
- subject
118
+ # subject is not already set, lets see what our defaults are
119
+ a = Array.new
120
+ # default subjects to ignore are in mms2r_media.yml
121
+ f = clz.yaml_file_name(sclz, :subject)
122
+ yf = File.join(self.class.conf_dir(), "#{f}")
123
+ a = a + YAML::load_file(yf) if File::exist?(yf)
124
+ # class default subjects
125
+ f = clz.yaml_file_name(clz, :subject)
126
+ yf = File.join(self.class.conf_dir(), "#{f}")
127
+ a = a + YAML::load_file(yf) if File::exist?(yf)
128
+ return @subject ||= subject if a.size == 0
129
+ return @subject ||= "" if a.detect{|r| r.match(subject.strip)}
130
+ return @subject ||= subject
131
+ end
132
+
133
+ # Convenience method that returns a string including all the text of the
134
+ # first text/plain file found. Returns empty string if no body text
135
+ # is found.
136
+ def get_body
137
+ return @body if @body
138
+
139
+ text_file = get_text
140
+ if text_file.nil?
141
+ return @body ||= ""
142
+ end
143
+
144
+ return @body ||= IO.readlines(text_file.path).join.strip
123
145
  end
124
146
 
125
147
  # Returns a File with the most likely candidate for the user-submitted
@@ -127,21 +149,136 @@ module MMS2R
127
149
  # this will try to give you that file. First it looks for videos, then
128
150
  # images. It also adds singleton methods to the File object so it can
129
151
  # be used in place of a CGI upload (local_path, original_filename, size,
130
- # and content_type)
152
+ # and content_type). The largest file found in terms of bytes is returned.
131
153
  #
132
- # Returns nil if no video or image is found.
154
+ # Returns nil if there are not any video or image Files found.
133
155
 
134
156
  def get_media
135
- get_attachement(['video', 'image'])
157
+ return @default_media ||= get_attachement(['video', 'image'])
136
158
  end
137
159
 
138
160
  # Returns a File with the most likely candidate that is text, or nil
139
161
  # otherwise. It also adds singleton methods to the File object so it can
140
162
  # be used in place of a CGI upload (local_path, original_filename, size,
141
- # and content_type)
163
+ # and content_type). The largest file found in terms of bytes is returned.
164
+ #
165
+ # Returns nil if there are not any text Files found
142
166
 
143
167
  def get_text
144
- get_attachement(['text'])
168
+ return @default_text ||= get_attachement(['text'])
169
+ end
170
+
171
+ ##
172
+ # process is a template method and collects all the media in a MMS.
173
+ # Override helper methods to this template to clean out advertising
174
+ # and/or ignore media that are advertising. This method should not be
175
+ # overridden unless there is an extreme special case in processing the
176
+ # media of a MMS (like Sprint)
177
+ #
178
+ # Helpers methods for the process template:
179
+ # * ignore_media? -- true if the media contained in a part should be ignored.
180
+ # * process_media -- retrieves media to temporary file, returns path to file.
181
+ # * transform_text -- called by process_media, strips out advertising.
182
+ # * temp_file -- creates a temporary filepath based on information from the part.
183
+ #
184
+ # Block support:
185
+ # Calling process() with a block to automatically iterate through media
186
+ # and *purge* after the block yields. For example, to process and receive
187
+ # all media types of video, you can do:
188
+ # mms.process do |media_type, file|
189
+ # results << file if media_type =~ /video/
190
+ # end
191
+ #
192
+ # note: auto-purging is a feature of calling process() with a block, purge
193
+ # must be explicitly called otherwise
194
+
195
+ def process()
196
+ @logger.info("#{self.class} processing") unless @logger.nil?
197
+
198
+ # build up all the parts
199
+ parts = @mail.parts
200
+ if !@mail.multipart?
201
+ parts = Array.new()
202
+ parts << @mail
203
+ end
204
+ # double check for multipart/alternative, if it exists
205
+ # replace it with its children parts
206
+ parts.each do |p|
207
+ if self.class.part_type?(p).eql?('multipart/alternative')
208
+ part = parts.delete(p)
209
+ part.parts.each { |mp| parts << mp }
210
+ end
211
+ end
212
+ # get to work
213
+ parts.each do |p|
214
+ t = self.class.part_type?(p)
215
+ unless ignore_media?(t,p)
216
+ t,f = process_media(p)
217
+ add_file(t,f) unless t.nil? || f.nil?
218
+ end
219
+ end
220
+
221
+ if block_given?
222
+ media.each do |k, v|
223
+ yield(k, v)
224
+ purge
225
+ end
226
+ end
227
+
228
+ end
229
+
230
+ ##
231
+ # Helper for process template method to determine if
232
+ # media contained in a part should be ignored. Producers
233
+ # should override this method to return true for media such
234
+ # as images that are advertising, carrier logos, etc.
235
+ # The corresponding *_ignore.yml for a given class contains
236
+ # either a regular expression for the text types or a file
237
+ # name for all other types. When writing an ignore regular
238
+ # expression assume that the text it will be evaluated against
239
+ # has been flattened where one or more consecutive whitespace
240
+ # (tab, space, new lines and line feeds) characters are replaced
241
+ # with one space ' ' character.
242
+
243
+ def ignore_media?(type,part)
244
+
245
+ # default media to ignore are in mms2r_media.yml
246
+ # which is a hash of mime types as keys each to an
247
+ # array of regular expressions
248
+ f = clz.yaml_file_name(sclz, :ignore)
249
+ yf = File.join(self.class.conf_dir(), "#{f}")
250
+ h = YAML::load_file(yf) if File::exist?(yf)
251
+ h ||= Hash.new
252
+
253
+ # merge in the ignore hash of the specific child
254
+ f = clz.yaml_file_name(clz, :ignore)
255
+ yf = File.join(self.class.conf_dir(), "#{f}")
256
+ if File::exist?(yf)
257
+ h2 = YAML::load_file(yf)
258
+ h2.each do |k,v|
259
+ unless h[k]
260
+ h[k] = v
261
+ else
262
+ v.each{|e| h[k] << e}
263
+ end
264
+ end
265
+ end
266
+ a ||= h[type]
267
+ return false if h.size == 0 || a.nil?
268
+
269
+ m = /^([^\/]+)\//.match(type)[1]
270
+ # fire each regular expression, only break if there is a match
271
+ ignore = a.each do |i|
272
+ if m.eql?('text') || type.eql?('application/smil')
273
+ s = part.body.gsub(/\s+/m," ").strip
274
+ break(i) if i.match(s)
275
+ else
276
+ break(i) if filename?(part).eql?(i)
277
+ end
278
+ end
279
+ return ignore.eql?(a) ? false : true # when ignore is equal to 'a' that
280
+ # means none of the breaks fired in
281
+ # the loop, if a break
145
282
  end
146
283
 
147
284
  ##
@@ -153,20 +290,25 @@ module MMS2R
153
290
  #
154
291
  # Producers should only override this method if the parts of
155
292
  # the MMS need special treatment besides what is expected for
156
- # a normal mime part.
293
+ # a normal mime part (like Sprint).
157
294
  #
158
- # Returns a tupple of content type, file path
295
+ # Returns a tuple of content type, file path
159
296
 
160
297
  def process_media(part)
161
298
  # TMail body auto-magically decodes quoted
162
299
  # printable for text/html type.
163
300
  file = temp_file(part)
164
- if self.class.main_type?(part).eql?('text')
165
- type, content = transform_text(part)
301
+ case
302
+ when self.class.main_type?(part).eql?('text')
303
+ type, content = transform_text_part(part)
304
+ when self.class.part_type?(part).eql?('application/smil')
305
+ type, content = transform_text_part(part)
166
306
  else
167
307
  type = self.class.part_type?(part)
168
308
  content = part.body
169
309
  end
310
+ return type, nil if content.nil?
311
+
170
312
  @logger.info("#{self.class} writing file #{file}") unless @logger.nil?
171
313
  File.open(file,'w'){ |f|
172
314
  f.write(content)
@@ -176,44 +318,42 @@ module MMS2R
176
318
 
177
319
  ##
178
320
  # Helper for process_media template method to transform text.
321
+ # The regular expressions for the transform are in the
322
+ # conf/*_transform.yml files.
323
+ # Input is the type of text and the text to transform.
179
324
 
180
- def transform_text(part)
181
- type = self.class.part_type?(part)
182
- text = part.body
183
- f = "#{self.class.name.downcase.gsub(/::/,'_')}_transform.yml"
325
+ def transform_text(type, text)
326
+ f = clz.yaml_file_name(clz, :transform)
184
327
  yf = File.join(self.class.conf_dir(), "#{f}")
185
328
  return type, text unless File::exist?(yf)
329
+
186
330
  h = YAML::load_file(yf)
187
331
  a = h[type]
188
332
  return type, text if a.nil?
189
- a.each do |from,to|
190
- text.gsub!(/#{from}/m,to)
333
+
334
+ #convert to UTF-8
335
+ begin
336
+ c = Iconv.new('ISO-8859-1', 'UTF-8' )
337
+ utf_t = c.iconv(text)
338
+ rescue Exception => e
339
+ utf_t = text
191
340
  end
192
- return type, text
341
+
342
+ # 'from' is a Regexp in the conf and 'to' is the match position
343
+ # or from is text that will be replaced with to
344
+ a.each { |from,to| utf_t = utf_t.gsub(from,to).strip }
345
+ return type, utf_t.strip
193
346
  end
194
347
 
195
348
  ##
196
- # Helper for process template method to determine if
197
- # media contained in a part should be ignored. Producers
198
- # should override this method to return true for media such
199
- # as images that are advertising, carrier logos, etc.
349
+ # Helper for process_media template method to transform text.
350
+ # The regular expressions for the trans are in *_transform.yml
351
+ # Input is a mail part
200
352
 
201
- def ignore_media?(type,part)
202
- f = "#{self.class.name.downcase.gsub(/::/,'_')}_ignore.yml"
203
- yf = File.join(self.class.conf_dir(), "#{f}")
204
- return false unless File::exist?(yf)
205
- h = YAML::load_file(yf)
206
- a = h[type]
207
- return false if a.nil?
208
- m = /^([^\/]+)\//.match(type)[1]
209
- a.each do |i|
210
- if m.eql?('text')
211
- return true if 0 == (part.body =~ /#{Regexp.escape("#{i}")}/m)
212
- else
213
- return true if filename?(part).eql?(i)
214
- end
215
- end
216
- false
353
+ def transform_text_part(part)
354
+ type = self.class.part_type?(part)
355
+ text = part.body.strip
356
+ transform_text(type, text)
217
357
  end
218
358
 
219
359
  ##
@@ -223,7 +363,7 @@ module MMS2R
223
363
  # header and creates a unique temporary directory for writing
224
364
  # the file so filename collision does not occur.
225
365
  # Consumers of this method expect the directory
226
- # structure to the file exists, if the method is overriden it
366
+ # structure to the file exists, if the method is overridden it
227
367
  # is mandatory that this behavior is retained.
228
368
 
229
369
  def temp_file(part)
@@ -240,44 +380,6 @@ module MMS2R
240
380
  FileUtils.rm_rf(@media_dir)
241
381
  end
242
382
 
243
- ##
244
- # process is a template method and collects all the media in a MMS.
245
- # Override helper methods to this template to clean out advertising
246
- # and/or ignore media that are advertising. This method should not be
247
- # overridden unless there is an extreme special case in processing the
248
- # media of a MMS.
249
- #
250
- # Helpers methods for the process template:
251
- # * ignore_media? -- true if the media contained in a part should be ignored.
252
- # * process_media -- retrieves media to temporary file, returns path to file.
253
- # * transform_text -- called by process_media, strips out advertising.
254
- # * temp_file -- creates a temporary filepath based on information from the part.
255
-
256
- def process()
257
- @logger.info("#{self.class} processing") unless @logger.nil?
258
-
259
- parts = @mail.parts
260
- if !@mail.multipart?
261
- parts = Array.new()
262
- parts << @mail
263
- end
264
- parts.each do |p|
265
- if self.class.part_type?(p).eql?('multipart/alternative')
266
- part = parts.delete(p)
267
- part.parts.each do |mp|
268
- parts << mp
269
- end
270
- end
271
- end
272
- parts.each do |p|
273
- t = self.class.part_type?(p)
274
- unless ignore_media?(t,p)
275
- t,f = process_media(p)
276
- add_file(t,f) unless f.nil?
277
- end
278
- end
279
- end
280
-
281
383
  ##
282
384
  # Helper to add a file to the media hash.
283
385
 
@@ -300,23 +402,6 @@ module MMS2R
300
402
  dir
301
403
  end
302
404
 
303
- ##
304
- # Factory method that creates MMS2R::Media products.
305
- #
306
- # Returns a MMS2R::Media product based on the characteristics
307
- # of the carrier from which the the MMS originated.
308
- # mail is a TMail object, logger is a Logger and can be
309
- # nil.
310
-
311
- def self.create(mail, logger=nil)
312
- d = lambda{['mms2r.media',MMS2R::Media]}
313
- cc = MMS2R::CARRIER_CLASSES.detect(d) do |n, c|
314
- /[^@]+@(.+)/.match(mail.from[0])[1] =~ /#{Regexp.escape("#{n}")}/
315
- end
316
- cls = cc[1]
317
- cls.new(mail, cc[0], logger)
318
- end
319
-
320
405
  ##
321
406
  # returns a filename declared for a part, or a default if its not defined
322
407
 
@@ -324,7 +409,7 @@ module MMS2R
324
409
  part.sub_header("content-type", "name") ||
325
410
  part.sub_header("content-disposition", "filename") ||
326
411
  (part['content-location'] && part['content-location'].body) ||
327
- "#{Time.now.to_i}.#{self.class.default_ext(self.class.part_type?(part))}"
412
+ "#{Time.now.to_f}.#{self.class.default_ext(self.class.part_type?(part))}"
328
413
  end
329
414
 
330
415
  @@tmp_dir = File.join(Dir.tmpdir, (ENV['USER'].nil? ? '':ENV['USER']), 'mms2r')
@@ -358,7 +443,7 @@ module MMS2R
358
443
  end
359
444
 
360
445
  ##
361
- # Helper to created a safe directory path element based on the
446
+ # Helper to create a safe directory path element based on the
362
447
  # mail message id.
363
448
 
364
449
  def self.safe_message_id(mid)
@@ -367,16 +452,16 @@ module MMS2R
367
452
  end
368
453
 
369
454
  ##
370
- # Returns a default file extension based on a content_type
455
+ # Returns a default file extension based on a content type
371
456
 
372
457
  def self.default_ext(content_type)
373
458
  ext = MMS2R::EXT[content_type]
374
- return /[^\/]+\/(.+)/.match(content_type)[1] if ext.nil?
459
+ ext = /[^\/]+\/(.+)/.match(content_type)[1] if ext.nil?
375
460
  ext
376
461
  end
377
462
 
378
463
  ##
379
- # Determines the mimetype of a part. Gauruntees a type is returned.
464
+ # Determines the mimetype of a part. Guarantees a type is returned.
380
465
 
381
466
  def self.part_type?(part)
382
467
  if part.content_type.nil?
@@ -399,24 +484,62 @@ module MMS2R
399
484
  /\/([^\/]+)$/.match(self.part_type?(part))[1]
400
485
  end
401
486
 
487
+ ##
488
+ # helper to contruct a yml file name with a class
489
+ # name based pattern, i.e. mms2r_tmobilemedia_ignore.yml
490
+ # for yaml_file_name(MMS2R::TMobileMedia,:ignore)
491
+
492
+ def self.yaml_file_name(clz,kind)
493
+ # like active_support's inflector
494
+ flat = clz.name.gsub(/::/, '_').
495
+ gsub(/([A-Z]+)([A-Z][a-z])/,'\1_\2').
496
+ gsub(/([a-z])([A-Z])/,'\1_\2').
497
+ tr("-", "_").downcase
498
+ "#{flat}_#{kind.to_s}.yml"
499
+ end
500
+
501
+ ##
502
+ # helper to fetch self.class quicly
503
+
504
+ def clz
505
+ self.class
506
+ end
507
+
508
+ ##
509
+ # helper to fetch self.class.superclass quicly
510
+
511
+ def sclz
512
+ self.class.superclass
513
+ end
514
+
402
515
  private
403
516
 
404
517
  ##
405
- # used by get_media and get_text to return the first attachment type
518
+ # used by get_media and get_text to return the biggest attachment type
406
519
  # listed in the types array
407
520
 
408
521
  def get_attachement(types)
409
522
 
410
- mime_type = nil
411
- types.each{|t|
412
- mime_type = media.keys.find { |key| 0 == (key =~ /#{t}/) } if mime_type.nil?
413
- }
414
-
415
- if mime_type.nil?
416
- return nil
523
+ # get all the files that are of the major types passed in
524
+ files = Array.new
525
+ types.each do |t|
526
+ media.keys.each do |k|
527
+ files.concat(media[k]) if /^#{t}\//.match(k)
528
+ end
529
+ end
530
+ return nil if files.size == 0
531
+
532
+ #get the largest file
533
+ size = 0
534
+ file = nil # explicitly declare the file
535
+ files.each do |f|
536
+ # this will safely evaluate since we wouldn't be looking at
537
+ # media[mime_type] after the check just before this
538
+ if File.size(f) > size
539
+ size = File.size(f)
540
+ file = File.new(f)
541
+ end
417
542
  end
418
-
419
- file = File.new(media[mime_type][0])
420
543
 
421
544
  # These singleton methods implement the interface necessary to be used
422
545
  # as a drop-in replacement for files uploaded with CGI.rb.