commit e983cc675a9caf9cac14fb93a22b07aa5e4ca7ff
parent 5615a88c32b8d7ca131d133a51f8177f4bcc3cfa
Author: Jaromil <jaromil@dyne.org>
Date: Thu, 8 Jan 2015 19:12:44 +0100
several improvements to fetchaddr and email parsing and filtering
Diffstat:
8 files changed, 300 insertions(+), 168 deletions(-)
diff --git a/src/fetchaddr.c b/src/fetchaddr.c
@@ -56,6 +56,8 @@ void chop(struct header *cur)
cur->value[--cur->len] = '\0';
}
+char print_email_only = 0;
+
int writeout(struct header *h, const char *datefmt,
unsigned char create_real_name)
{
@@ -96,9 +98,12 @@ int writeout(struct header *h, const char *datefmt,
strftime(timebuf, sizeof(timebuf), datefmt, localtime(&timep));
- printf("%s,%s\n", p->mailbox,
- p->personal && *p->personal ? p->personal : " ");
-
+ if(print_email_only == 1) {
+ printf("%s\n", p->mailbox);
+ } else {
+ printf("%s,%s\n", p->mailbox,
+ p->personal && *p->personal ? p->personal : " ");
+ }
rv = 1;
}
}
@@ -137,6 +142,8 @@ int main(int argc, char* argv[])
#endif
} else if (!strcmp (argv[i], "-a")) {
create_real_name = 1;
+ } else if (!strcmp (argv[i], "-e")) {
+ print_email_only = 1;
} else {
fprintf (stderr, "%s: `%s' wrong parameter\n", argv[0], argv[i]);
}
diff --git a/src/jaro b/src/jaro
@@ -20,8 +20,8 @@
# this source code; if not, write to:
# Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-VERSION=2.1
-DATE=May/2014
+VERSION=3.0
+DATE=Jan/2015
JAROMAILEXEC=$0
typeset -a OLDARGS
for arg in ${argv}; do OLDARGS+=($arg); done
@@ -35,16 +35,22 @@ DRYRUN=0
CLEANEXIT=1
CALLMUTT=1
+# default permission on files
+umask 066
+
# global variables for binaries called
typeset -h rm mkdir mutt
+# load zsh regex module
+zmodload zsh/regex
+# zmodload zsh/mapfile
+
# date stamp
datestamp=`date '+%d%b%y'`
##########################
-# # # # SQL
-# command
+# SQL command
SQL=sqlite3
@@ -52,6 +58,9 @@ PARAM=()
typeset -A global_opts
typeset -A opts
+typeset -h global_quit
+global_quit=0
+
# global variable for account selection
typeset -h account account_type
# account=default
@@ -66,6 +75,10 @@ typeset -h host port type
# global variables for addressbook
typeset -h hostname addressbook addressbook_tmp
+# global variables for email parsers
+typeset -A e_addr
+typeset -h e_parsed
+
# global array for maildirs (filled by list_maildirs)
typeset -al maildirs
@@ -132,26 +145,6 @@ _tmp_create() {
return 0
}
-# Cleanup anything sensitive before exiting.
-_endgame() {
- # Clear temporary files
- for f in $JAROTMPFILES; do
- func "endgame() cleaning tempfile $f"
- rm -f "$f"
- done
- unset JAROTMPFILES
-}
-# Trap functions for the _endgame event
-TRAPINT() { _endgame INT }
-TRAPEXIT() { _endgame EXIT }
-TRAPHUP() { _endgame HUP }
-TRAPQUIT() { _endgame QUIT }
-TRAPABRT() { _endgame ABORT }
-TRAPKILL() { _endgame KILL }
-TRAPPIPE() { _endgame PIPE }
-TRAPTERM() { _endgame TERM }
-TRAPSTOP() { _endgame STOP }
-
# standard output message routines
# it's always useful to wrap them, in case we change behaviour later
notice() { if [[ $QUIET == 0 ]]; then print "$fg_bold[green][*]$fg_no_bold[default] $1" >&2; fi }
@@ -241,12 +234,12 @@ if [ -d $WORKDIR/zlibs ]; then
if [ "$WORKDIR" = "../src" ]; then
for z in `find $WORKDIR/zlibs -type f`; do
func "Loading zlib: ${z}"
- . ${z}
+ source ${z}
done
else
for z in `find $WORKDIR/zlibs -type f | grep -v '.zwc$'`; do
func "Loading zlib: ${z}"
- . ${z}
+ source ${z}
done
fi
act "full set of auxiliary functions loaded"
@@ -262,6 +255,36 @@ ACCOUNTS="$MAILDIRS/Accounts"
KEYRING="$MAILDIRS/Keyring"
+# Cleanup anything sensitive before exiting.
+_endgame() {
+ func "endgame() $1"
+ [[ "$1" = "EXIT" ]] || {
+ global_quit=1
+ sleep 2
+ }
+ # Clear temporary files
+ for f in $JAROTMPFILES; do
+ func "endgame() cleaning tempfile $f"
+ rm -f "$f"
+ done
+ JAROTMPFILES=()
+
+ [[ -e "$MAILDIRS"/cache/notmuch.lock ]] && {
+ func "unlocking notmuch/Xapian search cache"
+ unlock "$MAILDIRS"/cache/notmuch
+ }
+}
+# Trap functions for the _endgame event
+TRAPINT() { _endgame INT }
+TRAPEXIT() { _endgame EXIT }
+TRAPHUP() { _endgame HUP }
+TRAPQUIT() { _endgame QUIT }
+TRAPABRT() { _endgame ABORT }
+TRAPKILL() { _endgame KILL }
+TRAPPIPE() { _endgame PIPE }
+TRAPTERM() { _endgame TERM }
+TRAPSTOP() { _endgame STOP }
+
case $OS in
GNU)
# backward compatibility tests for old paths in JaroMail <1.3
@@ -652,6 +675,9 @@ main()
{ option_is_set -R } && { muttflags+=" -R " }
{ option_is_set -f } && { FORCE=1 }
+ # clean up options from param
+ PARAM=(${PARAM// -? /})
+
case "$subcommand" in
compose) compose ${PARAM} ;;
queue) queue ${PARAM} ;;
diff --git a/src/zlibs/addressbook b/src/zlibs/addressbook
@@ -61,29 +61,25 @@ insert_address() {
func "address already present in $list"
return 1
}
-
+
print "From: $_name <$_email>" | \
abook --datafile "$ADDRESSBOOK" \
- --add-email-quiet
-
- return 0
-}
+ --add-email-quiet > /dev/null
-remove_address() {
- error "remove_address() TODO in abook branch"
return 0
}
search_addressbook() {
func "search \"$@\" in $list"
- abook --datafile "$ADDRESSBOOK" --mutt-query "$@"
+ abook --datafile "$ADDRESSBOOK" --mutt-query "${@:l}"
}
lookup_email() {
- func "lookup address $1 in $list"
+ _addr=${1:l}
+ func "lookup address $_addr in $list"
abook --datafile "$ADDRESSBOOK" \
- --mutt-query "$1" > /dev/null
+ --mutt-query "$_addr" > /dev/null
return $?
}
@@ -124,8 +120,9 @@ sender_isknown() {
{ print $0 }
/^$/ { exit }' | ${WORKDIR}/bin/fetchaddr -x From -a`"
- email="${head[(ws:,:)1]}"
- [[ "$email" = "" ]] && { return 1 }
+ email="${head[(ws:,:)1]:l}"
+ isemail $email
+ [[ $? = 0 ]] || { return 1 }
abook --datafile $MAILDIRS/$list.abook \
--mutt-query "$email" > /dev/null
@@ -134,77 +131,71 @@ sender_isknown() {
learn() {
func "learning ${PARAM[1]} in stdin piped mails"
- [[ $DRYRUN == 1 ]] && {
- func "dryrun parsing ${PARAM[1]} in stdin piped mails" }
+ [[ $DRYRUN == 1 ]] && func "running in dryrun mode, no entries added to addressbook"
what=sender
[[ "$1" = "" ]] || { what="$1" }
func "learning from $what"
- # read in only headers from stdin (till empty line)
- buffer=`awk '{ print $0 } /^$/ { exit }'`
-
case ${what} in
sender|from) # simple: one address only on From:
- head="`print $buffer | ${WORKDIR}/bin/fetchaddr -x From -a`"
- # (Q) eliminates quotes, then word split
- email="${(Q)head[(ws:,:)1]}"
- name="${(Q)head[(ws:,:)2]}"
- print "$head"
- [[ $DRYRUN == 1 ]] || {
- insert_address "$email" "$name"
- [[ $? = 0 ]] && { act "new: $_name <${_email}>" }
+
+ # now e_name e_mail and e_parsed are filled in
+ awk '{ print $0 } /^$/ { exit }' | e_parse From
+
+ # no need to cycle, From is always only one field
+ [[ $DRYRUN == 0 ]] && {
+ _e="${(k)e_addr}"
+ _n="${(v)e_addr}"
+ insert_address "$_e" "$_n"
+ [[ $? = 0 ]] && { act "$list <- $_n <$_e>" }
}
return 0
;;
all)
- head="`print $buffer | ${WORKDIR}/bin/fetchaddr -a`"
- for h in ${(f)head}; do
- # (Q) eliminates quotes, then word split
- email="${(Q)h[(ws:,:)1]}"
- name="${(Q)h[(ws:,:)2]}"
- print "$h"
+ awk '{ print $0 } /^$/ { exit }' | e_parse
- [[ $DRYRUN == 1 ]] || {
- insert_address "$email" "$name"
- [[ $? = 0 ]] && { act "new: $_name <${_email}>" }
- }
- done
+ [[ $DRYRUN == 0 ]] && {
+ # complex: more addresses in To: and Cc:
+ for _e in ${(k)e_addr}; do
+ _n="${e_addr[$_e]}"
+ insert_address "$_e" "$_n"
+ [[ $? = 0 ]] && { act "$list <- $_n <${_e}>" }
+ done
+ }
return 0
;;
+
+ recipient|to)
- recipient|to) # complex: more addresses in To: and Cc:
- head="`print $buffer | ${WORKDIR}/bin/fetchaddr -x To -a`"
- for h in ${(f)head}; do
- # (Q) eliminates quotes, then word split
- email="${(Q)h[(ws:,:)1]}"
- name="${(Q)h[(ws:,:)2]}"
- print "$h"
-
- [[ $DRYRUN == 1 ]] || {
- insert_address "$email" "$name"
- [[ $? = 0 ]] && { act "new: $_name <${_email}>" }
- }
- done
+ awk '{ print $0 } /^$/ { exit }' | e_parse To
+
+ [[ $DRYRUN == 0 ]] && {
+ # complex: more addresses in To: and Cc:
+ for _e in ${(k)e_addr}; do
+ _n="${e_addr[$_e]}"
+ insert_address "$_e" "$_n"
+ [[ $? = 0 ]] && { act "$list <- $_n <${_e}>" }
+ done
+ }
- head="`print $buffer | ${WORKDIR}/bin/fetchaddr -x Cc -a`"
- for h in ${(f)head}; do
- # (Q) eliminates quotes, then word split
- email="${(Q)h[(ws:,:)1]}"
- name="${(Q)h[(ws:,:)2]}"
- print "$h"
+ e_parse Cc
+
+ [[ $DRYRUN == 0 ]] && {
+ # complex: more addresses in To: and Cc:
+ for _e in ${(k)e_addr}; do
+ _n="${e_addr[$_e]}"
+ insert_address "$_e" "$_n"
+ [[ $? = 0 ]] && { act "$list <- $_n <${_e}>" }
+ done
+ }
- [[ $DRYRUN == 1 ]] || {
- insert_address "$email" "$name"
- [[ $? = 0 ]] && { act "new: $_name <${_email}>" }
- }
- done
return 0
;;
-
+
*)
error "Unknown learning function: $what" ;;
esac
@@ -226,35 +217,45 @@ forget() {
# extract all addresses found in a list of email files from stdin
extract_mails() {
_mails=`cat`
- # we switch dryrun temporarily off to use learn()
- # without modifying the addressbook
- _dryrun=$DRYRUN
- DRYRUN=1
+
+ _tot=`print $_mails | wc -l`
+ act "$_tot emails to parse"
+
+ [[ $_tot -gt 100 ]] && {
+ act "operation will take a while, showing progress"
+ _prog=0
+ c=0
+ }
# learn from senders, recipients or all
_action="$1"
- typeset -a learned
+
+ # -U eliminates duplicates
+ typeset -aU _res
+
for m in ${(f)_mails}; do
- _l=`hdr $m | learn $_action`
- # handles results on multiple lines (recipients, all)
- for ii in ${(f)_l}; do
- learned+=("$ii")
- done
- done
- DRYRUN=$_dryrun
- # eliminates duplicates
- typeset -A result
- for i in ${learned}; do
- _e=${i[(ws:,:)1]}
- [[ "${result[$_e]}" = "" ]] && {
- _n=${i[(ws:,:)2]}
- result+=("$_e" "$_n")
- print - "$_n <$_e>"
+ # e_parse fills in e_addr(map) and e_parsed(newline term str)
+ hdr $m | e_parse $_action
+ for _e in ${(k)e_addr}; do
+ _res+=("${(v)e_addr[$_e]} <$_e>")
+ done
+
+ [[ $_tot -gt 100 ]] && {
+ c=$(( $c + 1 ))
+ [[ $c -gt 99 ]] && {
+ _prog=$(( $_prog + $c ))
+ act "$_prog / $_tot processed so far"
+ c=1
+ }
}
done
- notice "${#result} addresses extracted"
+ # print out results
+ for r in $_res; do
+ print - $r
+ done
+ notice "${#_res} unique addresses extracted"
}
# extract all addresses found into a maildir
@@ -375,6 +376,9 @@ extract() {
# default is whitelist
arg=${PARAM[1]}
+
+ func "extract() arg: $arg (param: $PARAM)"
+
# no arg means print all entries from adressbook
[[ "$arg" = "" ]] && {
notice "Extracting all addresses in $list"
@@ -411,7 +415,7 @@ extract() {
_addrs=`gpg --list-keys --with-colons | awk -F: '{print $10}'`
for i in ${(f)_addrs}; do
_parsed=`print "From: $i" | ${WORKDIR}/bin/fetchaddr -a -x from`
- _e="${_parsed[(ws:,:)1]}"
+ _e="${_parsed[(ws:,:)1]:l}"
isemail "$_e"
[[ $? = 0 ]] || continue
# check if the email is not already parsed
@@ -438,7 +442,7 @@ extract() {
[[ "$_magic" =~ "PGP public key" ]] && {
notice "Extracting addresses from sigs on GPG key $arg"
_gpg="gpg --no-default-keyring --keyring $MAILDIRS/cache/pubkey.gpg --batch --with-colons"
- rm -f $MAILDIRS/cache/pubkey.gpg
+ ${=rm} $MAILDIRS/cache/pubkey.gpg
${=_gpg} --import "$arg"
# first make sure all unknown keys are imported
_addrs=`${=_gpg} --list-sigs | awk -F: '{print $5 " " $10}'`
@@ -452,7 +456,7 @@ extract() {
_addrs=`${=_gpg} --list-sigs | awk -F: '{print $10}'`
for i in ${(f)_addrs}; do
_parsed=`print "From: $i" | ${WORKDIR}/bin/fetchaddr -a -x from`
- _e="${_parsed[(ws:,:)1]}"
+ _e="${_parsed[(ws:,:)1]:l}"
isemail "$_e"
[[ $? = 0 ]] || continue
# check if the email is not already parsed
@@ -486,25 +490,27 @@ extract() {
# import address lists from stdin
import() {
-
- arg=${PARAM[1]}
- # remove options and trim
- arg=`trim ${arg//-?/}`
+ # case insensitive match
+ unsetopt CASE_MATCH
+
+ _arg=${PARAM[1]}
+
+ func "import() arg: $_arg (param: $PARAM)"
# a map to eliminate duplicates
typeset -AU result
- [[ "$arg" = "" ]] || {
- notice "Import address list from stdin into addressbook"
+ [[ "$_arg" = "" ]] && {
+ notice "Import address list from stdin into addressbook $list"
_stdin=`cat`
- print - $_stdin
_new=0
+ act "imported new entries will be printed on stdout"
for i in ${(f)_stdin}; do
# skip comments starting with #
[[ "$i[1]" = "#" ]] && continue
_parsed=`print - "From: $i" | ${WORKDIR}/bin/fetchaddr -a -x from`
- _e="${_parsed[(ws:,:)1]}"
+ _e="${_parsed[(ws:,:)1]:l}"
# check if is really an email
isemail "$_e"
@@ -529,10 +535,9 @@ import() {
continue
}
- act "import new entry: $_n <$_e>"
- [[ $DRYRUN = 0 ]] && {
- insert_address "$_e" "$_n"
- }
+ print - "$_n <$_e>"
+ [[ $DRYRUN = 0 ]] && insert_address "$_e" "$_n"
+
_new=$(( $_new + 1 ))
done
notice "Valid unique entries parsed: ${#result}"
@@ -540,9 +545,72 @@ import() {
return $?
}
+ [[ -r "$_arg" ]] && {
+ notice "Import address list from stdin into group file $arg"
+ act "parsing entries in group file"
+ _group=`cat $arg`
+ for i in ${(f)_group}; do
+ # skip comments starting with #
+ [[ "$i[1]" = "#" ]] && continue
+
+ _parsed=`print - "From: $i" | ${WORKDIR}/bin/fetchaddr -a -x from`
+ _e="${_parsed[(ws:,:)1]:l}"
+
+ # check if is really an email
+ isemail "$_e"
+ [[ $? = 0 ]] || {
+ func "not an email: $_e"
+ continue
+ }
+
+ # check if the email is a duplicate
+ [[ "${result[$_e]}" = "" ]] || {
+ func "duplicate email: $_e"
+ continue
+ }
+
+ _n="${_parsed[(ws:,:)2]}"
+ result+=("$_e" "$_n")
+ done
+
+ # imported all group file contents in results
+ notice "${#result} entries parsed in $arg"
+ act "reading entries from stdin, printing out new entries"
+
+ _stdin=`cat`
+ _new=0
+ for i in ${(f)_stdin}; do
+ # skip comments starting with #
+ [[ "$i[1]" = "#" ]] && continue
+
+ _parsed=`print - "From: $i" | ${WORKDIR}/bin/fetchaddr -a -x from`
+ _e="${_parsed[(ws:,:)1]:l}"
+
+ # check if is really an email
+ isemail "$_e"
+ [[ $? = 0 ]] || {
+ func "not an email: $_e"
+ continue
+ }
+
+ # check if the email is a duplicate
+ [[ "${result[$_e]}" = "" ]] || {
+ func "duplicate email: $_e"
+ continue
+ }
+
+ _n="${_parsed[(ws:,:)2]}"
+ result+=("$_e" "$_n")
+
+ print - "$_n <$_e>"
+ _new=$(( $_new + 1 ))
+ done
+ # TODO: overwrite group file with all entries
+ notice "Valid unique entries parsed: ${#result}"
+ act "new addresses found: ${_new}"
+
+ }
- # stdin
- notice "Importing addressbook from stdin list of addresses"
return 0
}
diff --git a/src/zlibs/email b/src/zlibs/email
@@ -265,7 +265,7 @@ send() {
# list mails to send
queue_outbox=`${=find} "${MAILDIRS}/outbox" -type f`
- queue_outbox_num=`${=find} "${MAILDIRS}/outbox" -type f|wc -l`
+ queue_outbox_num=`print $queue_outbox | wc -l`
{ test "$queue_outbox_num" = "0" } && {
act "Outbox is empty, no mails to send."
return 0 }
@@ -304,6 +304,12 @@ send() {
for qbody in ${(f)queue_outbox}; do
+ # clean interrupt
+ [[ $global_quit = 1 ]] && {
+ error "User break requested, interrupting operation"
+ break
+ }
+
# check if this is an anonymous mail
hdr "$qbody" | grep -i '^from: anon' > /dev/null
if [[ $? = 0 ]]; then
@@ -396,8 +402,7 @@ EOF
else
notice "Mail sent succesfully"
# whitelist those to whom we send mails
- cat "$qbody" | \
- "$WORKDIR/bin/jaro" -q learn recipient > /dev/null
+ hdr "$qbody" | learn recipient
cat "$qbody" | deliver sent
[[ $? = 0 ]] && { rm "$qbody" }
fi
diff --git a/src/zlibs/filters b/src/zlibs/filters
@@ -198,8 +198,8 @@ filter_maildir() {
return 1
}
- numm=`${=find} "$MAILDIRS/$mdinput" -maxdepth 2 -type f|wc -l`
mails=`${=find} "$MAILDIRS/$mdinput" -maxdepth 2 -type f`
+ numm=`print $mails | wc -l`
[[ $numm = 0 ]] && {
error "Nothing to filter inside maildir $mdinput"
@@ -210,6 +210,13 @@ filter_maildir() {
c=0
for m in ${(f)mails}; do
+
+ # clean interrupt
+ [[ $global_quit = 1 ]] && {
+ error "User break requested, interrupting operation"
+ break
+ }
+
match=0
c=$(($c + 1))
@@ -217,24 +224,24 @@ filter_maildir() {
hdr "$m" | sender_isknown
[[ $? = 0 ]] && {
[[ "$mdinput" = "zz.blacklist" ]] && {
- act "$c\t\t/ $numm"
+ act "$c\t/ $numm"
continue
}
cat "$m" | deliver zz.blacklist
[[ $? = 0 ]] && { rm "$m" }
- act "$c\t\t/ $numm\t\t-> zz.blacklist"
+ act "$c\t/ $numm\t-> zz.blacklist"
continue
}
hdr "$m" | awk '/Sender.*mailman-bounce/ { exit 1 }'
[[ $? = 0 ]] || {
[[ "$mdinput" = "zz.bounces" ]] && {
- act "$c\t\t/ $numm"
+ act "$c\t/ $numm"
continue
}
cat "$m" | deliver zz.bounces
[[ $? = 0 ]] && { rm "$m" }
- act "$c\t\t/ $numm\t\t-> zz.bounces"
+ act "$c\t/ $numm\t-> zz.bounces"
continue
}
@@ -245,20 +252,19 @@ filter_maildir() {
# run all filter regexps on the from: field
[[ "$ffrom" = "" ]] || {
- femail="${ffrom[(ws:,:)1]}"
+ femail="${ffrom[(ws:,:)1]:l}"
for exp in ${(k)filter_from}; do
if [[ "$femail" =~ "$exp" ]]; then
# if destination maildir is same as input, skip
[[ "${filter_from[$exp]}" = "$mdinput" ]] && {
- act "$c\t\t/ $numm"
+ act "$c\t/ $numm"
match=1
break
}
- act "$c\t\t/ $numm\t\t-> ${filter_from[$exp]}"
cat "$m" | deliver ${filter_from[$exp]}
if [[ $? = 0 ]]; then
- func "from filter match: $exp"
+ act "$c\t/ $numm\t-> ${filter_from[$exp]}"
match=1
rm "$m"
break
@@ -277,8 +283,8 @@ filter_maildir() {
typeset -alU ftos
# recompile the array of destination addresses
- ftos=(`hdr "$m" | ${WORKDIR}/bin/fetchaddr -x cc -a | cut -d, -f1`)
- ftos+=(`hdr "$m" | ${WORKDIR}/bin/fetchaddr -x to -a | cut -d, -f1`)
+ ftos=(`hdr "$m" | ${WORKDIR}/bin/fetchaddr -x cc -e`)
+ ftos+=(`hdr "$m" | ${WORKDIR}/bin/fetchaddr -x to -e`)
# run all filter regexps on the to: and cc: fields
{ test "$ftos" = "" } || {
@@ -288,15 +294,13 @@ filter_maildir() {
if [[ "$ft" =~ "$exp" ]]; then
# if destination maildir is same as input, skip
[[ "${filter_to[$exp]}" = "$mdinput" ]] && {
- act "$c\t\t/ $numm"
- func "same dir"
+ act "$c\t/ $numm"
match=1
break
}
- act "$c\t\t/ $numm\t\t-> ${filter_to[$exp]}"
cat "$m" | deliver ${filter_to[$exp]}
if [[ $? = 0 ]]; then
- func "to filter match: $exp"
+ act "$c\t/ $numm\t-> ${filter_to[$exp]}"
match=1
rm "$m"
break
@@ -322,24 +326,24 @@ filter_maildir() {
hdr "$m" | sender_isknown
[[ $? = 0 ]] && {
[[ "$mdinput" = "known" ]] && {
- act "$c\t\t/ $numm"
+ act "$c\t/ $numm"
continue
}
cat "$m" | deliver known
[[ $? = 0 ]] && { rm "$m" }
- act "$c\t\t/ $numm\t\t-> known"
+ act "$c\t/ $numm\t-> known"
continue
}
hdr "$m" | awk '/X-Spam-Flag.*YES/ { exit 1 }'
{ test $? = 0 } || {
[[ "$mdinput" = "zz.spam" ]] && {
- act "$c\t\t/ $numm"
+ act "$c\t/ $numm"
continue
}
cat "$m" | deliver zz.spam
[[ $? = 0 ]] && { rm "$m" }
- act "$c\t\t/ $numm\t\t-> zz.spam"
+ act "$c\t/ $numm\t-> zz.spam"
continue
}
@@ -349,14 +353,14 @@ filter_maildir() {
# check if destination address is in filter_own array
if [[ ${filter_own[(r)$f]} == ${f} ]] ; then
[[ "$mdinput" = "priv" ]] && {
- act "$c\t\t/ $numm"
+ act "$c\t/ $numm"
match=1
break
}
cat "$m" | deliver priv
[[ $? = 0 ]] && {
rm "$m";
- act "$c\t\t/ $numm\t\t-> priv"
+ act "$c\t/ $numm\t-> priv"
match=1
break
}
@@ -368,7 +372,7 @@ filter_maildir() {
hdr "$m" | ismailinglist
[[ $? = 0 ]] && {
[[ "$mdinput" = "unsorted.ml" ]] && {
- act "$c\t\t/ $numm"
+ act "$c\t/ $numm"
continue
}
cat "$m" | deliver unsorted.ml
@@ -378,9 +382,9 @@ filter_maildir() {
# if here then file to unsorted
if [ "$mdinput" = "unsorted" ]; then
- act "$c\t\t/ $numm"
+ act "$c\t/ $numm"
else
- act "$c\t\t/ $numm\t\t-> unsorted"
+ act "$c\t/ $numm\t-> unsorted"
cat "$m" | deliver unsorted
[[ $? = 0 ]] && { rm "$m" }
fi
@@ -402,7 +406,7 @@ update_mutt() {
func "lock: $dotlock"
${=mkdir} "$MUTTDIR"
${=mkdir} "$MUTTDIR"/cache
- rm -f "$MUTTDIR"/rc
+ ${=rm} "$MUTTDIR"/rc
gpgkey=""
# detect the default gpg key to always encrypt also to self
diff --git a/src/zlibs/helpers b/src/zlibs/helpers
@@ -41,14 +41,9 @@ awk '{ for (i=1;i<=NF;i++)
}
isemail() {
- [[ "$1" = "" ]] && {
- func "isemail() called on an empty string"
- return 1
- }
- print "$1" | \
- grep -E "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" \
- > /dev/null
- return $?
+ [[ "$1" -regex-match "\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,6}\b" ]] && return 0
+
+ return 1
}
ismailinglist() {
@@ -152,10 +147,36 @@ autostart() {
return 1
}
+e_parse() {
+ _arg=""
+ # optional second argument limits parsing to header fields
+ [[ "$1" = "" ]] || [[ "$1" = "all" ]] || _arg="-x $1"
+
+ # use RFC822 parser in fetchaddr
+ e_parsed=`${WORKDIR}/bin/fetchaddr ${=_arg} -a`
+
+ e_addr=()
+ for _p in ${(f)e_parsed}; do
+ _e="${(Q)_p[(ws:,:)1]:l}"
+ # check if an email address was found
+ isemail "$_e" && {
+ _n="${(Q)_p[(ws:,:)2]}"
+ # reformat output using comma as separator
+ e_addr+=("$_e" "$_n")
+ func "parsed: $_n <$_e>"
+ }
+ done
+
+ # no emails found
+ [[ ${#e_addr} = 0 ]] && return 1
+
+ return 0
+}
+
# short utility to print only mail headers
hdr() {
- { test -r "$1" } || {
+ [[ -r "$1" ]] || {
error "hdr() called on non existing file: $1"
return 1 }
awk '{ print $0 }
diff --git a/src/zlibs/maildirs b/src/zlibs/maildirs
@@ -256,13 +256,13 @@ deliver() {
}
_email=`cat`
- print "$_email" | ismailinglist
+ print - "$_email" | ismailinglist
[[ $? = 0 ]] && {
- print "$_email" | nm insert --folder="$dest" +filters +mailinglist
+ print - "$_email" | nm insert --folder="$dest" +filters +mailinglist
return $?
}
# anything else +filters
- print "$_email" | nm insert --folder="$dest" +filters
+ print - "$_email" | nm insert --folder="$dest" +filters
return $?
}
diff --git a/src/zlibs/search b/src/zlibs/search
@@ -41,6 +41,7 @@ nm() {
nm_setup() {
nm_dir="$MAILDIRS"/cache/notmuch
mkdir -p $nm_dir
+ lock $nm_dir
# setup the default tags for all new messages
deftags="$1"