mms2r 1.0.7 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +19 -1
- data/Manifest.txt +38 -19
- data/README.txt +40 -8
- data/Rakefile +2 -2
- data/conf/mms2r_cingular_me_media_subject.yml +3 -0
- data/conf/{mms2r_cingularmedia_transform.yml → mms2r_cingular_me_media_transform.yml} +1 -0
- data/conf/mms2r_dobson_media_ignore.yml +4 -0
- data/conf/mms2r_media_ignore.yml +4 -0
- data/conf/mms2r_media_subject.yml +3 -0
- data/conf/mms2r_my_cingular_media_subject.yml +3 -0
- data/conf/mms2r_nextel_media_ignore.yml +11 -0
- data/conf/mms2r_sprint_media_ignore.yml +5 -0
- data/conf/mms2r_sprint_media_subject.yml +3 -0
- data/conf/{mms2r_tmobilemedia_ignore.yml → mms2r_t_mobile_media_ignore.yml} +2 -5
- data/conf/mms2r_verizon_media_ignore.yml +4 -0
- data/conf/mms2r_verizon_media_transform.yml +6 -0
- data/dev_tools/debug_sprint_hpricot_parsing.rb +82 -0
- data/lib/mms2r.rb +61 -0
- data/lib/mms2r/cingular_me_media.rb +23 -0
- data/lib/mms2r/dobson_media.rb +4 -5
- data/lib/mms2r/{mmode_media.rb → m_mode_media.rb} +4 -4
- data/lib/mms2r/media.rb +283 -160
- data/lib/mms2r/my_cingular_media.rb +15 -0
- data/lib/mms2r/nextel_media.rb +9 -3
- data/lib/mms2r/sprint_media.rb +137 -29
- data/lib/mms2r/sprint_pcs_media.rb +16 -0
- data/lib/mms2r/t_mobile_media.rb +21 -0
- data/lib/mms2r/verizon_media.rb +11 -3
- data/lib/mms2r/vtext_media.rb +16 -0
- data/test/files/cingularme-text-02.mail +14 -0
- data/test/files/hello_world_empty_text.mail +6 -0
- data/test/files/hello_world_mail_multipart.mail +7 -0
- data/test/files/{cingular-image-01.mail → mycingular-image-01.mail} +0 -0
- data/test/files/simple-with-two-images-two-texts.mail +49 -0
- data/test/files/{sprint-image-02.mail → sprint-broken-image-01.mail} +1 -1
- data/test/files/sprint-image-01.mail +1 -1
- data/test/files/sprint-pcs-text-01.mail +8 -0
- data/test/files/sprint-text-01.mail +195 -8
- data/test/files/sprint-two-images-01.mail +198 -0
- data/test/files/sprint-video-01.mail +1 -1
- data/test/files/verizon-image-02.mail +1 -1
- data/test/files/vtext-text-01.mail +1 -1
- data/test/test_mms2r_cingular_me_media.rb +51 -0
- data/test/test_mms2r_dobson_media.rb +46 -0
- data/test/{test_mms2r_mmode.rb → test_mms2r_m_mode_media.rb} +1 -1
- data/test/test_mms2r_media.rb +160 -74
- data/test/test_mms2r_my_cingular_media.rb +31 -0
- data/test/test_mms2r_nextel_media.rb +100 -0
- data/test/test_mms2r_sprint_media.rb +221 -0
- data/test/test_mms2r_sprint_pcs_media.rb +27 -0
- data/test/{test_mms2r_tmobile.rb → test_mms2r_t_mobile_media.rb} +13 -13
- data/test/test_mms2r_verizon_media.rb +96 -0
- data/test/test_mms2r_vtext_media.rb +28 -0
- data/vendor/plugins/mms2r/lib/autotest/discover.rb +3 -0
- data/vendor/plugins/mms2r/lib/autotest/mms2r.rb +33 -0
- metadata +62 -37
- data/conf/mms2r_nextelmedia_ignore.yml +0 -10
- data/conf/mms2r_sprintmedia_ignore.yml +0 -10
- data/conf/mms2r_verizonmedia_ignore.yml +0 -3
- data/conf/mms2r_verizonmedia_transform.yml +0 -3
- data/lib/mms2r/cingular_media.rb +0 -11
- data/lib/mms2r/tmobile_media.rb +0 -11
- data/lib/mms2r/version.rb +0 -12
- data/test/test_mms2r_cingular.rb +0 -58
- data/test/test_mms2r_dobson.rb +0 -36
- data/test/test_mms2r_nextel.rb +0 -132
- data/test/test_mms2r_sprint.rb +0 -174
- 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
|
data/lib/mms2r/dobson_media.rb
CHANGED
@@ -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
|
10
|
-
#
|
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
|
-
|
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
|
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
|
-
#
|
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
|
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
|
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
|
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
|
-
|
165
|
-
|
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(
|
181
|
-
|
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
|
-
|
190
|
-
|
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
|
-
|
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
|
197
|
-
#
|
198
|
-
#
|
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
|
202
|
-
|
203
|
-
|
204
|
-
|
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
|
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.
|
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
|
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
|
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
|
-
|
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.
|
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
|
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
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
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.
|