commit 54aea8c2acdefe8e3cea2f48a0ef6abc92514b98
parent 8e6160a3d0404f538713327f409855a9ecf47f43
Author: Jaromil <jaromil@dyne.org>
Date:   Fri,  1 Jun 2012 13:28:19 +0200
safe locking mechanism, now sending multiple mails works
Diffstat:
| M | TODO |  |  | 6 | ++++++ | 
| M | install.sh |  |  | 1 | + | 
| M | src/jaro |  |  | 125 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------- | 
3 files changed, 97 insertions(+), 35 deletions(-)
diff --git a/TODO b/TODO
@@ -16,6 +16,12 @@
 * Stats
  + Have some fancy statistics
 
+* Speedmail or Quickmail
+  write down a mail from commandline and send it right away (if online)
+  doesn't uses Mutt to generate the mail body
+  but might read Mutt.txt configuration for headers and such
+  
+
 * DONE Maildirs
  + Remove duplicates from maildirs (garbage collection)
  + Backup system with expiration date
diff --git a/install.sh b/install.sh
@@ -247,6 +247,7 @@ cp src/lbdb/fetchaddr $WORKDIR/.lbdb/
 chmod +x $WORKDIR/.lbdb/*
 ln -sf $WORKDIR/.lbdb/lbdb-fetchaddr $WORKDIR/bin/
 ln -sf $WORKDIR/.lbdb/lbdbq $WORKDIR/bin/
+ln -sf $WORKDIR/.lbdb/dotlock $WORKDIR/bin/
 
 # OS specific lbdb rules
 case $OS in
diff --git a/src/jaro b/src/jaro
@@ -30,9 +30,9 @@ for arg in ${argv}; do OLDARGS+=($arg); done
 # declare global variables
 
 QUIET=0
-DEBUG=0
+DEBUG=1
 DRYRUN=0
-
+CLEANEXIT=1
 
 # which command to use when creating dirs
 mkdir="`which mkdir` -m 700 -p"
@@ -115,8 +115,9 @@ PROCMAILDIR=$WORKDIR/.procmail
 MUTTDIR=$WORKDIR/.mutt
 
 cleanexit() {
-    for f in `ls $WORKDIR/tmp/`; do
-	${=rm} $WORKDIR/tmp/$f
+    func "Clean exit procedures"
+    for f in `ls $WORKDIR/tmp/ | grep -v '.lock$'`; do
+	unlink $WORKDIR/tmp/$f
     done
     unset typeset -h name login host protocol port password auth folders accountopt
 }
@@ -131,6 +132,48 @@ TRAPINT() {
 	fi
 }
 
+lock() {
+    func "lock: $@"
+    $WORKDIR/.lbdb/dotlock ${=@}
+    case $? in
+	1) error "Cannot lock non existing file: $@"
+	    return 1 ;;
+	3) error "Locked file in use: $@"
+	    return 3 ;;
+	5) error "Impossible to lock: $@"
+	    return 5 ;;
+	# success
+	0) return 0 ;;
+    esac
+}
+newlock() { # create locked
+    func "creating locked file: $1"
+    touch $1
+    chmod 600 $1
+    lock $1
+}
+unlock() {
+    func "unlock: $@"
+    $WORKDIR/.lbdb/dotlock -u ${=@}
+    if [ $? != 0 ]; then
+	error "Unable to unlock: $@"
+	return 1
+    fi
+    return 0
+}
+locked_unlink() { # delete a file that we are locking
+    # use with care! this can permanently erase currently locked files
+    ${=rm} ${1}
+    touch ${1}
+    $WORKDIR/.lbdb/dotlock -d -f ${1}
+}
+unlink() { # lock and delete
+    func "unlink: $1"
+    lock ${1}
+    locked_unlink ${1} &
+}
+
+
 # we use pinentry
 # comes from gpg project and is secure
 # it also conveniently uses the right toolkit
@@ -261,9 +304,11 @@ read_account() {
 	error "account $acct not found in $adir"
 	return 1
     fi
-    atmp=$WORKDIR/tmp/$1
+
     case $type in
 	imap|smtp)
+
+	    lock $acct
 	    ttmp=`cat $acct | awk '
     /^#/ { next }
     /^name/ { printf "name=\""; for(i=2;i<=NF;i++) printf "%s ", $i; printf "\";" }
@@ -278,6 +323,8 @@ read_account() {
     /^options/ { printf "accountopt=\""; for(i=2;i<=NF;i++) printf "%s ", $i; printf "\";" }
     /^folders/ { printf "folders=\""; for(i=2;i<=NF;i++) printf "%s ", $i; printf "\";" }
     '`
+	    unlock $acct
+
 	    eval "$ttmp"
 	    # check required fields
 	    { test -z $host }  && { error "Field missing in account $acct: host"; return 1 }
@@ -323,10 +370,9 @@ read_default_account() {
     fi
     case $1 in
 	"in")
-	    if [ -r $adir/imap.default ]; then
-		read_account imap.default
-		return $?
-	    else
+	    read_account imap.default
+	    if [ $? = 0 ]; then return $? # configured default found
+	    else # pick first one
 		for a in `find $adir -name "imap*"`; do all+=($a); done
 		for a in `find $adir -name "pop*"`; do all+=($a); done
 		if [ ${#all} != 0 ]; then
@@ -338,10 +384,9 @@ read_default_account() {
 	    fi
 	    ;;
 	"out")
-	    if [ -r $adir/smtp.default ]; then
-		read_account smtp.default
-		return $?
-	    else
+	    read_account smtp.default
+	    if [ $? = 0 ]; then return $? # configured default found
+	    else # pick first one
 		for a in `find $adir -name "smtp*"`; do all+=($a); done
 		read_account `basename ${all[1]}` # take the first found
 		return $?
@@ -381,8 +426,10 @@ queue() {
     msmtpfile="$base.msmtp"
     # Write command line to $MSMTPFILE
     echo "$@" > "$msmtpfile"
+    lock $msmtpfile
     # Write the mail to $MAILFILE
     cat > "$mailfile"
+    unlock $msmtpfile
     cd -
     return 0
 }
@@ -456,17 +503,19 @@ fetch() {
     adir=$WORKDIR/Accounts
     acct=$1
     typeset -al all
+
     if [ -z $acct ]; then # fetch all accounts
-	for a in `find $adir -name "imap*"`; do all+=($a); done
-	for a in `find $adir -name "pop*"`; do all+=($a); done
-    else
-	# fetch only one account
-	for a in `find $adir -name "$acct*"`; do all+=($a); done
+	for a in `find $adir -type f -name "imap*"`; do all+=($a); done
+	for a in `find $adir -type f -name "pop*"`; do all+=($a); done
+    else # fetch only one account
+	for a in `find $adir -type f -name "$acct*"`; do all+=($a); done
     fi
+
     if ! [ -r $PROCMAILDIR/rc ]; then
 	act "updating procmail configuration"
 	update
     fi
+
     for a in ${all}; do
 	read_account `basename $a`
 	if [ $? != 0 ]; then
@@ -474,8 +523,6 @@ fetch() {
 	    return 1
 	fi
 	notice "Fetching mails from $name"
-	touch $WORKDIR/tmp/$host.fetch
-	chmod 600 $WORKDIR/tmp/$host.fetch
 	ask_password $login $host
 	if [ $? != 0 ]; then
 	    error "Error retrieving password for $login on $host"
@@ -483,6 +530,7 @@ fetch() {
 	    return 1
 	fi
 
+	newlock $WORKDIR/tmp/$host.fetch
 	cat <<EOF > $WORKDIR/tmp/$host.fetch
 poll $host with proto IMAP user "$login" there with password "$password"
 EOF
@@ -512,17 +560,17 @@ EOF
 	case $? in
 	    1) 
 		notice "No mails for $name"
-		${=rm} $WORKDIR/tmp/$host.fetch
+		unlock $WORKDIR/tmp/$host.fetch
 		return 1
 		;;
 	    2)
 		error "Invalid or unknown certificate for $host"
-		${=rm} $WORKDIR/tmp/$host.fetch
+		unlock $WORKDIR/tmp/$host.fetch
 		return 1
 		;;
 	    3)
 		error "Invalid password for user $login at $host"
-		${=rm} $WORKDIR/tmp/$host.fetch
+		unlock $WORKDIR/tmp/$host.fetch
 		return 1
 		;;
 	    *) ;;
@@ -530,18 +578,20 @@ EOF
 
 	# archive old procmail log
 	if [ -r $WORKDIR/log/procmail.log ]; then
-	    touch $WORKDIR/log/procmail-${datestamp}.log
-	    chmod 700 $WORKDIR/log/procmail-${datestamp}.log
+	    newlock $WORKDIR/log/procmail-${datestamp}.log
 	    cat $WORKDIR/log/procmail.log \
 		>> $WORKDIR/log/procmail-${datestamp}.log
 	    rm -f $WORKDIR/log/procmail.log
+	    unlock $WORKDIR/log/procmail-${datestamp}.log
 	fi
 	act "please wait while downloading mails..."
 
 	cat $WORKDIR/tmp/$host.fetch | fetchmail -f -
 	# TODO: substitute this with cat conf | fetchmail -f -
 	# to avoid writing the password in clear on filesystem
-	
+
+	unlock $WORKDIR/tmp/$host.fetch
+
 	total=`mailstat -k $WORKDIR/log/procmail.log | tail -n1 | awk '{print $2}'`
 	briefing=`mailstat -kt $WORKDIR/log/procmail.log |awk '!/procmail/ { print "    " $2 "\t" $3 }'|sort -nr`
 	notice "$total emails fetched"
@@ -578,13 +628,14 @@ send() {
     # defaults
     [ -z $auth ] && auth=plain
     [ -z $port ] && port=25
-    
-    touch $WORKDIR/tmp/$host.send
-    chmod 600 $WORKDIR/tmp/$host.send
+
+
     ask_password $login $host
+
+    newlock $WORKDIR/tmp/$host.send
     cat <<EOF > $WORKDIR/tmp/$host.send
 account default
-from ${name}
+from ${email}
 user ${login}
 host ${host}
 port ${port}
@@ -599,18 +650,22 @@ EOF
 
     for mail in `find $MAILDIRS/outbox -name "*.mail"`; do
        smtp=`echo ${mail} | sed -e 's/mail/msmtp/'`
+       lock ${smtp}
        recipients="`cat ${smtp}`"
        act "To: ${recipients}"
        msmtp -C $WORKDIR/tmp/$host.send -- ${=recipients} < "${mail}"
        if [ $? != 0 ]; then
            error "Error sending mail, skipped"
+	   unlock ${smtp}
        else
 	   act "Mail sent succesfully"
 	   # whitelist those to whom we send mails
-	   cat ${mail} | $WORKDIR/bin/jaro -q learn	   
-	   ${=rm} ${mail} ${smtp}
+	   cat ${mail} | $WORKDIR/bin/jaro -q learn
+	   ${=rm} ${mail} &
+	   locked_unlink ${smtp} &
        fi
     done
+    unlock $WORKDIR/tmp/$host.send
     return 0
 }
 
@@ -1092,8 +1147,8 @@ main()
 
 	update)  update ;;
 
-	query)   query ${PARAM} ;;
-	learn)   learn ${PARAM} ;;
+	query)   CLEANEXIT=0; query ${PARAM} ;;
+	learn)   CLEANEXIT=0; learn ${PARAM} ;;
 
 	backup)  backup ${PARAM} ;;
 	rmdupes) rmdupes ${PARAM} ;;
@@ -1111,5 +1166,5 @@ main()
 
 check_bin
 main $@
-cleanexit
+if [ $CLEANEXIT = 1 ]; then cleanexit; fi
 return $exitcode