-
diff --git a/apps/mdir/TODO b/apps/mdir/TODO
new file mode 100644
index 0000000..d1b1f3b
--- /dev/null
+++ b/apps/mdir/TODO
@@ -0,0 +1,10 @@
+* unfuck quoted-printable crap
+* more robust plaintext extraction from mime
+* more efficient month sort in the year view
+ * I think sort(1) might have a bug with -M and pos1
+ * or stupid awk can just produce an ordered list
+* a lot of speedup
+ * this might mean an external index
+ * or it might just mean aggressive in-app cache
+* do we want threading in the month views
+* decode non-ascii header values (From: especially)
diff --git a/apps/mdir/app.rc b/apps/mdir/app.rc
new file mode 100755
index 0000000..b9f05c9
--- /dev/null
+++ b/apps/mdir/app.rc
@@ -0,0 +1,178 @@
+fn conf_enable_mdir {
+ mdir=`{pwd}
+ listbase=$conf_wd
+ listname=`{basename `{ basename -d $listbase}}
+ conf_enable_app mdir
+ dirfilter=$dirfilter' /mbox\/?$/d;'
+}
+
+
+fn mdir_init {
+ showmonth=`{echo $req_path | sed 's/.*[0-9][0-9][0-9][0-9]\/([A-Z][a-z][^\/]+).*/\1/'}
+ showyear=`{echo $req_path | sed 's/.*\/([0-9][0-9][0-9][0-9])\/.*/\1/'}
+ handler_body_main='mdir_index'
+
+ if (~ $req_path $listbase[0-9][0-9][0-9][0-9]/[A-Z][a-z]*/[0-9]*) {
+ handler_body_main='message_display'
+ }
+ if not if (~ $req_path $listbase[0-9][0-9][0-9][0-9]/[A-Z][a-z]*) {
+ handler_body_main='month_display'
+ }
+ if not if(~ $req_path $listbase[0-9][0-9][0-9][0-9]*) {
+ handler_body_main='year_display'
+ }
+
+
+}
+
+fn message_display {
+ message=`{basename $req_path}
+ echo '
'$listname' - '$showyear' - '
+ echo ''$showmonth' -'
+ echo 'this message '
+ approx=`{echo $"message | sed 's/(...).*/\1/' }
+ neighbors=`{ls -p $mdir/mbox/$approx^*}
+ prevmsg=`{echo $neighbors | tr '\012' ' ' | sed -n 's/.* ([^ ]+) '$message'.*/\1/p'}
+ nextmsg=`{echo $neighbors | tr '\012' ' ' | sed -n 's/.*'$message' ([^ ]+).*/\1/p'}
+ echo '
'
+ if (~ $#prevmsg 1 || ~ $#nextmsg 1) { echo '[ ' }
+ if (~ $#prevmsg 1) { echo 'previous' }
+ if (~ $#prevmsg 1 && ~ $#nextmsg 1) { echo ' , ' }
+ if (~ $#nextmsg 1) { echo 'next' }
+ if (~ $#prevmsg 1 || ~ $#nextmsg 1) { echo ' ]' }
+ echo '
'
+ awk '
+ /^Subject:/ && (headersdone == 0) { subject=$0 }
+ /^From:/ && (headersdone == 0) { from=$0; gsub(/, "\\<", from); gsub(/>/, "\\>", from); }
+ /^Date:/ && (headersdone == 0) { date=$0 }
+ /^$/ && (headersdone==0) { print "" subject "
"; print from; print date; headersdone=1 }
+ (headersdone == 1) { exit }
+ ' $mdir/mbox/$message | sed 's/([^ @.]+)\@[^ @]+\.[^@ $][a-zA-Z]+/\1@[REDACTED]/g;'
+
+ cat $mdir/mbox/$message | {
+ boundary=undef;
+ while (line=`{read}) {
+ if (~ $line Content-Type*multipart*) { # flag mimeshit boundary
+ multipart=1
+ boundary=`{echo $line | sed 's/^.*boundary=//; s/[ ].*$//'}
+ if (test -z $boundary) { boundary=undef; } # fucking header wrap
+ }
+ if (~ $multipart 1) {
+ if (~ $boundary undef) { # desperately try to identify a boundary
+ boundary=`{echo $line | sed 's/^.*boundary=//; s/[ ].*$//'}
+ }
+ }
+
+ if (~ $"line '') { # note end of header section
+ endheaders = 1;
+ }
+
+ if (~ $boundary undef ) { # no boundary, headers over: print message
+ if (~ $endheaders 1) {
+ echo $line
+ }
+ }
+ if not { # boundaries: print only text/plain
+ if (~ $line --$boundary) { # boundary found, toggle state
+ if (~ $inboundary 1) {
+ inboundary=0
+ }
+ if not {
+ inboundary=1
+ }
+ }
+ if (~ $inboundary 1) { # we're in a text/plain part, print it
+ if (~ $textpart 1) {
+ echo $line
+ }
+ }
+ if (~ $line Content-Type*text*plain*) { # note advent of text/plain part
+ if (~ $inboundary 1) {
+ echo found text part
+ textpart=1
+ }
+ }
+ }
+ }
+ }
+
+ echo ''
+}
+
+fn mdir_index {
+ echo '' $listname '
'
+ echo ''
+ ls -p $mdir/mbox | awk ' { year = int($0 / 31556926); array[year+1970]+=1; }
+ END { for (i in array) { print "- " i " (" array[i] " messages)
" | "sort"} }'
+ echo '
'
+}
+
+fn year_display {
+echo ''
+echo ''
+ls -p $mdir/mbox | awk 'BEGIN { jan = (ENVIRON["showyear"] - 1970) * 31556926
+ feb = jan + 2629743; mar = feb + 2629743; apr = mar + 2629743; may = apr + 2629743;
+ jun = may + 2629743; jul = jun + 2629743; aug = jul + 2629743; sep = aug + 2629743;
+ oct = sep + 2629743; nov = oct + 2629743; dec = nov + 2629743; end = dec + 2629743 }
+ ($0 > jan) && ($0 < feb) { month["January"] += 1 }
+ ($0 > feb) && ($0 < mar) { month["February"] += 1 }
+ ($0 > mar) && ($0 < apr) { month["March"] += 1 }
+ ($0 > apr) && ($0 < may) { month["April"] += 1 }
+ ($0 > may) && ($0 < jun) { month["May"] += 1 }
+ ($0 > jun) && ($0 < jul) { month["June"] += 1 }
+ ($0 > jul) && ($0 < aug) { month["July"] += 1 }
+ ($0 > aug) && ($0 < sep) { month["August"] += 1 }
+ ($0 > sep) && ($0 < oct) { month["September"] += 1 }
+ ($0 > oct) && ($0 < nov) { month["October"] += 1 }
+ ($0 > nov) && ($0 < dec) { month["November"] += 1 }
+ ($0 > dec) && ($0 < end) { month["December"] += 1 }
+ END { for (i in month) {
+ print i "- " i " (" month[i] " messages)
"
+ } }
+ '| sort -M | sed 's/^[A-Za-z]+- /
- /'
+
+echo '
'
+}
+
+fn month_display {
+echo ''$listname' - '$showyear' - '$showmonth'
'
+echo ''
+ls -p $mdir/mbox | awk 'BEGIN { monthstamp = (ENVIRON["showyear"] - 1970) * 31556926
+ month = ENVIRON["showmonth"]
+ year = ENVIRON["showyear"]
+ listbase = ENVIRON["listbase"]
+ msg = ENVIRON["msg"]
+ if (month == "February") { monthstamp += 2629743 }
+ if (month == "March") { monthstamp += (2629743 * 2) }
+ if (month == "April") { monthstamp += (2629743 * 3) }
+ if (month == "May") { monthstamp += (2629743 * 4) }
+ if (month == "June") { monthstamp += (2629743 * 5) }
+ if (month == "July") { monthstamp += (2629743 * 6) }
+ if (month == "August") { monthstamp += (2629743 * 7) }
+ if (month == "September"){ monthstamp += (2629743 * 8) }
+ if (month == "October") { monthstamp += (2629743 * 9) }
+ if (month == "November") { monthstamp += (2629743 * 10) }
+ if (month == "December") { monthstamp += (2629743 * 11) }
+ monthend = monthstamp + 2629743
+ }
+ ($0 > monthstamp) && ($0 < monthend) { print $0 }
+ ' | sort -u | while (msg=`{read}) {
+ awk 'BEGIN { month = ENVIRON["showmonth"]; year = ENVIRON["showyear"];
+ listbase = ENVIRON["listbase"]; msg = ENVIRON["msg"] }
+ /^Subject:[ ]/ { subject = $0; sub(/^Subject: /, "", subject) }
+ /^From:[ ]/ { gsub(/^From:[ ]+/, "", $0);
+ gsub(/ <.*$/, "", $0);
+ gsub(/[<>]/, "", $0);
+ gsub(/^.*[(]/, "", $0);
+ gsub(/[)].*$/, "", $0);
+ gsub(/["]/, "", $0);
+ gsub(/@[^ ]+/, "", $0);
+ from=$0; }
+ /^$/ { nextfile; }
+ END { if (subject == "") { subject = "[no subject]" }
+ print "- ";
+ print subject " - " from "
" }' $mdir/mbox/$msg
+ }
+
+echo '
'
+}
diff --git a/apps/mdir/readme.txt b/apps/mdir/readme.txt
new file mode 100644
index 0000000..25ab886
--- /dev/null
+++ b/apps/mdir/readme.txt
@@ -0,0 +1,11 @@
+INSTALL:
+
+put this folder in e.g. /werc/apps/mdir
+
+put your mdir in e.g. /werc/sites/example.com/mail/
+(such that all the messages land in /werc/sites/example.com/mail/mbox/)
+
+mkdir /werc/sites/example.com/mail/_werc
+echo "conf_enable_mdir" > /werc/sites/example.com/mail/_werc/config
+
+good luck.
diff --git a/apps/wman/search.tpl b/apps/wman/search.tpl
index a6c59e4..ed57743 100755
--- a/apps/wman/search.tpl
+++ b/apps/wman/search.tpl
@@ -6,7 +6,7 @@
% if(! ~ $"post_arg_wman_search '') {
% if(~ $"wman_search_results '') {
- No matches found for '%($post_arg_wman_search%)'.
+ No matches found for '%($s%)'.
% }
% if not {
diff --git a/bin/contrib/rc-httpd/handlers/error b/bin/contrib/rc-httpd/handlers/error
index 282d870..fa594a9 100755
--- a/bin/contrib/rc-httpd/handlers/error
+++ b/bin/contrib/rc-httpd/handlers/error
@@ -3,7 +3,7 @@
fn do_error{
echo 'HTTP/1.1 '^$1^$cr
emit_extra_headers
- echo 'Content-type: text/html'^$cr
+ echo 'Content-type: text/html; charset=utf-8'^$cr
echo $cr
echo '
@@ -19,6 +19,11 @@ fn do_error{
'
}
+fn 400{
+ do_error '400 Bad Request' \
+ 'The request was invalid.'
+}
+
fn 401{
do_error '401 Unauthorized' \
'The requested path '^$"location^' requires authorization.'
diff --git a/bin/contrib/rc-httpd/rc-httpd b/bin/contrib/rc-httpd/rc-httpd
index 8e4fad9..864a8d0 100755
--- a/bin/contrib/rc-httpd/rc-httpd
+++ b/bin/contrib/rc-httpd/rc-httpd
@@ -86,6 +86,11 @@ if(~ $#SERVER_NAME 2){
SERVER_PORT=$SERVER_NAME(2)
SERVER_NAME=$SERVER_NAME(1)
}
+switch($SERVER_NAME){
+ case */* ..
+ error 400
+ exit
+}
if(~ $REQUEST_METHOD (PUT POST)){
if(! ~ $"CONTENT_LENGTH '')
trim_input | exec $rc_httpd_dir/select-handler
diff --git a/bin/werc.rc b/bin/werc.rc
index 0d006a3..101834e 100755
--- a/bin/werc.rc
+++ b/bin/werc.rc
@@ -12,7 +12,7 @@ difs=$ifs # Used to restore default ifs when needed
# Expected input: ls -F style, $sitedir/path/to/files/
#
dirfilter='s/\*$//; s,/+\./+,/,g; s,^\./,,; /\/[._][^\/]/d; /'$forbidden_uri_chars'/d; /\/sitemap\.xml$/d; /\/index\.(md|html|txt|tpl)$/d; /\/(robots|sitemap)\.txt$/d; /_werc\/?$/d; '
-dirclean=' s/\.(md|html|txt)$//; '
+dirclean=' s/\.(gmi|gem|md|html|txt)$//; '
# Careful, the proper p9p path might not be set until initrc.local is sourced
path=(. /bin ./bin)
diff --git a/bin/werclib.rc b/bin/werclib.rc
index bcebf91..0e095fc 100755
--- a/bin/werclib.rc
+++ b/bin/werclib.rc
@@ -97,6 +97,10 @@ fn get_md_title {
sed -n -e '1N; /^.*\n===*$/N; /.*\n===*\n *$/!b' -e 's/\n==*\n//p' < $1
}
+fn get_gmi_title {
+ sed -e 's/^# //;q' < $1
+}
+
fn get_html_title {
t=`{sed -n '32q; s/^.*<[Tt][Ii][Tt][Ll][Ee]> *([^<]+) *(<\/[Tt][Ii][Tt][Ll][Ee]>.*)?$/\1/p' < $1}
@@ -110,6 +114,10 @@ fn get_html_title {
fn get_file_title {
if (~ $1 *.md)
get_md_title $1
+ if not if(~ $1 *.gmi)
+ get_gmi_title $1
+ if not if(~ $1 *.gem)
+ get_gmi_title $1
if not if(~ $1 *.html)
get_html_title $1
if not if(~ $1 */) {
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
+-----------
+
+
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
+-----------
+
+
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=`{
+The latest dev code is available in the werc git repo: `git://shithub.us/sl/werc`
Version Numbering and Branching Rules
@@ -11,7 +11,7 @@ There is no such thing! Originally a convention similar to that of the Linux ker
For radical or experimental changes the `werc-dev` branch might be used, but at the moment it is outdated.
-Bug reports, feature requests, bug fixes and other patches are all very welcome, just send them to the [werc mailing list](http://lists.9front.org).
+Bug reports, feature requests, bug fixes and other patches are all very welcome, just send them to the [werc mailing list](http://lists.cat-v.org).
See Also
diff --git a/sites/werc.cat-v.org/index.md b/sites/werc.cat-v.org/index.md
index 0fa90f5..3d2ba76 100644
--- a/sites/werc.cat-v.org/index.md
+++ b/sites/werc.cat-v.org/index.md
@@ -65,7 +65,7 @@ the werc mailing list. To join, send a message with a body consisting only of th
To track commit messages, you can join the werc-commits mailing list. To join, send a message with a body consisting only of the word _subscribe_ to werc-commits-owner@cat-v.org.
-On irc, join [#cat-v](irc://irc.freenode.org/cat-v) on irc.freenode.org
+On irc, join [#cat-v](irc://irc.oftc.org/cat-v) on irc.oftc.org
License