Subject: v14i050: Network News Transfer Protocol, version 1.5, Part04/09 Newsgroups: comp.sources.unix Sender: sources Approved: rsalz@uunet.UU.NET Submitted-by: Phil Lapsley Posting-number: Volume 14, Issue 50 Archive-name: nntp1.5/part04 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh './common/conf.h' <<'END_OF_FILE' X/* X * Configuration information for use by NNTP server and support X * programs. Change these as appropriate for your system. X */ X X/* X * Compile time options. X */ X X#undef ALONE /* True if we're running without inetd */ X#undef FASTFORK /* True if we don't want to read active file on start */ X#undef BSD_42 /* 4.2 compatability code -- if this is defined, */ X /* DBM probably wants to be defined as well. */ X X#define NDBM /* Use new-style (4.3) ndbm(3x) libraries */ X X#undef DBM /* True if we want to use the old dbm(3x) libraries */ X /* IF YOU DEFINE THIS, change CFLAGS in makefile to */ X /* be -ldbm */ X X#undef USGHIST /* Use USG style history file (no DBM) */ X /* IF YOU DO NOT DEFINE NDBM or DBM, this is DEFAULT! */ X X#undef USG /* System V support */ X#undef EXCELAN /* Excelan EXOS 205 support */ X X#undef U_LONG /* Define this if your is missing */ X /* typedefs for u_long */ X X/* X * If you DON'T have vfork, make this "#define vfork fork" X * vfork will speed up article transfer nntpds by about 2.5 times. X */ X X#undef vfork X X/* X * If you have the syslog library routine, define SYSLOG to X * be thef syslog facility name under which stats should be X * logged. Newer 4.3 systems might choose LOG_NEWS; X * LOG_LOCAL7 is an acceptable substitute. X * X * If you don't have support for syslog, but want a facsimile, X * define FAKESYSLOG to be the name of a file to which to log stuff, X * then define SYSLOG and LOG, too. e.g., X * X * #define FAKESYSLOG "/usr/lib/news/nntplog" X * X * If you don't want any syslog-type activity, #undef SYSLOG. X * Obviously, this means that you can't define LOG, either. X */ X X#undef FAKESYSLOG X X#define SYSLOG LOG_NEWS X X#ifdef SYSLOG /* Define LOG if you want copious logging info */ X# define LOG /* undef it if you don't */ X#endif /* but you can only have LOG if you have SYSLOG */ X X#ifdef BSD_42 /* This is a logical, warranted assumption */ X# ifndef DBM /* which will probably get me in trouble. */ X# define DBM /* Kill it if you have 4.2 *and* ndbm. */ X# endif not DBM X#endif BSD_42 X X#ifdef USG /* Another similar assumption */ X# ifndef USGHIST X# define USGHIST X# endif not USGHIST X#endif USG X X#undef IHAVE_DEBUG /* Copious debugging output from ihave */ X X#define XHDR /* Optional XHDR command. Defining this will */ X /* speed up '=' command in rn, but will load */ X /* the server more. If your server is heavily */ X /* loaded already, defining this may be a bad idea */ X X#define SUBNET /* If you have 4.3 subnetting */ X#undef DAMAGED_NETMASK /* If your subnet mask is not a multiple of */ X /* four bits (e.g., UCSD) */ X X#undef NETMASK /* If you don't have subnet ioctls, define */ X /* this to be a hex constant of your subnet */ X /* mask, e.g., #define NETMASK 0xffffff00 */ X /* Of course, you must define SUBNET above, too. */ X#undef DECNET /* If you want decnet support */ X X#define GHNAME /* Define if you have gethostname() */ X#undef UUNAME /* Define to use /etc/uucpname */ X /* If neither of these are defined, */ X /* inews will use the contents of */ X /* /usr/include/whoami.h */ X X/* X * System V compatability X */ X X#ifdef USG X# define FCNTL /* If O_etc is defined in */ X# define NDIR /* If you need ndir library support */ X# define index strchr X# define rindex strrchr X# ifdef U_LONG X typedef unsigned long u_long; X typedef unsigned short u_short; X# endif U_LONG X# define IPPORT_NNTP 119 X#endif USG X X/* X * How long you want nntp servers to hang out without receiving X * commands before they close the connection with an error message. X * X * You CANNOT have TIMEOUT while running in standalone (ALONE) mode, X * as SIGALRM is used for different things. X * X * If you don't want any timeout, #undef it, i.e., X * X * #undef TIMEOUT X * X * TIMEOUT should be at least two hours, which allows users some time X * away from their terminal (e.g., at lunch) while reading news. X */ X X#ifndef ALONE X# define TIMEOUT (2 * 3600) X#endif ALONE X X/* X * How long you want nntp servers to wait without receiving data X * during article transfers. You CANNOT have XFER_TIMEOUT while X * running in standalond (ALONE) mode. X * X * If you don't want any transfer timeouts, #undef it, as above. X */ X X#ifndef ALONE X# define XFER_TIMEOUT (30 * 60) X#endif ALONE X X/* X * Your domain. This is for the inews generated From: line, X * assuming that it doesn't find one in the article's head. X * Suggestions are .UUCP if you don't belong to the Internet. X * If your hostname returns the fully-qualified domain name X * as some 4.3 BSD systems do, simply undefine DOMAIN. X * X * e.g. #define DOMAIN "berkeley.edu" X */ X X#define DOMAIN "uucp" X X/* X * A file containing the name of the host which is running X * the news server. This will have to match what rrn thinks, X * too. X */ X X#define SERVER_FILE "/usr/local/lib/rn/server" X X/* X * Person (user name) to post news as. X */ X X#define POSTER "news" X X/* X * These files are generated by the support programs, and are needed X * by the NNTP server. Make sure that whatever directory you X * decide these files should go is writable by whatever uid you X * have the sypport programs run under. X */ X X#define STAT_FILE "/usr/lib/news/mgdstats" X#define NGDATE_FILE "/usr/lib/news/groupdates" X X/* X * Some commonly used programs and files. X */ X X#define ACTIVE_FILE "/usr/lib/news/active" X#define ACCESS_FILE "/usr/lib/news/nntp_access" X#define HISTORY_FILE "/usr/lib/news/history" X#define SPOOLDIR "/usr/spool/news" X#define INEWS "/usr/lib/news/inews" X#define RNEWS "/usr/bin/rnews" /* Link to inews? */ X X/* X * Some miscellaneous stuff you probably don't want to change. X */ X X#define MAX_ARTICLES 4096 /* Maximum number of articles/group */ X#define READINTVL 60 * 10 /* 10 minutes b/n chking active file */ END_OF_FILE if test 5753 -ne `wc -c <'./common/conf.h'`; then echo shar: \"'./common/conf.h'\" unpacked with wrong size! fi # end of './common/conf.h' fi if test -f './doc/nntpd.dst' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./doc/nntpd.dst'\" else echo shar: Extracting \"'./doc/nntpd.dst'\" \(5373 characters\) sed "s/^X//" >'./doc/nntpd.dst' <<'END_OF_FILE' X.\" X.\" @(#)nntpd.dst 1.3 (Berkeley) 10/15/87 X.\" X.TH NNTPD 8C "8 July 1987" X.UC 4 X.SH NAME nntpd \- Network News Transfer Protocol server X.SH SYNOPSIS X.B LNNTPD X.br X.I (with INETD, see below) X.SH DESCRIPTION X.I Nntpd is a server that supports the proposed standard for the stream based transmission of network news articles. It can be used both by ``reader/poster'' clients that present news to users, and by X``transfer'' clients that transport news between machines. When used with Internet TCP, X.I nntpd operates at the port indicated in the ``nntp'' service entry in X.IR SERVICES ; the port number assigned by the Network Information Center for this service is 119. For use with DECNET, xxx. This manual page describes X.I nntpd from version 1.4 of the NNTP package. X.PP X.I Nntpd can operate either as a stand-alone server, or as a server under X.IR inetd (1). For stand-alone use, X.I nntpd must be compiled with the -DALONE option, and is invoked as mentioned in the synopsis above. Under X.IR inetd (1), the appropriate entry must be made in X.IR INETDCONFIG , and the server must be compiled without the X-DALONE flag. X.PP The server handles clients on a one to one basis, forking to take care of clients as they request connections. Each server changes its current directory to the news spool directory X( X.IR NEWSSPOOL ) and then executes commands from its client. These commands are described in ARPA Internet RFC 977, ``Network News Transfer Protocol; A Proposed Standard for the Stream Based Transmission of News Articles.'' X.SH "CLIENT ACCESS" X.PP Sites may choose to limit the hosts that can query the server for news. Further, some sites may not wish to allow certain hosts to post news. Finally, some sites may wish to restrict the newsgroups that can be accessed from remote hosts. Such limiting can be accomplished through an access file, X.IR NEWSLIB/nntp_access . This file consists of three or four fields in the following form: X.sp X.nf host/net read/xfer/no post/no newsgroups X.fi X.sp where X.f X.I host is a valid host name as found in X.I HOSTFILE, X.I net is a valid network name as found in X.I NETWORKFILE, and X.I ``read'', X.I ``xfer'', X.I ``post'', and X.I ``no'' are the corresponding string constants. X.I Newsgroups is an optional list of comma separated newsgroup names. Anything to the right of a `#' character is taken to be a comment and is ignored. X.PP The presence of an entry in this file implies that specific host, or hosts on the named network, are allowed to read news, but not to post news. The absence of a entry corresponding to a client's host or network implies that the client is not allowed to read or post news. Default permissions can be set by having the first entry in the file be a host/net name of X``default''. If this is used, ``default'' must be the first entry. X.PP The first field to the right of the host/net entry specifies the read access of the host/net in question. If the entry is ``read,'' matching hosts can both read and transfer news. If the entry is ``xfer,'' however, matching hosts can only execute commands used for transferring news, such as NEWNEWS, NEWGROUPS, IHAVE, and ARTICLE with message-id parameters. The string ``no'' denies read permission of any kind to a matching host. X.PP The next field to the right defines whether a matching host has post permission: if the field is ``post'' then the POST command is permitted; if the field is ``no,'' then matching clients are not allowed to post news. X.PP The next field is optional, and, if present, is a comma separated list of newsgroup names that restrict the client's reading ability. Clients are not allowed to read or transfer articles in newsgroup names preceded by an exclamation point. By default, clients are allowed to read all newsgroups. X.PP X.I Nntpd is selective and searches for a ``best match'' when searching this file to check its client's permissions. That is, a specific host name match is used over a client being a member of a specified net. X.SH EXAMPLE ACCESS FILE X.PP X.sp X.nf X# X# Example access file X# default xfer no ucb-ether read post shadow no no ic read post !ucb.postgres X.fi X.sp X.PP The above file allows only transfer of news (i.e., no reading or posting) by default. Hosts on the network ``ucb-ether'' would be able to read and post news. The host ``shadow'' would not be allowed to read or post news. Finally, the host ``ic'' is allowed to read and post news, but cannot access articles in the newsgroup X``ucb.postgres'' or any of its child newsgroups X(e.g., ``ucb.postgres.core''). X.SH "INFORMING USERS OF NEW NEWSGROUPS" X.PP The NEWGROUPS command has never worked very well because newsgroup creation dates are not stored under the USENET news system. As a result, it is left to client programs to determine by difference in active file size whether new groups exist, and if so, whether to inform the user of their existence. X.PP Older versions of X.I nntpd relied on the program X.I mkgrdates to prepare newsgroup creation information. X.I Mkgrdates was fallible and could present a hefty load on the serving system. Consequently, it is no longer supported, and its use is discouraged. X.SH AUTHOR Phil Lapsley (Internet: phil@berkeley.edu; UUCP: ...!ucbvax!phil) X.SH SEE ALSO services(5), inetd(8C) X.PP RFC 977, ``Network News Transfer Protocol: A Proposed Standard for the Stream Based Transmission of News Articles.'' END_OF_FILE if test 5373 -ne `wc -c <'./doc/nntpd.dst'`; then echo shar: \"'./doc/nntpd.dst'\" unpacked with wrong size! fi # end of './doc/nntpd.dst' fi if test -f './doc/nntpxmit.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./doc/nntpxmit.1'\" else echo shar: Extracting \"'./doc/nntpxmit.1'\" \(5838 characters\) sed "s/^X//" >'./doc/nntpxmit.1' <<'END_OF_FILE' X.TH NNTPXMIT 1 netnews/NNTP X.SH NAME X.I nntpxmit X\- transmit netnews articles to a remote NNTP server X.SH SYNOPSIS X.I nntpxmit X[ X.B \-a X] X[ X.B \-d X] X[ X.B \-s X] X[ X.B \-r X] X[ X.B \-T X] X[ X.B \-F X] X[ X.B \-D X] hostname|hostname:file [...] X.SH DESCRIPTION X.PP X.I Nntpxmit offers netnews articles [RFC850] named in a queue file (a file of filenames) to a remote NNTP (Network News Transfer Protocol, X[RFC977]) server, transmitting those articles that the remote server indicates that it does not already have. X.PP The command line arguments a processed sequentially, and the flags can thus be toggled several times during one invocation of the program, by giving the options more than once. The options are: X.IP hostname|hostname:file The name of the remote host, and the name of the queue file of articles destined for that host. The hostname may be an internet address in dotted format (e.g. 10.2.0.78, [10.0.0.78]). If the hostname is given without an associated file, it is assumed that the hostname is also the name of the queue file. If the separator is "::" instead of ":", it is assumed that the remote host speaks DECNET, instead of the default, IP/TCP. X.IP -s Toggles reporting of transfer statistics (how many articles we offered them, how many they accepted, etc). X.br Default is X.B ON. X.IP -d Toggles DEBUG output on stderr. This can be used to see exactly what the two systems are saying to each other, except for the actual article text. X.br Default is X.B OFF. X.IP -r Toggles requeuing of failed articles. A failed article is an article that we (client) offer them (remote server), they accept, we transmit, and then they report that they "failed" or dropped the article (i.e. inews(1) on the remote returned non-zero). If we have requeuing set, we save the list of articles that they failed on, and rewrite the queue file with them, so that they get reoffered the next time we initiate transmission to them. X.br Default is X.B ON. X.IP -a This flag says that the next queue file on the command line isn't a queue file, but is a single netnews article to be transmitted to the remote in a single operation. X.IP X.B NOTE: this option causes X.I nntpxmit to exit immediately after this transfer is done (regardless of whatever else is on the command line), and to exit with a code indicating whether the articles was successfully accepted by the remote server (zero exit for success, non-zero for failure). X.PP The next options set the underlying transport protocol that X.I nntpxmit uses. The NNTP specification assumes a TCP-style transport protocol underlies it (i.e. a reliable, flow-controlled, full-duplex byte stream). X.I Nntpxmit assumes that after doing some magic to get a descriptor, it can do read(2) and write(2) calls (and use stdio) to move data and check for errors. By default, X.I nntpxmit will use IP/TCP (DoD Internet Protocol suite). X.IP -T Sets transport protocol to IP/TCP for all remaining transfers (unless reset by other transport flags). Default transport. X.IP -D Sets transport protocol to DECNET for all remaining transfers (unless reset by other transport flags). X.B NOTE: using "::" as the hostname/queue filename separator has the same effect. X.IP -F This says that the hostname is a file descriptor number, already open to a remote server (with some reliable protocol underneath) that was passed to X.I nntpxmit through a fork(2). X.SH "THEORY OF OPERATION" X.PP X.I Nntpxmit implements an interactive ihave/sendme transmission system. Roughly, the protocol is X.IP 1. open the article, fetch out the message-id (required on all netnews articles), and send the command IHAVE to the remote. X.IP 2. The remote will then say either "I've seen it already" or "please send that article to me." X.IP 3. If the response was negative, X.I nntpxmit loops back to step 1 and offers the next article (until queue file EOF). Otherwise, X.I nntpxmit will send the article, using SMTP [RFC821] text transmission conventions X(i.e. CRLF line terminators, and dot escaping). X.IP 4. X.I Nntpxmit waits for the remote to say whether the article was successfully accepted or not. If the answer is negative and requeuing of failed articles is enabled, X.I nntpxmit will queue this article's filename to be written back to the queue file at the end of the session with this remote. X.PP If the communcation link should fail (and X.I nntpxmit detects it through a system call error return), X.I nntpxmit will rewrite the queue file with the article filenames of the articles that it did not transmit (that is, we don't retransmit stuff we've already successfully sent and gotten back an positive confirmation that they got it). X.SH FILES X/tmp/nntpxmitXXXXXX X.SH AUTHOR Erik E. Fair X.SH "SEE ALSO" inews(1), X.br RFC977 \- Network News Transfer Protocol (NNTP), X.br RFC850 \- USENET Article Format standard, X.br RFC821 \- Simple Mail Transfer Protocol (SMTP), X.SH BUGS X.PP Always requeuing failed articles can lead to beating the remote to death with a list of articles that he can't accept for come structural reason. How many of these have to pile up before you should declare that something is seriously wrong with the remote system and stop trying? X.PP While X.B nntpxmit will lock a queue file (your version of UNIX permitting) against multiple invocations of itself, there is no locking with inews(1), which is what writes the queue files in the first place. Therefore, never use X.B nntpxmit on the queue files that inews(1) writes, because two processes writing into the same file without some kind of cooperation will almost certainly trash the file; move them to some other name that inews(1) knows nothing about, so that you won't lose articles to races between inews and nntpxmit. X.PP Adding inews(1) compatible locking to the C code would be much more trouble than it's worth, and violates the KISS principle besides. END_OF_FILE if test 5838 -ne `wc -c <'./doc/nntpxmit.1'`; then echo shar: \"'./doc/nntpxmit.1'\" unpacked with wrong size! fi # end of './doc/nntpxmit.1' fi if test -f './inews/inews.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./inews/inews.c'\" else echo shar: Extracting \"'./inews/inews.c'\" \(6070 characters\) sed "s/^X//" >'./inews/inews.c' <<'END_OF_FILE' X#ifndef lint static char *sccsid = "@(#)inews.c 1.15 (Berkeley) 2/6/88"; X#endif X X/* X * Itty-bitty inews for talking to remote server. X * Simply accept input on stdin (or via a named file) and dump this X * to the server; add a From: and Path: line if missing in the original. X * Print meaningful errors from the server. X * Limit .signature files to MAX_SIGNATURE lines. X * No processing of command line options. X * X * Original by Steven Grady , with thanks from X * Phil Lapsley , who is now responsible for it. X */ X X#include X#include X#include X#include "../common/conf.h" X#include "../common/nntp.h" X#ifdef USG X#include X#else not USG X#include X#endif not USG X X#define MAX_SIGNATURE 4 X extern FILE *ser_wr_fp; X char host_name[256]; X main(argc, argv) int argc; char *argv[]; X{ X char line[NNTP_STRLEN], s[NNTP_STRLEN]; X int seen_fromline, in_header; X int response; X char *server; X char *getserverbyfile(); X register char *cp; X X ++argv; X while (argc > 1) X if (*argv[0] == '-') { X ++argv; X --argc; X } else X break; X X if (argc > 1) { X if (freopen(*argv, "r", stdin) == NULL) { X perror(*argv); X exit(1); X } X } X X uname(host_name); X X server = getserverbyfile(SERVER_FILE); X if (server == NULL) { X fprintf(stderr, X "Can't get the name of the news server from %s.\n", X SERVER_FILE); X fprintf(stderr, X "Either fix this file, or put NNTPSERVER in your enviroment.\n"); X exit(1); X } X X response = server_init(server); X if (response < 0) { X printf("Couldn't connect to %s news server, try again later.\n", X server); X exit(1); X } X X if (handle_server_response(response, server) < 0 X || response == OK_NOPOST) { X close_server(); X exit(1); X } X X put_server("POST"); X (void) get_server(line, sizeof(line)); X if (*line != CHAR_CONT) { X if (atoi(line) == ERR_NOPOST) { X close_server(); X fprintf(stderr, X "Sorry, you can't post from this machine.\n"); X exit(1); X } else { X close_server(); X fprintf(stderr, "Remote error: %s\n", line); X exit(1); X } X } X X in_header = 1; X seen_fromline = 0; X X while (gets(s) != NULL) { X if (s[0] == '.') /* Single . is eof, so put in extra one */ X (void) fputc('.', ser_wr_fp); X if (in_header && strneql(s, "From:", sizeof("From:")-1)) X seen_fromline = 1; X if (in_header && s[0] == '\0') { X in_header = 0; X if (!seen_fromline) X gen_frompath(); X } X fprintf(ser_wr_fp, "%s\r\n", s); X } X X append_signature(); X X fprintf(ser_wr_fp, ".\r\n"); X (void) fflush(ser_wr_fp); X (void) get_server(line, sizeof(line)); X if (*line != CHAR_OK) { X if (atoi(line) == ERR_POSTFAIL) { X close_server(); X printf("Article not accepted by server; not posted.\n"); X for (cp = line + 4; *cp && *cp != '\r'; cp++) X if (*cp == '\\') X putchar('\n'); X else X putchar(*cp); X exit(1); X } else { X close_server(); X fprintf(stderr, "Remote error: %s\n", line); X exit(1); X } X } X X /* X * Close server sends the server a X * "quit" command for us, which is why we don't send it. X */ X X close_server(); X X exit(0); X} X X/* X * append_signature -- append the person's .signature file if X * they have one. Limit .signature to MAX_SIGNATURE lines. X */ X append_signature() X{ X char line[256], sigfile[256]; X char *cp; X struct passwd *passwd; X FILE *fp; X char *index(); X int count = 0; X X passwd = getpwuid(getuid()); X if (passwd == NULL) X return; X X (void) strcpy(sigfile, passwd->pw_dir); X (void) strcat(sigfile, "/"); X (void) strcat(sigfile, ".signature"); X X fp = fopen(sigfile, "r"); X if (fp == NULL) X return; X X while (fgets(line, sizeof (line), fp)) { X count++; X if (count > MAX_SIGNATURE) { X fprintf(stderr, X "Warning: .signature files should be no longer than %d lines.\n", X MAX_SIGNATURE); X fprintf(stderr, X "(Only %d lines of your .signature were posted.)\n", X MAX_SIGNATURE); X break; X } X if (cp = index(line, '\n')) X *cp = '\0'; X fprintf(ser_wr_fp, "%s\r\n", line); X } X (void) fclose(fp); X} X X X/* X * gen_frompath -- generate From: and Path: lines, in the form X * X * From: user@host.domain (full_name) X * Path: host!user X * X * This routine should only be called if the message doesn't have X * a From: line in it. X */ X gen_frompath() X{ X char *full_name; X char *cp; X struct passwd *passwd; X char *index(), *getenv(); X X passwd = getpwuid(getuid()); X X full_name = getenv("NAME"); X if (full_name == NULL) { X full_name = passwd->pw_gecos; X if ((cp = index(full_name, ','))) X *cp = '\0'; X } X X#ifdef DOMAIN X X /* A heuristic to see if we should tack on a domain */ X X cp = index(host_name, '.'); X if (cp) X fprintf(ser_wr_fp, "From: %s@%s (", X passwd->pw_name, X host_name); X else X fprintf(ser_wr_fp, "From: %s@%s.%s (", X passwd->pw_name, X host_name, X DOMAIN); X#else X fprintf(ser_wr_fp, "From: %s@%s (", X passwd->pw_name, X host_name); X#endif X X for (cp = full_name; *cp != '\0'; ++cp) X if (*cp != '&') X putc(*cp, ser_wr_fp); X else { /* Stupid & hack. God damn it. */ X putc(toupper(passwd->pw_name[0]), ser_wr_fp); X fprintf(ser_wr_fp, passwd->pw_name+1); X } X X fprintf(ser_wr_fp, ")\r\n"); X X fprintf(ser_wr_fp, "Path: %s!%s\r\n", host_name, passwd->pw_name); X} X X X/* X * strneql -- determine if two strings are equal in the first n X * characters, ignoring case. X * X * Parameters: "a" and "b" are the pointers X * to characters to be compared. X * "n" is the number of characters to compare. X * X * Returns: 1 if the strings are equal, 0 otherwise. X * X * Side effects: None. X */ X strneql(a, b, n) register char *a, *b; int n; X{ X char lower(); X X while (n && lower(*a) == lower(*b)) { X if (*a == '\0') X return (1); X a++; X b++; X n--; X } X if (n) X return (0); X else X return (1); X} X X/* X * lower -- convert a character to lower case, if it's X * upper case. X * X * Parameters: "c" is the character to be X * converted. X * X * Returns: "c" if the character is not X * upper case, otherwise the lower X * case eqivalent of "c". X * X * Side effects: None. X */ X char lower(c) register char c; X{ X if (isascii(c) && isupper(c)) X c = c - 'A' + 'a'; X return(c); X} END_OF_FILE if test 6070 -ne `wc -c <'./inews/inews.c'`; then echo shar: \"'./inews/inews.c'\" unpacked with wrong size! fi # end of './inews/inews.c' fi if test -f './rrnpatches/newsetup.SH.pat' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./rrnpatches/newsetup.SH.pat'\" else echo shar: Extracting \"'./rrnpatches/newsetup.SH.pat'\" \(4675 characters\) sed "s/^X//" >'./rrnpatches/newsetup.SH.pat' <<'END_OF_FILE' X*** rn/newsetup.SH Sun Mar 15 19:54:40 1987 X--- rrn/newsetup.SH Thu Feb 25 20:35:26 1988 X*************** X*** 1,5 X case $CONFIG in X! '') . config.sh ;; X esac X echo "Extracting newsetup (with variable substitutions)" X $spitshell >newsetup <newsetup </tmp/n.local\$\$ \\ X X--- 75,80 ----- X -e "/^\$state\./{" \\ X -e " w /tmp/n.\$state\$\$" \\ X -e ' d' \\ X -e '}' X X $sed /tmp/n.local\$\$ \\ X*************** X*** 88,97 X -e '}' X X $sed /tmp/n.local\$\$ \\ X- -e "/^\$cntry\./{" \\ X- -e " w /tmp/n.\$cntry\$\$" \\ X- -e ' d' \\ X- -e '}' \\ X -e "/^\$cont\./{" \\ X -e " w /tmp/n.\$cont\$\$" \\ X -e ' d' \\ X X--- 78,83 ----- X -e '}' X X $sed /tmp/n.local\$\$ \\ X -e "/^\$cont\./{" \\ X -e " w /tmp/n.\$cont\$\$" \\ X -e ' d' \\ X*************** X*** 144,150 X /tmp/n.\$state\$\$ \\ X /tmp/n.\$cntry\$\$ \\ X /tmp/n.\$cont\$\$ \\ X- /tmp/n.mod\$\$ \\ X /tmp/n.news\$\$ \\ X /tmp/n.comp\$\$ \\ X /tmp/n.sci\$\$ \\ X X--- 130,135 ----- X /tmp/n.\$state\$\$ \\ X /tmp/n.\$cntry\$\$ \\ X /tmp/n.\$cont\$\$ \\ X /tmp/n.news\$\$ \\ X /tmp/n.comp\$\$ \\ X /tmp/n.sci\$\$ \\ X*************** X*** 152,159 X /tmp/n.soc\$\$ \\ X /tmp/n.misc\$\$ \\ X /tmp/n.talk\$\$ \\ X- /tmp/n.net\$\$ \\ X- /tmp/n.fa\$\$ \\ X /tmp/n.test\$\$ \\ X | $uniq >\$dotdir/.newsrc X X X--- 137,142 ----- X /tmp/n.soc\$\$ \\ X /tmp/n.misc\$\$ \\ X /tmp/n.talk\$\$ \\ X /tmp/n.test\$\$ \\ X | $uniq >\$dotdir/.newsrc X X*************** X*** 166,172 X /tmp/n.\$state\$\$ \\ X /tmp/n.\$cntry\$\$ \\ X /tmp/n.\$cont\$\$ \\ X- /tmp/n.mod\$\$ \\ X /tmp/n.news\$\$ \\ X /tmp/n.comp\$\$ \\ X /tmp/n.sci\$\$ \\ X X--- 149,154 ----- X /tmp/n.\$state\$\$ \\ X /tmp/n.\$cntry\$\$ \\ X /tmp/n.\$cont\$\$ \\ X /tmp/n.news\$\$ \\ X /tmp/n.comp\$\$ \\ X /tmp/n.sci\$\$ \\ X*************** X*** 173,180 X /tmp/n.soc\$\$ \\ X /tmp/n.rec\$\$ \\ X /tmp/n.talk\$\$ \\ X- /tmp/n.net\$\$ \\ X- /tmp/n.fa\$\$ \\ X /tmp/n.misc\$\$ \\ X /tmp/n.test\$\$ X X X--- 155,160 ----- X /tmp/n.soc\$\$ \\ X /tmp/n.rec\$\$ \\ X /tmp/n.talk\$\$ \\ X /tmp/n.misc\$\$ \\ X /tmp/n.test\$\$ \\ X \$active X*************** X*** 176,182 X /tmp/n.net\$\$ \\ X /tmp/n.fa\$\$ \\ X /tmp/n.misc\$\$ \\ X! /tmp/n.test\$\$ X X $cat <<'EOH' X Done. X X--- 156,163 ----- X /tmp/n.rec\$\$ \\ X /tmp/n.talk\$\$ \\ X /tmp/n.misc\$\$ \\ X! /tmp/n.test\$\$ \\ X! \$active X X $cat <<'EOH' X Done. END_OF_FILE if test 4675 -ne `wc -c <'./rrnpatches/newsetup.SH.pat'`; then echo shar: \"'./rrnpatches/newsetup.SH.pat'\" unpacked with wrong size! fi # end of './rrnpatches/newsetup.SH.pat' fi if test -f './rrnpatches/ng.c.pat' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./rrnpatches/ng.c.pat'\" else echo shar: Extracting \"'./rrnpatches/ng.c.pat'\" \(5064 characters\) sed "s/^X//" >'./rrnpatches/ng.c.pat' <<'END_OF_FILE' X*** rn/ng.c Sun Mar 15 19:54:26 1987 X--- rrn/ng.c Mon May 25 22:41:53 1987 X*************** X*** 48,53 X #include "rcln.h" X #include "last.h" X #include "search.h" X #include "INTERN.h" X #include "ng.h" X #include "artstate.h" /* somebody has to do it */ X X--- 48,54 ----- X #include "rcln.h" X #include "last.h" X #include "search.h" X+ #include "server.h" X #include "INTERN.h" X #include "ng.h" X #include "artstate.h" /* somebody has to do it */ X*************** X*** 110,115 X do_newsgroup(start_command) X char *start_command; /* command to fake up first */ X { X char oldmode = mode; X register long i; /* scratch */ X int skipstate; /* how many unavailable articles */ X X--- 111,121 ----- X do_newsgroup(start_command) X char *start_command; /* command to fake up first */ X { X+ #ifdef SERVER X+ char ser_line[256]; X+ char artname[32]; X+ static long our_pid; X+ #endif SERVER X char oldmode = mode; X register long i; /* scratch */ X int skipstate; /* how many unavailable articles */ X*************** X*** 117,122 X X char *whatnext = "%sWhat next? [%s]"; X X #ifdef ARTSEARCH X srchahead = (scanon && ((ART_NUM)toread[ng]) >= scanon ? -1 : 0); X /* did they say -S? */ X X--- 123,133 ----- X X char *whatnext = "%sWhat next? [%s]"; X X+ #ifdef SERVER X+ if (our_pid == 0) /* Agreed, this is gross */ X+ our_pid = getpid(); X+ #endif SERVER X+ X #ifdef ARTSEARCH X srchahead = (scanon && ((ART_NUM)toread[ng]) >= scanon ? -1 : 0); X /* did they say -S? */ X*************** X*** 125,130 X mode = 'a'; X recent_art = curr_art = 0; X exit_code = NG_NORM; X if (eaccess(ngdir,5)) { /* directory read protected? */ X if (eaccess(ngdir,0)) { X #ifdef VERBOSE X X--- 136,156 ----- X mode = 'a'; X recent_art = curr_art = 0; X exit_code = NG_NORM; X+ X+ #ifdef SERVER X+ sprintf(ser_line, "GROUP %s", ngname); X+ put_server(ser_line); X+ if (get_server(ser_line, sizeof(ser_line)) < 0) { X+ fprintf(stderr, "rrn: Unexpected close of server socket.\n"); X+ finalize(1); X+ } X+ if (*ser_line != CHAR_OK) { X+ if (atoi(ser_line) != ERR_NOGROUP) X+ fprintf(stderr, "rrn: server response to GROUP %s:\n%s\n", X+ ngname, ser_line); X+ return (-1); X+ } X+ #else not SERVER X if (eaccess(ngdir,5)) { /* directory read protected? */ X if (eaccess(ngdir,0)) { X #ifdef VERBOSE X*************** X*** 165,170 X mode = oldmode; X return -1; X } X X #ifdef CACHESUBJ X subj_list = Null(char **); /* no subject list till needed */ X X--- 191,197 ----- X mode = oldmode; X return -1; X } X+ #endif SERVER X X #ifdef CACHESUBJ X subj_list = Null(char **); /* no subject list till needed */ X*************** X*** 293,298 X else if X (!reread && !was_read(art) X && artopen(art) == Nullfp) { /* never read it, & cannot find it? */ X if (errno != ENOENT) { /* has it not been deleted? */ X #ifdef VERBOSE X IF(verbose) X X--- 320,326 ----- X else if X (!reread && !was_read(art) X && artopen(art) == Nullfp) { /* never read it, & cannot find it? */ X+ #ifndef SERVER X if (errno != ENOENT) { /* has it not been deleted? */ X #ifdef VERBOSE X IF(verbose) X*************** X*** 306,311 X skipstate = 0; X sleep(2); X } X switch(skipstate++) { X case 0: X clear(); X X--- 334,340 ----- X skipstate = 0; X sleep(2); X } X+ #endif X switch(skipstate++) { X case 0: X clear(); X*************** X*** 329,334 X default: X putchar('.'); X fflush(stdout); X #define READDIR X #ifdef READDIR X { /* fast skip patch */ X X--- 358,364 ----- X default: X putchar('.'); X fflush(stdout); X+ #ifndef SERVER X #define READDIR X #ifdef READDIR X { /* fast skip patch */ X*************** X*** 341,346 X art = newart - 1; X } X #endif X break; X } X oneless(art); /* mark deleted as read */ X X--- 371,396 ----- X art = newart - 1; X } X #endif X+ #else X+ { X+ char ser_line[256]; X+ ART_NUM newart; X+ X+ put_server("NEXT"); X+ if (get_server(ser_line, sizeof (ser_line)) < 0) { X+ fprintf(stderr, X+ "rrn: unexpected close of server socket.\n"); X+ finalize(1); X+ } X+ if (ser_line[0] != CHAR_OK) X+ newart = lastart + 1; X+ else X+ newart = atoi(ser_line+4); X+ for (i=art; i'./server/netaux.c' <<'END_OF_FILE' X#ifndef lint static char *sccsid = "@(#)netaux.c 1.11 (Berkeley) 2/25/88"; X#endif X X/* X * Routines to deal with network stuff for X * stand-alone version of server. X */ X X#include "common.h" X#include X#include X#ifndef EXCELAN X#include X#endif not EXCELAN X#include X#include X#ifdef USG X#include X#else not USG X#include X#endif USG X X#ifdef ALONE X X X/* X * disassociate this process from the invoker's terminal. X * Close all file descriptors, and then open 0, 1, and 2 to X * somewhere bogus (i.e., "/", O_RDONLY). This way we will know X * that stdin/out/err will at least be claimed. X * X * Parameters: None. X * X * Returns: Nothing. X * X * Side effects: Disassociates this process from X * a terminal; closes file descriptors; X * fd 0-2 opened as O_RDONLY to /. X */ X disassoc() X{ X register int i; X X#ifdef USG X (void) signal(SIGTERM, SIG_IGN); X (void) signal(SIGINT, SIG_IGN); X (void) signal(SIGQUIT, SIG_IGN); X#endif X X if (fork()) X exit(0); X X for (i = 0; i < 10; i++) X (void) close(i); X X#ifdef USG X (void) open("/", 0); X (void) dup2(0, 1); X (void) dup2(0, 2); X setpgrp(); X umask(000); X#else not USG X i = open("/dev/tty", O_RDWR); X if (i >= 0) { X ioctl(i, TIOCNOTTY, 0); X (void) close(i); X } X X i = open("/", O_RDONLY); X if (i >= 0) { X if (i != 0) { /* should never happen */ X (void) dup2(i, 0); X (void) close(i); X } X (void) dup2(0, 1); X (void) dup2(1, 2); X } X#endif not USG X} X X X/* X * get_socket -- create a socket bound to the appropriate X * port number. X * X * Parameters: None. X * X * Returns: Socket bound to correct address. X * X * Side effects: None. X * X * Errors: Syslogd, cause aboriton. X */ X get_socket() X{ X int s; X struct sockaddr_in sin; X#ifndef EXCELAN X struct servent *sp; X X sp = getservbyname("nntp", "tcp"); X if (sp == NULL) { X#ifdef SYSLOG X syslog(LOG_ERR, "get_socket: tcp/nntp, unknown service."); X#endif X exit(1); X } X#endif not EXCELAN X X bzero((char *) &sin, sizeof (sin)); X sin.sin_family = AF_INET; X sin.sin_addr.s_addr = htonl(INADDR_ANY); X#ifndef EXCELAN X sin.sin_port = sp->s_port; X X s = socket(AF_INET, SOCK_STREAM, 0); X#else EXCELAN X sin.sin_port = htons(IPPORT_NNTP); X s = 3; /* WTF??? */ X s = socket(SOCK_STREAM, (struct sockproto *)0, &sin, X (SO_KEEPALIVE|SO_ACCEPTCONN)); X#endif EXCELAN X if (s < 0) { X#ifdef EXCELAN X sleep(5); X return (-1); X#else not EXCELAN X#ifdef SYSLOG X syslog(LOG_ERR, "get_socket: socket: %m"); X#endif SYSLOG X exit(1); X#endif not EXCELAN X } X X#ifndef EXCELAN X if (bind(s, (struct sockaddr *) &sin, sizeof(sin)) < 0) { X#ifdef SYSLOG X syslog(LOG_ERR, "get_socket: bind: %m"); X#endif X exit(1); X } X#endif not EXCELAN X X return (s); X} X X/* X * make_stdio -- make a given socket be our standard input X * and output. X * X * Parameters: "sockt" is the socket we want to X * be file descriptors 0, 1, and 2. X * X * Returns: Nothing. X * X * Side effects: None. X */ X make_stdio(sockt) X int sockt; X{ X if (sockt != 0) { X (void) dup2(sockt, 0); X (void) close(sockt); X } X (void) dup2(0, 1); X (void) dup2(1, 2); X} X X/* X * set_timer -- set up the interval timer so that X * the active file is read in every so often. X * X * Parameters: None. X * X * Returns: Nothing. X * X * Side effects: Sets interval timer to READINTVL seconds. X * Sets SIGALRM to call read_again. X */ X set_timer() X{ X#ifndef USG X struct itimerval new, old; X#endif not USG X extern int read_again(); X X (void) signal(SIGALRM, read_again); X#ifdef USG X alarm(READINTVL); X#else not USG X X new.it_value.tv_sec = READINTVL; X new.it_value.tv_usec = 0; X new.it_interval.tv_sec = READINTVL; X new.it_interval.tv_usec = 0; X old.it_value.tv_sec = 0; X old.it_value.tv_usec = 0; X old.it_interval.tv_sec = 0; X old.it_interval.tv_usec = 0; X X if (setitimer(ITIMER_REAL, &new, &old) < 0) { X#ifdef SYSLOG X syslog(LOG_ERR, "set_timer: setitimer: %m\n"); X#endif SYSLOG X exit(1); X } X#endif not USG X} X X X/* X * read_again -- (maybe) read in the active file again, X * if it's changed since the last time we checked. X * X * Parameters: None (called by interrupt). X * X * Returns: Nothing. X * X * Side effects: May change "num_groups" and "group_array". X */ X read_again() X{ X static long last_mtime; /* Last time active file was changed */ X struct stat statbuf; X X if (stat(activefile, &statbuf) < 0) X return; X X if (statbuf.st_mtime != last_mtime) { X last_mtime = statbuf.st_mtime; X num_groups = read_groups(); X } X} X X X/* X * reaper -- reap children who are ready to die. X * Called by signal. X * X * Parameters: None. X * X * Returns: Nothing. X * X * Side effects: None. X */ X reaper() X{ X#ifndef USG X union wait status; X X while (wait3(&status, WNOHANG, (struct rusage *)0) > 0) X ; X#endif not USG X} X X#else not ALONE X X/* Kludge for greenhill's C compiler */ X static netaux_greenkludge() X{ X} X#endif not ALONE END_OF_FILE if test 4765 -ne `wc -c <'./server/netaux.c'`; then echo shar: \"'./server/netaux.c'\" unpacked with wrong size! fi # end of './server/netaux.c' fi if test -f './server/spawn.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./server/spawn.c'\" else echo shar: Extracting \"'./server/spawn.c'\" \(5169 characters\) sed "s/^X//" >'./server/spawn.c' <<'END_OF_FILE' X#ifndef lint static char *sccsid = "@(#)spawn.c 1.6 (Berkeley) 2/6/88"; X#endif X X#include "../common/conf.h" X X#include "common.h" X X#include X X#ifdef XFER_TIMEOUT static int xfer_lines; static int old_xfer_lines; X#endif X static char tempfile[256]; X X/* X * spawn -- create a child process with the input from the client X * as stdin. X * X * Parameters: "path" is the path of the program to invoke. X * "name" is the name to call the program. X * "flag" is a single flag to be passed to the program. X * "cont_code" is the response code to transmit X * on successful startup. X * "err_code" is the response code to transmit when X * something goes wrong. X * X * Returns: -1 on non-zero return from child, X * 0 on error before fork/exec, X * 1 otherwise. X * X * Side effects: Creates and removes temporary file; X * accepts input from client; forks and execs. X * Can time out if XFER_TIMEOUT is defined. X */ X spawn(path, name, flag, cont_code, err_code, errbuf) X char *path; X char *name; X char *flag; X int cont_code; X int err_code; X char *errbuf; X{ X char line[NNTP_STRLEN]; X register char *cp; X int i, fd; X int fds[2]; X int pid, npid; X int exit_status; X#ifdef XFER_TIMEOUT X int xfer_timeout(); X int (*otimeout)(); X#endif X#ifdef USG X int status; X#else not USG X union wait status; X#endif not USG X register FILE *fp; X X (void) strcpy(tempfile, "/tmp/rpostXXXXXX"); X (void) mktemp(tempfile); X X fp = fopen(tempfile, "w"); X if (fp == NULL) { X printf("%d Cannot create temporary file.\r\n", err_code); X (void) fflush(stdout); X return (0); X } else { X printf("%d Ok\r\n", cont_code); X (void) fflush(stdout); X } X X#ifdef XFER_TIMEOUT X xfer_lines = old_xfer_lines = 0; X otimeout = signal(SIGALRM, xfer_timeout); X (void) alarm(XFER_TIMEOUT); X#endif X X while (fgets(line, sizeof(line), stdin) != NULL) { X#ifdef XFER_TIMEOUT X xfer_lines++; X#endif X if ((cp = index(line, '\r')) != NULL) X *cp = '\0'; X else if ((cp = index(line, '\n')) != NULL) X *cp = '\0'; X X if (line[0] == '.' && line[1] == '\0') X break; X X if (line[0] == '.') X fputs(line+1, fp); X else X fputs(line, fp); X putc('\n', fp); X } X (void) fclose(fp); X X#ifdef XFER_TIMEOUT X (void) alarm(0); X (void) signal(SIGALRM, otimeout); X#endif X X /* See if the connection got closed somehow... */ X X if (line[0] != '.' && line[1] != '\0') { X (void) unlink(tempfile); X#ifdef SYSLOG X# ifdef LOG X syslog(LOG_ERR, "%s spawn: EOF before period on line by itself", X hostname); X# else X syslog(LOG_ERR, "spawn: EOF before period on line by itself"); X# endif X#endif X return (0); X } X X#ifdef POSTER X (void) chown(tempfile, uid_poster, gid_poster); X#endif X X /* Set up a pipe so we can see errors from rnews */ X X if (pipe(fds) < 0) { X#ifdef SYSLOG X syslog(LOG_ERR, "spawn: pipe: %m"); X#endif X (void) unlink(tempfile); X return (-1); X } X X /* X * Ok, now we have the article in "tempfile". We X * should be able to fork off, close fd's 0 to 31 (or X * whatever), open "tempfile" for input, thus making X * it stdin, and then execl the inews. We think. X */ X X pid = vfork(); X if (pid == 0) { /* We're in child */ X#ifdef POSTER X (void) setuid(uid_poster); X (void) setgid(gid_poster); X#endif X X /* Set up stdout and stderr for child */ X X if (fds[1] != 1) { X (void) dup2(fds[1], 1); X (void) close(fds[1]); X } X (void) dup2(1, 2); X X for (i = 3; i < 10; ++i) /* XXX but getdtablesize is too big */ X (void) close(i); X X fd = open(tempfile, O_RDONLY); X if (fd != 0) { X (void) dup2(fd, 0); X (void) close(fd); X } X X execl(path, name, flag, (char *) NULL); X fprintf(stderr, "spawn: execl "); X perror(path); X _exit(-1); /* Error */ X } else { X (void) close(fds[1]); X fp = fdopen(fds[0], "r"); X if (fp == NULL) { X printf("%d Cannot fdopen %s pipe\r\n", err_code, path); X (void) fflush(stdout); X#ifdef SYSLOG X syslog(LOG_ERR, "spawn: pipe: %m"); X#endif X (void) unlink(tempfile); X return (0); X } X X if (errbuf) X *errbuf = '\0'; X X while (fgets(line, sizeof (line), fp) != NULL) { X if (line[0] != '\n') { X if (errbuf) { X if (cp = index(line, '\n')) X *cp = '\0'; X (void) strcat(errbuf, line); X (void) strcat(errbuf, "\\"); X } X#ifdef SYSLOG X syslog(LOG_ERR, "%s: %s", path, line); X#endif X } X } X X while ((npid = wait(&status)) > 0) X if (npid == pid) { X#ifdef USG X exit_status = (status >> 8) & 0xff; X#else not USG X exit_status = status.w_T.w_Retcode; X#endif not USG X break; X } X X (void) fclose(fp); X (void) unlink(tempfile); X (void) fflush(stdout); X if (npid < 0) { X#ifdef SYSLOG X syslog(LOG_ERR, "spawn: wait pid %d: %m", pid); X#endif X return (-1); X } X X#ifdef SYSLOG X if (exit_status != 0) X syslog(LOG_ERR, "spawn: %s exit status %d", X path, exit_status); X#endif X X return (exit_status ? -1 : 1); X } X} X X#ifdef XFER_TIMEOUT X xfer_timeout() X{ X if (old_xfer_lines < xfer_lines) { X old_xfer_lines = xfer_lines; X (void) alarm(XFER_TIMEOUT); X return; X } X X /* Timed out. */ X X printf("%d timeout after %d seconds, closing connection.\r\n", X ERR_FAULT, XFER_TIMEOUT); X fflush(stdout); X X#ifdef LOG X syslog(LOG_ERR, "%s transfer_timeout", hostname); X#endif LOG X X (void) unlink(tempfile); X X exit(1); X} X X#endif XFER_TIMEOUT END_OF_FILE if test 5169 -ne `wc -c <'./server/spawn.c'`; then echo shar: \"'./server/spawn.c'\" unpacked with wrong size! fi # end of './server/spawn.c' fi if test -f './xmit/nntpxmit.1' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'./xmit/nntpxmit.1'\" else echo shar: Extracting \"'./xmit/nntpxmit.1'\" \(5838 characters\) sed "s/^X//" >'./xmit/nntpxmit.1' <<'END_OF_FILE' X.TH NNTPXMIT 1 netnews/NNTP X.SH NAME X.I nntpxmit X\- transmit netnews articles to a remote NNTP server X.SH SYNOPSIS X.I nntpxmit X[ X.B \-a X] X[ X.B \-d X] X[ X.B \-s X] X[ X.B \-r X] X[ X.B \-T X] X[ X.B \-F X] X[ X.B \-D X] hostname|hostname:file [...] X.SH DESCRIPTION X.PP X.I Nntpxmit offers netnews articles [RFC850] named in a queue file (a file of filenames) to a remote NNTP (Network News Transfer Protocol, X[RFC977]) server, transmitting those articles that the remote server indicates that it does not already have. X.PP The command line arguments a processed sequentially, and the flags can thus be toggled several times during one invocation of the program, by giving the options more than once. The options are: X.IP hostname|hostname:file The name of the remote host, and the name of the queue file of articles destined for that host. The hostname may be an internet address in dotted format (e.g. 10.2.0.78, [10.0.0.78]). If the hostname is given without an associated file, it is assumed that the hostname is also the name of the queue file. If the separator is "::" instead of ":", it is assumed that the remote host speaks DECNET, instead of the default, IP/TCP. X.IP -s Toggles reporting of transfer statistics (how many articles we offered them, how many they accepted, etc). X.br Default is X.B ON. X.IP -d Toggles DEBUG output on stderr. This can be used to see exactly what the two systems are saying to each other, except for the actual article text. X.br Default is X.B OFF. X.IP -r Toggles requeuing of failed articles. A failed article is an article that we (client) offer them (remote server), they accept, we transmit, and then they report that they "failed" or dropped the article (i.e. inews(1) on the remote returned non-zero). If we have requeuing set, we save the list of articles that they failed on, and rewrite the queue file with them, so that they get reoffered the next time we initiate transmission to them. X.br Default is X.B ON. X.IP -a This flag says that the next queue file on the command line isn't a queue file, but is a single netnews article to be transmitted to the remote in a single operation. X.IP X.B NOTE: this option causes X.I nntpxmit to exit immediately after this transfer is done (regardless of whatever else is on the command line), and to exit with a code indicating whether the articles was successfully accepted by the remote server (zero exit for success, non-zero for failure). X.PP The next options set the underlying transport protocol that X.I nntpxmit uses. The NNTP specification assumes a TCP-style transport protocol underlies it (i.e. a reliable, flow-controlled, full-duplex byte stream). X.I Nntpxmit assumes that after doing some magic to get a descriptor, it can do read(2) and write(2) calls (and use stdio) to move data and check for errors. By default, X.I nntpxmit will use IP/TCP (DoD Internet Protocol suite). X.IP -T Sets transport protocol to IP/TCP for all remaining transfers (unless reset by other transport flags). Default transport. X.IP -D Sets transport protocol to DECNET for all remaining transfers (unless reset by other transport flags). X.B NOTE: using "::" as the hostname/queue filename separator has the same effect. X.IP -F This says that the hostname is a file descriptor number, already open to a remote server (with some reliable protocol underneath) that was passed to X.I nntpxmit through a fork(2). X.SH "THEORY OF OPERATION" X.PP X.I Nntpxmit implements an interactive ihave/sendme transmission system. Roughly, the protocol is X.IP 1. open the article, fetch out the message-id (required on all netnews articles), and send the command IHAVE to the remote. X.IP 2. The remote will then say either "I've seen it already" or "please send that article to me." X.IP 3. If the response was negative, X.I nntpxmit loops back to step 1 and offers the next article (until queue file EOF). Otherwise, X.I nntpxmit will send the article, using SMTP [RFC821] text transmission conventions X(i.e. CRLF line terminators, and dot escaping). X.IP 4. X.I Nntpxmit waits for the remote to say whether the article was successfully accepted or not. If the answer is negative and requeuing of failed articles is enabled, X.I nntpxmit will queue this article's filename to be written back to the queue file at the end of the session with this remote. X.PP If the communcation link should fail (and X.I nntpxmit detects it through a system call error return), X.I nntpxmit will rewrite the queue file with the article filenames of the articles that it did not transmit (that is, we don't retransmit stuff we've already successfully sent and gotten back an positive confirmation that they got it). X.SH FILES X/tmp/nntpxmitXXXXXX X.SH AUTHOR Erik E. Fair X.SH "SEE ALSO" inews(1), X.br RFC977 \- Network News Transfer Protocol (NNTP), X.br RFC850 \- USENET Article Format standard, X.br RFC821 \- Simple Mail Transfer Protocol (SMTP), X.SH BUGS X.PP Always requeuing failed articles can lead to beating the remote to death with a list of articles that he can't accept for come structural reason. How many of these have to pile up before you should declare that something is seriously wrong with the remote system and stop trying? X.PP While X.B nntpxmit will lock a queue file (your version of UNIX permitting) against multiple invocations of itself, there is no locking with inews(1), which is what writes the queue files in the first place. Therefore, never use X.B nntpxmit on the queue files that inews(1) writes, because two processes writing into the same file without some kind of cooperation will almost certainly trash the file; move them to some other name that inews(1) knows nothing about, so that you won't lose articles to races between inews and nntpxmit. X.PP Adding inews(1) compatible locking to the C code would be much more trouble than it's worth, and violates the KISS principle besides. END_OF_FILE if test 5838 -ne `wc -c <'./xmit/nntpxmit.1'`; then echo shar: \"'./xmit/nntpxmit.1'\" unpacked with wrong size! fi # end of './xmit/nntpxmit.1' fi echo shar: End of archive 4 \(of 9\). cp /dev/null ark4isdone MISSING="" for I in 1 2 3 4 5 6 7 8 9 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 9 archives. rm -f ark[1-9]isdone ark[1-9][0-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0