home *** CD-ROM | disk | FTP | other *** search
- Subject: v19i072: NN, a Usenet news reader, Part11/15
- Newsgroups: comp.sources.unix
- Sender: sources
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: storm@texas.dk (Kim F. Storm)
- Posting-number: Volume 19, Issue 72
- Archive-name: nn/part11
-
- #!/bin/sh
- # this is part 11 of a multipart archive
- # do not concatenate these parts, unpack them in order with /bin/sh
- # file nngoback.1 continued
- #
- CurArch=11
- if test ! -r s2_seq_.tmp
- then echo "Please unpack part 1 first!"
- exit 1; fi
- ( read Scheck
- if test "$Scheck" != $CurArch
- then echo "Please unpack part $Scheck next!"
- exit 1;
- else exit 0; fi
- ) < s2_seq_.tmp || exit 1
- echo "x - Continuing file nngoback.1"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' >> nngoback.1
- X.SH SYNOPSIS
- X.B nngoback
- X[ \-\fBh\fP ]
- X.I days
- X.SH DESCRIPTION
- X.I nngoback
- Xwill rewind the record file of \fBnn\fP(1) one or more days, i.e. mark
- Xthe news articles which have arrived on the system during the last
- X.I days
- Xdays unread.
- X.LP
- XIf you are not up-to-date with your news reading, you can also use
- X\fBnngoback\fP to catch up to only have the last few days of news
- Xwaiting to be read in the following way:
- X.br
- X nn \-a0
- X.br
- X nngoback 3
- X.br
- XThe \fBnn\fP command will mark all articles in all groups as read (answer
- X.I all
- Xto the catch-up question.) The following \fBnngoback\fP will then make
- Xthe last three days of news unread again.
- X.LP
- XExamples:
- X.TP
- Xnngoback 0
- XMark the articles which have arrived today as unread.
- X.TP
- Xnngoback 1
- XMark the articles which have arrived yesterday and today as unread.
- X.TP
- Xnngoback 6
- XMark the articles which have arrived during the last week as unread.
- X.LP
- X\fBnngoback\fP have two methods to rewind the rc file:
- X.br
- X\- scan the history file for the articles (option \-\fBh\fP), or
- X.br
- X\- use a copy of the active file with the `right' age (default).
- X.LP
- XNormally, \fInngoback\fP will run \fInntidy\fP on your rc file using
- Xa copy of the active file saved on the requested day. Using this
- Xmethod, you cannot go more than 14 days back.
- X.LP
- XIf the \-\fBh\fP option is specified, the history file will be scanned
- Xto locate articles which have been received after the specified day
- Xand mark those as unread in the rc file. When this method is used,
- X\fBnngoback\fP can be quite slow depending on the size of the history
- Xfile in your news system; it uses \fBegrep\fP(1) to scan the file, so
- Xit must be read the entire file although the interesting data are
- Xfound towards the end of the file. This method does not normally work
- Xwith NNTP or in a network environment.
- X.LP
- XIt is a prerequisite that the script \fBback_act\fP is executed at an
- Xappropriate time once (and only once) every day. Preferably this is
- Xdone by \fBcron\fP right before the bacth of news for `today' is received.
- X\fBback_act\fP will maintain copies of the active file for the last 14
- Xdays, which can be used directly to rewind the rc file.
- X.SH FILES
- X.DT
- X.ta \w'$lib/date_regexp'u+3m
- X~/.nn/rc The record of read articles.
- X.br
- X~/.nn/rc.bak1 The original rc file before goback.
- X.br
- X$db/active.\fIN\fP The \fIN\fP days `old' active file.
- X.br
- X$lib/back_act Script run by cron to keep the `old' active files.
- X.br
- X$lib/date_regexp Program to build an egrep(1) pattern.
- X.br
- X$newslib/history The list of all articles in the system.
- X.DT
- X.LP
- XThe \fIdate_regexp\fP program builds an egrep pattern to extract the
- Xhistory file entries for a specified number of days.
- X.LP
- XOn some systems the history file is split into smaller files in a
- Xsubdirectory called history.d; \fBnngoback\fP tries to locate the
- Xright history file to use.
- X.SH SEE ALSO
- Xnn(1), nncheck(1), nngrep(1), nntidy(1)
- X.br
- Xnnadmin(1M), nnquery(1M), nnusage(1M), nnmaster(8)
- X.SH NOTES
- XThe `old' active files method also works with NNTP and with a shared
- Xdatabase (that is why the files are stored in the database directory).
- X.LP
- X\fBnngoback\fP does not check the age of the `old' active files; it
- Xwill blindly believe that active.0 was created today, and that
- Xactive.7 is really seven days old! Therefore, the \fIback_act\fP
- Xscript should be run once and only once every day for \fInngoback\fP
- Xto work properly.
- X.LP
- XWhen the history file is used, days are known to split at 12 midnight.
- XWhen old active files are used, days are counted relative to the time
- Xthe files were saved.
- X.SH AUTHOR
- XKim F. Storm, Texas Instruments A/S, Denmark
- X.br
- XE-mail: storm@texas.dk
- NO_NEWS_IS_GOOD_NEWS
- echo "File nngoback.1 is complete"
- chmod 0644 nngoback.1 || echo "restore of nngoback.1 fails"
- set `wc -c nngoback.1`;Sum=$1
- if test "$Sum" != "3723"
- then echo original size 3723, current size $Sum;fi
- echo "x - extracting nngoback.sh (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > nngoback.sh &&
- X# prefix is inserted above by make
- X
- X# go $1 days back in the news feed and adjust .nn/rc
- X# accordingly.
- X
- XUSE_HIST=false
- Xif [ "$1" = "-h" ]
- Xthen
- X USE_HIST=true
- X shift
- Xfi
- X
- Xif [ $# -ne 1 ]
- Xthen
- X echo "Usage: $0 [-h] days"
- X exit 1
- Xfi
- X
- Xif [ $USE_HIST = false ]
- Xthen
- X if [ -s $DB/active.$1 ]
- X then
- X nntidy - $DB/active.$1
- X else
- X echo $0: No suitable copy of the active file exists -- no update
- X fi
- X exit 0
- Xfi
- X
- XHISTORY="`expr $ACTIVE : '\(/.*/\)'`"history
- X
- Xif [ -s "${HISTORY}" ]
- Xthen
- X :
- Xelif [ -s "${HISTORY}.d/0" ]
- Xthen
- X HISTORY="${HISTORY}.d/*"
- Xelse
- X if $NNTP
- X then
- X echo "$0 is not setup to run with NNTP"
- X exit 2
- X fi
- X echo "Cannot find the history file -- no update"
- X exit 1
- Xfi
- X
- Xecho Working on your nn record file ... do not run nn until completed
- X
- Xecho "NOTICE: this operation is SLOOOOOOOOWWWWWWWW....."
- X
- Xcd
- Xcd .nn
- Xrm -f rc.bak1
- X
- Xtrap "mv rc.bak1 rc ; echo No changes ; exit 0" 1 2 3 13 14 15
- X
- Xmv rc rc.bak1
- X
- X{
- Xecho PHASE_1
- X# news.group last.art.no first.art.no mod
- Xcat $ACTIVE
- X
- Xecho PHASE_2
- X# + last.read.art.no news.group
- Xcat rc.bak1
- X
- Xecho PHASE_3
- X# from date time news.group/art.no ...
- Xcat $HISTORY | egrep "`$LIB/date_regexp $1`"
- X} |
- Xawk '
- XBEGIN{
- X p=0
- X}
- X/^PHASE_/ {
- X p++
- X next
- X}
- Xp == 1 {
- X last[$1]=$2+1
- X next
- X}
- Xp == 2 {
- X if (last[$3] > 0) {
- X subscr[$3] = $1
- X if ($1 == "!") last[$3] = $2 + 1;
- X }
- X next
- X}
- Xp == 3 {
- X for (i = 4; i <= NF; i++) {
- X if (split($i, x, "/") != 2) continue;
- X g=x[1]; n=x[2]
- X if (subscr[g] == "+" && n < last[g]) last[g] = n
- X }
- X}
- XEND {
- X for (g in subscr) printf("%s %06d %s\n", subscr[g], last[g]-1, g)
- X}' | sort +2 > rc
- X
- Xecho "nngoback $1 finished"
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 nngoback.sh || echo "restore of nngoback.sh fails"
- set `wc -c nngoback.sh`;Sum=$1
- if test "$Sum" != "1591"
- then echo original size 1591, current size $Sum;fi
- echo "x - extracting nngrep.1 (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > nngrep.1 &&
- X.TH NNGREP 1 "Release 6.3"
- X.UC 4
- X.SH NAME
- Xnngrep \- grep for news group names
- X.SH SYNOPSIS
- X.B nngrep
- X[ \-\fBa\fP ]
- X.I pattern
- X.SH DESCRIPTION
- X.B nngrep
- Xscan \fInn\fP's rc file for news group names that matches the
- X.I pattern
- Xand print their names on the standard output.
- X.LP
- XFor example, to get the names of all "source" groups, you can use the
- Xcommand
- X.br
- X nngrep source
- X.LP
- XNormally, \fInngrep\fP will only print names of groups to which you subscribe.
- X.LP
- XIf you specify the \-a option, it will print all matching groups in
- Xthe rc file.
- X.LP
- XYou can use this to read a specific subset of news groups with
- X\fInn\fP; for example
- X.br
- X nn -x -snn `nngrep source`
- X.SH FILES
- X.DT
- X.ta \w'~/.nn/rc.bak'u+3m
- X~/.nn/rc The record of read articles
- X.DT
- X.SH SEE ALSO
- Xnn(1), nncheck(1), nngoback(1), nngrep(1)
- X.br
- Xnnadmin(1M), nnquery(1M), nnusage(1M), nnmaster(8)
- X.SH BUGS
- XThe rc file only contains entries for the groups you have actually
- Xread, i.e. new groups which you have not yet read are not printed.
- XTherefore, groups in which no articles have ever been posted will not
- Xshow up either.
- X.LP
- XThis is actually a feature of \fInn\fP: it will
- Xdelay the entry of new groups into the rc file, so it can tell you
- Xthat it is a new group the first time you read it!
- X.SH AUTHOR
- XKim F. Storm, Texas Instruments A/S, Denmark
- X.br
- XE-mail: storm@texas.dk
- X
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 nngrep.1 || echo "restore of nngrep.1 fails"
- set `wc -c nngrep.1`;Sum=$1
- if test "$Sum" != "1337"
- then echo original size 1337, current size $Sum;fi
- echo "x - extracting nngrep.sh (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > nngrep.sh &&
- Xcd
- X
- Xif [ $# -eq 0 ] ; then
- X echo "usage: nngrep -a pattern"
- X exit 1
- Xfi
- X
- Xif [ "$1" = "-a" ] ; then
- X grep "$2" .nn/rc
- Xelse
- X grep "^+ .* .*$1" .nn/rc
- Xfi |
- Xawk '{print $3}'
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 nngrep.sh || echo "restore of nngrep.sh fails"
- set `wc -c nngrep.sh`;Sum=$1
- if test "$Sum" != "169"
- then echo original size 169, current size $Sum;fi
- echo "x - extracting nnmail.c (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > nnmail.c &&
- X/*
- X * nnmail - a mailer that understands @ addressing
- X * when you don't have sendmail or smail
- X */
- X
- X#include "config.h"
- X
- X#include "options.h"
- X
- Xchar * MAILER = MAILX;
- Xstatic int print_vers, test_mode;
- X
- XOption_Description( mail_options ) {
- X
- X 'v', Bool_Option( print_vers ),
- X 'm', String_Option( MAILER ),
- X 't', Bool_Option( test_mode ),
- X
- X '\0',
- X};
- X
- X
- Xmain(argc, argv)
- Xint argc;
- Xchar **argv;
- X{
- X int i, n;
- X char route[512];
- X char *getenv(), *envmail;
- X extern char **environ;
- X
- X if (envmail = getenv("NNMAILER"))
- X MAILER = envmail;
- X
- X n = parse_options(argc, argv, (char *)NULL,
- X mail_options, (char **)NULL, (int (*)())NULL);
- X
- X if (print_vers) {
- X print_version("Release %R.%V.%P #%U\n");
- X nn_exit(0);
- X }
- X
- X#ifndef HAVE_ROUTING
- X if (test_mode) {
- X extern FILE *route_trace;
- X route_trace = stdout;
- X }
- X#endif
- X
- X argv[0] = MAILER;
- X
- X#ifndef HAVE_ROUTING
- X for (i = 1; i <= n; i++)
- X if (reroute(route, argv[i])) {
- X if (test_mode) {
- X printf("%s \t--> %s\n", argv[i], route);
- X continue;
- X }
- X argv[i] = malloc(strlen(route)+1);
- X strcpy(argv[i], route);
- X } else
- X if (test_mode)
- X printf("%s \t*** no route found\n", argv[i]);
- X#endif
- X
- X if (test_mode) nn_exit(0);
- X
- X execve(MAILER, argv, environ);
- X fprintf(stderr, "Mailer '%s' not found\n", MAILER);
- X nn_exit(7);
- X}
- X
- X
- X/*VARARGS*/
- Xuser_error()
- X{
- X}
- X
- Xnn_exit(n)
- X{
- X exit(n);
- X}
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 nnmail.c || echo "restore of nnmail.c fails"
- set `wc -c nnmail.c`;Sum=$1
- if test "$Sum" != "1417"
- then echo original size 1417, current size $Sum;fi
- echo "x - extracting nnmaster.1m (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > nnmaster.1m &&
- X.TH NNMASTER 1M "Release 6.3"
- X.\" (c) Copyright 1988, Kim F. Storm
- X.UC 4
- X.SH NAME
- Xnnmaster \- nn database manager
- X.SH SYNOPSIS
- X.B nnmaster
- X[ \-\fBI\fP ]
- X.br
- X.B nnmaster
- X[ \-\fBw\fP ]
- X.br
- X.B nnmaster
- X[ \-\fBv\fP ]
- X.br
- X.B nnmaster
- X[ \-\fBr [ \fP\fIN\fP ] ]
- X[ \-\fBe\fP\fIN\fP ]
- X[ \-\fBC\fP ]
- X[ \-\fBE\fP ]
- X[ \-\fBu\fP ]
- X[ \-\fBt\fP ]
- X.SH DESCRIPTION
- X.I nnmaster
- Xis the daemon which is responsible for building and maintaining the
- Xdatabase used by the \fInn\fP(1) news reader.
- X.LP
- XNormally,
- X.I nnmaster
- Xis started when the system enters multi-user mode, and runs until
- Xsystem shutdown. To facilitate this, you should place the following
- Xcall in /etc/rc (or similar) to invoke the
- X.I nnmaster
- Xdaemon:
- X.sp 0.5v
- X $lib/nnmaster -r -C
- X.sp 0.5v
- Xwhere $lib is the LIB_DIRECTORY defined during configuration of \fInn\fP.
- X.LP
- XWhen
- X.I nnmaster
- Xis started as specified above, it will first perform a thorough consistency
- Xcheck on the database (option \-C).
- X.LP
- XThen, every 10 minutes (option \-r), it will look at the time-stamp
- Xof the news active file to see whether new articles have arrived on
- Xthe system (or whether articles have been expired).
- X.LP
- XIf the active file has been modified,
- X.I nnmaster
- Xwill collect the header information from the new articles and enter
- Xthem into the database (or remove the headers of the expired articles
- Xfrom the database).
- X.LP
- XIf it detects that some articles have been expired, it will
- Xautomatically remove the header information of the expired articles
- Xfrom the database.
- X.SH OPTIONS
- XThe following options control the behaviour of the \fInnmaster\fP.
- X.TP
- X\-\fBr\fP [ \fImin\fP ]
- X.br
- XDaemon mode. The \fInnmaster\fP will put itself in the background,
- Xand will checks for arrival of new articles and expired articles every
- X.I min
- Xminutes (and update the database accordingly). If
- X.I min
- Xis omitted, the default is to check every 10 minutes.
- X.sp 0.5v
- XWithout the \-r option, the \fInnmaster\fP will just perform a single
- Xcollection of new articles (if any) and then exit. This can be used
- Xto have the \fInnmaster\fP started by
- X.IR cron (8)
- Xat regular intervals instead of having it as a daemon which sleeps
- Xbetween checking for new articles. Since the \fInnmaster\fP is a bit
- Xexpensive to start up (it has to read a few files), it is up to you to
- Xdeside which mode is best on your system. (I have also heard that it
- Xworks to call \fInnmaster\fP without \-r from
- X.IR inews (1).
- XI cannot recommend this unless you receive batched news; invoking
- X\fInnmaster\fP for every received article sounds too expensive to me.)
- X.TP
- X\-\fBe\fP \fIart\fP
- X.br
- XRun internal
- X.I expire
- Xon a group in the database when
- X.I art
- Xarticles has been expired by
- X.IR expire (1M).
- XThe default is to expire a group whenever a single article in the
- Xgroup has been expired. Using this option, you can delay the expiring
- Xof the header information from the database until the specified number
- Xof articles are gone.
- X.sp 0.5v
- XUsing a
- X.I art
- Xvalue of 0 disables the automatic expire completely.
- XThis may be used to keep old article
- X.I headers
- Xonline after the articles have been removed (useful if you backup
- Xexpired articles on tape.) You can then use the Expire command in
- X\fInnadmin\fP(1M) to instruct the \fInnmaster\fP to expire individual
- Xor all groups.
- X.TP
- X.B \-C
- XPerform a consistency check on the database on start-up, and rebuild
- Xcorrupted database files. This operation can be quite time-consuming
- Xsince it reads through all the database files.
- X.TP
- X.B \-E
- XExpire groups by recollecting all available articles.
- X.sp 0.5v
- XThe default method to expire a group is to simply rewrite the database
- Xfiles for that group eliminating the entries for the non-existing
- Xarticles. The problem with the default approach is that it will only
- Xremove the entries for the articles with article number less than the
- Xlowest existing article number (found in the active file). This may
- Xcause problems if there is a single old article with a "distant"
- Xexpire date.
- X.sp 0.5v
- XSince recollecting all articles in a group may be expensive if you
- Xkeep news for a long time, you should not use the \-E option
- Xwithout a little thought.
- X.TP
- X.B \-I
- XInitialize database. This option will erase an existing database, and
- Xcreate an empty database containing entries for the currently known
- Xgroups. Since groups are sometimes identified by a number across
- Xinvokations of \fInn\fP (saved article selections), \fInnmaster\fP
- Xwill offer you to use the same numbering of the news groups as in the
- Xold database (it will ask whether you want to use the old group file).
- X.TP
- X.B \-t
- XTrace the collection process. This will place a lot of information
- Xinto the log file (T: entries). Otherwise, the log file will only
- Xcontain entries reporting the total number of articles collected or
- Xexpired during the collection process.
- X.TP
- X.B \-v
- XPrint the release and version identification for \fInnmaster\fP, and exit.
- X.TP
- X.B \-u
- XNormally, \fInnmaster\fP will just compare the time-stamp on the
- Xactive file with a time-stamp saved in the database to see if new
- Xarticles have arrived. The \-u option forces the \fInnmaster\fP to
- X.I read
- Xthe active file on start-up to see if new articles have arrived; the
- Xfollowing checks (in daemon mode) will still be based on the
- Xtime-stamp of the active file.
- X.TP
- X.B \-w
- XWakeup the real \fInnmaster\fP. Send a signal to the \fInnmaster\fP
- Xdaemon to have it check for new articles immediately.
- X.SH FILES
- XThe $db, $lib, and $news used below are synonyms for the DB_DIRECTORY,
- XLIB_DIRECTORY, and the news system's lib directories respectively.
- X.LP
- X.DT
- X.ta \w'$db/DATA/\fInnn\fP.[dx]'u+3m
- X$db/MASTER Database master index
- X.br
- X$db/GROUPS News group names in MASTER file order
- X.br
- X$db/DATA/\fInnn\fP.[dx] Database files for group number \fInnn\fP
- X.br
- X$lib/GATE Message channel from \fInnadmin\fP to \fInnmaster\fP
- X.br
- X$lib/MPID The process id of the \fInnmaster\fP daemon.
- X.br
- X$lib/Log The log file
- X.br
- X$news/active Existing articles and groups
- X.DT
- X.LP
- XThe MASTER file contains a record for each news group, occurring in
- Xthe same sequence as the group names in the GROUPS file. The sequence
- Xalso defines the group numbers used to identify the files in the
- Xdatabase and in a few other places.
- X.LP
- XThe GATE file will be created by \fInnadmin\fP when needed, and
- Xremoved by \fInnmaster\fP when it has read it. Therefore, to send a
- Xmessage to the \fInnmaster\fP requires that you are allowed to write
- Xin the $lib directory.
- X.LP
- XThe contents of the Log file are described in the \fInnadmin\fP manual.
- X.SH SEE ALSO
- Xnn(1), nncheck(1), nngrep(1), nntidy(1)
- X.br
- Xnnadmin(1M), nnquery(1M), nnusage(1M), nnmaster(8)
- X.SH NOTES
- XThe functionality of the \-e options should be to specify how many
- Xexpired articles should remain in the database. With the current
- Xfunctionality, all "old" headers will be removed from the database
- Xwhen \fInnmaster\fP performs the expire.
- X.LP
- XThe message "Article .... not found" is displayed by \fInn\fP if the
- Xuser has selected an article which is still in the database but has
- Xbeen expired in the news system.
- X.LP
- X\fInnmaster\fP uses the "lowest article number" field in the active
- Xfile to detect that
- X.I expire
- Xhas been run on the group. This "quick check" will not trigger an
- Xinternal expire if the "lowest numbered article" was not removed by
- Xexpire. To expire such a group, you must explicitly request it using
- Xthe Group-Expire command in \fInnadmin\fP(1M).
- X.SH AUTHOR
- XKim F. Storm, Texas Instruments A/S, Denmark
- X.br
- XE-mail: storm@texas.dk
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 nnmaster.1m || echo "restore of nnmaster.1m fails"
- set `wc -c nnmaster.1m`;Sum=$1
- if test "$Sum" != "7469"
- then echo original size 7469, current size $Sum;fi
- echo "x - extracting nnquery.sh (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > nnquery.sh &&
- X# CONFIG file is insert above this line by make
- X
- Xif [ -f ${ACTIVE} ] ; then
- X echo "Cannot locate active file ${ACTIVE}"
- X exit 3
- Xfi
- X
- XOUTAGED=30
- XREADERS=/tmp/nnq$$q
- XDIRS=/tmp/nnq$$d
- Xecho > $DIRS
- X
- X{
- Xsort ${ACTIVE}
- X
- Xawk -F: '{print "%s %s\n", $1, $6}' /etc/passwd |
- Xwhile read user homedir
- Xdo
- X if [ -f $homedir/.nn/rc ] ; then
- X if [ -n "`grep '^'$homedir'$' $DIRS`" ] ; then
- X :
- X else
- X echo $homedir >> $DIRS
- X if [ -n "`find $homedir/.nn -name rc -mtime -$OUTAGED -print`" ] ; then
- X echo $user >> $READERS
- X echo USER $user
- X cat $homedir/.nn/rc
- X fi
- X fi
- X fi
- Xdone
- X} |
- X
- Xawk '
- XBEGIN {
- X a=1
- X g=0
- X}
- X
- X$1 == "USER" {
- X a = 0
- X user = " " $2
- X next
- X}
- X
- Xa == 1 {
- X g++
- X group[$1] = g
- X name[g] = $1
- X# if ($2 == $3) last[g] = 0; else last[g] = $2+0
- X sub[g] = 0
- X users[g] = ""
- X next
- X}
- X
- X$1 == "!" {
- X next
- X}
- X
- X$1 == "+" {
- X n = group[$3]
- X# if ( last[n] == 0 ) next
- X# if ( ($2+200) < last[n] ) next
- X sub[n]++;
- X users[n] = users[n] user
- X next
- X}
- X
- X{
- X next
- X}
- X
- XEND {
- X for (n = 1; n <= g; n++) {
- X printf "%5d %s\t%s\n", sub[n], name[n], users[n]
- X }
- X}' |
- X
- Xif [ "$1" = "-s" ] ; then
- X grep -v "^[ ]*0"
- Xelif [ "$1" = "-u" ] ; then
- X grep "^[ ]*0"
- Xelse
- X cat
- Xfi
- X
- Xrm -f $READERS $DIRS
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 nnquery.sh || echo "restore of nnquery.sh fails"
- set `wc -c nnquery.sh`;Sum=$1
- if test "$Sum" != "1199"
- then echo original size 1199, current size $Sum;fi
- echo "x - extracting nntidy.1 (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > nntidy.1 &&
- X.TH NNTIDY 1 "Release 6.3"
- X.UC 4
- X.SH NAME
- Xnntidy \- tidy your personal \fInn\fP(1) rc file
- X.SH SYNOPSIS
- X.B nntidy
- X.SH DESCRIPTION
- X.B nntidy
- Xwill clean out non-existing groups, adjust obviously wrong article
- Xnumbers, and remove badly formed lines from your rc file.
- X.LP
- XIt will also sort the lines in the rc file in alphabetical order.
- X.LP
- XYou should run
- X.B nntidy
- Xif your rc file has been corrupted for some reason.
- X.SH FILES
- X.DT
- X.ta \w'~/.nn/rc.bak'u+3m
- X~/.nn/rc The record of read articles
- X.br
- X~/.nn/rc.bak The original rc file before tidy
- X.DT
- X.SH SEE ALSO
- Xnn(1), nncheck(1), nngoback(1), nngrep(1)
- X.br
- Xnnadmin(1M), nnquery(1M), nnusage(1M), nnmaster(8)
- X.SH AUTHOR
- XKim F. Storm, Texas Instruments A/S, Denmark
- X.br
- XE-mail: storm@texas.dk
- X
- X
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 nntidy.1 || echo "restore of nntidy.1 fails"
- set `wc -c nntidy.1`;Sum=$1
- if test "$Sum" != "742"
- then echo original size 742, current size $Sum;fi
- echo "x - extracting nntidy.sh (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > nntidy.sh &&
- X# CONFIG file is inserted above during installation
- X
- X# clean out non-existing groups, badly formed lines etc.
- X
- Xif [ ! -s ${2-$ACTIVE} ] ; then
- X echo "$0: Cannot locate active file ${2-$ACTIVE}"
- X exit 3
- Xfi
- X
- Xecho Working on your nn record file ... do not run nn until completed
- X
- Xcd
- Xcd .nn
- Xrm -f rc.bak1
- X
- Xtrap 'mv rc.bak1 rc ; echo "No changes" ; exit 0' 1 2 3 13 14 15
- X
- Xmv rc rc.bak1
- X
- X{
- X cat ${ACTIVE}
- X echo EOA
- X cat rc.bak1
- X
- X} |
- Xawk '
- XBEGIN{
- X act=1
- X}
- X$1 == "EOA" {
- X act=0
- X next
- X}
- XNF==4 {
- X if (act) {
- X X[$1] = 1
- X L[$1] = $2+0
- X if (L[$1] == 0) F[$1] = 0; else F[$1] = $3+0
- X }
- X next
- X}
- X$1 ~ /^#/ {
- X print $0
- X next
- X}
- XNF == 3 && ($1 == "!" || $1 == "+") {
- X if (X[$3] != 1) next
- X S[$3] = $1
- X if (L[$3] >= $2+0)
- X N[$3] = $2+0
- X else
- X N[$3] = F[$3]
- X next
- X}
- XEND {
- X for (g in N) printf("%s %06d %s\n", S[g], N[g], g)
- X}
- X' |
- Xsort +2 > rc
- X
- Xexit 0
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 nntidy.sh || echo "restore of nntidy.sh fails"
- set `wc -c nntidy.sh`;Sum=$1
- if test "$Sum" != "838"
- then echo original size 838, current size $Sum;fi
- echo "x - extracting nntp.c (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > nntp.c &&
- X/*
- X * nntp module for nn.
- X *
- X * The original taken from the nntp 1.5 clientlib.c
- X * Modified heavily for nn.
- X *
- X * Rene' Seindal (seindal@diku.dk) Thu Dec 1 18:41:23 1988
- X *
- X * Last change: Tue May 23 18:38:49 1989
- X */
- X
- X
- X#include "config.h"
- X
- X/*
- X * nn maintains a cache of recently used articles to improve efficiency.
- X * To change the size of the cache, define NNTPCACHE in config.h to be
- X * the new size of this cache.
- X */
- X
- X#ifndef NNTPCACHE
- X#define NNTPCACHE 10
- X#endif
- X
- X#undef DEBUG
- X
- X#ifdef NNTP
- X#include <stdio.h>
- X#include "nntp.h"
- X#include <sys/types.h>
- X#include <sys/socket.h>
- X#include <netdb.h>
- X
- X/* This is necessary due to the definitions in m-XXX.h */
- X#ifdef NETWORK_BYTE_ORDER
- X#include <netinet/in.h>
- X#endif
- X
- Xexport char nntp_server[256]; /* name of nntp server */
- Xexport int use_nntp = 0; /* bool: t iff we use nntp */
- Xexport int nntp_failed = 0; /* bool: t iff connection is broken */
- X /* in nntp_get_article() or nntp_get_active() */
- Ximport int silent;
- Ximport char news_active[];
- X
- Xextern int errno, sys_nerr;
- Xextern char *sys_errlist[];
- X
- X#define syserr() (errno >= 0 && errno < sys_nerr ? \
- X sys_errlist[errno] : "Illegal error.")
- X
- Xextern char *mktemp();
- X
- Xstatic FILE *nntp_in = NULL; /* fp for reading from server */
- Xstatic FILE *nntp_out = NULL; /* fp for writing to server */
- Xstatic int is_connected = 0; /* bool: t iff we are connected */
- Xstatic group_header *group_hd; /* ptr to servers current group */
- Xstatic int is_set = 0; /* bool: t iff group_hd is set */
- X
- X#define ERROR_LEVEL 400 /* All codes below are not errors */
- X
- X
- X/*
- X * nntp_find_server: Find out which host to use as NNTP server.
- X *
- X * This is done by consulting the file NNTP_SERVER (defined in config.h).
- X * Set nntp_server[] to the host's name.
- X */
- X
- Xvoid nntp_find_server()
- X{
- X char *cp, *name, *getenv();
- X char buf[BUFSIZ];
- X FILE *fp;
- X
- X /*
- X * This feature cannot normally be enabled, because the data base
- X * and the users rc file contains references to articles by number,
- X * which is not unique across NNTP servers.
- X */
- X#ifdef DEBUG
- X if ((cp = getenv("NNTPSERVER")) != NULL) {
- X strncpy(nntp_server, cp, sizeof nntp_server);
- X return;
- X }
- X#endif /* DEBUG */
- X
- X name = NNTP_SERVER;
- X if (*name != '/')
- X name = relative(lib_directory, name);
- X
- X if ((fp = open_file(name, OPEN_READ)) != NULL) {
- X while (fgets(buf, sizeof buf, fp) != 0) {
- X if (*buf == '#' || *buf == '\n')
- X continue;
- X if ((cp = strchr(buf, '\n')) != 0)
- X *cp = '\0';
- X strncpy(nntp_server, buf, sizeof nntp_server);
- X fclose(fp);
- X return;
- X }
- X fclose(fp);
- X }
- X
- X if (!is_master)
- X printf("\nCannot find name of NNTP server.\nCheck %s\n", name);
- X
- X sys_error("Failed to find name of NNTP server!");
- X}
- X
- X/*
- X * nntp_check: Find out whether we need to use NNTP.
- X *
- X * This is done by comparing the NNTP servers name with whatever
- X * gethostname() returns.
- X * use_nntp and news_active[] are initialised as a side effect.
- X */
- X
- Xvoid nntp_check()
- X{
- X char host[128];
- X char *cp;
- X
- X nntp_find_server();
- X gethostname(host, sizeof host);
- X use_nntp = strcmp(host, nntp_server) != 0; /* too simplistic ??? */
- X
- X if (use_nntp)
- X strcpy(news_active, relative(db_directory, "ACTIVE"));
- X else
- X strcpy(news_active, NEWS_ACTIVE);
- X}
- X
- X/*
- X * nntp_server_init: initialise a connection to the nntp server.
- X *
- X * It expects nntp_server[] to be set previously, by a call to
- X * nntp_check. It is called from nntp_get_article() and
- X * nntp_get_active() if there is no established connection.
- X */
- X
- Xnntp_server_init()
- X{
- X int sockt_rd, sockt_wr;
- X int response;
- X char line[NNTP_STRLEN];
- X
- X if (!is_master && !silent) {
- X printf("\rConnecting to NNTP server %s ... ", nntp_server);
- X fl;
- X }
- X nntp_failed = 1;
- X
- X sockt_rd = nntp_get_socket();
- X if ((nntp_in = fdopen(sockt_rd, "r")) == NULL)
- X return -1;
- X
- X sockt_wr = dup(sockt_rd);
- X if ((nntp_out = fdopen(sockt_wr, "w")) == NULL) {
- X nntp_in = NULL; /* from above */
- X return -1;
- X }
- X
- X /* Now get the server's signon message */
- X response = nntp_get_server(line, sizeof(line));
- X if (response < 0 || response >= ERROR_LEVEL) {
- X if (!is_master) {
- X user_error("Failed to connect to NNTP server.\n%s",
- X response >= ERROR_LEVEL ? line : syserr());
- X /* NOTREACHED */
- X } else {
- X log_entry('N', "Failed to connect to NNTP server.\n%s",
- X response >= ERROR_LEVEL ? line : syserr());
- X fclose(nntp_out);
- X fclose(nntp_in);
- X return -1;
- X }
- X }
- X if (!is_master && !silent) {
- X fputs("ok.\r", stdout);
- X fl;
- X }
- X is_connected = 1;
- X nntp_failed = 0;
- X return 0;
- X}
- X
- X/*
- X * nntp_get_socket: get a connection to the nntp server.
- X *
- X * Doesn't return in case of errors.
- X */
- X
- Xnntp_get_socket()
- X{
- X int s;
- X struct sockaddr_in sin;
- X struct servent *getservbyname(), *sp;
- X struct hostent *gethostbyname(), *hp;
- X#ifdef h_addr
- X int x = 0;
- X register char **cp;
- X#endif
- X int (*errfct)() = is_master ? sys_error : user_error;
- X
- X if ((sp = getservbyname("nntp", "tcp")) == NULL)
- X (*errfct)("nntp/tcp: Unknown service.\n");
- X
- X if ((hp = gethostbyname(nntp_server)) == NULL)
- X (*errfct)("NNTP server %s unknown.\n", nntp_server);
- X
- X bzero((char *) &sin, sizeof(sin));
- X sin.sin_family = hp->h_addrtype;
- X sin.sin_port = sp->s_port;
- X
- X#ifdef h_addr
- X /* get a socket and initiate connection -- use multiple addresses */
- X
- X for (cp = hp->h_addr_list; cp && *cp; cp++) {
- X s = socket(hp->h_addrtype, SOCK_STREAM, 0);
- X if (s < 0)
- X (*errfct)("Can't get NNTP socket: %s\n", syserr());
- X bcopy(*cp, (char *)&sin.sin_addr, hp->h_length);
- X
- X x = connect(s, (struct sockaddr *)&sin, sizeof (sin));
- X if (x == 0)
- X break;
- X if (!is_master)
- X msg("Connecting to %s: %s", nntp_server, syserr());
- X (void) close(s);
- X }
- X if (x < 0 && !is_master)
- X (*errfct)("Giving up on NNTP server %s!\n", nntp_server);
- X#else /* no name server */
- X if ((s = socket(AF_INET, SOCK_STREAM, 0)) < 0)
- X (*errfct)("Can't get NNTP socket: %s\n", syserr());
- X
- X /* And then connect */
- X bcopy(hp->h_addr, (char *) &sin.sin_addr, hp->h_length);
- X if (connect(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) {
- X if (is_master)
- X (*errfct)("Connecting to %s: %s", nntp_server, syserr());
- X }
- X
- X#endif
- X return s;
- X}
- X
- X/*
- X * nntp_put_server: send a line to the nntp server.
- X *
- X * Expects to be connected to the server.
- X */
- X
- Xnntp_put_server(string)
- Xchar *string;
- X{
- X#ifdef DEBUG
- X msg(">>> %s", string);
- X#endif
- X fprintf(nntp_out, "%s\r\n", string);
- X if (fflush(nntp_out) == EOF) {
- X nntp_error();
- X }
- X}
- X
- X/*
- X * nntp_get_server_line: get a line from the server.
- X *
- X * Expects to be connected to the server.
- X * The line can be any kind of line i.e., either response or text.
- X */
- X
- Xnntp_get_server_line(string, size)
- Xchar *string;
- Xint size;
- X{
- X register char *cp, *nl;
- X
- X errno = 0;
- X if (fgets(string, size, nntp_in) == NULL) {
- X nntp_error();
- X return -1;
- X }
- X for (cp = string, nl = NULL; *cp != NUL; cp++) {
- X if (*cp == CR) {
- X nl = cp;
- X break;
- X }
- X if (nl == NULL && *cp == NL)
- X nl = cp;
- X }
- X if (nl != NULL) *nl = NUL;
- X
- X return 0;
- X}
- X
- X/*
- X * nntp_get_server: get a response line from the server.
- X *
- X * Expects to be connected to the server.
- X * The numerical value of the response is returned.
- X */
- X
- Xnntp_get_server(string, size)
- Xchar *string;
- Xint size;
- X{
- X if (nntp_get_server_line(string, size) < 0)
- X return -1;
- X return isdigit(*string) ? atoi(string) : 0;
- X}
- X
- X/*
- X * nntp_close_server: close the connection to the server.
- X */
- X
- Xnntp_close_server()
- X{
- X if (!is_connected)
- X return;
- X
- X if (!nntp_failed) { /* avoid infinite recursion */
- X char line[NNTP_STRLEN];
- X
- X nntp_put_server("QUIT");
- X (void) nntp_get_server(line, sizeof line);
- X }
- X
- X (void) fclose(nntp_out);
- X (void) fclose(nntp_in);
- X
- X is_connected = 0;
- X}
- X
- X/*
- X * nntp_ask_server: ask the server a question and return the answer.
- X *
- X * Expects to be connected to the server.
- X * Returns the numerical value of the reponse, or -1 in case of errors.
- X */
- X
- Xnntp_ask_server(string, size)
- Xchar *string;
- Xint size;
- X{
- X (void)nntp_put_server(string);
- X
- X if (nntp_get_server(string, size) < 0)
- X return -1;
- X#ifdef DEBUG
- X msg("<<< %.75s", string);
- X#endif
- X return isdigit(*string) ? atoi(string) : 0;
- X}
- X
- X/*
- X * nntp_error: signal an error in talking to the server.
- X *
- X * An nn client terminates a session with the user.
- X * The master simply closes the connection, which is probably
- X * inadequate. nntp_failed is set, for use by the master to
- X * terminate collection.
- X */
- X
- Xnntp_error()
- X{
- X nntp_failed = 1;
- X if (is_master) {
- X log_entry('N', "Lost connection to server %s: %s", nntp_server, syserr());
- X if (is_connected)
- X nntp_close_server();
- X } else {
- X#ifdef DEBUG
- X printf("Can't talk to NNTP server %s: %s", nntp_server, syserr());
- X abort();
- X#else
- X user_error("Can't talk to NNTP server %s: %s", nntp_server, syserr());
- X#endif
- X }
- X}
- X
- X/*
- X * nntp_copy_text: copy text response into file.
- X *
- X * Sends COMMAND to the server, and copies the following text response
- X * into an open file.
- X * Return -1 on error, 0 otherwise.
- X */
- X
- Xnntp_copy_text(fp, command)
- XFILE *fp;
- Xchar *command;
- X{
- X char buf[NNTP_STRLEN];
- X char *cp;
- X int n, nlines;
- X
- X strcpy(buf, command);
- X if ((n = nntp_ask_server(buf, sizeof buf)) < 0) {
- X return -1;
- X }
- X if (n >= ERROR_LEVEL)
- X return -1;
- X
- X nlines = 0;
- X while ((n = nntp_get_server_line(buf, sizeof buf)) >= 0) {
- X cp = buf;
- X if (*cp == '.')
- X if (*++cp == '\0')
- X return nlines > 0 ? 0 : -1;
- X fputs(cp, fp);
- X putc('\n', fp);
- X nlines++;
- X }
- X return -1;
- X}
- X
- X/*
- X * nntp_get_active: get a copy of the active file.
- X *
- X * If we are the master get a copy of the file from the nntp server.
- X * nnadmin just uses the one we already got. In this way the master
- X * can maintain a remote copy of the servers active file.
- X * We try to be a little smart, if not inefficient, about the
- X * modification times on the local active file.
- X * Even when the master is running on the nntp server, a separate
- X * copy of the active file will be made for access via NFS.
- X */
- X
- Xnntp_get_active()
- X{
- X FILE *old, *new;
- X char bufo[NNTP_STRLEN], bufn[NNTP_STRLEN];
- X char *new_name;
- X int same;
- X
- X if (!is_master)
- X return access(news_active, 4);
- X
- X if (!is_connected && nntp_server_init() < 0)
- X return -1;
- X
- X new_name = mktemp(relative(db_directory, ".actXXXXXX"));
- X
- X if ((new = fopen(new_name, "w+")) == NULL)
- X return -1;
- X if (nntp_copy_text(new, "list") < 0) {
- X fclose(new);
- X unlink(new_name);
- X return -1;
- X }
- X rewind(new);
- X same = 0;
- X if ((old = open_file(news_active, OPEN_READ)) != NULL) {
- X do {
- X fgets(bufo, sizeof bufo, old);
- X fgets(bufn, sizeof bufn, new);
- X } while (!feof(old) && !feof(new) && strcmp(bufo, bufn) == 0);
- X same = feof(old) && feof(new);
- X fclose(old);
- X }
- X fclose(new);
- X
- X if (same)
- X unlink(new_name);
- X else
- X if (rename(new_name, news_active) != 0)
- X sys_error("Cannot rename %s to %s", new_name, news_active);
- X
- X return 0;
- X}
- X
- X/*
- X * The following functions implements a simple lru cache of recently
- X * accessed articles. It is a simple way to improve effeciency. Files
- X * must be kept by name, because the rest of the code expects to be able
- X * to open an article multiple times, and get separate file pointers.
- X */
- X
- Xstruct cache {
- X char *file_name; /* file name */
- X article_number art; /* article stored in file */
- X group_header *grp; /* from this group */
- X unsigned time; /* time last accessed */
- X} cache[NNTPCACHE];
- X
- Xstatic unsigned cur_time = 1; /* virtual time */
- X
- X/*
- X * nntp_search_cache: search the cache for an (article, group) pair.
- X *
- X * Returns a pointer to the slot where it is, null otherwise
- X */
- X
- Xstruct cache *nntp_search_cache(art, gh)
- Xarticle_number art;
- Xgroup_header *gh;
- X{
- X struct cache *cptr = cache;
- X int i;
- X
- X for (i = 0; i < NNTPCACHE; i++, cptr++)
- X if (cptr->art == art && cptr->grp == gh) {
- X cptr->time = cur_time++;
- X return cptr;
- X }
- X return NULL;
- X}
- X
- X/*
- X * nntp_new_slot: get a free cache slot.
- X *
- X * Returns a pointer to the allocated slot.
- X * Frees the old filename, and allocates a new, unused filename.
- X * The user's files are in ~/.nn, and the master's are in LIB_DIRECTORY.
- X */
- X
- Xstruct cache *nntp_new_slot()
- X{
- X struct cache *cptr = cache;
- X int i, lru;
- X unsigned min_time = cur_time;
- X char name[24];
- X
- X for (i = 0; i < NNTPCACHE; i++, cptr++)
- X if (min_time > cptr->time) {
- X min_time = cptr->time;
- X lru = i;
- X }
- X cptr = &cache[lru];
- X
- X if (cptr->file_name) {
- X unlink(cptr->file_name);
- X free(cptr->file_name);
- X }
- X sprintf(name, "nn%02d-XXXXXX", lru);
- X cptr->file_name =
- X copy_str(relative(is_master ? lib_directory : nn_directory,
- X mktemp(name)));
- X cptr->time = cur_time++;
- X#ifdef DEBUG
- X msg("cache: select slot %d, file name %s", lru, cptr->file_name);
- X#endif
- X return cptr;
- X}
- X
- X/*
- X * nntp_clean_cache: clean up the cache.
- X *
- X * Removes all allocated files.
- X */
- X
- Xvoid nntp_clean_cache()
- X{
- X struct cache *cptr = cache;
- X int i;
- X
- X for (i = 0; i < NNTPCACHE; i++, cptr++)
- X if (cptr->file_name)
- X unlink(cptr->file_name);
- X}
- X
- X/*
- X * nntp_set_group: set the server's current group.
- X *
- X * Actual communication is delayed until an article is accessed, to
- X * avoid unnecessary traffic.
- X */
- X
- Xnntp_set_group(gh)
- Xgroup_header *gh;
- X{
- X group_hd = gh;
- X is_set = 0;
- X return 0;
- X}
- X
- X/*
- X * nntp_get_article: get an article from the server.
- X *
- X * Returns a FILE pointer.
- X * If necessary the server's current group is set.
- X * The article (header and body) are copied into a file, so they
- X * are seekable (nn likes that).
- X */
- X
- XFILE *nntp_get_article(article)
- Xarticle_number article;
- X{
- X char buf[NNTP_STRLEN];
- X FILE *tmp;
- X struct cache *cptr;
- X int n;
- X
- X if (!is_connected && nntp_server_init() < 0) {
- X return NULL;
- X }
- X
- X /*
- X * Set the server group to the current group
- X */
- X if (is_set == 0) {
- X sprintf(buf, "group %s", group_hd->group_name);
- X if ((n = nntp_ask_server(buf, sizeof buf)) < 0){
- X return NULL;
- X }
- X if (n >= ERROR_LEVEL)
- X return NULL;
- X is_set = 1;
- X }
- X /*
- X * Search the cache for the requested article,and allocate a new
- X * slot if necessary.
- X */
- X cptr = nntp_search_cache(article, group_hd);
- X if (cptr != 0) {
- X return open_file(cptr->file_name, OPEN_READ);
- X }
- X cptr = nntp_new_slot();
- X
- X if ((tmp = open_file(cptr->file_name, OPEN_CREATE)) == NULL)
- X return NULL;
- X
- X /*
- X * Copy the article.
- X */
- X sprintf(buf, "article %d", article);
- X if (nntp_copy_text(tmp, buf) < 0) {
- X fclose(tmp);
- X return NULL;
- X }
- X fclose(tmp);
- X if ((tmp = open_file(cptr->file_name, OPEN_READ)) != NULL) {
- X cptr->art = article;
- X cptr->grp = group_hd;
- X }
- X return tmp;
- X}
- X
- X/*
- X * nntp_cleanup: clean up after an nntp session.
- X *
- X * Called from nn_exit().
- X */
- X
- Xnntp_cleanup()
- X{
- X if (is_connected)
- X nntp_close_server();
- X nntp_clean_cache();
- X}
- X#endif /* NNTP */
- X
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 nntp.c || echo "restore of nntp.c fails"
- set `wc -c nntp.c`;Sum=$1
- if test "$Sum" != "15036"
- then echo original size 15036, current size $Sum;fi
- echo "x - extracting nntp.h (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > nntp.h &&
- X/*
- X * Response codes for NNTP server
- X *
- X * @(#)nntp.h 1.7 (Berkeley) 1/11/88
- X *
- X * First digit:
- X *
- X * 1xx Informative message
- X * 2xx Command ok
- X * 3xx Command ok so far, continue
- X * 4xx Command was correct, but couldn't be performed
- X * for some specified reason.
- X * 5xx Command unimplemented, incorrect, or a
- X * program error has occured.
- X *
- X * Second digit:
- X *
- X * x0x Connection, setup, miscellaneous
- X * x1x Newsgroup selection
- X * x2x Article selection
- X * x3x Distribution
- X * x4x Posting
- X */
- X
- X#define CHAR_INF '1'
- X#define CHAR_OK '2'
- X#define CHAR_CONT '3'
- X#define CHAR_ERR '4'
- X#define CHAR_FATAL '5'
- X
- X#define INF_HELP 100 /* Help text on way */
- X#define INF_DEBUG 199 /* Debug output */
- X
- X#define OK_CANPOST 200 /* Hello; you can post */
- X#define OK_NOPOST 201 /* Hello; you can't post */
- X#define OK_SLAVE 202 /* Slave status noted */
- X#define OK_GOODBYE 205 /* Closing connection */
- X#define OK_GROUP 211 /* Group selected */
- X#define OK_GROUPS 215 /* Newsgroups follow */
- X#define OK_ARTICLE 220 /* Article (head & body) follows */
- X#define OK_HEAD 221 /* Head follows */
- X#define OK_BODY 222 /* Body follows */
- X#define OK_NOTEXT 223 /* No text sent -- stat, next, last */
- X#define OK_NEWNEWS 230 /* New articles by message-id follow */
- X#define OK_NEWGROUPS 231 /* New newsgroups follow */
- X#define OK_XFERED 235 /* Article transferred successfully */
- X#define OK_POSTED 240 /* Article posted successfully */
- X
- X#define CONT_XFER 335 /* Continue to send article */
- X#define CONT_POST 340 /* Continue to post article */
- X
- X#define ERR_GOODBYE 400 /* Have to hang up for some reason */
- X#define ERR_NOGROUP 411 /* No such newsgroup */
- X#define ERR_NCING 412 /* Not currently in newsgroup */
- X#define ERR_NOCRNT 420 /* No current article selected */
- X#define ERR_NONEXT 421 /* No next article in this group */
- X#define ERR_NOPREV 422 /* No previous article in this group */
- X#define ERR_NOARTIG 423 /* No such article in this group */
- X#define ERR_NOART 430 /* No such article at all */
- X#define ERR_GOTIT 435 /* Already got that article, don't send */
- X#define ERR_XFERFAIL 436 /* Transfer failed */
- X#define ERR_XFERRJCT 437 /* Article rejected, don't resend */
- X#define ERR_NOPOST 440 /* Posting not allowed */
- X#define ERR_POSTFAIL 441 /* Posting failed */
- X
- X#define ERR_COMMAND 500 /* Command not recognized */
- X#define ERR_CMDSYN 501 /* Command syntax error */
- X#define ERR_ACCESS 502 /* Access to server denied */
- X#define ERR_FAULT 503 /* Program fault, command not performed */
- X
- X/* RFC 977 defines this; don't change it. */
- X
- X#define NNTP_STRLEN 512
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 nntp.h || echo "restore of nntp.h fails"
- set `wc -c nntp.h`;Sum=$1
- if test "$Sum" != "2530"
- then echo original size 2530, current size $Sum;fi
- echo "x - extracting nnusage.1m (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > nnusage.1m &&
- X.TH NNUSAGE 1M "Release 6.1"
- X.UC 4
- X.SH NAME
- Xnnusage \- display \fInn\fP usage statistics
- X.SH SYNOPSIS
- X.B nnusage
- X[ -t ]
- X.SH DESCRIPTION
- X.B nnusage
- Xwill extract the usage entries from the log file and calculate the
- Xtotal usage time for each \fInn\fP user.
- X.LP
- XWithout options, the output will be sorted according to user names.
- X.LP
- XWith the \-t option, \fInnusage\fP will list the users ordered after
- Xthe total usage time.
- X.LP
- XSince it is possible to
- Xsuspend
- X\fInn\fP, or leave the terminal while \fInn\fP is active, \fInn\fP
- Xtries to be intelligent when it calculates the usage time so it will
- Xtruly report the actual time spent on news reading.
- X.SH FILES
- X.DT
- X.ta \w'$lib/Log'u+3m
- X$lib/Log The log file
- X.DT
- X.SH SEE ALSO
- Xnn(1), nncheck(1), nngoback(1), nngrep(1), nntidy(1)
- X.br
- Xnnadmin(1M), nnquery(1M), nnmaster(8)
- X.SH NOTES
- XThe \fInn\fP package must have been compiled with the STATISTICS
- Xoption turned on to produce the usage entries in the log file.
- X.LP
- XOnly \fInn\fP sessions longer than 5 minutes are registered in the log file.
- X.SH AUTHOR
- XKim F. Storm, Texas Instruments A/S, Denmark
- X.br
- XE-mail: storm@texas.dk
- X
- X
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 nnusage.1m || echo "restore of nnusage.1m fails"
- set `wc -c nnusage.1m`;Sum=$1
- if test "$Sum" != "1119"
- then echo original size 1119, current size $Sum;fi
- echo "x - extracting nnusage.sh (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > nnusage.sh &&
- X# CONFIG file is inserted here
- X
- Xif [ x"$1" = x'-t' ] ; then
- X SORTMODE="+1r"
- Xelse
- X SORTMODE=""
- Xfi
- X
- Xgrep '^U:' $LIB/Log |
- X
- Xawk '
- XNF == 7 {
- X if (split($7, t, ".") == 2) u[$5] += t[1] * 60 + t[2]
- X}
- XEND {
- X for (n in u) {
- X name=substr(n, 2, length(n)-3)
- X printf("%s%16d.%02d\n", name, u[n]/60, u[n]%60);
- X }
- X}' |
- X
- Xsort $SORTMODE
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 nnusage.sh || echo "restore of nnusage.sh fails"
- set `wc -c nnusage.sh`;Sum=$1
- if test "$Sum" != "326"
- then echo original size 326, current size $Sum;fi
- echo "x - extracting options.c (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > options.c &&
- X/*
- X * generic option parsing
- X *
- X * (c) Copyright 1988, Kim F. Storm, storm@texas.dk
- X */
- X
- X#include "config.h"
- X#include "options.h"
- X
- Xstatic char **save_argv, *usage_mesg;
- Xstatic struct option_descr *save_optd;
- X
- Xchar *program_name(av)
- Xchar **av;
- X{
- X char *cp;
- X
- X /* skip "/path/" part of program name */
- X if (cp = strrchr(*av, '/'))
- X return cp + 1;
- X else
- X return *av;
- X}
- X
- X
- Xparse_options(ac, av, envname, options, usage)
- Xint ac;
- Xchar **av, *envname;
- Xstruct option_descr options[];
- Xchar *usage;
- X{
- X register char *cp, opt;
- X register struct option_descr *od;
- X extern int atoi();
- X int files;
- X char **names;
- X char *envinit;
- X
- X save_argv = av;
- X save_optd = options;
- X
- X if (options == NULL) return 0;
- X
- X usage_mesg = usage;
- X
- X --ac;
- X names = ++av;
- X files = 0;
- X
- X envinit = envname ? getenv(envname) : NULL;
- X cp = envinit;
- X
- X next_option:
- X
- X if (envinit) {
- X while (*cp && isspace(*cp)) cp++;
- X if (*cp == '-') {
- X cp++;
- X goto next_option;
- X }
- X if (*cp == NUL) {
- X envinit = NULL;
- X goto next_option;
- X }
- X } else
- X if (cp == NULL || *cp == NUL) {
- X if ((cp = *av++) == NULL) {
- X *names = NULL;
- X return files;
- X }
- X ac--;
- X
- X if (*cp != '-') {
- X *names++ = cp;
- X cp = NULL;
- X files++;
- X goto next_option;
- X }
- X
- X cp++; /* skip - */
- X }
- X
- X opt = *cp++;
- X
- X for (od = options; od->option_letter; od++) {
- X if (od->option_letter != opt) continue;
- X
- X switch (od->option_type) {
- X
- X case 1: /* BOOL_OPTION */
- X
- X *((int *)(od->option_address)) = !*((int *)(od->option_address));
- X goto next_option;
- X
- X case 2: /* STRING_OPTION */
- X case 3: /* OPTIONAL_STRING */
- X
- X /* -oSTR or -o STR */
- X
- X while (*cp && isspace(*cp)) cp++;
- X
- X if (*cp == NUL) {
- X if (envinit || ac == 0) {
- X if (od->option_type == 3) goto opt_str;
- X error("missing string argumet to -%c", opt);
- X }
- X cp = *av++;
- X ac--;
- X }
- X
- X if (od->option_type == 3 && *cp == '-') goto opt_str;
- X
- X *(od->option_address) = cp;
- X
- X if (envinit) {
- X while (*cp && !isspace(*cp)) cp++;
- X if (*cp) *cp++ = NUL;
- X } else
- X cp = NULL;
- X
- X goto next_option;
- X
- X opt_str:
- X *(od->option_address) = od->option_default;
- X goto next_option;
- X
- X case 4:
- X case 5:
- X
- X /* -oN or -o N */
- X
- X while (*cp && isspace(*cp)) cp++;
- X
- X if (*cp) {
- X if (!isdigit(*cp)) {
- X if (od->option_type == 5) goto opt_int;
- X error("non-numeric argument to -%c", opt);
- X }
- X } else {
- X if (envinit || ac == 0 || !isdigit(**av)) {
- X if (od->option_type == 5) goto opt_int;
- X error("missing argument to -%c", opt);
- X }
- X
- X cp = *av++;
- X ac--;
- X }
- X *((int *)(od->option_address)) = atoi(cp);
- X while (isdigit(*cp)) cp++;
- X goto next_option;
- X
- X opt_int:
- X *((int *)(od->option_address)) = (int)(od->option_default);
- X goto next_option;
- X }
- X }
- X
- X error("unknown option '-%c'", opt);
- X /*NOTREACHED*/
- X}
- X
- X
- Xstatic error(message, option_letter)
- Xchar *message, option_letter;
- X{
- X char *prog_name = program_name(save_argv);
- X
- X fprintf(stderr, "%s: ", prog_name);
- X fprintf(stderr, message, option_letter);
- X fputc('\n', stderr);
- X
- X fprintf(stderr, "usage: %s", prog_name);
- X
- X dump_options(1, "");
- X dump_options(2, " STR");
- X dump_options(3, " [STR]");
- X dump_options(4, " NUM");
- X dump_options(5, " [NUM]");
- X
- X if (usage_mesg) fprintf(stderr, usage_mesg);
- X fputc(NL, stderr);
- X
- X nn_exit(9);
- X}
- X
- Xstatic dump_options(type, tail)
- Xint type;
- Xchar *tail;
- X{
- X register struct option_descr *od;
- X int any = 0;
- X
- X for (od = save_optd; od->option_letter; od++) {
- X if (od->option_type != type) continue;
- X fprintf(stderr, any ? "%c" : " -%c", od->option_letter );
- X any++;
- X }
- X
- X if (any && tail && tail[0]) {
- X fprintf(stderr, "%s", tail);
- X }
- X}
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 options.c || echo "restore of options.c fails"
- set `wc -c options.c`;Sum=$1
- if test "$Sum" != "3891"
- then echo original size 3891, current size $Sum;fi
- echo "x - extracting options.h (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > options.h &&
- X/*
- X * options.h - include file for generic option parsing
- X *
- X * (c) Copyright 1988, Kim F. Storm, storm@texas.dk
- X */
- X
- X/*
- X * To use this routine, you must a table called an Option_Description.
- X * Each element in this table describes one possible option:
- X * Its option letter
- X * Its argument type (if any)
- X * Whether an argument is mandatory or optional
- X * The address of the variable holding the option value
- X * The defualt value if argument is optional
- X *
- X * Example:
- X *
- X * A program accepts the following options:
- X * -a [no value]
- X * -b N [a numeric value]
- X * -p [N] [an optional numeric value]
- X * -t S [a string value]
- X *
- X * The corresponding option description table would then look like:
- X *
- X * #include <options.h>
- X * int a_flg = 1, b_value = 0, p_value = 0;
- X * char *t_string = "default";
- X *
- X * Option_Description( options ) {
- X * 'a', Bool_Option(a_flg),
- X * 'b', Int_Option(b_value),
- X * 'p', Int_Option_Optional(p_value, -1),
- X * 't', String_Option(t_string),
- X * '\0',
- X * }
- X * To parse the argument list - and the contents of the environment variable
- X * XXINIT, all that has to be done is to issue the following call:
- X *
- X * files = parse_options(argc, argv, "XXINIT", options, NULL);
- X *
- X * If no environment variable is associated with the program, use NULL as
- X * the third parameter.
- X *
- X * Upon return, the elements argv[1] .. argv[files] will contain
- X * the file names (and other 'non-options') that occur in the argument list.
- X *
- X * The last NULL argument may be replaced by your own 'usage routine'
- X * which will be called in the following way:
- X *
- X * usage(pname)
- X * char *pname; /+ argv[0] without path +/
- X *
- X *
- X * char *program_name(argv)
- X *
- X * return a pointer to the last component of argv[0] (the program name with
- X * with the path deleted).
- X *
- X
- X */
- X
- X
- Xstruct option_descr {
- X char option_letter;
- X char option_type;
- X char ** option_address;
- X char * option_default;
- X} ;
- X
- X
- X#define Option_Description(name) \
- X struct option_descr name[] =
- X
- X#define Bool_Option(addr) \
- X 1, (char **)(&addr), (char *)0
- X
- X#define String_Option(addr) \
- X 2, &addr, (char *)0
- X
- X#define String_Option_Optional(addr, default) \
- X 3, &addr, default
- X
- X#define Int_Option(addr) \
- X 4, (char **)(&addr), (char *)0
- X
- X#define Int_Option_Optional(addr, default) \
- X 5, (char **)(&addr), (char *)default
- NO_NEWS_IS_GOOD_NEWS
- chmod 0644 options.h || echo "restore of options.h fails"
- set `wc -c options.h`;Sum=$1
- if test "$Sum" != "2333"
- then echo original size 2333, current size $Sum;fi
- echo "x - extracting pack_date.c (Text)"
- sed 's/^X//' << 'NO_NEWS_IS_GOOD_NEWS' > pack_date.c &&
- X#include "config.h"
- X
- X/* #define DATE_TEST /* never define this !! */
- X
- X/*
- X * Calculate an approximate "time_stamp" value for a date
- X * string. The actual value is not at all critical,
- NO_NEWS_IS_GOOD_NEWS
- echo "End of part 11"
- echo "File pack_date.c is continued in part 12"
- echo "12" > s2_seq_.tmp
- exit 0
- ---
- Kim F. Storm storm@texas.dk Tel +45 429 174 00
- Texas Instruments, Marielundvej 46E, DK-2730 Herlev, Denmark
- No news is good news, but nn is better!
-
-