home *** CD-ROM | disk | FTP | other *** search
- /*#define PROCDEBUG*/
- /*
- ** RNEWS.C
- **
- ** RNEWS [file] (if not specified, stdin is used)
- **
- ** Copyright 1988 by William Loftus. All rights reserved.
- ** Extensive Changes Copyright 1990 by Matthew Dillon. All Rights Reserved.
- ** Extensive Changes Copyright 1993 by Michael B. Smith. All Rights Reserved.
- **
- ** MUST be compiled with 32-bit integers.
- **
- ** This is RNEWS. This is equivalent to the C-News (and B-News) RELAYNEWS
- ** program, but for AmigaUUCP.
- **
- ** Most current news systems will UUCP a file to this system containing
- ** multiple articles. That file will be compressed, using the standard
- ** compress (1) algorithm. *Sometimes* this file will have "#! cunbatch\n"
- ** as the first 12 characters in plain text.
- **
- ** RNEWS will decompress the input file, when needed, and unbatch the
- ** individual articles into their appropriate newsgroup locations.
- **
- ** Each newsgroup directory has a .next file which indicates the next
- ** article number to write. This number *used to* roll over at 32767.
- ** No longer.
- **
- ** The '-1' switch causes only the first valid newsgroup in a newsgroups
- ** header to get a copy of the article.
- **
- ** The '-D <number>' switch specifies the debug level.
- **
- ** The '-h' switch suppresses the use of hardlinks on 2.04 and above.
- **
- ** The '-n' switch means to "NOT" actually store articles (useful in
- ** debugging).
- **
- ** The '-o' switch causes the generation of '.overview' files for
- ** each newsgroup.
- **
- ** The '-p' switch indicates that PostNews is calling us -- that we don't
- ** have a compressed batch, regardless of the setting of '-u'.
- **
- ** The '-t <dir>' switch specifies the directory where all temporary files
- ** should go (NORMALLY UUNews: is used by this program). When set to use
- ** ram disk, RNEWS will work much faster....
- **
- ** The '-u <uncomp>' switch specifies the decompresser to use.
- **
- ** The '-x' switch sets the LogLevel used by ulog ().
- */
-
- #ifdef PROCDEBUG
- #define PROC(x) const char *_proc = x; printf ("%s: enter\n", _proc)
- #define D(x) printf ("%s: ", _proc); printf x
- #else
- #define PROC(x)
- #define D(x)
- #endif
-
- #include <exec/types.h>
- #include <exec/ports.h>
- #include <dos/dosextens.h>
- #include <dos/dostags.h>
- #include <clib/exec_protos.h>
- #include <clib/dos_protos.h>
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <ctype.h>
-
- #include <log.h>
- #include <ForwardNews.h> /* MRR, 09-23-90. */
- #include <owndevunit.h>
-
- #include "version.h"
- #include "config.h"
-
- IDENT (".28");
-
- typedef struct group {
- struct group *next;
- long actual; /* actual bytes */
- long bytes; /* uncompressed bytes */
- long articles; /* articles */
- char name [1];
- } group;
-
- void myexit (void);
- int dofile (FILE *, int);
- int unbatch (FILE *, int);
- int CopyToGroup (char *, int, char *, char **);
- int LinkToGroup (char *, char *);
- void initgroups (void);
- group *ValidGroup (const char *);
- void HandleSequenceNumber (char *, int *);
- int rm (const char *);
-
- static group
- groups;
-
- static char
- Buf [256],
- FBuf [256],
- TmpBuf [4096]; /* at least 1K */
-
- char
- HomeDir [256],
- *NewsDir = NULL,
- *TempDir = NULL,
- *UnComp = NULL;
- int
- PostNews = 0, /* call is from PostNews */
- JunkFlag_g = 0,
- _bufsiz = 16384, /* for DICE's stdio */
- DDebug = 0,
- UHaveNews = 0,
- DummyOpt = 0,
- LinksOk = 0,
- OnlyOne = 0,
- NewsOverview = 0;
-
- struct Library
- *OwnDevUnitBase = NULL;
-
- static const char
- news_rdy [] = { "T:NewsRdy" };
-
- #define PROG_NAME "RNews"
-
- /*
- ** main ()
- **
- ** The main loop. Note that OwnDevUnit must be valid for ulog() to work!
- */
-
- int
- main (int ac, char **av)
- {
- int
- err = 0,
- siz = 0,
- ret = 0,
- i,
- delFile = 0;
- FILE
- *fi;
- static const char
- odu_name [] = { ODU_NAME };
- char
- *newsFile = NULL; /* may, or may not, be malloc'ed -- do not free */
- /* (compiler exit routine will take care of it) */
-
- PROC ("main");
-
- LogProgram = PROG_NAME;
-
- memset (HomeDir, '\0', sizeof HomeDir);
- atexit (myexit);
-
- /*
- ** File Locking (ulog, LockFile, etc...)
- */
-
- if ((OwnDevUnitBase = OpenLibrary (odu_name, 0)) == NULL) {
- fprintf (stderr, "Unable to open %s\n", odu_name);
- D (("No %s\n", odu_name));
- exit (30);
- }
-
- /*
- ** Hardlinks are possible for 2.04 or later. NOTE! Do not use
- ** hardlinks on anything less than V37 !!
- */
-
- if (DOSBase->dl_lib.lib_Version >= 37)
- LinksOk = 1;
-
- getcwd (HomeDir, sizeof (HomeDir));
- NewsDir = GetConfigDir (UUNEWS);
-
- if (ac == 0) {
- ulog (-1, "cannot call RNews from workbench!");
- D (("called from WB?\n"));
- exit (30);
- }
-
- for (i = 1; i < ac; ++i) {
- char
- *ptr = av [i];
-
- if (*ptr != '-') {
- if (newsFile)
- ulog (-1, "Extraneous news file %s ignored", ptr);
- else
- newsFile = strdup (ptr);
- continue;
- }
-
- switch (ptr[1]) {
- case 'd': /* FIXME - use same as 'u' */
- case 'D':
- DDebug = (ptr[2]) ? atoi(ptr + 2) : 1;
- break;
- case 'h':
- LinksOk = 0;
- break;
- case 'n':
- DummyOpt = 1;
- break;
- case 'o':
- NewsOverview = 1;
- break;
- case 'p':
- PostNews = 1;
- break;
- case 't':
- if (ptr [2])
- TempDir = strdup (&ptr[2]);
- else
- TempDir = strdup (av [++i]);
- break;
- case 'u':
- if (DOSBase->dl_lib.lib_Version < 37) {
- fprintf (stderr, "Can't use -u/-d before 2.04\n");
- ulog (-1, "Can't use -u/-d before 2.04\n");
- exit (30);
- }
- if (ptr [2])
- UnComp = strdup (&ptr[2]);
- else
- UnComp = strdup (av [++i]);
- break;
- case 'x':
- LogLevel = atoi (ptr + 2);
- break;
- case '1':
- OnlyOne = 1;
- break;
- default:
- fprintf (stderr, "unknown flag '%s' ignored\n", ptr);
- break;
- }
- }
-
- initgroups ();
- if (GetForwardingInfo ()) { /* MRR, 09-23-90. */
- ulog (-1, "Failed to get news forwarding information - abort.");
- D (("exit, can't GetForwardingInfo\n"));
- exit (30);
- }
-
- /*
- ** uncompress file, if told to do so..
- */
-
- if (UnComp && PostNews == 0) {
- BPTR
- outfh,
- fh;
- int
- tot = 0,
- i;
- char
- *ptr;
-
- if (newsFile) {
- fh = Open (newsFile, MODE_OLDFILE);
- }
- else {
- fh = Input ();
- }
-
- sprintf (FBuf, "%s%s",
- TempDir ? TempDir : "",
- TmpFileName ("news-comp"));
- D (("temporary compressed file %s\n", FBuf));
-
- outfh = Open (FBuf, MODE_READWRITE);
- if (!outfh) {
- err = IoErr ();
- D (("couldn't open compressed %s (%ld)\n", FBuf, err));
- ulog (-1, "couldn't open for decompression %s (%ld)\n", FBuf, err);
- if (newsFile)
- Close (fh);
- exit (30);
- }
-
- if ((i = Read (fh, TmpBuf, sizeof (TmpBuf))) > 0) {
- if (TmpBuf [0] == '#' && TmpBuf [1] == '!') {
- if (LogLevel >= 1) {
- ptr = strchr (TmpBuf, '\n');
- memset (Buf, '\0', sizeof Buf);
- strncpy (Buf, TmpBuf, (int) (ptr - TmpBuf));
- ulog (1, "compression keyword: %s", Buf);
- }
- ptr = TmpBuf;
- while (*ptr != '\n') {
- ptr++;
- i--;
- }
- ptr++;
- i--;
- }
- else
- ptr = TmpBuf;
-
- Write (outfh, ptr, i);
- tot = i;
- }
-
- while ((i = Read (fh, TmpBuf, sizeof (TmpBuf))) > 0) {
- Write (outfh, TmpBuf, i);
- tot += i;
- }
-
- ulog (5, "Copied batch of %ld bytes", tot);
-
- if (!Flush (outfh)) { /* this Flush() is CRITICAL */
- ulog (0, "Flush failure %ld", IoErr ());
- }
-
- if (Seek (outfh, 0, OFFSET_BEGINNING) < 0) {
- ulog (0, "Seek failure %ld", IoErr ());
- }
-
- if (newsFile) {
- Close (fh);
- }
-
- sprintf (TmpBuf, "%s%s",
- TempDir ? TempDir : "",
- TmpFileName ("news-uncomp"));
- D (("temporary uncompressed file %s\n", TmpBuf));
-
- fh = Open (TmpBuf, MODE_NEWFILE);
- if (!fh) {
- err = IoErr ();
- D (("couldn't open decompress %s (IoErr %ld)\n", TmpBuf, err));
- ulog (-1, "couldn't open decompress %s (IoErr %ld)", TmpBuf, err);
- Close (outfh);
- DeleteFile (FBuf);
- exit (30);
- }
-
- i = SystemTags (UnComp, /* only in 2.04+ */
- SYS_Asynch, FALSE,
- SYS_Input, outfh,
- SYS_Output, fh,
- SYS_UserShell, TRUE,
- NP_Cli, TRUE,
- NP_StackSize, 16384,
- NP_CloseInput, FALSE,
- NP_CloseOutput, FALSE,
- TAG_DONE);
-
- /* do cleanup */
- err = IoErr ();
- Close (outfh);
- Close (fh);
- DeleteFile (FBuf);
- strcpy (FBuf, TmpBuf);
-
- /* check failure */
- if (i) {
- D (("couldn't run %s (rslt %ld, IoErr %ld), assuming local\n", UnComp, i, err));
- ulog (1, "couldn't run %s (rslt %ld, IoErr %ld), assuming local", UnComp, i, err);
- DeleteFile (FBuf);
- }
- else {
- ulog (1, "Decompression by '%s' successful", UnComp);
- newsFile = FBuf; /* so it's deleted later */
- delFile = 1;
- }
- }
-
- /*
- ** open input file
- */
-
- if (newsFile) {
- __aligned struct FileInfoBlock
- fib;
- BPTR
- lock;
-
- /* we were given the name of a news file */
- if ((fi = fopen (newsFile, "r")) == NULL) {
- ulog (-1, "Unable to open %s", newsFile);
- exit (30);
- }
- D (("input file %s\n", newsFile));
-
- if (lock = Lock (newsFile, SHARED_LOCK))
- if (Examine (lock, &fib)) {
- siz = fib.fib_Size;
- UnLock (lock);
- }
- else {
- err = IoErr ();
- UnLock (lock);
- ulog (-1, "Can't Examine() %s (%ld)", newsFile, err);
- fclose (fi);
- exit (30);
- }
- else {
- err = IoErr ();
- ulog (-1, "Can't Lock() %s (%ld)", newsFile, err);
- fclose (fi);
- exit (30);
- }
- }
- else {
- /* the input file is stdin */
- /* ensure it is seek()-able */
- if (fseek (stdin, 0L, 2) == 0) {
- /* seekable */
- fi = stdin;
- siz = ftell (fi);
- fseek (fi, 0L, 0);
- }
- else {
- /* not seekable */
- newsFile = malloc (255);
- if (newsFile == NULL) {
- ulog (-1, "malloc() : out of memory");
- exit (30);
- }
-
- sprintf (newsFile, "%s%s",
- TempDir ? TempDir : "",
- TmpFileName ("news-work"));
- D (("temporary file %s\n", newsFile));
-
- if (fi = fopen (newsFile, "w+")) {
- int n;
- int err = 0;
-
- while ((n = fread (TmpBuf, 1, sizeof (TmpBuf), stdin)) > 0) {
- int rslt = fwrite (TmpBuf, 1, n, fi);
-
- siz += n;
- if (rslt != n) {
- ulog (-1, "Write failed file %s, errno %ld", newsFile, errno);
- err = 1;
- break;
- }
- }
-
- if (err) {
- fclose (fi);
- rm (newsFile);
- exit (30);
- }
-
- fseek (fi, 0L, 0);
- delFile = 1;
- }
- else {
- ulog (-1, "Unable to create scratch file %s", newsFile);
- exit (30);
- }
- }
- }
-
- /*
- ** If any news group in a "Newsgroups:" list exists here the
- ** article is not stored to junk. If no news groups in the list
- ** exists the article is stored to junk.
- **
- ** The JunkSave configuration entry can be used to disable the
- ** saving of articles to junk.
- */
-
- {
- char
- *ptr = GetConfig (JUNKSAVE, "Y");
-
- if (ptr)
- if (ptr[0] == 'y' || ptr[0] == 'Y')
- JunkFlag_g = 1;
- else
- JunkFlag_g = -1;
- else
- JunkFlag_g = -1;
- }
-
- D (("chdir (%s)\n", NewsDir));
- if (chdir (NewsDir) != 0) {
- ulog (-1, "NewsDir %s doesn't exist; quitting", NewsDir);
- exit (30);
- }
-
- ret = dofile (fi, siz);
- fclose (fi);
-
- D (("chdir (%s)\n", HomeDir));
- if (chdir (HomeDir)) {
- ulog (-1, "Can't chdir %s", HomeDir);
- D (("chdir (%s) failed\n", HomeDir));
- }
- HomeDir [0] = '\0';
-
- if (delFile && ret == 0)
- rm (newsFile);
-
- if (UHaveNews) {
- struct MsgPort
- *port;
-
- Forbid ();
- if ((port = FindPort (news_rdy)) && port->mp_SigTask) {
- Signal (port->mp_SigTask, 1 << port->mp_SigBit);
- UHaveNews = 0;
- }
- Permit ();
- }
- if (UHaveNews) {
- int
- fd = open (news_rdy, O_RDONLY);
-
- if (fd < 0) {
- char
- *cmd;
-
- if (cmd = FindConfig (NEWSREADYCMD)) {
- fd = open (news_rdy, O_CREAT|O_TRUNC, 0666);
- if (fd >= 0)
- close (fd);
- sprintf (TmpBuf, "Run %s -x %s", cmd, news_rdy);
- Execute (TmpBuf, 0, 0);
- }
- }
- else {
- close (fd);
- }
- }
-
- D (("exit\n"));
- exit (ret);
- }
-
- /*
- ** processfile
- */
- int
- processfile (FILE *fi, char buf [], int bufsize)
- {
- int
- artlen = 0,
- r = 0,
- res = 0;
-
- PROC ("processfile");
-
- do {
- D (("-->:%s\n", buf));
-
- if (strncmp (buf, "#! rnews ", 9) == 0) {
- /*
- ** uncompressed batch
- */
-
- artlen = atoi (buf + 9);
- D (("article is current style, len %ld\n", artlen));
- r = unbatch (fi, artlen);
- if (res < r)
- res = r;
- }
- else {
- /*
- ** an unknown batch header is a fatal error.
- */
- char
- *p;
-
- D (("unknown batch header '%-20s'\n", buf));
- if (p = strchr (buf, '\n'))
- *p = '\0';
-
- ulog (-1, "unknown batch header (offset %ld, last artlen %ld) '%-20s'\n", ftell (fi), artlen, buf);
- res = 30;
- }
-
- D (("result %ld\n", res));
- if (res >= 30) {
- /* a fatal error has occured */
- break;
- }
- } while (fgets (buf, bufsize, fi));
-
- return res;
- }
-
- /*
- ** dofile ()
- **
- ** handle a news file
- */
-
- int
- dofile (FILE *fi, int siz)
- {
- FILE
- *f2 = NULL; /* the file we would switch to */
- unsigned char
- buf [255]; /* input buffer from 'fi' */
- int
- res = 0; /* our final procedure result */
-
- PROC ("dofile");
-
- if (!fi) {
- ulog (-1, "No file!");
- D (("exit, called without a file\n"));
- return 30;
- }
-
- D (("file size %ld\n", siz));
-
- groups.actual += siz;
-
- if (PostNews) {
- /* local posting */
- res = unbatch (fi, siz);
- goto leave;
- }
-
- /* start out by finding out what kind of file it is... */
- if (!fgets (buf, sizeof (buf), fi)) {
- ulog (0, "Cannot read input file");
- D (("exit, can't get first line\n"));
- return 20;
- }
-
- if (strncmp ("#! rnews ", buf, 9) == 0) {
- D (("batch is uncompressed\n"));
- res = processfile (fi, buf, sizeof (buf));
- }
- else {
- int
- uncompressit = 0;
- static char
- filename [255];
-
- if (strncmp ("#! cunbatch", buf, 11) == 0) {
- /* Definitely a compressed batch of news... */
- uncompressit = 1;
- D (("compressed batch\n"));
- }
- else {
- /* It *may* be a compressed batch of news, without a */
- /* cunbatch header. Figure it out. */
-
- if (buf [0] == 0x1f && buf [1] == 0x9d) {
- /* it has the magic numbers... */
- uncompressit = 1;
- D (("compress batch without header\n"));
- }
- else {
- /* probably a new local post from POSTNEWS */
- uncompressit = 0;
- D (("not batch, local post assumed (0x%2x%2x)\n",
- (buf [0] & 0xff), (buf [1] & 0xff)));
- }
-
- fseek (fi, 0L, 0);
- }
-
- if (uncompressit == 0) {
- res = unbatch (fi, siz);
- goto leave;
- }
-
- sprintf (filename, "%s%s",
- TempDir ? TempDir : "",
- TmpFileName ("news-work"));
- D (("file to decompress to: %s\n", filename));
-
- if (uncompress_to_file (fi, filename) < 0) {
- ulog (-1, "Newsfile Corrupt (%s), file not processed or deleted", filename);
- return 30;
- }
-
- f2 = fopen (filename, "r");
- if (!f2) {
- ulog (-1, "Cannot decompress news (IoErr %ld, errno %ld)\n",
- IoErr (), errno);
- if (DDebug < 10)
- rm (filename);
- #ifdef PROCDEBUG
- else {
- D (("should've removed '%s'\n", filename));
- }
- #endif
- D (("exit, couldn't open uncompressed file (%s)\n", filename));
- return 20;
- }
-
- if (!fgets (buf, sizeof (buf), f2)) {
- D (("Oops! EOF on f2"));
- res = 99;
- }
- else {
- res = processfile (f2, buf, sizeof (buf));
- }
- fclose (f2);
-
- if (DDebug < 10)
- rm (filename);
- #ifdef PROCDEBUG
- else {
- D (("should've removed '%s'\n", filename));
- }
- #endif
- }
-
- leave:
- if (res)
- ulog (-1, "dofile() error %d", res);
-
- D (("exit, result %ld\n", res));
- return res;
- }
-
- /*
- ** storearticle
- **
- ** Responsible for actually placing the article into the news tree.
- ** Sets hardlinks where appropriate, and stops after the first when
- ** requested by the user.
- */
-
- void
- storearticle (char *base, int bytes, char **realFileName)
- {
- char
- *grp;
- int
- didFwd = 0; /* at least one copy has been written to disk */
-
- ScanHeader (base, "Newsgroups:");
- while (grp = ScanNext ()) {
- group
- *gp;
-
- if (gp = ValidGroup (grp)) {
- ++gp->articles;
- gp->bytes += bytes;
-
- if (didFwd == 0 || LinkToGroup (grp, *realFileName) < 0) {
- if (CopyToGroup (base, bytes, grp, realFileName) < 0)
- ulog (-1, "Unable to copy article to group %s", grp);
- else {
- didFwd = 1;
- if (OnlyOne) {
- ++UHaveNews;
- break;
- }
- }
- }
- ++UHaveNews;
- }
- }
-
- return;
- }
-
- /*
- ** unbatch ()
- **
- ** Unbatches a news article starting at the current seek position and
- ** running for the specified number of bytes.
- **
- ** The article is stored into the appropriate newsgroup(s) as specified
- ** in UULib:NewsGroups, or in the 'junk' directory. Individual article
- ** sequence numbers are kept in a ".next" file in each newsgroup directory.
- **
- ** Note that realFileName is actually a dot-formatted newsgroup/artno,
- ** not a directory hierarchy.
- */
-
- int
- unbatch (FILE *fi, int bytes)
- {
- char
- *grp,
- *base = malloc (bytes + 1),
- *realFileName = NULL;
- int
- len = bytes,
- junkFlag;
- static const char
- ctrl_hdr [] = { "Control:" },
- control [] = { "control" };
-
-
- PROC ("unbatch");
-
- if (bytes <= 0) {
- D (("exit, bytes %ld\n", bytes));
- ulog (-1, "Internal error unbatch (), bytes %ld\n", bytes);
- return 30;
- }
- if (!base) {
- D (("exit, no mem\n"));
- ulog (-1, "Unable to malloc %ld bytes", bytes + 1);
- return 30;
- }
-
- D (("position before fread() %ld\n", ftell (fi)));
- bytes = fread (base, 1, bytes, fi);
- if (bytes <= 0) {
- D (("fread error %ld, errno %ld\n", bytes, errno));
- ulog (-1, "unbatch: read failed %ld", bytes);
- free (base);
- return 30;
- }
- base [bytes] = 0; /* NULL terminate buffer */
- D (("got %ld bytes, wanted %ld bytes, pos %ld (old pos s/b %ld)\n",
- bytes, len, ftell (fi), ftell (fi) - bytes));
-
- /*
- ** Global statistics
- */
-
- groups.bytes += bytes;
- ++groups.articles;
-
- /*
- ** See if this is a Control message
- ** If so, and it's a valid newsgroup, then file it in UUNews:Control
- */
-
- if (ScanHeader (base, ctrl_hdr) == 0) {
- if (ValidGroup (control)) {
- if (CopyToGroup (base, bytes, control, &realFileName) < 0)
- ulog (-1, "Unable to file %s message", control);
- else {
- char
- *p = strstr (base, ctrl_hdr),
- *s = strchr (p, '\n'),
- c = *s;
-
- *s = '\0';
- ulog (-1, "Control message: %s", p);
- *s = c;
- ++UHaveNews;
- /* FIXME : PROCESS control messages here! */
- }
- goto do_other_stuff;
- }
- }
-
- /*
- ** See if this article goes in junk
- */
-
- junkFlag = JunkFlag_g;
-
- ScanHeader (base, "Newsgroups:");
- while (grp = ScanNext ()) {
- if (ValidGroup (grp)) {
- junkFlag = 0;
- break;
- }
- }
-
- D (("junkFlag %ld\n", junkFlag));
-
- if (junkFlag) {
- if (junkFlag > 0) {
- CopyToGroup (base, bytes, "junk", &realFileName);
- ++UHaveNews;
- }
- }
- else {
- storearticle (base, bytes, &realFileName);
- }
-
- do_other_stuff:
- /*
- ** forward article to downstream sites if it was stored.
- */
-
- if (realFileName) {
- if (DummyOpt == 0)
- ForwardArticle (base, bytes, realFileName);
- free (realFileName);
- }
-
- free (base);
-
- D (("exit\n"));
- return 0;
- }
-
- /*
- ** LinkToGroup ()
- **
- ** If we are allowed to hard link and we have already written out
- ** one file (realFileName != NULL), then create a hard link instead
- ** of copying the file.
- **
- ** note that realFileName is actually a newsgroup/artno (dot format)
- **
- ** If this call fails RNews will attempt to make a copy of the file
- ** instead.
- */
-
- int
- LinkToGroup (char *grp, char *realFileName)
- {
- BPTR
- lock;
- int
- r = -1;
- char
- *real,
- *path;
-
- PROC ("LinkToGroup");
-
- if (LinksOk && realFileName) {
- /*
- ** ok to link, already made at least one copy of the file
- ** (need something to link to!)
- */
-
- if (real = HandleHeirarchy (NewsDir, realFileName, 0)) {
- if (lock = Lock (real, SHARED_LOCK)) {
- /*
- ** got a handle on the original file, convert
- ** group name to path and
- */
-
- if (path = HandleHeirarchy (NewsDir, grp, 0)) {
- int
- seqNo;
- /*
- ** attempt to link.
- */
-
- HandleSequenceNumber (path, &seqNo);
- sprintf (TmpBuf, "%s/%ld", path, seqNo);
-
- if (MakeLink (TmpBuf, (long) lock, 0L) == 0) {
- ulog (-1, "Couldn't create hardlink to %s (%ld), copying instead", TmpBuf, IoErr ());
- }
- else {
- r = 0;
- }
- free (path);
- }
- UnLock (lock);
- }
- free (real);
- }
- }
-
- D (("exit\n"));
- return r;
- }
-
- /*
- ** CopyToGroup ()
- **
- ** In the event that a hardlink is disallowed or not possible (due to
- ** this being the first instance of a news file), write out the file.
- */
-
- int
- CopyToGroup (char *buf, int bytes, char *grp, char **rfn)
- {
- int
- r = 0,
- seqNo;
- char
- *path;
- BPTR
- out;
-
- PROC ("CopyToGroup");
-
- if ((path = HandleHeirarchy (NewsDir, grp, DummyOpt)) == NULL) {
- D (("exit, HandleHeirarchy failed\n"));
- return -1;
- }
-
- /*
- ** Obtain a sequence number (and bump .next file)
- */
-
- HandleSequenceNumber (path, &seqNo);
- D (("sequence number %ld\n", seqNo));
-
- /*
- ** write the file. When we write a real file, we set *rfn to point
- ** to the dotted file name for ForwardArticle(). This allows us
- ** to implement hard links for multiple references
- */
-
- if (*rfn == NULL) {
- sprintf (TmpBuf, "%s/%d", grp, seqNo);
- *rfn = strdup (TmpBuf);
- D (("rfn = '%s'\n", TmpBuf));
- }
- sprintf (TmpBuf, "%s/%d", path, seqNo);
- D (("file = '%s'\n", TmpBuf));
-
- free (path); /* we are done with it... */
-
- if (DummyOpt) {
- D (("exit, DummyOpt\n"));
- return 0;
- }
-
- if (out = Open (TmpBuf, MODE_NEWFILE)) {
- int
- n = Write (out, buf, bytes);
-
- Close (out);
- if (n != bytes)
- r = -1;
- }
-
- D (("exit, result %ld\n", r));
- return r;
- }
-
- void
- HandleSequenceNumber (char *path, int *pseq)
- {
- int
- len;
- BPTR
- file;
-
- /*
- ** do not use update I/O on the .next file, so that XFH will work...
- */
-
- PROC ("HandleSequenceNumber");
-
- sprintf (TmpBuf, "%s/.next", path);
-
- if (file = Open (TmpBuf, MODE_OLDFILE)) {
- len = Read (file, Buf, sizeof Buf);
-
- if (len > 0) {
- Buf [len] = '\0';
- D (("'%s' contains '%s'\n", TmpBuf, Buf));
- *pseq = atoi (Buf);
- }
- else {
- len = IoErr ();
- D (("couldn't read '%s', IoErr %ld\n", TmpBuf, len));
- *pseq = 1;
- }
- Close (file);
- }
- else {
- len = IoErr ();
- D (("couldn't open '%s', IoErr = %ld, set sequence to 1\n",
- TmpBuf, len));
- *pseq = 1;
- }
-
- sprintf (Buf, "%ld", (*pseq + 1));
- D (("new sequence number %ld, Buf contains '%s'\n", (*pseq + 1), Buf));
-
- if (DummyOpt)
- return;
-
- if (file = Open (TmpBuf, MODE_NEWFILE)) {
- Write (file, Buf, strlen (Buf));
- Close (file);
- }
-
- D (("exit\n"));
- return;
- }
-
- void
- myexit (void)
- {
- group
- *gp;
-
- PROC ("myexit");
-
- if (HomeDir [0]) {
- D (("chdir (%s)\n", HomeDir));
- if (chdir (HomeDir)) {
- D (("chdir (%s) failed\n", HomeDir));
- ulog (-1, "chdir (%s) failed\n", HomeDir);
- }
- }
-
- OpenLog ();
- for (gp = groups.next; gp; gp = gp->next) {
- if (gp->articles) {
- ulog(-1, "%s%-24s %4ld ARTS %7ld UNCOMP",
- DummyOpt ? "(d) " : "",
- gp->name, gp->articles, gp->bytes);
- }
- }
-
- ulog (-1, "%-24s %4ld ARTS %7ld/%-7ld BYTES/UNCOMPRESSED",
- "TOTAL", groups.articles, groups.actual, groups.bytes);
- CloseLog ();
-
- UnLockFiles ();
-
- if (OwnDevUnitBase) {
- CloseLibrary (OwnDevUnitBase);
- OwnDevUnitBase = NULL;
- }
-
- D (("exit\n"));
- return;
- }
-
- /*
- ** Newsgroups
- */
-
- void
- initgroups (void)
- {
- struct group
- *gp;
- int
- c,
- len;
- FILE
- *fp;
-
- if (groups.next != NULL)
- return;
-
- if ((fp = openlib ("newsgroups")) == NULL) {
- ulog (-1, "Couldn't open UULib:Newsgroups file");
- exit (30);
- }
-
- gp = &groups;
- while (fgets (Buf, sizeof (Buf), fp)) {
-
- for (len = 0;
- (c = Buf [len]) != ' ' && c != 9 && c != '\n';
- ++len)
- ;
- Buf [len] = 0;
-
- if ((gp->next = malloc (sizeof (group) + len + 1)) == NULL) {
- ulog (-1, "Malloc failed!");
- exit (30);
- }
- gp = gp->next;
- clrmem (gp, sizeof (group));
- strcpy (gp->name, Buf);
- }
- fclose (fp);
-
- return;
- }
-
- group *
- ValidGroup (const char *grp)
- {
- struct group
- *gp;
-
- for (gp = groups.next; gp; gp = gp->next) {
- if (stricmp (gp->name, grp) == 0)
- break;
- }
-
- return gp;
- }
-
- int
- rm (const char *file)
- {
- int
- rslt;
-
- PROC ("rm");
- D (("removing %s\n", file));
-
- rslt = remove (file);
-
- #ifdef PROCDEBUG
- if (rslt) {
- D (("error removing file %ld\n", errno));
- }
- #endif
-
- return rslt;
- }
-