#ifdef MULTINET
	#define NEED_DECLARE XXX
	#include "multinet_root:[multinet.include]errno.h"
	#include "multinet_root:[multinet.include.sys]types.h"
	#include "multinet_root:[multinet.include.sys]socket.h"
	#include "multinet_root:[multinet.include.sys]time.h"
	#include "multinet_root:[multinet.include.sys]ioctl.h"
	#include "multinet_root:[multinet.include.netinet]in.h"
	#include "multinet_root:[multinet.include]netdb.h"
#endif
#define MAX_CHAN 10
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define EOL "\015\012"

char *ncpy(char *dst, char *src, int len);
void nntp_newchan(void);
void chan_init(int c);
int nntp_chan_init(int i);
void nntp_doclose(int c);

static int read_again[MAX_CHAN];
static short s_listen,chan[MAX_CHAN]; /*Should keep list of inuse ones.*/
static struct sockaddr_in chan_sin[MAX_CHAN];
static char *chan_outbf[MAX_CHAN];
static char *chan_str[MAX_CHAN];
static int chan_busy[MAX_CHAN];
int nchan;

static	struct sockaddr_in sin, sin2;
static	struct hostent *hp;
static	struct servent *sp;
#define BFSZ 4000

int nntp_chan_init(int i)
{
	int noblock=1;
	socket_ioctl(chan[i],FIONBIO,&noblock);
	return TRUE;
}
void nntp_init(void)
{
	int n;
	int on=1;
	char buf[256];
	int i;

	for (i=0; i<MAX_CHAN; i++) {
		chan[i] = -1;	
		chan_outbf[i] = malloc(BFSZ+2);
		chan_str[i] = malloc(100000);
	}
	/*
	 *  Create an IP-family socket on which to listen for connections
	 */

	s_listen = socket(AF_INET, SOCK_STREAM, 0);
	if (s_listen < 0) {
		socket_perror("tcpechoserver: socket");
		exit(0x10000000);
	}

	sp = getservbyname("nntp", "tcp");
	if (sp == NULL) {
		fprintf(stderr, "tcpechoserver: nntp/tcp: unknown service\n");
		exit(0x10000000);
	}

	if (setsockopt(s_listen, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on)) < 0) {
		socket_perror("tcpnntpserver: setsockopt");
		exit(0x10000000);
	}

	sin.sin_family = AF_INET;
	sin.sin_addr.s_addr = INADDR_ANY;
	sin.sin_port = sp->s_port;

	if (bind(s_listen,(struct sockaddr *)  &sin, sizeof (sin)) < 0) {
		socket_perror("tcpnntpserver: bind");
		exit(0x10000000);
	}

	if (listen(s_listen, 5) < 0) {
		socket_perror("tcpnntpserver: listen");
		exit(0x10000000);
	}
}
static struct timeval timeout;
static struct timeval timecopy;
void nntp_wait(void)
{
	int i,nc;
	char rbf[200];
	int r;
	fd_set readfd,writefd,exceptfd;	

	printf("nntp: Wait start\n");

	timeout.tv_sec = 3; /*Wake up once every 3 second*/
	timeout.tv_usec = 0;
again:
	FD_ZERO(&readfd);
	FD_ZERO(&writefd);
	FD_ZERO(&exceptfd);
	FD_SET(s_listen,&readfd);
	for (i=0; i<nchan; i++) if (chan[i]>=0) {
		if (chan[i]>=0) {
		   FD_SET(chan[i],&readfd);
		   FD_SET(chan[i],&exceptfd); 
		   if (chan_busy[i]) FD_SET(chan[i],&writefd);
		}	   
	}
   	timecopy = timeout; /* Because linux clears the value each call */
   	nc = select(getdtablesize(),&readfd,&writefd,&exceptfd,&timecopy);
   	if (nc<0) {
	  /* Find which channel caused the bad status return */
	 for (i=0; i<nchan; i++) if (chan[i]>=0)  {
	 	FD_ZERO(&readfd);
	 	FD_ZERO(&writefd); FD_ZERO(&exceptfd);
	 	FD_SET(chan[i],&readfd);
   	 	timecopy.tv_sec = 0;
	 	nc = select(getdtablesize(), &readfd, &writefd, &exceptfd, &timecopy);
	 	if (nc<0) {
	 	  printf("nntp: which bad Status [%d] %d =%d \n",i,chan[i],nc);
	 	  nntp_doclose(i);
	 	}
      	  }
  	} else {
        if (FD_ISSET(s_listen,&readfd)) {
		printf("nntp: Newchan\n"); 
		nntp_newchan();
	}
	for (i=0; i<nchan; i++) if (chan[i]>=0) {
		if (FD_ISSET(chan[i],&exceptfd)) {
			printf("nntp: Except condition on channel %d %d \n",i,chan[i]);
		}
		/* Write data if we have some and the channel is ready */
		if (chan_busy[i]) if (FD_ISSET(chan[i],&writefd)) {
			nntp_write_now(i);
		}
		if (FD_ISSET(chan[i],&readfd)) {
			/* Send the test data back to this channel*/
			r =  socket_read(chan[i],rbf,100);
			do_send(i);		 
		}
	}
   }
      goto again;
}
int nntp_getchan(void)
{
	int i;
	for (i=0; i<nchan ; i++) {
		if (chan[i]<0) {
			return i;
		}
	}	
	return nchan++;
}
void nntp_doclose(int c)
{	
	printf("chan: real close  %d %d \n",c,chan[c]);
 	if (chan[c]<0) printf("nntp: Channel is not open, PANIC, %d %d \n",c,chan[c]); 
	if (socket_close(chan[c])<0) printf("nntp: Channel close failed\n");
	chan[c] = -1;
	if (c==nchan-1) nchan--; /* should search backwards too, but doesn' matter much*/
}
void nntp_newchan(void)
{
	char buf[1000];
	int n=nntp_getchan(); 
	int sizesin=sizeof(chan_sin[0]);
	int noblock=1;
	int status;
	char *canpost;
   	
	printf("nntp: Newchan connecting [%d]\n",n);
	chan[n] = accept(s_listen,(struct sockaddr *)  &chan_sin[n], &sizesin);
	if (chan[n] < 0) { 
	  socket_perror("tcpnntpserver: accept"); 
	  printf("Socket newchan failed\n");
	  return;
	}
	printf("nntp: open channel %d %d \n",n,chan[n]);
	socket_errno = 0; /* Clear any nameserver errors when connecting*/
	status = 201;
	canpost = "posting disabled";
	canpost = "posting OK"; status=200;
	sprintf(buf, "%d Testing multinet bug \015\012",status);
	nntp_chan_init(n);
	nntp_write(n, buf, strlen(buf));
}
int nntp_write(int c, char *bf, int sz)
{
	strcat(chan_str[c],bf);
	chan_busy[c] = TRUE;
	return TRUE;
}
int nntp_write_now(int c)
{
	int sz;
	int r;
	int blen=strlen(chan_str[c]);

	sz = BFSZ-1;
	if (sz > blen) sz = blen;
	printf("nntp: write %d bytes \n",sz);
	ncpy(chan_outbf[c],chan_str[c],sz);
	if (blen>sz) {
		memmove(chan_str[c],chan_str[c]+sz,strlen(chan_str[c])-sz+1);
	} else {
		strcpy(chan_str[c],"");
		chan_busy[c] = FALSE;
	}
	printf("Writting %d bytes \n",sz);
	r = socket_write(chan[c],chan_outbf[c],sz);
	printf("Written socket_errno %d \n",socket_errno);
	socket_perror("Any errors:");
	if (r<0) {
		printf("nntp: socket_write error\n");
	}
	printf("nntp: write_done\n");
	return r;
}
main()
{
	int c;

	nntp_init();
	nntp_wait();
}
static char bf[28000];
int do_send(int c)
{
	int i;
	strcpy(bf,""); 
	for (i=0; i<100; i++) 
		sprintf(bf+strlen(bf),"%d:1234567890abcdefghij1234567890abcdefgh\015\012",i);
	nntp_write(c,bf,strlen(bf));
	nntp_write(c,bf,strlen(bf)); 
	return TRUE;
}

char *ncpy(char *dst, char *src, int len)
{
	strncpy(dst,src,len);
	dst[len] = 0;
	return dst;
}


