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.
- 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.
|