
/*
 *  BATCHNEWS.C
 *
 *  (C)Copyright 1990, Mark R. Rinfret, All Rights Reserved
 *
 *  Author:	Mark R. Rinfret, September 1990
 *
 *  The batchnews program allows you to forward news to other sites.
 *  It expects to find a text file named UUSPOOL/batch/<system>
 *  where <system> is the name of the system to receive the news.
 *  The file UULIB/sys is the configuration file which determines the
 *  newsgroups that are to be forwarded to <system>.
 */

#include "news.h"
#include <errno.h>
#include <ctype.h>
#include <log.h>
#include <exec/types.h>
#include <libraries/dos.h>

#define MAX_FILE_SIZE	(65536-16)

IDENT(".05");

void		BatchNews(const char *dirName, const char *systemName);
static void	news_exit(int stat);
void		SpoolBatch(const char *systemName);

#define exit news_exit

typedef struct FileInfoBlock	FIB;

static char TmpBuf[2048];
static char NewsFile[256];
char homedir[256];

char *NewsDir;
char *WKName;

#define PROG_NAME "BatchNews"

int
main(ac, av)
int ac;
char *av[];
{
    char	*batchDirName;
    FIB 	*fib = malloc(sizeof(FIB));
    int 	ret = 0;
    short	i;
    BPTR	lock;

    LogProgram = PROG_NAME;

    LockFile("BATCHNEWS");
#ifndef TEST
    fclose(stderr);         /* Assume we are running in the background */
#endif

    getcwd(homedir, sizeof(homedir));
    NewsDir = GetConfigDir(UUNEWS);

    if (chdir(NewsDir) != 0) {
	ulog(-1, "BatchNews: NewsDir '%s' doesn't exist; quitting", NewsDir);
	news_exit(1);
    }

    WKName = strdup(TmpFileName("news-work"));

    batchDirName = strdup(MakeConfigPath(UUSPOOL,"batch"));
    lock = Lock(batchDirName, SHARED_LOCK);
    if (! lock ) {
	ulog(-1,"Where is batch directory '%s'?", batchDirName);
	news_exit(1);
    }
    if (Examine(lock, fib)) {
	while (ExNext(lock, fib)) {
	    if (fib->fib_DirEntryType > 0)
		continue;
#ifdef TEST
	    printf("scan: '%s'\n", fib->fib_FileName);
#endif
	    if (is_in_L_sys_file(fib->fib_FileName)) {
		BatchNews(batchDirName, fib->fib_FileName);
	    }
	}
    }
    UnLock(lock);
    news_exit(ret);
}

void
BatchNews(const char *dirName, const char *systemName)
{

    static char batchFileName[128];

    char *nodename = FindConfig(NODENAME);
    FILE	    *batchFile = NULL;
    FIB 	    *fib = malloc(sizeof(FIB));
    long	    fileSize;
    int 	    length;
    BPTR	    lock = 0;
    FILE	    *newsFile = NULL;
    int 	    ret = 0;
    long	    testSize;
    long	    totalSize;
    FILE	    *workFile = NULL;

#ifdef TEST
    printf("BatchNews: system = '%s'\n", systemName);
#endif
    strcpy(batchFileName, dirName);
    strcat(batchFileName, "/");
    strcat(batchFileName, systemName);
    batchFile = fopen(batchFileName, "r");
    if (! batchFile) {
#ifdef TEST
	perror(batchFileName);
#endif
	return; 	   /* Try later? */
    }

    workFile = fopen(WKName, "w");
    if (! workFile) {
no_workfile:
	ret = errno;
	ulog(-1,"Failed to open work file '%s'\n",WKName);
#ifdef TEST
	perror(WKName);
#endif
	news_exit(ret);
    }

    totalSize = 0;

    while (fgets(TmpBuf, 80, batchFile)) {
#ifdef TEST
	puts(TmpBuf);
#endif
	if (*TmpBuf == '\0' || *TmpBuf == '\n')
	    continue;

	length = strlen(TmpBuf);

	if (TmpBuf[length-1] == '\n')
	    TmpBuf[--length] = '\0';        /* Drop trailing newline. */

	lock = Lock(TmpBuf, SHARED_LOCK);
	if (!lock) {
bad_article:
	    ulog(-1,"Article '%s' missing?", TmpBuf);
#ifdef TEST
	    printf("Bad article name: '%s'\n", TmpBuf);
#endif
	    continue;
	}
	if (Examine(lock, fib)) {
	    fileSize = fib->fib_Size;
	} else {
	    UnLock(lock);
	    goto bad_article;
	}
	UnLock(lock);

	if (fileSize + totalSize > MAX_FILE_SIZE) {
	    fclose(workFile);
	    SpoolBatch(systemName);
	    totalSize = 0;
	    workFile = fopen(WKName, "w");  /* Re-open the work file. */
	    if (!workFile)
		goto no_workfile;
	}
	strcpy(NewsFile, TmpBuf);
	newsFile = fopen(NewsFile, "r");
	if (!newsFile)
	    continue;

	/*
	 *  First line MUST be the Path: header
	 */

	if (fgets(TmpBuf, sizeof(TmpBuf) - 16, newsFile) == NULL) {
	    ulog(-1, "Read Error: %s", NewsFile);
	    fclose(newsFile);
	    continue;
	}
	if (strncmp(TmpBuf, "Path:", 5) != 0) {
	    ulog(-1, "Path: does not head news file!: %s", NewsFile);
	    fclose(newsFile);
	    continue;
	}

	/*
	 *  Chg Dec '90, postnews no longer generates Path: <nodename>!<user>,
	 *		 but instead generates only Path: <user>, so we no
	 *		 longer check for the path already containing our
	 *		 node name.
	 */

	{
	    char *ptr = TmpBuf + 5;
	    while (*ptr == ' ' || *ptr == 9)
		++ptr;
	    fileSize -= strlen(ptr);
	    strins(ptr, "!");
	    strins(ptr, nodename);
	    fileSize += strlen(ptr);
	}
	fprintf(workFile,"#! rnews %ld\n", fileSize);
	fputs(TmpBuf, workFile);
	testSize = strlen(TmpBuf);

	while (fgets(TmpBuf, sizeof(TmpBuf) - 16, newsFile)) {
	    fputs(TmpBuf, workFile);
	    testSize += strlen(TmpBuf);
	}
	fclose(newsFile);
	totalSize += fileSize;
	if (testSize != fileSize)
	    ulog(-1, "copy size mismatch: %d/%d", fileSize, testSize);
    }

done:
    if (batchFile) {
	fclose(batchFile);
	remove(batchFileName);
    }
    if (workFile) {
	fclose(workFile);
	if (ret == 0 && totalSize)
	    SpoolBatch(systemName);
    }
    free(fib);
    remove(WKName);
}

void
SpoolBatch(const char *systemName)
{
    /* Compress the batch file. */
    sprintf(TmpBuf, "cbatch -b12 %s", WKName);
    system(TmpBuf);

    /* Submit it to uux for transmission to target system. */
    sprintf(TmpBuf, "%s %s \"%s!rnews\"", GetConfigProgram(UUX),
	    WKName, systemName);
    system(TmpBuf);
}

#undef exit
static /*volatile*/ void
news_exit(int stat)
{
    chdir(homedir);
    UnLockFile("BATCHNEWS");
    exit(stat);
}
