commit 124f55125e99db9b961921d6920774bb87f71e4d
parent 54aea8c2acdefe8e3cea2f48a0ef6abc92514b98
Author: Jaromil <jaromil@dyne.org>
Date:   Fri,  1 Jun 2012 16:43:48 +0200
better handling of multiple accounts
Diffstat:
| M | src/jaro |  |  | 291 | +++++++++++++++++++++++++++++++++++++------------------------------------------ | 
1 file changed, 138 insertions(+), 153 deletions(-)
diff --git a/src/jaro b/src/jaro
@@ -46,6 +46,10 @@ PARAM=()
 typeset -A global_opts
 typeset -A opts
 
+# global variable for account selection
+typeset -h account
+account=default
+
 # global variables for accounts
 typeset -h name login host protocol port password auth folders accountopt
 
@@ -77,10 +81,10 @@ if [ "$1" != "-q" ]; then # honor quiet flag
     case $(uname) in
 	Linux) OS=GNU
 	    notice "Jaro Mail v$VERSION running on GNU/Linux"	;;
-	
+
 	Darwin) OS=MAC
 	    notice "Jaro Mail v$VERSION running on Mac/OSX"	;;
-	
+
 	*) OS=GNU # default
 	    error "Running on an unknown operating system, assuming GNU" ;;
     esac
@@ -217,7 +221,7 @@ ask_password() {
 		act "New password set for $1 @ $2"
 		security add-internet-password -a $1 -s $2 -w "${password}"
 	    else
-		act "Using saved password for $1 @ $2"        
+		act "Using saved password for $1 @ $2"
 		password=`security find-internet-password -a $1 -s $2 -g \
 		    2>&1| awk '/^password:/ { print $2 }' | sed -e 's/"//g'`
 	    fi
@@ -248,7 +252,7 @@ set from = "$name <$login>"
 EOF
     else
 	error "No identity found, left blank."
-	touch $MUTTDIR/identity	
+	touch $MUTTDIR/identity
     fi
 }
 
@@ -261,11 +265,11 @@ option_is_set() {
     [[ -n ${(k)opts[$1]} ]];
     r=$?
     if [[ $2 == out ]]; then
-        if [[ $r == 0 ]]; then
-            echo 'set'
-        else
-            echo 'unset'
-        fi
+	if [[ $r == 0 ]]; then
+	    echo 'set'
+	else
+	    echo 'unset'
+	fi
     fi
     return $r;
 }
@@ -290,21 +294,31 @@ maildirmake() {
     ${=mkdir} ${1}/tmp
 
 }
-# arg 1 : account name, es: imap.gmail
+# arg 1 : account type, es: imap or smtp
+# -a defines which account name other than 'default'
 read_account() {
-    adir=$WORKDIR/Accounts
-    acct=$1
-    type="`echo $1|cut -d. -f1`"
+    typeset -al all
+
+    if [ -z $1 ]; then type="*"
+
+    else type=$1 # smtp, imap, pop ... file prefixes"
+    fi
+
     # find the file
-    if [ -r $adir/$acct.txt ]; then
-	acct=$adir/$acct.txt
-    elif [ -r $adir/$acct ]; then  # try without .txt
-	acct=$adir/$acct
-    else
-	error "account $acct not found in $adir"
+    for a in `find $WORKDIR/Accounts -name "$type.$account*" | grep -v smtp`; do all+=($a); done
+    if [ ${#all} = 0 ]; then
+	error "No $type account found: $account"
+	return 1
+    elif [ ${#all} != 1 ]; then
+	error "Too many $type accounts named $account:"
+	for i in ${all}; do act -n "${all[i]}"; done
+	echo; error "Refine your account keyword"
 	return 1
     fi
 
+    acct=${all[1]}
+    type=`basename $acct | cut -d. -f1`
+
     case $type in
 	imap|smtp)
 
@@ -341,7 +355,7 @@ read_account() {
 
 	    func "type: $type"
 	    func "name: $name"
-	    func "email: $email"	    
+	    func "email: $email"
 	    func "host: $host"
 	    func "login: $login"
 	    func "trans: $transport"
@@ -358,43 +372,6 @@ read_account() {
     esac
     return 0
 }
-# read a default account
-# arg: "in" or "out"
-# meaning an account to receive or send emails
-read_default_account() {
-    adir=$WORKDIR/Accounts
-    typeset -al all
-    if [ -z $1 ]; then
-	error "Error: read_default_account called without argument"
-	return 1
-    fi
-    case $1 in
-	"in")
-	    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
-		    read_account `basename ${all[1]}` # take the first found
-		    return $?
-		else
-		    error "No accounts configured, look in $WORKDIR/Accounts"
-		fi
-	    fi
-	    ;;
-	"out")
-	    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 $?
-	    fi
-	    ;;
-    esac
-    return 1
-}
 
 queue() {
     local base;
@@ -409,7 +386,7 @@ queue() {
     # Create new unique filenames of the form
     # MAILFILE:  ccyy-mm-dd-hh.mm.ss[-x].mail
     # MSMTPFILE: ccyy-mm-dd-hh.mm.ss[-x].msmtp
-    # where x is a consecutive number only appended if you send more than one 
+    # where x is a consecutive number only appended if you send more than one
     # mail per second.
     base="`date +%Y-%m-%d-%H.%M.%S`"
     func "[$base] queue called with params: ${PARAM[@]}"
@@ -449,7 +426,7 @@ cert() {
 	gmail)
 	    cc=Equifax_Secure_Certificate_Authority
 	    if ! [ -r $WORKDIR/certs/${cc}.pem ]; then
-		
+
 		curl -o $WORKDIR/certs/${cc}.pem \
 		    "https://www.geotrust.com/resources/root_certificates/certificates/${cc}.cer"
 		openssl x509 -in \
@@ -499,16 +476,32 @@ cert() {
 
 ###########
 # FETCHMAIL
+fetchall() {
+    notice "Fetching all accounts in $MAILDIRS"
+    res=0
+    for i in `find $WORKDIR/Accounts -type f | grep -v README`; do
+	a=`basename $i`
+	type=`echo $a | cut -d. -f1`
+	account=`echo $a | cut -d. -f2`
+	func "$account type $type: $a"
+	fetch $type
+	if [ $? != 0 ]; then res=1; fi
+	# returns an error if just one of the accounts did
+    done
+    return $res
+}
 fetch() {
     adir=$WORKDIR/Accounts
-    acct=$1
+
     typeset -al all
 
-    if [ -z $acct ]; then # fetch all accounts
-	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
+    # recurdion here
+    if [ "$1" = "all" ]; then fetchall; return $?; fi
+
+    read_account "$1"
+    if [ $? != 0 ]; then
+	error "Account configuration not found, or broken. Aborting operation."
+	return 1
     fi
 
     if ! [ -r $PROCMAILDIR/rc ]; then
@@ -516,87 +509,81 @@ fetch() {
 	update
     fi
 
-    for a in ${all}; do
-	read_account `basename $a`
-	if [ $? != 0 ]; then
-	    error "Account configuration not found, or broken. Aborting operation."
-	    return 1
-	fi
-	notice "Fetching mails from $name"
-	ask_password $login $host
-	if [ $? != 0 ]; then
-	    error "Error retrieving password for $login on $host"
-	    unset password all
-	    return 1
-	fi
+    notice "Fetching mails for $name"
+    ask_password $login $host
+    if [ $? != 0 ]; then
+	error "Error retrieving password for $login on $host"
+	unset password all
+	return 1
+    fi
 
-	newlock $WORKDIR/tmp/$host.fetch
-	cat <<EOF > $WORKDIR/tmp/$host.fetch
+    newlock $WORKDIR/tmp/$host.fetch
+    cat <<EOF > $WORKDIR/tmp/$host.fetch
 poll $host with proto IMAP user "$login" there with password "$password"
 EOF
-	unset password
+    unset password
 
-	if ! [ -z $accountopt ]; then # add option configuration
-	    echo "${accountopt}" >> $WORKDIR/tmp/$host.fetch; fi
+    if ! [ -z $accountopt ]; then # add option configuration
+	echo "${accountopt}" >> $WORKDIR/tmp/$host.fetch; fi
 
-	if ! [ -z $folders ]; then # add folder configuration
-	    echo "folder ${folders}" >> $WORKDIR/tmp/$host.fetch; fi
+    if ! [ -z $folders ]; then # add folder configuration
+	echo "folder ${folders}" >> $WORKDIR/tmp/$host.fetch; fi
 
-	cat <<EOF >> $WORKDIR/tmp/$host.fetch
+    cat <<EOF >> $WORKDIR/tmp/$host.fetch
 ssl warnings 3600 and wants mda "procmail -m $PROCMAILDIR/rc"
 EOF
-	if [ "$cert" = "check" ]; then
-	    cat <<EOF >> $WORKDIR/tmp/$host.fetch
+    if [ "$cert" = "check" ]; then
+	cat <<EOF >> $WORKDIR/tmp/$host.fetch
 sslcertck sslcertpath '$WORKDIR/certs'
 EOF
-	fi
-	cat <<EOF >> $WORKDIR/tmp/$host.fetch
+    fi
+    cat <<EOF >> $WORKDIR/tmp/$host.fetch
 antispam 571 550 501 554
 EOF
 
 	# try login without doing anything
-	fetchmail -c -f $WORKDIR/tmp/$host.fetch
+    fetchmail -c -f $WORKDIR/tmp/$host.fetch
 	# examine result
-	case $? in
-	    1) 
-		notice "No mails for $name"
-		unlock $WORKDIR/tmp/$host.fetch
-		return 1
-		;;
-	    2)
-		error "Invalid or unknown certificate for $host"
-		unlock $WORKDIR/tmp/$host.fetch
-		return 1
-		;;
-	    3)
-		error "Invalid password for user $login at $host"
-		unlock $WORKDIR/tmp/$host.fetch
-		return 1
+    case $? in
+	1)
+	    notice "No mails for $name"
+	    unlock $WORKDIR/tmp/$host.fetch
+	    return 1
 		;;
-	    *) ;;
-	esac
+	2)
+	    error "Invalid or unknown certificate for $host"
+	    unlock $WORKDIR/tmp/$host.fetch
+	    return 1
+	    ;;
+	3)
+	    error "Invalid password for user $login at $host"
+	    unlock $WORKDIR/tmp/$host.fetch
+	    return 1
+	    ;;
+	*) ;;
+    esac
 
 	# archive old procmail log
-	if [ -r $WORKDIR/log/procmail.log ]; then
-	    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..."
+    if [ -r $WORKDIR/log/procmail.log ]; then
+	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 -
+    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
+    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"
+    echo "${briefing}"
 
-	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"
-	echo "${briefing}"
-    done
     return 0
 }
 
@@ -612,19 +599,14 @@ send() {
     mailnum=`ls ${MAILDIRS}/outbox | grep 'mail$' | wc -l`
     mailnum=${mailnum// /} # trim whitespace
     if [ "$mailnum" = "0" ]; then
-        act "Outbox is empty, no mails to send."
-        return 0
+	act "Outbox is empty, no mails to send."
+	return 0
     fi
 
-    if [ -z $1 ]; then # no particular account specified
-	# use the default account
-	read_default_account "out"
-    else
-	read_account smtp.${1}
-    fi
+    read_account smtp
 
     notice "Sending out ${mailnum} mails via $name"
- 
+
     # defaults
     [ -z $auth ] && auth=plain
     [ -z $port ] && port=25
@@ -655,7 +637,7 @@ EOF
        act "To: ${recipients}"
        msmtp -C $WORKDIR/tmp/$host.send -- ${=recipients} < "${mail}"
        if [ $? != 0 ]; then
-           error "Error sending mail, skipped"
+	   error "Error sending mail, skipped"
 	   unlock ${smtp}
        else
 	   act "Mail sent succesfully"
@@ -673,12 +655,12 @@ EOF
 # PEEK
 # this function will open the MTA to the imap server without fetching mails locally
 peek() {
-    # TODO account selection with -a
-    read_default_account in
+    read_account imap
+
     notice "Peek into remote imap account $name"
 
     folder=""
-    if ! [ -z ${1} ]; then 
+    if ! [ -z ${1} ]; then
 	folder="/${1}"
 	act "opening folder ${folder}"
     fi
@@ -710,7 +692,7 @@ update() {
     # generate muttrc
     # backup what's too old in the maildirs
     # ...
-    
+
     # debug configuration
     func "MAILDIRS:    $MAILDIRS"
     func "WORKDIR:     $WORKDIR"
@@ -726,7 +708,7 @@ update() {
     maildirmake $MAILDIRS/unsorted
     maildirmake $MAILDIRS/ml.unsorted
     ${=mkdir} $MAILDIRS/outbox
-    
+
     ######
     # MUTT
     ${=mkdir} $MUTTDIR
@@ -775,13 +757,14 @@ source $WORKDIR/Mutt.txt
 
 EOF
 
-    
+
     # just the header, will be completed later in procmail loop
     rm -f $MUTTDIR/mboxes
     echo -n "mailboxes +priv" > $MUTTDIR/mboxes
 
     # update identity with default
-    read_default_account "in"
+    read_account imap
+
     switch_identity
 
     ##########
@@ -816,7 +799,7 @@ EOF
 
     #######
     echo "# filters generated from Filters.txt" >> $PROCMAILDIR/rc
-    
+
     for f in `cat $WORKDIR/Filters.txt | awk '/^#/ {next} /^./ { print $1 ";" $2 ";" $3 ";" $4 }'`; do
 	header="${f[(ws:;:)1]}"
 	address="${f[(ws:;:)2]}"
@@ -846,7 +829,7 @@ EOF
 
     #######
     echo "# filters generated from Accounts" >> $PROCMAILDIR/rc
-    
+
     typeset -al accts
     for f in `cat $WORKDIR/Accounts/* | awk '/^email/ { print $2 }'`; do
 	echo "ADDR=${f}\tDEST=priv/\tINCLUDERC=\$PMSRC/pf-chkto.rc"  >> $PROCMAILDIR/rc
@@ -1014,6 +997,7 @@ Main commands:
 
 Options:
 
+ -a     use a particular account instead of default (keyword)
  -h     print this help
  -v     version information for this tool
  -q     run quietly without printing informations
@@ -1052,14 +1036,14 @@ main()
     #       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=(q -quiet=q D -debug=D h -help=h v -version=v n -dry-run=n)
+    main_opts=(a: -account=a q -quiet=q D -debug=D h -help=h v -version=v n -dry-run=n)
     subcommands_opts[__default]=""
     subcommands_opts[queue]=""
     subcommands_opts[fetch]=""
     subcommands_opts[send]=""
     subcommands_opts[read]=""
     subcommands_opts[compose]=""
-    subcommands_opts[peek]=""    
+    subcommands_opts[peek]=""
     subcommands_opts[update]=""
     subcommands_opts[query]=""
     subcommands_opts[learn]=""
@@ -1074,9 +1058,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)
@@ -1084,11 +1068,11 @@ main()
     unset discardme
     subcommand=$1
     if [[ -z $subcommand ]]; then
-        subcommand="__default"
+	subcommand="__default"
     fi
     if [[ -z ${(k)subcommands_opts[$subcommand]} ]]; then #there's no such subcommand
-        error "Subcommand '$subcommand' doesn't exist"
-        exitcode=1
+	error "Subcommand '$subcommand' doesn't exist"
+	exitcode=1
 	return 1
     fi
     argv=(${oldstar})
@@ -1098,10 +1082,10 @@ main()
     # zsh magic: ${=string} will split to multiple arguments when spaces occur
     set -A cmd_opts ${main_opts} ${=subcommands_opts[$subcommand]}
     if [[ -n $cmd_opts ]]; then #if there is no option, we don't need parsing
-        zparseopts -M -E -D -Aopts ${cmd_opts}
+	zparseopts -M -E -D -Aopts ${cmd_opts}
 	if [[ $? != 0 ]]; then
 	    error "Some error occurred during option processing."
-            exitcode=1
+	    exitcode=1
 	    return 1
 	fi
     fi
@@ -1127,10 +1111,11 @@ main()
     fi
   ### End parsing command-specific options
 
-    if option_is_set -v; then 
+    if option_is_set -v; then
 	cat $JAROMAILEXEC | awk '/^#/ {print $0 } !/^#/ {exit}'
 	echo
     fi
+    if option_is_set -a; then account=`option_value -a`; fi
     if option_is_set -h; then usage;  fi
     if option_is_set -q; then QUIET=1; fi
     if option_is_set -D; then func "Debug messages ON"; DEBUG=1; fi