Add the magic 'TO' header.

Checks both To: and Cc: as an OR, without needing to specify both in separate rules.

FossilOrigin-Name: e8cde0ba2d9b19089d80aeea455d6d6024cda477e206f567a379fd1b1d596815
This commit is contained in:
Mahlon E. Smith 2023-06-21 04:14:54 +00:00
parent 2952e2cbd7
commit f0221aac0a
4 changed files with 57 additions and 37 deletions

View file

@ -29,6 +29,9 @@ const CONFFILES = @[
]
### FIXME: generate default config?
#############################################################
# T Y P E S
#############################################################

View file

@ -113,7 +113,7 @@ proc newMessage*( dir: Maildir ): Message =
result.path = joinPath( result.dir.tmp, result.basename )
try:
debug "Opening new message at {result.path}".fmt
debug "Opening new message at:\n {result.path}".fmt
result.stream = openFileStream( result.path, fmWrite )
result.path.setFilePermissions( OWNERFILEPERMS )
except CatchableError as err:
@ -130,8 +130,8 @@ proc save*( msg: Message, dir=msg.dir ) =
## maildir, but can be provided a different one.
msg.stream.close
let newpath = joinPath( dir.new, msg.basename )
debug "Delivering message to {newpath}".fmt
msg.path.moveFile( newpath )
debug "Delivered message to:\n {newpath}".fmt
msg.dir = dir
msg.path = newpath
@ -139,8 +139,8 @@ proc save*( msg: Message, dir=msg.dir ) =
proc delete*( msg: Message ) =
## Remove a message from disk.
msg.stream.close
debug "Removing message at {msg.path}".fmt
msg.path.removeFile
debug "Removed message at:\n {msg.path}".fmt
msg.path = ""
@ -157,7 +157,7 @@ proc writeStdin*( msg: Message ): Message =
msg.stream.write( buf )
msg.stream.flush
msg.stream.close
debug "Wrote {total} bytes from stdin".fmt
debug "Wrote {total} bytes".fmt
proc filter*( orig_msg: Message, cmd: seq[string] ): Message =
@ -249,44 +249,58 @@ proc parseHeaders*( msg: Message ) =
( header, value ) = ( matches[0].toLower, matches[1] )
# FIXME: magic TO
proc walkRules*( 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
## if there was a valid match found.
msg.parseHeaders
result = false
msg.parseHeaders
for rule in rules:
var match = false
if rule.headers.len > 0: debug "Evaluating rule..."
block thisRule:
for header, regexp in rule.headers:
let header_chk = header.toLower
var hmatch = false
var
hmatch = false
headerlbl = header_chk
recipients: seq[ string ]
values: seq[ string ]
debug " checking header \"{header}\"".fmt
if msg.headers.hasKey( header_chk ):
for val in msg.headers[ header_chk ]:
try:
hmatch = val.match( regexp.re )
if hmatch:
debug " match on \"{regexp}\"".fmt
break # a single multi-header is sufficient
except RegexError as err:
debug " invalid regexp \"{regexp}\" ({err.msg}), skipping".fmt.replace( "\n", " " )
break thisRule
# Did any of the (possibly) multi-header values match?
if hmatch:
match = true
else:
debug " no match, skipping others"
break thisRule
# TO checks both To: and Cc: simultaneously.
#
if header == "TO":
headerlbl = "to|cc"
recipients = msg.headers.getOrDefault( "to", @[] ) &
msg.headers.getOrDefault( "cc", @[] )
debug " checking header \"{headerlbl}\"".fmt
if recipients.len > 0:
values = recipients
elif msg.headers.hasKey( header_chk ):
values = msg.headers[ header_chk ]
else:
debug " nonexistent header, skipping others"
break thisRule
for val in values:
try:
hmatch = val.match( regexp.re({reStudy,reIgnoreCase}) )
if hmatch:
debug " match on \"{regexp}\"".fmt
break # a single multi-header is sufficient
except RegexError as err:
debug " invalid regexp \"{regexp}\" ({err.msg}), skipping".fmt.replace( "\n", " " )
break thisRule
# Did any of the (possibly) multi-header values match?
if hmatch:
match = true
else:
debug " no match for \"{regexp}\", skipping others".fmt
break thisRule
result = match

View file

@ -9,6 +9,10 @@ import
lib/util
# TODO: logfile
# TODO: timer/performance
# TODO: more performant debug
# Without this, we got nuthin'!
if not existsEnv( "HOME" ):
deferral "Unable to determine HOME from environment."
@ -25,14 +29,14 @@ var msg = default.newMessage.writeStdin
# If there are "early rules", parse the message now and walk those.
if conf.early_rules.len > 0:
if msg.walkRules( conf.early_rules, default ): quit( 0 )
if msg.evalRules( conf.early_rules, default ): quit( 0 )
# Apply any configured global filtering.
for filter in conf.filter: msg = msg.filter( filter )
# Walk the rules, and if nothing hits, deliver to fallthrough.
if conf.rules.len > 0:
if not msg.walkRules( conf.rules, default ): msg.save
if not msg.evalRules( conf.rules, default ): msg.save
else:
msg.save