rumbster 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,22 @@
1
+ #
2
+ # scanner.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 'tmail/textutils'
12
+
13
+ module TMail
14
+ require 'tmail/scanner_r.rb'
15
+ begin
16
+ raise LoadError, 'Turn off Ruby extention by user choice' if ENV['NORUBYEXT']
17
+ require 'tmail/scanner_c.so'
18
+ Scanner = Scanner_C
19
+ rescue LoadError
20
+ Scanner = Scanner_R
21
+ end
22
+ end
@@ -0,0 +1,243 @@
1
+ #
2
+ # scanner_r.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 'tmail/config'
12
+
13
+ module TMail
14
+
15
+ class Scanner_R
16
+
17
+ Version = '0.10.8'
18
+ Version.freeze
19
+
20
+ MIME_HEADERS = {
21
+ :CTYPE => true,
22
+ :CENCODING => true,
23
+ :CDISPOSITION => true
24
+ }
25
+
26
+ alnum = 'a-zA-Z0-9'
27
+ atomsyms = %q[ _#!$%&`'*+-{|}~^/=? ].strip
28
+ tokensyms = %q[ _#!$%&`'*+-{|}~^. ].strip
29
+
30
+ atomchars = alnum + Regexp.quote(atomsyms)
31
+ tokenchars = alnum + Regexp.quote(tokensyms)
32
+ iso2022str = '\e(?!\(B)..(?:[^\e]+|\e(?!\(B)..)*\e\(B'
33
+
34
+ eucstr = '(?:[\xa1-\xfe][\xa1-\xfe])+'
35
+ sjisstr = '(?:[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc])+'
36
+ utf8str = '(?:[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf])+'
37
+
38
+ quoted_with_iso2022 = /\A(?:[^\\\e"]+|#{iso2022str})+/n
39
+ domlit_with_iso2022 = /\A(?:[^\\\e\]]+|#{iso2022str})+/n
40
+ comment_with_iso2022 = /\A(?:[^\\\e()]+|#{iso2022str})+/n
41
+
42
+ quoted_without_iso2022 = /\A[^\\"]+/n
43
+ domlit_without_iso2022 = /\A[^\\\]]+/n
44
+ comment_without_iso2022 = /\A[^\\()]+/n
45
+
46
+ PATTERN_TABLE = {}
47
+ PATTERN_TABLE['EUC'] =
48
+ [
49
+ /\A(?:[#{atomchars}]+|#{iso2022str}|#{eucstr})+/n,
50
+ /\A(?:[#{tokenchars}]+|#{iso2022str}|#{eucstr})+/n,
51
+ quoted_with_iso2022,
52
+ domlit_with_iso2022,
53
+ comment_with_iso2022
54
+ ]
55
+ PATTERN_TABLE['SJIS'] =
56
+ [
57
+ /\A(?:[#{atomchars}]+|#{iso2022str}|#{sjisstr})+/n,
58
+ /\A(?:[#{tokenchars}]+|#{iso2022str}|#{sjisstr})+/n,
59
+ quoted_with_iso2022,
60
+ domlit_with_iso2022,
61
+ comment_with_iso2022
62
+ ]
63
+ PATTERN_TABLE['UTF8'] =
64
+ [
65
+ /\A(?:[#{atomchars}]+|#{utf8str})+/n,
66
+ /\A(?:[#{tokenchars}]+|#{utf8str})+/n,
67
+ quoted_without_iso2022,
68
+ domlit_without_iso2022,
69
+ comment_without_iso2022
70
+ ]
71
+ PATTERN_TABLE['NONE'] =
72
+ [
73
+ /\A[#{atomchars}]+/n,
74
+ /\A[#{tokenchars}]+/n,
75
+ quoted_without_iso2022,
76
+ domlit_without_iso2022,
77
+ comment_without_iso2022
78
+ ]
79
+
80
+
81
+ def initialize(str, scantype, comments)
82
+ init_scanner str
83
+ @comments = comments || []
84
+ @debug = false
85
+
86
+ # fix scanner mode
87
+ @received = (scantype == :RECEIVED)
88
+ @is_mime_header = MIME_HEADERS[scantype]
89
+
90
+ atom, token, @quoted_re, @domlit_re, @comment_re = PATTERN_TABLE[$KCODE]
91
+ @word_re = (MIME_HEADERS[scantype] ? token : atom)
92
+ end
93
+
94
+ attr_accessor :debug
95
+
96
+ def scan(&block)
97
+ if @debug
98
+ scan_main do |arr|
99
+ s, v = arr
100
+ printf "%7d %-10s %s\n",
101
+ rest_size(),
102
+ s.respond_to?(:id2name) ? s.id2name : s.inspect,
103
+ v.inspect
104
+ yield arr
105
+ end
106
+ else
107
+ scan_main(&block)
108
+ end
109
+ end
110
+
111
+ private
112
+
113
+ RECV_TOKEN = {
114
+ 'from' => :FROM,
115
+ 'by' => :BY,
116
+ 'via' => :VIA,
117
+ 'with' => :WITH,
118
+ 'id' => :ID,
119
+ 'for' => :FOR
120
+ }
121
+
122
+ def scan_main
123
+ until eof?
124
+ if skip(/\A[\n\r\t ]+/n) # LWSP
125
+ break if eof?
126
+ end
127
+
128
+ if s = readstr(@word_re)
129
+ if @is_mime_header
130
+ yield :TOKEN, s
131
+ else
132
+ # atom
133
+ if /\A\d+\z/ =~ s
134
+ yield :DIGIT, s
135
+ elsif @received
136
+ yield RECV_TOKEN[s.downcase] || :ATOM, s
137
+ else
138
+ yield :ATOM, s
139
+ end
140
+ end
141
+
142
+ elsif skip(/\A"/)
143
+ yield :QUOTED, scan_quoted_word()
144
+
145
+ elsif skip(/\A\[/)
146
+ yield :DOMLIT, scan_domain_literal()
147
+
148
+ elsif skip(/\A\(/)
149
+ @comments.push scan_comment()
150
+
151
+ else
152
+ c = readchar()
153
+ yield c, c
154
+ end
155
+ end
156
+
157
+ yield false, '$'
158
+ end
159
+
160
+ def scan_quoted_word
161
+ scan_qstr(@quoted_re, /\A"/, 'quoted-word')
162
+ end
163
+
164
+ def scan_domain_literal
165
+ '[' + scan_qstr(@domlit_re, /\A\]/, 'domain-literal') + ']'
166
+ end
167
+
168
+ def scan_qstr(pattern, terminal, type)
169
+ result = ''
170
+ until eof?
171
+ if s = readstr(pattern) then result << s
172
+ elsif skip(terminal) then return result
173
+ elsif skip(/\A\\/) then result << readchar()
174
+ else
175
+ raise "TMail FATAL: not match in #{type}"
176
+ end
177
+ end
178
+ scan_error! "found unterminated #{type}"
179
+ end
180
+
181
+ def scan_comment
182
+ result = ''
183
+ nest = 1
184
+ content = @comment_re
185
+
186
+ until eof?
187
+ if s = readstr(content) then result << s
188
+ elsif skip(/\A\)/) then nest -= 1
189
+ return result if nest == 0
190
+ result << ')'
191
+ elsif skip(/\A\(/) then nest += 1
192
+ result << '('
193
+ elsif skip(/\A\\/) then result << readchar()
194
+ else
195
+ raise 'TMail FATAL: not match in comment'
196
+ end
197
+ end
198
+ scan_error! 'found unterminated comment'
199
+ end
200
+
201
+ # string scanner
202
+
203
+ def init_scanner(str)
204
+ @src = str
205
+ end
206
+
207
+ def eof?
208
+ @src.empty?
209
+ end
210
+
211
+ def rest_size
212
+ @src.size
213
+ end
214
+
215
+ def readstr(re)
216
+ if m = re.match(@src)
217
+ @src = m.post_match
218
+ m[0]
219
+ else
220
+ nil
221
+ end
222
+ end
223
+
224
+ def readchar
225
+ readstr(/\A./)
226
+ end
227
+
228
+ def skip(re)
229
+ if m = re.match(@src)
230
+ @src = m.post_match
231
+ true
232
+ else
233
+ false
234
+ end
235
+ end
236
+
237
+ def scan_error!(msg)
238
+ raise SyntaxError, msg
239
+ end
240
+
241
+ end
242
+
243
+ end # module TMail
@@ -0,0 +1,256 @@
1
+ #
2
+ # stringio.rb
3
+ #
4
+ # Copyright (c) 1999-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
+ # $amstdId: stringio.rb,v 1.12 2004/02/20 00:31:14 aamine Exp $
11
+ #
12
+
13
+ class StringInput
14
+
15
+ include Enumerable
16
+
17
+ class << self
18
+ def new(str)
19
+ if block_given?
20
+ begin
21
+ f = super
22
+ yield f
23
+ ensure
24
+ f.close if f
25
+ end
26
+ else
27
+ super
28
+ end
29
+ end
30
+
31
+ alias open new
32
+ end
33
+
34
+ def initialize(str)
35
+ @src = str
36
+ @pos = 0
37
+ @closed = false
38
+ @lineno = 0
39
+ end
40
+
41
+ attr_reader :lineno
42
+
43
+ def string
44
+ @src
45
+ end
46
+
47
+ def inspect
48
+ "#<#{self.class}:#{@closed ? 'closed' : 'open'},src=#{@src[0,30].inspect}>"
49
+ end
50
+
51
+ def close
52
+ stream_check!
53
+ @pos = nil
54
+ @closed = true
55
+ end
56
+
57
+ def closed?
58
+ @closed
59
+ end
60
+
61
+ def pos
62
+ stream_check!
63
+ [@pos, @src.size].min
64
+ end
65
+
66
+ alias tell pos
67
+
68
+ def seek(offset, whence = IO::SEEK_SET)
69
+ stream_check!
70
+ case whence
71
+ when IO::SEEK_SET
72
+ @pos = offset
73
+ when IO::SEEK_CUR
74
+ @pos += offset
75
+ when IO::SEEK_END
76
+ @pos = @src.size - offset
77
+ else
78
+ raise ArgumentError, "unknown seek flag: #{whence}"
79
+ end
80
+ @pos = 0 if @pos < 0
81
+ @pos = [@pos, @src.size + 1].min
82
+ offset
83
+ end
84
+
85
+ def rewind
86
+ stream_check!
87
+ @pos = 0
88
+ end
89
+
90
+ def eof?
91
+ stream_check!
92
+ @pos > @src.size
93
+ end
94
+
95
+ def each(&block)
96
+ stream_check!
97
+ begin
98
+ @src.each(&block)
99
+ ensure
100
+ @pos = 0
101
+ end
102
+ end
103
+
104
+ def gets
105
+ stream_check!
106
+ if idx = @src.index(?\n, @pos)
107
+ idx += 1 # "\n".size
108
+ line = @src[ @pos ... idx ]
109
+ @pos = idx
110
+ @pos += 1 if @pos == @src.size
111
+ else
112
+ line = @src[ @pos .. -1 ]
113
+ @pos = @src.size + 1
114
+ end
115
+ @lineno += 1
116
+
117
+ line
118
+ end
119
+
120
+ def getc
121
+ stream_check!
122
+ ch = @src[@pos]
123
+ @pos += 1
124
+ @pos += 1 if @pos == @src.size
125
+ ch
126
+ end
127
+
128
+ def read(len = nil)
129
+ stream_check!
130
+ return read_all() unless len
131
+ str = @src[@pos, len]
132
+ @pos += len
133
+ @pos += 1 if @pos == @src.size
134
+ str
135
+ end
136
+
137
+ alias sysread read
138
+
139
+ def read_all
140
+ stream_check!
141
+ return nil if eof?
142
+ rest = @src[@pos ... @src.size]
143
+ @pos = @src.size + 1
144
+ rest
145
+ end
146
+
147
+ def stream_check!
148
+ @closed and raise IOError, 'closed stream'
149
+ end
150
+
151
+ end
152
+
153
+
154
+ class StringOutput
155
+
156
+ class << self
157
+ def new(str = '')
158
+ if block_given?
159
+ begin
160
+ f = super
161
+ yield f
162
+ ensure
163
+ f.close if f
164
+ end
165
+ else
166
+ super
167
+ end
168
+ end
169
+
170
+ alias open new
171
+ end
172
+
173
+ def initialize(str = '')
174
+ @dest = str
175
+ @closed = false
176
+ end
177
+
178
+ def close
179
+ @closed = true
180
+ end
181
+
182
+ def closed?
183
+ @closed
184
+ end
185
+
186
+ def string
187
+ @dest
188
+ end
189
+
190
+ alias value string
191
+ alias to_str string
192
+
193
+ def size
194
+ @dest.size
195
+ end
196
+
197
+ alias pos size
198
+
199
+ def inspect
200
+ "#<#{self.class}:#{@dest ? 'open' : 'closed'},#{id}>"
201
+ end
202
+
203
+ def print(*args)
204
+ stream_check!
205
+ raise ArgumentError, 'wrong # of argument (0 for >1)' if args.empty?
206
+ args.each do |s|
207
+ raise ArgumentError, 'nil not allowed' if s.nil?
208
+ @dest << s.to_s
209
+ end
210
+ nil
211
+ end
212
+
213
+ def puts(*args)
214
+ stream_check!
215
+ args.each do |str|
216
+ @dest << (s = str.to_s)
217
+ @dest << "\n" unless s[-1] == ?\n
218
+ end
219
+ @dest << "\n" if args.empty?
220
+ nil
221
+ end
222
+
223
+ def putc(ch)
224
+ stream_check!
225
+ @dest << ch.chr
226
+ nil
227
+ end
228
+
229
+ def printf(*args)
230
+ stream_check!
231
+ @dest << sprintf(*args)
232
+ nil
233
+ end
234
+
235
+ def write(str)
236
+ stream_check!
237
+ s = str.to_s
238
+ @dest << s
239
+ s.size
240
+ end
241
+
242
+ alias syswrite write
243
+
244
+ def <<(str)
245
+ stream_check!
246
+ @dest << str.to_s
247
+ self
248
+ end
249
+
250
+ private
251
+
252
+ def stream_check!
253
+ @closed and raise IOError, 'closed stream'
254
+ end
255
+
256
+ end