tmail/tmail/mails.rb
#
# mails.rb
#
# Copyright (c) 1999 Minero Aoki <aamine@dp.u-netsurf.ne.jp>
#
# This program is free software.
# You can distribute/modify this program under the terms of
# the GNU Lesser General Public License version 2 or later.
#
require 'racc/scanner'
begin
require 'tmail/mails.so'
rescue LoadError
module TMail
class MailScanner < Racc::Scanner
# mode
MODE_NONE = :MODE_NONE
MODE_822 = :MODE_822
MODE_MIME = :MODE_MIME
MODE_RECV = :MODE_RECV
def initialize( str, header, comments )
super( str )
@header = header
@comments = comments
@m_atom = :MODE_822
@m_recv = :MODE_NONE
case header
when 'CTypeH', 'CEncodingH', 'CDispositionH'
@m_atom = :MODE_MIME
when 'RecvH'
@m_recv = :MODE_RECV
end
end
# exp
atomchars = Regexp.quote( "\#!$%&`'*+{|}~^/=?" ) + '\\-'
tokenchars = Regexp.quote( "\#!$%&`'*+{|}~^." ) + '\\-'
eucchars = "\xa1\xa1-\xf3\xfe"
jisstr = "\\e..[^\\e]*\\e.."
ATOM = /\A[\w#{atomchars}#{eucchars}]+|#{jisstr}/o
TOKEN = /\A[\w#{tokenchars}#{eucchars}]+|#{jisstr}/o
DIGIT = /\A\d+\z/o
LWSP = /\A(?:\n|\r\n|\r)?[ \t]+/o
BACKSLASH = /\A\\/o
BEGIN_Q = /\A"/o
Q_ENT = /\A[^"\\\e]+|#{jisstr}/o
END_Q = /\A"/o
BEGIN_C = /\A\(/o
C_ENT = /\A[^\)\(\\\e]+|#{jisstr}/o
END_C = /\A\)/o
BEGIN_D = /\A\[/o
D_ENT = /\A[^\]\\]+|#{jisstr}/o
END_D = /\A\]/o
OMIT = '$omit'
def scan( ret )
sret = nil
vret = OMIT
until sret do
unless @scan.rest? then
sret = false; vret = false
break
end
@scan.skip LWSP
if @m_atom == :MODE_822 then
if vret = @scan.scan( ATOM ) then
sret = :ATOM
if DIGIT === vret then
sret = :DIGIT
vret = vret
elsif @m_recv = :MODE_RECV then
case vret.downcase
when 'from' then sret = :FROM
when 'by' then sret = :BY
when 'via' then sret = :VIA
when 'with' then sret = :WITH
when 'id' then sret = :ID
when 'for' then sret = :FOR
end
end
break
end
elsif @m_atom == :MODE_MIME then
if vret = @scan.scan( TOKEN ) then
sret = :TOKEN
break
end
else
bug! 'atom mode is not 822/MIME'
end
if @scan.skip( BEGIN_Q ) then
sret = :QUOTED
vret = quoted
elsif @scan.skip( BEGIN_C ) then
@comments.push comment if @comments
elsif @scan.skip( BEGIN_D ) then
sret = :DOMLIT
vret = domlit
else
sret = vret = @scan.getch
end
end
ret[0] = sret
ret[1] = vret
debug_report( ret ) if @debug
ret
end
private
def quoted
ret = ''
while true do
if temp = @scan.scan( Q_ENT ) then ret << temp
elsif @scan.skip( END_Q ) then break
elsif @scan.skip( BACKSLASH ) then ret << @scan.getch
else
unless @scan.rest? then
scan_error! "found unterminated quoted-string"
end
bug! 'in quoted, no match'
end
end
ret
end
def comment
ret = ''
nest = 1
while nest > 0 and @scan.rest? do
if temp = @scan.scan( C_ENT ) then ret << temp
elsif @scan.skip( END_C ) then nest -= 1
elsif @scan.skip( BEGIN_C ) then nest += 1
elsif @scan.skip( BACKSLASH ) then ret << @scan.getch
else
unless @scan.rest? then
scan_error! "found unterminated comment"
end
bug! 'in comment, no match'
end
end
if nest > 0 then
scan_error! "found unterminated comment"
end
ret
end
def domlit
ret = ''
while true do
if temp = @scan.scan( D_ENT ) then
ret << temp
end
if @scan.skip( END_D ) then break
elsif @scan.skip( BACKSLASH ) then ret << @scan.getch
else
unless @scan.rest? then
scan_error! "found unterminated domain literal"
end
bug! 'in domlit, no match'
end
end
ret
end
end
end # module TMail
end # mails.so not exist