🚀 go-pugleaf

RetroBBS NetNews Server

Inspired by RockSolid Light RIP Retro Guy

Article View: dnet.general
Article #2159

News-Abrechnung

#2159
From: News Administrator
Date: Thu, 29 Jun 1989 12:22
892 lines
23590 bytes
Hi allesamt!

Da die news ja jetzt volumenmaessig abgerechnet werden,
wir aber nur von einer (1!) Site die Menge der weiterverteilten
News bekommen, hier nochmal fuer alle unsere Abrechnungssoftware.

Jeder, der News weiterverteilt, muss diese veraenderte Batcherversion
und die zugehoerigen Programme bei sich installieren, alle anderen
sollten sie sich fuer den Fall der Faelle aufheben.

Wenn wir von einer Site, die News weiterverteilt, keine Abrechnungsdaten
erhalten, so muessen wir leider fuer die angeschlossenen Sites das 
gleiche Volumen wie fuer die weiterverteilende Site berechnen.

Alles verstanden? Wenn nicht, bitte Fragen an mich.

	Gruesse
		Jan-Hinrich

So und nun folgt die Software: (bis auf die Telephongebuehren gratis ;-)

#! /bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #! /bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create:
#	Makefile
#	README
#	accounting.sh
#	batch.c
#	monthly.sh
#	newsacc.c
#	newsbatch
# This archive created: Thu Jun 29 13:05:30 1989
export PATH; PATH=/bin:/usr/bin:$PATH
if test -f 'Makefile'
then
	echo shar: "will not over-write existing file 'Makefile'"
else
cat << \SHAR_EOF > 'Makefile'
newsacc: newsacc.c
	cc -O -o newsacc newsacc.c
SHAR_EOF
fi
if test -f 'README'
then
	echo shar: "will not over-write existing file 'README'"
else
cat << \SHAR_EOF > 'README'
	Installation der Newsaccounting Software

Die Accountingsoftware besteht aus den Dateien:

-rw-r--r--  1 news     news           47 Jul  6  1988 Makefile
-rw-r--r--  1 news     news         4777 Jun 29 13:01 README
-rwxr-xr-x  1 news     news          731 Dec 19  1988 accounting.sh
-rw-r--r--  1 news     news         7470 Mar 26  1988 batch.c
-rwxr-xr-x  1 news     news          777 Mar 31 18:50 monthly.sh
-rw-rw-r--  1 news     news         4450 Apr 26 17:47 newsacc.c
-rwxr-xr-x  1 news     news         1718 Aug 15  1988 newsbatch

Das zentrale Programm newsacc wird benutzt, um die Accountingdaten nach
verschiedenen Kriterien zu summieren und sortieren.

Das Programm batch ist eine modifizierte Version des News2.11 batch.
Zusaetzlich zu den Funktionen des originalen batch wird fuer jeden Artikel,
der ge'batch'ed wird, sein Newsgruppenname und seine Laenge in Bytes in
einer Datei mitgeschnitten.

Das Shellscript newsbatch ist ein Ersatz fuer das sendbatch Shellscript.
Das newsbatch Script liest die Liste der zu versorgenden Sites aus einer
Konfigurierungsdatei und achtet auch auf die Plattenauslastung.


Das Shellscript accounting.sh sollte einmal pro Nacht aufgerufen werden, um
die Accountingdaten aufzusummieren.
Das Shellscript monthly.sh wird benutzt, um eine monatliche Uebersicht ueber
die verschickten News zu generieren.



1. Format der Accountingdaten

Die Daten der Sites befinden sich in dem Directory /usr/spool/news/accounting.
Dieser Pfad ist in allen oben genannten Programmen und Scripten fest enthalten.
In diesem Directory findet man fuer jeden Site folgende Dateien:

site.accounting
	In dieser Datei protokolliert das Programm batch die Artikel und
	deren Laenge.

site.yesterday
	Dies ist ein Backup der alten Datei site.accounting, das von dem
	Script accounting.sh angelegt wird.

site
	Diese Datei enthaelt die verschickten News pro Gruppe und stellt
	die Summierung aller bisherigen Accountingdaten dar.  Sie wird
	jede Nacht von dem Script accounting.sh aus der alten Datei site
	und site.acounting des Tages erzeugt.

site.datum
	Dies ist ein Backup von site des angegebenen Datums.
	Es wird monatlich von monthly.sh erzeugt.

Das Format dieser Dateien ist zeilenweise
Newsgruppenname	Bytes
Die Zeilen sind nach den Gruppennamen geordnet.


2. Batch

Um die Accountingsoftware zu benutzen, muss man die News gebatched
verschicken.  Das modifizierte Batch Programm hat einen dritten
Parameter erhalten, der die Lage des Direktories der Accountingdaten
angibt.  Das Batch Programm sollte einfach uebersetzt werden, und an
Stelle des alten Batch Programms installiert werden.

Anstelle des ueblichen sendbatch Scripts sollte man das neue newsbatch
Script verwenden, dass das batch Programm mit den richtigen Parametern
versorgt.  (Man kann natuerlich auch das sendbatch aendern)  Das
newsbatch Script bezieht seine Informationen ueber die zu verschickenden
News nicht ueber seine Argumente, sondern aus eine speziellen Datei.
Diese ist per default
	/usr/lib/news/news.list.
In dieser Datei sollte fuer jede Site, die mit News versorgt wird, eine
Zeile stehen. Die Zeilen bestehen aus 6 Feldern (mit Blank oder Tab getrennt):

1. Feld:	yes oder no.	Besagt, ob News verteilt werden sollen.

2. Feld:	Grade.		Wenn das UUCP keine Grades versteht,
				sollte man dies aus dem newsbatch Script
				loeschen.

3. Feld:	Site.		Der Name der Site, die News erhalten soll.

4. Feld:	Size.		Die gewuenschte Groesse der Batchfiles.
				50000 ist ein guter Wert.

5. Feld:	Compress.	Entweder no, wenn nicht komprimiert werden
				soll, oder die Bitoption.
				Bsp.: -b16 oder -b12

6. Feld:	Accounting.	Entweder s, t, a oder no. (Siehe newsacc)

Beispiel:
yes N	tub	50000	-b16	s


3. Newsacc

  Das Programm newsacc wird benutzt, um die von batch erzeugten
Accountingdaten aufzuarbeiten.  Es wird mit
	newsacc -[ast] file
aufgerufen, wobei file der Name der Accountingdaten ist.
(z.B.: /usr/spool/news/accounting/tub.accounting)

Die Optionen sind:

-s	Gibt auf stdout eine sortierte, summierte Liste aller Newsgruppen aus.
-t	Gibt auf stdout die sortierte Liste aller Newsgruppen, summiert
	nach den Toplevelgruppen (comp, news, rec usw.) aus
-a	Gibt auf stdout die Summe aller in internationalen Gruppen
	verschickten News aus.

	Die kostenpflichtigen Gruppen werden unter dem #define COSTLY
	definiert.


4. accounting.sh und monthly.sh

Das Script accounting.sh sollte einmal pro Nacht aufgerufen werden.
Fuer jeden Site in news.list summiert es Gruppenweise die Daten aus
site und site.accounting auf, legt die Summe unter site.yesterday
und site ab und loescht site.accounting.

Das Script monthly.sh sollte als Vorschlag dienen, die summierten Newsdaten
einmal pro Monat zur Verrechnung an unido zu schicken.



	Viel Spass,

	Jan-Hinrich
SHAR_EOF
fi
if test -f 'accounting.sh'
then
	echo shar: "will not over-write existing file 'accounting.sh'"
else
cat << \SHAR_EOF > 'accounting.sh'
#! /bin/sh

# create a summary of sent newsgroups for each site in ~news/news.list

ACCDIR=/usr/spool/news/accounting
LISTFILE=/usr/lib/news/news.list
WEEKFILE=/usr/lib/news/weekly.list

while read zeile
do
	set $zeile
	SITE=$1
	/bin/mv $ACCDIR/$SITE.weekly $ACCDIR/$SITE.work
	/bin/cat $ACCDIR/$SITE.accounting >> $ACCDIR/$SITE.work
	/usr/local/newsacc -s $SITE.work > $ACCDIR/$SITE.weekly
	/bin/rm  $ACCDIR/$SITE.work
done < $WEEKFILE


while read zeile
do
	set $zeile
	SITE=$3
	/bin/mv $ACCDIR/$SITE $ACCDIR/$SITE.wrk
	/bin/cat $ACCDIR/$SITE.accounting >> $ACCDIR/$SITE.wrk
	rm $ACCDIR/$SITE.accounting
	/usr/local/newsacc -s $SITE.wrk > $ACCDIR/$SITE
	mv $ACCDIR/$SITE.wrk $ACCDIR/$SITE.yesterday
done < $LISTFILE
rm $TMPFILE

SHAR_EOF
chmod +x 'accounting.sh'
fi
if test -f 'batch.c'
then
	echo shar: "will not over-write existing file 'batch.c'"
else
cat << \SHAR_EOF > 'batch.c'

/*
 * This software is Copyright (c) 1985 by Rick Adams.
 *
 * Permission is hereby granted to copy, reproduce, redistribute or
 * otherwise use this software as long as: there is no monetary
 * profit gained specifically from the use or reproduction or this
 * software, it is not sold, rented, traded or otherwise marketed, and
 * this copyright notice is included prominently in any copy
 * made.
 *
 * The author make no claims as to the fitness or correctness of
 * this software for any use whatsoever, and it is provided as is. 
 * Any use of this software is at the user's own risk.
 *
 * Batch: program to batch a list of news articles into an unbatch script.
 * Usage: /usr/lib/news/batch listfile [bytecount]
 *  where listfile is a file containing a list, one per line, of full
 *  path names of files containing articles, e.g. as produced by the F
 *  transmission option in the sys file.
 *  bytecount is the maximum number of bytes to output before exiting
 * Output is placed on standard output.
 *
 * Intended usage:
 *
 *	With the shellfile "sendbatch", with machine names as arguments:
 * 		e.g
 *		sendbatch rlgvax seismo
 *
 * This would be invoked every hour or two from crontab.
 *
 * Accounting stuff added by Andreas Toenne <atoenne@unido.uucp>
 * 
 * If ACCOUNTING is defined the groupname and size will be logged 
 * for all articels in the listfile. 
 * The default logfile is /tmp/sitename.account and may be overun by
 * setting a third argument :
 * batch listfile [bytecount] [logfiledir]
 *
 */

#define ACCOUNTING

#ifdef SCCSID
static char	*SccsId = "@(#)batch.c	1.20	11/30/87";
#endif /* SCCSID */

#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <errno.h>
#include "defs.h"

#if defined(USG) || defined(BSD4_2)
#include <fcntl.h>
#endif

struct stat sbuf;

extern int errno;
extern char *sys_errlist[];
#ifdef ACCOUNTING
extern char *rindex();
#endif

main(argc,argv)
char **argv;
{
	register FILE *fd, *nfd;
	register int c;
	register long n;
	register char *cp;
	char *fdstatus;
	long maxbytes, nbytes;
	long atol();
	char fname[512];
	char workfile[512];
	char cbuf[BUFSIZ];
	char *index(), *fgets();
#ifdef ACCOUNTING
	FILE *accountingFile;
	char accountingFileName[512];
	char accountingGroupName[512];
	int i,j;
#endif

	if (argc < 2) {
		fprintf(stderr, "Usage: batch listfile [bytecount] [accounting filename]\n");
		exit(1);
	}

	/*
	 * Rename real file to a work name to avoid race conditions.
	 * If workfile exists skip the rename in order
	 * to recover from a crash w/o losing anything.
	 */
	(void) strcpy(workfile, argv[1]);
	(void) strcat(workfile, ".work");
	if (access(workfile, 0) < 0) {
		if (access(argv[1], 0) < 0 && errno == ENOENT)
			exit(0);	/* no news */
		if (rename(argv[1], workfile) < 0) {
			logerror("rename(%s,%s) %s", argv[1], workfile,
				sys_errlist[errno]);
			exit(1);
		}
	}
	fd = fopen(workfile, "r");
	if (fd == NULL) {
		logerror("fopen(%s,r) %s", workfile, sys_errlist[errno]);
		exit(1);
	}
#ifdef ACCOUNTING
	/* get default accounting dir */
	(void) strcpy(accountingFileName, "/tmp");
#endif

	if (argc > 2)
		maxbytes = atol(argv[2]);
	else
		maxbytes = 100000000L; /* backwards compatible */
#ifdef ACCOUNTING
	/* if maxbytes is 0L, we got no bytecount but only */
	/* an accounting filename */
	if (maxbytes == 0L)
	{
		maxbytes = 100000000L;
		strcpy(accountingFileName, argv[2]);
	}
	if (argc > 3)
		strcpy(accountingFileName,argv[3]);
	strcat(accountingFileName, "/");
	cp = rindex(argv[1], '/');
	if (cp)
		strcat(accountingFileName, cp);
	else
		strcat(accountingFileName, argv[1]);
	strcat(accountingFileName, ".accounting");
	accountingFile = fopen(accountingFileName, "a");
	if (accountingFile == NULL) {
		logerror("fopen(%s,a) %s", accountingFileName, sys_errlist[errno]);
		exit(1);
	}
#endif
	nbytes = 0;
	while ((fdstatus = fgets(fname, sizeof fname, fd)) != NULL) {
		cp = index(fname, '\n');
		if (cp)
			*cp = '\0';
		if (fname[0] == '\0')
			continue;
		nfd = fopen(fname, "r");
		if (nfd == NULL) {
			perror(fname);
			continue;
		}
		(void) fstat(fileno(nfd), &sbuf);
		if (cp)
			*cp = '\n';
		if (sbuf.st_size == 0) {
			(void) fclose(nfd);
			continue;
		}
		nbytes += sbuf.st_size;
		if (nbytes > maxbytes && nbytes != sbuf.st_size)
			break;
		printf("#! rnews %ld\n", (long)sbuf.st_size);
		/* guess length of #! rnews string */
		nbytes += 13;
		n = 0;
		while (c = fread(cbuf, 1, sizeof cbuf, nfd)) {
			fwrite(cbuf, 1, c, stdout);
			n += c;
		}
#ifdef ACCOUNTING
		/* den folgenden Text habe ich wohl ohne zu denken */
		/* runtergetippt (Bitte wegsehen :-) */
		/* compute the group's name */
		i = strlen(SPOOLDIR)+1;
		for (j=0; fname[i]; i++,j++)
			accountingGroupName[j] = fname[i];
		cp = rindex(accountingGroupName, '/');
		if (cp)
			*cp = '\0';
		else
			accountingGroupName[j] = '\0';
		for (cp=accountingGroupName; *cp; cp++)
			if (*cp == '/') *cp = '.';
		/* log the name and size in the log file */
		fprintf(accountingFile, "%s %ld\n", accountingGroupName, sbuf.st_size);
#endif ACCOUNTING
		(void) fclose(nfd);
		if (ferror(stdout)){
			logerror("stdout write %s", sys_errlist[errno]);
			exit(1);
		}
		(void) fflush(stdout);
		if (n != sbuf.st_size) { /* paranoia */
			logerror("%s, expected %ld bytes, got %ld", fname,
				n, sbuf.st_size);
			/* breaking out of this early will end up resyncing
			   the batch files (isn't serendipity wonderful?) */
			break;
		}
	}
	if (fdstatus != NULL) {		/* exceeded maxbytes */
		char tmpfile[512];

		(void) umask(2);
		(void) strcpy(tmpfile, argv[1]);
		(void) strcat(tmpfile, ".tmp");
	    	nfd = fopen(tmpfile, "w");
		if (nfd == NULL) {
			logerror("fopen(%s,w) %s", tmpfile, sys_errlist[errno]);
			exit(1);
		}
		do {
			fputs(fname, nfd);
		} while (fgets(fname, sizeof fname, fd) != NULL);
		if (ferror(nfd)) {
			logerror("write(%s) %s", tmpfile, sys_errlist[errno]);
			exit(1);
		}
		(void) fclose(nfd);
		(void) fclose(fd);
		/* will pick it up next time thru */
		if (rename(tmpfile, workfile) < 0) {
			logerror("rename(%s,%s) %s", tmpfile, workfile,
				sys_errlist[errno]);
			exit(1);
		}
	}		
	else
		(void) unlink(workfile);
#ifdef ACCOUNTING
	(void) fclose(accountingFile);
#endif ACCOUNTING
	exit(0);
}

/*
 * Log the given message, with printf strings and parameters allowed,
 * on the log file, if it can be written.
 */
/* VARARGS1 */
logerror(fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9)
char *fmt;
long a1, a2, a3, a4, a5, a6, a7, a8, a9;
{
	FILE *logfile;
	char lfname[BUFLEN];		/* the log file */
	char bfr[BUFLEN];
	char *logtime, *ctime(); 
	time_t t;

	(void) time(&t);
	logtime = ctime(&t);
	logtime[16] = 0;
	logtime += 4;

#if defined(LOGDIR) || defined(HOME)
	(void) sprintf(lfname, "%s/%s/errlog", logdir(HOME), LIBDIR);
#else
	(void) sprintf(lfname, "%s/errlog", LIBDIR);
#endif

	(void) sprintf(bfr, fmt, a1, a2, a3, a4, a5, a6, a7, a8, a9);
	fprintf(stderr, bfr);
	if (access(lfname, 0) == 0 && (logfile = fopen(lfname, "a")) != NULL) {
#if defined(USG) || defined(BSD4_2)
		int flags;
		flags = fcntl(fileno(logfile), F_GETFL, 0);
		(void) fcntl(fileno(logfile), F_SETFL, flags|O_APPEND);
#else /* v7 */
		(void) lseek(fileno(logfile), 0L, 2);
#endif /* v7 */
		fprintf(logfile, "%s\tbatch\t%s\n", logtime, bfr);
		(void) fclose(logfile);
	}
}

#ifndef RENAMESUB
rename(from, to)
register char *from, *to;
{
	(void) unlink(to);
	if (link(from, to) < 0)
		return -1;

	(void) unlink(from);
	return 0;
}
#endif /* !RENAMESUB */
SHAR_EOF
fi
if test -f 'monthly.sh'
then
	echo shar: "will not over-write existing file 'monthly.sh'"
else
cat << \SHAR_EOF > 'monthly.sh'
#! /bin/sh

# create a summary of sent newsgroups for each site in ~news/news.list
# and send it to all sites

ACCDIR=/usr/spool/news/accounting
LISTFILE=/usr/lib/news/news.list
TMPFILE=/tmp/monthlynews.accounting
MAIL=/usr/ucb/mail

set `date`
SUFFIX=$2$6

while read zeile
do
	set $zeile
	SITE=$3
	GRADE=$6
	
	if test $GRADE \!\= no
	then
		/usr/local/newsacc -$GRADE $SITE | $MAIL -s "Monatliche Newsabrechnung" $SITE@unido.uucp
	fi

	/usr/local/newsacc -a $SITE >> $TMPFILE
	mv $ACCDIR/$SITE $ACCDIR/$SITE.$SUFFIX
done < $LISTFILE

$MAIL -s "This month news" evi@unido.uucp news@unido.uucp < $TMPFILE
rm $TMPFILE
/usr/local/newsacc -a $ACCDIR/linod.$SUFFIX >> $TMPFILE
$MAIL -s "Summe der kostenpflichtigen Newsgruppen!" ap@unido.uucp news@unido.uucp < $TMPFILE
rm $TMPFILE
SHAR_EOF
chmod +x 'monthly.sh'
fi
if test -f 'newsacc.c'
then
	echo shar: "will not over-write existing file 'newsacc.c'"
else
cat << \SHAR_EOF > 'newsacc.c'
/*
	News Accounting Tool
	by: Andreas Toenne, atoenne@unido.uucp
*/
/*
 *	Rev 1.1 newsacc.c added option and optimized code
 *	jf@unido
 */

/*
 *	Rev 1.2 newsacc.c fixed some bugs, new output format!!
 *	jf@unido
 */

/* Accounting data is collected in files ACCDIR/site.accounting by
   a modified batch program.
   Format is: full newsgroupname blank size in bytes

   Desired output format is:

	-s	groupwise sum (newsgroupname blanks size in bytes [9digits])
	-t	toplevel groupwise sum (same format as above)
	-c	toplevel groupwise sum and total sum of all costly newsgroups
		(same format as above, except last line is like -a)
	-a	total sum of all costly toplevel groups which are specified
		as COSTLY.
		Format: newsvolume <tab> sitename <tab> bytecount

   Usage: newsacc -[acst] sitename
*/

#include <stdio.h>
#define TRUE (1)
#define FALSE (0)

#define ACCDIR "/usr/spool/news/accounting"
#define MAXGROUPS 1000

#define NONE 0
#define SINGLE 1
#define TOPLEVEL 2
#define TOTAL 3
#define TOTALCOSTLY 4

#define COSTLY {"alt", "comp", "misc", "news", "rec", "sci", "soc", "talk", "gnu", "bionet", "unix-pc", NULL}

extern char *index();
typedef struct
{
	char name[80];
	long sum;
} group;

char *costly[] = COSTLY;

group groups[MAXGROUPS];	/* unsorted list of groups */
group topgroups[20];		/* list of toplevel groups */
short maxno=0;			/* number of highest entry in groups */
short maxtop=0;			/* number of highest entry in topgroups */

FILE *accfile;			/* the accounting file */


/* search for an entry for the name and return a pointer to it.
   Add a new entry if none was found */

group *search_entry(name, where, top)
char *name;
group where[];
short *top;
{
	short i;

	for (i=0; i < *top && strcmp(name, where[i].name); i++);
	if (i == *top)
	{
		(*top)++;
		if (*top == MAXGROUPS) error("Too many newsgroups");
		strcpy(where[i].name, name);
		where[i].sum = 0L;
	}
	return(& where[i]);
}

error(s)
char *s;
{
	fputs(s, stderr);
	exit(1);
}

sorter(a,b)
group *a,*b;
{
	return(strcmp(a->name, b->name) > 0);
}

char *toplevel(name)
char *name;
{
	char *c;

	c = index(name, '.');
	if (c==0)
		return(name);
	else
	{
		*c = '\0';
		return(name);
	}
}

short is_costly(name)
char *name;
{
	short i;

	for (i=0; costly[i]; i++)
		if (!strcmp(toplevel(name), costly[i]))
			return(TRUE);
	return(FALSE);
}

main(argc, argv)
int argc;
char *argv[];
{
	short do_what = NONE;
	char accfile_name[128];
	char cmd[256];
	char sitename[16];
	char groupname[80];
	int amount;
	int i;
	

	if ((argc != 3) || (argv[1][0] != '-'))
	{
		error("Usage: newsacc -[acts] sitename\n");
	}
	strcpy(sitename, argv[2]);
	switch(argv[1][1])
	{
		case 'a': do_what = TOTAL; break;
		case 'c': do_what = TOTALCOSTLY; break;
		case 's': do_what = SINGLE; break;
		case 't': do_what = TOPLEVEL; break;
		default: error("Usage: newsacc !-acts! sitename\n");
	}
	sprintf(accfile_name, "%s/%s", ACCDIR, sitename);

	if ((accfile = fopen(accfile_name, "r")) == NULL)
	{
		perror(accfile_name);
		exit(1);
	}

	while (! feof(accfile))
	{
		if (fscanf(accfile, "%s %d\n", groupname, &amount) != 2)
			error("Error while reading accounting data");
		search_entry(groupname, groups, &maxno)->sum += amount;
	}
	fclose(accfile);
	qsort(&groups, maxno, sizeof(group), &sorter);

	switch(do_what)
	{
		case SINGLE: 
			for (i = 0; i < maxno; i++)
				printf("%-40s\t%9d\n", groups[i].name, groups[i].sum);
			break;
		case TOPLEVEL:
			amount = 0;
			for (i = 0; i < maxno; i++)
			{
				amount += groups[i].sum;
				search_entry(toplevel(groups[i].name), topgroups, &maxtop)->sum += groups[i].sum;
			}
			qsort(&topgroups, maxtop, sizeof(group), &sorter);
			for (i = 0; i < maxtop; i++)
				printf("%-20s\t%9d\n", topgroups[i].name, topgroups[i].sum);
			printf("\nnewsvolume\t%s\t%9d\n", sitename, amount);
			break;
		case TOTAL:
			amount = 0;
			for (i = 0; i < maxno; i++)
				if (is_costly(groups[i].name))
					amount += groups[i].sum;
			printf("newsvolume\t%s\t%9d\n", sitename, amount);
			break;
		case TOTALCOSTLY:
			amount = 0;
			for (i = 0; i < maxno; i++)
				if (is_costly(groups[i].name))
				{
					amount += groups[i].sum;
					search_entry(toplevel(groups[i].name), topgroups, &maxtop)->sum += groups[i].sum;
				}
			qsort(&topgroups, maxtop, sizeof(group), &sorter);
			for (i = 0; i < maxtop; i++)
				printf("%-20s\t%9d\n", topgroups[i].name, topgroups[i].sum);
			printf("\nnewsvolume\t%s\t%9d\n", sitename, amount);
			break;
	}
}
SHAR_EOF
fi
if test -f 'newsbatch'
then
	echo shar: "will not over-write existing file 'newsbatch'"
else
cat << \SHAR_EOF > 'newsbatch'
#!sh
# news batcher

LOCKFILE=/tmp/newslock
WORK=/usr/lib/news/news.work
LOGFILE=/usr/lib/news/batchlog
TEMP=/tmp/newstmp
LIST=/usr/lib/news/news.list
SPOOL=/usr/spool/news/batched
ACCOUNTING=/usr/spool/news/accounting
LIB=/usr/lib/news
#MINIMUM=4000
MINIMUM=9000
LIMIT=300

cd /usr/lib/news

# ignore trap 8
trap '' 8

# read process number and check if the process is present
if read PROCESS
then
	if kill -8 $PROCESS
	then
		kill -9 $$
	fi
fi < $LOCKFILE

# create lockfile
echo $$ > $LOCKFILE

# create workfile if it is not present
if test \! -w $WORK -o \! -s $WORK
then
	cp $LIST $WORK
fi

date >> $LOGFILE

# loop once for each site in WORK
while test $? -eq 0 -a -s $WORK
do
	set `/bin/df /usr/spool/uucp | /usr/ucb/tail -1`
	if expr $4 \< $MINIMUM
	then
		echo low disk space \( $4 \) >> $LOGFILE
		kill -9 $$
	fi

	exec < $WORK
	read zeile
	set $zeile
	OK=$1
	GRADE=$2
	SITE=$3
	SIZE=$4
	COMPRESS=$5
	ACC=$6
	cat > $TEMP
	mv $TEMP $WORK

	if test $OK \= no
	then
		echo no news for $SITE >> $LOGFILE
		continue
	fi

	set `(cd /usr/spool/uucp/$SITE/C. ; /bin/ls | /usr/ucb/wc -l)`
	if expr $1 \> $LIMIT
	then
		echo $SITE has exceeded its limit \( $1 \) >> $LOGFILE
		continue
	fi

echo >> /dev/null
# action
	while test $? -eq 0 -a \( -s $SPOOL/$SITE -o -s $SPOOL/$SITE.work \)
	do
		(if test $COMPRESS \!\= no
		then
			echo '#! c7unbatch';
			$LIB/batch $SPOOL/$SITE $SIZE $ACCOUNTING |
			$LIB/compress $COMPRESS |
			$LIB/encode 
		else
			$LIB/batch $SPOOL/$SITE $SIZE $ACCOUNTING
		fi) |
		if test -s $SPOOL/$SITE.cmd
		then
			$SPOOL/$SITE.cmd
		else
			uux - -g$GRADE -r -z $SITE!rnews
		fi
		echo $SITE spooled $SIZE with $COMPRESS >> $LOGFILE
	done

done

# remove old files
rm $LOCKFILE
rm $WORK
SHAR_EOF
chmod +x 'newsbatch'
fi
exit 0
#	End of shell archive
Technical Details
Message-ID: <492@unido.UUCP>
Path: arc1-ca.pugleaf.net!gmdzi!unido!news

Show Full Headers
Complete Article Headers
X-Google-Language: GERMAN,ASCII-7-bit
X-Google-Thread: 10dc06,cebf652f3c81c035,start
X-Google-Attributes: gid10dc06,public
X-Google-ArrivalTime: 1989-06-29 06:17:38 PST
Path: arc1-ca.pugleaf.net!gmdzi!unido!news
From: news@unido.UUCP (News Administrator)
Newsgroups: dnet.general
Subject: News-Abrechnung
Keywords: Dringend.
Message-ID: <492@unido.UUCP>
Date: 29 Jun 89 12:22:05 GMT
Reply-To: news@unido.UUCP (News Administrator)
Followup-To: dnet.general
Distribution: dnet
Organization: University of Dortmund, West Germany
Lines: 892
Posted: Thu Jun 29 13:22:05 1989