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:
| M | src/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() {