#!/bin/rc # 2022-11-16T18:11:20-05:00 # Mother wants to talk to you. # Similar to nedmail. Use with 9front or upas/fs. (Creates mdir format files on save.) # BONUS: Helper program for use with faces(1): http://plan9.stanleylieber.com/rc/facemother rfork en ramfs -p argv0=$0 if(~ $#editor 0) editor=hold if(~ $#pager 0) pager=cat mb=mbox msg=() sort=-r fn d{ if(test $1 -le $#rposts && test -d $rposts($1)){ flag +D $1 && dposts=($dposts $1) || echo !delete $1 failed } if not echo !address } fn deldposts{ ndel=() for(i in $dposts){ if(test $i -le $#rposts && test -d $rposts($i)){ echo delete $mb $rposts($i) >/mail/fs/ctl && echo !deleted $i && ndel=($ndel $i) || echo !delete $i failed } } echo !$#ndel messages deleted } fn e{ >/tmp/e && eval $editor /tmp/e && yn send && if(~ $yn y) /bin/upas/marshal $* $rposts($2)^/flags && puth $2 || echo !address } } fn fmtd{ date=`{read} switch($date(2)){ case Jan; mo=1 case Feb; mo=2 case Mar; mo=3 case Apr; mo=4 case May; mo=5 case Jun; mo=6 case Jul; mo=7 case Aug; mo=8 case Sep; mo=9 case Oct; mo=10 case Nov; mo=11 case Dec; mo=12 } switch($date(3)){ case [0-9] da=0^$date(3) case * da=$date(3) } switch($date(6)){ case `{date | awk '{print $6;}'} ti=`{echo $date(4) | awk '{print substr($0,0,5);}'} case * ti=$date(6) } echo $mo/$da $ti } fn geth{ for(i in $*){ flags=`{sed -n 18p $rposts($i)^/info | sed 's/-//g'} mime=`{ if(~ `{sed -n 7p $rposts($i)^/info} multipart*) echo H } size=`{sed -n 17p $rposts($i)^/info} date=`{sed -n 5p $rposts($i)^/info | fmtd} from=`{sed -n 1p $rposts($i)^/info} subject=`{sed -n 6p $rposts($i)^/info | awk '{print substr($0,0,50);}'} # Unicode 00a0 divides the message number from the headline. # Command input ignores everything after the unicode 00a0. # These lines may be selected and sent to the prompt # in order to print the indicated message. echo ' '$"i' '$"mime' '$"flags' '$"size' '$"date' '$"from' '$"subject } } fn getposts{ ls | grep -e '^[0-9]+$' | sort -n $sort } fn getr{ switch($*){ case ,; echo $posts case ,*; seq 1 `{echo $* | sed 's/,//g'} case *,; seq `{echo $* | sed 's/,//g'} $posts($#posts) case *,*; seq `{echo $* | sed 's/,/ /g'} case *; echo $* } } fn h{ sed -n $1^p /tmp/h } fn m{ if(test $1 -le $#rposts && test -f $rposts($1)^/info){ subject=`{sed -n 6p $rposts($1)^/info} if(! ~ $subject FWD:* Fwd:* fwd:*) subject=(Fwd: $subject) e -s $"subject -A $rposts($1)^/raw $*(2-) && flag +a $1 } if not echo !address } fn mb{ mb=$1 if(test -d /mail/box/$user/$mb || test -d $mb){ if(! ~ $mb mbox){ if(~ $mb /mail/fs/*) mb=`{basename $mb} if not if(~ $mb /*) echo open $mb `{basename $mb} >/mail/fs/ctl if not echo open /mail/box/$user/$mb $mb >/mail/fs/ctl mb=`{basename $mb} } cd /mail/fs/$mb dposts=() y post=$posts(1) prompt=$post } if not echo !^$mb does not exist } fn printhelp{ echo 'Commands are of the form [] [args] := | ',' := a reply to sender and recipients b print the next ten headers d mark for deletion e ... enter message (args passed to upas/marshal) g/regexp/cmd grep headlines for regexp and run cmd on matches h print message headline (,h for all) help print this help message m ... forward mail to address(es) mb ... change to specified mailbox p print the processed message P print the raw message q quit r reply to message s ... store message in specified mailbox u remove deletion mark y synchronize with mail box " print message in quoted form, suitable for reply |cmd pipe the processed message to a command ||cmd pipe the raw message to a command !cmd run a command' } fn pp{ if(test $1 -le $#rposts && test -f $rposts($1)^/header){ { # Avoid stutter by dumping everything into a file first. cat $rposts($1)^/header echo if(test -d $rposts($1)^/1){ parts=`{ls -p $rposts($1) | grep -e '^[0-9]+'} body=1/body if(test -f $rposts($1)^/1/1/body) body=1/1/body } if not{ parts=() body=body } type=`{file -m $rposts($1)^/$body} if(~ $type text/plain) cat $rposts($1)^/$body if not if(~ $type text/html){ hcmd=(htmlfmt -l60 -cutf8 -a $rposts($1)^/$body) echo !/bin/^$"hcmd eval $hcmd echo echo !--- $rposts($1) $type `{du $rposts($1)^/$body | awk '{print $1}'} [file:///mail/fs/$mb/^$rposts($1)^/$body] # plumb to browser } if not{ disp=`{sed -n 8p $rposts($1)^/info} file=`{sed -n 9p $rposts($1)^/info} fakefile $rposts($1) } echo if(! ~ $#parts 0){ if(! ~ $#parts 1) parts=$parts(2-) for(j in $parts){ type=`{file -m $rposts($1)^/$j/body} disp=`{sed -n 8p $rposts($1)^/$j/info} file=`{sed -n 9p $rposts($1)^/$j/info} fakefile $rposts($1)^/$j } parts=() } } >/tmp/p eval $pager /tmp/p go=1 r=$1 post=$1 prompt=$1 flag +s $1 } if not echo !address } fn P{ if(test $1 -le $#rposts && test -f $rposts($1)^/rawunix){ eval $pager $rposts($1)^/rawunix go=1 r=$1 post=$1 prompt=$1 flag +s $1 } if not echo !address } fn puth{ flags=`{sed -n 18p $rposts($1)^/info | sed 's/-//g'} mime=`{ if(~ `{sed -n 7p $rposts($1)^/info} multipart*) echo H } size=`{sed -n 17p $rposts($1)^/info} date=`{sed -n 5p $rposts($1)^/info | fmtd} from=`{sed -n 1p $rposts($1)^/info} subject=`{sed -n 6p $rposts($1)^/info | awk '{print substr($0,0,50);}'} { echo $1 echo c # REMEMBER: Unicode 00a0 divides the message number from the headline. echo ' '^$1^' '$"mime' '$"flags' '$"size' '$"date' '$"from' '$"subject echo . echo w echo q } | sam -d /tmp/h >/dev/null >[2=1] } fn r{ if(test $1 -le $#rposts && test -f $rposts($1)^/info){ subject=`{sed -n 6p $rposts($1)^/info} if(! ~ $subject RE:* Re:* re:*) subject=(Re: $subject) e -R $rposts($1) -s $"subject $*(2-) `{sed -n 4p $rposts($1)^/info} && flag +a $1 } if not echo !address } fn s{ if(test $1 -le $#rposts && test -f $rposts($1)^/raw){ if(! test -d /mail/box/$user/$2) echo create $2 >/mail/fs/ctl /bin/upas/mbappend $2 $rposts($1)^/raw && flag +S $1 && echo !saved in $2 } if not echo !address } fn u{ if(test $1 -le $#rposts && test -d $rposts($1)) flag -D $1 || echo !undelete $1 failed if not echo !address dposts=`{grep -v $1 <{for(j in $dposts){ echo $j }}} } fn y{ go=() r=$post if(! ~ $#dposts 0){ deldposts dposts=() } if(! ~ $q 1){ rposts=`{getposts} posts=`{seq 1 $#rposts} post=$posts(1) prompt=$post geth $posts >/tmp/h if(~ $#msg 0) echo $#posts messages } } fn yn{ echo echo -n $* ' (y, n) ' yn=`{read} switch($yn){ case y n ; case * yn } } fn '"' { pager=cat pp $1 | sed 1d | sed 's/^/> /g' | sed 's/^> >/>>/g' } fn usage{ echo usage: $argv0 [ -b ] [ -d ] [ -f mbox ] [ -p msg ] [ -r ] >[1=2] exit usage } while(~ $1 -*){ switch($1){ case -b; biff=-b case -d; debug=1 case -f; mb=$2; shift case -p; msg=$2; shift case -r; sort=(); shift case *; usage } shift } if(! ~ $#* 0) usage if(! test -f /mail/fs/ctl) /bin/upas/fs $biff #>[2]/dev/null if(! test -d /mail/box/$user/$mb && ! test -d $mb){ echo !^$mb does not exist exit $mb^' does not exist' } mb $mb if(! ~ $#msg 0){ for(i in `{seq 1 $#rposts}) if(~ $msg $rposts($i)) msg=$posts($i) pp $msg } while(){ echo -n $"prompt': ' # Command input ignores everything after unicode 00a0. rcmd=`{read | sed 's/[ ].*$//g' | sed 's/^([0-9]+)?(,)?([0-9]+)?/& /g'} switch($rcmd){ case ,* [0-9]* r=`{getr $rcmd(1)} cmd=$rcmd(2-) if(~ $#cmd 0) cmd=p case * r=$post cmd=$rcmd } switch($cmd){ case a a' '* for(i in $r) r $i $cmd(2-) `{sed -n 2,3p $rposts($i)^/info | sort -n | uniq} post=$r($#r) prompt=$post case b r=`{seq $r(1) `{echo $r(1)^+10|bc}} if(test $r($#r) -gt $posts($#posts)) r=`{seq $r(1) $posts($#posts)} if(! ~ $#r 0 && test $r(1) -le $posts($#posts)){ sed -n $r(1)^,$r($#r)^p /tmp/h post=$r($#r) prompt=$post } if not echo !address case d for(i in $r) d $i post=$r($#r) prompt=$post case e' '* e $cmd(2-) case g/* regexp=`{echo $cmd | awk -F '/' '{print $2;}'} # BUG: / is stripped from regexp and cmd. cmd=`{echo $cmd | awk -F '/' '{$1=""; $2=""; print;}'} r=`{