f2075502d88bda8119e20bc280994ab45cb6d46f
4 # Copyright (c) 1998-2003 Minero Aoki <aamine@loveruby.net>
6 # Permission is hereby granted, free of charge, to any person obtaining
7 # a copy of this software and associated documentation files (the
8 # "Software"), to deal in the Software without restriction, including
9 # without limitation the rights to use, copy, modify, merge, publish,
10 # distribute, sublicense, and/or sell copies of the Software, and to
11 # permit persons to whom the Software is furnished to do so, subject to
12 # the following conditions:
14 # The above copyright notice and this permission notice shall be
15 # included in all copies or substantial portions of the Software.
17 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
18 # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19 # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
20 # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
21 # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
22 # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
23 # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 # Note: Originally licensed under LGPL v2+. Using MIT license for Rails
26 # with permission of Minero Aoki.
29 require 'tmail/config'
45 atomsyms
= %q
[ _
#!$%&`'*+-{|}~^/=? ].strip
46 tokensyms
= %q
[ _
#!$%&`'*+-{|}~^@. ].strip
47 atomchars
= alnum
+ Regexp
.quote(atomsyms
)
48 tokenchars
= alnum
+ Regexp
.quote(tokensyms
)
49 iso2022str
= '\e(?!\(B)..(?:[^\e]+|\e(?!\(B)..)*\e\(B'
51 eucstr
= "(?:[\xa1-\xfe][\xa1-\xfe])+"
52 sjisstr
= "(?:[\x81-\x9f\xe0-\xef][\x40-\x7e\x80-\xfc])+"
53 utf8str
= "(?:[\xc0-\xdf][\x80-\xbf]|[\xe0-\xef][\x80-\xbf][\x80-\xbf])+"
55 quoted_with_iso2022
= /\A(?:[^\\\e"]+|#{iso2022str})+/n
56 domlit_with_iso2022
= /\A(?:[^\\\e\]]+|#{iso2022str})+/n
57 comment_with_iso2022
= /\A(?:[^\\\e()]+|#{iso2022str})+/n
59 quoted_without_iso2022
= /\A[^\\"]+/n
60 domlit_without_iso2022
= /\A[^\\\]]+/n
61 comment_without_iso2022
= /\A[^\\()]+/n
64 PATTERN_TABLE
['EUC'] =
66 /\A(?:[#{atomchars}]+|#{iso2022str}|#{eucstr})+/n
,
67 /\A(?:[#{tokenchars}]+|#{iso2022str}|#{eucstr})+/n
,
72 PATTERN_TABLE
['SJIS'] =
74 /\A(?:[#{atomchars}]+|#{iso2022str}|#{sjisstr})+/n
,
75 /\A(?:[#{tokenchars}]+|#{iso2022str}|#{sjisstr})+/n
,
80 PATTERN_TABLE
['UTF8'] =
82 /\A(?:[#{atomchars}]+|#{utf8str})+/n
,
83 /\A(?:[#{tokenchars}]+|#{utf8str})+/n
,
84 quoted_without_iso2022
,
85 domlit_without_iso2022
,
86 comment_without_iso2022
88 PATTERN_TABLE
['NONE'] =
91 /\A[#{tokenchars}]+/n
,
92 quoted_without_iso2022
,
93 domlit_without_iso2022
,
94 comment_without_iso2022
98 def initialize( str
, scantype
, comments
)
100 @comments = comments
|| []
104 @received = (scantype
== :RECEIVED)
105 @is_mime_header = MIME_HEADERS
[scantype
]
107 atom
, token
, @quoted_re, @domlit_re, @comment_re = PATTERN_TABLE
[TMail
.KCODE
]
108 @word_re = (MIME_HEADERS
[scantype
] ? token
: atom
)
117 printf
"%7d %-10s %s\n",
119 s
.respond_to
?(:id2name) ? s
.id2name
: s
.inspect
,
141 if skip(/\A[\n\r\t ]+/n
) # LWSP
145 if s
= readstr(@word_re)
153 yield [RECV_TOKEN
[s
.downcase
] || :ATOM, s
]
160 yield [:QUOTED, scan_quoted_word()]
163 yield [:DOMLIT, scan_domain_literal()]
166 @comments.push
scan_comment()
178 scan_qstr(@quoted_re, /\A"/, 'quoted-word')
181 def scan_domain_literal
182 '[' + scan_qstr(@domlit_re, /\A\]/, 'domain-literal') + ']'
185 def scan_qstr( pattern
, terminal
, type
)
188 if s
= readstr(pattern
) then result
<< s
189 elsif skip(terminal
) then return result
190 elsif skip(/\A\\/) then result
<< readchar()
192 raise "TMail FATAL: not match in #{type}"
195 scan_error
! "found unterminated #{type}"
201 content
= @comment_re
204 if s
= readstr(content
) then result
<< s
205 elsif skip(/\A\)/) then nest
-= 1
206 return result
if nest
== 0
208 elsif skip(/\A\(/) then nest
+= 1
210 elsif skip(/\A\\/) then result
<< readchar()
212 raise 'TMail FATAL: not match in comment'
215 scan_error
! 'found unterminated comment'
220 def init_scanner( str
)
233 if m
= re
.match(@src)
246 if m
= re
.match(@src)
254 def scan_error
!( msg
)
255 raise SyntaxError
, msg