mms2r 1.1.12 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (131) hide show
  1. data/History.txt +32 -2
  2. data/Manifest.txt +41 -79
  3. data/README.txt +50 -51
  4. data/Rakefile +3 -2
  5. data/conf/aliases.yml +8 -0
  6. data/conf/message.alltel.com.yml +14 -0
  7. data/conf/messaging.nextel.com.yml +10 -0
  8. data/conf/mms.att.net.yml +9 -0
  9. data/conf/mms.dobson.net.yml +4 -0
  10. data/conf/mms.luxgsm.lu.yml +8 -0
  11. data/conf/mms.myhelio.com.yml +12 -0
  12. data/conf/mms.netcom.no.yml +4 -0
  13. data/conf/mms.o2online.de.yml +8 -0
  14. data/conf/mms.three.co.uk.yml +15 -0
  15. data/conf/mms2r_media.yml +6 -0
  16. data/conf/orangemms.net.yml +13 -0
  17. data/conf/pm.sprint.com.yml +10 -0
  18. data/conf/pxt.vodafone.net.nz.yml +5 -0
  19. data/conf/tmomail.net.yml +16 -0
  20. data/conf/vzwpix.com.yml +8 -0
  21. data/dev_tools/anonymizer.rb +20 -0
  22. data/lib/mms2r.rb +19 -45
  23. data/lib/mms2r/media.rb +288 -300
  24. data/lib/mms2r/media/sprint.rb +189 -0
  25. data/test/fixtures/att-text-01.mail +27 -0
  26. data/test/fixtures/helio-image-01.mail +8 -8
  27. data/test/fixtures/helio-message-01.mail +327 -0
  28. data/test/fixtures/luxgsm-image-01.mail +388 -0
  29. data/test/fixtures/netcom-image-01.mail +556 -0
  30. data/test/fixtures/o2-de-image-01.mail +314 -0
  31. data/test/fixtures/orange-uk-image-01.mail +71 -0
  32. data/test/fixtures/pxt-image-01.mail +118 -0
  33. data/test/fixtures/sprint-broken-image-01.mail +1 -1
  34. data/test/fixtures/sprint-image-01.mail +211 -195
  35. data/test/fixtures/sprint-purged-image-01.mail +1 -1
  36. data/test/fixtures/sprint-two-images-01.mail +231 -198
  37. data/test/fixtures/sprint-video-01.mail +210 -195
  38. data/test/fixtures/three-uk-image-01.mail +1202 -0
  39. data/test/test_helper.rb +39 -0
  40. data/test/{test_mms2r_alltel_media.rb → test_message_alltel_com.rb} +13 -17
  41. data/test/{test_mms2r_nextel_media.rb → test_messaging_nextel_com.rb} +12 -19
  42. data/test/{test_mms2r_sprint_pcs_media.rb → test_messaging_sprintpcs_com.rb} +9 -10
  43. data/test/test_mms2r_media.rb +474 -316
  44. data/test/test_mms_att_net.rb +92 -0
  45. data/test/test_mms_dobson_net.rb +41 -0
  46. data/test/test_mms_luxgsm_lu.rb +50 -0
  47. data/test/test_mms_myhelio_com.rb +60 -0
  48. data/test/test_mms_netcom_no.rb +52 -0
  49. data/test/test_mms_o2online_de.rb +53 -0
  50. data/test/test_mms_three_co_uk.rb +42 -0
  51. data/test/test_orangemms_net.rb +100 -0
  52. data/test/test_pm_sprint_com.rb +201 -0
  53. data/test/test_pxt_vodafone_net_nz.rb +37 -0
  54. data/test/{test_mms2r_t_mobile_media.rb → test_tmomail_net.rb} +8 -19
  55. data/test/{test_mms2r_verizon_media.rb → test_vzwpix_com.rb} +34 -27
  56. data/vendor/plugins/mms2r/lib/autotest/mms2r.rb +16 -11
  57. metadata +128 -157
  58. data/conf/mms2r_alltel_media_ignore.yml +0 -13
  59. data/conf/mms2r_att_media_subject.yml +0 -3
  60. data/conf/mms2r_cingular_me_media_subject.yml +0 -3
  61. data/conf/mms2r_cingular_me_media_transform.yml +0 -7
  62. data/conf/mms2r_dobson_media_ignore.yml +0 -4
  63. data/conf/mms2r_helio_media_ignore.yml +0 -6
  64. data/conf/mms2r_media_ignore.yml +0 -5
  65. data/conf/mms2r_media_subject.yml +0 -3
  66. data/conf/mms2r_my_cingular_media_subject.yml +0 -3
  67. data/conf/mms2r_nextel_media_ignore.yml +0 -11
  68. data/conf/mms2r_orange_france_media_ignore.yml +0 -6
  69. data/conf/mms2r_orange_poland_media_subject.yml +0 -3
  70. data/conf/mms2r_sprint_media_ignore.yml +0 -7
  71. data/conf/mms2r_sprint_media_subject.yml +0 -3
  72. data/conf/mms2r_t_mobile_media_ignore.yml +0 -16
  73. data/conf/mms2r_verizon_media_ignore.yml +0 -4
  74. data/conf/mms2r_verizon_media_transform.yml +0 -5
  75. data/lib/mms2r/alltel_media.rb +0 -10
  76. data/lib/mms2r/att_media.rb +0 -13
  77. data/lib/mms2r/cingular_me_media.rb +0 -23
  78. data/lib/mms2r/dobson_media.rb +0 -13
  79. data/lib/mms2r/helio_media.rb +0 -20
  80. data/lib/mms2r/m_mode_media.rb +0 -13
  81. data/lib/mms2r/my_cingular_media.rb +0 -15
  82. data/lib/mms2r/nextel_media.rb +0 -17
  83. data/lib/mms2r/orange_france_media.rb +0 -10
  84. data/lib/mms2r/orange_poland_media.rb +0 -10
  85. data/lib/mms2r/sprint_media.rb +0 -182
  86. data/lib/mms2r/sprint_pcs_media.rb +0 -16
  87. data/lib/mms2r/t_mobile_media.rb +0 -21
  88. data/lib/mms2r/verizon_media.rb +0 -19
  89. data/lib/mms2r/vtext_media.rb +0 -16
  90. data/lib/vendor/text/format.rb +0 -1466
  91. data/lib/vendor/tmail.rb +0 -3
  92. data/lib/vendor/tmail/address.rb +0 -242
  93. data/lib/vendor/tmail/attachments.rb +0 -39
  94. data/lib/vendor/tmail/base64.rb +0 -71
  95. data/lib/vendor/tmail/config.rb +0 -69
  96. data/lib/vendor/tmail/encode.rb +0 -467
  97. data/lib/vendor/tmail/facade.rb +0 -552
  98. data/lib/vendor/tmail/header.rb +0 -914
  99. data/lib/vendor/tmail/info.rb +0 -35
  100. data/lib/vendor/tmail/loader.rb +0 -1
  101. data/lib/vendor/tmail/mail.rb +0 -447
  102. data/lib/vendor/tmail/mailbox.rb +0 -433
  103. data/lib/vendor/tmail/mbox.rb +0 -1
  104. data/lib/vendor/tmail/net.rb +0 -280
  105. data/lib/vendor/tmail/obsolete.rb +0 -135
  106. data/lib/vendor/tmail/parser.rb +0 -1522
  107. data/lib/vendor/tmail/port.rb +0 -377
  108. data/lib/vendor/tmail/quoting.rb +0 -131
  109. data/lib/vendor/tmail/scanner.rb +0 -41
  110. data/lib/vendor/tmail/scanner_r.rb +0 -263
  111. data/lib/vendor/tmail/stringio.rb +0 -277
  112. data/lib/vendor/tmail/tmail.rb +0 -1
  113. data/lib/vendor/tmail/utils.rb +0 -238
  114. data/test/fixtures/broken_from_spam.mail +0 -80
  115. data/test/fixtures/hello_world_empty_text.mail +0 -7
  116. data/test/fixtures/hello_world_mail_multipart.mail +0 -24
  117. data/test/fixtures/hello_world_mail_plain_no_content_type.mail +0 -7
  118. data/test/fixtures/hello_world_mail_plain_with_content_type.mail +0 -8
  119. data/test/fixtures/simple-with-two-images-two-texts.mail +0 -49
  120. data/test/fixtures/simple_image.mail +0 -19
  121. data/test/fixtures/simple_multipart_alternative.mail +0 -42
  122. data/test/test_mms2r_att_media.rb +0 -54
  123. data/test/test_mms2r_cingular_me_media.rb +0 -51
  124. data/test/test_mms2r_dobson_media.rb +0 -46
  125. data/test/test_mms2r_helio_media.rb +0 -49
  126. data/test/test_mms2r_m_mode_media.rb +0 -36
  127. data/test/test_mms2r_my_cingular_media.rb +0 -31
  128. data/test/test_mms2r_orange_france_media.rb +0 -53
  129. data/test/test_mms2r_orange_poland_media.rb +0 -42
  130. data/test/test_mms2r_sprint_media.rb +0 -269
  131. data/test/test_mms2r_vtext_media.rb +0 -28
@@ -1,3 +0,0 @@
1
- require 'tmail/info'
2
- require 'tmail/mail'
3
- require 'tmail/mailbox'
@@ -1,242 +0,0 @@
1
- #
2
- # address.rb
3
- #
4
- #--
5
- # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining
8
- # a copy of this software and associated documentation files (the
9
- # "Software"), to deal in the Software without restriction, including
10
- # without limitation the rights to use, copy, modify, merge, publish,
11
- # distribute, sublicense, and/or sell copies of the Software, and to
12
- # permit persons to whom the Software is furnished to do so, subject to
13
- # the following conditions:
14
- #
15
- # The above copyright notice and this permission notice shall be
16
- # included in all copies or substantial portions of the Software.
17
- #
18
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
- #
26
- # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
27
- # with permission of Minero Aoki.
28
- #++
29
-
30
- require 'tmail/encode'
31
- require 'tmail/parser'
32
-
33
-
34
- module TMail
35
-
36
- class Address
37
-
38
- include TextUtils
39
-
40
- def Address.parse( str )
41
- Parser.parse :ADDRESS, str
42
- end
43
-
44
- def address_group?
45
- false
46
- end
47
-
48
- def initialize( local, domain )
49
- if domain
50
- domain.each do |s|
51
- raise SyntaxError, 'empty word in domain' if s.empty?
52
- end
53
- end
54
- @local = local
55
- @domain = domain
56
- @name = nil
57
- @routes = []
58
- end
59
-
60
- attr_reader :name
61
-
62
- def name=( str )
63
- @name = str
64
- @name = nil if str and str.empty?
65
- end
66
-
67
- alias phrase name
68
- alias phrase= name=
69
-
70
- attr_reader :routes
71
-
72
- def inspect
73
- "#<#{self.class} #{address()}>"
74
- end
75
-
76
- def local
77
- return nil unless @local
78
- return '""' if @local.size == 1 and @local[0].empty?
79
- @local.map {|i| quote_atom(i) }.join('.')
80
- end
81
-
82
- def domain
83
- return nil unless @domain
84
- join_domain(@domain)
85
- end
86
-
87
- def spec
88
- s = self.local
89
- d = self.domain
90
- if s and d
91
- s + '@' + d
92
- else
93
- s
94
- end
95
- end
96
-
97
- alias address spec
98
-
99
-
100
- def ==( other )
101
- other.respond_to? :spec and self.spec == other.spec
102
- end
103
-
104
- alias eql? ==
105
-
106
- def hash
107
- @local.hash ^ @domain.hash
108
- end
109
-
110
- def dup
111
- obj = self.class.new(@local.dup, @domain.dup)
112
- obj.name = @name.dup if @name
113
- obj.routes.replace @routes
114
- obj
115
- end
116
-
117
- include StrategyInterface
118
-
119
- def accept( strategy, dummy1 = nil, dummy2 = nil )
120
- unless @local
121
- strategy.meta '<>' # empty return-path
122
- return
123
- end
124
-
125
- spec_p = (not @name and @routes.empty?)
126
- if @name
127
- strategy.phrase @name
128
- strategy.space
129
- end
130
- tmp = spec_p ? '' : '<'
131
- unless @routes.empty?
132
- tmp << @routes.map {|i| '@' + i }.join(',') << ':'
133
- end
134
- tmp << self.spec
135
- tmp << '>' unless spec_p
136
- strategy.meta tmp
137
- strategy.lwsp ''
138
- end
139
-
140
- end
141
-
142
-
143
- class AddressGroup
144
-
145
- include Enumerable
146
-
147
- def address_group?
148
- true
149
- end
150
-
151
- def initialize( name, addrs )
152
- @name = name
153
- @addresses = addrs
154
- end
155
-
156
- attr_reader :name
157
-
158
- def ==( other )
159
- other.respond_to? :to_a and @addresses == other.to_a
160
- end
161
-
162
- alias eql? ==
163
-
164
- def hash
165
- map {|i| i.hash }.hash
166
- end
167
-
168
- def []( idx )
169
- @addresses[idx]
170
- end
171
-
172
- def size
173
- @addresses.size
174
- end
175
-
176
- def empty?
177
- @addresses.empty?
178
- end
179
-
180
- def each( &block )
181
- @addresses.each(&block)
182
- end
183
-
184
- def to_a
185
- @addresses.dup
186
- end
187
-
188
- alias to_ary to_a
189
-
190
- def include?( a )
191
- @addresses.include? a
192
- end
193
-
194
- def flatten
195
- set = []
196
- @addresses.each do |a|
197
- if a.respond_to? :flatten
198
- set.concat a.flatten
199
- else
200
- set.push a
201
- end
202
- end
203
- set
204
- end
205
-
206
- def each_address( &block )
207
- flatten.each(&block)
208
- end
209
-
210
- def add( a )
211
- @addresses.push a
212
- end
213
-
214
- alias push add
215
-
216
- def delete( a )
217
- @addresses.delete a
218
- end
219
-
220
- include StrategyInterface
221
-
222
- def accept( strategy, dummy1 = nil, dummy2 = nil )
223
- strategy.phrase @name
224
- strategy.meta ':'
225
- strategy.space
226
- first = true
227
- each do |mbox|
228
- if first
229
- first = false
230
- else
231
- strategy.meta ','
232
- end
233
- strategy.space
234
- mbox.accept strategy
235
- end
236
- strategy.meta ';'
237
- strategy.lwsp ''
238
- end
239
-
240
- end
241
-
242
- end # module TMail
@@ -1,39 +0,0 @@
1
- require 'stringio'
2
-
3
- module TMail
4
- class Attachment < StringIO
5
- attr_accessor :original_filename, :content_type
6
- end
7
-
8
- class Mail
9
- def has_attachments?
10
- multipart? && parts.any? { |part| attachment?(part) }
11
- end
12
-
13
- def attachment?(part)
14
- (part['content-disposition'] && part['content-disposition'].disposition == "attachment") ||
15
- part.header['content-type'].main_type != "text"
16
- end
17
-
18
- def attachments
19
- if multipart?
20
- parts.collect { |part|
21
- if attachment?(part)
22
- content = part.body # unquoted automatically by TMail#body
23
- file_name = (part['content-location'] &&
24
- part['content-location'].body) ||
25
- part.sub_header("content-type", "name") ||
26
- part.sub_header("content-disposition", "filename")
27
-
28
- next if file_name.blank? || content.blank?
29
-
30
- attachment = Attachment.new(content)
31
- attachment.original_filename = file_name.strip
32
- attachment.content_type = part.content_type
33
- attachment
34
- end
35
- }.compact
36
- end
37
- end
38
- end
39
- end
@@ -1,71 +0,0 @@
1
- #
2
- # base64.rb
3
- #
4
- #--
5
- # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining
8
- # a copy of this software and associated documentation files (the
9
- # "Software"), to deal in the Software without restriction, including
10
- # without limitation the rights to use, copy, modify, merge, publish,
11
- # distribute, sublicense, and/or sell copies of the Software, and to
12
- # permit persons to whom the Software is furnished to do so, subject to
13
- # the following conditions:
14
- #
15
- # The above copyright notice and this permission notice shall be
16
- # included in all copies or substantial portions of the Software.
17
- #
18
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
- #
26
- # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
27
- # with permission of Minero Aoki.
28
- #++
29
-
30
- module TMail
31
-
32
- module Base64
33
-
34
- module_function
35
-
36
- def rb_folding_encode( str, eol = "\n", limit = 60 )
37
- [str].pack('m')
38
- end
39
-
40
- def rb_encode( str )
41
- [str].pack('m').tr( "\r\n", '' )
42
- end
43
-
44
- def rb_decode( str, strict = false )
45
- str.unpack('m')
46
- end
47
-
48
- begin
49
- require 'tmail/base64.so'
50
- alias folding_encode c_folding_encode
51
- alias encode c_encode
52
- alias decode c_decode
53
- class << self
54
- alias folding_encode c_folding_encode
55
- alias encode c_encode
56
- alias decode c_decode
57
- end
58
- rescue LoadError
59
- alias folding_encode rb_folding_encode
60
- alias encode rb_encode
61
- alias decode rb_decode
62
- class << self
63
- alias folding_encode rb_folding_encode
64
- alias encode rb_encode
65
- alias decode rb_decode
66
- end
67
- end
68
-
69
- end
70
-
71
- end
@@ -1,69 +0,0 @@
1
- #
2
- # config.rb
3
- #
4
- #--
5
- # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining
8
- # a copy of this software and associated documentation files (the
9
- # "Software"), to deal in the Software without restriction, including
10
- # without limitation the rights to use, copy, modify, merge, publish,
11
- # distribute, sublicense, and/or sell copies of the Software, and to
12
- # permit persons to whom the Software is furnished to do so, subject to
13
- # the following conditions:
14
- #
15
- # The above copyright notice and this permission notice shall be
16
- # included in all copies or substantial portions of the Software.
17
- #
18
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
- #
26
- # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
27
- # with permission of Minero Aoki.
28
- #++
29
-
30
- module TMail
31
-
32
- class Config
33
-
34
- def initialize( strict )
35
- @strict_parse = strict
36
- @strict_base64decode = strict
37
- end
38
-
39
- def strict_parse?
40
- @strict_parse
41
- end
42
-
43
- attr_writer :strict_parse
44
-
45
- def strict_base64decode?
46
- @strict_base64decode
47
- end
48
-
49
- attr_writer :strict_base64decode
50
-
51
- def new_body_port( mail )
52
- StringPort.new
53
- end
54
-
55
- alias new_preamble_port new_body_port
56
- alias new_part_port new_body_port
57
-
58
- end
59
-
60
- DEFAULT_CONFIG = Config.new(false)
61
- DEFAULT_STRICT_CONFIG = Config.new(true)
62
-
63
- def Config.to_config( arg )
64
- return DEFAULT_STRICT_CONFIG if arg == true
65
- return DEFAULT_CONFIG if arg == false
66
- arg or DEFAULT_CONFIG
67
- end
68
-
69
- end
@@ -1,467 +0,0 @@
1
- #
2
- # encode.rb
3
- #
4
- #--
5
- # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
6
- #
7
- # Permission is hereby granted, free of charge, to any person obtaining
8
- # a copy of this software and associated documentation files (the
9
- # "Software"), to deal in the Software without restriction, including
10
- # without limitation the rights to use, copy, modify, merge, publish,
11
- # distribute, sublicense, and/or sell copies of the Software, and to
12
- # permit persons to whom the Software is furnished to do so, subject to
13
- # the following conditions:
14
- #
15
- # The above copyright notice and this permission notice shall be
16
- # included in all copies or substantial portions of the Software.
17
- #
18
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
19
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
21
- # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
22
- # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
23
- # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
24
- # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
- #
26
- # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
27
- # with permission of Minero Aoki.
28
- #++
29
-
30
- require 'nkf'
31
- require 'tmail/base64.rb'
32
- require 'tmail/stringio'
33
- require 'tmail/utils'
34
-
35
-
36
- module TMail
37
-
38
- module StrategyInterface
39
-
40
- def create_dest( obj )
41
- case obj
42
- when nil
43
- StringOutput.new
44
- when String
45
- StringOutput.new(obj)
46
- when IO, StringOutput
47
- obj
48
- else
49
- raise TypeError, 'cannot handle this type of object for dest'
50
- end
51
- end
52
- module_function :create_dest
53
-
54
- def encoded( eol = "\r\n", charset = 'j', dest = nil )
55
- accept_strategy Encoder, eol, charset, dest
56
- end
57
-
58
- def decoded( eol = "\n", charset = 'e', dest = nil )
59
- accept_strategy Decoder, eol, charset, dest
60
- end
61
-
62
- alias to_s decoded
63
-
64
- def accept_strategy( klass, eol, charset, dest = nil )
65
- dest ||= ''
66
- accept klass.new(create_dest(dest), charset, eol)
67
- dest
68
- end
69
-
70
- end
71
-
72
-
73
- ###
74
- ### MIME B encoding decoder
75
- ###
76
-
77
- class Decoder
78
-
79
- include TextUtils
80
-
81
- encoded = '=\?(?:iso-2022-jp|euc-jp|shift_jis)\?[QB]\?[a-z0-9+/=]+\?='
82
- ENCODED_WORDS = /#{encoded}(?:\s+#{encoded})*/i
83
-
84
- OUTPUT_ENCODING = {
85
- 'EUC' => 'e',
86
- 'SJIS' => 's',
87
- }
88
-
89
- def self.decode( str, encoding = nil )
90
- encoding ||= (OUTPUT_ENCODING[$KCODE] || 'j')
91
- opt = '-m' + encoding
92
- str.gsub(ENCODED_WORDS) {|s| NKF.nkf(opt, s) }
93
- end
94
-
95
- def initialize( dest, encoding = nil, eol = "\n" )
96
- @f = StrategyInterface.create_dest(dest)
97
- @encoding = (/\A[ejs]/ === encoding) ? encoding[0,1] : nil
98
- @eol = eol
99
- end
100
-
101
- def decode( str )
102
- self.class.decode(str, @encoding)
103
- end
104
- private :decode
105
-
106
- def terminate
107
- end
108
-
109
- def header_line( str )
110
- @f << decode(str)
111
- end
112
-
113
- def header_name( nm )
114
- @f << nm << ': '
115
- end
116
-
117
- def header_body( str )
118
- @f << decode(str)
119
- end
120
-
121
- def space
122
- @f << ' '
123
- end
124
-
125
- alias spc space
126
-
127
- def lwsp( str )
128
- @f << str
129
- end
130
-
131
- def meta( str )
132
- @f << str
133
- end
134
-
135
- def text( str )
136
- @f << decode(str)
137
- end
138
-
139
- def phrase( str )
140
- @f << quote_phrase(decode(str))
141
- end
142
-
143
- def kv_pair( k, v )
144
- @f << k << '=' << v
145
- end
146
-
147
- def puts( str = nil )
148
- @f << str if str
149
- @f << @eol
150
- end
151
-
152
- def write( str )
153
- @f << str
154
- end
155
-
156
- end
157
-
158
-
159
- ###
160
- ### MIME B-encoding encoder
161
- ###
162
-
163
- #
164
- # FIXME: This class can handle only (euc-jp/shift_jis -> iso-2022-jp).
165
- #
166
- class Encoder
167
-
168
- include TextUtils
169
-
170
- BENCODE_DEBUG = false unless defined?(BENCODE_DEBUG)
171
-
172
- def Encoder.encode( str )
173
- e = new()
174
- e.header_body str
175
- e.terminate
176
- e.dest.string
177
- end
178
-
179
- SPACER = "\t"
180
- MAX_LINE_LEN = 70
181
-
182
- OPTIONS = {
183
- 'EUC' => '-Ej -m0',
184
- 'SJIS' => '-Sj -m0',
185
- 'UTF8' => nil, # FIXME
186
- 'NONE' => nil
187
- }
188
-
189
- def initialize( dest = nil, encoding = nil, eol = "\r\n", limit = nil )
190
- @f = StrategyInterface.create_dest(dest)
191
- @opt = OPTIONS[$KCODE]
192
- @eol = eol
193
- reset
194
- end
195
-
196
- def normalize_encoding( str )
197
- if @opt
198
- then NKF.nkf(@opt, str)
199
- else str
200
- end
201
- end
202
-
203
- def reset
204
- @text = ''
205
- @lwsp = ''
206
- @curlen = 0
207
- end
208
-
209
- def terminate
210
- add_lwsp ''
211
- reset
212
- end
213
-
214
- def dest
215
- @f
216
- end
217
-
218
- def puts( str = nil )
219
- @f << str if str
220
- @f << @eol
221
- end
222
-
223
- def write( str )
224
- @f << str
225
- end
226
-
227
- #
228
- # add
229
- #
230
-
231
- def header_line( line )
232
- scanadd line
233
- end
234
-
235
- def header_name( name )
236
- add_text name.split(/-/).map {|i| i.capitalize }.join('-')
237
- add_text ':'
238
- add_lwsp ' '
239
- end
240
-
241
- def header_body( str )
242
- scanadd normalize_encoding(str)
243
- end
244
-
245
- def space
246
- add_lwsp ' '
247
- end
248
-
249
- alias spc space
250
-
251
- def lwsp( str )
252
- add_lwsp str.sub(/[\r\n]+[^\r\n]*\z/, '')
253
- end
254
-
255
- def meta( str )
256
- add_text str
257
- end
258
-
259
- def text( str )
260
- scanadd normalize_encoding(str)
261
- end
262
-
263
- def phrase( str )
264
- str = normalize_encoding(str)
265
- if CONTROL_CHAR === str
266
- scanadd str
267
- else
268
- add_text quote_phrase(str)
269
- end
270
- end
271
-
272
- # FIXME: implement line folding
273
- #
274
- def kv_pair( k, v )
275
- return if v.nil?
276
- v = normalize_encoding(v)
277
- if token_safe?(v)
278
- add_text k + '=' + v
279
- elsif not CONTROL_CHAR === v
280
- add_text k + '=' + quote_token(v)
281
- else
282
- # apply RFC2231 encoding
283
- kv = k + '*=' + "iso-2022-jp'ja'" + encode_value(v)
284
- add_text kv
285
- end
286
- end
287
-
288
- def encode_value( str )
289
- str.gsub(TOKEN_UNSAFE) {|s| '%%%02x' % s[0] }
290
- end
291
-
292
- private
293
-
294
- def scanadd( str, force = false )
295
- types = ''
296
- strs = []
297
-
298
- until str.empty?
299
- if m = /\A[^\e\t\r\n ]+/.match(str)
300
- types << (force ? 'j' : 'a')
301
- strs.push m[0]
302
-
303
- elsif m = /\A[\t\r\n ]+/.match(str)
304
- types << 's'
305
- strs.push m[0]
306
-
307
- elsif m = /\A\e../.match(str)
308
- esc = m[0]
309
- str = m.post_match
310
- if esc != "\e(B" and m = /\A[^\e]+/.match(str)
311
- types << 'j'
312
- strs.push m[0]
313
- end
314
-
315
- else
316
- raise 'TMail FATAL: encoder scan fail'
317
- end
318
- (str = m.post_match) unless m.nil?
319
- end
320
-
321
- do_encode types, strs
322
- end
323
-
324
- def do_encode( types, strs )
325
- #
326
- # result : (A|E)(S(A|E))*
327
- # E : W(SW)*
328
- # W : (J|A)+ but must contain J # (J|A)*J(J|A)*
329
- # A : <<A character string not to be encoded>>
330
- # J : <<A character string to be encoded>>
331
- # S : <<LWSP>>
332
- #
333
- # An encoding unit is `E'.
334
- # Input (parameter `types') is (J|A)(J|A|S)*(J|A)
335
- #
336
- if BENCODE_DEBUG
337
- puts
338
- puts '-- do_encode ------------'
339
- puts types.split(//).join(' ')
340
- p strs
341
- end
342
-
343
- e = /[ja]*j[ja]*(?:s[ja]*j[ja]*)*/
344
-
345
- while m = e.match(types)
346
- pre = m.pre_match
347
- concat_A_S pre, strs[0, pre.size] unless pre.empty?
348
- concat_E m[0], strs[m.begin(0) ... m.end(0)]
349
- types = m.post_match
350
- strs.slice! 0, m.end(0)
351
- end
352
- concat_A_S types, strs
353
- end
354
-
355
- def concat_A_S( types, strs )
356
- i = 0
357
- types.each_byte do |t|
358
- case t
359
- when ?a then add_text strs[i]
360
- when ?s then add_lwsp strs[i]
361
- else
362
- raise "TMail FATAL: unknown flag: #{t.chr}"
363
- end
364
- i += 1
365
- end
366
- end
367
-
368
- METHOD_ID = {
369
- ?j => :extract_J,
370
- ?e => :extract_E,
371
- ?a => :extract_A,
372
- ?s => :extract_S
373
- }
374
-
375
- def concat_E( types, strs )
376
- if BENCODE_DEBUG
377
- puts '---- concat_E'
378
- puts "types=#{types.split(//).join(' ')}"
379
- puts "strs =#{strs.inspect}"
380
- end
381
-
382
- flush() unless @text.empty?
383
-
384
- chunk = ''
385
- strs.each_with_index do |s,i|
386
- mid = METHOD_ID[types[i]]
387
- until s.empty?
388
- unless c = __send__(mid, chunk.size, s)
389
- add_with_encode chunk unless chunk.empty?
390
- flush
391
- chunk = ''
392
- fold
393
- c = __send__(mid, 0, s)
394
- raise 'TMail FATAL: extract fail' unless c
395
- end
396
- chunk << c
397
- end
398
- end
399
- add_with_encode chunk unless chunk.empty?
400
- end
401
-
402
- def extract_J( chunksize, str )
403
- size = max_bytes(chunksize, str.size) - 6
404
- size = (size % 2 == 0) ? (size) : (size - 1)
405
- return nil if size <= 0
406
- "\e$B#{str.slice!(0, size)}\e(B"
407
- end
408
-
409
- def extract_A( chunksize, str )
410
- size = max_bytes(chunksize, str.size)
411
- return nil if size <= 0
412
- str.slice!(0, size)
413
- end
414
-
415
- alias extract_S extract_A
416
-
417
- def max_bytes( chunksize, ssize )
418
- (restsize() - '=?iso-2022-jp?B??='.size) / 4 * 3 - chunksize
419
- end
420
-
421
- #
422
- # free length buffer
423
- #
424
-
425
- def add_text( str )
426
- @text << str
427
- # puts '---- text -------------------------------------'
428
- # puts "+ #{str.inspect}"
429
- # puts "txt >>>#{@text.inspect}<<<"
430
- end
431
-
432
- def add_with_encode( str )
433
- @text << "=?iso-2022-jp?B?#{Base64.encode(str)}?="
434
- end
435
-
436
- def add_lwsp( lwsp )
437
- # puts '---- lwsp -------------------------------------'
438
- # puts "+ #{lwsp.inspect}"
439
- fold if restsize() <= 0
440
- flush
441
- @lwsp = lwsp
442
- end
443
-
444
- def flush
445
- # puts '---- flush ----'
446
- # puts "spc >>>#{@lwsp.inspect}<<<"
447
- # puts "txt >>>#{@text.inspect}<<<"
448
- @f << @lwsp << @text
449
- @curlen += (@lwsp.size + @text.size)
450
- @text = ''
451
- @lwsp = ''
452
- end
453
-
454
- def fold
455
- # puts '---- fold ----'
456
- @f << @eol
457
- @curlen = 0
458
- @lwsp = SPACER
459
- end
460
-
461
- def restsize
462
- MAX_LINE_LEN - (@curlen + @lwsp.size + @text.size)
463
- end
464
-
465
- end
466
-
467
- end # module TMail