commit 0e1e1e9cb2ff662780c3ab3a9131cf253844812e
parent 0857fed85fe514e1da491d3756b8e2df18d06a03
Author: Jaromil <jaromil@dyne.org>
Date:   Thu, 15 Jan 2015 13:59:47 +0100
filter delivery cleanup and optimizations, fixes to exitcodes and more code cleanups
Diffstat:
5 files changed, 207 insertions(+), 150 deletions(-)
diff --git a/src/jaro b/src/jaro
@@ -34,6 +34,9 @@ DEBUG=0
 DRYRUN=0
 CALLMUTT=1
 
+# use gnome-keyring for passwords on GNU systems
+GNOMEKEY=0
+
 # default permission on files
 umask 066
 
@@ -86,7 +89,7 @@ typeset -al maildirs
 typeset -h mutt pgpewrap dotlock
 
 # global variable for exit code
-typeset exitcode
+typeset -h exitcode
 # exitcode=0
 
 # global variable for infos on imap folder
@@ -255,10 +258,10 @@ KEYRING="$MAILDIRS/Keyring"
 
 
 # Cleanup anything sensitive before exiting.
-_endgame() {
+endgame() {
     func "endgame() $1"
-    [[ "$1" = "EXIT" ]] || {
-        error "QUIT signal sent to processes, waiting 2 seconds..."
+    [[ "$1" = "NOERRORS" ]] || {
+        error "$1 signal sent to processes, waiting to quit..."
         global_quit=1
         sleep 2
     }
@@ -274,17 +277,18 @@ _endgame() {
         unlock "$MAILDIRS"/cache/notmuch
     }
     func "endgame() exit code: $exitcode"
+    return $exitcode
 }
 # Trap functions for the _endgame event
-TRAPINT()  { _endgame INT;   return $exitcode }
-# TRAPEXIT() { _endgame EXIT;  return $exitcode }
-TRAPHUP()  { _endgame HUP;   return $exitcode }
-TRAPQUIT() { _endgame QUIT;  return $exitcode }
-TRAPABRT() { _endgame ABORT; return $exitcode }
-TRAPKILL() { _endgame KILL;  return $exitcode }
-TRAPPIPE() { _endgame PIPE;  return $exitcode }
-TRAPTERM() { _endgame TERM;  return $exitcode }
-TRAPSTOP() { _endgame STOP;  return $exitcode }
+TRAPINT()  { _endgame INT;   return $? }
+# TRAPEXIT() { _endgame EXIT;  return $? }
+TRAPHUP()  { _endgame HUP;   return $? }
+TRAPQUIT() { _endgame QUIT;  return $? }
+TRAPABRT() { _endgame ABORT; return $? }
+TRAPKILL() { _endgame KILL;  return $? }
+TRAPPIPE() { _endgame PIPE;  return $? }
+TRAPTERM() { _endgame TERM;  return $? }
+TRAPSTOP() { _endgame STOP;  return $? }
 # TRAPZERR() { func "function returns non-zero." }
 
 case $OS in
@@ -334,11 +338,6 @@ MUTTDIR="$MAILDIRS/.mutt"
     cp "$WORKDIR/Mutt.txt" "$MAILDIRS/Mutt.txt"
     notice "Default Mutt configuration template created" }
 
-# use gnome-keyring for passwords on GNU systems
-GNOMEKEY=0
-pidof gnome-keyring-daemon > /dev/null && {
-     act "using gnome-keyring to store secrets"
-     GNOMEKEY=1 }
 
 # binary programs recognition
 check_bin() {
@@ -354,47 +353,53 @@ check_bin() {
 
     # make sure a gnupg dir exists
     { test -r $HOME/.gnupg/pubring.gpg } || {
-    ${=mkdir} $HOME/.gnupg
-    touch $HOME/.gnupg/pubring.gpg
-    touch $HOME/.gnupg/secring.gpg
+        ${=mkdir} $HOME/.gnupg
+        touch $HOME/.gnupg/pubring.gpg
+        touch $HOME/.gnupg/secring.gpg
     }
 
     # which find command to use
     case $OS in
-    GNU) find="find -O3" ;;
-    MAC) find="gfind -O3" ;;
-    *) find="find"
+        GNU) find="find -O3" ;;
+        MAC) find="gfind -O3" ;;
+        *) find="find"
     esac
 
     # which wipe command to use
     if command -v wipe > /dev/null; then
-    rm="wipe -f -s -q -R /dev/urandom"
+        rm="wipe -f -s -q -R /dev/urandom"
     elif command -v srm > /dev/null; then
-    rm="srm -m"
+        rm="srm -m"
     else
-    rm="rm -f"
+        rm="rm -f"
     fi
     func "Rm binary: $rm"
 
     # which mutt binary to use
     if command -v mutt > /dev/null; then
-    # system-wite
-    mutt="mutt"
-    # TODO: check if this is also the location on Fedora
-    pgpewrap="/usr/lib/mutt/pgpewrap"
-    dotlock="mutt_dotlock"
+        # system-wite
+        mutt="mutt"
+        # TODO: check if this is also the location on Fedora
+        pgpewrap="/usr/lib/mutt/pgpewrap"
+        dotlock="mutt_dotlock"
     elif command -v mutt-jaro > /dev/null; then
-    # in-house compiled
-    mutt=mutt-jaro
-    pgpewrap=pgpewrap
-    dotlock=dotlock
+        # in-house compiled
+        mutt=mutt-jaro
+        pgpewrap=pgpewrap
+        dotlock=dotlock
     else
-    error "Cannot find Mutt. Please install it."
-    exit 1
+        error "Cannot find Mutt. Please install it."
+        exit 1
     fi
     func "Mutt binary: $mutt"
     # make sure there is always a muttpass file even if empty
     touch $MAILDIR/tmp/muttpass
+
+
+    pidof gnome-keyring-daemon > /dev/null && {
+        act "using gnome-keyring to store secrets"
+        GNOMEKEY=1 }
+    
     return 0
 }
 
@@ -513,17 +518,16 @@ EOF
 
 typeset -A subcommands_opts
 
-main()
-    {
+main() {
     ### Options configuration
     #Hi, dear developer! Are you trying to add a new subcommand, or to add some options?
     #Well, keep in mind that:
     # 1. An option CAN'T have differente meanings/behaviour in different subcommands.
     #    For example, "-s" means "size" and accept an argument. If you are tempted to add
     #    an option "-s" (that means, for example "silent", and doesn't accept an argument)
-    #              DON'T DO IT!
-    #     There are two reasons for that:
-    #       I. usability; user expect that "-s" is "size
+#              DON'T DO IT!
+        #     There are two reasons for that:
+        #       I. usability; user expect that "-s" is "size
     #       II. Option parsing WILL EXPLODE if you do this kind of bad things
     #               (it will say "option defined more than once, and he's right)
     main_opts=(a: -account=a l: -list=l q -quiet=q D -debug=D h -help=h v -version=v n -dry-run=n f -force=f)
@@ -592,9 +596,9 @@ main()
     ### Detect subcommand
     local -aU every_opts #every_opts behave like a set; that is, an array with unique elements
     for optspec in $subcommands_opts$main_opts; do
-    for opt in ${=optspec}; do
-        every_opts+=${opt}
-    done
+        for opt in ${=optspec}; do
+            every_opts+=${opt}
+        done
     done
     local -a oldstar
     oldstar=($argv)
@@ -602,9 +606,9 @@ main()
     unset discardme
     subcommand=$1
     if [[ -z $subcommand ]]; then
-    subcommand="__default"
+        subcommand="__default"
     fi
-
+    
     if [[ -z ${(k)subcommands_opts[$subcommand]} ]]; then
         # unknown command, pass it to autostart
         func "unknown command, autostart: $@"
@@ -619,7 +623,7 @@ main()
     
     argv=(${oldstar})
     unset oldstar
-
+    
     ### Parsing global + command-specific options
     # zsh magic: ${=string} will split to multiple arguments when spaces occur
     set -A cmd_opts ${main_opts} ${=subcommands_opts[$subcommand]}
@@ -685,8 +689,15 @@ main()
     PARAM=(${PARAM// -? /})
 
     case "$subcommand" in
-    compose) compose ${PARAM} ;;
-    queue)   queue ${PARAM} ;;
+
+    compose) compose ${PARAM}
+            exitcode=$?
+            ;;
+
+    queue)  queue ${PARAM}
+            exitcode=$?
+            ;;
+
     fetch)
         if [[ "$account" = "" ]]; then
             fetchall
@@ -695,10 +706,19 @@ main()
         fi
         filter_maildir incoming
         ;;
-    send)    send ${PARAM} ;; # was checking is_online
-    peek)    peek ${PARAM} ;; # was checking is_online
 
-    later|remember) cat | deliver remember ;;
+    send)   send ${PARAM}
+            exitcode=$?
+            ;;
+
+    peek)   peek ${PARAM}
+            exitcode=$?
+            ;;
+
+    later|remember)
+            cat | deliver remember
+            exitcode=$?
+            ;;
 
     update|init)
         init_inbox
@@ -709,21 +729,37 @@ main()
 
     help) usage ;;
 
-    index) nm_index ;;
+    index) nm_index
+           exitcode=$?
+           ;;
+
     search) search ${PARAM} ;;
+
     notmuch)
             notice "Command: notmuch ${PARAM}"
             nm ${PARAM}
+            exitcode=$?
             ;;
 
     stat) stats ${PARAM} ;;
 
-    complete) complete ${PARAM}       ;;
-    isknown) sender_isknown ${PARAM} ;;
-    learn)   learn ${PARAM}          ;;
-    forget)  forget ${PARAM}         ;;
 
-    import)  import ${PARAM} ;;
+    complete) complete ${PARAM}
+              exitcode=$?
+              ;;
+
+    isknown) sender_isknown ${PARAM}
+             exitcode=$?
+             ;;
+
+    learn)  learn ${PARAM}
+            exitcode=$?
+            ;;
+
+    import) import ${PARAM}
+            exitcode=$?
+            ;;
+
     "export")
             case "$PARAM" in
                 abook)
@@ -736,22 +772,35 @@ main()
             esac
             ;;
 
-    abook)   edit_abook ${PARAM}         ;;
+    abook)  edit_abook ${PARAM}
+            exitcode=$?
+            ;;
 
     edit|vim)   edit_file ${PARAM}    ;;
     open)       open_folder ${PARAM}  ;;
     preview)    preview_file ${PARAM} ;;
 
-    backup)  backup ${PARAM}  ;;
+    backup)  backup ${PARAM}
+            exitcode=$?
+            ;;
+
     rmdupes) rmdupes ${PARAM} ;;
     merge)   merge ${PARAM}   ;;
 
     filter)
         update_filters ${PARAM}
+        [[ $? = 0 ]] || {
+            error "error updating filters, operation aborted."
+            break
+        }
         filter_maildir ${PARAM}
+        exitcode=$?
         ;;
 
-    deliver) deliver ${PARAM} ;;
+    deliver)
+            deliver ${PARAM}
+            exitcode=$?
+            ;;
 
     passwd) new_password ;;
 
@@ -781,21 +830,19 @@ main()
             read_account $account
             ask_password
             bytes_total=`imap_get_size "$2"`
+            exitcode=$?
             notice "Size of account $login on $imap"
             act "$bytes_total bytes"
             mib_total=$(( $bytes_total / 1048576 ))
             act "$mib_total MB (MiB)"
-            exitcode=$?
             ;;
         listfolders)
             read_account $account
             ask_password
             folders=(`imap_list_folders`)
-            notice "List of folders for $login on $imap"
-            for f in $folders; do
-            print "$f"
-            done
             exitcode=$?
+            notice "List of folders for $login on $imap"
+            for f in $folders; do print "$f"; done
             ;;
         # interactive)
         #     read_account
@@ -821,7 +868,7 @@ main()
 
     smtp)
         smtp_send ${PARAM}
-        exitcode=$res
+        exitcode=$?
         ;;
 
     *) # unknown command, pass it to autostart
@@ -834,10 +881,12 @@ main()
         }
         ;;
     esac
+
+    return $exitcode
 }
 
 
 check_bin
 main $@
-_endgame EXIT
+endgame NOERRORS
 return $exitcode
diff --git a/src/zlibs/addressbook b/src/zlibs/addressbook
@@ -198,16 +198,6 @@ learn() {
 
 }
 
-forget() {
-    error "forget() TODO in abook branch"
-    return 0
-
-    # func "forget sender from mail in stdin"
-    # act "Expecting mail from stdin pipe"
-    # head="`${WORKDIR}/bin/fetchaddr -x From -a`"
-    # # forget the email part of the parsed head
-    # remove_address "${head[(ws:,:)1]}"
-}
 
 # extract all addresses found in a list of email files from stdin
 extract_mails() {
diff --git a/src/zlibs/email b/src/zlibs/email
@@ -138,8 +138,8 @@ fetch() {
     }
 
     # updates the notmuch configuration
-    # setup the unread default tag
     nm_setup unread
+    # setup :unread: as default tag
 
     notice "Fetching email for account ${account}"
 
diff --git a/src/zlibs/filters b/src/zlibs/filters
@@ -190,7 +190,8 @@ filter_maildir() {
         ownfilters=1
     }
 
-    [[ "$1" = "" ]] && { mdinput=incoming }
+    # default maildir to filter is incoming
+    mdinput=${1:-incoming}
 
     maildircheck "$MAILDIRS/$mdinput"
     [[ $? = 0 ]] || {
@@ -220,6 +221,19 @@ filter_maildir() {
         match=0
         c=$(($c + 1))
 
+        # check if its an empty file
+        _fsize=`stat -c '%s' "$m"`
+        [[ $_fsize = 0 ]] && {
+            act "$c\t/ $numm\t(empty)"
+            rm "$m"
+            continue
+        }
+
+        # parse if its a mailinglist
+        _md=0
+        hdr "$m" | ismailinglist
+        [[ $? = 0 ]] && _md=1
+
         list="blacklist"
         hdr "$m" | sender_isknown
         [[ $? = 0 ]] && {
@@ -248,28 +262,42 @@ filter_maildir() {
         [[ "$ownfilters" = "1" ]] && {
 
             func "processing through own filters"
-            ffrom=`hdr "$m" | ${WORKDIR}/bin/fetchaddr -x From -a`
 
             # run all filter regexps on the from: field
-            [[ "$ffrom" = "" ]] || {
-                femail="${ffrom[(ws:,:)1]:l}"
+            _dest=""
+            e_addr=()
+            hdr "$m" | e_parse From
+            [[ $? = 0 ]] && {
+                femail="${(k)e_addr}" # e_parse From hit is always one
                 for exp in ${(k)filter_from}; do
-
+                    
+                    # fuzzy match on a string (PCRE)
                     if [[ "$femail" =~ "$exp" ]]; then
+
+                        # retrieve the filter destination maildir
+                        _dest="${filter_from[$exp]}"
+
                         # if destination maildir is same as input, skip
-                        [[ "${filter_from[$exp]}" = "$mdinput" ]] && {
+                        [[ "$_dest" = "$mdinput" ]] && {
                             act "$c\t/ $numm"
                             match=1
                             break 
                         }
-                        cat "$m" | deliver ${filter_from[$exp]}
+
+                        # tag mailinglists
+                        if [[ $_md = 1 ]]; then
+                            cat "$m" | deliver "$_dest" "+filtered +mailinglist"
+                        else
+                            cat "$m" | deliver "$_dest" "+filtered"
+                        fi
+
                         if [[ $? = 0 ]]; then
-                            act "$c\t/ $numm\t-> ${filter_from[$exp]}"
+                            act "$c\t/ $numm\t-> $_dest\t(from $femail)"
                             match=1
                             rm "$m"
                             break
                         else
-                            error "Error filtering to maildir ${filter_from[$exp]}"
+                            error "Error filtering to maildir $_dest"
                             error "File: $m"
                             continue
                         fi
@@ -281,31 +309,43 @@ filter_maildir() {
                 }
             }
 
-            typeset -alU ftos
+            _dest=""
             # recompile the array of destination addresses
-            ftos=(`hdr "$m" | ${WORKDIR}/bin/fetchaddr -x cc -e`)
-            ftos+=(`hdr "$m" | ${WORKDIR}/bin/fetchaddr -x to -e`)
-
+            e_addr=()
+            hdr "$m" | e_parse To
+            hdr "$m" | e_parse Cc
             # run all filter regexps on the to: and cc: fields
-            { test "$ftos" = "" } || {
-                for ft in ${(f)ftos}; do
+            [[ $? = 0 ]] && {
+                for ft in ${(k)e_addr}; do
                     for exp in ${(k)filter_to}; do
-                        # special zsh parsing in PCRE (=~)
+                        
+                        # fuzzy match on a string (PCRE)
                         if [[ "$ft" =~ "$exp" ]]; then
+                            
+                            # retrieve the filter destination maildir
+                            _dest="${filter_to[$exp]}"
+                            
                             # if destination maildir is same as input, skip
-                            [[ "${filter_to[$exp]}" = "$mdinput" ]] && {
+                            [[ "$_dest" = "$mdinput" ]] && {
                                 act "$c\t/ $numm"
                                 match=1
                                 break
                             }
-                            cat "$m" | deliver ${filter_to[$exp]}
+
+                            # tag mailinglists
+                            if [[ $_md = 1 ]]; then
+                                cat "$m" | deliver "$_dest" "+filtered +mailinglist"
+                            else
+                                cat "$m" | deliver "$_dest" "+filtered"
+                            fi
+                            
                             if [[ $? = 0 ]]; then
-                                act "$c\t/ $numm\t-> ${filter_to[$exp]}"
+                                act "$c\t/ $numm\t-> $_dest\t(to $ft)"
                                 match=1
                                 rm "$m"
                                 break
                             else
-                                error "Error filtering to maildir ${filter_to[$exp]}"
+                                error "Error filtering to maildir $_dest"
                                 error "File: $m"
                                 continue
                             fi
@@ -329,7 +369,7 @@ filter_maildir() {
                 act "$c\t/ $numm"
                 continue
             }
-            cat "$m" | deliver known
+            cat "$m" | deliver known "+inbox +priv"
             [[ $? = 0 ]] && { rm "$m" }
             act "$c\t/ $numm\t-> known"
             continue
@@ -357,7 +397,7 @@ filter_maildir() {
                     match=1
                     break
                 }
-                cat "$m" | deliver priv
+                cat "$m" | deliver priv "+priv"
                 [[ $? = 0 ]] && {
                     rm "$m";
                     act "$c\t/ $numm\t-> priv"
@@ -368,14 +408,13 @@ filter_maildir() {
         done
         [[ $match = 1 ]] && continue
 
-        # parse if its an unknown mailinglist
-        hdr "$m" | ismailinglist
-        [[ $? = 0 ]] && {
+        # its an unkown mailinglist
+        [[ $_ml = 1 ]] && {
             [[ "$mdinput" = "unsorted.ml" ]] && {
                 act "$c\t/ $numm"
                 continue
             }
-            cat "$m" | deliver unsorted.ml
+            cat "$m" | deliver unsorted.ml "+unsorted +mailinglist"
             [[ $? = 0 ]] && { rm "$m" }
             continue
         }
@@ -385,7 +424,7 @@ filter_maildir() {
             act "$c\t/ $numm"
         else
             act "$c\t/ $numm\t-> unsorted"
-            cat "$m" | deliver unsorted
+            cat "$m" | deliver unsorted "+unsorted"
             [[ $? = 0 ]] && { rm "$m" }
         fi
 
diff --git a/src/zlibs/maildirs b/src/zlibs/maildirs
@@ -196,11 +196,9 @@ merge() {
 # important to return 1 on all errors
 # so that fetchmail does not deletes mail from server
 deliver() {
-    if [ "$1" = "" ]; then
-        dest="incoming"
-    else
-        dest="$1"
-    fi
+
+    # default destination is incoming
+    dest=${1:-incoming}
     
     # create destination maildir if not existing
     [[ -r "$MAILDIRS/$dest" ]] || {
@@ -217,52 +215,33 @@ deliver() {
 
     func "deliver to $dest"
     
-    # destinations excluded from notmuch indexing
-    [[ "$dest" = "outbox" ]] \
-        || [[ "$dest" =~ "^zz." ]] \
-        || [[ "$dest" = "incoming" ]] && {
-
-        base="`hostname`_jaro_`date +%Y-%m-%d_%H-%M-%S`_$RANDOM"        
-        
+    [[ "$2" = "" ]] && {
+        # no tag specified, plain delivery without indexing
+        ## destinations excluded from notmuch indexing
+        # for indexing rules see filter_maildir()
+        # [[ "$dest" = "outbox" ]] \
+        #     || [[ "$dest" =~ "^zz." ]] \
+        #     || [[ "$dest" = "incoming" ]] && {
+        base="`hostname`_jaro_`date +%Y-%m-%d_%H-%M-%S`_$RANDOM"                
         cat > "$MAILDIRS/$dest/new/$base"
         [[ $? = 0 ]] || {
-            error "Could not write email file into maildir $dest."
+            error "Could not deliver email file into maildir $dest"
             func "Returning error to caller."
             return 1
         }
         return 0
     }
-
+    
     #########
     # notmuch indexing from here
+    tags="$2"
+    func "indexing tags: $tags"
 
-    # tag +inbox
-    [[ "$dest" = "known" ]] \
-        || [[ "$dest" = "sent" ]] && {
-        cat | nm insert --folder="$dest" +inbox +priv
-        return $?
-    }
-
-    [[ "$dest" = "priv" ]] && {
-        cat | nm insert --folder="$dest" +priv
-        return $?
-    }
+    cat | nm insert --folder="$dest" ${=tags}
+    res=$?
+    [[ $res = 0 ]] || \
+        error "Could not deliver email file into maildir $dest with tags $tags"
+    
+    return $res
     
-    # tag +unsorted
-    [[ "$dest" = "unsorted" ]] \
-        || [[ "$dest" =~ "^lists." ]] && {
-        cat | nm insert --folder="$dest" +unsorted
-        return $?
-    }
-
-    _email=`cat`
-    print - "$_email" | ismailinglist
-    [[ $? = 0 ]] && {
-        print - "$_email" | nm insert --folder="$dest" +filters +mailinglist
-        return $?
-    }
-
-    # anything else +filters
-    print - "$_email" | nm insert --folder="$dest" +filters
-    return $?
 }