shithub: mother

ref: 8130672a9e99e52ac95d3bc11d1adff7d3ffaccc
dir: /mother/

View raw version
#!/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 $* </tmp/e
}
fn fakefile{
	if(! ~ $#file 0 || ~ $disp file inline){
		file='(file,'$"file')'
		fake=`{
			if(~ $type *gif *GIF)
				echo body.gif
			if not if(~ $type *jpeg *JPEG *jpg *JPG)
				echo body.jpg
			if not if(~ $type *png *PNG)
				echo body.png
			if not if(~ $file *.*)
				echo body.^`{echo $file | sed 's/(^.*\.|\)$)//g'}
			if not
				echo body
		}
		filepath=`{echo -n /mail/fs/$mb/^$1^/$fake}
		size=`{du $1^/$fake}
		echo !--- $1 $type $size(1) $file [$filepath]
	}
}
fn flag{
	if(~ $1 [\+][aDdfrSs] [-][aDdfrSs]){
		echo $1 >$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 [<range>] <command> [args]
<range> := <addr> | <addr>','<addr>
<command> :=
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=`{</tmp/h grep -e $"regexp | sed 's/ .*$//g'} # Strip everything after unicode 00a0.
		if(~ $#cmd 0)
			cmd=p
		if(~ $cmd d h p P u '"'){
			for(i in $r)
				eval $cmd $i
		}
		if not if(~ $cmd a' '* m' '* r' '* s' '*){
			for(i in $r)
				eval $cmd(1) $i $cmd(2-)
		}
		if not
			echo !illegal command
		post=$r($#r)
		prompt=$post
	case h
		{
			for(i in $r)
				h $i
		} | eval $pager
		post=$r($#r)
		prompt=$post
	case help
		printhelp
	case m' '*
		for(i in $r)
			m $i $cmd(2-)
		post=$r($#r)
		prompt=$post
	case mb' '*
		mb $cmd(2-)
	case p
		for(i in $r)
			pp $i
	case P
		for(i in $r)
			P $i
	case q
		q=1 y # BUP STOP
		exit ''
	case r r' '*
		for(i in $r)
			r $i $cmd(2-)
		post=$r($#r)
		prompt=$post
	case s' '*


		for(i in $r)
			s $i $cmd(2-)


		post=$r($#r)
		prompt=$post
	case u


		for(i in $r)
			u $i


		post=$r($#r)
		prompt=$post
	case y
		y
	case '"'
		for(i in $r)
			'"' $i | eval $pager
		post=$r($#r)
		prompt=$post
	case '?'
		echo dposts: $dposts
		echo rposts: $rposts
		echo posts: $posts
		echo post: $post
		echo r: $r
		if(! ~ $#mlpath 0)
			echo mdir: $mlpath^/^`{sed -n 19p $r/info}
		if(! ~ $#msg 0)
			echo msg: $msg
	case '|'*
		for(i in $r)
			pager=cat pp $i | eval `{echo $cmd | sed 's/^.//'}
	case '||'*
		for(i in $r)
			pager=cat P $i | eval `{echo $cmd | sed 's/^..//'}
	case '!'*
		for(i in $r)
			eval `{echo $cmd | sed 's/^.//'}
	case *
		if(~ $post $posts(1) && ~ $#go 0)
			pp $post
		if not if(! ~ $post $posts($#posts)){
			post=`{echo $post^+1 | bc}
			if(test $post -gt $posts($#posts))
				post=$posts($#posts)
			pp $post
		}
	}	
}