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 2143dbf0a452894c24c9ef5b313cd542018344db
parent 1ea3f5cc38350085ccb1232ed35f94c79b006eb4
Author: Jaromil <jaromil@dyne.org>
Date:   Fri, 26 Dec 2014 12:22:32 +0100

various generic code cleanups and reorganization

Diffstat:
Msrc/zlibs/accounts | 25++++++++++++-------------
Msrc/zlibs/email | 497++++++++++++++++++++++++++++++++++++++++---------------------------------------
Msrc/zlibs/filters | 378++++++++++++++++++++++++++++++++++++++++----------------------------------------
Msrc/zlibs/helpers | 303++++++++++++++++++++++++++++++++++++++++++-------------------------------------
4 files changed, 610 insertions(+), 593 deletions(-)

diff --git a/src/zlibs/accounts b/src/zlibs/accounts @@ -28,7 +28,7 @@ read_account() { typeset -al all unset name email imap imap_port smtp smtp_port \ - host login transport auth cert options folders exclude + host login transport auth cert options folders exclude # parse arguments { test "$account" = "" } && { account="default" } @@ -38,13 +38,13 @@ read_account() { acct="$MAILDIRS/Accounts/$account"; { test -r "$acct" } || { acct="$MAILDIRS/Accounts/$account.txt" - { test -r "$acct" } || { - error "no account found: $acct" - act "Refine your argument using '-a accountname'" - act "Available accounts:" - ls "$MAILDIRS/Accounts/" - return 1 - } + { test -r "$acct" } || { + error "no account found: $acct" + act "Refine your argument using '-a accountname'" + act "Available accounts:" + ls "$MAILDIRS/Accounts/" + return 1 + } } ttmp=`awk ' @@ -66,8 +66,8 @@ read_account() { /^exclude/ { printf "exclude=("; for(i=2;i<=NF;i++) printf "%s ", $i; printf ");" } ' "$acct"` { test $? = 0 } || { - error "Error parsing account: $acct" - return 1 } + error "Error parsing account: $acct" + return 1 } eval "$ttmp" # check required fields @@ -86,12 +86,12 @@ read_account() { { test -z $transport } && { transport=plain } { test -z $imap_port } && { imap_port=143 } { test -z $smtp_port } && { smtp_port=25 } - + { test -z $auth } && { auth=plain } { test -z $cert } && { cert=ignore } { test -z $accountopt } && { accountopt=keep } # cert and password can be missing - + func "name: $name" func "email: $email" func "login: $login" @@ -113,4 +113,3 @@ read_account() { return 0 } - diff --git a/src/zlibs/email b/src/zlibs/email @@ -21,21 +21,10 @@ # Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. # extract all emails found in stdin, one per line -extract_emails() { -awk '{ for (i=1;i<=NF;i++) - if ( $i ~ /[[:alnum:]]@[[:alnum:]]/ ) { - gsub(/<|>|,/ , "" , $i); print $i } }' -} - compose() { # no args, open in compose mode - tmp="${TMPDIR}/compose.$datestamp.$RANDOM" - _res=0; - echo "To: ${PARAM[@]}" > $tmp - ${=mutt} -F $MUTTDIR/rc -H $tmp - _res=$? - rm -f $tmp - return $_res + ${=mutt} -F $MUTTDIR/rc -H <(print "To: ${PARAM[@]}") + return $? } @@ -57,33 +46,33 @@ queue() { maildirmake "$MAILDIRS/outbox" { test $? = 0 } || { - act "updating outbox format to Maildir" - # silently migrate the outbox from the old format to the new - tmpp=(`find "$MAILDIRS/outbox" -type f`) - if [ ${#tmpp} = 0 ]; then - # the old format outbox is just empty - rmdir "$MAILDIRS/outbox" - maildirmake "$MAILDIRS/outbox" - else - # there are some mails to be sent in the old format outbox - # preserve them while migrating to the new format - # this code is less interesting, since it handles an old - # format in JaroMail - tmppp="$TMPDIR/jaro-outbox-migration-$RANDOM" - mkdir -p $tmppp - mv "$MAILDIRS/outbox/*" $tmppp/ - rmdir "$MAILDIRS/outbox" - maildirmake "$MAILDIRS/outbox" - # here we devince two useful arrays: - # bodies: the list of mail bodies to send - # corresponding to files with same name and extension .msmtp - bodies=(`find "$tmppp" -type f -name '*.mail'`) - for i in ${bodies}; do - cat "$i" | deliver outbox - { test $? = 0 } && { rm "$i" } - done - rmdir $tmppp - fi + act "updating outbox format to Maildir" + # silently migrate the outbox from the old format to the new + tmpp=(`find "$MAILDIRS/outbox" -type f`) + if [ ${#tmpp} = 0 ]; then + # the old format outbox is just empty + rmdir "$MAILDIRS/outbox" + maildirmake "$MAILDIRS/outbox" + else + # there are some mails to be sent in the old format outbox + # preserve them while migrating to the new format + # this code is less interesting, since it handles an old + # format in JaroMail + tmppp="$TMPDIR/jaro-outbox-migration-$RANDOM" + mkdir -p $tmppp + mv "$MAILDIRS/outbox/*" $tmppp/ + rmdir "$MAILDIRS/outbox" + maildirmake "$MAILDIRS/outbox" + # here we devince two useful arrays: + # bodies: the list of mail bodies to send + # corresponding to files with same name and extension .msmtp + bodies=(`find "$tmppp" -type f -name '*.mail'`) + for i in ${bodies}; do + cat "$i" | deliver outbox + { test $? = 0 } && { rm "$i" } + done + rmdir $tmppp + fi } ${=mkdir} "$MAILDIRS/outbox/send" @@ -93,60 +82,60 @@ queue() { if [[ "${=queue_to}" =~ '@jaromail.group' ]]; then - groupfile="`print ${=queue_to}|cut -d@ -f1`" - act "email recipients are in group ${groupfile}" - - { test -r "$MAILDIRS/Groups/$groupfile" } || { - maildirmake "$MAILDIRS/postponed" - mv "${TMPDIR}/${queue_body}.mail" "$MAILDIRS/postponed/new" - unlock "$MAILDIRS/outbox" - error "Group not found: $groupfile" - return 1 } - - recipients=`cat "$MAILDIRS/Groups/$groupfile" | grep -v '^#'` - groupnum=`print ${recipients} | wc -l` - groupmode=`head -n1 "$MAILDIRS/Groups/$groupfile" | awk '/^#mode/ { print $2 } { next }'` - { test "$groupmode" = "" } && { groupmode="individual" } - act "$groupnum recipients in total, sending mode $groupmode" - - - case $groupmode in - - # individual group mode hides other recipients and send - # multiple mail envelopes with each single recipient in To: - individual) - for i in ${(f)recipients}; do - ig=${base}-${RANDOM} - cat "${TMPDIR}/${queue_body}.mail" | \ - awk '/^To:/ { print "'"To: $i"'"; next } { print $0 }' \ - > "${MAILDIRS}/outbox/new/${ig}.mail" - done - ;; - - # carboncopy group mode sends a single envelope where all - # recipients can see and reply to each other - carboncopy|cc) - cc="" - for i in ${(f)recipients}; do - if [ "$cc" = "" ]; then cc="$i" - else cc+=", $i"; fi - done - ig=${base}-${RANDOM} - cat "${TMPDIR}/${queue_body}.mail" | \ - awk '/^To:/ { print "'"To: $cc"'"; print "'"Reply-To: $cc"'"; next } - { print $0 }' \ - > "${MAILDIRS}/outbox/new/${ig}.mail" - ;; - esac + groupfile="`print ${=queue_to}|cut -d@ -f1`" + act "email recipients are in group ${groupfile}" + + { test -r "$MAILDIRS/Groups/$groupfile" } || { + maildirmake "$MAILDIRS/postponed" + mv "${TMPDIR}/${queue_body}.mail" "$MAILDIRS/postponed/new" + unlock "$MAILDIRS/outbox" + error "Group not found: $groupfile" + return 1 } + + recipients=`cat "$MAILDIRS/Groups/$groupfile" | grep -v '^#'` + groupnum=`print ${recipients} | wc -l` + groupmode=`head -n1 "$MAILDIRS/Groups/$groupfile" | awk '/^#mode/ { print $2 } { next }'` + { test "$groupmode" = "" } && { groupmode="individual" } + act "$groupnum recipients in total, sending mode $groupmode" + + + case $groupmode in + + # individual group mode hides other recipients and send + # multiple mail envelopes with each single recipient in To: + individual) + for i in ${(f)recipients}; do + ig=${base}-${RANDOM} + cat "${TMPDIR}/${queue_body}.mail" | \ + awk '/^To:/ { print "'"To: $i"'"; next } { print $0 }' \ + > "${MAILDIRS}/outbox/new/${ig}.mail" + done + ;; + + # carboncopy group mode sends a single envelope where all + # recipients can see and reply to each other + carboncopy|cc) + cc="" + for i in ${(f)recipients}; do + if [ "$cc" = "" ]; then cc="$i" + else cc+=", $i"; fi + done + ig=${base}-${RANDOM} + cat "${TMPDIR}/${queue_body}.mail" | \ + awk '/^To:/ { print "'"To: $cc"'"; print "'"Reply-To: $cc"'"; next } + { print $0 }' \ + > "${MAILDIRS}/outbox/new/${ig}.mail" + ;; + esac else - # recipients are set in the email envelope - cat "$TMPDIR/$queue_body.mail" | deliver "outbox" + # recipients are set in the email envelope + cat "$TMPDIR/$queue_body.mail" | deliver "outbox" fi unlock "$MAILDIRS/outbox" { test -r "${TMPDIR}/${queue_body}.mail" } && { - ${=rm} "${TMPDIR}/${queue_body}.mail" } + ${=rm} "${TMPDIR}/${queue_body}.mail" } return 0 } @@ -159,25 +148,25 @@ fetchall() { accts=`${=find} $MAILDIRS/Accounts -type f | grep -v README` notice "Fetching mail for all accounts: ${#accts} found" for i in ${(f)accts}; do - account=`basename $i` - fetch - if [ $? != 0 ]; then res=1; fi - # returns an error if just one of the accounts did + account=`basename $i` + fetch + if [ $? != 0 ]; then res=1; fi + # returns an error if just one of the accounts did done return $res } fetch() { { test "$account" = "" } && { - fetchall; return $? } + fetchall; return $? } -# setup global account variables + # setup global account variables read_account ${account} -# name login host protocol port auth folders accountopt + # name login host protocol port auth folders accountopt { test $? != 0 } && { - error "Invalid account: $account" - return 1 + error "Invalid account: $account" + return 1 } notice "Fetching email for account ${account}" @@ -189,7 +178,9 @@ fetch() { host=$imap port=$imap_port ask_password - { test $? = 0 } || { error "Impossible to fetch email for account ${account}"; return 1 } + { test $? = 0 } || { + error "Impossible to fetch email for account ${account}"; + return 1 } # this puts total size in $imap_info # experimental only, commented out for now @@ -202,21 +193,31 @@ fetch() { # notice "Total occupation is `human_size ${imap_info[${#imap_info}]}`" - fmconf=("poll $imap with proto IMAP user \"$login\" there with password \"$password\"") - - if ! [ -z $accountopt ]; then # add option configuration - fmconf+=(" ${accountopt} "); fi - - # if no folders specified, use all - [[ "$folders" == "" ]] && { - folders=(`imap_list_folders`) } - act "${#folders} folders found" - - # unset here because listing folders still needs a pass - unset password + fmconf=("poll $imap with proto IMAP user \"$login\" there with password \"$password\"") + + if ! [ -z $accountopt ]; then # add option configuration + fmconf+=(" ${accountopt} "); fi + + # check if folders on commandline + if [[ "$PARAM[@]" = "" ]]; then + + # if no folders specified, use all + [[ "$folders" == "" ]] && { + folders=(`imap_list_folders`) } + act "${#folders} folders found" + + else + + act "commanded to fetch folders: ${PARAM[@]}" + folders=(${PARAM[@]}) + + fi + + # unset here because listing folders still needed a pass + unset password # nothing to download, bail out with error - [[ ${#folders} == "0" ]] && return 1 + [[ ${#folders} == "0" ]] && return 1 # remove excludes [[ ${#exclude} == "0" ]] || { @@ -226,60 +227,60 @@ fetch() { done } 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+=(" antispam 571 550 501 554 ") - - print $accountopt | grep 'keep' > /dev/null - { test $? = 0 } || { - error "planning to delete mails from server, account option: $accountopt" } - - # try login without doing anything - print "$fmconf" | fetchmail -c -f - - res=$? - # examine result - case $ret in - 1) - notice "No mails for $name" - unset $fmconf - return 1 - ;; - 2) - error "Invalid or unknown certificate for $imap" - unset $fmconf - return 1 - ;; - 3) - error "Invalid password for user $login at $imap" - unset $fmconf - return 1 - ;; - *) - func "fetchmail returns $ret" ;; - esac + + # 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+=(" antispam 571 550 501 554 ") + + print $accountopt | grep 'keep' > /dev/null + { test $? = 0 } || { + error "planning to delete mails from server, account option: $accountopt" } + + # try login without doing anything + print "$fmconf" | fetchmail -c -f - + res=$? + # examine result + case $ret in + 1) + notice "No mails for $name" + unset $fmconf + return 1 + ;; + 2) + error "Invalid or unknown certificate for $imap" + unset $fmconf + return 1 + ;; + 3) + error "Invalid password for user $login at $imap" + unset $fmconf + return 1 + ;; + *) + func "fetchmail returns $ret" ;; + esac if [[ $DRYRUN = 0 ]]; then - - act "please wait while downloading mails to incoming..." - - print " $fmconf " | fetchmail -f - - + + act "please wait while downloading mails to incoming..." + + print " $fmconf " | fetchmail -f - + else act "dryrun: nothing will be fetched really." fi - unset $fmconf - + unset $fmconf + return 0 } @@ -295,13 +296,13 @@ send() { queue_outbox=`${=find} "${MAILDIRS}/outbox" -type f` queue_outbox_num=`${=find} "${MAILDIRS}/outbox" -type f|wc -l` { test "$queue_outbox_num" = "0" } && { - act "Outbox is empty, no mails to send." - return 0 } + act "Outbox is empty, no mails to send." + return 0 } read_account ${account} { test $? != 0 } && { - error "Invalid account: $account" - return 1 + error "Invalid account: $account" + return 1 } # defaults @@ -310,8 +311,8 @@ send() { is_online ${smtp} ${smtp_port} { test $? = 0 } || { - error "Smtp host not reachable: $smtp_host:$smtp_port" - return 1 } + error "Smtp host not reachable: $smtp_host:$smtp_port" + return 1 } notice "Sending out $queue_outbox_num mails via account ${account}" @@ -325,18 +326,18 @@ send() { port=$smtp_port ask_password { test $? = 0 } || { - error "Error retrieving password for $login on $smtp" - unset password - unlock "${MAILDIRS}/outbox" - return 1 } + error "Error retrieving password for $login on $smtp" + unset password + unlock "${MAILDIRS}/outbox" + return 1 } for qbody in ${(f)queue_outbox}; do - # check if this is an anonymous mail - hdr "$qbody" | grep -i '^from: anon' > /dev/null - if [ $? = 0 ]; then - anoncfg="${TMPDIR}/${smtp}.anon.$RANDOM" - cat <<EOF > "$anoncfg" + # check if this is an anonymous mail + hdr "$qbody" | grep -i '^from: anon' > /dev/null + if [ $? = 0 ]; then + anoncfg="${TMPDIR}/${smtp}.anon.$RANDOM" + cat <<EOF > "$anoncfg" REMAIL n POOLSIZE 0 SENDPOOLTIME 0m @@ -354,19 +355,19 @@ VERBOSE=2 EOF - act "Sending out anonymous email via mixmaster" - recipients=(`cat $qbody | fetchaddr -a -x to | cut -d, -f1`) - recipients+=(`cat $qbody | fetchaddr -a -x cc | cut -d, -f1`) - for r in ${recipients}; do - act "Sending to: ${r}" + act "Sending out anonymous email via mixmaster" + recipients=(`cat $qbody | fetchaddr -a -x to | cut -d, -f1`) + recipients+=(`cat $qbody | fetchaddr -a -x cc | cut -d, -f1`) + for r in ${recipients}; do + act "Sending to: ${r}" - # parse subject line - anonsubj=`hdr "$qbody" | awk ' + # parse subject line + anonsubj=`hdr "$qbody" | awk ' /^Subject: / { for(i=2;i<=NF;i++) printf "%s ", $i }'` - act "Subject: $anonsubj" + act "Subject: $anonsubj" - # strip headers and send via mixmaster - cat "$qbody" | awk ' + # strip headers and send via mixmaster + cat "$qbody" | awk ' BEGIN { head=1 } /^To: / { print $0; next } /^Cc: / { print $0; next } @@ -381,26 +382,26 @@ BEGIN { head=1 } /^$/ { head=0 } { if(head==0) print $0 } ' | tee -a "$qbody.anon" | mixmaster --config=$anoncfg -m --to="$r" --subject="$anonsubj" - res=$? - mv "$qbody.anon" "$qbody" - func "mixmaster returns $res" - done + res=$? + mv "$qbody.anon" "$qbody" + func "mixmaster returns $res" + done - ${=rm} $anoncfg + ${=rm} $anoncfg - else # normal send with msmtp + else # normal send with msmtp - act "Sending out email" - hdr "$qbody" | awk ' + act "Sending out email" + hdr "$qbody" | awk ' /^From:/ { print " . " $0 } /^To:/ { print " . " $0 } /^Cc:/ { print " . " $0 } /^Subject:/ { print " . " $0 } ' - tmp="$TMPDIR/msmtp.$host.$datestamp.$RANDOM" - newlock "$tmp" - cat <<EOF > "$tmp" + tmp="$TMPDIR/msmtp.$host.$datestamp.$RANDOM" + newlock "$tmp" + cat <<EOF > "$tmp" account default from ${email} user ${login} @@ -413,25 +414,25 @@ logfile "${MAILDIRS}/logs/msmtp.log" auth ${auth} password ${password} EOF - tsize=`stat -c '%s' "$qbody"` - act "sending $tsize bytes over the network ..." - msmtp -C "$tmp" -t < "${qbody}" - res=$? - # unlink "$tmp" - unlock "$tmp" - rm -f "$tmp" - fi - - # evaluate results - if [ "$res" != "0" ]; then - error "Error sending mail, skipped" - else - notice "Mail sent succesfully" - # whitelist those to whom we send mails - cat "$qbody" | "$WORKDIR/bin/jaro" -q learn recipient - cat "$qbody" | deliver sent - { test $? = 0 } && { rm "$qbody" } - fi + tsize=`stat -c '%s' "$qbody"` + act "sending $tsize bytes over the network ..." + msmtp -C "$tmp" -t < "${qbody}" + res=$? + # unlink "$tmp" + unlock "$tmp" + rm -f "$tmp" + fi + + # evaluate results + if [ "$res" != "0" ]; then + error "Error sending mail, skipped" + else + notice "Mail sent succesfully" + # whitelist those to whom we send mails + cat "$qbody" | "$WORKDIR/bin/jaro" -q learn recipient + cat "$qbody" | deliver sent + { test $? = 0 } && { rm "$qbody" } + fi done @@ -447,8 +448,8 @@ EOF peek() { read_account ${account} { test $? != 0 } && { - error "Invalid account: $account" - return 1 + error "Invalid account: $account" + return 1 } is_online ${imap} ${imap_port} @@ -458,53 +459,53 @@ peek() { folder="" if ! [ -z ${1} ]; then - folder="${1}" - act "opening folder ${folder}" + folder="${1}" + act "opening folder ${folder}" fi case $transport in - ssl|tls) act "using secure connection (SSL)" - iproto="imaps" ;; - plain) act "using clear text connection" - iproto="imap" ;; - *) - error "Unknown transport: $transport" - error "Configuration error in imap account ${account}" - return 1 ;; + ssl|tls) act "using secure connection (SSL)" + iproto="imaps" ;; + plain) act "using clear text connection" + iproto="imap" ;; + *) + error "Unknown transport: $transport" + error "Configuration error in imap account ${account}" + return 1 ;; esac # escape at sign in login ilogin=`print $login | sed 's/@/\\@/'` { test $DRYRUN != 1 } && { - type=imap - host=$imap - port=$imap_port - ask_password - - { test $? != 0 } && { - error "Error retrieving password for $login on $imap" - unset password all; return 1 - } - tmp="$TMPDIR/$imap.peek.$RANDOM" - newlock "$tmp" - cat <<EOF >> "$tmp" + type=imap + host=$imap + port=$imap_port + ask_password + + { test $? != 0 } && { + error "Error retrieving password for $login on $imap" + unset password all; return 1 + } + tmp="$TMPDIR/$imap.peek.$RANDOM" + newlock "$tmp" + cat <<EOF >> "$tmp" set imap_pass = "${password}" # set imap_peek = yes EOF - unset password - print "source '$tmp'" > "$TMPDIR/muttpass" - # when peeking don't mark unread messages as Old - # and sort date received with no threading (latest up) - cat <<EOF >> "$TMPDIR/muttpass" + unset password + print "source '$tmp'" > "$TMPDIR/muttpass" + # when peeking don't mark unread messages as Old + # and sort date received with no threading (latest up) + cat <<EOF >> "$TMPDIR/muttpass" unset mark_old set sort=reverse-date-received EOF - (sleep 1; - cp /dev/null "$TMPDIR/muttpass" - unlink "$tmp" # secure delete in ram - ) & - ${=mutt} -F $MUTTDIR/rc -f ${iproto}://${ilogin}@${imap}:${imap_port}/${folder} + (sleep 1; + cp /dev/null "$TMPDIR/muttpass" + unlink "$tmp" # secure delete in ram + ) & + ${=mutt} -F $MUTTDIR/rc -f ${iproto}://${ilogin}@${imap}:${imap_port}/${folder} } # DRYRUN return $? diff --git a/src/zlibs/filters b/src/zlibs/filters @@ -55,23 +55,23 @@ init_inbox() { ${=mkdir} "$MAILDIRS/tmp" { test -d "$MAILDIRS/Accounts" } || { - ${=mkdir} "$MAILDIRS/Accounts" - cp "$WORKDIR"/Accounts/* "$MAILDIRS/Accounts/" } + ${=mkdir} "$MAILDIRS/Accounts" + cp "$WORKDIR"/Accounts/* "$MAILDIRS/Accounts/" } { test -r "$MAILDIRS"/Manual.pdf } || { - cp "$WORKDIR"/jaromail-manual.pdf "$MAILDIRS"/Manual.pdf } + cp "$WORKDIR"/jaromail-manual.pdf "$MAILDIRS"/Manual.pdf } { test -r "$MAILDIRS"/Identity.txt } || { - cp "$WORKDIR"/Identity.txt "$MAILDIRS"/Identity.txt } + cp "$WORKDIR"/Identity.txt "$MAILDIRS"/Identity.txt } { test -r "$MAILDIRS"/Filters.txt } || { - cp "$WORKDIR"/Filters.txt "$MAILDIRS"/Filters.txt } + cp "$WORKDIR"/Filters.txt "$MAILDIRS"/Filters.txt } { test -r "$MAILDIRS"/Aliases.txt } || { - cp "$WORKDIR"/Aliases.txt "$MAILDIRS"/Aliases.txt } + cp "$WORKDIR"/Aliases.txt "$MAILDIRS"/Aliases.txt } { test -r "$MAILDIRS"/Applications.txt } || { - cp "$WORKDIR"/Applications.txt "$MAILDIRS"/Applications.txt } + cp "$WORKDIR"/Applications.txt "$MAILDIRS"/Applications.txt } return 0 } @@ -80,8 +80,8 @@ init_inbox() { # the cache consists of array and maps declarations for zsh update_filters() { { test -r "$MAILDIRS/Filters.txt" } || { - error "Filters not found in $MAILDIRS/Filters.txt" - return 1 } + error "Filters not found in $MAILDIRS/Filters.txt" + return 1 } notice "Updating filters..." @@ -106,30 +106,30 @@ EOF # insert filter rules in the cache for f in ${(f)ffilters}; do - header="${f[(ws:;:)1]}" - regexp="${f[(ws:;:)2]}" - action="${f[(ws:;:)3]}" - destination="${f[(ws:;:)4]}" - case $header in - to) - cat <<EOF >> "$ff" + header="${f[(ws:;:)1]}" + regexp="${f[(ws:;:)2]}" + action="${f[(ws:;:)3]}" + destination="${f[(ws:;:)4]}" + case $header in + to) + cat <<EOF >> "$ff" filter_to+=("${regexp}" "${destination}") EOF - func "from: <${regexp}> -> ${destination}" - maildirmake $MAILDIRS/$destination - ;; - from) - cat <<EOF >> "$ff" + func "from: <${regexp}> -> ${destination}" + maildirmake $MAILDIRS/$destination + ;; + from) + cat <<EOF >> "$ff" filter_from+=("${regexp}" "${destination}") EOF - func "to: <${regexp}> -> ${destination}" - maildirmake $MAILDIRS/$destination - ;; - - *) - error "invalid filter: $f" - ;; - esac + func "to: <${regexp}> -> ${destination}" + maildirmake $MAILDIRS/$destination + ;; + + *) + error "invalid filter: $f" + ;; + esac done # compile the list of own addresses and aliases @@ -138,19 +138,19 @@ EOF /^$/ { next } /^email/ { print $2 }' \ "$MAILDIRS"/Accounts/*`; do - cat <<EOF >> "$ff" + cat <<EOF >> "$ff" filter_own+=($i) EOF done { test -r $MAILDIRS/Aliases.txt } && { - for i in `awk ' + for i in `awk ' /^#/ { next } /^$/ { next } { print $1 }' "$MAILDIRS/Aliases.txt"`; do - cat <<EOF >> "$ff" + cat <<EOF >> "$ff" filter_own+=($i) EOF - done + done } unlock "$ff" @@ -170,151 +170,151 @@ filter_maildir() { # be there. maildircheck "$MAILDIRS/unsorted" { test $? = 0 } || { - error "Invalid fallback maildir destination, operation aborted." - func "Returning error to caller." - return 1; } + error "Invalid fallback maildir destination, operation aborted." + func "Returning error to caller." + return 1; } # loads up the filter cache (zsh compiled arrays) { test -r "$MAILDIRS/cache/filters" } && { - source $MAILDIRS/cache/filters - ownfilters=1 } + source $MAILDIRS/cache/filters + ownfilters=1 } { test "$1" = "" } && { mdinput=incoming } maildircheck "$MAILDIRS/$mdinput" { test $? = 0 } || { - error "Invalid maildir to filter: $mdinput" - return 1; } + error "Invalid maildir to filter: $mdinput" + return 1; } numm=`${=find} "$MAILDIRS/$mdinput" -maxdepth 2 -type f|wc -l` mails=`${=find} "$MAILDIRS/$mdinput" -maxdepth 2 -type f` { test "$numm" = "0" } && { - error "Nothing to filter inside maildir $mdinput" - return 1 } + error "Nothing to filter inside maildir $mdinput" + return 1 } notice "Filtering maildir: $mdinput ($numm mails}" c=0 for m in ${(f)mails}; do - match=0 - c=$(($c + 1)) - - list="blacklist" - hdr "$m" | sender_isknown - { test $? = 0 } && { - cat "$m" | deliver zz.blacklist - { test $? = 0 } && { rm "$m" } - act "$c\t\t/ $numm\t\t->\tzz.blacklist" - continue } - - hdr "$m" | awk '/Sender.*mailman-bounce/ { exit 1 }' - { test $? = 0 } || { - act "$c\t\t/ $numm\t\t->\tzz.bounces" - cat "$m" | deliver zz.bounces - { test $? = 0 } && { rm "$m" } - continue } - - { test "$ownfilters" = "1" } && { - - func "processing through own filters" - ffrom=`hdr "$m" | ${WORKDIR}/bin/fetchaddr -x From -a` - - # run all filter regexps on the from: field - { test "$ffrom" = "" } || { - femail="${ffrom[(ws:,:)1]}" - for exp in ${(k)filter_from}; do - # special zsh parsing in PCRE (=~) - if [[ "$femail" =~ "$exp" ]]; then - # if destination maildir is same as input, skip - { test "${filter_from[$exp]}" = "$mdinput" } && { - act "$c\t\t/ $numm" - match=1; break } - act "$c\t\t/ $numm\t\t-> ${filter_from[$exp]}" - cat "$m" | deliver ${filter_from[$exp]} - if [ $? = 0 ]; then - func "from filter match: $exp" - match=1; rm "$m"; break - else - error "Error filtering to maildir ${filter_from[$exp]}" - error "File: $m" - continue - fi - fi - done - } - { test "$match" = "1" } && { continue } - - typeset -alU ftos - # recompile the array of destination addresses - ftos=(`hdr "$m" | ${WORKDIR}/bin/fetchaddr -x cc -a | cut -d, -f1`) - ftos+=(`hdr "$m" | ${WORKDIR}/bin/fetchaddr -x to -a | cut -d, -f1`) - - # run all filter regexps on the to: and cc: fields - { test "$ftos" = "" } || { - for ft in ${(f)ftos}; do - for exp in ${(k)filter_to}; do - # special zsh parsing in PCRE (=~) - if [[ "$ft" =~ "$exp" ]]; then - # if destination maildir is same as input, skip - { test "${filter_to[$exp]}" = "$mdinput" } && { - act "$c\t\t/ $numm" - match=1; break } - act "$c\t\t/ $numm\t\t-> ${filter_to[$exp]}" - cat "$m" | deliver ${filter_to[$exp]} - if [ $? = 0 ]; then - func "to filter match: $exp" - match=1; rm "$m"; break - else - error "Error filtering to maildir ${filter_to[$exp]}" - error "File: $m" - continue - fi - fi - done - { test "$match" = "1" } && { break } - done - } - - { test "$match" = "1" } && { func "own filter match"; continue } - - } # own filters - - list="whitelist" - hdr "$m" | sender_isknown - { test $? = 0 } && { - act "$c\t\t/ $numm\t\t-> known" - cat "$m" | deliver known - { test $? = 0 } && { rm "$m" } - continue } - - hdr "$m" | awk '/X-Spam-Flag.*YES/ { exit 1 }' - { test $? = 0 } || { - act "$c\t\t/ $numm\t\t-> zz.spam" - cat "$m" | deliver zz.spam - { test $? = 0 } && { rm "$m" } - continue } - - # parse own email and aliases - match=0 - for f in $ftos; do - # check if destination address is in filter_own array - if [[ ${filter_own[(r)$f]} == ${f} ]] ; then - act "$c\t\t/ $numm\t\t-> priv" - cat "$m" | deliver priv - { test $? = 0 } && { rm "$m"; match=1; break } - fi - done - { test "$match" = "1" } && { continue } - - # if here then file to unsorted - if [ "$mdinput" = "unsorted" ]; then - act "$c\t\t/ $numm" - else - act "$c\t\t/ $numm\t\t-> unsorted" - cat "$m" | deliver unsorted - { test $? = 0 } && { rm "$m" } - fi + match=0 + c=$(($c + 1)) + + list="blacklist" + hdr "$m" | sender_isknown + { test $? = 0 } && { + cat "$m" | deliver zz.blacklist + { test $? = 0 } && { rm "$m" } + act "$c\t\t/ $numm\t\t->\tzz.blacklist" + continue } + + hdr "$m" | awk '/Sender.*mailman-bounce/ { exit 1 }' + { test $? = 0 } || { + act "$c\t\t/ $numm\t\t->\tzz.bounces" + cat "$m" | deliver zz.bounces + { test $? = 0 } && { rm "$m" } + continue } + + { test "$ownfilters" = "1" } && { + + func "processing through own filters" + ffrom=`hdr "$m" | ${WORKDIR}/bin/fetchaddr -x From -a` + + # run all filter regexps on the from: field + { test "$ffrom" = "" } || { + femail="${ffrom[(ws:,:)1]}" + for exp in ${(k)filter_from}; do + # special zsh parsing in PCRE (=~) + if [[ "$femail" =~ "$exp" ]]; then + # if destination maildir is same as input, skip + { test "${filter_from[$exp]}" = "$mdinput" } && { + act "$c\t\t/ $numm" + match=1; break } + act "$c\t\t/ $numm\t\t-> ${filter_from[$exp]}" + cat "$m" | deliver ${filter_from[$exp]} + if [ $? = 0 ]; then + func "from filter match: $exp" + match=1; rm "$m"; break + else + error "Error filtering to maildir ${filter_from[$exp]}" + error "File: $m" + continue + fi + fi + done + } + { test "$match" = "1" } && { continue } + + typeset -alU ftos + # recompile the array of destination addresses + ftos=(`hdr "$m" | ${WORKDIR}/bin/fetchaddr -x cc -a | cut -d, -f1`) + ftos+=(`hdr "$m" | ${WORKDIR}/bin/fetchaddr -x to -a | cut -d, -f1`) + + # run all filter regexps on the to: and cc: fields + { test "$ftos" = "" } || { + for ft in ${(f)ftos}; do + for exp in ${(k)filter_to}; do + # special zsh parsing in PCRE (=~) + if [[ "$ft" =~ "$exp" ]]; then + # if destination maildir is same as input, skip + { test "${filter_to[$exp]}" = "$mdinput" } && { + act "$c\t\t/ $numm" + match=1; break } + act "$c\t\t/ $numm\t\t-> ${filter_to[$exp]}" + cat "$m" | deliver ${filter_to[$exp]} + if [ $? = 0 ]; then + func "to filter match: $exp" + match=1; rm "$m"; break + else + error "Error filtering to maildir ${filter_to[$exp]}" + error "File: $m" + continue + fi + fi + done + { test "$match" = "1" } && { break } + done + } + + { test "$match" = "1" } && { func "own filter match"; continue } + + } # own filters + + list="whitelist" + hdr "$m" | sender_isknown + { test $? = 0 } && { + act "$c\t\t/ $numm\t\t-> known" + cat "$m" | deliver known + { test $? = 0 } && { rm "$m" } + continue } + + hdr "$m" | awk '/X-Spam-Flag.*YES/ { exit 1 }' + { test $? = 0 } || { + act "$c\t\t/ $numm\t\t-> zz.spam" + cat "$m" | deliver zz.spam + { test $? = 0 } && { rm "$m" } + continue } + + # parse own email and aliases + match=0 + for f in $ftos; do + # check if destination address is in filter_own array + if [[ ${filter_own[(r)$f]} == ${f} ]] ; then + act "$c\t\t/ $numm\t\t-> priv" + cat "$m" | deliver priv + { test $? = 0 } && { rm "$m"; match=1; break } + fi + done + { test "$match" = "1" } && { continue } + + # if here then file to unsorted + if [ "$mdinput" = "unsorted" ]; then + act "$c\t\t/ $numm" + else + act "$c\t\t/ $numm\t\t-> unsorted" + cat "$m" | deliver unsorted + { test $? = 0 } && { rm "$m" } + fi done @@ -387,29 +387,29 @@ EOF wwwtext=w3m if command -v elinks > /dev/null; then - cat <<EOF >> $MUTTDIR/mailcap + cat <<EOF >> $MUTTDIR/mailcap text/html; elinks -dump -dump-charset %{charset} %s; nametemplate=%s.html; copiousoutput EOF elif command -v w3m > /dev/null; then - cat <<EOF >> $MUTTDIR/mailcap + cat <<EOF >> $MUTTDIR/mailcap text/html; w3m -I %{charset} -T text/html %s; nametemplate=%s.html; copiousoutput EOF elif command -v lynx > /dev/null; then - cat <<EOF >> $MUTTDIR/mailcap + cat <<EOF >> $MUTTDIR/mailcap text/html; lynx -dump -assume_charset=%{charset} %s; nametemplate=%s.html; copiousoutput EOF fi { test -r "${MAILDIRS}/Applications.txt" } && { - # here is the tweak to open attachments - # with Mutt without blocking it (fork) + # here is the tweak to open attachments + # with Mutt without blocking it (fork) apptypes=`cat "${MAILDIRS}/Applications.txt"` for t in ${(f)apptypes}; do - eval `print $t | awk ' + eval `print $t | awk ' { print "_type=" $1 "; _app=" $2 ";" }'` - cat <<EOF >> $MUTTDIR/mailcap + cat <<EOF >> $MUTTDIR/mailcap ${_type}; a="${TMPDIR}" && f=\`basename %s\` && rm -f "\$a"/"\$f" && cp %s "\$a"/"\$f" && ${_app} "\$a"/"\$f" EOF done @@ -428,9 +428,9 @@ EOF for f in `cat "$MAILDIRS/Filters.txt" | awk ' /^#/ {next} /^./ { print $4 }'`; do - # MUTT (generate mailboxes priority this parser) - print " \\" >> $MUTTDIR/mboxes - print -n " +${f} " >> $MUTTDIR/mboxes + # MUTT (generate mailboxes priority this parser) + print " \\" >> $MUTTDIR/mboxes + print -n " +${f} " >> $MUTTDIR/mboxes done print " \\" >> $MUTTDIR/mboxes print " +unsorted.ml +unsorted" >> $MUTTDIR/mboxes @@ -456,10 +456,10 @@ $condition [ EOF c=${#sieve_filter_array} for i in $sieve_filter_array; do - print -n "\"$i\"" >> "$MAILDIRS/Filters.sieve" - c=$(( $c - 1 )) - { test $c != 0 } && { print -n "," >> "$MAILDIRS/Filters.sieve" } - print >> "$MAILDIRS/Filters.sieve" + print -n "\"$i\"" >> "$MAILDIRS/Filters.sieve" + c=$(( $c - 1 )) + { test $c != 0 } && { print -n "," >> "$MAILDIRS/Filters.sieve" } + print >> "$MAILDIRS/Filters.sieve" done cat <<EOF >> "$MAILDIRS/Filters.sieve" @@ -480,12 +480,12 @@ sieve_complex_filter() { [[ ${#sieve_filter_map} == 0 ]] && { return 1 } condition="$1" func "Sieve complex filter entries: ${#sieve_filter_map}" - + for fil in ${(k)sieve_filter_map}; do - print "$condition \"${fil}\" { fileinto :create \"${sieve_filter_map[$fil]}\"; stop; }" \ - >> "$MAILDIRS/Filters.sieve" + print "$condition \"${fil}\" { fileinto :create \"${sieve_filter_map[$fil]}\"; stop; }" \ + >> "$MAILDIRS/Filters.sieve" done - + return 0 } @@ -509,17 +509,17 @@ EOF sieve_filter_array=() newlock "$TMPDIR/blacklist.sieve.$id" cat <<EOF | ${SQL} -batch ${addressbook} \ - >> "$TMPDIR/blacklist.sieve.$id" + >> "$TMPDIR/blacklist.sieve.$id" SELECT email FROM blacklist; EOF for i in `cat "$TMPDIR/blacklist.sieve.$id"`; do - sieve_filter_array+=("$i"); done + sieve_filter_array+=("$i"); done unlink "$TMPDIR/blacklist.sieve.$id" { test "${#sieve_filter_array}" = "0" } || { - sieve_filter \ - 'if header :contains "From"' \ - zz.blacklist + sieve_filter \ + 'if header :contains "From"' \ + zz.blacklist } # bounces @@ -554,19 +554,19 @@ EOF sieve_filter_array=() newlock "$TMPDIR/whitelist.sieve.$id" cat <<EOF | ${SQL} -batch ${addressbook} \ - >> "$TMPDIR/whitelist.sieve.$id" + >> "$TMPDIR/whitelist.sieve.$id" SELECT email FROM whitelist; EOF for i in `cat "$TMPDIR/whitelist.sieve.$id"`; do - sieve_filter_array+=("$i"); done + sieve_filter_array+=("$i"); done unlink "$TMPDIR/whitelist.sieve.$id" sieve_filter \ - 'if header :contains "From"' \ - INBOX + 'if header :contains "From"' \ + INBOX cat <<EOF >> "$MAILDIRS/Filters.sieve" # spam @@ -579,8 +579,8 @@ EOF # own addresses and aliases sieve_filter_array=($filter_own) sieve_filter \ - 'if header :contains [ "To","Cc" ] ' \ - priv + 'if header :contains [ "To","Cc" ] ' \ + priv # unsorted cat <<EOF >> "$MAILDIRS/Filters.sieve" diff --git a/src/zlibs/helpers b/src/zlibs/helpers @@ -27,6 +27,23 @@ # which mutt binary to use mutt="mutt" +# extract all emails found in a text from stdin +# outputs them one per line +extract_emails() { +awk '{ for (i=1;i<=NF;i++) + if ( $i ~ /[[:alnum:]]@[[:alnum:]]/ ) { + gsub(/<|>|,/ , "" , $i); print $i } }' +} + +# parses stdin and converts some characters to html +escape_html() { + sed -e ' +s/\&/\&amp;/g +s/>/\&gt;/g +s/</\&lt;/g +s/"/\&quot;/g +' +} autostart() { @@ -34,44 +51,44 @@ autostart() { # no argument passed. open first folder with new mail { test -z ${1} } && { - { test ! -r $MUTTDIR/rc } \ - && { error "Jaro Mail is not yet configured." - error "To configure, edit the files in $MAILDIRS/Accounts" - return 1 } + { test ! -r $MUTTDIR/rc } \ + && { error "Jaro Mail is not yet configured." + error "To configure, edit the files in $MAILDIRS/Accounts" + return 1 } - ${=mutt} -F $MUTTDIR/rc ${=muttflags} -Z - return $? + ${=mutt} -F $MUTTDIR/rc ${=muttflags} -Z + return $? } # argument passed: determine if an email print "${1}" \ - | tr 'A-Z' 'a-z' \ - | grep '^[a-zA-Z0-9._%+-]*@[a-zA-Z0-9]*[\.[a-zA-Z0-9]*]*[a-zA-Z0-9]$' \ - > /dev/null + | tr 'A-Z' 'a-z' \ + | grep '^[a-zA-Z0-9._%+-]*@[a-zA-Z0-9]*[\.[a-zA-Z0-9]*]*[a-zA-Z0-9]$' \ + > /dev/null { test $? = 0 } && { - notice "Composing message to: ${@}" - # its an email, TODO see if we have it in our addressbook - ${=mutt} -F $MUTTDIR/rc ${=muttflags} ${=@} - return 0 + notice "Composing message to: ${@}" + # its an email, TODO see if we have it in our addressbook + ${=mutt} -F $MUTTDIR/rc ${=muttflags} ${=@} + return 0 } # or a directory of file { test -r "$1" } && { - # is it a maildir? then open - { maildircheck ${1} } && { - ${=mutt} -F $MUTTDIR/rc ${=muttflags} -f ${1} - return 0 } - # is it a regular file? then attach it - { test -f "$1" } && { - ${=mutt} -F $MUTTDIR/rc ${=muttflags} -a ${=@} - return 0 } + # is it a maildir? then open + { maildircheck ${1} } && { + ${=mutt} -F $MUTTDIR/rc ${=muttflags} -f ${1} + return 0 } + # is it a regular file? then attach it + { test -f "$1" } && { + ${=mutt} -F $MUTTDIR/rc ${=muttflags} -a ${=@} + return 0 } } # or the name of a folder in Jaro Mail { maildircheck "$MAILDIRS/$1" } && { - notice "Opening folder ${1}" - ${=mutt} -F $MUTTDIR/rc ${=muttflags} -f "$MAILDIRS/${1}" - return 0 + notice "Opening folder ${1}" + ${=mutt} -F $MUTTDIR/rc ${=muttflags} -f "$MAILDIRS/${1}" + return 0 } return $? @@ -81,8 +98,8 @@ autostart() { # short utility to print only mail headers hdr() { { test -r "$1" } || { - error "hdr() called on non existing file: $1" - return 1 } + error "hdr() called on non existing file: $1" + return 1 } awk '{ print $0 } /^$/ { exit }' "$1" } @@ -90,8 +107,8 @@ hdr() { # short utility to print only mail body body() { { test -r "$1" } || { - error "body() called on non existing file: $1" - return 1 } + error "body() called on non existing file: $1" + return 1 } awk ' BEGIN { head=1 } /^$/ { head=0 } @@ -109,7 +126,7 @@ BEGIN { head=1 } # however the default is nano if nothing else is choosen. jarovim() { vim -c 'set fo=tcrq' -c 'set tw=72' \ - -c 'map <C-j> {gq}' -c 'imap <C-j> <esc>{gq}i' \ + -c 'map <C-j> {gq}' -c 'imap <C-j> <esc>{gq}i' \ "${@}" return $? } @@ -119,27 +136,27 @@ edit_file() { { test ${JARO_EDITOR} } && { _editor="$JARO_EDITOR" } { test "$_editor" = "" } && { _editor=vim } case $_editor in - # refine settings for email - vi|vim) jarovim "${PARAM}"; return $? ;; - emacs) emacsclient -a emacs "${PARAM}"; return $? ;; - *) ${=_editor} "${PARAM}"; return $? ;; + # refine settings for email + vi|vim) jarovim "${PARAM}"; return $? ;; + emacs) emacsclient -a emacs "${PARAM}"; return $? ;; + *) ${=_editor} "${PARAM}"; return $? ;; esac # if we are here we need to guess case $OS in - MAC) open -t ${=PARAM} ;; - GNU) - ps ax|grep '[e]macs' > /dev/null - if [ $? = 0 ]; then - emacsclient -a ${=PARAM} - elif command -v vim > /dev/null; then - jarovim ${=PARAM} - elif command -v nano > /dev/null; then - nano -m -S -Q ">" -I -E -D -T 4 -U -W -c -i -k -r 72 ${=PARAM} - else - error "No editor found, please configure the JARO_EDITOR environment variable." - fi - ;; + MAC) open -t ${=PARAM} ;; + GNU) + ps ax|grep '[e]macs' > /dev/null + if [ $? = 0 ]; then + emacsclient -a ${=PARAM} + elif command -v vim > /dev/null; then + jarovim ${=PARAM} + elif command -v nano > /dev/null; then + nano -m -S -Q ">" -I -E -D -T 4 -U -W -c -i -k -r 72 ${=PARAM} + else + error "No editor found, please configure the JARO_EDITOR environment variable." + fi + ;; esac return $? } @@ -149,8 +166,8 @@ edit_file() { open_folder() { notice "Opening folder ${1}" { maildircheck ${MAILDIRS}/${1} } && { - ${=mutt} -F $MUTTDIR/rc ${=muttflags} -f "$MAILDIRS/${1}" - return $? } + ${=mutt} -F $MUTTDIR/rc ${=muttflags} -f "$MAILDIRS/${1}" + return $? } return 1 } @@ -158,12 +175,12 @@ open_folder() { ## Open a File preview_file() { case $OS in - GNU) - xdg-open "${PARAM}" & - ;; - MAC) - open -g "${PARAM}" - ;; + GNU) + xdg-open "${PARAM}" & + ;; + MAC) + open -g "${PARAM}" + ;; esac } @@ -173,8 +190,8 @@ preview_file() { is_online() { func "Test if we are online" { test "$FORCE" = "1" } && { - act "Internet check skipped (--force in use)" - return 0 + act "Internet check skipped (--force in use)" + return 0 } _res=1 _host=${1:-8.8.8.8} @@ -182,95 +199,95 @@ is_online() { _mode=inet # or host { test "$_port" = "NONE" } || { _mode=host } - + case $_mode in - inet) - func "trying to ping ${_host}" - ping -c1 -n ${_host} 2>&1 > /dev/null - { test $? = 0 } || { - error "Internet seems unreachable" - act "Network connection is checked with a ping to 8.8.8.8" - act "if your network doesn't allows it to pass, use -f to force." - error "Operation aborted." - exit 1 - } - act "Internet seems to be reachable" - ;; - host) - func "trying to connect ${_host} port ${_port}" - nc -w 16 -z ${_host} ${_port} > /dev/null - { test $? = 0 } || { - error "Host unreachable: $_host" - act "Network connection is checked with 16s timeout" - act "if you want to bypass this check, use -f to force." - error "Operation aborted." - return 1 - } - act "Host $_host responds on port $_port" - ;; + inet) + func "trying to ping ${_host}" + ping -c1 -n ${_host} 2>&1 > /dev/null + { test $? = 0 } || { + error "Internet seems unreachable" + act "Network connection is checked with a ping to 8.8.8.8" + act "if your network doesn't allows it to pass, use -f to force." + error "Operation aborted." + exit 1 + } + act "Internet seems to be reachable" + ;; + host) + func "trying to connect ${_host} port ${_port}" + nc -w 16 -z ${_host} ${_port} > /dev/null + { test $? = 0 } || { + error "Host unreachable: $_host" + act "Network connection is checked with 16s timeout" + act "if you want to bypass this check, use -f to force." + error "Operation aborted." + return 1 + } + act "Host $_host responds on port $_port" + ;; esac return 0 } - + # opens and closes a ramdisk for temporary files # users can do this explicitly between session to speed up operations ramdisk() { case $OS in - GNU) - # TODO - # not so urgent, since usually /dev/shm is mounted and writable - ;; - MAC) - case ${PARAM[1]} in - open) - mount | grep 'JaroTmp' > /dev/null - { test $? = 0 } && { - error "A Jaro Mail ramdisk is already open" - return 1 } - { test -z ${PARAM[2]} } && { size=10 } || { size=${PARAM[2]} } - act "Creating ramdisk of ${size}MB" - - # 2048 is a megabyte here - devsize=$((1024*2*$size)) - devname=`hdid -nomount ram://${devsize}` - act "Mounting ramdisk on $devname" - diskutil eraseVolume HFS+ JaroTmp `basename $devname` > /dev/null - { test $? != 0 } && { - error "Error initializing ramdisk" - hdiutil detach `basename $devname` - return 1 } - notice "Operation successful, ramdisk ready on /Volume/JaroTmp" - TMPRAM=1 - ;; - close) - devname=`mount | awk '/JaroTmp/ {print $1}'` - { test "$devname" = "" } && { - error "No ramdisk seems to be open" - return 1 } - act "Unmounting ramdisk: $devname" - diskutil unmount /Volumes/JaroTmp > /dev/null - hdiutil detach `basename $devname` > /dev/null - notice "Ramdisk succesfully detached" - TMPRAM=0 - ;; - esac - ;; + GNU) + # TODO + # not so urgent, since usually /dev/shm is mounted and writable + ;; + MAC) + case ${PARAM[1]} in + open) + mount | grep 'JaroTmp' > /dev/null + { test $? = 0 } && { + error "A Jaro Mail ramdisk is already open" + return 1 } + { test -z ${PARAM[2]} } && { size=10 } || { size=${PARAM[2]} } + act "Creating ramdisk of ${size}MB" + + # 2048 is a megabyte here + devsize=$((1024*2*$size)) + devname=`hdid -nomount ram://${devsize}` + act "Mounting ramdisk on $devname" + diskutil eraseVolume HFS+ JaroTmp `basename $devname` > /dev/null + { test $? != 0 } && { + error "Error initializing ramdisk" + hdiutil detach `basename $devname` + return 1 } + notice "Operation successful, ramdisk ready on /Volume/JaroTmp" + TMPRAM=1 + ;; + close) + devname=`mount | awk '/JaroTmp/ {print $1}'` + { test "$devname" = "" } && { + error "No ramdisk seems to be open" + return 1 } + act "Unmounting ramdisk: $devname" + diskutil unmount /Volumes/JaroTmp > /dev/null + hdiutil detach `basename $devname` > /dev/null + notice "Ramdisk succesfully detached" + TMPRAM=0 + ;; + esac + ;; esac } human_size() { { test $1 -gt 0 } || { - error "human_size() called with zero argument" - return 1 } + error "human_size() called with zero argument" + return 1 } # megabytes { test $1 -gt 1048576 } && { - print -n "$(( $1 / 1024 / 1024 )) MB" - return 0} + print -n "$(( $1 / 1024 / 1024 )) MB" + return 0} # kilobytes { test $1 -gt 1024 } && { - print -n "$(( $1 / 1024 )) KB" - return 0} + print -n "$(( $1 / 1024 )) KB" + return 0} # bytes print -n "$1 Bytes" return 0 @@ -287,40 +304,40 @@ cert() { cc=Equifax_Secure_Certificate_Authority if ! [ -r $MAILDIRS/certs/${cc}.pem ]; then - curl -o $MAILDIRS/certs/${cc}.pem \ - "https://www.geotrust.com/resources/root_certificates/certificates/${cc}.cer" - openssl x509 -in \ - $MAILDIRS/certs/${cc}.pem -fingerprint \ - -subject -issuer -serial -hash -noout + curl -o $MAILDIRS/certs/${cc}.pem \ + "https://www.geotrust.com/resources/root_certificates/certificates/${cc}.cer" + openssl x509 -in \ + $MAILDIRS/certs/${cc}.pem -fingerprint \ + -subject -issuer -serial -hash -noout fi notice "Google CA succesfully installed" # dyne|autistici|freaknet) cc=Autistici_Certificate_Authority if ! [ -r $MAILDIRS/certs/${cc}.pem ]; then - curl -o $MAILDIRS/certs/${cc}.pem \ - "http://ca.autistici.org/ca.pem" - openssl x509 -in \ - $MAILDIRS/certs/${cc}.pem \ - -fingerprint -subject -issuer -serial -hash -noout + curl -o $MAILDIRS/certs/${cc}.pem \ + "http://ca.autistici.org/ca.pem" + openssl x509 -in \ + $MAILDIRS/certs/${cc}.pem \ + -fingerprint -subject -issuer -serial -hash -noout fi notice "Aut/Inv CA succesfully installed" # riseup) cc=RiseupCA if ! [ -r $MAILDIRS/certs/${cc}.pem ]; then - curl -o $MAILDIRS/certs/${cc}.pem "https://help.riseup.net/assets/43052/RiseupCA.pem" - openssl x509 -in \ - $MAILDIRS/certs/${cc}.pem \ - -fingerprint -subject -issuer -serial -hash -noout + curl -o $MAILDIRS/certs/${cc}.pem "https://help.riseup.net/assets/43052/RiseupCA.pem" + openssl x509 -in \ + $MAILDIRS/certs/${cc}.pem \ + -fingerprint -subject -issuer -serial -hash -noout fi notice "Riseup CA succesfully installed" act "refreshing certificates" c_rehash $MAILDIRS/certs > /dev/null if [ $? != 0 ]; then - error "Error refreshing certificates in $MAILDIRS/certs" - c_rehash $MAILDIRS/certs + error "Error refreshing certificates in $MAILDIRS/certs" + c_rehash $MAILDIRS/certs fi notice "Done importing most common certificates." return 0