Checkpoint.
- Use an optional logger (global) tied into debug() - Defer string interpolation for logging until we know we need it FossilOrigin-Name: 0b3e7b516a0fed2cd11fd49a5ce76fde2db36bffa30914b63f9940a4d79bb5f8
This commit is contained in:
parent
f0221aac0a
commit
d63a73a22a
6 changed files with 48 additions and 27 deletions
2
Makefile
2
Makefile
|
|
@ -11,7 +11,7 @@ dependencies:
|
||||||
|
|
||||||
development: ${FILES}
|
development: ${FILES}
|
||||||
# can use gdb with this...
|
# can use gdb with this...
|
||||||
nim --debugInfo --assertions:on --linedir:on -d:testing -d:nimTypeNames --nimcache:.cache c ${FILES}
|
nim --verbosity:2 --debugInfo --assertions:on --linedir:on -d:debug -d:nimTypeNames --nimcache:.cache c ${FILES}
|
||||||
mv src/sieb .
|
mv src/sieb .
|
||||||
|
|
||||||
debugger: ${FILES}
|
debugger: ${FILES}
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ logfile: sieb.log
|
||||||
early_rules:
|
early_rules:
|
||||||
-
|
-
|
||||||
headers:
|
headers:
|
||||||
TO: mahlon@(laika|ravn)
|
TO: mhlon@(laika|ravn)
|
||||||
received: .*sendgrid.*
|
received: .*sendgrid.*
|
||||||
filter:
|
filter:
|
||||||
- [ reformail, -A, "X-Sieb: This matched." ]
|
- [ reformail, -A, "X-Sieb: This matched." ]
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,6 @@ const CONFFILES = @[
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
### FIXME: generate default config?
|
|
||||||
|
|
||||||
|
|
||||||
#############################################################
|
#############################################################
|
||||||
# T Y P E S
|
# T Y P E S
|
||||||
#############################################################
|
#############################################################
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,7 @@ proc newMaildir*( path: string ): Maildir =
|
||||||
result.tmp = joinPath( path, "tmp" )
|
result.tmp = joinPath( path, "tmp" )
|
||||||
|
|
||||||
if not dirExists( path ):
|
if not dirExists( path ):
|
||||||
debug "Creating new maildir at {path}".fmt
|
"Creating new maildir at $#".debug( path )
|
||||||
try:
|
try:
|
||||||
for p in [ result.path, result.cur, result.new, result.tmp ]:
|
for p in [ result.path, result.cur, result.new, result.tmp ]:
|
||||||
p.createDir
|
p.createDir
|
||||||
|
|
@ -113,7 +113,7 @@ proc newMessage*( dir: Maildir ): Message =
|
||||||
result.path = joinPath( result.dir.tmp, result.basename )
|
result.path = joinPath( result.dir.tmp, result.basename )
|
||||||
|
|
||||||
try:
|
try:
|
||||||
debug "Opening new message at:\n {result.path}".fmt
|
"Opening new message at:\n $#".debug( result.path )
|
||||||
result.stream = openFileStream( result.path, fmWrite )
|
result.stream = openFileStream( result.path, fmWrite )
|
||||||
result.path.setFilePermissions( OWNERFILEPERMS )
|
result.path.setFilePermissions( OWNERFILEPERMS )
|
||||||
except CatchableError as err:
|
except CatchableError as err:
|
||||||
|
|
@ -131,7 +131,7 @@ proc save*( msg: Message, dir=msg.dir ) =
|
||||||
msg.stream.close
|
msg.stream.close
|
||||||
let newpath = joinPath( dir.new, msg.basename )
|
let newpath = joinPath( dir.new, msg.basename )
|
||||||
msg.path.moveFile( newpath )
|
msg.path.moveFile( newpath )
|
||||||
debug "Delivered message to:\n {newpath}".fmt
|
"Delivered message to:\n $#".debug( newpath )
|
||||||
msg.dir = dir
|
msg.dir = dir
|
||||||
msg.path = newpath
|
msg.path = newpath
|
||||||
|
|
||||||
|
|
@ -140,7 +140,7 @@ proc delete*( msg: Message ) =
|
||||||
## Remove a message from disk.
|
## Remove a message from disk.
|
||||||
msg.stream.close
|
msg.stream.close
|
||||||
msg.path.removeFile
|
msg.path.removeFile
|
||||||
debug "Removed message at:\n {msg.path}".fmt
|
"Removed message at:\n $#".debug( msg.path )
|
||||||
msg.path = ""
|
msg.path = ""
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -157,7 +157,7 @@ proc writeStdin*( msg: Message ): Message =
|
||||||
msg.stream.write( buf )
|
msg.stream.write( buf )
|
||||||
msg.stream.flush
|
msg.stream.flush
|
||||||
msg.stream.close
|
msg.stream.close
|
||||||
debug "Wrote {total} bytes".fmt
|
"Wrote $# bytes".debug( total )
|
||||||
|
|
||||||
|
|
||||||
proc filter*( orig_msg: Message, cmd: seq[string] ): Message =
|
proc filter*( orig_msg: Message, cmd: seq[string] ): Message =
|
||||||
|
|
@ -172,7 +172,7 @@ proc filter*( orig_msg: Message, cmd: seq[string] ): Message =
|
||||||
options = FILTERPROCOPTS
|
options = FILTERPROCOPTS
|
||||||
)
|
)
|
||||||
|
|
||||||
debug "Running filter: {cmd}".fmt
|
"Running filter: $#".debug( cmd )
|
||||||
# let process = cmd.startProcess( options = FILTERPROCOPTS )
|
# let process = cmd.startProcess( options = FILTERPROCOPTS )
|
||||||
|
|
||||||
# Read from the original message, write to the filter
|
# Read from the original message, write to the filter
|
||||||
|
|
@ -195,24 +195,24 @@ proc filter*( orig_msg: Message, cmd: seq[string] ): Message =
|
||||||
new_msg.stream.flush
|
new_msg.stream.flush
|
||||||
|
|
||||||
let exitcode = process.waitForExit
|
let exitcode = process.waitForExit
|
||||||
debug "Filter exited: {exitcode}".fmt
|
"Filter exited: $#".debug( exitcode )
|
||||||
process.close
|
process.close
|
||||||
if exitcode == 0:
|
if exitcode == 0:
|
||||||
new_msg.stream.close
|
new_msg.stream.close
|
||||||
orig_msg.delete
|
orig_msg.delete
|
||||||
result = new_msg
|
result = new_msg
|
||||||
else:
|
else:
|
||||||
debug "Unable to filter message: non-zero exit code".fmt
|
"Unable to filter message: non-zero exit code".debug
|
||||||
|
|
||||||
except OSError as err:
|
except OSError as err:
|
||||||
debug "Unable to filter message: {err.msg}".fmt
|
"Unable to filter message: $#".debug( err.msg )
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
proc parseHeaders*( msg: Message ) =
|
proc parseHeaders*( msg: Message ) =
|
||||||
## Walk the RFC2822 headers, placing them into memory.
|
## Walk the RFC2822 headers, placing them into memory.
|
||||||
## This 'unwraps' multiline headers, and allows for duplicate headers.
|
## This 'unwraps' multiline headers, and allows for duplicate headers.
|
||||||
debug "Parsing message headers."
|
let preparsed = not msg.headers.isNil
|
||||||
msg.headers = initTable[ string, seq[string] ]()
|
msg.headers = initTable[ string, seq[string] ]()
|
||||||
msg.open
|
msg.open
|
||||||
|
|
||||||
|
|
@ -248,6 +248,10 @@ proc parseHeaders*( msg: Message ) =
|
||||||
msg.headers[ header ] = @[ value ]
|
msg.headers[ header ] = @[ value ]
|
||||||
( header, value ) = ( matches[0].toLower, matches[1] )
|
( header, value ) = ( matches[0].toLower, matches[1] )
|
||||||
|
|
||||||
|
"Parsed message headers.".debug
|
||||||
|
if msg.headers.hasKey( "message-id" ):
|
||||||
|
"Message-ID is \"$#\"".debug( msg.headers[ "message-id" ] )
|
||||||
|
|
||||||
|
|
||||||
proc evalRules*( msg: var Message, rules: seq[Rule], default: Maildir ): bool =
|
proc evalRules*( msg: var Message, rules: seq[Rule], default: Maildir ): bool =
|
||||||
## Evaluate each rule against the Message, returning true
|
## Evaluate each rule against the Message, returning true
|
||||||
|
|
@ -258,7 +262,7 @@ proc evalRules*( msg: var Message, rules: seq[Rule], default: Maildir ): bool =
|
||||||
for rule in rules:
|
for rule in rules:
|
||||||
var match = false
|
var match = false
|
||||||
|
|
||||||
if rule.headers.len > 0: debug "Evaluating rule..."
|
if rule.headers.len > 0: "Evaluating rule...".debug
|
||||||
block thisRule:
|
block thisRule:
|
||||||
for header, regexp in rule.headers:
|
for header, regexp in rule.headers:
|
||||||
let header_chk = header.toLower
|
let header_chk = header.toLower
|
||||||
|
|
@ -275,37 +279,38 @@ proc evalRules*( msg: var Message, rules: seq[Rule], default: Maildir ): bool =
|
||||||
recipients = msg.headers.getOrDefault( "to", @[] ) &
|
recipients = msg.headers.getOrDefault( "to", @[] ) &
|
||||||
msg.headers.getOrDefault( "cc", @[] )
|
msg.headers.getOrDefault( "cc", @[] )
|
||||||
|
|
||||||
debug " checking header \"{headerlbl}\"".fmt
|
" checking header \"$#\"".debug( headerlbl )
|
||||||
if recipients.len > 0:
|
if recipients.len > 0:
|
||||||
values = recipients
|
values = recipients
|
||||||
elif msg.headers.hasKey( header_chk ):
|
elif msg.headers.hasKey( header_chk ):
|
||||||
values = msg.headers[ header_chk ]
|
values = msg.headers[ header_chk ]
|
||||||
else:
|
else:
|
||||||
debug " nonexistent header, skipping others"
|
" nonexistent header, skipping others".debug
|
||||||
break thisRule
|
break thisRule
|
||||||
|
|
||||||
for val in values:
|
for val in values:
|
||||||
try:
|
try:
|
||||||
hmatch = val.match( regexp.re({reStudy,reIgnoreCase}) )
|
hmatch = val.match( regexp.re({reStudy,reIgnoreCase}) )
|
||||||
if hmatch:
|
if hmatch:
|
||||||
debug " match on \"{regexp}\"".fmt
|
" match on \"$#\"".debug( regexp )
|
||||||
break # a single multi-header is sufficient
|
break # a single multi-header is sufficient
|
||||||
except RegexError as err:
|
except RegexError as err:
|
||||||
debug " invalid regexp \"{regexp}\" ({err.msg}), skipping".fmt.replace( "\n", " " )
|
let errmsg = err.msg.replace( "\n", " " )
|
||||||
|
" invalid regexp \"$#\" ($#), skipping".debug( regexp, errmsg )
|
||||||
break thisRule
|
break thisRule
|
||||||
|
|
||||||
# Did any of the (possibly) multi-header values match?
|
# Did any of the (possibly) multi-header values match?
|
||||||
if hmatch:
|
if hmatch:
|
||||||
match = true
|
match = true
|
||||||
else:
|
else:
|
||||||
debug " no match for \"{regexp}\", skipping others".fmt
|
" no match for \"$#\", skipping others".debug( regexp )
|
||||||
break thisRule
|
break thisRule
|
||||||
|
|
||||||
result = match
|
result = match
|
||||||
|
|
||||||
|
|
||||||
if result:
|
if result:
|
||||||
debug "Rule match!"
|
"Rule match!".debug
|
||||||
for filter in rule.filter: msg = msg.filter( filter )
|
for filter in rule.filter: msg = msg.filter( filter )
|
||||||
|
|
||||||
var deliver: Maildir
|
var deliver: Maildir
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,9 @@ import
|
||||||
std/terminal,
|
std/terminal,
|
||||||
std/strutils
|
std/strutils
|
||||||
|
|
||||||
|
import
|
||||||
|
logging
|
||||||
|
|
||||||
|
|
||||||
#############################################################
|
#############################################################
|
||||||
# C O N S T A N T S
|
# C O N S T A N T S
|
||||||
|
|
@ -68,9 +71,13 @@ proc deferral*( msg: string ) =
|
||||||
quit( 1 )
|
quit( 1 )
|
||||||
|
|
||||||
|
|
||||||
proc debug*( msg: string ) =
|
proc debug*( msg: string, args: varargs[string, `$`] ) =
|
||||||
## Emit +msg+ if debug mode is enabled.
|
## Emit +msg+ if debug mode is enabled, coercing arguments into a string for
|
||||||
if defined( testing ): echo msg
|
## formatting.
|
||||||
|
if defined( debug ) or not logger.closed:
|
||||||
|
var str = msg % args
|
||||||
|
if defined( debug ): echo str
|
||||||
|
if not logger.closed: str.log
|
||||||
|
|
||||||
|
|
||||||
proc parse_cmdline*: Opts =
|
proc parse_cmdline*: Opts =
|
||||||
|
|
@ -84,7 +91,7 @@ proc parse_cmdline*: Opts =
|
||||||
)
|
)
|
||||||
|
|
||||||
# always set debug mode if development build.
|
# always set debug mode if development build.
|
||||||
result.debug = defined( testing )
|
result.debug = defined( debug )
|
||||||
|
|
||||||
for kind, key, val in getopt():
|
for kind, key, val in getopt():
|
||||||
case kind
|
case kind
|
||||||
|
|
|
||||||
14
src/sieb.nim
14
src/sieb.nim
|
|
@ -5,13 +5,18 @@ import
|
||||||
|
|
||||||
import
|
import
|
||||||
lib/config,
|
lib/config,
|
||||||
|
lib/logging,
|
||||||
lib/message,
|
lib/message,
|
||||||
lib/util
|
lib/util
|
||||||
|
|
||||||
|
# /home/mahlon/repo/sieb/src/sieb.nim(30) sieb
|
||||||
|
# /home/mahlon/.choosenim/toolchains/nim-1.6.10/lib/system/io.nim(759) open
|
||||||
|
# Error: unhandled exception: cannot open: /home/mahlon/ [IOError]
|
||||||
|
|
||||||
# TODO: logfile
|
|
||||||
# TODO: timer/performance
|
# TODO: timer/performance
|
||||||
# TODO: more performant debug
|
# TODO: more performant debug
|
||||||
|
# TODO: generate default config?
|
||||||
|
|
||||||
|
|
||||||
# Without this, we got nuthin'!
|
# Without this, we got nuthin'!
|
||||||
if not existsEnv( "HOME" ):
|
if not existsEnv( "HOME" ):
|
||||||
|
|
@ -23,6 +28,13 @@ let
|
||||||
conf = get_config( opts.config )
|
conf = get_config( opts.config )
|
||||||
default = newMaildir( joinPath( home, "Maildir" ) )
|
default = newMaildir( joinPath( home, "Maildir" ) )
|
||||||
|
|
||||||
|
if conf.logfile != "":
|
||||||
|
createLogger( conf.logfile )
|
||||||
|
|
||||||
|
|
||||||
|
# FIXME: at exit?
|
||||||
|
# ... if logger not nil logger close
|
||||||
|
|
||||||
|
|
||||||
# Create a new message under Maildir/tmp, and stream stdin to it.
|
# Create a new message under Maildir/tmp, and stream stdin to it.
|
||||||
var msg = default.newMessage.writeStdin
|
var msg = default.newMessage.writeStdin
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue