jaromail

a commandline tool to easily and privately handle your e-mail
git clone git://parazyd.org/jaromail.git
Log | Files | Refs | Submodules | README

commit 1ef2e876c146f857430f43589399f8d3a65faea1
parent 1c96a2c33cec3aa3b5face8314f2f771db7f3203
Author: Jaromil <jaromil@dyne.org>
Date:   Mon,  9 Nov 2015 12:09:20 +0100

Fixes to sslproto selection in fetchmail

and more cleanups affecting fetch, search and locking

Diffstat:
Mdoc/Accounts/default.txt | 8++++++--
Mdoc/jaromail-manual.org | 4++++
Msrc/jaro | 21++++++++++-----------
Msrc/zlibs/accounts | 5++++-
Msrc/zlibs/email | 23+++++++++++++----------
Msrc/zlibs/filters | 31+++++++++++++++++++------------
Msrc/zlibs/imap | 14++++++++++----
Msrc/zlibs/locking | 30+++++++++++++++++-------------
Msrc/zlibs/search | 9+++++++++
9 files changed, 92 insertions(+), 53 deletions(-)

diff --git a/doc/Accounts/default.txt b/doc/Accounts/default.txt @@ -33,9 +33,13 @@ auth plain # or kerberos, etc # Server certificate: check or ignore cert ignore -# Transport protocol: ssl, tls or plain -transport tls +# Possible values are '', 'SSL2' (not supported on all systems), +# 'SSL23', (use of these two values is discouraged and should only +# be used as a last resort) 'SSL3', and 'TLS1' (default). +# transport TLS1 +# Add a specific certificate file, checked before installed defaults +# certfile /path/to/my/private/cert # Options when fetching # to empty your mailbox you can use: fetchall flush diff --git a/doc/jaromail-manual.org b/doc/jaromail-manual.org @@ -845,6 +845,10 @@ If filters are updated or one desires to import a maildir into Jaro Mail processing it through its filters, the *filter* command is provided to (re)filter a maildir. First edit *Filters.txt* with matches for the to: (which includes cc:) and from: header fields, then run: +: jaro update + +To tell Jaro Mail to update its internal filters according to the modifications, and then: + : jaro filter my-old-maildir Beware that filtering is a lengthy operation, especially on big diff --git a/src/jaro b/src/jaro @@ -91,7 +91,7 @@ esac # global variables -vars+=(DEBUG QUIET DRYRUN CALLMUTT MAILDIRS) +vars+=(DEBUG QUIET DRYRUN CALLMUTT MAILDIRS WORKDIR) QUIET=${QUIET:-0} DEBUG=${DEBUG:-0} DRYRUN=${DRYRUN:-0} @@ -646,8 +646,10 @@ main() { fetch) account=${account:-default} - fetch ${PARAM} - filter_maildir incoming + fetch ${PARAM} && \ + update_filters && \ + filter_maildir incoming && \ + update_notmuch ;; send) send ${PARAM} @@ -675,14 +677,11 @@ main() { [[ -d $p ]] && MAILDIRS=$p done } - MAILDIRS=$MAILDIRS init_inbox - MAILDIRS=$MAILDIRS update_filters - MAILDIRS=$MAILDIRS update_mutt - MAILDIRS=$MAILDIRS update_sieve - isfound notmuch && { - MAILDIRS=$MAILDIRS nm_setup - MAILDIRS=$MAILDIRS nm new 2>&1 | grep -v '^Note: Ignoring' - } + init_inbox + update_filters + update_mutt + update_sieve + update_notmuch notice "Initialization completed in $MAILDIRS" act "configure accounts in $MAILDIRS/Accounts" ;; diff --git a/src/zlibs/accounts b/src/zlibs/accounts @@ -57,6 +57,7 @@ read_account() { /^port / { printf "port=\"%s\";", $2 } /^login/ { printf "login=\"%s\";", $2 } /^transport/ { printf "transport=\"%s\";", $2 } + /^certfile/ { printf "certfile=\"%s\";", $2 } /^imap_port/ { printf "imap_port=\"%s\";", $2 } /^smtp_port/ { printf "smtp_port=\"%s\";", $2 } /^auth/ { printf "auth=\"%s\";", $2 } @@ -84,7 +85,8 @@ read_account() { { test -z $name } && { name="$type" } { test -z $login } && { login="$email" } # usually email and login are the same { test -z $email } && { email="$login" } # so if one is specified, deduce the other - { test -z $transport } && { transport=plain } + { test -z $transport } && { transport=TLS1 } + { test -z $certfile } && { certfile="" } { test -z $imap_port } && { imap_port=143 } { test -z $smtp_port } && { smtp_port=25 } @@ -106,6 +108,7 @@ read_account() { func "smtp port: $smtp_port" func "trans: $transport" + func "certfile: $certfile" func "cert: $cert" func "auth: $auth" [[ "$password" = "" ]] || func "password: manually set" diff --git a/src/zlibs/email b/src/zlibs/email @@ -247,26 +247,27 @@ fetch() { fi - func "fetch folders: $folders" - - # add folder configuration - fmconf+=(" folder ${=folders} "); - - fmconf+=(" ${transport} warnings 3600 and wants mda \"jaro -q deliver\" ") - if [ "$cert" = "check" ]; then # we now use system-wide certs fmconf+=(" sslcertck ") # sslcertpath '$WORKDIR/certs' fi + fmconf+=(" sslproto ${transport} warnings 3600 and wants mda \"jaro -q deliver\" ") + fmconf+=(" antispam 571 550 501 554 ") [[ $accountopt =~ 'keep' ]] || { - error "planning to delete mails from server, account option: $accountopt" } + warning "planning to delete mails from server, account option: $accountopt" } + + func "fetch folders: $folders" + + # add folder configuration + fmconf+=(" folder ${=folders} "); # try login without doing anything - print "$fmconf" | fetchmail -c -f - + flog=("${(f)$(print "$fmconf" | fetchmail -v -c -f -)}") + res=$? # examine result case $res in @@ -285,8 +286,10 @@ fetch() { unset $fmconf return 1 ;; + 7) warning "Mailbox selection failed (${flog[${#flog}]#*\(}" + ;; *) - func "fetchmail returns $ret" ;; + func "fetchmail returns $res" ;; esac if [[ $DRYRUN = 0 ]]; then diff --git a/src/zlibs/filters b/src/zlibs/filters @@ -95,7 +95,7 @@ update_filters() { [[ -r "$ff" ]] && { rm -f "$ff" } newlock "$ff" - sysread -o 1 <<EOF >> "$ff" + cat <<EOF >> "$ff" # automatically generated by jaromail typeset -Al filter_from typeset -alU filter_own @@ -109,7 +109,9 @@ EOF /^#/ {next} /^./ { print $1 ";" $2 ";" $3 ";" $4 }' "$MAILDIRS/Filters.txt"` - # insert filter rules in the cache + # + func "insert filter rules in the cache" + for f in ${(f)ffilters}; do header="${f[(ws:;:)1]}" regexp="${f[(ws:;:)2]}" @@ -117,14 +119,14 @@ EOF destination="${f[(ws:;:)4]}" case $header in to) - sysread -o 1 <<EOF >> "$ff" + cat <<EOF >> "$ff" filter_to+=("${regexp}" "${destination}") EOF func "from: <${regexp}> -> ${destination}" maildirmake $MAILDIRS/$destination ;; from) - sysread -o 1 <<EOF >> "$ff" + cat <<EOF >> "$ff" filter_from+=("${regexp}" "${destination}") EOF func "to: <${regexp}> -> ${destination}" @@ -144,13 +146,15 @@ EOF # nm new # } - # compile the list of own addresses and aliases + # + func "compile the list of own addresses and aliases" + for i in `awk ' /^#/ { next } /^$/ { next } /^email/ { print $2 }' \ "$MAILDIRS"/Accounts/*`; do - sysread -o 1 <<EOF >> "$ff" + cat <<EOF >> "$ff" filter_own+=($i) EOF done @@ -159,15 +163,18 @@ EOF /^#/ { next } /^$/ { next } { print $1 }' "$MAILDIRS/Aliases.txt"`; do - sysread -o 1 <<EOF >> "$ff" + cat <<EOF >> "$ff" filter_own+=($i) EOF done } + # + func "unlocking and compiling the cache" + unlock "$ff" zcompile "$ff" - # recursive reload + func "recursive reload" source "$WORKDIR/zlibs/filters" return 0 } @@ -175,8 +182,8 @@ EOF filter_maildir() { fn filter_maildir - req=(MAILDIR) - ckreq + req=(MAILDIRS) + ckreq || return 1 # Makes glob matching case insensitive unsetopt CASE_MATCH @@ -528,7 +535,7 @@ EOF [[ "$gpgkey" = "" ]] || { # gpg special settings - sysread -o 1 <<EOF >> "$MAILDIRS/.mutt"/rc + cat <<EOF >> "$MAILDIRS/.mutt"/rc ## GnuPG specific settings # create a pgp/mime encrypted attachment set pgp_encrypt_only_command="gpgewrap gpg --batch --quiet --no-verbose --output - --encrypt --textmode --armor --always-trust --encrypt-to $gpgkey -- -r %r -- '%f'" @@ -542,7 +549,7 @@ EOF } # MUTT MAILCAP - sysread -o 1 <<EOF > $MAILDIRS/.mutt/mailcap + cat <<EOF > $MAILDIRS/.mutt/mailcap text/plain; iconv -f iso-8859-1 -t utf-8; test=charset=%{charset} \ && test x`echo \"$charset\" | tr a-z A-Z` = xISO-8859-1; copiousoutput text/plain; cat %s diff --git a/src/zlibs/imap b/src/zlibs/imap @@ -21,17 +21,23 @@ # Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. run_imap_query() { - if [ "$transport" = "plain" ]; then + fn run_imap_query + _trans=${transport:-plain} + case $_trans in + SSL*) _trans=ssl ;; + TLS*) _trans=tls ;; + esac + if [ "$_trans" = "plain" ]; then func "running plain imap query via netcat, no encryption" nc ${imap} ${imap_port} -q 10 2>&1 - elif [ "$transport" = "tls" ]; then + elif [ "$_trans" = "tls" ]; then func "running tls imap query via openssl, encrypted" openssl s_client -quiet -connect ${imap}:${imap_port} 2>&1 - elif [ "$transport" = "ssl" ]; then + elif [ "$_trans" = "ssl" ]; then func "running ssl imap query via openssl, encrypted" openssl s_client -starttls imap -quiet -connect ${imap}:${imap_port} 2>&1 else - error "unknown transport \"$transport\" for a imap query" + error "unknown transport \"$_trans\" for a imap query" fi } diff --git a/src/zlibs/locking b/src/zlibs/locking @@ -22,11 +22,12 @@ lock() { - fn "lock $@" + fn "lock $*" _file=$1 - req=(_file) - freq=($_file) - ckreq || return 1 + # can't use ckreq as that returns error on file empty + [[ -r "$_file" ]] || { + error "cannot unlock, file not existing: $_file" + return 1 } if helper.isfound dotlock; then dotlock=`command -v dotlock` @@ -56,10 +57,8 @@ lock() { } newlock() { # lock file, create if not existing - fn "newlock $@" + fn "newlock $*" _file="$1" - req=(_file) - ckreq || return 1 touch "$_file" chmod 600 "$_file" @@ -112,11 +111,13 @@ pidcheck() { # check if lock belongs to us } unlock() { - fn "unlock $@" + fn "unlock $*" _file="$1" - req=(_file) - ckreq || return 1 - + # can't use ckreq as that returns error on file empty + [[ -r "$_file" ]] || { + error "cannot unlock, file not existing: $_file" + return 1 } + pidcheck "$_file" [[ $? = 0 ]] || { return 1 } @@ -130,9 +131,12 @@ unlock() { } unlink() { # delete a file that we are locking - fn "unlink $@" + fn "unlink $*" _file="$1" - ckreq || return 1 + # can't use ckreq as that returns error on file empty + [[ -r "$_file" ]] || { + error "cannot unlock, file not existing: $_file" + return 1 } unlock "$_file" ${=rm} "$_file" diff --git a/src/zlibs/search b/src/zlibs/search @@ -104,6 +104,15 @@ nm_index() { notice "Indexing completed" } +update_notmuch() { + fn update_notmuch + + isfound notmuch && [[ -r $MAILDIRS/.notmuch/xapian ]] && { + notice "Updating notmuch indexes" + nm_setup + nm new 2>&1 | grep -v '^Note: Ignoring' + } +} search() { fn search ${=PARAM}