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 4441325aa6ee9e6f9e9b982ca7032d7501c3e99f
parent 483b0da4d14b2fada3e58b3e5dbf2450b194cd0a
Author: Jaromil <jaromil@dyne.org>
Date:   Sun, 17 Jun 2012 14:57:22 +0200

search and backup improvements (intuitive args) and better stats

Diffstat:
Msrc/jaro | 263+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------
1 file changed, 219 insertions(+), 44 deletions(-)

diff --git a/src/jaro b/src/jaro @@ -448,6 +448,25 @@ option_value() { #First argument, the option (something like "-s") <<< ${opts[$1]} } + +# checks if its a maildir +# returns 0 (success) if yes +# no in all other cases +maildircheck() { + { test -r $1 } || { + error "Maildir not existing: $1" + return 1 } + { test -w $1 } || { + error "Directory not writable: $1" + return 1 } + { test -r $1/cur } \ + && { test -r $1/new } \ + && { test -r $1/tmp } \ + && { return 0 } # Yes is a maildir + func "Not a maildir: $1" + return 1 +} + maildirmake() { if [ -z $1 ]; then @@ -816,8 +835,26 @@ EOF } stats() { - mailstat -k $WORKDIR/log/procmail.log - return $? + # make index of all maildirs + notice "Maildirs status" + typeset -alU ml + typeset -al empty + for i in `ls $MAILDIRS`; do + { maildircheck $MAILDIRS/${i} } || { continue } + cur=`ls $MAILDIRS/$i/cur | wc -l` + new=`ls $MAILDIRS/$i/cur | wc -l` + tot=$(( $cur + $new )) + ml+=("$tot\t:: $i\t ($cur/$new)") + done + for m in ${ml}; do + { test ${m[1]} = "0" } && { + empty+=${m} + continue } + act "$m" + done + { test ${#empty} != 0 } && { emptystr="(${#empty} are empty)" } + notice "Total maildirs: ${#ml} $emptystr" + return 0 } ###### @@ -1326,17 +1363,90 @@ search() { { which mairix > /dev/null } || { return 1 } id=$RANDOM rc=$TMPDIR/search.conf.$id + typeset -al expr + typeset -al fold + # intelligent parse of args, position independent + # check if its a folder, if not is an expression + mlstr="all folders"; ml=""; c=0 + basedir=$MAILDIRS + # check if the name of a maildir is among params + for p in ${PARAM}; do + c=$(( $c + 1 )) + func "checking param: ${p}" + if [ -r ${p} ]; then + + { maildircheck ${p} } && { + fold+=(${p}) + { test ${#fold} = 1 } && { + # base path is the dir of the first folder + pushd `dirname ${p}` + basedir=`pwd` + popd } + } + + elif [ -r ${MAILDIRS}/${p} ]; then + + { maildircheck ${MAILDIRS}/${p} } && { fold+=(${MAILDIRS}/${p}) } + + else # not a folder, add it to expressions array + expr+=(${p}) + fi + done + + + # now fold is an array of specified folders + # expr is an array of specified search expressions + + # to search only one maildir then we need to index it + # separate from the rest of the maildirs + if [ ${#fold} != 0 ]; then + { test ${#expr} = 0 } && { + error "no search expression given for folders ${fold[@]}" + return 1 } + # forge the folder string for mairix conf + folders=""; for f in ${fold}; do folders="$folders`basename $f`:"; done + cat <<EOF > $rc +base=$basedir +database=$TMPDIR/search.db.$id +maildir=${folders} +mfolder=$TMPDIR/search.result.$id +mformat=maildir +EOF + + exitcode=1 + act "Indexing ${folders}" + mairix -F -f $rc 2> /dev/null + { test $? = 0 } && { + act "Searching for: ${expr}" + found=`mairix -F -f $rc ${=expr} 2> /dev/null | awk '{ print $2}'` + if [ $found != 0 ]; then + mutt -F $MUTTDIR/rc -R -f $TMPDIR/search.result.$id + notice "Found $found matches looking for '$expr' in $folders" + find $TMPDIR/search.result.$id + cat $rc + exitcode=0 + else error "No matches found."; fi + } + + + rm -f $rc + rm -f $TMPDIR/search.db.$id +# rm -rf $TMPDIR/search.result.$id + return $exitcode + + + #################################################### + else # no folder specified on commandline, search all # make index if no params given - ml=""; c=0 - for i in `ls $MAILDIRS`; do + c=0 + for i in `ls $MAILDIRS`; do # is it a maildir? - { test -r $MAILDIRS/${i}/cur } \ - && { test -r $MAILDIRS/${i}/new } \ - && { test -r $MAILDIRS/${i}/tmp } \ - && { c=`expr $c + 1`; ml="$ml:$i" } - done - func "searching maildirs: $ml" + { maildircheck $MAILDIRS/${i} } && { + c=`expr $c + 1`; ml="$ml:$i" } + done + fi + cat <<EOF > $rc base=$MAILDIRS database=$WORKDIR/search.db @@ -1351,14 +1461,20 @@ EOF mairix -F -f $rc rm -f $rc exitcode=$? - { test $exitcode = 0 } && { notice "Done." } || { error "Error, indexing aborted." } + if [ $exitcode = 0 ]; then notice "Done." + else error "Error, indexing aborted."; fi + rm -f $rc return $exitcode } - act "Searching maildirs for: $PARAM" - act -n "" - mairix -F -f $rc ${=PARAM} 2> /dev/null - { test $? = 0 } && { mutt -F $MUTTDIR/rc -R -f $TMPDIR/search.result.$id } - rm -rf $TMPDIR/search.result.$id + act "Searching $mlstr for: ${expr}" + exitcode=1 + found=`mairix -F -f $rc ${=expr} 2> /dev/null | awk '{print $2}'` + if [ $found != 0 ]; then + mutt -F $MUTTDIR/rc -R -f $TMPDIR/search.result.$id + notice "Found $found matches looking for '$expr' in all mail folders" + exitcode=0 + else error "Nothing found matching '$expr'"; fi + rm -rf $TMPDIR/search.*.$id rm -f $rc } ############## @@ -1379,41 +1495,100 @@ open_file() { ###################### # Maildir manipulation backup() { - src=${PARAM[1]} - dst=${PARAM[2]} - expire=${PARAM[3]} - if ! [ -r ${src}/cur ]; then - error "No maildir found in $src" + id=$RANDOM + rc=$TMPDIR/backup.conf.$id + typeset -al expr + typeset -al fold + + src=""; dst="" + basedir=$MAILDIRS + # check if the name of a maildir is among params + # we need at least 2 maildirs, the second is the destination + for p in ${PARAM}; do + c=$(( $c + 1 )) + + if [ $c = ${#PARAM} ]; then + # last one is always the destination + func "destination is ${p}" + fold+=(${p}) + + elif [ -r ${p} ]; then + + { maildircheck ${p} } && { + func "param ${p} is a maildir" + fold+=(${p}) + { test ${#fold} = 1 } && { + # base path is the dir of the first folder + pushd `dirname ${p}` + basedir=`pwd` + popd } + } + + elif [ -r ${MAILDIRS}/${p} ]; then + + { maildircheck ${MAILDIRS}/${p} } && { + func "param ${p} is a jaro maildir" + fold+=(${MAILDIRS}/${p}) + } + + else # not a folder, add it to expressions array + func "param ${p} is an expression" + expr+=(${p}) + fi + done + + { test ${#fold} -lt 2 } && { + error "Not enough folders specified for backup: minimum is 2" + act "When specifying more than 2, the last one is the destination" return 1 - fi - if ! [ -r ${dst}/cur ]; then - maildirmake "${dst}" - fi - if [ -z $expire ]; then - error "No expiration date set for backup, please indicate how many days old" + } + + dst=${fold[${#fold}]} + { test -r $dst } && { + error "Backup destination already exists: $dst" + return 1 } + + maildirmake "${dst}" + + { test ${#expr} = 0 } && { + error "No expression set for backup, please indicate what you want to backup" + act "For example: d:10y-2y (all mails older than 1 year up to 10 years ago" + act "Or a simple search string, all expressions can be verified using search." return 1 - fi - notice "Backup of all read mails older than $expire days" - oldread=`find $src/cur -type f | wc -l` - oldunread=`find $src/new -type f | wc -l` + } - newread=`find $src/cur -type f -mtime +$expire | wc -l` - newunread=`find $src/new -type f -mtime +$expire | wc -l` + # forge the folder string for mairix conf + folders="" + for f in ${fold}; do + { test $f = $dst } || { + folders="$folders`basename $f`:" } + done - act "from: (${oldread}/${oldunread} read/unread) maildir $src" - if [ $newunread != 0 ]; then # use some highlight to signal long due unread - act "to: ($fg[red]${newread}/${newunread} read/unread$fg[white]) maildir $fg_bold[white]$dst$fg_no_bold[white]" - else - act "to: (${newread}/${newunread} read/unread) maildir $dst" - fi + notice "Backup of all mails in '$folders' matching expression '$expr'" - if [ $DRYRUN = 1 ]; then return 0; fi + act "Indexing folders" + cat <<EOF > $rc +base=$basedir +database=$TMPDIR/backup.db.$id +maildir=${folders} +mfolder=$dst +mformat=maildir +EOF + mairix -F -f $rc 2> /dev/null + act "Copying matches to $dst" + pushd `dirname $dst`; basedir=`pwd`; popd + rm -f $rc; cat <<EOF > $rc +base=$basedir +database=$TMPDIR/backup.db.$id +maildir=${folders} +mfolder=$dst +mformat=maildir +EOF + found=`mairix -F -f $rc -H ${expr} 2> /dev/null | awk '{print $2}'` + notice "$found matches found, destination folder size is `du -hs $basedir/$dst | awk '{print $1}'`" - find $src/cur -mtime +$expire -type f -exec mv {} $dst/cur/ \; - find $src/new -mtime +$expire -type f -exec mv {} $dst/new/ \; + # TODO: remove matched messages from source folders using rmdupes - notice "Operation completed, current maildir sizes:" - du -hs $src $dst } rmdupes() {