commit b89665a20ce042d69e3834750e5b654eef7cbc90
parent 993044f8f78996aa70f0fb9087ec6aabe6045a30
Author: Jaromil <jaromil@dyne.org>
Date: Sun, 22 Mar 2015 10:30:04 +0100
major cleanup and adoption of zuper extension
Diffstat:
11 files changed, 623 insertions(+), 274 deletions(-)
diff --git a/TODO.md b/TODO.md
@@ -3,6 +3,14 @@
Contribute code or donate to complete this TODO
https://www.dyne.org/donate
+## Save and check SSL/TLS server fingerprints
+
+use a k/v store to save and check the fingerprints of servers
+using fingerprint() inside helpers
+provide a command to save a new fingerprint overriding old one
+bail out in error when known fingeprint doesn't match
+
+
## Notmuch web
Fire up the web interface for notmuch searches
diff --git a/build/build-gnu.sh b/build/build-gnu.sh
@@ -6,8 +6,6 @@ builddir=`pwd`
# cc="${builddir}/cc-static.zsh"
cc="gcc -O3"
-pushd ..
-
which apt-get > /dev/null && distro=debian
which yum > /dev/null && distro=fedora
@@ -82,8 +80,8 @@ debian_req() {
print -n "Compiling the address parser (RFC2047) ... "
${=cc} -c helpers.c
${=cc} -c rfc2047.c
- ${=cc} -c rfc822.c;
- ${=cc} -c -DHAVE_ICONV fetchaddr.c;
+ ${=cc} -c rfc822.c
+ ${=cc} -c -DHAVE_ICONV fetchaddr.c
${=cc} -o fetchaddr fetchaddr.o helpers.o rfc2047.o rfc822.o
popd
cp src/fetchaddr build/gnu/
@@ -155,4 +153,3 @@ print "Now run 'make install' as root to install jaromail in /usr/local"
print "use PREFIX=/home/private/jaromail to avoid system-wide installation."
print
-popd
diff --git a/build/install-gnu.sh b/build/install-gnu.sh
@@ -33,7 +33,7 @@ cp -ra $srcdir/src/stats/* $JARO_SHARE/.stats/
mkdir -p $JARO_LIBEXEC/{bin,zlibs}
cp $srcdir/src/jaro $JARO_LIBEXEC/bin
cp -ra $srcdir/build/gnu/* $JARO_LIBEXEC/bin
-cp -ra $srcdir/src/zlibs/* $JARO_LIBEXEC/zlibs/
+cp -r $srcdir/src/zlibs/* $JARO_LIBEXEC/zlibs/
for l in `ls $JARO_LIBEXEC/zlibs/ | grep '.zwc$'`; do
rm -f $l
diff --git a/src/jaro b/src/jaro
@@ -4,7 +4,9 @@
#
# a tool to easily and privately handle your e-mail communication
#
-# Copyleft (C) 2010-2015 Denis Roio <jaromil@dyne.org>
+# Copyright (C) 2010-2015 Dyne.org Foundation
+#
+# JaroMail is designed, written and maintained by Denis Roio <jaromil@dyne.org>
#
# This source code is free software; you can redistribute it and/or
# modify it under the terms of the GNU Public License as published by
@@ -20,37 +22,90 @@
# this source code; if not, write to:
# Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
-VERSION=3.2
-DATE=Jan/2015
+VERSION=3.3
+DATE=Mar/2015
JAROMAILEXEC=$0
-typeset -a OLDARGS
-for arg in ${argv}; do OLDARGS+=($arg); done
-##########################
-# declare global variables
+# default permission on files
+umask 066
-QUIET=0
-DEBUG=0
-DRYRUN=0
-CALLMUTT=1
+# honor quiet and debug flags as early as possible
+if [[ ${@} == *-q* ]]; then quiet=1; fi
+if [[ ${@} == *-D* ]]; then debug=1; fi
+
+
+# check if we are inside the directory
+if [ -r jaro/bin/jaro ]; then
+ MAILDIRS=`pwd`
+# check if we are on OSX
+elif [ -r /Applications/JaroMail.app ]; then
+ MAILDIRS="$HOME/Library/Application Support/JaroMail"
+# else use GNU/Linux default
+else
+ MAILDIRS=$HOME/Mail
+fi
+
+# end override
+MAILDIRS=${JAROMAILDIR:-$MAILDIRS}
+
+
+# check if we are testing from source
+if [ -r ../src/jaro ]; then
+ WORKDIR="../src"
+# check if we are on OSX
+elif [ -r /Applications/JaroMail.app/Contents/Resources/jaro ]; then
+ WORKDIR="/Applications/JaroMail.app/Contents/Resources/jaro"
+else # use GNU/Linux default
+ WORKDIR="/usr/local/share/jaromail"
+fi
+
+# env override
+WORKDIR=${JAROWORKDIR:-$WORKDIR}
+
+# load our zuper extension
+source $WORKDIR/zlibs/zuper
+
+
+# what operating system are we in? use os_detect()
+# simplifying modes of operation: GNU or MAC
+case $(uname -o) in
+ GNU/Linux) OS=GNU
+ notice "Jaro Mail v$VERSION running on GNU/Linux" ;;
+
+ Darwin) OS=MAC
+ notice "Jaro Mail v$VERSION running on Mac/OSX" ;;
+
+ Cygwin) OS=WIN
+ notice "Jaro Mail v$VERSION runing on MS/Win" ;;
+
+ *) OS=GNU # default
+ error "Running on an unknown operating system, assuming GNU" ;;
+esac
+
+
+
+# global variables
+vars+=(DEBUG QUIET DRYRUN CALLMUTT cur_fun)
+QUIET=${QUIET:-0}
+DEBUG=${DEBUG:-0}
+DRYRUN=${DRYRUN:-0}
+CALLMUTT=${CALLMUTT:-1}
# use gnome-keyring for passwords on GNU systems
-GNOMTEKEY=0
+vars+=(GNOMEKEY)
+GNOMEKEY=${GNOMEKEY:-0}
-# default permission on files
-umask 066
# global variables for binaries called
-typeset -h rm mkdir mutt
+vars+=(rm mkdir mutt SQL)
-# load zsh regex module
+# load zsh modules
zmodload zsh/regex
zmodload zsh/mapfile
zmodload zsh/system
zmodload -F zsh/stat b:zstat
zmodload zsh/sched
-# date stamp
-datestamp=`date '+%d%b%y'`
+
##########################
# SQL command
@@ -65,32 +120,32 @@ typeset -h global_quit
global_quit=0
# global variable for account selection
-typeset -h account account_type
+vars+=(account account_type)
# account=default
-typeset -h list
+vars+=(list)
list=whitelist
# global variables for accounts
-typeset -h name login imap imap_port smtp smtp_port protocol password auth accountopt
+vars+=(name login imap imap_port smtp smtp_port protocol password auth accountopt)
typeset -ah folders exclude
-typeset -h host port type
+vars+=(host port type)
# global variables for addressbook
-typeset -h hostname addressbook addressbook_tmp
+vars+=(hostname addressbook addressbook_tmp)
# global variables for email parsers
typeset -A e_addr
-typeset -h e_parsed
+vars+=(e_parsed)
# global array for maildirs (filled by list_maildirs)
typeset -al maildirs
# global variable for mutt binary
-typeset -h mutt pgpewrap dotlock
+vars+=(mutt pgpewrap dotlock)
# global variable for exit code
-typeset -h exitcode
+vars+=(exitcode)
# exitcode=0
# global variable for infos on imap folder
@@ -99,123 +154,10 @@ typeset -h exitcode
typeset -alU imap_info
# global variable for mutt options
-typeset -h muttflags
+vars+=(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
- 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
-}
-
-# 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 }
-error() { if [[ $QUIET == 0 ]]; then print "$fg[red][!]$fg[default] $1" >&2; fi }
-func() { if [[ $DEBUG == 1 ]]; then print "$fg[blue][D]$fg[default] $1" >&2; fi }
-act() {
- if [[ $QUIET == 0 ]]; then
- if [ "$1" = "-n" ]; then
- print -n "$fg_bold[white] . $fg_no_bold[default] $2" >&2;
- else
- print "$fg_bold[white] . $fg_no_bold[default] $1" >&2;
- fi
- fi
-}
-
-# honor quiet and debug flags as early as possible
-if [[ ${@} == *-q* ]]; then QUIET=1; fi
-if [[ ${@} == *-D* ]]; then DEBUG=1; fi
-
-
-# what operating system are we in? use os_detect()
-# simplifying modes of operation: GNU or MAC
-case $(uname -o) in
- GNU/Linux) OS=GNU
- notice "Jaro Mail v$VERSION running on GNU/Linux" ;;
-
- Darwin) OS=MAC
- notice "Jaro Mail v$VERSION running on Mac/OSX" ;;
-
- Cygwin) OS=WIN
- notice "Jaro Mail v$VERSION runing on MS/Win" ;;
-
- *) OS=GNU # default
- error "Running on an unknown operating system, assuming GNU" ;;
-esac
-
-# check if we are inside the directory
-if [ -r jaro/bin/jaro ]; then
- MAILDIRS=`pwd`
-
-# check if we are on OSX
-elif [ -r /Applications/JaroMail.app ]; then
- MAILDIRS="$HOME/Library/Application Support/JaroMail"
-
-# else use GNU/Linux default
-else
- MAILDIRS=$HOME/Mail
-fi
-
-# end override
-{ test "$JAROMAILDIR" = "" } || { MAILDIRS="$JAROMAILDIR" }
-
-# default working dir
-
-
-# check if we are testing from source
-if [ -r ../src/jaro ]; then
- WORKDIR="../src"
-# check if we are on OSX
-elif [ -r /Applications/JaroMail.app/Contents/Resources/jaro ]; then
- WORKDIR="/Applications/JaroMail.app/Contents/Resources/jaro"
-else # use GNU/Linux default
- WORKDIR="/usr/local/share/jaromail"
-fi
-
-# env override
-[[ "$JAROWORKDIR" = "" ]] || { WORKDIR="${JAROWORKDIR}" }
-
# default addressbook
ADDRESSBOOK="$MAILDIRS/whitelist.abook"
@@ -260,52 +202,29 @@ else
exit 1
fi
-ACCOUNTS="$MAILDIRS/Accounts"
-KEYRING="$MAILDIRS/Keyring"
-# Cleanup anything sensitive before exiting.
-endgame() {
- func "endgame() $1"
- [[ "$1" = "NOERRORS" ]] || {
- error "$1 signal sent to processes, waiting to quit..."
- global_quit=1
- sleep 2
- }
- # Clear temporary files
- for f in $JAROTMPFILES; do
- func "endgame() cleaning tempfile $f"
- rm -f "$f"
- done
- JAROTMPFILES=()
+##########
+# complete
+source $WORKDIR/zlibs/zuper.init
- func "endgame() exit code: $exitcode"
- return $exitcode
-}
-# Trap functions for the endgame event
-TRAPINT() { endgame INT; return $? }
-# TRAPEXIT() { endgame EXIT; return $? }
-TRAPHUP() { endgame HUP; return $? }
-TRAPQUIT() { endgame QUIT; return $? }
-TRAPABRT() { endgame ABORT; return $? }
-TRAPKILL() { endgame KILL; return $? }
-# TRAPPIPE() { endgame PIPE; return $? }
-TRAPTERM() { endgame TERM; return $? }
-TRAPSTOP() { endgame STOP; return $? }
-# TRAPZERR() { func "function returns non-zero." }
+
+
+ACCOUNTS="$MAILDIRS/Accounts"
+KEYRING="$MAILDIRS/Keyring"
case $OS in
- GNU)
+ 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)
;;
@@ -313,36 +232,35 @@ esac
hostname=$(hostname) # gather the current hostname
-
[[ "$1" = "source" ]] || { # skip checks if just sourcing
-# make sure we have a directory for account configurations
-{ test -d "$ACCOUNTS" } || { ${=mkdir} "$ACCOUNTS" }
+ # make sure we have a directory for account configurations
+ { test -d "$ACCOUNTS" } || { ${=mkdir} "$ACCOUNTS" }
-# make sure we have a local keyring in case system-wide not found
-{ test -r "$KEYRING" } || { create_keyring "$KEYRING" }
+ # make sure we have a local keyring in case system-wide not found
+ { test -r "$KEYRING" } || { create_keyring "$KEYRING" }
-# make sure we have an addressbook
-[[ -r "$ADDRESSBOOK" ]] || { create_addressbook "$ADDRESSBOOK" }
+ # make sure we have an addressbook
+ [[ -r "$ADDRESSBOOK" ]] || { create_addressbook "$ADDRESSBOOK" }
-${=mkdir} "$MAILDIRS/logs"
-# ${=mkdir} "$MAILDIRS/certs"
+ ${=mkdir} "$MAILDIRS/logs"
+ # ${=mkdir} "$MAILDIRS/certs"
-MUTTDIR="$MAILDIRS/.mutt"
-{ test -d "$MUTTDIR" } || { ${=mkdir} "$MUTTDIR" }
+ MUTTDIR="$MAILDIRS/.mutt"
+ { test -d "$MUTTDIR" } || { ${=mkdir} "$MUTTDIR" }
-# make sure we have Filters.txt Applications.txt Mutt.txt
-{ test -r "$MAILDIRS/Filters.txt" } || {
- cp "$WORKDIR/Filters.txt" "$MAILDIRS/Filters.txt"
- notice "Default filters created" }
+ # make sure we have Filters.txt Applications.txt Mutt.txt
+ { test -r "$MAILDIRS/Filters.txt" } || {
+ cp "$WORKDIR/Filters.txt" "$MAILDIRS/Filters.txt"
+ notice "Default filters created" }
-{ test -r "$MAILDIRS/Applications.txt" } || {
- cp "$WORKDIR/Applications.txt" "$MAILDIRS/Applications.txt"
- notice "Default helper applications settings created" }
+ { test -r "$MAILDIRS/Applications.txt" } || {
+ cp "$WORKDIR/Applications.txt" "$MAILDIRS/Applications.txt"
+ notice "Default helper applications settings created" }
-{ test -r "$MAILDIRS/Mutt.txt" } || {
- cp "$WORKDIR/Mutt.txt" "$MAILDIRS/Mutt.txt"
- notice "Default Mutt configuration template created" }
+ { test -r "$MAILDIRS/Mutt.txt" } || {
+ cp "$WORKDIR/Mutt.txt" "$MAILDIRS/Mutt.txt"
+ notice "Default Mutt configuration template created" }
} # if not sourcing
@@ -415,7 +333,7 @@ check_bin() {
act "using gnome-keyring to store secrets"
GNOMEKEY=1
}
-
+
return 0
}
@@ -494,7 +412,7 @@ a pipe | in front indicate they take an email body from stdin
|smtp read a mail from stdin and send it via [accounts]'s smtp
-== Storage commands
+== Storage commands
open open a maildir folder (can use -R for read-only)
@@ -575,7 +493,6 @@ main() {
subcommands_opts[passwd]=""
subcommands_opts[cert]=""
- subcommands_opts[ramdisk]=""
subcommands_opts[source]=""
subcommands_opts[isonline]=""
@@ -589,7 +506,7 @@ main() {
subcommands_opts[extract]=""
subcommands_opts[smtp]=""
-
+
subcommands_opts[crypt]=""
subcommands_opts[cryptsign]=""
@@ -611,7 +528,7 @@ main() {
if [[ -z $subcommand ]]; then
subcommand="__default"
fi
-
+
if [[ -z ${(k)subcommands_opts[$subcommand]} ]]; then
# unknown command, pass it to autostart
func "unknown command, autostart: $@"
@@ -623,10 +540,10 @@ main() {
}
return $exitcode
fi
-
+
argv=(${oldstar})
unset oldstar
-
+
### Parsing global + command-specific options
# zsh magic: ${=string} will split to multiple arguments when spaces occur
set -A cmd_opts ${main_opts} ${=subcommands_opts[$subcommand]}
@@ -666,7 +583,7 @@ main() {
fi
{ option_is_set -a } && { account=`option_value -a` }
{ option_is_set -l } && {
- if [[ "`option_value -l`" =~ "black" ]]; then
+ if [[ "`option_value -l`" =~ "black" ]]; then
list=blacklist
elif [[ "`option_value -l`" =~ "white" ]]; then
list=whitelist
@@ -725,7 +642,7 @@ main() {
update_filters
update_mutt
update_sieve
- command -v notmuch > /dev/null && {
+ command -v notmuch > /dev/null && {
nm_setup
nm new 2>&1 | grep -v '^Note: Ignoring'
}
@@ -814,11 +731,9 @@ main() {
cert) cert ${PARAM} ;; # was checking is_online
- ramdisk) ramdisk ${PARAM} ;;
-
isonline) is_online ${=PARAM}; exitcode=$? ;;
-
+
publish)
md="$1"
{ maildircheck "$md" 2>/dev/null } || { md="${MAILDIRS}/${md}" }
@@ -883,7 +798,7 @@ main() {
isml)
ismailinglist
[[ $? = 0 ]] && \
- notice "Email read from stdin is a mailinglist"
+ notice "Email read from stdin is a mailinglist"
exitcode=$?
;;
@@ -912,4 +827,4 @@ main() {
check_bin
main $@
endgame NOERRORS
-return $exitcode
+#return $exitcode
diff --git a/src/zlibs/email b/src/zlibs/email
@@ -38,8 +38,8 @@ queue() {
# set it ready for saving in outbux
queue_body="$base"
- _tmp_create
- tmpqueue="$JAROTMP"
+ ztmp
+ tmpqueue=$ztmpfile
# pre-processing of the email headers
awk '
@@ -285,8 +285,8 @@ smtp_send() {
unset password
return 1 }
- _tmp_create
- msmtpcfg="$JAROTMP"
+ ztmp
+ msmtpcfg=$ztmpfile
sysread -o 1 <<EOF > $msmtpcfg
account default
from ${email}
@@ -336,8 +336,8 @@ send() {
hdr "$qbody" | grep -i '^from: anon' > /dev/null
if [[ $? = 0 ]]; then
- _tmp_create
- anoncfg="$JAROTMP"
+ ztmp
+ anoncfg=$ztmpfile
sysread -o 1 <<EOF > "$anoncfg"
REMAIL n
@@ -462,8 +462,8 @@ peek() {
unset password all; return 1
}
- _tmp_create
- _pass_tmp="$JAROTMP"
+ ztmp
+ _pass_tmp=$ztmpfile
sysread -o 1 <<EOF >> "$_pass_tmp"
set imap_pass = "${password}"
# set imap_peek = yes
diff --git a/src/zlibs/filters b/src/zlibs/filters
@@ -587,8 +587,8 @@ EOF
print " \\" >> $MUTTDIR/mboxes
print " +unsorted.ml +unsorted" >> $MUTTDIR/mboxes
- _tmp_create
- ttmp="$JAROTMP"
+ ztmp
+ ttmp=$ztmpfile
uniq $MUTTDIR/mboxes > $ttmp
mv $ttmp $MUTTDIR/mboxes
@@ -649,7 +649,7 @@ update_sieve() {
#######
# SIEVE
act "generating sieve filter rules"
- id=$datestamp.$RANDOM
+ id=`datestamp`.$RANDOM
newlock "$MAILDIRS/Filters.sieve"
rm -f "$MAILDIRS/Filters.sieve"
touch "$MAILDIRS/Filters.sieve"
diff --git a/src/zlibs/helpers b/src/zlibs/helpers
@@ -27,6 +27,7 @@
# which mutt binary to use
mutt="mutt"
+datestamp() { date '+%d%b%y' }
# remote leading and trailing spaces in a string taken from stdin
trim() {
@@ -329,52 +330,6 @@ is_online() {
}
-# 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
- ;;
- esac
-}
-
human_size() {
{ test $1 -gt 0 } || {
error "human_size() called with zero argument"
@@ -467,3 +422,51 @@ cert() {
}
######################
+# obsoleted
+
+
+# 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
+ ;;
+ esac
+}
diff --git a/src/zlibs/maildirs b/src/zlibs/maildirs
@@ -107,8 +107,8 @@ rmdupes() {
tot=0
typeset -al msgs
- _tmp_create
- formail_cache="$JAROTMP"
+ ztmp
+ formail_cache=$ztmpfile
for folder in ${=@}; do
{ test -r "$folder" } || { folder="$MAILDIRS/$folder" }
diff --git a/src/zlibs/search b/src/zlibs/search
@@ -236,7 +236,7 @@ search() {
}
backup() {
- id=$datestamp.$RANDOM
+ id=`datestamp`.$RANDOM
c=0
dst=${PARAM[1]}
diff --git a/src/zlibs/zuper b/src/zlibs/zuper
@@ -0,0 +1,410 @@
+#!/usr/bin/env zsh
+#
+# Zuper - Zsh Ultimate Programmer's Extensions Refurbished
+#
+# Copyright (C) 2015 Dyne.org Foundation
+#
+# Zuper is designed, written and maintained by Denis Roio <jaromil@dyne.org>
+#
+# This source code is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This source code is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# Please refer to the GNU Public License for more details.
+#
+# You should have received a copy of the GNU Public License along with
+# this source code; if not, write to:
+# Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+##########################
+typeset -aU vars
+typeset -aU arrs
+vars=(debug quiet ztmpfile)
+arrs=()
+
+debug=${debug:-0}
+quiet=${quiet:-0}
+
+vars+=(zuper_version)
+zuper_version=0.1
+
+# Messaging function with pretty coloring
+autoload colors
+colors
+
+
+vars+=(last_act last_func last_notice)
+
+function _msg() {
+ local msg="$2"
+ command -v gettext 1>/dev/null 2>/dev/null && msg="$(gettext -s "$2")"
+ for i in $(seq 3 ${#});
+ do
+ msg=${(S)msg//::$(($i - 2))*::/$*[$i]}
+ done
+
+ local command="print -P"
+ local progname="$fg[magenta]${TOMBEXEC##*/}$reset_color"
+ local message="$fg_bold[normal]$fg_no_bold[normal]$msg$reset_color"
+ local -i returncode
+
+ case "$1" in
+ inline)
+ command+=" -n"; pchars=" > "; pcolor="yellow"
+ ;;
+ message)
+ last_act="$msg"
+ pchars=" . "; pcolor="white"; message="$fg_no_bold[$pcolor]$msg$reset_color"
+ ;;
+ verbose)
+ last_func="$msg"
+ pchars="[D]"; pcolor="blue"
+ ;;
+ success)
+ last_notice="$msg"
+ pchars="(*)"; pcolor="green"; message="$fg_no_bold[$pcolor]$msg$reset_color"
+ ;;
+ warning)
+ pchars="[W]"; pcolor="yellow"; message="$fg_no_bold[$pcolor]$msg$reset_color"
+ ;;
+ failure)
+ pchars="[E]"; pcolor="red"; message="$fg_no_bold[$pcolor]$msg$reset_color"
+ returncode=1
+ ;;
+ print)
+ progname=""
+ ;;
+ *)
+ pchars="[F]"; pcolor="red"
+ message="Developer oops! Usage: _msg MESSAGE_TYPE \"MESSAGE_CONTENT\""
+ returncode=127
+ zerr
+ ;;
+ esac
+ ${=command} "${progname} $fg_bold[$pcolor]$pchars$reset_color ${message}$color[reset_color]" >&2
+ return $returncode
+}
+
+function _message say act() {
+ local notice="message"
+ [[ "$1" = "-n" ]] && shift && notice="inline"
+ [[ $quiet = 1 ]] || _msg "$notice" $@
+ return 0
+}
+
+function _verbose xxx func() {
+ [[ $debug = 1 ]] && _msg verbose $@
+ return 0
+}
+
+function _success yes notice() {
+ [[ $quiet = 1 ]] || _msg success $@
+ return 0
+}
+
+function _warning no warn warning() {
+ [[ $quiet = 1 ]] || _msg warning $@
+ return 0
+}
+
+function _failure fatal die error() {
+ # typeset -i exitcode=${exitv:-1}
+ [[ $quiet = 1 ]] || _msg failure $@
+ return 1
+}
+
+function _print() {
+ [[ $quiet = 1 ]] || _msg print $@
+ return 0
+}
+
+
+
+fn() {
+ local msg="$1"
+ command -v gettext 1>/dev/null 2>/dev/null \
+ && msg="$(gettext -s "$1")"
+ for i in $(seq 2 ${#}); do
+ msg=${(S)msg//::$(($i - 1))*::/$*[$i]}
+ done
+
+ fun="$msg"
+ func "$fun"
+ req=()
+ freq=()
+}
+
+ckreq reqck() {
+ err=0
+ for v in $req; do
+ [[ "${(P)v}" = "" ]] && {
+ warn "required setting is blank: $v"
+ err=1
+ }
+ done
+
+ [[ $err = 1 ]] && return $err
+
+ for f in $freq; do
+ # exists and has size greater than zero
+ [[ -s $f ]] || {
+ warn "required file empty: $f"
+ err=1
+ }
+ done
+ return $err
+}
+
+zerr() {
+ error "error in: ${fun:-$last_notice}"
+
+ [[ "$last_func" = "" ]] || warn "called in: $last_func"
+ [[ "$last_act" = "" ]] || warn "called in: $last_act"
+ [[ "$last_notice" = "" ]] || warn "called in: $last_notice"
+ [[ "$fun" = "" ]] || warn "called in: $fun"
+ error "error reported, operation aborted."
+ return 1
+}
+
+zdump() {
+ fn zdump
+ for v in $vars; do
+ print "$v \t ${(P)v}"
+ done
+ for a in $arrs; do
+ print "$a \t ${(P)a}"
+ done
+}
+
+
+
+##########################
+# Endgame handling
+
+arrs+=(destruens)
+
+# Trap functions for the endgame event
+TRAPINT() { endgame INT; return $? }
+# TRAPEXIT() { endgame EXIT; return $? }
+TRAPHUP() { endgame HUP; return $? }
+TRAPQUIT() { endgame QUIT; return $? }
+TRAPABRT() { endgame ABORT; return $? }
+TRAPKILL() { endgame KILL; return $? }
+# TRAPPIPE() { endgame PIPE; return $? }
+TRAPTERM() { endgame TERM; return $? }
+TRAPSTOP() { endgame STOP; return $? }
+# TRAPZERR() { func "function returns non-zero." }
+
+
+endgame() {
+ fn "endgame $*"
+
+ # execute all no matter what
+ TRAPZERR() { }
+
+ # process registered destructors
+ for d in $destruens; do
+ fn "destructor: $d"
+ $d
+ done
+ return 0
+}
+
+
+##########################
+# Temp file handling
+
+# ztmp() fills in $ztmpfile global. Caller must copy that variable as
+# it will be overwritten at every call.
+ztmp() {
+ fn ztmp
+
+ ztmpfile=`mktemp`
+ tmpfiles+=($ztmpfile)
+}
+
+# All tempfiles are freed in endgame()
+_ztmp_destructor() {
+ fn _ztmp_destructor
+
+ for f in $tmpfiles; do
+ rm -f "$f"
+ done
+ tmpfiles=()
+}
+
+arrs+=(tmpfiles)
+destruens+=(_ztmp_destructor)
+
+
+# optional: define zkv=1 on source
+
+[[ "$zkv" = "" ]] || {
+
+ ##########################
+ # Key/Value file storage using ZSh associative maps
+
+ zmodload zsh/system
+
+ # load a map from a file
+ # map must be already instantiated with typeset -A by called
+ # name of map is defined inside the file
+ zkv.load() {
+ fn "zkv-load $*"
+
+ file=$1
+ [[ "$file" = "" ]] && {
+ error "zkv-open() missing argument: file-path"
+ zerr
+ return 1 }
+ [[ -r "$file" ]] || {
+ error "zkv-open() file not found $file"
+ zerr
+ return 1 }
+ [[ -s "$file" ]] || {
+ error "zkv-open() file is empty"
+ zerr
+ return 1 }
+
+ source $file
+ }
+
+ # save a map in a file
+ # $1 = name of the map associative array
+ # $2 = full path to the file
+ zkv.save() {
+ fn "zkv.save $*"
+
+ _map=$1
+ _path=$2
+ [[ "$_path" = "" ]] && {
+ error "zkv.save() missing argument: map-name path-to-file"
+ zerr
+ return 1
+ }
+ [[ -r $_path ]] && {
+ func "zkv.close() overwriting $_path"
+ func "backup turd left behind: ${_path}~"
+ mv $_path $_path~
+ }
+ touch $_path
+
+ # wondering about http://www.zsh.org/mla/users/2015/msg00286.html
+ # meanwhile solved using a double array, wasting a full map memcpy
+ _karr=(${(Pk)_map})
+ _varr=(${(Pv)_map})
+ _num="${#_karr}"
+ for c in {1..$_num}; do
+ # can also be cat here, however for speed we use builtins
+ # switch to cat if compatibility is an issue
+ sysread -o 1 <<EOF >> $_path
+$_map+=("${_karr[$c]}" "${(v)_varr[$c]}")
+EOF
+ done
+ func "$_num key/values stored in $_path"
+ }
+
+}
+
+# optional: define zconsul=1 on source
+
+[[ "$zconsul" = "" ]] || {
+
+ ########
+ # Consul
+ # there is a clear zsh optimization here in get/set kv
+ # using zsh/tcp instead of spawning curl
+ # and perhaps querying with one call using ?recursive
+
+ zmodload zsh/net/tcp
+
+ zconsul.set() {
+ fn "zconsul.set $*"
+
+ # checks if consul running up to the caller
+
+ _host=$1 # ip address
+ _port=${host[(ws@:@)2]:-8500}
+ _k=$2 # key name
+ _v=$3 # value
+
+ req=(_host _port _k _v)
+ ckreq || return $?
+
+ ztcp $_host $_port || {
+ zerr
+ return 1
+ }
+
+ _fd=$REPLY
+ # func "tcp open on fd $fd"
+ cat <<EOF >& $_fd
+PUT /v1/kv/$_k HTTP/1.1
+User-Agent: Zuper/$zuper_version
+Host: $_host:$_port
+Accept: */*
+Content-Length: ${#v}
+Content-Type: application/x-www-form-urlencoded
+
+EOF
+
+ print -n "$v" >& $_fd
+
+ sysread -i $_fd _res
+
+ # close connection
+ ztcp -c $_fd
+
+ [[ "$_res" =~ "true" ]] || {
+ warn "cannot set key/value in consul: $_k = $_v"
+ zerr
+ return 1
+ }
+
+ return 0
+
+ }
+
+ zconsul.get() {
+ fn "zconsul.get $*"
+
+ _host=$1 # ip address
+ _port=${host[(ws@:@)2]:-8500}
+ _k=$2 # key name
+ _v=$3 # value
+
+ req=(_host _port _k _v)
+ ckreq || return $?
+
+ _k=$1
+
+ ztcp $_host $_port || {
+ zerr
+ return 1
+ }
+
+ _fd=$REPLY
+
+ cat <<EOF >& $_fd
+GET /v1/kv/$k HTTP/1.1
+User-Agent: Zuper/$zuper_version
+Host: $_host:$_port
+Accept: */*
+
+EOF
+ sysread -i $_fd -o 1 | awk -F: '
+/"Value":/ { gsub(/"|}]/,"",$7) ; print $7 }' | base64 -d
+
+ # close connection
+ ztcp -c $_fd
+
+ return 0
+
+ }
+
+}
diff --git a/src/zlibs/zuper.init b/src/zlibs/zuper.init
@@ -0,0 +1,16 @@
+##########################
+# Zuper Init
+
+# initialize globals only after sourcing everything
+# since zlibs may contain more variable declarations
+for v in $vars; do
+ typeset -h $v
+done
+for a in $arrs; do
+ typeset -a $a
+done
+func "Zuper $zuper_version initialized"
+func "${#vars} global variables registered"
+func "${#arrs} global arrays registered"
+
+