diff --git a/sites/plan9.stanleylieber.com/mother/README b/sites/plan9.stanleylieber.com/mother/README new file mode 100644 index 0000000..2dc70ad --- /dev/null +++ b/sites/plan9.stanleylieber.com/mother/README @@ -0,0 +1,65 @@ +mother +====== + +Mother is an [rc(1)](http://man.9front.org/1/rc) script that provides +an experience similar to +[nedmail(1)](http://man.9front.org/1/nedmail). + +Download it [here](http://only9fans.com/sl/mother/HEAD/info.html). + +help +---- + + usage: mother [ -d ] [ -f mbox ] [ -p msg ] [ -r ] + + 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 + +extensions +---------- + +A script may be used in conjunction with +[faces(1)](http://man.9front.org/1/faces) and the +[plumber(4)](http://man.9front.org/4/plumber) to open individual +messages (or the entire mailbox) by clicking mb1 on a face in the +[faces(1)](http://man.9front.org/1/faces) window. Each click produces +a new window containing the selected message. + +The script: +[facemother](https://plan9.stanleylieber.com/rc/facemother) <- read +and modify as needed before using + +The plumber rule: + + # faces -> new mail window for message + type is text + data matches '[a-zA-Z¡-￿0-9_\-./]+' + data matches '/mail/fs/[a-zA-Z¡-￿0-9/]+/[0-9]+' + plumb to showmail + plumb start window -r 646 117 1366 676 facemother $0 + +screenshots +----------- + +![ello.co](img/ello.co.png) diff --git a/sites/plan9.stanleylieber.com/mother/facemother b/sites/plan9.stanleylieber.com/mother/facemother new file mode 100755 index 0000000..facd29f --- /dev/null +++ b/sites/plan9.stanleylieber.com/mother/facemother @@ -0,0 +1,19 @@ +#!/bin/rc +# 2018-02-15T21:12:06-0500 +# helper program for launching http://plan9.stanleylieber.com/mother from faces(1). +rfork en + +# plumber rules for faces(1) +#type is text +#data matches '[a-zA-Z¡-￿0-9_\-./]+' +#data matches '/mail/fs/[a-zA-Z¡-￿0-9/]+/[0-9]+' +#plumb to showmail +#plumb start window -r 583 206 1303 1200 facemother $0 + +# open and print only the indicated message +msg=`{sed -n 19p $1/info} +upas/fs -f /mail/box/sl/mbox/$msg +mother -p 1 + +# use existing mailbox, print the indicated message +#mother -p `{basename $1} diff --git a/sites/plan9.stanleylieber.com/mother/img/ello.co.png b/sites/plan9.stanleylieber.com/mother/img/ello.co.png new file mode 100644 index 0000000..93ce227 Binary files /dev/null and b/sites/plan9.stanleylieber.com/mother/img/ello.co.png differ diff --git a/sites/plan9.stanleylieber.com/mother/index.md b/sites/plan9.stanleylieber.com/mother/index.md new file mode 100644 index 0000000..2dc70ad --- /dev/null +++ b/sites/plan9.stanleylieber.com/mother/index.md @@ -0,0 +1,65 @@ +mother +====== + +Mother is an [rc(1)](http://man.9front.org/1/rc) script that provides +an experience similar to +[nedmail(1)](http://man.9front.org/1/nedmail). + +Download it [here](http://only9fans.com/sl/mother/HEAD/info.html). + +help +---- + + usage: mother [ -d ] [ -f mbox ] [ -p msg ] [ -r ] + + 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 + +extensions +---------- + +A script may be used in conjunction with +[faces(1)](http://man.9front.org/1/faces) and the +[plumber(4)](http://man.9front.org/4/plumber) to open individual +messages (or the entire mailbox) by clicking mb1 on a face in the +[faces(1)](http://man.9front.org/1/faces) window. Each click produces +a new window containing the selected message. + +The script: +[facemother](https://plan9.stanleylieber.com/rc/facemother) <- read +and modify as needed before using + +The plumber rule: + + # faces -> new mail window for message + type is text + data matches '[a-zA-Z¡-￿0-9_\-./]+' + data matches '/mail/fs/[a-zA-Z¡-￿0-9/]+/[0-9]+' + plumb to showmail + plumb start window -r 646 117 1366 676 facemother $0 + +screenshots +----------- + +![ello.co](img/ello.co.png) diff --git a/sites/plan9.stanleylieber.com/mother/mkfile b/sites/plan9.stanleylieber.com/mother/mkfile new file mode 100755 index 0000000..e72fed0 --- /dev/null +++ b/sites/plan9.stanleylieber.com/mother/mkfile @@ -0,0 +1,9 @@ +web:V: + cp README index.md + if(test -f mother.tgz) + rm mother.tgz + cd .. + tar zcvf /tmp/mother.tgz mother + cd mother + cp /tmp/mother.tgz ../src/ + rm /tmp/mother.tgz diff --git a/sites/plan9.stanleylieber.com/mother/mother b/sites/plan9.stanleylieber.com/mother/mother new file mode 100755 index 0000000..b700e0c --- /dev/null +++ b/sites/plan9.stanleylieber.com/mother/mother @@ -0,0 +1,504 @@ +#!/bin/rc +# 2022-11-16T18:11:20-05:00 +# Mother wants to talk to you. +# Similar to nedmail. Use with 9front or nupas/fs (creates mdir format files on save). +# BONUS: Helper program for use with faces(1): http://plan9.stanleylieber.com/mother/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=`{