[comp.lang.icon] post.icn

ron@mlfarm.com (Ronald Florence) (01/09/91)

It won't put gnus-post or Pnews out of business, but it works, both
for original postings and follow-ups.  The code borrows from Richard
Goerwitz's tempname generator and from reply.icn.  The limited ms-dos
support is untested.  Perhaps someone can suggest how to include
support for VMS or other systems in this and reply.icn.

I hope this is useful to someone.
--

Ronald Florence			ron@mlfarm.com


#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	post.icn
# This archive created: Wed Jan  9 10:26:12 1991
# By:	Ronald Florence (Maple Lawn Farm, Stonington, CT)
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'post.icn'
then
	echo shar: "will not over-write existing file 'post.icn'"
else
cat << \SHAR_EOF > 'post.icn'
############################################################################
#
#	Name:	post.icn
#
#	Title:	News Poster
#
#	Author:	Ronald Florence  (ron@mlfarm.com)
#
#	Date:	January 8, 1991
#
############################################################################
#
#  This program posts a news article to Usenet via uux or mail.  
#  Given an optional argument (the name of a file containing a
#  news article), it creates a follow-up article, with an 
#  attribution and quoted text.
#
#      usage: post [news-article]
#
############################################################################
#
#  Configure: smarthost, mode, editor or EDITOR environment variable.
#
############################################################################
#
#  Requires: UNIX or MS-DOS.  
#  Bugs: ms-dos requires hard-coded system info.
#
############################################################################

global sitename, domain, tz

procedure main(arg)
  
  smarthost := "news-feed"	# Your news feed.
  mode := "uux"			# Use "mail" for a sendnews feed.
  domain := ".UUCP"

  if (find("UNIX", &features) & find("pipes", &features)) then {
    console := "/dev/tty"
    tmpdir := "/tmp/"
    (inf := open("logname", "pr")) & (logname := !inf) & close(inf)
				# Uuname sometimes pads with spaces.
    (inf := open("uuname -l", "pr")) & (sitename := trim(!inf)) & close(inf)
    (tz := getenv("TZ")) & tz ?:= (tab(many(&letters)), tab(upto(&letters)))
    sigfile := getenv("HOME") || "/.signature"
    editor := "/bin/vi"
  }
  else if find("MS-DOS", &features) then {
    console := "CON"
    tmpdir := ""
    logname := &null
    sitename := &null
    tz := &null			# Hours off GMT.
    sigfile := &null
    editor := "edlin"
  }
  (\logname & \sitename & \tz) | stop("post: missing system info")
  article := open(tmpfile := tempname(tmpdir), "w") | 
    stop("post: cannot write temp file")
  write(article, "Path: ", sitename, "!", logname)
  write(article, "From: ", logname, "@", sitename, domain)

  if \arg[1] then {
    inf := open(arg[1]) | {
      remove(tmpfile)
      stop("post: cannot read ", arg[1])
    }
    reply_headers(inf, article)
    every write(article, " > ", !inf)
    close(inf)
  }
  else {
    write(article, query("Newsgroups: "))
    write(article, query("Subject: "))
    every write(article, req_headers())
    write(article, "\n")
  }
  edstr := (getenv("EDITOR") | editor) || " " || tmpfile || " < " || console
  system(edstr)
  writes("Are you sure you want to post this to Usenet y/n? ")
  stdin := open(console)
  upto('nN', read(stdin)) & {
    remove(tmpfile)
    stop("Article aborted.")
  }
				# Try to append the .signature.
  \sigfile & (inf := open(sigfile)) & {
    article := open(tmpfile, "a")
    write(article, "--")
    every write(article, !inf)
    close(inf)
  }
				# Don't force an immediate poll.
  if find("uux", mode) then mode ||:= " - -r"
				# Sendnews format requires an initial `N'.
  else if find("mail", mode) then {
    inf := open(tmpfile)
    outf := open(tmp2 := tempname(tmpdir), "w")
    every write(outf, "N", !inf)
    remove(tmpfile)
    rename(tmp2, tmpfile)
  }
  mode ||:= " " || smarthost || "!rnews < " || tmpfile
  (system(mode) = 0) & write("Article posted!")
  remove(tmpfile)
end


procedure tempname(dir)
	
  every temp_name := dir || "article." || right(1 to 999,3,"0") do {
    close(open(temp_name)) & next
    suspend \temp_name
  }
end


procedure reply_headers(infile, art)

  every s := !infile do s ? {
				# Case-insensitive matches for headers.
    tab(match("from: ", map(&subject))) & {
      if find("<") then {
	fullname := trim(tab(upto('<')))
	address := (move(1), tab(find(">")))
      }
      else {
	address := trim(tab(upto('(') | 0))
	fullname := (move(1), tab(find(")")))
      }
      quoter := (\fullname | address)
    }
    tab(match("date: ", map(&subject))) & date := tab(0)
    tab(match("message-id: ", map(&subject))) & id := tab(0)
    match("subject: ", map(&subject)) & subject := s
    match("newsgroups: ", map(&subject)) & newsgroup := tab(upto(',') | 0)
    match("references: ", map(&subject)) & refs := s
    (\quoter & *s = 0) & {
				# Newsgroup and subject are required.
      write(art, \newsgroup | query("Newsgroup: "))
      write(art, \subject | query("Subject: "))
				# Message-ID and Date go here.
      every write(art, req_headers())
				# Threaded readers need References.
      write(art, \refs | "References:", " ", id)
      write(art, "In-reply-to: ", quoter, "'s message of ", date)
      write(art, "\nIn ", id, ", ", quoter, " writes:\n")
      return 
    }
  }
end


procedure req_headers()
				# Crude, but it's a unique id.
  uniq := "<"
  &date || &clock ? while tab(upto(&digits)) do uniq ||:= tab(many(&digits))
  uniq ||:= "@" || sitename || domain || ">"
				# Date in RFC 822 format.
  &dateline ? {
    month := left((tab(find(" ")+1), tab(many(&letters))), 3) || " "
    date := (tab(upto(&digits)), tab(many(&digits))) || " " || month
    date ||:= (tab(upto(&digits)), right(tab(many(&digits)), 2))
  }
				# GMT would be better; this is allowed.
  if (tz > 0) then zone := " -"
  else zone := " +"
  zone ||:= left(right(abs(tz), 2, "0"), 4, "0")
  suspend "Message-ID: " || uniq
  suspend "Date: " || date || " " || &clock || zone
end


procedure query(prompt)

  writes(prompt)
  ans := read()
  return prompt || ans
end

SHAR_EOF
if test 5403 -ne "`wc -c < 'post.icn'`"
then
	echo shar: "error transmitting 'post.icn'" '(should have been 5403 characters)'
fi
fi
exit 0
#	End of shell archive

--

Ronald Florence			ron@mlfarm.com

ron@mlfarm.com (Ronald Florence) (01/12/91)

This patch will add (Full Name) to the From line of outgoing postings
from post.icn.  Most of the changes are added lines, so if you don't
have `patch' it shouldn't be too onerous to do manually.

If your passwd file keeps full names between a "-" and a "(", try
setting "unixtype" to "usg".  Use "bsd" for Xenix, V7 or other passwd
files which have the full name the first item after the colon in the
field.  The ms-dos support relies on a hard-coded full name (ugh!).  


*** post.icn~	Tue Jan  8 19:57:00 1991
--- post.icn	Thu Jan 10 23:15:24 1991
***************
*** 19,25 ****
  #
  ############################################################################
  #
! #  Configure: smarthost, mode, editor or EDITOR environment variable.
  #
  ############################################################################
  #
--- 19,25 ----
  #
  ############################################################################
  #
! #  Configure: smarthost, mode, unixtype, editor or EDITOR env. variable.
  #
  ############################################################################
  #
***************
*** 34,39 ****
--- 34,40 ----
    
    smarthost := "news-feed"	# Your news feed.
    mode := "uux"			# Use "mail" for a sendnews feed.
+   unixtype := "bsd"		# Use "usg" for "-Full Name(" passwd file.
    domain := ".UUCP"
  
    if (find("UNIX", &features) & find("pipes", &features)) then {
***************
*** 43,48 ****
--- 44,57 ----
  				# Uuname sometimes pads with spaces.
      (inf := open("uuname -l", "pr")) & (sitename := trim(!inf)) & close(inf)
      (tz := getenv("TZ")) & tz ?:= (tab(many(&letters)), tab(upto(&letters)))
+     \logname & (inf := open("/etc/passwd")) & every s := !inf do s ? {
+       =(logname) & {
+ 	every tab(upto(':')+1) \4 
+ 	if find("bsd", unixtype) then fullname := tab(upto(':'))
+ 	else fullname := (tab(upto('-')+1), tab(upto('(')))
+ 	break
+       }	
+     }
      sigfile := getenv("HOME") || "/.signature"
      editor := "/bin/vi"
    }
***************
*** 52,57 ****
--- 61,67 ----
      logname := &null
      sitename := &null
      tz := &null			# Hours off GMT.
+     fullname := &null
      sigfile := &null
      editor := "edlin"
    }
***************
*** 59,65 ****
    article := open(tmpfile := tempname(tmpdir), "w") | 
      stop("post: cannot write temp file")
    write(article, "Path: ", sitename, "!", logname)
!   write(article, "From: ", logname, "@", sitename, domain)
  
    if \arg[1] then {
      inf := open(arg[1]) | {
--- 69,77 ----
    article := open(tmpfile := tempname(tmpdir), "w") | 
      stop("post: cannot write temp file")
    write(article, "Path: ", sitename, "!", logname)
!   writes(article, "From: ", logname, "@", sitename, domain)
!   \fullname & writes(article, " (", fullname, ")")
!   write(article)
  
    if \arg[1] then {
      inf := open(arg[1]) | {
--

Ronald Florence			ron@mlfarm.com