123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864 |
- #!/bin/sh
- # This file defines the edmail mail user agent.
- # Copyright (C) 2017-2018 mlaine@sdfeu.org
- # Permission is hereby granted, free of charge, to any person obtaining
- # a copy of this software and associated documentation files (the
- # "Software"), to deal in the Software without restriction, including
- # without limitation the rights to use, copy, modify, merge, publish,
- # distribute, sublicense, and/or sell copies of the Software, and to
- # permit persons to whom the Software is furnished to do so, subject to
- # the following conditions:
- # The above copyright notice and this permission notice shall be
- # included in all copies or substantial portions of the Software.
- # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
- # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
- # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
- # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
- # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- #-----------------------------------------------------------------------
- monnum () {
- case "$mon" in
- 'Jan') mon=1 ;;
- 'Feb') mon=2 ;;
- 'Mar') mon=3 ;;
- 'Apr') mon=4 ;;
- 'May') mon=5 ;;
- 'Jun') mon=6 ;;
- 'Jul') mon=7 ;;
- 'Aug') mon=8 ;;
- 'Sep') mon=9 ;;
- 'Oct') mon=10 ;;
- 'Nov') mon=11 ;;
- 'Dec') mon=12 ;;
- esac
- }
- pad () {
- case "$1" in
- [0-9]) printf '0%s\n' "$1" ;;
- *) printf '%s\n' "$1" ;;
- esac
- }
- parsedate () {
- date="$(awk '/^Date: /{print;exit}' "$file" | cut -d' ' -f2-)"
- set -- $(printf '%s\n' "${date#*, }")
- day="${1#0}"; mon="$2"; year="$3"; time="${4%:*}"; tz="${5#*[+-]}"
- hrs="${time%:*}"; hrs="${hrs#0}"
- min="${time#*:}"; min="${min#0}"
- tzhrs="${tz%??*}"; tzhrs="${tzhrs#0}"
- tzmin="${tz#*??}"; tzmin="${tzmin#0}"
- monnum
- case "$5" in
- '+0000'|'-0000'|'GMT')
- true ;;
- '+'*)
- hrs="$((hrs-tzhrs))"
- min="$((min-tzmin))"
- test "$min" -lt 00 && min="$((min+60))" && hrs="$((hrs-1))"
- test "$hrs" -lt 00 && hrs="$((hrs+24))" && day="$((day-1))"
- case "$mon" in
- 3)
- test "$day" -lt 1 && day=28 && mon="$((mon-1))" ;;
- 5|7|10|12)
- test "$day" -lt 1 && day=30 && mon="$((mon-1))" ;;
- *)
- test "$day" -lt 1 && day=31 && mon="$((mon-1))" ;;
- esac ;;
- '-'*)
- hrs="$((hrs+tzhrs))"
- min="$((min+tzmin))"
- test "$min" -gt 59 && min="$((min%60))" && hrs="$((hrs+1))"
- test "$hrs" -gt 23 && hrs="$((hrs%24))" && day="$((day+1))"
- case "$mon" in
- 2)
- test "$day" -gt 28 && day=1 && mon="$((mon+1))" ;;
- 4|6|9|11)
- test "$day" -gt 30 && day=1 && mon="$((mon+1))" ;;
- *)
- test "$day" -gt 31 && day=1 && mon="$((mon+1))" ;;
- esac ;;
- *)
- time='??:??' ;;
- esac
- test "$mon" -gt 12 && mon=1 && year="$((year+1))"
- test "$mon" -lt 1 && mon=12 && year="$((year-1))"
- mon="$(pad "$mon")"; day="$(pad "$day")"
- hrs="$(pad "$hrs")"; min="$(pad "$min")"
- test "$time" = '??:??' || time="$hrs:$min"
- }
- awkmatch () {
- awk -v p="$pat" 'BEGIN{s=1}$0~p{s=0;exit}END{exit s}' "$file"
- }
- update () {
- if [ -n "$filter" ]; then
- true > "$templist"
- find "$dir" -type f |
- while read -r file; do
- if awkmatch; then
- printf '%s\n' "$file" >> "$templist"
- fi
- done
- else
- find "$dir" -type f > "$templist"
- fi
- if ! cmp -s "$templist" "$filelist"; then
- cp "$templist" "$filelist"
- true > "$statlist"
- while read -r file; do
- set -- $(wc < "$file")
- lines="$1"; bytes="$3"
- parsedate; date="$year $mon $day $hrs $min"
- printf '%s %s\n' "$file" "$lines $bytes $date" >> "$statlist"
- done < "$filelist"
- n="$(awk 'END{print NR}' "$filelist")"
- fi
- if [ -n "$bysize" ]; then
- sort -k 3,3nr -o "$statlist" "$statlist"
- elif ! cmp -s "$tempstat" "$statlist"; then
- sort -k 4,4n -k 5,5n -k 6,6n -k 7,7n -k 8,8n -o "$statlist" "$statlist"
- cp "$statlist" "$tempstat"
- fi
- }
- archive () {
- find "$new" -type f > "$templist"
- newn="$(awk 'END{print NR}' "$templist")"
- test "$newn" -eq 0 && return 1
- while read -r file; do
- filename="${file##*/}"
- mv "$file" "${cur}/${filename%:*}:2,S"
- done < "$templist"
- }
- loop () {
- i=0; j=0
- while read -r line; do
- i="$((i+1))"
- if [ "$cmd" = 'z' ]; then
- true
- elif [ "$i" -le "$upper" ]; then
- if [ "$i" -ge "$lower" ]; then
- j="$((j+1))"
- else
- continue
- fi
- else
- break
- fi
- "$1" "$line"
- done < "$statlist"
- }
- term () {
- cols="$(tput cols)"
- rows="$(tput lines)"
- rows="$((rows-3))"
- test "$rows" -lt 10 && rows=10
- upper="$((cursor+rows-6))"
- test "$upper" -gt "$n" && upper="$n"
- lower="$((upper-rows+1))"
- if [ "$lower" -lt 1 ]; then
- upper="$((upper-lower+1))"
- lower=1
- fi
- }
- field () {
- printf '%s\n' "$head" | awk -v p="^$1: " '$0~p{print;exit}' | cut -d' ' -f2-
- }
- brief () {
- set -- $1
- file="$1"; lines="$2"; bytes="$3"; date="$5/$6/$4 $7:$8"
- head="$(awk 'BEGIN{RS=""}NR==1{print;exit}' "$file")"
- case "$dir" in
- "$tmp"|"$record")
- name="$(field 'To')" ;;
- *)
- name="$(field 'From' | tr -d \")"; name="${name% <*}" ;;
- esac
- name="$(printf '%s\n' "$name" | cut -c-22)"
- subj="$(field 'Subject')"
- if [ "$lines" -lt 1000 ] && [ "$bytes" -lt 10000 ]; then
- size="$lines/$bytes"
- else
- size="$(du -h "$file" | cut -f1 )"
- fi
- pre=' '
- if [ "$cmd" = 'z' ]; then
- unset pre
- elif [ "$i" -eq "$cursor" ]; then
- pre='->'
- fi
- c="${#n}"; wdth="$((cols-54-c))"
- set -- "$pre" "$c" "$i" "$name" "$date" "$size" "$wdth" "$subj"
- printf '%s%*s %-22s %s %-8s "%.*s"\n' "$@"
- }
- headline () {
- unset match sort
- test "$filter" && match=" matching \"$pat\""
- test "$bysize" && sort=', sorted by size'
- case "$n" in
- 0)
- printf '%s: no messages%s%s\n' "$dir" "${match:-}" "${sort:-}"
- cursor=1; return ;;
- 1)
- printf '%s: %s messages%s%s\n' "$dir" "$n" "${match:-}"\
- "${sort:-}" ;;
- *)
- printf '%s: %s messages%s%s\n' "$dir" "$n" "${match:-}"\
- "${sort:-}" ;;
- esac
- }
- list () {
- update; term
- if [ "$cmd" = 'z' ]; then
- wdth="$((wdth+2))"
- headline; loop 'brief' | pager
- else
- headline; loop 'brief'
- fi
- }
- part () {
- file="$(awk -v i="$cursor" 'NR==i{print $1;exit}' "$statlist")"
- head="$(awk 'BEGIN{RS=""}NR==1{print;exit}' "$file")"
- body="$(awk '/^$/?i++:i' "$file")"
- }
- retain () {
- date="Date: $(field 'Date')"
- addr="From: $(field 'From' | tr -d \")"
- to="To: $(field 'To')"
- cc="$(field 'Cc')"
- subj="Subject: $(field 'Subject')"
- if [ -n "$cc" ]; then
- set -- "$date" "$addr" "$to" "Cc: $cc" "$subj"
- else
- set -- "$date" "$addr" "$to" "$subj"
- fi
- retain="$(printf '%s\n' "$@")"
- }
- page () {
- if [ "$n" -eq 0 ]; then
- printf 'EOF\n'
- return 1
- fi
- cursor="${cmd:-"$cursor"}"
- part
- retain
- tput clear
- printf '%s\n' "$retain" '' "$body" | pager
- }
- int () {
- if ([ "$1" -gt 0 ] && [ "$1" -le "$n" ]) 2>'/dev/null'; then
- return 0
- fi
- return 1
- }
- valid () {
- arg="${cmd#?}"
- if [ -n "$arg" ]; then
- lower="${arg%-*}"
- upper="${arg#*-}"
- if [ "$arg" = '*' ]; then
- lower=1
- upper="$n"
- elif [ "$arg" = '-.' ]; then
- lower=1
- upper="$cursor"
- elif [ "$arg" = '.-' ]; then
- lower="$cursor"
- upper="$n"
- elif [ "$arg" = ',' ]; then
- lower="$n"
- upper="$n"
- elif [ "$arg" = '-' ]; then
- printf '?\n'
- return 1
- fi
- test -z "$upper" && upper="$n"
- test -z "$lower" && lower=1
- elif [ "$n" -eq 0 ]; then
- printf 'EOF\n'
- return 1
- else
- lower="$cursor"
- upper="$cursor"
- return 0
- fi
- if int "$lower" && int "$upper"; then
- case "$cmd" in
- 'd'*|'y'*|'@'*)
- if [ "$upper" -ge "$lower" ]; then
- true
- else
- printf 'invalid range\n'
- return 1
- fi ;;
- *)
- if [ "$lower" -ne "$upper" ]; then
- printf 'this command supports no ranges\n'
- return 1
- else
- cursor="$lower"
- fi ;;
- esac
- else
- printf '?\n'
- return 1
- fi
- }
- header () {
- valid || return 1
- part
- tput clear
- printf '%s\n' "$head" | pager
- }
- pipe () {
- valid || return 1
- part
- test "$args" || args="$pipeto"
- tput clear
- printf '%s\n' "$body" | sh -c "$args" | pager
- }
- save () {
- # TODO: save MIME attachments
- valid || return 1
- if [ -z "$args" ]; then
- printf 'provide a filename\n'
- return 1
- fi
- part
- retain
- printf '%s\n\n%s\n' "$retain" "$body" > "$HOME/$args"
- printf 'message %s saved to %s/%s\n' "$cursor" "$HOME" "$args"
- }
- cpdo () {
- file="${1%% *}"
- filename="${file##*/}"
- cp "$file" "$args/${filename%:*}:2,S"
- }
- copy () {
- valid || return 1
- if [ -z "$args" ]; then
- printf 'provide a directory to copy into\n'
- return 1
- fi
- case "$args" in
- '/'*)
- true ;;
- 'i')
- args="$new" ;;
- 'c')
- args="$cur" ;;
- 't')
- args="$tmp" ;;
- 'o')
- if [ -n "$record" ]; then
- args="$record"
- else
- args="$HOME/$args/o"
- fi ;;
- *)
- args="$HOME/$args" ;;
- esac
- if [ ! -d "$args" ]; then
- printf '%s does not exist, create it? [Y/n]: ' "$args"
- read -r mkd
- case "$mkd" in
- ''|'Y'|'y')
- mkdir -p "$args" ;;
- *)
- printf 'aborting\n'
- return 1 ;;
- esac
- fi
- loop 'cpdo'
- count="$((upper-lower+1))"
- if [ "$count" -eq 1 ]; then
- printf 'one message copied to %s\n' "$args"
- else
- printf '%s messages copied to %s\n' "$count" "$args"
- fi
- }
- printfile () {
- printf '%s\n' "${1%% *}" >> "$templist"
- }
- delete () {
- valid || return 1
- count="$((upper-lower+1))"
- true > "$templist"
- loop 'printfile'
- while read -r file; do
- filename="${file##*/}"
- printf '/%s/d\n%s\n' "$filename" 'wq' | ed -s "$filelist"
- printf '/%s/d\n%s\n' "$filename" 'wq' | ed -s "$statlist"
- if [ "$dir" = "$del" ]; then
- rm "$file"
- else
- mv "$file" "${del}/${filename%:*}:2,T"
- fi
- done < "$templist"
- cp "$statlist" "$tempstat"
- n="$(awk 'END{print NR}' "$filelist")"
- if [ "$lower" -lt "$cursor" ]; then
- if [ "$upper" -ge "$cursor" ]; then
- cursor="$lower"
- else
- cursor="$((cursor-upper+lower-1))"
- fi
- fi
- test "$cursor" -gt "$n" && cursor="$n"
- test "$cursor" -lt 1 && cursor=1
- if [ "$count" -gt 1 ]; then
- printf '%s messages deleted\n' "$count"
- fi
- }
- parsemsg () {
- mid="$(field 'Message-ID')"
- addr="$(field 'From')"
- subj="$(field 'Subject')"
- replyto="$(field 'Reply-To')"
- to="${replyto:-"$addr"}"
- to="${to#*<}"; to="${to%>*}"
- subj="Re: ${subj#Re: *}"
- ref="$(printf '%s\n' "$head" | awk '/:/{i=0}/^References:/{i=1}i')"
- irt="$(printf '%s\n' "$head" | awk '/:/{i=0}/^In-Reply-To:/{i=1}i')"
- irtl="$(printf '%s\n' "$irt" | awk 'END{print NR}')"
- }
- toed () {
- printf '%s\n' "$@" | ed -s "$msg"
- }
- reply () {
- valid || return 1
- part
- parsemsg
- printf 'To [%s]: ' "$to"
- read -r newto
- printf 'Subject [%s]: ' "$subj"
- read -r newsubj
- subj="${newsubj:-"$subj"}"
- to="${newto:-"$to"}"
- msg="${tmp}/$(date '+%s')-edmail@$(hostname)"
- printf '%s\n' "$body" > "$msg"
- toed ',s/^/> /' '0a' "$addr wrote:" '' '.' 'w'
- editor "$msg"
- hdrs
- if [ -n "$ref" ]; then
- toed '0a' "$ref" " $mid" '.' 'w'
- elif [ -n "$irt" ] && [ "$irtl" -eq 1 ]; then
- toed '0a' "References: ${irt#* }" " $mid" '.' 'w'
- fi
- if [ -n "$mid" ]; then
- toed '0a' "In-Reply-To: $mid" '.' 'w'
- fi
- }
- edit () {
- if [ "${dir##*/}" != 'tmp' ] && [ "$cmd" != '#' ]; then
- printf 'will not comply outside tmp/\n'
- return 1
- fi
- valid || return 1
- part
- if [ "$cmd" = '#' ]; then
- editor "$file"
- return 0
- fi
- to="$(field 'To')"
- subj="$(field 'Subject')"
- printf 'To [%s]: ' "$to"
- read -r newto
- printf 'Subject [%s]: ' "$subj"
- read -r newsubj
- subj="${newsubj:-"$subj"}"
- to="${newto:-"$to"}"
- msg="${tmp}/$(date '+%s')-edmail@$(hostname)"
- printf '%s\n' "$body" > "$msg"
- editor "$msg"
- hdrs
- rm "$file"
- update
- }
- compose () {
- if [ -n "$args" ]; then
- to="$args"
- else
- printf 'To: '
- read -r to
- fi
- printf 'Subject: '
- read -r subj
- msg="${tmp}/$(date '+%s')-edmail@$(hostname)"
- editor "$msg"
- if [ -f "$msg" ]; then
- hdrs
- test -f "$sign" && cat "$sign" >> "$msg"
- else
- printf 'nothing written\n'
- fi
- }
- hdrs () {
- h1="Message-ID: <${msg##*/}>"
- h2="Date: $(date '+%a, %d %b %Y %T %z')"
- h3="From: $from"
- h4="To: $to"
- h5="Subject: $subj"
- toed '0a' "$h1" "$h2" "$h3" "$h4" "$h5" '' '.' 'w'
- }
- send () {
- if [ -z "$(find "$tmp" -type f)" ]; then
- printf '%s contains no messages\n' "$tmp"
- return 1
- fi
- i=0; j=0
- for file in "$tmp"/*; do
- j="$((j+1))"
- addr="$(awk '/^To: /{print;exit}' "$file" | cut -d' ' -f2-)"
- if sendmail "$addr" < "$file"; then
- i="$((i+1))"
- if [ -n "$record" ]; then
- mv "$file" "$record"
- else
- rm "$file"
- fi
- else
- printf 'edmail: could not send %s\n\n' "$file"
- fi
- done
- if [ "$i" -eq 0 ]; then
- printf 'no messages sent\n'
- elif [ "$j" -eq 1 ]; then
- printf '%s/%s message successfully sent\n' "$i" "$j"
- else
- printf '%s/%s messages successfully sent\n' "$i" "$j"
- fi
- test "${dir##*/}" = 'tmp' && update
- }
- parserc () {
- printf '%s\n' ',s/ *$//' "/^set $1=" | ed -s "$mailrc"\
- 2>'/dev/null' | cut -d'=' -f2- | tr -d \"
- }
- statfold () {
- for fold in "$@"; do
- if [ ! -d "$fold" ]; then
- if [ -z "$said" ]; then
- printf 'could not find the following, required, directories:\n'
- said=0
- fi
- printf ' %s\n' "$fold"
- notfound=0
- fi
- done
- test "$notfound" && return 0
- }
- folders () {
- new="$maildir/new"
- cur="$maildir/cur"
- tmp="$maildir/tmp"
- del="$maildir/.del"
- }
- init () {
- test "${tempdir:="$(mktemp -dt edmail.XXXXXX)"}" || return 1
- filelist="$tempdir/filelist"; templist="$tempdir/templist"
- statlist="$tempdir/statlist"; tempstat="$tempdir/tempstat"
- trap "rm -r $tempdir; exit" 0
- trap "printf '\n'; continue" 2
- if [ ! -f "${mailrc:="$HOME/.mailrc"}" ]; then
- printf 'could not find %s\n' "$mailrc"
- return 1
- fi
- fetchmail="$(parserc 'fetchmail')"
- sendmail="$(parserc 'sendmail')"
- maildir="$(parserc 'folder')"
- record="$(parserc 'record')"
- from="$(parserc 'from')"
- sign="$(parserc 'signature')"
- pager="$(parserc 'PAGER')"
- editor="$(parserc 'EDITOR')"
- pipeto="$(parserc 'cmd')"
- test "$maildir" || maildir="$HOME/.maildir"
- folders
- set -- "$new" "$cur" "$tmp" "$del"
- if [ -n "$record" ]; then
- case "$record" in
- '+'*)
- record="$maildir/${record#+}" ;;
- *)
- true ;;
- esac
- set -- "$@" "$record"
- fi
- if [ -z "$from" ]; then
- printf "set the string option 'from' in %s\\n" "$mailrc"
- return 1
- elif statfold "$@"; then
- printf 'create them? [Y/n]: '
- read -r mkd
- case "$mkd" in
- ''|'Y'|'y')
- if mkdir -p "$@"; then
- folders
- printf '#\n' > "$templist"
- return 0
- fi ;;
- *)
- printf 'exiting\n' ;;
- esac
- else
- folders
- printf '#\n' > "$templist"
- return 0
- fi
- return 1
- }
- fetchmail () {
- if [ -n "$fetchmail" ]; then
- if [ ! -x "$fetchmail" ]; then
- printf '%s is not executable\n' "$fetchmail"
- return 1
- else
- "$fetchmail"
- fi
- else
- mpop
- fi
- }
- sendmail () {
- if [ -n "$sendmail" ]; then
- if [ ! -x "$sendmail" ]; then
- printf '%s is not executable\n' "$sendmail"
- return 1
- else
- "$sendmail" "$@" || return 1
- fi
- else
- msmtp -- "$@" || return 1
- fi
- }
- pager () {
- if [ -n "$pager" ]; then
- if [ ! -x "$pager" ]; then
- printf '%s is not executable\n' "$pager"
- return 1
- else
- "$pager"
- fi
- else
- more
- fi
- }
- editor () {
- if [ -n "$editor" ]; then
- if [ ! -x "$editor" ]; then
- printf '%s is not executable\n' "$editor"
- return 1
- else
- "$editor" "$@"
- fi
- else
- ed -sp \* "$@"
- fi
- }
- serv () {
- case "$cmd" in
- '')
- page ;;
- ',')
- cmd="$n"
- page ;;
- 'f'|'+')
- if [ "$cursor" -lt "$n" ]; then
- cursor="$((cursor+1))"
- cmd="$cursor"
- page
- else
- printf 'EOF\n'
- fi ;;
- 'b'|'-')
- if [ "$cursor" -gt 1 ]; then
- cursor="$((cursor-1))"
- cmd="$cursor"
- page
- else
- printf 'BOF\n'
- fi ;;
- 'l'|'.')
- list ;;
- 'z')
- list ;;
- 'g')
- cursor=1
- list ;;
- 'g'*)
- valid || return 1
- list ;;
- 'G')
- cursor="$n"
- list ;;
- 'k')
- k="$((cursor-20))"
- if [ "$k" -le 1 ]; then
- cursor=1
- else
- cursor="$k"
- fi
- list ;;
- 'j')
- j="$((cursor+20))"
- if [ "$j" -le "$n" ]; then
- cursor="$j"
- fi
- list ;;
- 'i')
- dir="$new"
- cursor=1
- list ;;
- 'c')
- dir="$cur"
- cursor=1
- list ;;
- 't')
- dir="$tmp"
- cursor=1
- list ;;
- '%')
- dir="$del"
- cursor=1
- list ;;
- 'o')
- if [ -z "$record" ]; then
- printf '?\n'
- return 1
- fi
- dir="$record"
- cursor=1
- list ;;
- 'm')
- compose ;;
- 'h'*)
- header ;;
- 'd'*)
- delete ;;
- 'r'*)
- reply ;;
- 'p'*)
- pipe ;;
- 'y'*)
- copy ;;
- 'e'*|'#'*)
- edit ;;
- 's'*)
- save ;;
- 'w')
- send ;;
- 'n')
- fetchmail
- test "$dir" = "$new" && update ;;
- 'v')
- printf 'edmail version 0.1.0\n' ;;
- 'a')
- if archive; then
- printf '%s new messages moved to %s\n' "$newn" "$cur"
- else
- printf 'nothing to be done\n'
- fi
- test "$dir" = "$new" && update ;;
- 'q')
- find "$del" -type f -delete
- archive; exit 0 ;;
- 'x')
- exit 0 ;;
- 'u')
- if [ -z "$bysize" ]; then
- bysize=0
- else
- unset bysize
- fi
- list ;;
- '/')
- if [ -z "$filter" ]; then
- filter=0
- else
- unset filter
- fi
- list ;;
- '/'*)
- pat="${cmd#?}${args:+" $args"}"
- filter=0
- cursor=1
- list ;;
- '@'*)
- valid || return 1
- awk -v a="$lower" -v b="$upper" 'NR>=a&&NR<=b{print $1}'\
- "$statlist" ;;
- ';')
- tput clear ;;
- '?')
- man edmail ;;
- '!'|'$')
- sh ;;
- '!'*)
- sh -c "${cmd#?} $args" ;;
- *)
- if int "$cmd"; then
- page
- else
- printf '?\n'
- fi ;;
- esac
- }
- main () {
- init || exit 1
- cmd='i'; serv
- while true; do
- printf '& '
- read -r cmd args
- serv
- done
- }
- main
|