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:
parent
2952e2cbd7
commit
f0221aac0a
4 changed files with 57 additions and 37 deletions
17
config.yml
17
config.yml
|
|
@ -3,13 +3,13 @@
|
|||
#
|
||||
|
||||
# Default, no logging. Relative to homedir.
|
||||
#logfile: sieb.log
|
||||
logfile: sieb.log
|
||||
|
||||
## Rules tried before global filtering
|
||||
early_rules:
|
||||
-
|
||||
headers:
|
||||
to: mahlon@(laika|ravn)
|
||||
TO: mahlon@(laika|ravn)
|
||||
received: .*sendgrid.*
|
||||
filter:
|
||||
- [ reformail, -A, "X-Sieb: This matched." ]
|
||||
|
|
@ -17,7 +17,7 @@ early_rules:
|
|||
|
||||
## Filter message before additional rules.
|
||||
filter:
|
||||
- [ reformail, -A, "X-Sieb: That shit totally matched" ]
|
||||
- [ reformail, -A, "X-Sieb: Processed!" ]
|
||||
|
||||
## Ordered, top down, first match wins.
|
||||
## Headers are lowercased. Multiple matches are AND'ed.
|
||||
|
|
@ -25,12 +25,11 @@ filter:
|
|||
## Delivery default is ~/Maildir, any set value is an auto-created maildir under
|
||||
## that path.
|
||||
##
|
||||
# rules:
|
||||
# -
|
||||
# headers:
|
||||
# x-what: pcre-matcher
|
||||
# poonie: pcre-matcher
|
||||
# deliver: .whatever
|
||||
rules:
|
||||
-
|
||||
headers:
|
||||
x-sieb: global
|
||||
deliver: .whoas
|
||||
|
||||
# # Magic "TO" which means To: OR Cc:
|
||||
# -
|
||||
|
|
|
|||
|
|
@ -29,6 +29,9 @@ const CONFFILES = @[
|
|||
]
|
||||
|
||||
|
||||
### FIXME: generate default config?
|
||||
|
||||
|
||||
#############################################################
|
||||
# T Y P E S
|
||||
#############################################################
|
||||
|
|
|
|||
|
|
@ -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,26 +249,44 @@ 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 ]:
|
||||
# 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 )
|
||||
hmatch = val.match( regexp.re({reStudy,reIgnoreCase}) )
|
||||
if hmatch:
|
||||
debug " match on \"{regexp}\"".fmt
|
||||
break # a single multi-header is sufficient
|
||||
|
|
@ -280,11 +298,7 @@ proc walkRules*( msg: var Message, rules: seq[Rule], default: Maildir ): bool =
|
|||
if hmatch:
|
||||
match = true
|
||||
else:
|
||||
debug " no match, skipping others"
|
||||
break thisRule
|
||||
|
||||
else:
|
||||
debug " nonexistent header, skipping others"
|
||||
debug " no match for \"{regexp}\", skipping others".fmt
|
||||
break thisRule
|
||||
|
||||
result = match
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue