shithub: riscv

Download patch

ref: 8347075fd940894edcc27e36cb3a21d368c4e606
parent: 5d3d085492010ab1f4900892e000a3c175bcac90
author: stanley lieber <stanley.lieber@gmail.com>
date: Tue Apr 1 10:34:29 EDT 2014

add newt(1): nntp client for use with nntpfs(4)

--- /dev/null
+++ b/rc/bin/newt
@@ -1,0 +1,246 @@
+#!/bin/rc
+# bloated, featureful usenet reader for use with nntpfs
+rfork en
+ramfs
+argv0=$0
+if(~ $#editor 0)
+	editor=hold
+group=alt/test
+maxposts=30
+mnt=/mnt/news
+if(~ $#newtname 0)
+	newtname=newt@dont-email.me
+fn enterpost{
+	{
+		echo From: $"newtname
+		echo Newsgroups: `{echo $group | sed 's/\//\./g'}
+		echo Subject: $"subject
+		echo
+	} >/tmp/post
+	eval $editor /tmp/post
+	cat /tmp/post >$mnt/$group/post
+}
+fn f { du -a $* | sed 's/^.*	//g' }
+fn fmtd{
+	date=`{cat}
+	if(! ~ $date(1) [0-9]*)
+		date=`{nshift $date}
+	da=$date(1)
+	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
+	}
+	if(! ~ $date(3) `{date | awk '{print $6;}'})
+		ti=$date(3)
+	if not
+		ti=`{echo $date(4) | awk '{print substr($0,0,5);}'}
+	echo $mo/$da $ti
+}
+fn geth{
+	for(i in $*){
+		from=`{awk -F '	' '{print $3;}' $i/xover}
+		if(! ~ $#from 0 && ! ~ $#from 1){
+			nfrom=`{
+				for(i in $from){
+					if(~ $i *@*)
+						echo $i | sed 's/(<|>)//g'
+				}
+			}
+			if(! ~ $#nfrom 0)
+				from=$nfrom
+		}
+		if(! ~ $#from 0){
+			date=`{awk -F '	' '{print $4;}' $i/xover >[2]/dev/null | fmtd}
+			awk -v date'='$"date -v from'='$from(1) -F '	' \
+				'{print " " $1 "	" date " " from "		" substr($2,0,50);}' $i/xover >[2]/dev/null
+		}
+		if not
+			echo ' '$"i'	nil	nil	nil'
+	}
+}
+fn getposts{ ls | grep -e '^[0-9]+$' | sort -n | tail -$maxposts }
+fn k{
+	kmnt=`{echo $mnt | sed 's/\//\\\//g'}
+	f $mnt/$* |
+		grep -v -e '\/([0-9]+(\/|$)|post$)' |
+		sed 's/^'$"kmnt'\// g	/g' |
+		sort
+}
+fn nshift{ shift; echo $* }
+fn printhelp{
+echo '[0-9]+	print specified message
+b		back
+e		enter message
+f		jump to first message
+g ...		go to specified group
+h		print message headlines
+help		print this help message
+k ...		list sub-groups under specified group
+l		jump to last message
+n		next
+p		print message with minimal headers
+P		print message with full headers
+q		quit
+r		reply to message
+y		synchronize message list with server
+"		print message in quoted form, suitable for reply
+|cmd		pipe message body to a command
+||cmd		pipe raw message to a command
+?		print debug information'
+}
+fn printp{
+	if(test -d $mnt/$group/$1){
+		grep -e '(^From|^Newsgroups|^Subject|^Date)' $1/header
+		echo
+		cat $1/body
+	}
+	echo
+	prompt=$group/$1
+}
+fn printpp{
+	if(test -d $mnt/$group/$1){
+		cat $1/article
+	}
+	echo
+	prompt=$group/$1
+}
+fn usage{
+	echo usage: $argv0 '[ -f newsgroup ] [ -m mountpoint ] [ -p maxposts ]' >[1=2]
+	exit usage
+}
+while(~ $1 -*){
+	switch($1){
+	case -f
+		group=`{echo $2 | sed 's/\./\//g'}
+		shift
+	case -m
+		mnt=$2
+		shift
+	case -p
+		maxposts=$2
+		shift
+	case *
+		usage
+	}
+	shift
+}
+if(! ~ $#* 0)
+	usage
+prompt=$group
+if(! test -d $mnt/$group){
+	echo !$mnt/$group does not exist >[1=2]
+	exit
+}
+builtin cd $mnt/$group
+go=()
+posts=`{getposts}
+geth $posts >/tmp/h
+post=$posts(1)
+echo $#posts messages
+while(){
+	echo -n $"prompt': '
+	cmd=`{read}
+	switch($cmd){
+	case [0-9]*
+		post=$cmd(1)
+		printp $post
+	case b
+		if(! ~ $post $posts(1)){
+			post=`{echo $post^-1 | bc}
+			printp $post
+		}
+	case e
+		enterpost
+	case f
+		post=$posts(1)
+		printp $post
+	case g' '*
+		ngroup=`{nshift $cmd | sed 's/\./\//g'}
+		if(test -d $mnt/$ngroup){
+			if(grep -s -e '^[0-9]+$' <{ls -p $mnt/$ngroup}){
+				group=$ngroup
+				builtin cd $mnt/$group
+				go=()
+				posts=`{getposts}
+				geth $posts >/tmp/h
+				post=$posts(1)
+				prompt=$group
+				echo $#posts messages
+			}
+			if not
+				echo !$ngroup contains no messages
+		}
+		if not
+			echo !$ngroup does not exist
+	case h
+		cat /tmp/h
+	case help
+		printhelp
+	case k
+		k $group
+	case k' '*
+		k `{nshift $cmd | sed 's/\./\//g'}
+	case l
+		post=$posts($#posts)
+		printp $post
+	case p
+		printp $post
+	case p' '*
+		post=`{nshift $cmd}
+		printp $post
+	case P
+		printpp $post
+	case P' '*
+		post=`{nshift $cmd}
+		printpp $post
+	case q
+		exit
+	case r
+		if(test -f $mnt/$group/$post/header){
+			subject='Re: '^`{grep -e '^Subject: ' $mnt/$group/$post/header | sed 's/^Subject: //g'}
+			enterpost
+		}
+		if not
+			echo !message missing
+	case y
+		posts=`{getposts}
+		geth $posts >/tmp/h
+		echo $#posts messages
+	case '"'
+		printp $post | sed 1d | sed 's/^/> /g' | sed 's/^> >/>>/g'
+	case '||'*
+		cmd=`{echo $"cmd | sed 's/^\|\|//g'}
+		cat $mnt/$group/$post/article | eval $cmd
+	case '|'*
+		cmd=`{echo $"cmd | sed 's/^\|//g'}
+		cat $mnt/$group/$post/body | eval $cmd
+	case '?'
+		echo mnt: $mnt
+		echo group: $group
+		echo maxposts: $maxposts
+		echo posts: $posts
+		echo post: $post	
+	case n *
+		if(~ $post $posts(1) && ~ $#go 0){
+			go=1
+			printp $post
+		}
+		if not if(! ~ $post $posts($#posts)){
+			go=1
+			post=`{echo $post^+1 | bc}
+			if(test $post -gt $posts($#posts))
+				post=$posts($#posts)
+			printp $post
+		}
+	}	
+}
--- /dev/null
+++ b/sys/man/1/newt
@@ -1,0 +1,132 @@
+.TH NEWT 1
+.SH NAME
+newt \- network news transport protocol (NNTP) client
+.SH SYNOPSIS
+.B newt
+[
+.B -f
+.I newsgroup
+] [
+.B -m
+.I mountpoint
+] [
+.B -p
+.I maxposts
+]
+.SH DESCRIPTION
+.I Newt
+provides an interactive, text-based interface to NNTP
+articles served by
+.IR nntpfs (4) .
+.PP
+There are a number of options:
+.TP
+.B  -f
+Load the specified newsgroup. Default is
+.B alt.test.
+.TP
+.B  -m
+Directory where
+.I nntpfs
+is mounted. Default is
+.B /mnt/news.
+.TP
+.B -p
+Number of posts to display, up to and including the most recent post.
+.PP
+.I Newt
+starts by reading the list of messages in the
+.I newsgroup,
+printing out the number of messages, and then prompting for commands
+from standard input. The prompt itself presents the name of the group
+and the message number in the form of a file system path relative to the
+.I mountpoint.
+.PP
+The commands are:
+.PP
+.TP
+.I number
+Print message
+.I number.
+.TP
+.B b
+Print the previous message.
+.TP
+.B e
+Enter a new message, honoring the environment variable
+.I editor.
+Default is
+.IR hold (1) .
+.TP
+.B f
+Jump to the first message in the group.
+.TP
+.BI g " newsgroup
+Change to the specified
+.I newsgroup.
+The name of a group may be provided in dotted
+(\fIalt.test\fR) or path (\fIalt/test\fR) format.
+.TP
+.B h
+Print the disposition, date, sender and subject line
+of all messages in the group. These lines are suitable
+for selecting and sending to the prompt, in order to
+print messages either singly or in aggregate.
+.TP
+.B help
+Print a summary of the available commands.
+.TP
+.BI k " [newsgroup]
+Without an argument,
+.I k
+walks the directories under the current group
+and prints commands suitable for changing to each
+available sub-group. When provided with an argument,
+it instead walks the directories under the group specified
+by the argument.
+.TP
+.B l
+Jump to the last message in the group.
+.TP
+.B n, or enter key
+Print the next message.
+.TP
+.B p
+Print the current message with minimal headers.
+.TP
+.B P
+Print the raw message with full headers.
+.TP
+.B q
+Quit.
+.TP
+.B r
+Reply to the current message.
+.TP
+.B y
+Synchronize message list with the server.
+.TP
+.BI | command
+Run the
+.I command
+with the message body as standard input.
+.TP
+.BI || command
+Run the
+.I command
+with the whole message as standard input.
+.TP
+\fB"\fP
+Print the current message in quoted form, suitable for reply.
+.SH SOURCE
+.B /rc/bin/newt
+.SH "SEE ALSO"
+.IR nntpfs (4)
+.SH BUGS
+The list of available newsgroups offered by a given server
+may run to many megabytes in size. This complicates
+walking the list over a slow Internet connection, and renders
+searching all but infeasible.
+.SH HISTORY
+.I Newt
+first appeared in 9front (April, 2014).