mms2r 1.0.7 → 1.1.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 (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.