
*** Modified files in JOE when it aborted on Sat Aug 17 07:47:55 1996
*** JOE was aborted by signal 15

*** File 'nntpd.c'
/* Hacked to NNTP by jason fesler 8/10/95 */
/* This is a *DUMP* nntp receiver!  */
/* Any POST or IHAVE will put it in POST mode */
/* QUIT is the only other command known */
/* if the environmentvariable NNTPSERVER is set, it will */
/* allow connections only from that machine.  MUST USE CANONICAL NAME */
/* ie, calweb.calweb.com (instead of the alias news.calweb.com) */
/* as this is compared against reverse-IP address lookup. */

/*
 * For a real news server, see CHANGI; this is just a low-memory usage hack
 * for my personal needs.
 */

/******************************************************************
*                                                                 *
* NNTPD.C NNTP daemon for OS/2 using EMX.                         *
* Based on SMTPD by (c) 1995 Pete Appleton.                       *
* Code is subject to GNU license conditions.                      *
* createunique() adapted from Dr. Niel Kempson's deliver.exe      *
*                                                                 *
******************************************************************/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/*
 * #include <os2.h>
 */
#include <sys\types.h>
#include <sys\socket.h>
#include <netinet\in.h>
#include <arpa\inet.h>
#include <unistd.h>
#include <netdb.h>
#include <fcntl.h>
#include <io.h>
#include <share.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <signal.h>
#include <setjmp.h>
#include "nntpd.h"


#define PORT 119
#define TIMEOUT 300
int             inetd = 0;
int             port = PORT;
int             debug = 0;
int             quiet = 0;
char            nntpserver[256];
long            starttime, stoptime, totalmessages;


/* Can't someone just do a "#include *" extension? */

int             hsock_in, hsock_out;	/* socket descriptors, kept global
					 * for close routines */
int             daemon_stat;	/* daemon status, ditto */

void            closein(void);
void            closeout(void);
void            stripcrlf(char *);


int             alarmhit = 0;
char            theirname[256];
char            colorstring[256] = "";

jmp_buf         jbuf;
char            lastuser[256] = "";

void
                maybesleep(void);


void
myhandler(int sig)
{
	alarmhit = sig;
	signal(sig, SIG_ACK);
	switch (sig) {
	case SIGPIPE:
		fprintf(stderr, "SIGNAL %i: Broken pipe (they disconnected)\n", sig);
		break;
	case SIGALRM:
		fprintf(stderr, "SIGNAL %i: Alarm (timeout)\n", sig);
		break;
	default:
		fprintf(stderr, "SIGNAL %i: Unhandled signal\n", sig);
		break;
	}
}

int
quiethandler(int sig)
{
	alarmhit = sig;
	signal(sig, SIG_ACK);
	printf("No identd; longjmp'ing\n");
	longjmp(&jbuf, 1);
}


char           *
datestring(char *s)
{
	static char     buf[150];
	struct tm      *time_now;
	time_t          secs_now;
	char            tzone[256];

	long            temp;
	tzset();
	time(&secs_now);
	time_now = localtime(&secs_now);
	strftime(buf, sizeof(buf) - 1, s, time_now);
	return buf;
}


void
doingnews(int i)
{
	FILE           *file;
	char            buf[256];
	if (getenv("NNTPSTAT"))
		strcpy(buf, getenv("NNTPSTAT"));
	else
		return;
	file = fopen(buf, "wt");
	printf("Updating status file %s\n", buf);
	if (file) {
		if (i)
			fprintf(file, "NNTPD_News Rcv'g since %s (will lag)\n", datestring("%H:%M"));
		else
			fprintf(file, "NNTPD_News idle since %s\n", datestring("%H:%M"));
		fclose(file);

	}
}

char           *
trythis(int socket, int portnum)
{
	int             length;
	struct sockaddr sa;
	struct sockaddr_in *sin = (struct sockaddr_in *) & sa;
	struct hostent *hp;
	static char     host_name[256];
	length = sizeof(sa);

	if (getpeername(socket, &sa, &length) < 0) {
		/* function failed, example errno, whatever... */
		return "foobar";
		/* exit(), return, break and so forth */
	}
	/* Now, resolve the address */

	hp = gethostbyaddr((char *) &sin->sin_addr.s_addr,
			   sizeof(sin->sin_addr.s_addr),
			   AF_INET);
	strcpy(host_name, (char *) (hp ? hp->h_name : inet_ntoa(sin->sin_addr)));

	if (inetd)
		printf("%sNNTP:%5u>>> Incoming connection is from %s\n", colorstring, inetd, host_name);
	else
		printf("Incoming connection is from %s\n", host_name);

	signal(SIGPIPE, quiethandler);
	signal(SIGALRM, quiethandler);
	alarm(15);
	/* iduser(portnum, sin); */
	alarm(0);

	signal(SIGPIPE, myhandler);
	signal(SIGALRM, myhandler);

	if (lastuser[0]) {
		if (inetd)
			printf("%sNNTP:%5u>>> identd reports %s\n", colorstring, inetd, lastuser);
		else
			printf("identd reports %s\n", lastuser);

	}
	return host_name;
}




void
main(int argc, char **argv)
{
	char            buffer[80];
	char           *hostname;
	char            hostipbuf[256];	/* used when hostname returns NULL */
	char            dlvr_agent[1024];
	struct sockaddr_in sock_in, sock_out;
	struct hostent *hoststruct, *clientstruct;
	FILE           *fi, *fo;
	int             dlvr_type, i, x;
	unsigned char   a, b, c, d;
	time_t          t;
	char           *p;	/* gen purpose pointer */

	int             processconnection(char *, char *, FILE *, FILE *, int, char *);
	void            usage(char *);

	i = getpid() % 14;
	switch (i) {
	case 0:
		strcpy(colorstring, "[0;31m");
		break;
	case 1:
		strcpy(colorstring, "[0;32m");
		break;
	case 2:
		strcpy(colorstring, "[0;33m");
		break;
	case 3:
		strcpy(colorstring, "[0;34m");
		break;
	case 4:
		strcpy(colorstring, "[0;35m");
		break;
	case 5:
		strcpy(colorstring, "[0;36m");
		break;
	case 6:
		strcpy(colorstring, "[0;37m");
		break;
	case 7:
		strcpy(colorstring, "[0;1;31m");
		break;
	case 8:
		strcpy(colorstring, "[0;1;32m");
		break;
	case 9:
		strcpy(colorstring, "[0;1;33m");
		break;
	case 10:
		strcpy(colorstring, "[0;1;34m");
		break;
	case 11:
		strcpy(colorstring, "[0;1;35m");
		break;
	case 12:
		strcpy(colorstring, "[0;1;36m");
		break;
	case 13:
		strcpy(colorstring, "[0;1;37m");
		break;
	}



	debug = 0;
	if (getenv("DEBUG"))
		debug = 1;
	if (hostname = getenv("NNTPSERVER"))
		strcpy(nntpserver, hostname);
	signal(SIGPIPE, myhandler);
	signal(SIGALRM, myhandler);
	gethostname(buffer, 80);
	hoststruct = gethostbyname(buffer);
	a = hoststruct->h_addr[0];
	b = hoststruct->h_addr[1];
	c = hoststruct->h_addr[2];
	d = hoststruct->h_addr[3];
	if (hoststruct->h_name == NULL) {	/* no name */
		hoststruct->h_name = hostipbuf;
		sprintf(hostipbuf, "%i.%i.%i.%i", a, b, c, d);
	}
	hostname = strdup(hoststruct->h_name);

	if (argc == 2) {
		if (stricmp(argv[1], "-t")) {
			usage(argv[0]);
			exit(1);
		}
		dlvr_type = DONTSPOOL;
	} else {
		dlvr_type = SPOOLDIRECT;
		strcpy(dlvr_agent, ".\\");
		for (i = 1; i < argc; i++) {
			p = argv[i];
			if (!p)
				continue;

			if (stricmp(p, "-p") == 0) {
				i++;
				p = argv[i];
				strcpy(dlvr_agent, p);
				if (*p)
					if (p[strlen(p) - 1] == '\\')
						p[strlen(p) - 1] = 0;

			} else if (strcmp(p, "-q") == 0) {
				quiet = 1;
			} else if (stricmp(p, "-s") == 0) {
				i++;
				p = argv[i];
				inetd = atol(p);
				printf("%sNNTP:%5u--- NNTPD Daemon Starting\n",
				       colorstring, inetd);
			} else {
				printf("NNTPD: Invalid option \"%s\"\n", p);
				usage(argv[0]);
				exit(1);
			}
		}
	}
	if (!inetd) {
		printf("\x1b[0;1;36mNNTP Daemon for GIGO 7/14/96 (C) 1995,1996 Jason Fesler.\n");
		printf("\x1b[0;36mOriginal code (C) 1995 Pete Appleton, and subject to GNU license.\n");
		printf("\x1b[0;1;33m");	/* bright for warnings! */
		hsock_in = socket(AF_INET, SOCK_STREAM, 0);
		memset(&sock_in, 0, sizeof(sock_in));
		i = 1;
		x = setsockopt(hsock_in, SOL_SOCKET, SO_REUSEADDR, &i, sizeof(i));
		if (x) {
			perror("Error on setsockopt()");
			exit(1);
		}
		printf("Daemon configured for %s (%i.%i.%i.%i) port %i\n", hostname, a, b, c, d, PORT);

		sock_in.sin_family = AF_INET;
		sock_in.sin_addr.s_addr = INADDR_ANY;
		sock_in.sin_port = htons(PORT);

		memset(buffer, 0, 80);
		if (hsock_in == -1) {
			perror("Error occured on socket()");
			exit(1);
		}
		atexit(closein);
		x = bind(hsock_in, (struct sockaddr *) & sock_in, sizeof(sock_in));
		if (x == -1) {
			perror("Error occured on bind()");
			exit(1);
		}
	}
	do {
		if (!inetd) {
			x = listen(hsock_in, 0);
			if (x == -1) {
				perror("Error occured on listen()");
				exit(1);
			}
			if (nntpserver[0] == 0) {
				printf("\x1b[0;1;5;36mNNTPSERVER environment variable not set; running INSECURE!\n");
			}
			printf("\x1b[31m");
			printf("Waiting for connection ");
			if (nntpserver[0])
				printf("from %s", nntpserver);
			printf("\n");
			i = sizeof(sock_out);
			hsock_out = accept(hsock_in, (struct sockaddr *) & sock_out, &i);
			if (hsock_out == -1) {
				perror("Error occured on accept()");
				exit(1);
			}
		} else {
			hsock_out = _impsockhandle(inetd, 0);
			if (hsock_out == -1) {
				printf("NNTPD: error occured on accept()");
				exit(1);
			}
		}
		time(&starttime);
		totalmessages = 0;
		fo = fdopen(hsock_out, "w");
		fi = fdopen(hsock_out, "r");
		if (!fo) {
			printf("Can't open output stream\n");
			exit(1);
		}
		if (!fi) {
			printf("Can't open input stream\n");
			exit(1);
		}
		atexit(closeout);

		strcpy(theirname, trythis(hsock_out, PORT));

		time(&t);
		if (!inetd)
		printf("Connection accepted from %s  %s\n", theirname, ctime(&t));
		
		printf("\x1b[0;1;33m");
		daemon_stat = STATUS_TRANSINPROGRESS;
		doingnews(1);
		x = processconnection(dlvr_agent, hostname, fi, fo, dlvr_type, theirname);
		time(&stoptime);
		if (stoptime == starttime)
			stoptime++;
		doingnews(0);
		if (totalmessages)
			printf("Total %lu messages over %lu seconds (%lu.%02lu m/s)\n",
			       totalmessages,
			       (stoptime - starttime),
			       ((totalmessages * 100) / (stoptime - starttime)) / 100,
			       ((totalmessages * 100) / (stoptime - starttime)) % 100);
		daemon_stat = STATUS_IDLE;

		if (x) {
			printf("\x1b[0;1;33mNNTPD session failed... ");
		}
		switch (x) {
		case CONN_NORMTERM:
			/* printf("Connection terminated normally.\n"); */
			break;
		case CONN_SOCKETBROKEN:
			printf("Broken socket\n");
			break;
		case CONN_AGENTERROR:
			printf("Couldn't open delivery agent.");
			break;
		case CONN_UNKNOWN:
			printf("Unknown error!\n");
			break;
		default:
			printf("timeout, or error in daemon!\n");
		}
		close(hsock_out);
		fclose(fi);
		fclose(fo);
		if (inetd)
			break;	/* quit! */
	} while (1);
}

int
processconnection(char *dlvr_agent, char *hostname, FILE * fi, FILE * fo, int dlvr_type, char *clientname)
{

	int             sosend(FILE *, char *);
	int             soread(FILE *, char *);
	char           *transp(char *);
	FILE           *creatunique(char *);

	int             retcode = CONN_NORMTERM, heloflag = 0, mailflag = 0, rcptflag = 0, x = 0, i;
	char            inp_line[MAXDATA];
	char            buf2[MAXDATA];
	long            pos, posstart;
	FILE           *pipe;
	char           *commands[] = {"post", "mail from:", "rcpt to:", "ihave", "quit", "rset", "noop", "$$$"};
	char            buffer[256];
	char            buffer2[256];
	long            articlecount = 0;
	char           *temp;
	time_t          t;
	struct hostent *claimedstruct;
	int             headers;

	inp_line[0] = '\0';
	alarmhit = 0;
	buffer[0] = 0;
	if (nntpserver[0])
		strcpy(buffer, nntpserver);
	if (buffer[0])
		if (stricmp(buffer, theirname) != 0) {
			sprintf(buffer2, "502 GIGO NNTPD server can't talk to %s.  Goodbye.\r\n", theirname);
			sosend(fo, buffer2);
			return -1;
		}
	sprintf(buffer2, "200 GIGO NNTPD Server Ready.  (Posting Ok)\r\n");
	sosend(fo, buffer2);
	memset(buffer2, 0, sizeof(buffer2));
	do {
		memset(inp_line, 0, sizeof(inp_line));
		x = soread(fi, inp_line);
		/* fprintf(stderr,"alarmhit=%i |",alarmhit); */
		if (alarmhit) {
			retcode = CONN_SOCKETBROKEN;
			return;
		}
		if (x == -1) {
			retcode = CONN_SOCKETBROKEN;
		} else {
			if (debug) {
				time(&t);
				printf("\x1b[0;36m%s>>> %s", datestring("%H:%M:%S "), inp_line);
			}
			for (i = 0; i <= HASHCOMMS; i++) {
				if (!strnicmp(commands[i], inp_line, strlen(commands[i])))
					break;
			}
		}
		switch (i) {
		case 0:
			goto ihave;
		case 1:
	what:
			sprintf(buffer, "500 What?\r\n");
			sosend(fo, buffer);
			break;
	ihave:
		case 3:
			x = 0;
			switch (dlvr_type) {
			case DONTSPOOL:
				pipe = fopen("nul", "w");
				printf("Would have opened mail pipe!\n");
				break;
			case SPOOLDIRECT:
				pipe = creatunique(dlvr_agent);
				break;
			}
			if (!pipe)
				x = -1;
			if (!x) {
				sosend(fo, "335 Ok\r\n");
				headers = 1;
				do {
					x = soread(fi, inp_line);

					temp = transp(inp_line);
					stripcrlf(temp);
					if (temp != NULL && x != -1) {
						if (dlvr_agent) {
							fprintf(pipe, "%s\n", temp);
							strcpy(buf2, temp);
							strupr(buf2);
							if (headers)
								if (strncmp(buf2, "NEWSGROUPS:", 11) == 0) {
									articlecount++;
									strcpy(temp + 65, "..");
									if (quiet == 0)
										if (inetd)
											printf("%sNNTPD:%5u>>> %05i %s\n",
											       colorstring, inetd, articlecount, temp + 11);
										else
											printf("%s %05i %s\n", datestring("%H:%M:%S"), articlecount, temp + 11);
								}
							if (buf2[0] == 0)
								headers = 0;

						}
					} else {
						x = -1;
					}
					if (alarmhit) {
						if (dlvr_agent)
							fprintf(pipe, "\n\n** Error on NNTP receive; you may see duplicates of this message.\n\n");
						x = -1;
						fclose(pipe);
						mailflag = 0;
						rcptflag = 0;
						retcode = CONN_SOCKETBROKEN;
						return;
					}
				} while (x != -1);
				sosend(fo, "235 Garbage in, garbage out\r\n");
				/*
				 * printf("\x1b[0;1;33mReceived mail\n");
				 */
				x = 0;
				maybesleep();
			} else {
				sosend(fo, "451 Error in NNTP daemon ;-(\r\n");
			}
			totalmessages++;
			fclose(pipe);
			if (!x) {
				mailflag = 0;
				rcptflag = 0;
			}
			x = 0;
			break;
		case 2:
			goto what;
		case 4:
			x = -1;
			sprintf(buffer, "205 %s OK, see ya!\r\n", hostname);
			sosend(fo, buffer);
			break;
		case 5:
			sosend(fo, "250 OK Rebooting..\r\n");
			fclose(pipe);
			mailflag = 0;
			rcptflag = 0;
			break;
		case 6:
			sosend(fo, "250 Task intensive operation aborted\r\n");
			break;
		default:
			sosend(fo, "503 Huh?\r\n");
		}
	} while (x != -1);

	return (retcode);
}

int
sosend(FILE * file, char *data)
{
	int             retcode;

	retcode = fputs(data, file);
	if (debug) {
		printf("\x1b[0;32m%s <<< %s", datestring("%H:%M:%S "), data);
	}
	fflush(file);
	if (retcode == EOF) {
		retcode = -1;
	} else {
		retcode = strlen(data);
	}
	return (retcode);
}

int
soread(FILE * file, char *data)
{
	int             retcode;
	char           *temp;
	alarm(TIMEOUT);		/* Be sure to abort out of routines */
	temp = fgets(data, MAXDATA, file);
	alarm(0);		/* turn off the alarm */
	if (temp) {
		retcode = strlen(data);
	} else {
		retcode = -1;
	}
	return (retcode);
}

void
stripcrlf(char *temp)
{
	if (temp) {
		if (strchr(temp, '\r')) {
			*strchr(temp, '\r') = '\0';
		}
		if (strchr(temp, '\n')) {
			*strchr(temp, '\n') = '\0';
		}
	}
}

void
closein(void)
{
	close(hsock_in);
}

void
closeout(void)
{
	close(hsock_out);
}

char           *
transp(char *dataline)
{
	static char     retval[2048];
	strcpy(retval, dataline);
	stripcrlf(retval);

	if (retval[0] == '.') {
		if (retval[1] == '\0') {
			return NULL;
		} else {
			return &retval[1];
		}
	}
	return &retval[0];
}

FILE           *
creatunique(char *path)
{
	FILE           *file;
	time_t          t;
	int             fh, i;
	static char     fname[1024];
	time(&t);
	fh = -1;

	strcpy(fname, path);
	for (i = 0; i < 1000; ++i) {
		sprintf(fname, "%s\\%.8lx.bag", path, (unsigned long) (t + i), i);
		fh = sopen(fname, O_WRONLY | O_CREAT | O_EXCL, SH_DENYRW, S_IREAD | S_IWRITE);

		if (fh != -1)
			break;

		if (errno != EEXIST) {
			perror(fname);
		}
	}
	if (fh == -1) {
		file == NULL;
	} else {
		file = fdopen(fh, "wb");
		if (debug)
			printf("opening %s\n", fname);
	}

	return (file);
}

void
usage(char *exename)
{
	printf("\nUsage:  %s -p <directory> \n",
	       strlwr(strrchr(exename, '\\') + 1));
}


void
maybesleep(void)
{
	char            buf[256];
	char           *p;
	FILE           *file;
	int             i;
	p = getenv("ETC");
	strcpy(buf, p ? p : "c:\\tcpip\\etc");
	strcat(buf, "\\nntp.wait");
	file = fopen(buf, "rt");
if (file) {		
		
	fgets(buf, sizeof(buf), file);
	fclose(file);
	i = atoi(buf);
	if (i > 15)
		printf("Pausing %i\n");
	sleep(i);
	 }
    /*Sleep extra 5 seconds while line 2 VMODEM is in use */
     file = fopen("d:\\fd\\semaphor\\fdinsess.2","rt"); 
     if (file) {
     close(file);
     sleep(5);	
     }else printf("FD not in session\n");
     
}
