int die(char *s) { printf("dmie %s \n",s); } #ifdef VMS #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" #else #define UCX TRUE #include "fdset.h" #include #include #include #include #include #include #include /* change hostent to comply with BSD 4.3 */ #include #include /* INET symbol definitions */ #define SOCKET_DEF TRUE #endif #endif #ifdef unix #include #include #include #include #include #include #include #ifdef LINUX #include #else /* This one works for solaris , why the hell isn't it standardized */ #include #endif #define SOCKET_DEF TRUE #endif #ifdef SOCKET_DEF #define socket_perror perror #define socket_close close #define socket_open open #define socket_read read #define socket_ioctl ioctl #define socket_write write #define bcopy(src,dst,len) memmove(dst,src,len) #endif #include #include "dnews.h" #include "str.h" #include "lib.h" #include "emsg.h" #define EOL "\015\012" #ifdef NEED_DECLARE int socket(unsigned int address,unsigned int type,unsigned int protocol); void socket_perror(char *s); int socket_read(int channel, char *buffer, int size); int socket_write(int channel, char *buffer, int size); int connect(); int select(); int socket_close(); int setsockopt(); int bind(); int listen(); int accept(); char *bcopy(); char *bset(); char *bzero(); int htons(); int sleep(); int inet_ntoa(); int getdtablesize(); #endif #include #include #include "nntp.h" void channel_read(int c, int gotio); void event_wait(void); void suck_do(void); void lib_sleep(int x); void chan_init(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 String chan_write[MAX_CHAN]; static int chan_busy[MAX_CHAN]; static int chan_close[MAX_CHAN]; int nchan; static struct sockaddr_in sin, sin2; static struct hostent *hp; static struct servent *sp; #define BFSZ 4000 #define emsg printf #define dmsg printf #define imsg printf #define filemsg printf int nntp_chan_init(int i); void nntp_doclose(int c); int nntp_chan_init(int i) { int noblock=1; chan_close[i] = FALSE; socket_ioctl(chan[i],FIONBIO,&noblock); str_setlen(&chan_write[i],0); /* No more to write */ return TRUE; } int nntp_chan(int i) { return (int) chan[i]; } void nntp_init(void) { int n; #ifdef UCX char on=1; #else int on=1; #endif char buf[256]; int i; for (i=0; is_port; if (bind(s_listen,(struct sockaddr *) &sin, sizeof (sin)) < 0) { filemsg("nntp: Can't bind \n"); socket_perror("tcpnntpserver: bind"); exit(0x10000000); } if (listen(s_listen, 5) < 0) { filemsg("nntp: Can't set listen \n"); socket_perror("tcpnntpserver: listen"); exit(0x10000000); } dmsg("nntp: init done\n"); } static struct timeval timeout; static struct timeval timecopy; void nntp_setsleep(int x) /* Used when background job wants to be called alot*/ { timeout.tv_sec = x; } void nntp_wait(void) { int i,nc; fd_set readfd,writefd,exceptfd; dmsg("nntp: Wait start\n"); timeout.tv_sec = 3; /*Wake up once a second*/ timeout.tv_usec = 0; again: FD_ZERO(&readfd); FD_ZERO(&writefd); FD_ZERO(&exceptfd); FD_SET(s_listen,&readfd); for (i=0; i=0) { if (chan_close[i]) if (!chan_busy[i]) nntp_doclose(i); } for (i=0; 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) { for (i=0; 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) { filemsg("nntp: which bad Status [%d] %d =%d \n",i,chan[i],nc); nntp_doclose(i); } } } else { if (FD_ISSET(s_listen,&readfd)) {emsg("nntp: Newchan\n"); nntp_newchan();} for (i=0; i=0) { if (FD_ISSET(chan[i],&exceptfd)) { dmsg("nntp: Except condition on channel %d %d \n",i,chan[i]); } if (chan_busy[i]) if (FD_ISSET(chan[i],&writefd)) { nntp_write_now(i); } if (FD_ISSET(chan[i],&readfd)) { /* dmsg("nntp: chan_read %d\n",i); */ channel_read(i,TRUE); /* dmsg("nntp: chan_read_done \n"); */ } } suck_do(); /*do back ground jobs */ } goto again; } int nntp_getchan(void) { /* shoould search thru list for unallocated one.*/ int i; for (i=0; ih_name); } wmsg("nntp: open channel %d %d \n",n,chan[n]); status = 201; canpost = "posting disabled"; canpost = "posting OK"; status=200; sprintf(buf, "%d %s Dynamic-NEWS Version %s, %s \015\012", status,"myname",DNEWS_VERSION,canpost); nntp_chan_init(n); nntp_write(n, buf, strlen(buf)); } int nntp_open(char *dst_name) { int dst_port=119; struct hostent *hp; struct sockaddr_in sin; int noblock=1; int st; int n=nntp_getchan(); char bf[200],*s; if (strchr(dst_name,':')!=NULL) { strcpy(bf,dst_name); s = strchr(bf,':'); *s = 0; dst_name = bf; if (s==NULL) emsg("nntp: Thats very strange\n"); dst_port = atoi(s+1); if (dst_port==0) dst_port = 119; } hp = gethostbyname(dst_name); if (hp==NULL) { emsg("nntp: Hostname not found {%s} \n",dst_name); return -1; } chan[n] = socket(hp->h_addrtype,SOCK_STREAM, 0); if (chan[n]<0) { socket_perror("Socket"); return -1;} sin.sin_family = hp->h_addrtype; bcopy(hp->h_addr, &sin.sin_addr, hp->h_length); sin.sin_port = htons(dst_port); st = connect(chan[n],(struct sockaddr *) &sin, sizeof(sin)); if (st<0) { socket_perror("connect"); return -1;} nntp_chan_init(n); return n; } int nntp_write(int c, char *bf, int sz) { str_adds(&chan_write[c],bf,sz); chan_busy[c] = TRUE; return TRUE; } int nntp_write_now(int c) { int sz; int r; int blen=str_len(&chan_write[c]); sz = BFSZ-1; if (sz > blen) sz = blen; dmsg("nntp: write %d bytes \n",sz); ncpy(chan_outbf[c],str_s(&chan_write[c]),sz); if (blen>sz) { str_right(&chan_write[c],sz); } else { str_setlen(&chan_write[c],0); /* No more to write */ chan_busy[c] = FALSE; } printf("Writenow {%s} \n",chan_outbf[c]); r = socket_write(chan[c],chan_outbf[c],sz); if (r<0) { filemsg("nntp: socket_write error\n"); nntp_close(c); } dmsg("nntp: write_done\n"); return r; } int nntp_read(int c, char *bf, int sz) { int r; int nbytes; if (chan[c]<0) { emsg("nntp: Channel is not open, PANIC, %d %d \n",c,chan[c]); return -1; } #ifdef unix socket_ioctl(chan[c],FIONREAD,&nbytes); if (nbytes0) { /* dmsg("nntp: Socket read %d bytes \n",sz); */ r = socket_read(chan[c],bf,sz); } if (r<500) dmsg("nntp: Socket read_done, got %d bytes\n",r); return r; } void hexdump(char *x) { int i; printf("Hex: "); for (i=0; i<8; i++,x++) { printf("%2x ",*x); } printf("\n"); } int nntp_isopen(int c) { if (chan[c]<0) return FALSE; return TRUE; } char *nntp_hostname(void) { static char host[200],dom[200],both[300]; if (gethostname(host,190)!=0) emsg("nntp: Can't get host name\n"); return host; } #ifdef NEED_DTABLE int getdtablesize(void) { return 30; } #endif main() { int c; nntp_init(); nntp_wait(); } enum {S_OPEN,S_MODE,S_LIST,S_GROUP,S_NEXT,S_LOOP,S_WAIT}; static char *state_name[]={ "S_OPEN","S_MODE","S_LIST","S_GROUP","S_NEXT","S_LOOP","S_WAIT",NULL }; int nntp_put(int chan, char *s) { printf("Write {%s} \n",s); return nntp_write(chan,s,strlen(s)); } static int state,newstate; static char *wait_str="startxx"; #define wait_for(xx) newstate=state+1; state=S_WAIT; wait_str = xx; void suck_do(void) { static int c; if (newstate!=S_GROUP) printf("State %d {%s} wait {%s} \n",state,state_name[state],wait_str); switch (state) { case S_OPEN: c = nntp_open("news.palm.cri.nz"); wait_for("200"); break; case S_MODE: nntp_put(c,"mode reader\015\012"); wait_for("200"); break; case S_LIST: nntp_put(c,"list\015\012"); wait_for(".\015\012"); break; case S_GROUP: nntp_put(c,"group comp.os.vms\015\012"); wait_for("211"); break; case S_NEXT: nntp_put(c,"next\015\012"); state++; break; case S_LOOP: state = S_LIST; break; case S_WAIT: break; } } #define MAXREC 30000 #define INSIZE MAXREC #define LF "\012" void channel_read(int c, int xxx) { int nn,rlen; char *s1,*s2; char tmp[200],rec[MAXREC]; static int n[MAX_CHAN],r[MAX_CHAN]; static char *buf[MAX_CHAN]; /* Increase to 8001 when debuging finished*/ static int want; if (buf[c]==NULL) buf[c] = (char *) malloc(INSIZE); want = INSIZE-1-n[c]; if (want>2000) want = 2000; /* Limit the size of chunks we process */ if (want<=0) { emsg("chan: Record too big in item, throwing it away, tough\n"); n[c] = 0; } nn = nntp_read(c, buf[c]+n[c],want); if (nn==0) emsg("fatal: Read zero bytes, asked for %d bytes \n",want); if (nn>0) n[c] +=nn; if (nn<=0) {nntp_close(c); n[c] = 0;} else if (n[c]>0) { s1 = buf[c]; s1[n[c]] = 0; s2 = strstr(s1,LF); if (s2==NULL) return; for (;s2!=NULL;) { rlen = s2-s1+1; if (rlen>=(MAXREC-100)) { emsg("Record too big %d \n",rec); rlen = MAXREC-100; } ncpy(rec,s1,rlen); /*dmsg("chanrec: Got rec n[%d]=%d (%d) \n",c,n[c],rlen);*/ n[c] -= rlen; if (rec[rlen-2]!='\r') { /* add CR if missing */ strcpy(rec+rlen-1,EOL); rlen++; } chan_read(c,rec,rlen); s1 = s2 + 1; s2 = strstr(s1,LF); } memmove(buf[c],s1,strlen(s1)+1); } } int chan_read(int c, char *ss, int sz) { int r=0; if (newstate!=S_GROUP) printf("Chan_read, {%s} \n",ss); if (strncmp(ss,wait_str,strlen(wait_str))==0) { printf("Matched {%s} \n",wait_str); state=newstate; wait_str = "tennis.rackque.asdf"; } return TRUE; } char *ncpy(char *dst, char *src, int len) { strncpy(dst,src,len); dst[len] = 0; return dst; } #undef emsg #undef dmsg #undef wmsg void emsg(va_list arg_list, ...) { printf("emsg \n"); } void dmsg(va_list arg_list, ...) { printf("dmsg \n"); } void wmsg(va_list arg_list, ...) { printf("dmsg \n"); }