commit c8fbefbb5a92e2285621a24431582fec04686fc5
parent 3dcefa72ffb432c96f6af3fcee59ccc361ccaeca
Author: Jaromil <jaromil@dyne.org>
Date: Wed, 7 Jan 2015 20:37:40 +0100
new tmpfile system and endgame() plus cleanups to addressbook import code
Diffstat:
8 files changed, 389 insertions(+), 412 deletions(-)
diff --git a/doc/Accounts/default.txt b/doc/Accounts/default.txt
@@ -34,7 +34,7 @@ auth plain # or kerberos, etc
cert ignore
# Transport protocol: ssl, tls or plain
-transport ssl
+transport tls
# Options when fetching
diff --git a/src/jaro b/src/jaro
@@ -34,7 +34,6 @@ DEBUG=0
DRYRUN=0
CLEANEXIT=1
CALLMUTT=1
-TMPRAM=0
# global variables for binaries called
typeset -h rm mkdir mutt
@@ -88,6 +87,71 @@ typeset -h muttflags
autoload colors; colors
+# temporary directory
+typeset TMPPREFIX=${TMPPREFIX:-/tmp}
+typeset -H JAROTMP # Filename of secure temp just created (see _tmp_create())
+typeset -aH JAROTMPFILES # Keep track of temporary files
+
+# Provide a random filename in shared memory
+_tmp_create() {
+ [[ -d "$TMPPREFIX" ]] || {
+ # we create the tempdir with the sticky bit on
+ sudo mkdir -m 1777 "$TMPPREFIX"
+ [[ $? == 0 ]] || _failure "Fatal error creating the temporary directory: ::1 temp dir::" "$TMPPREFIX"
+ }
+
+ # We're going to add one more $RANDOM for each time someone complain
+ # about this being too weak of a random.
+ tfile="${TMPPREFIX}/$RANDOM$RANDOM$RANDOM$RANDOM" # Temporary file
+ umask 066
+ [[ $? == 0 ]] || {
+ error "Fatal error setting the permission umask for temporary files"
+ return 1
+ }
+
+ [[ -r "$tfile" ]] && {
+ error "Someone is messing up with us trying to hijack temporary files."
+ return 1
+ }
+
+ touch "$tfile"
+ [[ $? == 0 ]] || {
+ error "Fatal error creating a temporary file: ::1 temp file::" "$tfile"
+ return 1
+ }
+
+ [[ $? == 0 ]] || {
+ error "Fatal error setting ownership on temporary file: ::1 temp file::" "$tfile"
+ return 1
+ }
+
+ func "Created tempfile: $tfile"
+ JAROTMP="$tfile"
+ JAROTMPFILES+=("$tfile")
+
+ return 0
+}
+
+# Cleanup anything sensitive before exiting.
+_endgame() {
+ # Clear temporary files
+ for f in $JAROTMPFILES; do
+ func "endgame() cleaning tempfile $f"
+ rm -f "$f"
+ done
+ unset JAROTMPFILES
+}
+# Trap functions for the _endgame event
+TRAPINT() { _endgame INT }
+TRAPEXIT() { _endgame EXIT }
+TRAPHUP() { _endgame HUP }
+TRAPQUIT() { _endgame QUIT }
+TRAPABRT() { _endgame ABORT }
+TRAPKILL() { _endgame KILL }
+TRAPPIPE() { _endgame PIPE }
+TRAPTERM() { _endgame TERM }
+TRAPSTOP() { _endgame STOP }
+
# standard output message routines
# it's always useful to wrap them, in case we change behaviour later
notice() { if [[ $QUIET == 0 ]]; then print "$fg_bold[green][*]$fg_no_bold[default] $1" >&2; fi }
@@ -197,48 +261,24 @@ fi
ACCOUNTS="$MAILDIRS/Accounts"
KEYRING="$MAILDIRS/Keyring"
-# temporary directory
-TMPDIR="$MAILDIRS/tmp/jaromil.$USER"
-case $OS in
- GNU)
- touch /dev/shm/test.jaromail.$USER > /dev/null
- { test $? = 0 } && {
- # we can use volatile ram
- rm /dev/shm/test.jaromail.$USER
- TMPDIR=/dev/shm/tmp.jaromail.$USER
- TMPRAM=1
- }
-
- # backward compatibility tests for old paths in JaroMail <1.3
- { test -d $WORKDIR/Accounts } && { test ! -d $ACCOUNTS } && {
- act "Updating accounts location: $ACCOUNTS"
- cp -ra $WORKDIR/Accounts $ACCOUNTS }
-
- { test -r "$WORKDIR/keyring" } && { test ! -r "$KEYRING" } && {
- act "Updating keyring location: $KEYRING"
- cp $WORKDIR/keyring "$KEYRING" }
+case $OS in
+ GNU)
+ # backward compatibility tests for old paths in JaroMail <1.3
+ { test -d $WORKDIR/Accounts } && { test ! -d $ACCOUNTS } && {
+ act "Updating accounts location: $ACCOUNTS"
+ cp -ra $WORKDIR/Accounts $ACCOUNTS
+ }
+
+ { test -r "$WORKDIR/keyring" } && { test ! -r "$KEYRING" } && {
+ act "Updating keyring location: $KEYRING"
+ cp $WORKDIR/keyring "$KEYRING"
+ }
;;
MAC)
- mount | grep 'JaroTmp' > /dev/null
- { test $? = 0 } && {
- # our RAM temp directory is active
- TMPDIR=/Volumes/JaroTmp/jaromail.$USER
- TMPRAM=1
- }
;;
esac
-# use the TMP in RAM if possible, for acceleration
-{ test $TMPRAM = 1 } && {
- act "Using temporary directory in volatile RAM" }
-
-# make sure we have a temp dir
-${=mkdir} "$TMPDIR"
-{ test $? != 0 } && {
- error "Cannot create temporary directory: $TMPDIR"
- return 1 }
-
hostname=$(hostname) # gather the current hostname
# make sure we have a directory for account configurations
@@ -275,65 +315,6 @@ pidof gnome-keyring-daemon > /dev/null && {
act "using gnome-keyring to store secrets"
GNOMEKEY=1 }
-
-cleanexit() {
- func "Clean exit procedures"
-
- # security check
- { test "$TMPDIR" = "" } && {
- error "Temporary directory not defined"
- act "skipping cleanup, this might leave private traces."
- return 1
- }
-
- # first delete dirs
- tmpdirs=`${=find} "$TMPDIR" -maxdepth 1 -type d`
- for d in ${(f)tmpdirs}; do
- { test "$d" = "$TMPDIR" } || {
- func "deleting dir: $d"
- ${=rm} -r "${d}" }
- done
-
- # then locks, with a warning
- llist=`${=find} "$TMPDIR" -maxdepth 1 -type f -name '*.lock'`
- for l in ${(f)llist}; do
- lname=`basename ${(s:.lock:)l}`
- func "cleaning lock for $lname"
-
- # skip if in course of unlink - parallel operation, see unlink()
- pidfile="${TMPDIR}/$lname.pid"
- if [ -r ${pidfile} ]; then
- pid=`cat $pidfile`
- func "forced removal of lock left by pid $pid: $lname"
- rm -f ${pidfile}
- else
- func "forced removal of lock left by unknown pid: $lname"
- fi
- rm -f "${TMPDIR}/${lname}.lock"
-
- # remove the actual file
- if [ -r "${TMPDIR}/$lname" ]; then
- func "deleting temp file: ${TMPDIR}/$lname"
- ${=rm} "${TMPDIR}/$lname"
- else func "empty lock: file was already removed"; fi
-
- done
-
-
-# { test $TMPRAM = 1 } && { rmdir $TMPDIR }
-}
-# make sure tmp is wiped from sensitive data in case of sigINT
-TRAPINT() {
- error "Caught signal, aborting operations."
-
- { test $CLEANEXIT = 1 } && {
- func "Forcing removal of locks"
- cleanexit & }
-
- if [ "$DEBUG" = "1" ]; then return 1
- else exit 1; fi
-}
-
# binary programs recognition
check_bin() {
@@ -388,7 +369,7 @@ check_bin() {
fi
func "Mutt binary: $mutt"
# make sure there is always a muttpass file even if empty
- touch $TMPDIR/muttpass
+ touch $MAILDIR/tmp/muttpass
return 0
}
@@ -713,7 +694,7 @@ main()
learn) CLEANEXIT=0; learn ${PARAM} ;;
forget) CLEANEXIT=0; forget ${PARAM} ;;
- import) import_addressbook "${PARAM}" ;;
+ import) import ${PARAM} ;;
"export")
case "$PARAM" in
abook)
@@ -728,9 +709,9 @@ main()
abook) edit_abook ${PARAM} ;;
- edit|vim) CLEANEXIT=0; edit_file ${PARAM} ;;
- open) CLEANEXIT=0; open_folder ${PARAM} ;;
- preview) CLEANEXIT=0; preview_file ${PARAM} ;;
+ edit|vim) CLEANEXIT=0; edit_file ${PARAM} ;;
+ open) CLEANEXIT=0; open_folder ${PARAM} ;;
+ preview) CLEANEXIT=0; preview_file ${PARAM} ;;
backup) backup ${PARAM} ;;
rmdupes) rmdupes ${PARAM} ;;
@@ -801,18 +782,18 @@ main()
;;
list|extract)
- extract ${PARAM}
- exitcode=$?
- ;;
+ extract ${PARAM}
+ exitcode=$?
+ ;;
*) # unknown command, pass it to autostart
func "unknown command, remote check"
autostart ${PARAM}
exitcode=$?
{ $exitcode != 0 } && {
- error "command \"$subcommand\" not recognized"
- act "try -h for help"
- CLEANEXIT=0
+ error "command \"$subcommand\" not recognized"
+ act "try -h for help"
+ CLEANEXIT=0
}
;;
esac
@@ -822,5 +803,4 @@ main()
check_bin
main $@
-{ test "$CLEANEXIT" = "1" } && { cleanexit & }
return $exitcode
diff --git a/src/zlibs/addressbook b/src/zlibs/addressbook
@@ -282,6 +282,90 @@ extract_maildir() {
return 0
}
+
+# import emails from VCard into abook
+# checks if the emails are already known
+import_vcard() {
+ act "import VCard from file: $1"
+
+ [[ -r "$1" ]] || {
+ error "File not found: $1"
+ return 1
+ }
+
+ vcard="$1"
+ head -n1 $vcard | grep '^BEGIN:VCARD' > /dev/null
+
+ [[ $? = 0 ]] || {
+ error "File to import is not a VCard: $vcard"
+ return 1
+ }
+
+ notice "Import VCard in addressbook: ${vcard}"
+
+ # parse the vcard and print a simple name and email list
+ # each value on a single line, entry tuples followed by a #
+ # we skip entries that don't have an email
+ addresses=`cat ${vcard} | awk '
+BEGIN { newcard=0; c=0; name=""; email=""; }
+/^BEGIN:VCARD/ { newcard=1 }
+/^FN:/ { if(newcard = 1) name=$0 }
+/^EMAIL/ { if(newcard = 1) email=$0 }
+/^END:VCARD/ {
+ if(newcard = 1) {
+ newcard=0
+ if(email != "") {
+ c+=1
+ print name
+ print email
+ print "# " c
+ }
+ email=""
+ next
+ }
+}
+' | cut -d: -f2`
+
+ # now parse the temporary list of name and emails
+ # made of name, email and a hash for each, newline separated
+
+ # ${=rm} $tmp
+
+ lock $ADDRESSBOOK
+
+ newa=1; _name=""; _email=""
+ for a in ${(f)addresses}; do
+ { test "${a[1]}" = "#" } && {
+ newa=1; # its the end of the entry
+
+ # handle lines with multiple emails in vcard
+ # TODO: generate Groups/${_name} from this
+ for ee in ${=_email}; do
+ # check if we have this email already
+ _e=`print ${ee} | extract_emails`
+ func "lookup_email: ${_e}"
+ lookup_email "${_e}"
+
+ [[ $? = 0 ]] || {
+ insert_address "${_e}" "${_name}"
+ act "${a} ${_name} <${_e}>"
+ }
+ done
+
+ continue }
+ if [[ $newa -eq 1 ]]; then
+ # (V) makes special chars visible, we need to remove them..
+ _name="${(V)a[(ws:^:)1]}"; newa=0; continue
+ elif [[ $newa -eq 0 ]]; then
+ _email="${(V)a[(ws:^:)1]}"
+ fi
+ done
+
+ unlock $ADDRESSBOOK
+
+ notice "Done importing addresses"
+}
+
# extract all entries in addressbook or all addresses in a pgp keyring
# or all signatures on a pgp key (even without importing it)
extract() {
@@ -289,36 +373,41 @@ extract() {
# without arguments just list all entries in the active list
# default is whitelist
- [[ "$1" = "" ]] && {
- notice "Extracting all addresses in whitelist"
+
+ arg=${PARAM[1]}
+ # no arg means print all entries from adressbook
+ [[ "$arg" = "" ]] && {
+ notice "Extracting all addresses in $list"
awk -F'=' '
/^name/ { printf("%s ",$2) }
/^email/ { printf("<%s>\n",$2) }
-' "$MAILDIRS"/$list.abook
+' $ADDRESSBOOK
return 0
}
- [[ -r "$1" ]] && { # first arg is a file
-
- # a map to eliminate duplicates
- typeset -AU result
+ [[ -r "$arg" ]] && {
+ # if first arg is a file, could be a maildir, a gpg keyring,
+ # a gpg pubkey or a vcard
# if first arg is a directory then extract from maildir
- [[ -d "$1" ]] && {
+ [[ -d "$arg" ]] && {
notice "Extracting $2 addresses from maildir $1"
extract_maildir "$1" "$2"
return $?
}
func "testing argument with file magic"
- _magic=`file "$1"`
+ _magic=`file "$arg"`
+
+ # a map to eliminate duplicates
+ typeset -AU result
######### GPG
# first arg is a GnuPG key ring
[[ "$_magic" =~ "GPG key public ring" ]] && {
- notice "Extracting addresses found in GPG keyring: $1"
+ notice "Extracting addresses found in GPG keyring: $arg"
_addrs=`gpg --list-keys --with-colons | awk -F: '{print $10}'`
for i in ${(f)_addrs}; do
_parsed=`print "From: $i" | ${WORKDIR}/bin/fetchaddr -a -x from`
@@ -347,10 +436,10 @@ extract() {
# first arg is a GnuPG public key
[[ "$_magic" =~ "PGP public key" ]] && {
- notice "Extracting addresses from sigs on GPG key $1"
+ notice "Extracting addresses from sigs on GPG key $arg"
_gpg="gpg --no-default-keyring --keyring $MAILDIRS/cache/pubkey.gpg --batch --with-colons"
rm -f $MAILDIRS/cache/pubkey.gpg
- ${=_gpg} --import "$1"
+ ${=_gpg} --import "$arg"
# first make sure all unknown keys are imported
_addrs=`${=_gpg} --list-sigs | awk -F: '{print $5 " " $10}'`
for i in ${(f)_addrs}; do
@@ -395,135 +484,69 @@ extract() {
}
-# import an addressbook, autodetect its type
-import_addressbook() {
- [[ "$1" = "" ]] || {
- notice "Import addressbook from vCard: $1"
- import_vcard "$1"
- return $?
- }
+# import address lists from stdin
+import() {
+
+ arg=${PARAM[1]}
+ # remove options and trim
+ arg=`trim ${arg//-?/}`
# a map to eliminate duplicates
typeset -AU result
- # stdin
- notice "Importing addressbook from stdin list of addresses"
- _stdin=`cat`
- _new=0
- for i in ${(f)_stdin}; do
- # skip comments starting with #
- [[ "$i[1]" = "#" ]] && continue
-
- _parsed=`print - "From: $i" | ${WORKDIR}/bin/fetchaddr -a -x from`
- _e="${_parsed[(ws:,:)1]}"
-
- # check if is really an email
- isemail "$_e"
- [[ $? = 0 ]] || continue
-
- # check if the email is not a duplicate
- [[ "${result[$_e]}" = "" ]] || continue
-
- _n="${_parsed[(ws:,:)2]}"
- result+=("$_e" "$_n")
-
- # check if the email is not already known
- lookup_email "$_e"
- [[ $? = 0 ]] && continue
-
- [[ $DRYRUN = 0 ]] && insert_address "$_e" "$_n"
- act "new entry imported: $_n <$_e>"
- _new=$(( $_new + 1 ))
- done
- notice "Valid unique entries parsed: ${#result}"
- act "new addresses found: ${_new}"
- return 0
-}
-
-
-
-# import emails from VCard into abook
-# checks if the emails are already known
-import_vcard() {
- act "import VCard from file: $1"
-
- [[ -r "$1" ]] || {
- error "File not found: $1"
- return 1
- }
+ [[ "$arg" = "" ]] || {
+ notice "Import address list from stdin into addressbook"
+ _stdin=`cat`
+ print - $_stdin
+ _new=0
+ for i in ${(f)_stdin}; do
+ # skip comments starting with #
+ [[ "$i[1]" = "#" ]] && continue
+
+ _parsed=`print - "From: $i" | ${WORKDIR}/bin/fetchaddr -a -x from`
+ _e="${_parsed[(ws:,:)1]}"
+
+ # check if is really an email
+ isemail "$_e"
+ [[ $? = 0 ]] || {
+ func "not an email: $_e"
+ continue
+ }
- vcard="$1"
- head -n1 $vcard | grep '^BEGIN:VCARD' > /dev/null
+ # check if the email is not a duplicate
+ [[ "${result[$_e]}" = "" ]] || {
+ func "duplicate email: $_e"
+ continue
+ }
+
+ _n="${_parsed[(ws:,:)2]}"
+ result+=("$_e" "$_n")
+
+ # check if the email is not already known
+ lookup_email "$_e"
+ [[ $? = 0 ]] && {
+ func "email already known: $_e"
+ continue
+ }
- [[ $? = 0 ]] || {
- error "File to import is not a VCard: $vcard"
- return 1
+ act "import new entry: $_n <$_e>"
+ [[ $DRYRUN = 0 ]] && {
+ insert_address "$_e" "$_n"
+ }
+ _new=$(( $_new + 1 ))
+ done
+ notice "Valid unique entries parsed: ${#result}"
+ act "new addresses found: ${_new}"
+ return $?
}
- notice "Import VCard in addressbook: ${vcard}"
- # parse the vcard and print a simple name and email list
- # each value on a single line, entry tuples followed by a #
- # we skip entries that don't have an email
- addresses=`cat ${vcard} | awk '
-BEGIN { newcard=0; c=0; name=""; email=""; }
-/^BEGIN:VCARD/ { newcard=1 }
-/^FN:/ { if(newcard = 1) name=$0 }
-/^EMAIL/ { if(newcard = 1) email=$0 }
-/^END:VCARD/ {
- if(newcard = 1) {
- newcard=0
- if(email != "") {
- c+=1
- print name
- print email
- print "# " c
- }
- email=""
- next
- }
+ # stdin
+ notice "Importing addressbook from stdin list of addresses"
+ return 0
}
-' | cut -d: -f2`
- # now parse the temporary list of name and emails
- # made of name, email and a hash for each, newline separated
- # ${=rm} $tmp
-
- lock $ADDRESSBOOK
-
- newa=1; _name=""; _email=""
- for a in ${(f)addresses}; do
- { test "${a[1]}" = "#" } && {
- newa=1; # its the end of the entry
-
- # handle lines with multiple emails in vcard
- # TODO: generate Groups/${_name} from this
- for ee in ${=_email}; do
- # check if we have this email already
- _e=`print ${ee} | extract_emails`
- func "lookup_email: ${_e}"
- lookup_email "${_e}"
-
- [[ $? = 0 ]] || {
- insert_address "${_e}" "${_name}"
- act "${a} ${_name} <${_e}>"
- }
- done
-
- continue }
- if [[ $newa -eq 1 ]]; then
- # (V) makes special chars visible, we need to remove them..
- _name="${(V)a[(ws:^:)1]}"; newa=0; continue
- elif [[ $newa -eq 0 ]]; then
- _email="${(V)a[(ws:^:)1]}"
- fi
- done
-
- unlock $ADDRESSBOOK
-
- notice "Done importing addresses"
-}
# export old addressbook format to abook
export_abook() {
diff --git a/src/zlibs/email b/src/zlibs/email
@@ -38,104 +38,73 @@ queue() {
# set it ready for saving in outbux
queue_body="$base"
+ _tmp_create
+ tmpqueue="$JAROTMP"
+
# pre-processing of the email headers
- cat | awk '
+ awk '
/User-Agent:/ { print "User-Agent: Jaro Mail <http://jaromail.dyne.org>"; next }
{ print $0 }
-' > "$TMPDIR/${queue_body}.mail"
+' > "$tmpqueue"
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
- }
${=mkdir} "$MAILDIRS/outbox/send"
-
lock "$MAILDIRS/outbox"
# check if recipients are a Group
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 }
+
+ groupfile="`print ${=queue_to}|cut -d@ -f1`"
+ act "email recipients are in group ${groupfile}"
+
+ [[ -r "$MAILDIRS/Groups/$groupfile" ]] || {
+ maildirmake "$MAILDIRS/postponed"
+ mv "$tmpqueue" "$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 }'`
+ [[ "$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 "$tmpqueue" | \
+ 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 "$tmpqueue" | \
+ awk '/^To:/ { print "'"To: $cc"'"; print "'"Reply-To: $cc"'"; next }
{ print $0 }' \
> "${MAILDIRS}/outbox/new/${ig}.mail"
- ;;
- esac
-
+ ;;
+ esac
+
else
- # recipients are set in the email envelope
- cat "$TMPDIR/$queue_body.mail" | deliver "outbox"
+ # recipients are set in the email envelope
+ cat "$tmpqueue" | deliver "outbox"
fi
-
+
unlock "$MAILDIRS/outbox"
- { test -r "${TMPDIR}/${queue_body}.mail" } && {
- ${=rm} "${TMPDIR}/${queue_body}.mail" }
return 0
}
@@ -338,7 +307,10 @@ send() {
# check if this is an anonymous mail
hdr "$qbody" | grep -i '^from: anon' > /dev/null
if [[ $? = 0 ]]; then
- anoncfg="${TMPDIR}/${smtp}.anon.$RANDOM"
+
+ _tmp_create
+ anoncfg="$JAROTMP"
+
cat <<EOF > "$anoncfg"
REMAIL n
POOLSIZE 0
@@ -389,8 +361,6 @@ BEGIN { head=1 }
func "mixmaster returns $res"
done
- ${=rm} $anoncfg
-
else # normal send with msmtp
act "Sending out email"
@@ -485,23 +455,26 @@ peek() {
error "Error retrieving password for $login on $imap"
unset password all; return 1
}
- tmp="$TMPDIR/$imap.peek.$RANDOM"
- newlock "$tmp"
+
+ _tmp_create
+ tmp="$JAROTMP"
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"
+ touch "$MAILDIRS/tmp/muttpass"
+ cat <<EOF >> "$MAILDIRS/tmp/muttpass"
+source '$tmp'
unset mark_old
set sort=reverse-date-received
EOF
+ # fork a process to delete the pass files after use
(sleep 1;
- cp /dev/null "$TMPDIR/muttpass"
- unlink "$tmp" # secure delete in ram
+ cp /dev/null "$MAILDIRS/tmp/muttpass"
+ cp /dev/null "$tmp" # zero the tmp passfile
) &
${=mutt} -F $MUTTDIR/rc -f ${iproto}://${ilogin}@${imap}:${imap_port}/${folder}
diff --git a/src/zlibs/filters b/src/zlibs/filters
@@ -444,7 +444,7 @@ source '$WORKDIR/.mutt/formats'
source '$WORKDIR/.mutt/keybindings'
source '$WORKDIR/.mutt/colors'
source '$MAILDIRS/Identity.txt'
-source '$TMPDIR/muttpass'
+source '$MAILDIRS/tmp/muttpass'
EOF
@@ -496,16 +496,16 @@ EOF
eval `print $t | awk '
{ print "_type=" $1 "; _app=" $2 ";" }'`
cat <<EOF >> $MUTTDIR/mailcap
-${_type}; a="${TMPDIR}" && f=\`basename %s\` && rm -f "\$a"/"\$f" && cp %s "\$a"/"\$f" && ${_app} "\$a"/"\$f"
+${_type}; a="${MAILDIRS}/tmp" && f=\`basename %s\` && rm -f "\$a"/"\$f" && cp %s "\$a"/"\$f" && ${_app} "\$a"/"\$f"
EOF
done
cat <<EOF >> $MUTTDIR/mailcap
-application/*; a="${TMPDIR}" && f=\`basename %s\` && rm -f "\$a"/"\$f" && cp %s "\$a"/"\$f" && jaro preview "\$a"/"\$f"
+application/*; a="${MAILDIRS}/tmp" && f=\`basename %s\` && rm -f "\$a"/"\$f" && cp %s "\$a"/"\$f" && jaro preview "\$a"/"\$f"
EOF
} # Applications.txt
# this one is empty and sources files in temp when necessary
- touch $TMPDIR/muttpass
+ touch $MAILDIRS/tmp/muttpass
# just the header, will be completed later
rm -f $MUTTDIR/mboxes
@@ -514,15 +514,17 @@ 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
-
- uniq $MUTTDIR/mboxes > $TMPDIR/mboxes
- mv $TMPDIR/mboxes $MUTTDIR/mboxes
+
+ _tmp_create
+ ttmp="$JAROTMP"
+ uniq $MUTTDIR/mboxes > $ttmp
+ mv $ttmp $MUTTDIR/mboxes
}
diff --git a/src/zlibs/helpers b/src/zlibs/helpers
@@ -183,7 +183,7 @@ BEGIN { head=1 }
# of course we have a preference for AutOrg, the editor from our suite
# however the default is nano if nothing else is choosen.
jarovim() {
- vim -c 'set fo=tcrq' -c 'set tw=72' \
+ vim -c 'set fo=tcrq' -c 'set tw=72' -c 'set paste' \
-c 'map <C-j> {gq}' -c 'imap <C-j> <esc>{gq}i' \
"${@}"
return $?
diff --git a/src/zlibs/maildirs b/src/zlibs/maildirs
@@ -92,57 +92,55 @@ rmdupes() {
## special argument lastlog
{ test "$1" = "lastlog" } && {
- lastdirs=(`maildirs_lastlog`)
- act "Pruning duplicates across ${#lastdirs} destination maildirs:"
- act "${lastdirs}"
- # recursion here
- rmdupes ${=lastdirs}
- notice "Done pruning"
- # all the prioritization above is so that duplicates are spotted
- # across different maildirs and deleted from the filtered source
- return 0
+ lastdirs=(`maildirs_lastlog`)
+ act "Pruning duplicates across ${#lastdirs} destination maildirs:"
+ act "${lastdirs}"
+ # recursion here
+ rmdupes ${=lastdirs}
+ notice "Done pruning"
+ # all the prioritization above is so that duplicates are spotted
+ # across different maildirs and deleted from the filtered source
+ return 0
}
###############
-
+
tot=0
typeset -al msgs
-
- formail_cache="$TMPDIR/filter.rmdupes.$datestamp.$RANDOM"
- newlock "$formail_cache"
-
+
+ _tmp_create
+ formail_cache="$JAROTMP"
+
for folder in ${=@}; do
- { test -r "$folder" } || { folder="$MAILDIRS/$folder" }
- { test -r "$folder" } || {
- error "Directory not found: $folder"
- continue }
-
- { maildircheck "${folder}" } || {
- error "Not a maildir folder: $folder"
- continue }
-
- c=0
- notice "Checking for duplicates in $folder"
- msgs=`${=find} "${folder}" -maxdepth 2 -type f`
- act "Please wait, this can take a while..."
-
-
-
- for m in ${(f)msgs}; do
- func "formail < $m"
- # 128MB should be enough ehre?
- formail -D 128000000 "$formail_cache" <"$m" \
- && rm "$m" && c=$(( $c + 1 ))
- done
- act "$c duplicates found and deleted"
- tot=$(( $tot + $c ))
+ { test -r "$folder" } || { folder="$MAILDIRS/$folder" }
+ { test -r "$folder" } || {
+ error "Directory not found: $folder"
+ continue }
+
+ { maildircheck "${folder}" } || {
+ error "Not a maildir folder: $folder"
+ continue }
+
+ c=0
+ notice "Checking for duplicates in $folder"
+ msgs=`${=find} "${folder}" -maxdepth 2 -type f`
+ act "Please wait, this can take a while..."
+
+
+
+ for m in ${(f)msgs}; do
+ func "formail < $m"
+ # 128MB should be enough ehre?
+ formail -D 128000000 "$formail_cache" <"$m" \
+ && rm "$m" && c=$(( $c + 1 ))
+ done
+ act "$c duplicates found and deleted"
+ tot=$(( $tot + $c ))
done
-
- unlink "$formail_cache"
-
+
if [ "$tot" = "0" ]; then
- act "No duplicates found at all"
+ act "No duplicates found at all"
else
- act "$tot total duplicates found and deleted"
+ act "$tot total duplicates found and deleted"
fi
}
diff --git a/src/zlibs/publish b/src/zlibs/publish
@@ -159,51 +159,52 @@ pubdb_extract_body() {
_path="$1"
{ test -r "$_path" } || { error "mail not found for body extraction: $_path"; return 1 }
- pushd ${TMPDIR}/pubdb
+ mkdir -p ${MAILDIRS}/pubdb
+ pushd ${MAILDIRS}/pubdb
# check if it has already html
_html=`mu extract "$_path" | awk '/text\/html/ {print $1; exit}'`
- { test "$_html" = "" } || {
+ [[ "$_html" = "" ]] || {
mu extract --overwrite --parts="$_html" "$_path"
- # check if there is an html header to weed out
- grep '<body>' "$_html".part > /dev/null
- if [ $? = 0 ]; then
- awk '
+ # check if there is an html header to weed out
+ grep '<body>' "$_html".part > /dev/null
+ if [ $? = 0 ]; then
+ awk '
BEGIN { body=0 }
/<body/ { body=1; next }
/<\/body/ { body=0; next }
{ if(body==1) print $0 }' "$_html".part | iconv -c
- else
- cat "$_html".part | iconv -c
- fi
- rm "$_html".part
- return 0 }
-
+ else
+ cat "$_html".part | iconv -c
+ fi
+ rm "$_html".part
+ return 0 }
+
# use the first text/plain
_text=`mu extract "$_path" | awk '/text\/plain/ {print $1; exit}'`
{ test "$_text" = "" } || {
- mu extract --overwrite --parts="$_text" "$_path"
- # here we tweak the origin to avoid headers in markdown
- # preferring to interpret # as inline preformat
- cat "$_text".part | sed '
+ mu extract --overwrite --parts="$_text" "$_path"
+ # here we tweak the origin to avoid headers in markdown
+ # preferring to interpret # as inline preformat
+ cat "$_text".part | sed '
s/^#/ /g
' | iconv -c | maruku --html-frag 2>/dev/null | sed '
s|http://[^ |<]*|<a href="&">&</a>|g
s|https://[^ |<]*|<a href="&">&</a>|g'
-# s|www\.[^ |<]*|<a href="http://&">&</a>|g'
- rm "$_text".part
- return 0
- }
+ # s|www\.[^ |<]*|<a href="http://&">&</a>|g'
+rm "$_text".part
+return 0
+}
- # check if its an html only mail
- # _html=`mu extract "$_path" | awk '/text\/html/ {print $1; exit}'`
- # { test "$_html" = "" } || {
- # mu extract --overwrite --parts="$_html" "$_path"
- # elinks -dump "$_html".part
- # rm "$_html".part
- # return 0 }
+# check if its an html only mail
+# _html=`mu extract "$_path" | awk '/text\/html/ {print $1; exit}'`
+# { test "$_html" = "" } || {
+# mu extract --overwrite --parts="$_html" "$_path"
+# elinks -dump "$_html".part
+# rm "$_html".part
+# return 0 }
- return 0
+return 0
}