[net.sources] rn version 4.1, part 1 of 8

lwall@sdcrdcf.UUCP (Larry Wall) (10/03/84)

#! /bin/sh

# Make a new directory for the rn sources, cd to it, and run kits 1 thru 8 
# through sh.  When all 8 kits have been run, read README.

echo "This is rn kit 1 (of 8).  If kit 1 is complete, the line"
echo '"'"End of kit 1 (of 8)"'" will echo at the end.'
echo ""
export PATH || (echo "You didn't use sh, you clunch." ; kill $$)
echo Extracting rn.man
cat >rn.man <<'!STUFFY!FUNK!'
''' $Header: rn.man,v 4.1 84/09/24 12:07:50 lwall Exp $
''' 
''' $Log:	rn.man,v $
''' Revision 4.1  84/09/24  12:07:50  lwall
''' Real baseline.
''' 
''' Revision 4.0.1.1  84/09/19  10:52:04  lwall
''' Additional warnings and "bugs".
''' 
''' Revision 4.0  84/09/04  09:52:24  lwall
''' Baseline for netwide release
''' 
''' 
.de Sh
.br
.ne 5
.PP
\fB\\$1\fR
.PP
..
.de Sp
.if t .sp .5v
.if n .sp
..
.de Ip
.br
.ie \\n.$>=3 .ne \\$3
.el .ne 3
.IP "\\$1" \\$2
..
'''
'''     Set up \*(-- to give an unbreakable dash;
'''     string Tr holds user defined translation string.
'''     Bell System Logo is used as a dummy character.
'''
.tr \(bs-|\(bv\*(Tr
.ie n \{\
.ds -- \(bs-
.if (\n(.H=4u)&(1m=24u) .ds -- \(bs\h'-12u'\(bs\h'-12u'-\" diablo 10 pitch
.if (\n(.H=4u)&(1m=20u) .ds -- \(bs\h'-12u'\(bs\h'-8u'-\" diablo 12 pitch
.ds L" "
.ds R" "
.ds L' '
.ds R' '
'br\}
.el\{\
.ds -- \(em\|
.tr \*(Tr
.ds L" ``
.ds R" ''
.ds L' `
.ds R' '
'br\}
.TH RN 1 LOCAL
.SH NAME
rn - new read news program
.SH SYNOPSIS
.B rn [options] [newsgroups]
.SH DESCRIPTION
.I Rn
is a replacement for the readnews(1) program that was written to be as
efficient as possible, particularly in human interaction.
.I Rn
attempts to minimize the amount of \*(L"dead\*(R" time spent reading
news\*(--it tries to get things done while the user is reading or deciding
whether to read, and attempts to get useful information onto the screen as
soon as possible, highlighting spots that the eye makes frequent reference
to, like subjects and previously read lines.
Whether or not it's faster, it SEEMS faster.
.PP
If no newsgroups are specified, all the newsgroups which have unread news
are displayed, and then the user is asked for each one whether he wants to
read it, in the order in which the newsgroups occur in the
.I .newsrc
file.
With a list of newsgroups,
.I rn
will start up in \*(L"add\*(R" mode, using the list as a set of patterns to
add new newsgroups and restrict which newsgroups are displayed.
See the discussion of the \*(L'a\*(R' command on the newsgroup selection
level.
.PP
.I Rn
operates on three levels: the newsgroup selection level, the article
selection level, and the paging level.
Each level has its own set of commands, and its own help menu.
At the paging level (the bottom level),
.I rn
behaves much like the
.IR more (1)
program.
At the article selection level, you may specify which article you want
next, or read them in the default order, which is either in order of
arrival on your system, or by subject threads.
At the newsgroup selection level (the top level), you may specify which
newsgroup you want next, or read them in the default order, which is the
order that the newsgroups occur in your
.I .newsrc
file.
(You will therefore want to rearrange your
.I .newsrc
file to put the most interesting newsgroups first.
This can be done with the \*(L'm\*(R' command on the Newsgroup Selection level.
WARNING: invoking readnews/vnews (the old user interface) in any way (including
as a news checker in your login sequence!) will cause your
.I .newsrc
to be disarranged again.)
.PP
On any level, at ANY prompt, an \*(L'h\*(R' may be typed for a list of
available commands.
This is probably the most important command to remember, so don't you
forget it.
Typing space to any question means to do the normal thing.
You will know what that is because
every prompt has a list of several plausible commands enclosed in
square brackets.
The first command in the list is the one which will be done if you type
a space.
(All input is done in cbreak mode, so carriage returns should not be typed
to terminate anything except certain multi-character commands.
Those commands will be obvious in the discussion below because they take an
argument.)
.PP
Upon startup,
.I rn
will do several things:
.Ip 1. 4
It will look for your
.I .newsrc
file, which is your list of subscribed-to
newsgroups.
If
.I rn
doesn't find a
.IR .newsrc ,
it will create one.
If it does find one, it will back it up under the name \*(L".oldnewsrc\*(R".
.Ip 2. 4
It will input your
.I .newsrc
file, listing out the first several newsgroups
with unread news.
.Ip 3. 4
It will perform certain consistency checks on your
.IR .newsrc .
If your
.I .newsrc
is out of date in any of several ways,
.I rn
will warn you and patch it up for you, but you may have to wait a little
longer for it to start up.
.Ip 4. 4
.I Rn
will next check to see if any new newsgroups have been created, and give
you the opportunity to add them to your
.IR .newsrc .
.Ip 5. 4
.I Rn
goes into the top prompt level\*(--the newsgroup selection level.
.Sh "Newsgroup Selection Level"
In this section the words \*(L"next\*(R" and \*(L"previous\*(R" refer to
the ordering of the newsgroups in your
.I .newsrc
file.
On the newsgroup selection level, the prompt looks like this:
.Sp
******** 17 unread articles in net.blurfl\*(--read now? [ynq]
.Sp
and the following commands may be given at this level:
.Ip y,SP 8
Do this newsgroup now.
.Ip .command 8
Do this newsgroup now, but execute
.I command
before displaying anything.
The command will be interpreted as if given on the article selection level.
.Ip = 8
Do this newsgroup now, but list subjects before displaying articles.
.Ip n 8
Go to the next newsgroup with unread news.
.Ip N 8
Go to the next newsgroup.
.Ip p 8
Go to the previous newsgroup with unread news.
If there is none, stay at the current newsgroup.
.Ip P 8
Go to the previous newsgroup.
.Ip \- 8
Go to the previously displayed newsgroup (regardless of whether it is
before or after the current one in the list).
.Ip 1 8
Go to the first newsgroup.
.Ip ^ 8
Go to the first newsgroup with unread news.
.Ip $ 8
Go to the end of the newsgroups list.
.Ip "g newsgroup" 8
Go to
.IR newsgroup .
If it isn't currently subscribed to, you will be asked if you want to
subscribe.
.Ip "/pattern" 8
Scan forward for a newsgroup matching
.IR pattern .
Patterns do globbing like filenames, i.e., use ? to match a single
character, * to match any sequence of characters, and [] to specify a list
of characters to match.
(\*(L"all\*(R" may be used as a synonym for \*(L"*\*(R".)
Unlike normal filename globbing, newsgroup searching is not anchored to
the front and back of the filename, i.e. \*(L"/jok\*(R" will find
net.jokes.
You may use ^ or $ to anchor the front or back of the search:
\*(L"/^test$\*(R" will find newsgroup test and nothing else
If you want to include newsgroups with 0 unread articles, append /r.
If the newsgroup is not found between the current newsgroup and the last
newsgroup, the search will wrap around to the beginning.
.Ip "?pattern" 8
Same as /, but search backwards.
.Ip u 8
Unsubscribe from current newsgroup.
.Ip "l string" 8
List newsgroups not subscribed to which contain the string specified.
.Ip L 8 13v
Lists the current state of the
.IR .newsrc ,
along with status information.
.Sp
.nf
    \h'|0.5i'Status    \h'|2i'Meaning
    \h'|0.5i'<number>  \h'|2i'Count of unread articles in newsgroup.
    \h'|0.5i'READ      \h'|2i'No unread articles in newsgroup.
    \h'|0.5i'UNSUB     \h'|2i'Unsubscribed newsgroup.
    \h'|0.5i'BOGUS     \h'|2i'Bogus newsgroup.
    \h'|0.5i'JUNK      \h'|2i'Ignored line in .newsrc
\h'|2i'(e.g. readnews \*(L"options\*(R" line).
.fi
.Sp
(A bogus newsgroup is one that is not in the list of active newsgroups
in the active file, which on most systems is /usr/lib/news/active.)
.Ip "m name" 8
Move the named newsgroup somewhere else in the
.IR .newsrc .
If no name is given, the current newsgroup is moved.
There are a number of ways to specify where you want the newsgroup\*(--type
h for help when it asks where you want to put it.
.Ip c 8
Catch up\*(--mark all unread articles in this newsgroup as read.
.Ip "o pattern" 8
Only display those newsgroups whose name matches
.IR pattern .
Patterns are the same as for the \*(L'/\*(R' command.
Multiple patterns may be separated by spaces, just as on the
command line.
The restriction will remain in effect either until there are no articles
left in the restricted set of newsgroups, or another restriction command
is given.
Since
.I pattern
is optional, \*(L'o\*(R' by itself will remove the
restriction.
.Ip "a pattern" 8
Add new newsgroups matching
.IR pattern .
Newsgroups which are already in your
.I .newsrc
file, whether subscribed to or
not, will not be listed.
If any new newsgroups are found, you will be asked for each one whether
you would like to add it.
After any new newsgroups have been added, the \*(L'a\*(R' command also
restricts the current set of newsgroups just like the \*(L'o\*(R' command
does.
.Ip & 8
Print out the current status of command line switches and any newsgroup
restrictions.
.Ip "&switch {switch}" 8
Set additional command line switches.
.Ip !command 8
Escape to a subshell.
One exclamation mark (!) leaves you in your own news directory.
A double exclamation mark (!!) leaves you in the spool
directory for news, which on most systems is /usr/spool/news.
The environment variable SHELL will be used if defined.
If
.I command
is null, an interactive shell is started.
.Ip q 8
Quit.
.Ip ^K 8
Edit the global KILL file.
This is a file which contains /pattern/j commands (one per line) to be
applied to every newsgroup as it is started up, that is, when it is
selected on the newsgroup selection level.
The purpose of a KILL file is to mark articles as read on the basis of some
set of patterns.
This saves considerable wear and tear on your \*(L'n\*(R' key.
There is also a local KILL file for each newsgroup.
Because of the overhead involved in searching for articles to kill, it is
better if possible to use a local KILL file.
Local KILL files are edited with a \*(L'^K\*(R' on the article selection level.
There are also automatic ways of adding search commands to the local KILL
file\*(--see the \*(L'K\*(R' command and the K search modifier on the
article selection level.
.Sp
If either of the environment variables VISUAL or EDITOR is set, the
specified editor will be invoked; otherwise a default editor (normally vi(1))
is invoked on the KILL file.
.Sh "Article Selection Level"
On the article selection level,
.I rn
selects (by default) unread articles in numerical order (the order in which
articles have arrived at your site).
If you do a subject search (^N), the default order is modified to be
numerical order within each subject thread.
You may switch back and forth between numerical order and subject thread
order at will.
The
.B \-S
switch can be used to make subject search mode the default.
.Sp
On the article selection level you are
.I not
asked whether you want to read an article before the article is displayed;
rather,
.I rn
simply displays the first page (or portion of a page, at low baud rates) of the
article and asks if you want to continue.
The normal article selection prompt comes at the END of the article
(though article selection commands can be given from within the middle
of the article (the pager level) also).
The prompt at the end of an article looks like this:
.Sp 
End of article 248 (of 257)\*(--what next? [npq]
.Sp
The following are the options at this point:
.Ip n,SP 8
Scan forward for next unread article.
(Note: the \*(L'n\*(R' (next) command when typed at the end of an article
does not mark the article as read, since an article is automaticaly marked
as read after the last line of it is printed.
It is therefore possible to type a sequence such as \*(L'mn\*(R' and leave
the article marked as unread.
The fact that an article is marked as read by typing \*(L'n\*(R',
\&\*(L'N\*(R', \*(L'^N\*(R', \*(L's\*(R', or \*(L'S\*(R' within the MIDDLE of
the article is in fact a special case.)
.Ip N 8
Go to the next article.
.Ip ^N 8
Scan forward for the next article with the same subject, and make ^N default
(subject search mode).
.Ip p 8
Scan backward for previous unread article.
If there is none, stay at the current article.
.Ip P 8
Go to the previous article.
.Ip \- 8
Go to the previously displayed article (regardless of whether that article
is before or after this article in the normal sequence).
.Ip ^P 8
Scan backward for the previous article with the same subject, and make
^N default (subject search mode).
.Ip ^R 8
Restart the current article.
.Ip ^L 8
Refresh the screen.
.Ip ^X 8
Restart the current article, and decrypt as a rot13 message.
.Ip X 8
Refresh the screen, and decrypt as a rot13 message.
.Ip b 8
Back up one page.
.Ip q 8
Quit this newsgroup and go back to the newsgroup selection level.
.Ip ^ 8
Go to the first unread article.
.Ip $ 8
Go to the last article (actually, one past the last article).
.Ip "number" 8
Go to the numbered article.
.Ip "range{,range} command{:command}" 8
Apply a set of commands to a set of articles.
A range consists of either <article number> or
<article\ number>\-<article\ number>.
A dot \*(L'.\*(R' represents the current article, and a dollar
sign \*(L'$\*(R' represents the last article.
.Sp
Applicable commands include \*(L'm\*(R' (mark as unread), \*(L'M\*(R'
(delayed mark as unread), \*(L'j\*(R' (mark as read), \*(L"s dest\*(R"
(save to a destination), \*(L"!command\*(R" (shell escape), \*(L"=\*(R"
(print the subject) and \*(L"C\*(R" (cancel).
.Ip j 8
Junk the current article\*(--mark it as read.
If this command is used from within an article, you are left at the end of
the article, unlike \*(L'n\*(R', which looks for the next article.
.Ip m 8
Mark the current article as still unread.
(If you are in subject search mode you probably want to use M instead of m.
Otherwise the current article may be selected as the beginning of the next
subject thread.)
.Ip M 8
Mark the current article as still unread, but not until the newsgroup
is exited.
Until then, the current article will be marked as read.
This is useful for returning to an article in another session, or in another
newsgroup.
.Ip /pattern 8
Scan forward for article containing
.I pattern
in the subject.
See the section on Regular Expressions.
Together with the escape substitution facility described later, it becomes
easy to search for various attributes of the current article, such as
subject, article ID, author name, etc.
The previous pattern can be recalled with \*(L"<esc>/\*(R".
If
.I pattern
is omitted, the previous pattern is assumed.
.Ip /pattern/h 8
Scan forward for article containing
.I pattern
in the header.
.Ip /pattern/a 8
Scan forward for article containing
.I pattern
anywhere in article.
.Ip /pattern/r 8
Scan read articles also.
.Ip /pattern/c 8
Make search case sensitive.
Ordinarily upper and lower case are considered the same.
.Ip "/pattern/modifiers:command{:command}" 8
Apply the commands listed to articles matching the search command (possibly
with h, a, or r modifiers).
Applicable commands include \*(L'm\*(R' (mark as unread), \*(L'M\*(R'
(delayed mark as unread), \*(L'j\*(R' (mark as read), \*(L"s dest\*(R"
(save to a destination), \*(L"!command\*(R" (shell escape), \*(L"=\*(R"
(print the subject) and \*(L"C\*(R" (cancel).
If the first command is \*(L'm\*(R' or \*(L'M\*(R', modifier r is assumed.
A K may be included in the modifiers (not the commands) to cause the
entire command (sans K) to be saved to the local KILL file, where it will
be applied to every article that shows up in the newsgroup.
.Sp
For example, to save all articles in a given newsgroup to the line printer
and mark them read, use \*(L"/^/\||\|lpr:j\*(R".
If you say \*(L"/^/K\||\|lpr:j\*(R", this will happen every time you enter the
newsgroup.
.Ip ?pattern 8
Scan backward for article containing
.I pattern
in the subject.
May be modified as the forward search is: ?pattern?modifiers[:commands].
It is likely that you will want an r modifier when scanning backward.
.Ip k 8
Mark as read all articles with the same subject as the current article.
(Note: there is no single character command to temporarily mark as read (M
command) articles matching the current subject.
That can be done with \*(L"/<esc>s/M\*(R", however.)
.Ip K 8
Do the same as the k command, but also add a line to the local KILL file for
this newsgroup to kill this subject every time the newsgroup is started up.
For a discussion of KILL files, see the \*(L'^K\*(R' command below.
See also the K modifier on searches above.
.Ip ^K 8
Edit the local KILL file for this newsgroup.
Each line of the KILL file should be a command of the form /pattern/j.
(With the exception that
.I rn
will insert a line at the beginning of the form \*(L"THRU <number>\*(R",
which tells
.I rn
the maximum article number that the KILL file has been applied to.  You
may delete the THRU line to force a rescan of current articles.)
You may also have reason to use the m, h, or a modifiers.
Be careful with the M modifier in a kill file\*(--there are more efficient
ways to never read an article.
You might have reason to use it if a particular series of articles is posted
to multiple newsgroups.
In this case, M would force you to view the article in a different newsgroup.
.Sp
To see only newgroup articles in the control newsgroup, for instance, you
might put
.Sp
/^/j
.br
/newgroup/m
.Sp
which kills all subjects not containing \*(L"newgroup\*(R".
You can add lines automatically via the K command and K search modifiers,
but editing is the only way to remove lines.
If either of the environment variables VISUAL or EDITOR is set, the
specified editor will be invoked; otherwise a default editor (normally vi)
is invoked on the KILL file.
.Sp
The KILL file may also contain switch setting lines beginning with \*(L'&\*(R'.
Additionally, any line beginning with \*(L'X\*(R' is executed on exit
from the newsgroup rather than on entrance.
This can be used to set switches back to a default value.
.Ip r 8
Reply through net mail.
The environment variables MAILPOSTER and MAILHEADER may be used to modify
the mailing behavior of
.I rn
(see environment section).
.Ip R 8
Reply, including the current article in the header file generated.
(See \*(L'F\*(R' command below).
The YOUSAID environment variable controls the format of the attribution line.
.Ip f 8
Submit a followup article.
.Ip F 8
Submit a followup article, and include the old article, with lines prefixed
either by \*(L">\*(R" or by the argument to a
.B \-F
switch.
.I Rn
will attempt to provide an attribution line in front of the quoted article,
generated from the From: line of the article.
Unfortunately, the From: line doesn't always contain the right name; you
should double check it against the signature and change it if necessary,
or you may have to apologize for quoting the wrong person.
The environment variables NEWSPOSTER, NEWSHEADER and ATTRIBUTION may be
used to modify the posting behavior of
.I rn
(see environment section).
.Ip C 8
Cancel the current article, but only if you are the contributor or superuser.
.Ip c 8
Catch up in this newsgroup; i.e., mark all articles as read.
.Ip u 8
Unsubscribe to this newsgroup.
.Ip "s destination" 8
Save to a filename or pipe using sh.
If the first character of the destination is a vertical bar, the rest of
the command is considered a shell command to which the article is passed
through standard input.
The command is subject to filename expansion.
(See also the environment variable PIPESAVER.)
If the destination does not begin with a vertical bar, the rest of the
command is assumed to be a filename of some sort.
An initial tilde \*(L'~\*(R' will be translated to the name of the home
directory, and an initial environment variable substitution is also allowed.
If only a directory name is specified, the environment variable SAVENAME
is used to generate the actual name.
If only a filename is specified (i.e. no directory), the environment variable
SAVEDIR will be used to generate the actual directory.
If nothing is specified, then obviously both variables will be used.
Since the current directory for rn while doing a save command is your
private news directory, saying \*(L"s ./filename\*(R" will force the file
to your news directory.
Save commands are also run through % interpretation, so that you can
say \*(L"s %O/filename\*(R" to save to the directory you were in when you ran
.IR rn ,
and \*(L"s %t\*(R" to save to a filename consisting of the Internet address
of the sender.
.Sp
After generating the full pathname of the file to save to,
.I rn
determines if the file exists already, and if so, appends to it.
.I Rn
will attempt to determine if an existing file is a mailbox or a normal file,
and save the article in the same format.
If the output file does not yet exist,
.I rn
will by default ask you which format you want, or you can make it skip the
question with either the
.B \-M
or
.B \-N
switch.
If the article is to be saved in mailbox format, the command to do so is
generated from the environment variable MBOXSAVER.
Otherwise, NORMSAVER is used.
.Ip "S destination" 8
Save to a filename or pipe using a preferred shell, such as csh.
Which shell is used depends first on what you have the environment variable
SHELL set to, and in the absence of that, on what your news administrator
set for the preferred shell when he or she installed
.IR rn .
.Ip "| command" 8
Shorthand for \*(L"s | command\*(R".
.Ip "w destination" 8
The same as \*(L"s destination\*(R", but saves without the header.
.Ip "W destination" 8
The same as \*(L"S destination\*(R", but saves without the header.
.Ip & 8
Print out the current status of command line switches.
.Ip "&switch {switch}" 8
Set additional command line switches.
.Ip !command 8
Escape to a subshell.
One exclamation mark (!) leaves you in your own news directory.
A double exclamation mark (!!) leaves you in the spool
directory of the current newsgroup.
The environment variable SHELL will be used if defined.
If
.I command
is null, an interactive shell is started.
.Sp
You can use escape key substitutions described later to get to many
run-time values.
The command is also run through % interpretation, in case it is being called
from a range or search command.
.Ip = 8
List subjects of unread articles.
.Ip # 8
Print last article number.
.Sh "Pager Level"
At the pager level (within an article), the prompt looks like this:
.Sp
\*(--MORE\*(--(17%)
.Sp
and a number of commands may be given:
.Ip SP 8
Display next page.
.Ip x 8
Display next page and decrypt as a rot13 message.
.Ip d,^D 8
Display half a page more.
.Ip CR 8
Display one more line.
.Ip q 8
Go to the end of the current article (don't mark it either read or unread).
Leaves you at the \*(L"What next?\*(R" prompt.
.Ip j 8
Junk the current article.
Mark it read and go to the end of the article.
.Ip ^L 8
Refresh the screen.
.Ip X 8
Refresh the screen and decrypt as a rot13 message.
.Ip b,^B 8
Back up one page.
.Ip gpattern 8
Goto (search forward for)
.I pattern
within current article.
Note that there is no space between the command and the pattern.
If the pattern is found, the page containing the pattern will be displayed.
Where on the page the line matching the pattern goes depends on the value
of the
.B \-g
switch.
By default the matched line goes at the top of the screen.
.Ip G 8
Search for g pattern again.
.Ip ^G 8
This is a special version of the \*(L'g\*(R' command that is for skipping
articles in a digest.
It is equivalent to setting \*(L"\-g4\*(R" and then executing the command
\*(L"g^Subject:\*(R".
.Ip !command 8
Escape to a subshell.
.PP
The following commands skip the rest of the current article, then behave just
as if typed to the \*(L"What next?\*(R" prompt at the end of the article.
See the documentation at the article selection level for these commands.
.Sp	
    # $ & / = ? c C f F k K ^K m M r R ^R u v Y ^
.br
    number
.br
    range{,range} command{:command}
.Sp
The following commands also skip to the end of the article, but have the
additional effect of marking the current article as read:
.Sp
    n N ^N s S | w W
.Sp
.Sh "Miscellaneous facts about commands"
An \*(L'n\*(R' typed at either the \*(L"Last newsgroup\*(R" prompt or a
\*(L"Last article\*(R" prompt will cycle back to the top of the newsgroup
or article list, whereas a \*(L'q\*(R' will quit the level.
(Note that \*(L'n\*(R' does not mean \*(L"no\*(R", but rather
\*(L"next\*(R".)
A space will of course do whatever is shown as the
default, which will vary depending on whether rn thinks you have more
articles or newsgroups to read.
.PP
The \*(L'b\*(R' (backup page) command may be repeated until the beginning of
the article is reached.
If
.I rn
is suspended (via a ^Z), then when the job is resumed, a refresh (^L) will
automatically be done (Berkeley-type systems only).
If you type a command such as \*(L'!\*(R' or \*(L's\*(R' which takes you
from the middle of the article to the end, you can always get back into the
middle by typing \*(L'^L\*(R'.
.PP
In multi-character commands such as \*(L'!\*(R', \*(L's\*(R', \*(L'/\*(R',
etc, you can interpolate various run-time values by typing escape and a
character.
To find out what you can interpolate, type escape and \*(L'h\*(R', or check
out the single character % substitutions for environment variables in the
Interpretation and Interpolation section, which are the same.
Additionally, typing a double escape will cause any % substitutions in the
string already typed in to be expanded.
.Sh "Options"
.I Rn
has a nice set of options to allow you to tailor the interaction
to your liking.
(You might like to know that the author swears by \*(L"\-e \-m \-S \-/\*(R".)
These options may be set on the command line, via the RNINIT
environment variable, via a file pointed to by the RNINIT variable, or
from within rn via the & command.
Options may generally be unset by saying \*(L"+switch\*(R".
Options include:
.TP 5
.B \-c
checks for news without reading news.
If a list of newsgroups is given on the command line, only those newsgroups
will be checked; otherwise all subscribed-to newsgroups are checked.
Whenever the
.B \-c
switch is specified, a non-zero exit status from
.I rn
means that there is unread news in one of the checked newsgroups.
The
.B \-c
switch does not disable the printing of newsgroups with unread news;
this is controlled by the
.B \-s
switch.
(The
.B \-c
switch is not meaningful when given via the & command.)
.TP 5
.B \-C<number>
tells
.I rn
how often to checkpoint the
.IR .newsrc ,
in articles read.
Actually, this number says when to start thinking about doing a checkpoint
if the situation is right.
If a reasonable checkpointing situation doesn't arise within 10 more
articles, the
.I .newsrc
is checkpointed willy-nilly.
.TP 5
.B \-d<directory name>
sets the default save directory to something other than ~/News.
The directory name will be globbed (via csh) if necessary (and if possible).
Articles saved by
.I rn
may be placed in the save directory or in a subdirectory thereof depending
on the command that you give and the state of the environment variables
SAVEDIR and SAVENAME.
Any KILL files (see the K command in the Article Selection section)
also reside in this directory and its subdirectories, by default.
In addition, shell escapes leave you in this directory.
.TP 5
.B \-D<flags>
enables debugging output.
See rn.h for flag values.
.TP 5
.B \-e
causes each page within an article to be started at the top of the screen,
not just the first page.
(It is similar to the
.B \-c
switch of
.IR more (1).)
You never have to read scrolling text with this switch.
This is helpful especially at certain baud rates because you can start reading
the top of the next page without waiting for the whole page to be printed.
It works nicely in conjuction with the
.B \-m
switch, especially if you use half-intensity for your highlight mode.
.TP 5
.B \-E<name>=<val>
sets the environment variable <name> to the value specified.
Within
.IR rn ,
\*(L"&\-ESAVENAME=%t\*(R" is similar to \*(L"setenv SAVENAME '%t'\*(R" in
.IR csh ,
or \*(L"SAVENAME='%t'; export SAVENAME\*(R" in
.IR sh .
Any environment variables set with
.B \-E
will be inherited by subprocesses of
.IR rn .
.TP 5
.B \-F<string>
sets the prefix string for the \*(L'F\*(R' followup command to use in
prefixing each line of the quoted article.
For example, \*(L"\-F<tab>\*(R" inserts a tab on the front of each line
(which will cause long lines to wrap around, unfortunately),
\*(L"\-F>>>>\*(R" inserts \*(L">>>>\*(R" on every line, and
\*(L"\-F\*(R" by itself causes nothing to be inserted, in case you want to
reformat the text, for instance.
The initial default prefix is \*(L">\*(R".
.TP 5
.B \-g<line>
tells
.I rn
which line of the screen you want searched-for strings to show up on when
you search with the \*(L'g\*(R' command within an article.
The lines are numbered starting with 1.
The initial default is \*(L"\-g1\*(R", meaning the first line of the screen.
Setting the line to less than 1 or more than the number of lines on the screen
will set it to the last line of the screen.
.TP 5
.B \-h<string>
hides (disables the printing of) all header lines beginning with
.I string.
For instance, \-hexp will disable the printing of the \*(L"Expires:\*(R" line.
Case is insignificant.
If <string> is null, all header lines except Subject are hidden, and you
may then use
.B +h
to select those lines you want to see.
You may wish to use the baud-rate switch modifier below to hide more lines
at lower baud rates.
.TP 5
.B \-H<string>
works just like
.B \-h
except that instead of setting the hiding flag for a header line, it sets
the magic flag for that header line.
Certain header lines have magic behavior that can be controlled this way.
At present, the following actions are caused by the flag for the particular
line:
the Newsgroups line will only print when there are multiple newsgroups,
the Subject line will be underlined, and the Expires line will always be
suppressed if there is nothing on it.
In fact, all of these actions are the default, and you must use
.B +H
to undo them.
.TP 5
.B \-i=<number>
specifies how long (in lines) to consider the initial page of an
article\*(--normally this is determined automatically depending on baud rate.
(Note that an entire article header will always be printed regardless of the
specified initial page length.
If you are working at low baud rate and wish to reduce the size of the
headers, you may hide certain header lines with the
.B \(bsh
switch.)
.TP 5
.B \-l
disables the clearing of the screen at the beginning of each
article, in case you have a bizarre terminal.
.TP 5
.B \-m=<mode>
enables the marking of the last line of the previous page
printed, to help the user see where to continue reading.
This is most helpful when less than a full page is going to be displayed.
It may also be used in conjunction with the
.B \-e
switch, in which case the page is erased, and the first line (which is
the last line of the previous page) is highlighted.
If
.B \-m=s
is specified, the standout mode will be used, but if
.B \-m=u
is specified, underlining will be used.
If neither
.B =s
or
.B =u
is specified, standout is the default.
.TP 5
.B \-M
forces mailbox format in creating new save files.
Ordinarily you are asked which format you want.
.TP 5
.B \-N
forces normal (non-mailbox) format in creating new save files.
Ordinarily you are asked which format you want.
.TP 5
.B \-r
causes
.I rn
to restart in the last newsgroup read during a previous session with
.I rn.
It is equivalent to starting up normally and then getting to the newsgroup
with a g command.
.TP 5
.B \-s
with no argument suppresses the initial listing of newsgroups with unread
news, whether
.B \-c
is specified or not.
Thus
.B \-c
and
.B \-s
can be used together to test \*(L"silently\*(R" the status of news from
within your
.I .login
file.
If
.B \-s
is followed by a number, the initial listing is suppressed after that many
lines have been listed.
Presuming that you have your
.I .newsrc
sorted into order of interest,
.B \-s5
will tell you the 5 most interesting newsgroups that have unread news.
This is also a nice feature to use in your
.I .login
file, since it not only tells you whether there is unread news, but also how
important the unread news is, without having to wade through the entire
list of unread newsgroups.
If no 
.B \-s
switch is given 
.B \-s5
is assumed, so just putting \*(L"rn \-c\*(R"
into your
\&.login file is fine.
.TP 5
.B \-S<number>
causes
.I rn
to enter subject search mode (^N) automatically whenever a newsgroup is
started up with <number> unread articles or more.
Additionally, it causes any \*(L'n\*(R' typed while in subject search mode
to be interpreted as \*(L'^N\*(R' instead.
(To get back out of subject search mode, the best command is probably
\&\*(L'^\*(R'.)
If <number> is omitted, 3 is assumed.
.TP 5
.B \-t
puts
.I rn
into terse mode.
This is more cryptic but useful for low baud rates.
(Note that your system administrator may have compiled
.I rn
with either verbose or terse messages only to save memory.)
You may wish to use the baud-rate switch modifier below to enable terse mode
only at lower baud rates.
.TP 5
.B \-T
allows you to type ahead of rn.
Ordinarily rn will eat typeahead to prevent your autorepeating space bar from
doing a very frustrating thing when you accidentally hold it down.
If you don't have a repeating space bar, or you are working at low baud
rate, you can set this switch to prevent this behavior.
You may wish to use the baud-rate switch modifier below to disable typeahead
only at lower baud rates.
.TP 5
.B \-v
sets verification mode for commands.
When set, the command being executed is displayed to give some feedback that
the key has actually been typed.
Useful when the system is heavily loaded and you give a command that takes
a while to start up.
.TP 5
.B \-/
sets SAVEDIR to \*(L"%p/%c\*(R" and SAVENAME to \*(L"%a\*(R", which means
that by default articles are saved in a subdirectory of your private news
directory corresponding to the name of the the current newsgroup, with the
filename being the article number.
.B +/
sets SAVEDIR to \*(L"%p\*(R" and SAVENAME to \*(L"%^C\*(R", which by
default saves articles directly to your private news directory, with the
filename being the name of the current newsgroup, first letter capitalized.
(Either
.B +/
or
.B \-/
may be default on your system, depending on the feelings of your news
administrator when he, she or it installed
.IR rn .)
You may, of course, explicitly set SAVEDIR and SAVENAME to other values\*(--see
discussion in the environment section.
.PP
Any switch may be selectively applied according to the current baud-rate.
Simply prefix the switch with +speed to apply the switch at that speed or
greater, and \%\-speed to apply the switch at that speed or less.
Examples: \%\-1200\-hposted suppresses the Posted line at 1200 baud or less;
\%+9600\-m enables marking at 9600 baud or more.
You can apply the modifier recursively to itself also: \%+300\-1200\-t sets
terse mode from 300 to 1200 baud.
.PP
Some switch arguments, such as environment variable values, may require
spaces in them.
Such spaces should be quoted via ", ', or \e in the conventional fashion,
even when passed via RNINIT or the & command.
.Sh "Regular Expressions"
The patterns used in article searching are regular expressions such as
those used by
.IR ed (1).
In addition, \ew matches an alphanumeric character and \eW a nonalphanumeric.
Word boundaries may be matched by \eb, and non-boundaries by \eB.
The bracketing construct \e(\ ...\ \e) may also be used, and \edigit matches
the digit'th substring, where digit can range from 1 to 9.
\e0 matches whatever the last bracket match matched.
Up to 10 alternatives may given in a pattern, separated by \e|, with the
caveat that \e(\ ...\ \e|\ ...\ \e) is illegal.
.Sh "Interpretation and Interpolation"
Many of the strings that
.I rn
handles are subject to interpretations of several types.
Under filename expansion, an initial \*(L"~/\*(R" is translated to the name
of your home directory, and \*(L"~name\*(R" is translated to the login
directory for the user specified.
Filename expansion will also expand an initial environment variable, and
also does the backslash and percent expansion mentioned below.
.PP
All interpreted strings go through both backslash and percent interpretation.
The backslash escapes are the normal ones (such as \en, \et, \ennn, etc.).
The special percent escapes are similar to printf percent escapes.
These cause the substitution of various run-time values into the string.
The following are currently recognized:
.Ip %a 8
Current article number.
.Ip %A 8
Full name of current article (%P/%c/%a).
(On a Eunice system with the LINKART option, %P/%c/%a returns the name of
the article in the current newsgroup, while %A returns the real name of
the article, which may be different if the current article was posted to
multiple newsgroups.)
.Ip %b 8
Destination of last save command, often a mailbox.
.Ip %B 8
The byte offset to the beginning of the part of the article to be saved,
set by the save command.
The \*(L's\*(R' and \*(L'S\*(R' commands set it to 0, and the \*(L'w\*(R'
and \*(L'W\*(R' commands set it to the byte offset of the body of the article.
.Ip %c 8
Current newsgroup, directory form.
.Ip %C 8
Current newsgroup, dot form.
.Ip %d 8
Full name of newsgroup directory (%P/%c).
.Ip %D 8
\*(L"Distribution:\*(R" line from the current article.
.Ip %f 8
\*(L"From:\*(R" line from the current article, or the \*(L"Reply-To:\*(R"
line if there is one.
This differs from %t in that comments (such as the full name) are not
stripped out with %f.
.Ip %F 8
\*(L"Newsgroups:\*(R" line for a new article, constructed from
\*(L"Newsgroups:\*(R" and \*(L"Followup-To:\*(R" lines of current article.
.Ip %h 8
Name of the header file to pass to the mail or news poster,
containing all the information that the poster program needs in the
form of a message header.
It may also contain a copy of the current article.
The format of the header file is controlled by the MAILHEADER and NEWSHEADER
environment variables.
.Ip %H 8
Host name (your machine's name).
.Ip %i 8
\*(L"Message-I.D.:\*(R" line from the current article, with <> guaranteed.
.Ip %l 8
The news administrator's login name, if any.
.Ip %L 8
Login name (yours).
.Ip %M 8
The number of articles marked to return via the \*(L'M\*(R' command.
If the same article is Marked multiple times, \*(L"%M\*(R" counts it
multiple times in the current implementation.
.Ip %n 8
\*(L"Newsgroups:\*(R" line from the current article.
.Ip %N 8
Full name (yours).
.Ip %o 8
Organization (yours).
.Ip %O 8
Original working directory (where you ran rn from).
.Ip %p 8
Your private news directory, normally ~/News.
.Ip %P 8
Public news spool directory, normally /usr/spool/news.
.Ip %r 8
Last reference on references line of current article (parent article id).
.Ip %R 8
References list for a new article, constructed from the references and article
ID of the current article.
.Ip %s 8
Subject, with all Re's and (nf)'s stripped off.
.Ip %S 8
Subject, with one \*(L"Re:\*(R" stripped off.
.Ip %t 8
\*(L"To:\*(R" line derived from the \*(L"From:\*(R" and \*(L"Reply-To:\*(R"
lines of the current article.
This always returns an Internet format address.
.Ip %T 8
\*(L"To:\*(R" line derived constructed from the \*(L"Path:\*(R" line of the
current article to produce a uucp path.
.Ip %u 8
The number of unread articles in the current newsgroup.
.Ip %U 8
The number of unread articles in the current newsgroup, not counting the
current article.
.Ip %x 8
The news library directory.
.Ip %X 8
The rn library directory.
.Ip %~ 8
Your home directory.
.Ip %. 8
The directory containing your dot files, which is your home directory unless
the environment variable DOTDIR is defined when rn is invoked.
.Ip %$ 8
Current process number.
.Ip %/ 8
Last search string.
.Ip %% 8
A percent sign.
.Ip "%{name} or %{name\-default}" 8
The environment variable \*(L"name\*(R".
.Ip %[name] 8
The value of header line \*(L"Name:\*(R" from the current article.
The \*(L"Name:\ \*(R" is not included.
For example \*(L"%D\*(R" and \*(L"%[distribution]\*(R" are equivalent.
The name must be spelled out in full.
.Ip "%(test_text=pattern?then_text:else_text)" 8
If
.I test_text
matches
.IR pattern ,
has the value
.IR then_text ,
otherwise
.IR else_text .
The \*(L":else_text\*(R" is optional, and if absent, interpolates the null string.
The = may be replaced with != to negate the test.
To quote any of the metacharacters
(\*(L'=\*(R', \*(L'?\*(R', \*(L':\*(R', or \*(L')\*(R'),
precede with a backslash.
.Ip %digit 8
The digits 1 through 9 interpolate the string matched by the nth bracket
in the last pattern match that had brackets.
If the last pattern had alternatives, you may not know the number of the
bracket you want\*(--%0 will give you the last bracket matched.
.PP
Modifiers: to capitalize the first letter, insert \*(L'^\*(R':
\*(L"%^C\*(R" produces something like \*(L"Net.jokes\*(R".
Inserting \*(L'`\*(R' causes the first letter following the last
\&\*(L'/\*(R' to be capitalized: \*(L"%`c\*(R" produces \*(L"net/Jokes\*(R".
.SH ENVIRONMENT
The following environment variables are paid attention to by
.IR rn .
In general the default values assumed for these variables by
.I rn
are reasonable, so if you are using
.I rn
for the first time, you can safely ignore this section.
.PP
Those variables marked (%) are subject to % interpolation, and those marked
(~) are subject to both % interpolation and ~ interpretation.
.Ip "ATTRIBUTION (%)" 8
Gives the format of the attribution line in front of the quoted article
included by an F command.
.Sp
Default: In article %i %f writes:
.Ip "CANCEL (~)" 8
The shell command used to cancel an article.
.Sp
Default: inews \-h < %h
.Ip "CANCELHEADER (%)" 8 13v
The format of the file to pass to the CANCEL command in order to cancel
an article.
.Sp
Default:
.br
Newsgroups: %n
.br
Subject: cmsg cancel %i
.br
References: %R
.br
Reply-To: %L@%H.UUCP (%N)
.br
Distribution: %D
.br
Organization: %o
.sp 1
%i cancelled from rn.
.Ip DOTDIR 8
Where to find your dot files, if they aren't in your home directory.
Can be interpolated using \*(L"%.\*(R".
.Sp
Default: $HOME
.Ip "EDITOR (~)" 8
The name of your editor, if VISUAL is undefined.
.Sp
Default: whatever your news administrator compiled in, usually vi.
.Ip "FIRSTLINE (%)" 8
Controls the format of the line displayed at the top of an article.
Warning: this may go away.
.Sp
Default: Article %a %(%U%M!=^00$?(%U more%(%M!=^0$? + %M Marked to return)\e) )in %C:, more or less.
.Ip HOME 8
Your home directory.
Affects ~ interpretation, and the location of your
dot files if DOTDIR is not defined.
.Sp
Default: $LOGDIR
.Ip "KILLGLOBAL (~)" 8
Where to find the KILL file to apply to every newsgroup.
See the \*(L'^K\*(R' command at the newsgroup selection level.
.Sp
Default: %p/KILL
.Ip "KILLLOCAL (~)" 8
Where to find the KILL file for the current newsgroup.
See the commands \*(L'K\*(R' and \*(L'^K\*(R' at the article selection level,
and the search modifier \*(L'K\*(R'.
.Sp
Default: %p/%c/KILL
.Ip LOGDIR 8
Your home directory if HOME is undefined.
Affects ~ interpretation, and the location of your
dot files if DOTDIR is not defined.
.Sp
Default: none.
.Sp
Explanation: you must have either $HOME or $LOGDIR.
.Ip LOGNAME 8
Your login name, if USER is undefined.
May be interpolated using \*(L"%L\*(R".
.Sp
Default: value of getlogin().
.Ip "MAILFILE (~)" 8
Where to check for mail.
.Sp
Default: /usr/spool/mail/%L
.Ip "MAILHEADER (%)" 8
The format of the header file for replies.
See also MAILPOSTER.
.Sp
Default:
.Sp
To: %T
.br
Subject: Re: %S
.br
Newsgroups: %n
.br
In-Reply-To: %i
.br
%(%[references]!=^$?References\\: %[references]
.br
)Organization: %o
.br
Cc: 
.br
Bcc: \en\en
.Ip "MAILPOSTER (~)" 8
The shell command to be used by the reply commands (r and R)
in order to allow you to enter and deliver the response.
.I Rn
will not itself call upon an editor for replies\*(--this
is a function of the program called by
.IR rn .
See also MAILHEADER.
.Sp
Default: Rnmail \-h %h
.Ip "MBOXSAVER (~)" 8
The shell command to save an article in mailbox format.
.Sp
Default: %X/mbox.saver %A %P %c %a %B %C "%b" \e
.br
"From: %T %(%[posted]!=^$?%[posted]:\e
.br
%(%[date]=^\e(\ew*\e), \e(\ew*\e)-\e(\ew*\e)-\e(\ew*\e) \e([^ ]*\e)?\e
.br
%1 %3 %(%2=..?%2: %2) %5 19%4))"
.Sp
Explanation: the first seven arguments are the same as for NORMSAVER.
The eighth argument to the shell script is the new From: line
for the article, including the posting date,
derived either directly from the Posted: line, or not-so-directly from
the Date: line.
Header munging at its finest.
.Ip NAME 8
Your full name.
May be interpolated using \*(L"%N\*(R".
.Sp
Default: name from /etc/passwd, or ~/.fullname.
.Ip "NEWSHEADER (%)" 8 16v
The format of the header file for followups.
See also NEWSPOSTER.
.Sp
Default:
.Sp
Newsgroups: %F
.br
Subject: Re: %S
.br
Summary:
.br
Expires: 
.br
References: %R
.br
Sender: 
.br
Reply-To: %L@%H.UUCP (%N)
.br
Followup-To: 
.br
Distribution: %D
.br
Organization: %o
.br
Keywords: \en\en
.Ip "NEWSPOSTER (~)" 8
The shell command to be used by the followup commands (f and F)
in order to allow you to enter and post a followup news article.
.I Rn
will not itself call upon an editor for followups\*(--this
is a function of the program called by
.IR rn .
See also NEWSHEADER.
.Sp
Default: Pnews \-h %h
.Ip "NORMSAVER (~)" 8
The shell command to save an article in the normal (non-mailbox) format.
.Sp
Default: %X/norm.saver %A %P %c %a %B %C "%b"
.Ip ORGANIZATION 8
Either the name of your organization, or the name of a file containing the
name of your organization.
May be interpolated using \*(L"%o\*(R".
.Sp
Default: whatever your news administrator compiled in.
.Ip "PIPESAVER (%)" 8
The shell command to execute in order to accomplish a save to a pipe
(\*(L"s\ |\ command\*(R" or \*(L"w\ |\ command\*(R").
The command typed by the user is substituted in as %b.
.Sp
Default: %(%B=^0$?<%A:tail +%Bc %A |) %b
.Sp
Explanation: if %B is 0, the command is \*(L"<%A %b\*(R", otherwise
the command is \*(L"tail +%Bc %A | %b\*(R".
.Ip RNINIT 8
Default values for switches may be passed to
.I rn
by placing them in RNINIT.
Any switch that is set in RNINIT may be overruled 
on the command line, or via the \*(L'&\*(R' command from within
.IR rn .
Binary-valued switches that are set with \*(L"\-switch\*(R" may be unset
using \*(L"+switch\*(R".
.Sp
If RNINIT begins with a \*(L'/\*(R' it is assumed to be the name of a file
containing switches.
If you want to set many environment variables but don't want to keep
them all in your environment, or if the use of any of these variables
conflicts with other programs, you can use this feature along with the
.B \-E
switch to set the environment variables upon startup.
.Sp
Default: \*(L" \*(R".
.Ip "SAVEDIR (~)" 8
The name of the directory to save to, if the save command does not specify
a directory name.
.Sp
Default:
.br
   If
.B \-/
is set: %p/%c
.br
   If
.B +/
is set: %p
.Ip "SAVENAME (%)" 8
The name of the file to save to, if the save command contains only a
directory name.
.Sp
Default:
.br
   If
.B \-/
is set: %a
.br
   If
.B +/
is set: %^C
.Ip SHELL 8
The name of your preferred shell.
It will be used by the \*(L'!\*(R', \*(L'S\*(R' and \*(L'W\*(R' commands.
.Sp
Default: whatever your news administrator compiled in.
.Ip TERM 8
Determines which termcap entry to use, unless TERMCAP contains the entry.
.Ip TERMCAP 8
Holds either the name of your termcap file, or a termcap entry.
.Sp
Default: /etc/termcap, normally.
.Ip USER 8
Your login name.
May be interpolated using \*(L"%L\*(R".
.Sp
Default: $LOGNAME
.Ip "VISUAL (~)" 8
The name of your editor.
.Sp
Default: $EDITOR
.Ip "YOUSAID (%)" 8
Gives the format of the attribution line in front of the quoted article
included by an R command.
.Sp
Default: In article %i you write:
.SH AUTHOR
Larry Wall <lwall@sdcrdcf.UUCP>
.br
Regular expression routines are borrowed from emacs, by James Gosling.
.SH FILES
.Ip "%./.newsrc" 1.25i
status of your news reading
.Ip "%./.oldnewsrc" 1.25i
backup copy of your
.I .newsrc
from start of session
.Ip "%./.rnlock" 1.25i
lock file so you don't screw up your
.I .newsrc
.Ip "%./.rnlast" 1.25i
info from last run of rn
.Ip "%./.rnsoft" 1.25i
soft pointers into /usr/lib/active to speed startup, synchronous with
.I .newsrc
.Ip "%./.rnhead" 1.25i
temporary header file to pass to a mailer or news poster
.Ip "%p" 1.25i
your news save directory, usually ~/News
.Ip "%x/active" 1.25i
the list of active newsgroups, usually /usr/lib/news/active
.Ip "%P" 1.25i
the public news spool directory, usually /usr/spool/news
.SH SEE ALSO
newsrc(25), more(1), readnews(1), Pnews(1), Rnmail(1)
.SH DIAGNOSTICS
Generally self-documenting, as they say.
.SH BUGS
The
.B \-h
switch can only hide header lines that
.I rn
knows about.
.PP
The \*(L'\-\*(R' command doesn't cross newsgroup boundaries, and only undoes
the last article selection.
.PP
If you edit your
.I .newsrc
while
.I rn
is running,
.I rn
will happily wipe out your changes when it decides to
write out the
.I .newsrc
file.
.PP
.I Rn
doesn't do certain things (like ordering articles on posting date) that
the author feels should be handled by inews.
.PP
Marking of duplicate articles as read in cross-referenced newsgroups will
not work unless the Xref patch is installed in inews.
.PP
If you get carried away with % or escape substitutions, you can overflow
buffers.
.PP
There should be no fixed limit on the number of newsgroups.
.PP
Some of the more esoteric features may be missing on machines with limited
address space.
!STUFFY!FUNK!
echo Extracting bits.c
cat >bits.c <<'!STUFFY!FUNK!'
/* $Header: bits.c,v 4.1 84/09/24 11:43:17 lwall Exp $
 *
 * $Log:	bits.c,v $
 * Revision 4.1  84/09/24  11:43:17  lwall
 * Real baseline.
 * 
 * Revision 4.0.1.7  84/09/21  15:49:29  lwall
 * New Xref format forced by newsgroup aliasing in 2.10.2.
 * 
 * Revision 4.0.1.6  84/09/14  15:16:14  lwall
 * Fixed nasty dangling else.
 * 
 * Revision 4.0.1.5  84/09/13  12:02:20  lwall
 * UNLINK for Eunice.
 * 
 * Revision 4.0.1.4  84/09/13  11:19:51  lwall
 * addartnum() now returns int.
 * 
 * Revision 4.0.1.3  84/09/10  15:06:49  lwall
 * Delinted.
 * 
 * Revision 4.0.1.2  84/09/06  17:00:58  lwall
 * Implemented newsgroup exit commands.
 * 
 * Revision 4.0.1.1  84/09/06  08:15:36  lwall
 * Include artio.h and interp.h.
 * 
 * Revision 4.0  84/09/04  09:49:52  lwall
 * Baseline for netwide release
 * 
 */

#include "EXTERN.h"
#include "common.h"
#include "rcstuff.h"
#include "head.h"
#include "util.h"
#include "final.h"
#include "rn.h"
#include "cheat.h"
#include "ng.h"
#include "artio.h"
#include "intrp.h"
#include "ngdata.h"
#include "rcln.h"
#include "kfile.h"
#include "INTERN.h"
#include "bits.h"

MEM_SIZE ctlsize;			/* size of bitmap in bytes */

void
bits_init()
{
#ifdef DELAYMARK
    dmname = savestr(filexp(RNDELNAME));
#else
    ;
#endif
}

/* checkpoint the .newsrc */

void
checkpoint_rc()
{
#ifdef DEBUGGING
    if (debug & DEB_CHECKPOINTING) {
	fputs("(ckpt)",stdout);
	fflush(stdout);
    }
#endif
    if (doing_ng)
	restore_ng();			/* do not restore M articles */
    if (rc_changed)
	write_rc();
#ifdef DEBUGGING
    if (debug & DEB_CHECKPOINTING) {
	fputs("(done)",stdout);
	fflush(stdout);
    }
#endif
}

/* reconstruct the .newsrc line in a human readable form */

void
restore_ng()
{
    register char *s, *mybuf = buf;
    register ART_NUM i;
    ART_NUM count=0;
    int safelen = LBUFLEN - 16;

    strcpy(buf,rcline[ng]);		/* start with the newsgroup name */
    s = buf + rcnums[ng] - 1;		/* use s for buffer pointer */
    *s++ = rcchar[ng];			/* put the requisite : or !*/
    *s++ = ' ';				/* put the not-so-requisite space */
    for (i=1; i<=lastart; i++) {	/* for each article in newsgroup */
	if (s-mybuf > safelen) {	/* running out of room? */
	    safelen *= 2;
	    if (mybuf == buf) {		/* currently static? */
		*s = '\0';
		mybuf = safemalloc((MEM_SIZE)safelen + 16);
		strcpy(mybuf,buf);	/* so we must copy it */
		s = mybuf + (s-buf);
					/* fix the pointer, too */
	    }
	    else {			/* just grow in place, if possible */
		char *newbuf;

		newbuf = saferealloc(mybuf,(MEM_SIZE)safelen + 16);
		s = newbuf + (s-mybuf);
		mybuf = newbuf;
	    }
	}
	/*NOSTRICT*/
	if (!was_read(i))		/* still unread? */
	    count++;			/* then count it */
	else {				/* article was read */
	    ART_NUM oldi;

	    sprintf(s,"%ld",(long)i);	/* put out the min of the range */
	    s += strlen(s);		/* keeping house */
	    oldi = i;			/* remember this spot */
	    /*NOSTRICT*/
	    do i++; while (i <= lastart && was_read(i));
					/* find 1st unread article or end */
	    i--;			/* backup to last read article */
	    if (i > oldi) {		/* range of more than 1? */
		sprintf(s,"-%ld,",(long)i);
					/* then it out as a range */
		s += strlen(s);		/* and housekeep */
	    }
	    else
		*s++ = ',';		/* otherwise, just a comma will do */
	}
    }
    if (*(s-1) == ',')			/* is there a final ','? */
	s--;				/* take it back */
    *s++ = '\0';			/* and terminate string */
#ifdef DEBUGGING
    if (debug & DEB_NEWSRC_LINE && !panic) {
	printf("%s: %s\n",rcline[ng],rcline[ng]+rcnums[ng]);
	printf("%s\n",mybuf);
    }
#endif
    free(rcline[ng]);			/* return old rc line */
    if (mybuf = buf) {
	rcline[ng] = safemalloc((MEM_SIZE)(s-buf)+1);
					/* grab a new rc line */
	strcpy(rcline[ng], buf);	/* and load it */
    }
    else {
	mybuf = saferealloc(mybuf,(MEM_SIZE)(s-mybuf)+1);
					/* be nice to the heap */
	rcline[ng] = mybuf;
    }
    *(rcline[ng] + rcnums[ng] - 1) = '\0';
    if (rcchar[ng] == NEGCHAR) {	/* did they unsubscribe? */
	printf(unsubto,ngname);
	toread[ng] = TR_UNSUB;		/* make line invisible */
    }
    else
	/*NOSTRICT*/
	toread[ng] = (ART_UNREAD)count;		/* remember how many unread there are */
}

/* mark an article unread, keeping track of toread[] */

void
onemore(artnum)
ART_NUM artnum;
{
    /*NOSTRICT*/
    if (ctl_read(artnum)) {
	/*NOSTRICT*/
	ctl_clear(artnum);
	++toread[ng];
    }
}

/* mark an article read, keeping track of toread[] */

void
oneless(artnum)
ART_NUM artnum;
{
    /*NOSTRICT*/
    if (!ctl_read(artnum)) {
	/*NOSTRICT*/
	ctl_set(artnum);
	if (toread[ng] > TR_NONE)
	    --toread[ng];
    }
}

/* mark an article as unread, making sure that firstart is properly handled */
/* cross-references are left as read in the other newsgroups */

void
unmark_as_read(artnum)
ART_NUM artnum;
{
    check_first(artnum);
    onemore(artnum);
#ifdef MCHASE
    if (!parse_maybe(artnum))
	chase_xrefs(artnum,FALSE);
#endif
}

#ifdef DELAYMARK
/* temporarily mark article as read.  When newsgroup is exited, articles */
/* will be marked as unread.  Called via M command */

void
delay_unmark(artnum)
ART_NUM artnum;
{
    if (!dmfp)
	dmfp = fopen(dmname,"w");
    oneless(artnum);			/* set the correct bit */
    dmcount++;
    fprintf(dmfp,"%ld\n",(long)artnum);
}
#endif

/* mark article as read.  If article is cross referenced to other */
/* newsgroups, mark them read there also. */

void
mark_as_read(artnum)
ART_NUM artnum;
{
    oneless(artnum);			/* set the correct bit */
    checkcount++;			/* get more worried about crashes */
    chase_xrefs(artnum,TRUE);
}

/* make sure we have bits set correctly down to firstart */

void
check_first(min)
ART_NUM min;
{
    register ART_NUM i = firstart;

    if (min < absfirst)
	min = absfirst;
    if (min < i) {
	for (i--; i>=min; i--)
	    /*NOSTRICT*/
	    ctl_set(i);		/* mark as read */
	firstart = min;
    }
}

/* bring back articles marked with M */

#ifdef DELAYMARK
void
yankback()
{
    register ART_NUM anum;

    if (dmfp) {			/* delayed unmarks pending? */
#ifdef VERBOSE
	printf("\nReturning %ld Marked article%s...\n",(long)dmcount,
	    dmcount == 1 ? nullstr : "s");
#endif
	fclose(dmfp);
	if (dmfp = fopen(dmname,"r")) {
	    while (fgets(buf,sizeof buf,dmfp) != Nullch) {
		anum = (ART_NUM)atol(buf);
		/*NOSTRICT*/
		onemore(anum);             /* then unmark them */
#ifdef MCHASE
		chase_xrefs(anum,FALSE);
#endif
	    }
	    fclose(dmfp);
	    dmfp = Nullfp;
	    UNLINK(dmname);		/* and be tidy */
	}
    }
    dmcount = 0;
}
#endif
    
/* run down xref list and mark as read or unread */

int
chase_xrefs(artnum,markread)
ART_NUM artnum;
int markread;
{
#ifdef ASYNC_PARSE
    if (parse_maybe(artnum))		/* make sure we have right header */
	return -1;
#endif
    if (
#ifdef DEBUGGING
	debug & DEB_FEED_XREF ||
#endif
	htype[XREF_LINE].ht_minpos >= 0) {
					/* are there article# xrefs? */
	char *xref_buf, *curxref;
	register char *xartnum;
	register ART_NUM x;
	char tmpbuf[128];

#ifdef DEBUGGING
	if (htype[XREF_LINE].ht_minpos >= 0)
#endif
	    xref_buf = fetchlines(artnum,XREF_LINE);
					/* get xrefs list */
#ifdef DEBUGGING
	else {
	    xref_buf = safemalloc((MEM_SIZE)100);
	    printf("Give Xref: ");
	    gets(xref_buf);
	}
#endif
#ifdef DEBUGGING
	if (debug & DEB_XREF_MARKER)
	    printf("Xref: %s\n",xref_buf);
#endif
	curxref = cpytill(tmpbuf,xref_buf,' ');
	if (strEQ(tmpbuf,sitename))
	    curxref++;
	else {
#ifdef DEBUGGING
	    if (debug)
		printf("Xref not from this system--ignoring\n");
#endif
	    goto wild_goose;
	}
	while (*curxref) {
					/* for each newsgroup */
	    curxref = cpytill(tmpbuf,curxref,' ');
	    xartnum = index(tmpbuf,':');
	    if (!xartnum)		/* probably an old-style Xref */
		break;
	    *xartnum++ = '\0';
	    if (strNE(tmpbuf,ngname)) {/* not the current newsgroup? */
		x = atol(xartnum);
		if (x)
		    if (markread) {
			if (addartnum(x,tmpbuf))
			    goto wild_goose;
		    }
#ifdef MCHASE
		    else
			subartnum(x,tmpbuf);
#endif
	    }
	    while (*curxref && isspace(*curxref))
		curxref++;
	}
      wild_goose:
	free(xref_buf);
    }
    return 0;
}

int
initctl()
{
    char *mybuf = buf;			/* place to decode rc line */
    register char *s, *c, *h;
    register long i;
    
#ifdef DELAYMARK
    dmcount = 0;
#endif
    if ((lastart = getngsize(ng)) < 0)	/* this cannot happen (laugh here) */
	return -1;

    absfirst = getabsfirst(ng,lastart);	/* remember first existing article */
    if (!absfirst)			/* no articles at all? */
	absfirst = 1;			/* pretend there is one */
    /*NOSTRICT*/
    ctlsize = (MEM_SIZE)(OFFSET(lastart)/BITSPERBYTE+20);
    ctlarea = safemalloc(ctlsize);	/* allocate control area */

    /* now modify ctlarea to reflect what has already been read */

    for (s = rcline[ng] + rcnums[ng]; *s == ' '; s++) ;
					/* find numbers in rc line */
    i = strlen(s);
    if (i >= LBUFLEN-2)			/* bigger than buf? */
	/*NOSTRICT*/
	mybuf = safemalloc((MEM_SIZE)(i+2));
    strcpy(mybuf,s);			/* make scratch copy of line */
    mybuf[i++] = ',';			/* put extra comma on the end */
    mybuf[i] = '\0';
    s = mybuf;				/* initialize the for loop below */
    if (strnEQ(s,"1-",2)) {		/* can we save some time here? */
	firstart = atol(s+2)+1;		/* ignore first range thusly */
	s=index(s,',') + 1;
    }
    else
	firstart = 1;			/* all the bits are valid for now */
    if (absfirst > firstart) {		/* do we know already? */
	toread[ng] -= (ART_UNREAD)(absfirst - firstart);
	firstart = absfirst;		/* no point calling getngmin again */
    }
    else if (artopen(firstart) == Nullfp) {
					/* first unread article missing? */
	i = getngmin(".",firstart);	/* see if expire has been busy */
	if (i) {			/* avoid a bunch of extra opens */
	    toread[ng] -= (ART_UNREAD)(i - firstart);
	    firstart = i;
	}
    }
#ifdef PENDING
#   ifdef CACHESUBJ
	subj_to_get = firstart;
#   endif
#endif
    for (i=OFFSET(firstart)/BITSPERBYTE; i<ctlsize; i++)
	ctlarea[i] = 0;			/* assume unread */
#ifdef DEBUGGING
    if (debug & DEB_CTLAREA_BITMAP) {
	printf("\n%s\n",mybuf);
	for (i=1; i <= lastart; i++)
	    /*NOSTRICT*/
	    if (! was_read(i))
		printf("%ld ",(long)i);
    }
#endif
    for ( ; (c = index(s,',')) != Nullch; s = ++c) {
					/* for each range */
	ART_NUM min, max;

	*c = '\0';			/* do not let index see past comma */
	if ((h = index(s,'-')) != Nullch) {	/* is there a -? */
	    min = atol(s);
	    max = atol(h+1);
	    if (min < firstart)		/* make sure range is in range */
		min = firstart;
	    if (max > lastart)
		max = lastart;
	    for (i=min; i<=max; i++)	/* for all articles in range */
		/*NOSTRICT*/
		ctl_set(i);		/* mark them read */
	}
	else if ((i = atol(s)) >= firstart && i <= lastart)
					/* is single number reasonable? */
	    /*NOSTRICT*/
	    ctl_set(i);			/* mark it read */
#ifdef DEBUGGING
	if (debug & DEB_CTLAREA_BITMAP) {
	    printf("\n%s\n",s);
	    for (i=1; i <= lastart; i++)
		/*NOSTRICT*/
		if (! was_read(i))
		    printf("%ld ",(long)i);
	}
#endif
    }
#ifdef DEBUGGING
    if (debug & DEB_CTLAREA_BITMAP) {
	fputs("\n(hit CR)",stdout);
	gets(cmd_buf);
    }
#endif
    if (mybuf != buf)
	free(mybuf);
    return 0;
}

void
grow_ctl()
{
    ART_NUM newlast;
    ART_NUM tmpfirst;
    MEM_SIZE newsize;
    register ART_NUM i;

    forcegrow = FALSE;
    newlast = getngsize(ng);
    if (newlast > lastart) {
	ART_NUM tmpart = art;
	/*NOSTRICT*/
	newsize = (MEM_SIZE)(OFFSET(newlast)/BITSPERBYTE+2);
	if (newsize > ctlsize) {
	    newsize += 20;
	    ctlarea = saferealloc(ctlarea,newsize);
	    ctlsize = newsize;
	}
	toread[ng] += (ART_UNREAD)(newlast-lastart);
	for (i=lastart+1; i<=newlast; i++)
	    /*NOSTRICT*/
	    ctl_clear(i);	/* these articles are unread */
#ifdef CACHESUBJ
	if (subj_list != Null(char**)) {
	    /*NOSTRICT*/
	    subj_list = (char**)saferealloc((char*)subj_list,
		  (MEM_SIZE)((OFFSET(newlast)+2)*sizeof(char *)) );
	    for (i=lastart+1; i<=newlast; i++)
		subj_list[OFFSET(i)] = Nullch;
	}
#endif
	tmpfirst = lastart+1;
	lastart = newlast;
#ifdef KILLFILES
#ifdef VERBOSE
	IF(verbose)
	    sprintf(buf,
		"%ld more article%s arrived--looking for more to kill...\n\n",
		(long)(lastart - firstart + 1),
		(lastart > firstart ? "s have" : " has" ) );
	ELSE			/* my, my, how clever we are */
#endif
#ifdef TERSE
	    strcpy(buf, "More news--killing...\n\n");
#endif
	kill_unwanted(tmpfirst,buf,TRUE);
#endif
	art = tmpart;
    }
}

!STUFFY!FUNK!
echo Extracting makedist
cat >makedist <<'!STUFFY!FUNK!'
#!/bin/sh
# $Header: makedist,v 4.1 84/09/24 11:59:46 lwall Exp $
#
# $Log:	makedist,v $
# Revision 4.1  84/09/24  11:59:46  lwall
# Real baseline.
# 
# Revision 4.0  84/09/04  09:51:22  lwall
# Baseline for netwide release
# 

rm -f kit*.list
manifake
kitlists
manimake
makekit kit*.list
!STUFFY!FUNK!
echo ""
echo "End of kit 1 (of 8)"
cat /dev/null >kit1isdone
config=true
for iskit in 1 2 3 4 5 6 7 8; do
    if test -f kit${iskit}isdone; then
	echo "You have run kit ${iskit}."
    else
	echo "You still need to run kit ${iskit}."
	config=false
    fi
done
case $config in
    true)
	echo "You have run all your kits.  Please read README and then type Configure."
	chmod 755 Configure
	;;
esac
: I do not append .signature, but someone might mail this.
exit