rumbster 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,52 @@
1
+ #
2
+ # base64.rb
3
+ #
4
+ # Copyright (c) 1998-2004 Minero Aoki
5
+ #
6
+ # This program is free software.
7
+ # You can distribute/modify this program under the terms of
8
+ # the GNU Lesser General Public License version 2.1.
9
+ #
10
+
11
+ module TMail
12
+
13
+ module Base64
14
+
15
+ module_function
16
+
17
+ def rb_folding_encode(str, eol = "\n", limit = 60)
18
+ [str].pack('m')
19
+ end
20
+
21
+ def rb_encode(str)
22
+ [str].pack('m').tr( "\r\n", '' )
23
+ end
24
+
25
+ def rb_decode(str, strict = false)
26
+ str.unpack('m')
27
+ end
28
+
29
+ begin
30
+ require 'tmail/base64.so'
31
+ alias folding_encode c_folding_encode
32
+ alias encode c_encode
33
+ alias decode c_decode
34
+ class << self
35
+ alias folding_encode c_folding_encode
36
+ alias encode c_encode
37
+ alias decode c_decode
38
+ end
39
+ rescue LoadError
40
+ alias folding_encode rb_folding_encode
41
+ alias encode rb_encode
42
+ alias decode rb_decode
43
+ class << self
44
+ alias folding_encode rb_folding_encode
45
+ alias encode rb_encode
46
+ alias decode rb_decode
47
+ end
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,39 @@
1
+ unless Enumerable.method_defined?(:map)
2
+ module Enumerable
3
+ alias map collect
4
+ end
5
+ end
6
+
7
+ unless Enumerable.method_defined?(:select)
8
+ module Enumerable
9
+ alias select find_all
10
+ end
11
+ end
12
+
13
+ unless Enumerable.method_defined?(:reject)
14
+ module Enumerable
15
+ def reject
16
+ result = []
17
+ each do |i|
18
+ result.push i unless yield(i)
19
+ end
20
+ result
21
+ end
22
+ end
23
+ end
24
+
25
+ unless Enumerable.method_defined?(:sort_by)
26
+ module Enumerable
27
+ def sort_by
28
+ map {|i| [yield(i), i] }.sort.map {|val, i| i }
29
+ end
30
+ end
31
+ end
32
+
33
+ unless File.respond_to?(:read)
34
+ def File.read(fname)
35
+ File.open(fname) {|f|
36
+ return f.read
37
+ }
38
+ end
39
+ end
@@ -0,0 +1,50 @@
1
+ #
2
+ # config.rb
3
+ #
4
+ # Copyright (c) 1998-2004 Minero Aoki
5
+ #
6
+ # This program is free software.
7
+ # You can distribute/modify this program under the terms of
8
+ # the GNU Lesser General Public License version 2.1.
9
+ #
10
+
11
+ module TMail
12
+
13
+ class Config
14
+
15
+ def initialize(strict)
16
+ @strict_parse = strict
17
+ @strict_base64decode = strict
18
+ end
19
+
20
+ def strict_parse?
21
+ @strict_parse
22
+ end
23
+
24
+ attr_writer :strict_parse
25
+
26
+ def strict_base64decode?
27
+ @strict_base64decode
28
+ end
29
+
30
+ attr_writer :strict_base64decode
31
+
32
+ def new_body_port(mail)
33
+ StringPort.new
34
+ end
35
+
36
+ alias new_preamble_port new_body_port
37
+ alias new_part_port new_body_port
38
+
39
+ end
40
+
41
+ DEFAULT_CONFIG = Config.new(false)
42
+ DEFAULT_STRICT_CONFIG = Config.new(true)
43
+
44
+ def Config.to_config(arg)
45
+ return DEFAULT_STRICT_CONFIG if arg == true
46
+ return DEFAULT_CONFIG if arg == false
47
+ arg or DEFAULT_CONFIG
48
+ end
49
+
50
+ end
@@ -0,0 +1,447 @@
1
+ #
2
+ # encode.rb
3
+ #
4
+ # Copyright (c) 1998-2004 Minero Aoki
5
+ #
6
+ # This program is free software.
7
+ # You can distribute/modify this program under the terms of
8
+ # the GNU Lesser General Public License version 2.1.
9
+ #
10
+
11
+ require 'nkf'
12
+ require 'tmail/base64.rb'
13
+ require 'tmail/stringio'
14
+ require 'tmail/textutils'
15
+
16
+
17
+ module TMail
18
+
19
+ module StrategyInterface
20
+
21
+ def create_dest(obj)
22
+ case obj
23
+ when nil
24
+ StringOutput.new
25
+ when String
26
+ StringOutput.new(obj)
27
+ when IO, StringOutput
28
+ obj
29
+ else
30
+ raise TypeError, 'cannot handle this type of object for dest'
31
+ end
32
+ end
33
+ module_function :create_dest
34
+
35
+ def encoded(eol = "\r\n", charset = 'j', dest = nil)
36
+ accept_strategy Encoder, eol, charset, dest
37
+ end
38
+
39
+ def decoded(eol = "\n", charset = 'e', dest = nil)
40
+ accept_strategy Decoder, eol, charset, dest
41
+ end
42
+
43
+ alias to_s decoded
44
+
45
+ def accept_strategy(klass, eol, charset, dest = nil)
46
+ dest ||= ''
47
+ accept klass.new(create_dest(dest), charset, eol)
48
+ dest
49
+ end
50
+
51
+ end
52
+
53
+
54
+ ###
55
+ ### MIME B encoding decoder
56
+ ###
57
+
58
+ class Decoder
59
+
60
+ include TextUtils
61
+
62
+ encoded = '=\?(?:iso-2022-jp|euc-jp|shift_jis)\?[QB]\?[a-z0-9+/=]+\?='
63
+ ENCODED_WORDS = /#{encoded}(?:\s+#{encoded})*/i
64
+
65
+ OUTPUT_ENCODING = {
66
+ 'EUC' => 'e',
67
+ 'SJIS' => 's',
68
+ }
69
+
70
+ def self.decode(str, encoding = nil)
71
+ encoding ||= (OUTPUT_ENCODING[$KCODE] || 'j')
72
+ opt = '-m' + encoding
73
+ str.gsub(ENCODED_WORDS) {|s| NKF.nkf(opt, s) }
74
+ end
75
+
76
+ def initialize(dest, encoding = nil, eol = "\n")
77
+ @f = StrategyInterface.create_dest(dest)
78
+ @encoding = (/\A[ejs]/ =~ encoding) ? encoding[0,1] : nil
79
+ @eol = eol
80
+ end
81
+
82
+ def decode(str)
83
+ self.class.decode(str, @encoding)
84
+ end
85
+ private :decode
86
+
87
+ def terminate
88
+ end
89
+
90
+ def header_line(str)
91
+ @f << decode(str)
92
+ end
93
+
94
+ def header_name(nm)
95
+ @f << nm << ': '
96
+ end
97
+
98
+ def header_body(str)
99
+ @f << decode(str)
100
+ end
101
+
102
+ def space
103
+ @f << ' '
104
+ end
105
+
106
+ alias spc space
107
+
108
+ def lwsp(str)
109
+ @f << str
110
+ end
111
+
112
+ def meta(str)
113
+ @f << str
114
+ end
115
+
116
+ def text(str)
117
+ @f << decode(str)
118
+ end
119
+
120
+ def phrase(str)
121
+ @f << quote_phrase(decode(str))
122
+ end
123
+
124
+ def kv_pair(k, v)
125
+ @f << k << '=' << v
126
+ end
127
+
128
+ def puts(str = nil)
129
+ @f << str if str
130
+ @f << @eol
131
+ end
132
+
133
+ def write(str)
134
+ @f << str
135
+ end
136
+
137
+ end
138
+
139
+
140
+ ###
141
+ ### MIME B-encoding encoder
142
+ ###
143
+
144
+ #
145
+ # FIXME: This class can handle only (euc-jp/shift_jis -> iso-2022-jp).
146
+ #
147
+ class Encoder
148
+
149
+ include TextUtils
150
+
151
+ BENCODE_DEBUG = false unless defined?(BENCODE_DEBUG)
152
+
153
+ def Encoder.encode(str)
154
+ e = new()
155
+ e.header_body str
156
+ e.terminate
157
+ e.dest.string
158
+ end
159
+
160
+ SPACER = "\t"
161
+ MAX_LINE_LEN = 70
162
+
163
+ OPTIONS = {
164
+ 'EUC' => '-Ej -m0',
165
+ 'SJIS' => '-Sj -m0',
166
+ 'UTF8' => nil, # FIXME
167
+ 'NONE' => nil
168
+ }
169
+
170
+ def initialize(dest = nil, encoding = nil, eol = "\r\n", limit = nil)
171
+ @f = StrategyInterface.create_dest(dest)
172
+ @opt = OPTIONS[$KCODE]
173
+ @eol = eol
174
+ reset
175
+ end
176
+
177
+ def normalize_encoding(str)
178
+ if @opt
179
+ then NKF.nkf(@opt, str)
180
+ else str
181
+ end
182
+ end
183
+
184
+ def reset
185
+ @text = ''
186
+ @lwsp = ''
187
+ @curlen = 0
188
+ end
189
+
190
+ def terminate
191
+ add_lwsp ''
192
+ reset
193
+ end
194
+
195
+ def dest
196
+ @f
197
+ end
198
+
199
+ def puts(str = nil)
200
+ @f << str if str
201
+ @f << @eol
202
+ end
203
+
204
+ def write(str)
205
+ @f << str
206
+ end
207
+
208
+ #
209
+ # add
210
+ #
211
+
212
+ def header_line(line)
213
+ scanadd line
214
+ end
215
+
216
+ def header_name(name)
217
+ add_text name.split(/-/).map {|i| i.capitalize }.join('-')
218
+ add_text ':'
219
+ add_lwsp ' '
220
+ end
221
+
222
+ def header_body(str)
223
+ scanadd normalize_encoding(str)
224
+ end
225
+
226
+ def space
227
+ add_lwsp ' '
228
+ end
229
+
230
+ alias spc space
231
+
232
+ def lwsp(str)
233
+ add_lwsp str.sub(/[\r\n]+[^\r\n]*\z/, '')
234
+ end
235
+
236
+ def meta(str)
237
+ add_text str
238
+ end
239
+
240
+ def text(str)
241
+ scanadd normalize_encoding(str)
242
+ end
243
+
244
+ def phrase(str)
245
+ str = normalize_encoding(str)
246
+ if CONTROL_CHAR =~ str
247
+ scanadd str
248
+ else
249
+ add_text quote_phrase(str)
250
+ end
251
+ end
252
+
253
+ # FIXME: implement line folding
254
+ #
255
+ def kv_pair(k, v)
256
+ v = normalize_encoding(v)
257
+ if token_safe?(v)
258
+ add_text k + '=' + v
259
+ elsif not CONTROL_CHAR =~ v
260
+ add_text k + '=' + quote_token(v)
261
+ else
262
+ # apply RFC2231 encoding
263
+ kv = k + '*=' + "iso-2022-jp'ja'" + encode_value(v)
264
+ add_text kv
265
+ end
266
+ end
267
+
268
+ def encode_value(str)
269
+ str.gsub(RFC2231_UNSAFE) {|s| '%%%02X' % s[0] }
270
+ end
271
+
272
+ private
273
+
274
+ def scanadd(str, force = false)
275
+ types = ''
276
+ strs = []
277
+
278
+ until str.empty?
279
+ if m = /\A[^\e\t\r\n ]+/.match(str)
280
+ types << (force ? 'j' : 'a')
281
+ strs.push m[0]
282
+
283
+ elsif m = /\A[\t\r\n ]+/.match(str)
284
+ types << 's'
285
+ strs.push m[0]
286
+
287
+ elsif m = /\A\e../.match(str)
288
+ esc = m[0]
289
+ str = m.post_match
290
+ if esc != "\e(B" and m = /\A[^\e]+/.match(str)
291
+ types << 'j'
292
+ strs.push m[0]
293
+ end
294
+
295
+ else
296
+ raise 'TMail FATAL: encoder scan fail'
297
+ end
298
+ str = m.post_match
299
+ end
300
+
301
+ do_encode types, strs
302
+ end
303
+
304
+ def do_encode(types, strs)
305
+ #
306
+ # result : (A|E)(S(A|E))*
307
+ # E : W(SW)*
308
+ # W : (J|A)+ but must contain J # (J|A)*J(J|A)*
309
+ # A : <<A character string not to be encoded>>
310
+ # J : <<A character string to be encoded>>
311
+ # S : <<LWSP>>
312
+ #
313
+ # An encoding unit is `E'.
314
+ # Input (parameter `types') is (J|A)(J|A|S)*(J|A)
315
+ #
316
+ if BENCODE_DEBUG
317
+ puts
318
+ puts '-- do_encode ------------'
319
+ puts types.split(//).join(' ')
320
+ p strs
321
+ end
322
+
323
+ e = /[ja]*j[ja]*(?:s[ja]*j[ja]*)*/
324
+
325
+ while m = e.match(types)
326
+ pre = m.pre_match
327
+ concat_A_S pre, strs[0, pre.size] unless pre.empty?
328
+ concat_E m[0], strs[m.begin(0) ... m.end(0)]
329
+ types = m.post_match
330
+ strs.slice! 0, m.end(0)
331
+ end
332
+ concat_A_S types, strs
333
+ end
334
+
335
+ def concat_A_S(types, strs)
336
+ i = 0
337
+ types.each_byte do |t|
338
+ case t
339
+ when ?a then add_text strs[i]
340
+ when ?s then add_lwsp strs[i]
341
+ else
342
+ raise "TMail FATAL: unknown flag: #{t.chr}"
343
+ end
344
+ i += 1
345
+ end
346
+ end
347
+
348
+ METHOD_ID = {
349
+ ?j => :extract_J,
350
+ ?e => :extract_E,
351
+ ?a => :extract_A,
352
+ ?s => :extract_S
353
+ }
354
+
355
+ def concat_E(types, strs)
356
+ if BENCODE_DEBUG
357
+ puts '---- concat_E'
358
+ puts "types=#{types.split(//).join(' ')}"
359
+ puts "strs =#{strs.inspect}"
360
+ end
361
+
362
+ flush() unless @text.empty?
363
+
364
+ chunk = ''
365
+ strs.each_with_index do |s,i|
366
+ mid = METHOD_ID[types[i]]
367
+ until s.empty?
368
+ unless c = __send__(mid, chunk.size, s)
369
+ add_with_encode chunk unless chunk.empty?
370
+ flush
371
+ chunk = ''
372
+ fold
373
+ c = __send__(mid, 0, s)
374
+ raise 'TMail FATAL: extract fail' unless c
375
+ end
376
+ chunk << c
377
+ end
378
+ end
379
+ add_with_encode chunk unless chunk.empty?
380
+ end
381
+
382
+ def extract_J(chunksize, str)
383
+ size = max_bytes(chunksize, str.size) - 6
384
+ size = (size % 2 == 0) ? (size) : (size - 1)
385
+ return nil if size <= 0
386
+ "\e$B#{str.slice!(0, size)}\e(B"
387
+ end
388
+
389
+ def extract_A(chunksize, str)
390
+ size = max_bytes(chunksize, str.size)
391
+ return nil if size <= 0
392
+ str.slice!(0, size)
393
+ end
394
+
395
+ alias extract_S extract_A
396
+
397
+ def max_bytes(chunksize, ssize)
398
+ (restsize() - '=?iso-2022-jp?B??='.size) / 4 * 3 - chunksize
399
+ end
400
+
401
+ #
402
+ # free length buffer
403
+ #
404
+
405
+ def add_text(str)
406
+ @text << str
407
+ # puts '---- text -------------------------------------'
408
+ # puts "+ #{str.inspect}"
409
+ # puts "txt >>>#{@text.inspect}<<<"
410
+ end
411
+
412
+ def add_with_encode(str)
413
+ @text << "=?iso-2022-jp?B?#{Base64.encode(str)}?="
414
+ end
415
+
416
+ def add_lwsp(lwsp)
417
+ # puts '---- lwsp -------------------------------------'
418
+ # puts "+ #{lwsp.inspect}"
419
+ fold if restsize() <= 0
420
+ flush
421
+ @lwsp = lwsp
422
+ end
423
+
424
+ def flush
425
+ # puts '---- flush ----'
426
+ # puts "spc >>>#{@lwsp.inspect}<<<"
427
+ # puts "txt >>>#{@text.inspect}<<<"
428
+ @f << @lwsp << @text
429
+ @curlen += (@lwsp.size + @text.size)
430
+ @text = ''
431
+ @lwsp = ''
432
+ end
433
+
434
+ def fold
435
+ # puts '---- fold ----'
436
+ @f << @eol
437
+ @curlen = 0
438
+ @lwsp = SPACER
439
+ end
440
+
441
+ def restsize
442
+ MAX_LINE_LEN - (@curlen + @lwsp.size + @text.size)
443
+ end
444
+
445
+ end
446
+
447
+ end # module TMail