home *** CD-ROM | disk | FTP | other *** search
Text File | 2003-06-11 | 38.5 KB | 1,705 lines |
- .oO Phrack Magazine Oo.
-
- Volume Seven, Issue Forty-Nine
-
- File 09 of 16
-
- by Dr.Dimitri Vulis (KOTM)
-
- A Content-Blind Cancelbot for Usenet (CBCB)
-
- Usenet News is a popular system for transmitting articles. Historically it
- used to propagate over UUCP. However today most of the transmission is done
- over the Internet TCP/IP connections using the NNTP protocol (RFC 977).
-
- Each article consists of a series of headers of the form
- Keyword: value
- followed by a blank line, followed by the body of the message.
- Some required headers are self-explanatory: From:, Date:, Subject:.
-
- The Newsgroups: header identifies a series of keywords that can be used
- to search for articles in the newsfeed. For example:
- Newsgroups: news.admin.policy,comp.lang.c
- identifies a Usenet article relevant to both Usenet administrative policy
- and to the C computer language.
-
- The Message-Id: header uniquely identifies each article. For example:
- Message-Id: <12341223@whitehouse.gov>
- The message-ids are not supposed to be recycled.
-
- The cancelbot program is supposed to search the user-specified newsgroups for
- articles whose headers match user-specified regular expressions and to issue
- special 'cancel' control articles. It will copy some of the headers from the
- original message and add a special header:
- Control: cancel <message-id>
-
- This program is an NNTP client. Much of the processing is offloaded to an
- NNTP server, to which the cancelbot talks using the Internet sockets protocol.
-
- This cancelbot does not look at article bodies and is therefore content-blind.
-
- Inputs:
-
- argv[1] (required) hosts file
-
- A line that starts with # is a comment. Otherwise, each line contains the
- following 5 fields:
-
- 1. hostname (some.domain.com) or ip address (a.b.c.d)
- 2. port (normally 119)
- 3. Y/N - do we ask this host for NEWNEWS/HEADER?
- 4. I/P/N - do we inject cancels to this host with IHAVE, POST, not at all
- 5. Timeout - the number of seconds to wait for a response from this server.
-
- Example of a hosts file:
-
- # ask the local server for new news and post back the cancels
- 127.0.0.1 119 Y P 60
- # don't get message-ids from remote server, but give it cancels via IHAVE
- news.xx.net 119 N I 300
-
-
- argv[2] (required) target file
-
- A line that starts with # is a comment. Otherwise, each line contains the
- following 9 fields:
-
- 1. List of newsgroups to be scanned for new messages. This is not interpreted
- by the cancelbot, but passed on to the NNTP server. Per RFC 997, multiple
- groups can be separated by commas. Asterisk "*" may be used to match multiple
- newsgroup names. The exclamation point "!" (as the first character) may be used
- to negate a match. Warning: specifying a single * will generate a lot of data.
-
- Example: news.groups,comp.*,sci.*,!sci.math.*
-
- 2. A watchword (case-sensitive) that needs to be contained in the article
- headers for the cancel to be issued.
-
- 3. Format of the Subject: header in the cancel article.
- C - Subject cancel <message-id> (same as Control:)
- O - Subject: header copied from the original article
- N - none.
- If N is specified, then Subject: MUST be provided in the file appended to
- the header, or the cancel won't propagate.
-
- 4. cancel message-id prefix
- normally cancel. or cn.
-
- Most cancellation articles follow the so-called $alz convention:
- Control: cancel <message.id>
- Message-id: <cancel.message.id>
- However this is not a requirement.
-
- 5. path constant (string to put in path). May be 'none'.
- 6. path copy # (number of elements to copy from the right, may be 0)
-
- Explanation of these two parameters:
- each Usenet article contains the "Path:" header with a list of hosts separated
- by explanation marks. For example:
- Path: ohost1!ohost2!ohost3!ohost4
- If you specify path constant of "nhosta!nhostb" and path copy of 2
- then the path written by cbcb will be
- Path: nhosta!nhostb!ohost3!ohost4
-
- 7. Name of the file appended to the header or 'none'
-
- Examples:
-
- # should be supplied as a courtesy
- X-Cancelled-By: Cancelbot
- # if and only if target file field 3 contains 'N':
- Subject: Cancelling a Usenet article
- # only if posting via IHAVE:
- NNTP-Posting-Host: usenet.cabal.org
-
- 8. Name of the file that will become the body of the cancel or 'none'
-
- If 'none' is specified, the default will be
- "Please cancel this article."
-
- 9. The string to be prepended to the newsgroups. Normally 'none',
- but may be set to something like misc.test (or misc.test,alt.test).
-
- Example of a target file:
-
- # delete all articles that mention C++ (but not c++)
- comp.lang.c.* C++ C cancel. cyberspam 3 can.hdr none none
- # no sex in the sci hierarchy, and add misc.test to the cancel
- sci.* sex C cn. plutonium 2 can1.hdr can.txt misc.test
-
- argv[3] (optional) datestamp, YYMMDD. If not specified, default is 900101. Only
- articles after this date are examined. This parameter is not processed by the
- cancelbot, but passed on to the NNTP server. It should normally be specified
- so as not to look at old Usenet articles.
-
- argv[4] (optional) timestamp, digits HHMMSS, where HH is hours on the 24-hour
- clock, MM is minutes 00-59, and SS is seconds 00-59. If not specified, default
- is 000000. Note that both datestamp and timestamp are in Greenwich mean time.
-
- ---------------8<-------cut me loose!-------------->8--------------------------
- ed-note:
- To compile, you must define an OS type (under gcc, this is accomplished using
- the -Dmacro directive). Under Unix, for example:
- gcc -DCBCB_UNIX -o cancelbot cbcb.c
-
- ---------------8<-------cut me loose!-------------->8--------------------------
-
- cbcb.c:
- /*
-
- Context-blind CancelBot 0.9 04/01/96
-
- Description of operations:
-
- Open socket connections to the hosts listed in the hosts file
-
- loop on targets
- {
- loop on servers
- {
- if (newnews_flag=='Y')
- {
- send NEWNEWS newsgroups datestamp timestamp GMT to this socket
- receive a list of message-ids and save them in a LIFO linked list
- loop on message-ids
- {
- send HEADER message-id to this server's socket
- receieve a header
- if the header contains the watchword
- {
- compose a cancel according to the target file specifications
- loop on servers
- {
- if post_flag is P or I
- send the cancel to this server's socket using posting method
- }
- }
- delete this message-id from the linked list
- }
- }
- }
- }
-
- */
-
- #ifndef CBCB_UNIX
- #ifndef CBCB_VMS
- #ifndef CBCB_NT
- #ifndef CBCB_OS2
- #error One of (CBCB_UNIX, CBCB_VMS, CBCB_NT, CBCB_OS2) must be defined
- #endif
- #endif
- #endif
- #endif
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <signal.h>
- #include <string.h>
- #include <ctype.h>
-
- /* various flavors of Unix */
-
- #ifdef CBCB_UNIX
- /* gcc -DCBCB_UNIX cbcb.c -o cbcb */
- #include <unistd.h>
- #include <sys/types.h>
- #include <sys/socket.h>
- #include <sys/time.h>
- #include <netinet/in.h>
- #include <arpa/inet.h>
- #include <netdb.h>
- /* perror to be called after failed socket calls */
- #define perror_sock perror
- /* how to close a socket */
- #define close_sock close
- #endif
-
- /* Windows NT, /subsystem:console. The executable is supposed to work
- under NT and Windows 95, but not under Win32s. */
-
- #ifdef CBCB_NT
- /* important note: when compiling on NT, say something like
- cl /DCBCB_NT /Ogaityb1 /G5Fs /ML cbcb.c wsock32.lib */
- #include <winsock.h>
- /* regular perror doesn't work with WinSock under NT */
- #define perror_sock(s) fprintf(stderr,"%s : WinSock error %d\n",s,WSAGetLastError())
- /* regular close doesn't work with WinSock under NT */
- #define close_sock closesocket
- /* NT doesn't understand unix-style sleep in seconds */
- #define sleep(n) Sleep(n*1000)
- #endif
-
- /* DEC VAX/VMS */
-
- #ifdef CBCB_VMS
- /* important note: when compiling on VAX/VMS, say something like
- cc/define=CBCB_VMS cbcb/nodebug/optimize=(disjoint,inline)
- link cbcb/nouserlib/notraceback,sys$library:ucx$ipc.olb/lib,-
- sys$library:vaxcrtl.olb/lib
- (to link in shared routines)
- */
- #include <types.h>
- #include <socket.h>
- #include <netdb.h>
- #include <in.h>
- #include <inet.h>
- #include <time.h>
- #include <unixio.h>
- #define perror_sock perror
- #define close_sock close
- #endif
-
- /* IBM OS/2 - link with tcpip.lib */
-
- #ifdef CBCB_OS2
- #define OS2
- /* we will use a BSD-like select, not Oleg's hack */
- #define BSD_SELECT
- #define INCL_DOSPROCESS
- #include <bsedos.h> /* DosSleep */
- #include <sys\types.h>
- #include <sys\socket.h>
- #include <sys\select.h>
- #include <netinet\in.h>
- /*#include <arpa\inet.h>*/
- #include <netdb.h>
- /* perror to be called after failed socket calls */
- #define perror_sock fprintf(stderr,"%s : tcp error %d\n",s,tcperrno())
- /* how to close a socket */
- #define close_sock soclose
- #define sleep(n) DosSleep(n/1000)
- #endif
-
- /*
-
- Future Macintosh notes: Need Apple's MPW (Macintosh Programmer's Workshop).
- Build CBCB as an MPW tool. Set the Macintosh file type to MPST and the
- Macintosh creator to MPS, so we can use stdout and stderr.
-
- Sockets are supposed to be available on the Mac.
-
- */
-
- #ifndef FD_ZERO
- /* macros for select() not defined on VAX or HPUX
- However they are defined to be something completely different
- under NT WinSock, so we must use macros */
- #define fd_set int
- #define FD_ZERO(p) {*(p)=0;}
- #define FD_SET(s,p) {*(p)|=(1<<(s));}
- #define FD_ISSET(s,p) ((*(p)&(1<<(s)))!=0)
- #endif
-
- /* file pointers */
- FILE *sptr, /* hosts file */
- *tptr; /* target file*/
-
- /* there's a reason for making all these variables static. If I weren't lazy,
- I would have put them in their respective functions with 'static' */
-
- #define MAXHOSTS 100
-
- struct {
- int cfd; /* socket handle */
- char newnews_flag;
- char post_flag;
- int timeout;
- } hosts[MAXHOSTS];
- int nhosts;
-
- short int port;
-
- #define ASCII_CR 13
- #define ASCII_LF 10
-
- #define BUFFERSIZE 2048
-
- #define BUFFERBIGSIZE 20480
- char buffer_big[BUFFERBIGSIZE];
-
- struct _msgidq {
- char *msgid;
- struct _msgidq *next;
- };
-
- struct _msgidq *msg_queue,*msg_t;
-
- int parse_state, /* for parsing server responses */
- h_flag,d_flag; /* shortcut for states when parsing headers */
-
- char hostname[BUFFERSIZE];
- char buffer[BUFFERSIZE];
- char extra_header[BUFFERSIZE];
- char extra_body[BUFFERSIZE];
- int file_rec;
- char newsgroups[BUFFERSIZE]; /* target field 1 */
- char watchword[BUFFERSIZE]; /* target field 2 */
- char subject_flag; /* target field 3 */
- char cmsg_id_prefix[BUFFERSIZE]; /* target field 4 */
- char path_const[BUFFERSIZE]; /* target field 5 */
- int path_num; /* target field 6 */
- char hdr_fname[BUFFERSIZE]; /* target field 7 */
- char txt_fname[BUFFERSIZE]; /* target field 8 */
- char extra_ngrp[BUFFERSIZE]; /* target field 9 */
-
- char *datestamp,*timestamp; /* for the NEWNEWS command */
- char *sznone="none";
- char *szcabal=" Usenet@Cabal";
- char *szsubject="Subject:";
- char *szsubjectc="Subject: cmsg";
- char *szendl="\r\n";
- char *szempty="";
-
- int nretry; /* number of retries in various places */
- int nbytes;
- int host1,host2,i,j; /* loop indices */
-
- #define NOLDHEADERS 8
- /* We're interested in 8 original headers :
-
- Path: 0 (requires special handling)
- From: 1
- Sender: 2
- Approved: 3
- Newsgroups: 4
- Date: 5
- Subject: 6
- Organization: 7
-
- */
-
- char *h_ptr[NOLDHEADERS];
- char *t_ptr[3];
-
- /* ANSI function prototypes */
- int cbcb_parse_hosts(void);
- int cbcb_parse_targets(void);
- int cbcb_process_target(void);
- int cbcb_parse_message_ids(void);
- int cbcb_process_article(char *);
- int cbcb_get_headers(void);
- void cbcb_save_headers(void);
- void cbcb_save_header(int);
- int cbcb_flush_sock(int);
- int cbcb_test_sock(int);
- int cbcb_recv_resp(int,char);
- int cbcb_copy_buffer(char *);
-
- int main(int argc,char*argv[])
- {
-
- /* process the arguments */
-
- if (argc<3 || argc>5)
- {
- fprintf(stderr,"Usage: cbcb hostfile targetfile [datestamp] [timestamp]\n");
- return(1);
- }
-
- if (argc<4)
- datestamp="900101";
- else
- datestamp=argv[3];
-
- if (argc<5)
- timestamp="000000";
- else
- timestamp=argv[4];
-
- /* open the hosts file */
-
- if (NULL==(sptr=fopen(argv[1],"r")))
- {
- perror("open()");
- fprintf(stderr,"cbcb cannot open hosts file %s\n",argv[1]);
- return(0);
- }
-
- /* open the target file */
-
- if (NULL==(tptr=fopen(argv[2],"r")))
- {
- perror("open()");
- fprintf(stderr,"cbcb cannot open target file %s\n",argv[2]);
- return(0);
- }
-
- #ifdef SIGPIPE
- signal(SIGPIPE,SIG_IGN); /* ignore broken pipes if this platform knows them */
- #endif
-
- /* establish the connections to the NNTP servers */
-
- if (0==cbcb_parse_hosts())
- {
- fprintf(stderr,"cbcb unable to connect to any NNTP servers\n");
- return(1);
- }
-
- fclose(sptr);
-
- if (!cbcb_parse_targets())
- {
- fprintf(stderr,"cbcb encountered an error processing targets\n");
- return(1);
- }
-
- fclose(tptr);
-
- /* final cleanup */
- for (i=0; i<nhosts; i++)
- close_sock(hosts[i].cfd);
- #ifdef CBCB_NT
- WSACleanup();
- #endif
-
- return(0);
- }
-
-
- int cbcb_parse_hosts(void)
- {
- unsigned long host_ip;
- struct hostent *host_struct;
- struct in_addr *host_node;
- /*
- struct servent *sp;
- */
- struct sockaddr_in serverUaddr;
- #ifdef CBCB_NT
- WSADATA wsaData; /* needed for WSAStartup */
- #endif
-
- #ifdef CBCB_NT
- if (WSAStartup(MAKEWORD(1,1),&wsaData))
- {
- perror_sock("WSAStartup()");
- fprintf(stderr,"couldn't start up WinSock\n");
- return(0);
- }
- fprintf(stderr,"Found WinSock: %s\n",wsaData.szDescription);
- #endif
-
- #ifdef CBCB_OS2
- if (0!=sock_init())
- {
- perror_sock("sock_init()");
- fprintf(stderr,"couldn't start up sockets - is inet.sys running?\n");
- return(0);
- }
- #endif
-
- /*
- if (NULL==(sp=getservbyname("nntp","tcp")))
- {
- fprintf(stderr,"Can't find the NNTP port\n");
- return(0);
- }
- ...
- serverUaddr.sin_port=(sp->s_port);
- */
-
- /* loop on the hosts file */
- nhosts=0;
- file_rec=0;
- while(NULL!=fgets(buffer,sizeof(buffer),sptr))
- {
- file_rec++;
- if (*buffer=='#')
- continue;
- if (nhosts>=MAXHOSTS)
- {
- fprintf(stderr,"Please increase MAXHOSTS\n");
- break;
- }
- if (5!=sscanf(buffer,"%2048s %hd %c %c %d",
- hostname,&port,&hosts[nhosts].newnews_flag,&hosts[nhosts].post_flag,
- &hosts[nhosts].timeout))
- {
- fprintf(stderr,"Error parsing host file line %d \"%s\"\n",file_rec,buffer);
- continue;
- }
- /* verify that the newnews flag is Y or N */
- if (hosts[nhosts].newnews_flag=='n')
- hosts[nhosts].newnews_flag='N';
- else if (hosts[nhosts].newnews_flag=='y')
- hosts[nhosts].newnews_flag='Y';
- else if (hosts[nhosts].newnews_flag!='Y'&&hosts[nhosts].newnews_flag!='N')
- {
- fprintf(stderr,"Newnews flag %c, must be Y or N on line %d\n",
- hosts[nhosts].newnews_flag,file_rec);
- continue;
- }
- /* verify that the posting flag is P, or I, or N */
- if (hosts[nhosts].post_flag=='i')
- hosts[nhosts].post_flag='I';
- else if (hosts[nhosts].post_flag=='p')
- hosts[nhosts].post_flag='P';
- else if (hosts[nhosts].post_flag=='n')
- hosts[nhosts].post_flag='N';
- else if (hosts[nhosts].post_flag!='I'&&hosts[nhosts].post_flag!='P'&&hosts[nhosts].post_flag!='N')
- {
- fprintf(stderr,"Posting flag %c, must be I, or P, or N on line %d\n",
- hosts[nhosts].post_flag,file_rec);
- continue;
- }
- /* translate the hostname into an ip address. If it starts with a digit,
- try to interpret it as a A.B.C.D address */
- if (!isdigit(*hostname)||(0xFFFFFFFF==(host_ip=inet_addr(hostname))))
- {
- if (NULL==(host_struct=gethostbyname(hostname)))
- {
- perror("gethostbyname");
- fprintf(stderr,"Can't resolve host name %s to ip on line %d\n",
- hostname,file_rec);
- continue;
- }
- host_node=(struct in_addr*)host_struct->h_addr;
- fprintf(stderr,"Note: Using NNTP server at %s\n",inet_ntoa(*host_node));
- host_ip=host_node->s_addr;
- }
-
- /* fill in the address to connect to */
- memset(&serverUaddr,0,sizeof(serverUaddr));
- serverUaddr.sin_family=PF_INET;
- serverUaddr.sin_addr.s_addr=/*htonl*/(host_ip); /* already in net order */
- serverUaddr.sin_port=htons(port);
-
- /* try to create a socket */
- if ((hosts[nhosts].cfd=socket(AF_INET,SOCK_STREAM,0))<0)
- {
- perror_sock("socket()");
- continue;
- }
-
- conn1:
- if (0>=connect(hosts[nhosts].cfd,(struct sockaddr*)&serverUaddr,sizeof(serverUaddr)))
- goto conn2; /* we use goto so we can use continue */
- if (nretry>10)
- {
- fprintf(stderr,"give up trying to connect to %s port %hd on line %d\n",
- hostname,port,file_rec);
- close_sock(hosts[nhosts].cfd);
- hosts[nhosts].newnews_flag=hosts[nhosts].post_flag='N';
- continue;
- }
- perror_sock("connect()");
- nretry++;
- sleep(1);
- goto conn1;
- conn2:
- if (!cbcb_recv_resp(nhosts,'2'))
- {
- fprintf(stderr,"NNTP problem after connecting to %s port %hd on line %d\n",
- hostname,port,file_rec);
- close_sock(hosts[nhosts].cfd);
- hosts[nhosts].newnews_flag=hosts[nhosts].post_flag='N';
- continue;
- }
- nhosts++;
- }
-
- return(nhosts);
- }
-
- int cbcb_parse_targets(void)
- {
-
- file_rec=0;
- while(fgets(buffer,sizeof(buffer),tptr)) /* read a target line */
- {
- file_rec++;
- if (*buffer=='#') /* comment */
- continue;
- /* parse the buffer into the 8 fields */
-
- if (9!=sscanf(buffer,"%2048s %2048s %c %2048s %2048s %d %2048s %2048s %2048s",
- newsgroups, watchword, &subject_flag, cmsg_id_prefix, path_const,
- &path_num, hdr_fname, txt_fname, extra_ngrp))
- {
- fprintf(stderr,"Error parsing 8 fields on line %d \"%s\"\n",
- file_rec,buffer);
- continue;
- }
-
- /* verify that the subject flag is C, O, or N */
-
- if (subject_flag=='c')
- subject_flag='C';
- else if (subject_flag=='o')
- subject_flag='O';
- else if (subject_flag=='n')
- subject_flag='N';
- else if (subject_flag!='C'&&subject_flag!='O'&&subject_flag!='N')
- {
- fprintf(stderr,"Subject flag %c, must be C, O, or N on line %d\n",
- subject_flag,file_rec);
- continue;
- }
-
- if (0==strcmp(path_const,sznone)) /* if 'none' is specified */
- {
- if (path_num==0)
- {
- fprintf(stderr,"Can't have path_const none and path_num 0\n");
- continue;
- }
- path_const[0]=0;
- }
- else /* if not none, append bang if needed */
- {
- i=strlen(path_const);
- if (path_const[i-1]!='!')
- {
- path_const[i]='!';
- path_const[i+1]=0;
- }
- }
-
- if (0==strcmp(extra_ngrp,sznone)) /* if 'none' is specified */
- extra_ngrp[0]=0;
- else /* if not none, append comma if needed */
- {
- i=strlen(extra_ngrp);
- if (extra_ngrp[i-1]!=',')
- {
- extra_ngrp[i]=',';
- extra_ngrp[i+1]=0;
- }
- }
-
- /* read the extra header lines */
-
- if (0==strcmp(hdr_fname,sznone)) /* if 'none' is specified */
- *extra_header=0;
- else
- {
- /* try to open the specified file */
- if (NULL==(sptr=fopen(hdr_fname,"r")))
- {
- perror("open()");
- fprintf(stderr,"cbcb cannot open extra-header file %s\n",hdr_fname);
- continue;
- }
- nbytes=fread(buffer,1,BUFFERSIZE,sptr);
- fclose(sptr);
- if (nbytes>=BUFFERSIZE)
- fprintf(stderr,"extra-header file %s is too long\n",hdr_fname);
- if (!cbcb_copy_buffer(extra_header))
- {
- fprintf(stderr,"error in header file\n");
- continue;
- }
- }
-
- /* read the body the same way */
-
- if (0==strcmp(txt_fname,sznone)) /* if 'none' is specified */
- strcpy(extra_body,"Please cancel this article\r\n");
- else
- {
- /* try to open the specified file */
- if (NULL==(sptr=fopen(txt_fname,"r")))
- {
- perror("open()");
- fprintf(stderr,"cbcb cannot open body file %s\n",txt_fname);
- continue;
- }
- nbytes=fread(buffer,1,BUFFERSIZE,sptr);
- fclose(sptr);
- if (nbytes>=BUFFERSIZE)
- fprintf(stderr,"body file %s is too long\n",txt_fname);
- if (!cbcb_copy_buffer(extra_body))
- {
- fprintf(stderr,"error in body file\n");
- continue;
- }
- }
-
- if (!cbcb_process_target()) /* process otherwise. warn and go on if error */
- fprintf(stderr,"cbcb encountered a problem processing target, line %d\n",
- file_rec);
- }
-
- return(1);
- }
-
- int cbcb_process_target(void)
- {
-
- /* loop on hosts */
- for (host1=0; host1<nhosts; host1++)
- if (hosts[host1].newnews_flag=='Y') /* if we want to get message-ids from it */
- {
- cbcb_flush_sock(hosts[host1].cfd);
-
- /* compose the rfc 977 newnews command. Ansi C would let us write
- nbytes=sprintf(..), but gcc has a non-compilant sprintf which return
- buffer instead, so we must use strlen */
- sprintf(buffer,"NEWNEWS %s %s %s GMT\r\n",
- newsgroups,datestamp,timestamp);
- nbytes=strlen(buffer);
- /* send the command to the server */
- if (nbytes!=send(hosts[host1].cfd,buffer,nbytes,0))
- {
- perror_sock("NEWNEWS send()");
- continue;
- }
- /* the server is supposed to return a list of message-ids now */
- if (!cbcb_parse_message_ids())
- fprintf(stderr,"Problem parsing message-ids\n");
- /* no 'continue': even if we return a partial queue, try to process it */
-
- /* loop through headers, newest first */
- while (msg_queue)
- {
- msg_t=msg_queue;
- if (!cbcb_process_article(msg_queue->msgid))
- fprintf(stderr,"Problem processing article <%s>\n",msg_queue->msgid);
- msg_queue=msg_queue->next;
- free(msg_t);
- }
-
- }
-
- return(1);
- }
-
-
- int cbcb_parse_message_ids(void)
- {
-
- msg_queue=NULL;
- parse_state=7;
-
- nretry=0;
- recv_msgids:
- if (!cbcb_test_sock(hosts[host1].cfd)) /* nothing to read */
- {
- if (nretry>hosts[host1].timeout)
- {
- fprintf(stderr,"timeout waiting to recv message-ids\n");
- return(0);
- }
- fprintf(stderr,".");
- nretry++;
- sleep(1);
- goto recv_msgids;
- }
- nbytes=recv(hosts[host1].cfd,buffer,sizeof(buffer),0);
- if (nbytes<0) /* an error shouldn't happen here */
- {
- perror_sock("NEWNEWS recv()");
- return(0);
- }
- #ifdef DEBUG
- fwrite(buffer,1,nbytes,stdout); /* for debugging only!! */
- #endif
- /* now see if what we received makes sense */
- for (i=0; i<nbytes; i++)
- {
- switch(parse_state)
- {
- case 0:
- if (buffer[i]=='.')
- parse_state=4;
- else if (buffer[i]!='<')
- goto recv_bad_msg_id;
- else
- {
- j=0;
- parse_state=1;
- }
- break;
- case 1:
- if (buffer[i]=='>')
- {
- /* add to the queue */
- msg_t=(struct _msgidq*)malloc(sizeof(struct _msgidq));
- if (msg_t==NULL)
- {
- fprintf(stderr,"malloc failed\n");
- return(0);
- }
- msg_t->msgid=(char*)malloc(j+1);
- if (msg_t->msgid==NULL)
- {
- free(msg_t);
- fprintf(stderr,"malloc failed\n");
- return(0);
- }
- memcpy(msg_t->msgid,buffer_big,j);
- *(msg_t->msgid+j)=0;
- msg_t->next=msg_queue;
- msg_queue=msg_t;
-
- parse_state=2;
- }
- else
- {
- if (j>=BUFFERBIGSIZE)
- {
- fprintf(stderr,"Please increase BUFFERBIGSIZE\n");
- return(0);
- }
- buffer_big[j]=buffer[i];
- j++;
- /* parse_state=1; */
- }
- break;
- case 2:
- if (buffer[i]==ASCII_CR)
- parse_state=3;
- else
- goto recv_bad_msg_id;
- break;
- case 3:
- if (buffer[i]==ASCII_LF)
- parse_state=0;
- else
- goto recv_bad_msg_id;
- break;
- case 4:
- if (buffer[i]==ASCII_CR)
- parse_state=5;
- else
- goto recv_bad_msg_id;
- break;
- case 5:
- if (buffer[i]==ASCII_LF)
- parse_state=6;
- else
- goto recv_bad_msg_id;
- break;
- case 6: /* more data after final . */
- goto recv_bad_msg_id;
- case 7: /* initial, really */
- if (buffer[i]=='2')
- parse_state=8;
- else
- goto recv_bad_msg_id;
- break;
- case 8:
- if (buffer[i]==ASCII_CR)
- parse_state=3;
- break;
- }
- }
-
- if (parse_state!=6)
- goto recv_msgids;
- /* normal competion */
- return(1);
-
- recv_bad_msg_id:
- fprintf(stderr,"Unexpected response (expected message-ids) ");
- if (i)
- {
- fprintf(stderr,"after \"");
- fwrite(buffer,1,i,stderr);
- fprintf(stderr,"\" ");
- }
- if (i<nbytes)
- {
- fprintf(stderr,"before \"");
- fwrite(buffer+i,1,nbytes-i,stderr);
- fprintf(stderr,"\"");
- }
- fprintf(stderr,"\n");
- return(0);
- }
-
- int cbcb_process_article(char *msgid)
- {
-
- /* if there is any leftover data in the socket, get it out */
- cbcb_flush_sock(hosts[host1].cfd);
-
- /* compose the rfc 977 head command */
- sprintf(buffer,"HEAD <%s>\r\n",msgid);
-
- /* send the command to the server */
- nbytes=strlen(buffer);
- if (nbytes!=send(hosts[host1].cfd,buffer,nbytes,0))
- {
- perror_sock("HEAD send()");
- return(0);
- }
-
- /* the server is supposed to return the article headers now */
-
- if (!cbcb_get_headers())
- {
- fprintf(stderr,"Problem retrieving headers\n");
- return(0);
- }
-
- if (!strstr(buffer_big,watchword))
- return(1); /* no match, nothing to do */
-
- /* found the watchword: let's cancel */
- cbcb_save_headers();
- sprintf(buffer_big,"\
- Path: %s%s\r\n\
- From:%s\r\n\
- Sender:%s\r\n\
- Approved:%s\r\n\
- Newsgroups: %s%s\r\n\
- Date:%s\r\n\
- %s%s%s\
- Organization:%s\r\n\
- Control:%s\r\n\
- Message-ID: <%s%s>\r\n\
- %s\
- \r\n\
- %s\
- .\r\n",
- path_const,
- h_ptr[0],h_ptr[1],h_ptr[2],h_ptr[3],extra_ngrp,h_ptr[4],h_ptr[5],
- t_ptr[0],h_ptr[6],t_ptr[1],h_ptr[7],t_ptr[2],
- cmsg_id_prefix,msgid,extra_header,extra_body);
-
- fputs(buffer_big,stderr); /* to see what we're posting */
-
- for (host2=0; host2<nhosts; host2++)
- if (hosts[host2].post_flag=='P'||hosts[host2].post_flag=='I')
- {
- cbcb_flush_sock(hosts[host2].cfd);
- if (hosts[host2].post_flag=='P')
- {
- /* send the command to the server */
- if (6!=send(hosts[host2].cfd,"POST\r\n",6,0))
- {
- perror_sock("POST send()");
- continue;
- }
- }
- else /*hosts[host2].post_flag=='I') */
- {
- sprintf(buffer,"IHAVE <%s%s>\r\n",cmsg_id_prefix,msgid);
- nbytes=strlen(buffer);
- /* send the command to the server */
- if (nbytes!=send(hosts[host2].cfd,buffer,nbytes,0))
- {
- perror_sock("IHAVE send()");
- continue;
- }
- }
- if (!cbcb_recv_resp(host2,'3'))
- {
- fprintf(stderr,"NNTP problem while trying to post\n");
- continue;
- }
- nbytes=strlen(buffer_big);
- if (nbytes!=send(hosts[host2].cfd,buffer_big,nbytes,0))
- {
- perror_sock("article send()");
- continue;
- }
- if (!cbcb_recv_resp(host2,'2'))
- {
- fprintf(stderr,"NNTP problem after posting\n");
- continue;
- }
- }
-
- return(1); /* all's well */
- }
-
- int cbcb_get_headers(void)
- {
-
- h_ptr[0]=h_ptr[1]=h_ptr[2]=h_ptr[3]=h_ptr[4]=h_ptr[5]=h_ptr[6]=h_ptr[7]=NULL;
- h_flag=d_flag=parse_state=0;
- nretry=0;
- j=0;
- /* recv */
- recv_headers:
-
- if (!cbcb_test_sock(hosts[host1].cfd)) /* nothing to read */
- {
- if (nretry>hosts[host1].timeout)
- {
- fprintf(stderr,"timeout waiting to recv article headers\n");
- return(0);
- }
- fprintf(stderr,".");
- nretry++;
- sleep(1);
- goto recv_headers;
- }
-
- nbytes=recv(hosts[host1].cfd,buffer,sizeof(buffer),0);
- if (nbytes<0) /* an error shouldn't happen here */
- {
- perror_sock("headers recv()");
- return(0);
- }
- #ifdef DEBUG
- fwrite(buffer,1,nbytes,stdout); /* for debugging only!! */
- #endif
- /* see if what we received makes sense */
- for (i=0; i<nbytes; i++)
- {
- switch(parse_state)
- {
- case 0:
- if (buffer[i]=='2')
- parse_state=1;
- else
- goto recv_bad_header;
- break;
- case 1:
- if (buffer[i]=='2')
- parse_state=2;
- else
- goto recv_bad_header;
- break;
- case 2:
- if (buffer[i]==ASCII_CR)
- parse_state=3;
- /*
- else
- parse_state=2;
- */
- break;
- case 3:
- if (buffer[i]==ASCII_LF)
- {
- if (d_flag)
- parse_state=5;
- else
- {
- h_flag=1;
- parse_state=4;
- goto recv_header_save;
- }
- }
- else
- goto recv_bad_header;
- break;
- case 4:
- if (buffer[i]==ASCII_CR) /* don't save cr's */
- parse_state=3;
- else
- {
- if (h_flag)
- {
- d_flag=0;
- if (buffer[i]=='.')
- d_flag=1;
- else if (buffer[i]=='p'||buffer[i]=='P')
- parse_state=10;
- else if (buffer[i]=='f'||buffer[i]=='F')
- parse_state=20;
- else if (buffer[i]=='s'||buffer[i]=='S')
- parse_state=30;
- else if (buffer[i]=='a'||buffer[i]=='A')
- parse_state=40;
- else if (buffer[i]=='n'||buffer[i]=='N')
- parse_state=50;
- else if (buffer[i]=='d'||buffer[i]=='D')
- parse_state=60;
- else if (buffer[i]=='o'||buffer[i]=='O')
- parse_state=70;
- else if (buffer[i]==' '||buffer[i]=='\t') /* space means continuation */
- j--; /* backup over the lf */
- h_flag=0;
- }
- else
- d_flag=0;
- goto recv_header_save;
- }
- break;
- case 5: /* more data after the final . */
- goto recv_bad_header;
- /* we recognize these headers on the fly */
- case 10:
- if (buffer[i]=='a'||buffer[i]=='A')
- parse_state=11;
- else
- parse_state=4;
- goto recv_header_save;
- case 11:
- if (buffer[i]=='t'||buffer[i]=='t')
- parse_state=12;
- else
- parse_state=4;
- goto recv_header_save;
- case 12:
- if (buffer[i]=='h'||buffer[i]=='H')
- parse_state=13;
- else
- parse_state=4;
- goto recv_header_save;
- case 13:
- if (buffer[i]==':')
- h_ptr[0]=buffer_big+j+1; /* Path: */
- parse_state=4;
- goto recv_header_save;
- case 20:
- if (buffer[i]=='r'||buffer[i]=='R')
- parse_state=21;
- else
- parse_state=4;
- goto recv_header_save;
- case 21:
- if (buffer[i]=='o'||buffer[i]=='O')
- parse_state=22;
- else
- parse_state=4;
- goto recv_header_save;
- case 22:
- if (buffer[i]=='m'||buffer[i]=='M')
- parse_state=23;
- else
- parse_state=4;
- goto recv_header_save;
- case 23:
- if (buffer[i]==':')
- h_ptr[1]=buffer_big+j+1; /* From: */
- parse_state=4;
- goto recv_header_save;
- case 30:
- if (buffer[i]=='e'||buffer[i]=='E')
- parse_state=31;
- else if (buffer[i]=='u'||buffer[i]=='U')
- parse_state=90;
- else
- parse_state=4;
- goto recv_header_save;
- case 31:
- if (buffer[i]=='n'||buffer[i]=='N')
- parse_state=32;
- else
- parse_state=4;
- goto recv_header_save;
- case 32:
- if (buffer[i]=='d'||buffer[i]=='D')
- parse_state=33;
- else
- parse_state=4;
- goto recv_header_save;
- case 33:
- if (buffer[i]=='e'||buffer[i]=='E')
- parse_state=34;
- else
- parse_state=4;
- goto recv_header_save;
- case 34:
- if (buffer[i]=='r'||buffer[i]=='R')
- parse_state=35;
- else
- parse_state=4;
- goto recv_header_save;
- case 35:
- if (buffer[i]==':')
- h_ptr[2]=buffer_big+j+1; /* Sender: */
- parse_state=4;
- goto recv_header_save;
- case 40:
- if (buffer[i]=='p'||buffer[i]=='P')
- parse_state=41;
- else
- parse_state=4;
- goto recv_header_save;
- case 41:
- if (buffer[i]=='p'||buffer[i]=='P')
- parse_state=42;
- else
- parse_state=4;
- goto recv_header_save;
- case 42:
- if (buffer[i]=='r'||buffer[i]=='R')
- parse_state=43;
- else
- parse_state=4;
- goto recv_header_save;
- case 43:
- if (buffer[i]=='o'||buffer[i]=='O')
- parse_state=44;
- else
- parse_state=4;
- goto recv_header_save;
- case 44:
- if (buffer[i]=='v'||buffer[i]=='V')
- parse_state=45;
- else
- parse_state=4;
- goto recv_header_save;
- case 45:
- if (buffer[i]=='e'||buffer[i]=='E')
- parse_state=46;
- else
- parse_state=4;
- goto recv_header_save;
- case 46:
- if (buffer[i]=='d'||buffer[i]=='D')
- parse_state=47;
- else
- parse_state=4;
- goto recv_header_save;
- case 47:
- if (buffer[i]==':')
- h_ptr[3]=buffer_big+j+1; /* Approved: */
- parse_state=4;
- goto recv_header_save;
- case 50:
- if (buffer[i]=='e'||buffer[i]=='E')
- parse_state=51;
- else
- parse_state=4;
- goto recv_header_save;
- case 51:
- if (buffer[i]=='w'||buffer[i]=='W')
- parse_state=52;
- else
- parse_state=4;
- goto recv_header_save;
- case 52:
- if (buffer[i]=='s'||buffer[i]=='S')
- parse_state=53;
- else
- parse_state=4;
- goto recv_header_save;
- case 53:
- if (buffer[i]=='g'||buffer[i]=='G')
- parse_state=54;
- else
- parse_state=4;
- goto recv_header_save;
- case 54:
- if (buffer[i]=='r'||buffer[i]=='R')
- parse_state=55;
- else
- parse_state=4;
- goto recv_header_save;
- case 55:
- if (buffer[i]=='o'||buffer[i]=='O')
- parse_state=56;
- else
- parse_state=4;
- goto recv_header_save;
- case 56:
- if (buffer[i]=='u'||buffer[i]=='U')
- parse_state=57;
- else
- parse_state=4;
- goto recv_header_save;
- case 57:
- if (buffer[i]=='p'||buffer[i]=='P')
- parse_state=58;
- else
- parse_state=4;
- goto recv_header_save;
- case 58:
- if (buffer[i]=='s'||buffer[i]=='S')
- parse_state=59;
- else
- parse_state=4;
- goto recv_header_save;
- case 59:
- if (buffer[i]==':')
- h_ptr[4]=buffer_big+j+2; /* Newsgroups:, skip space */
- parse_state=4;
- goto recv_header_save;
- case 60:
- if (buffer[i]=='a'||buffer[i]=='A')
- parse_state=61;
- else
- parse_state=4;
- goto recv_header_save;
- case 61:
- if (buffer[i]=='t'||buffer[i]=='T')
- parse_state=62;
- else
- parse_state=4;
- goto recv_header_save;
- case 62:
- if (buffer[i]=='e'||buffer[i]=='E')
- parse_state=63;
- else
- parse_state=4;
- goto recv_header_save;
- case 63:
- if (buffer[i]==':')
- h_ptr[5]=buffer_big+j+1; /* Date: */
- parse_state=4;
- goto recv_header_save;
- case 70:
- if (buffer[i]=='r'||buffer[i]=='R')
- parse_state=71;
- else
- parse_state=4;
- goto recv_header_save;
- case 71:
- if (buffer[i]=='g'||buffer[i]=='G')
- parse_state=72;
- else
- parse_state=4;
- goto recv_header_save;
- case 72:
- if (buffer[i]=='a'||buffer[i]=='A')
- parse_state=73;
- else
- parse_state=4;
- goto recv_header_save;
- case 73:
- if (buffer[i]=='n'||buffer[i]=='N')
- parse_state=74;
- else
- parse_state=4;
- goto recv_header_save;
- case 74:
- if (buffer[i]=='i'||buffer[i]=='I')
- parse_state=75;
- else
- parse_state=4;
- goto recv_header_save;
- case 75:
- if (buffer[i]=='z'||buffer[i]=='Z')
- parse_state=76;
- else
- parse_state=4;
- goto recv_header_save;
- case 76:
- if (buffer[i]=='a'||buffer[i]=='A')
- parse_state=77;
- else
- parse_state=4;
- goto recv_header_save;
- case 77:
- if (buffer[i]=='t'||buffer[i]=='T')
- parse_state=78;
- else
- parse_state=4;
- goto recv_header_save;
- case 78:
- if (buffer[i]=='i'||buffer[i]=='I')
- parse_state=79;
- else
- parse_state=4;
- goto recv_header_save;
- case 79:
- if (buffer[i]=='o'||buffer[i]=='O')
- parse_state=80;
- else
- parse_state=4;
- goto recv_header_save;
- case 80:
- if (buffer[i]=='n'||buffer[i]=='N')
- parse_state=81;
- else
- parse_state=4;
- goto recv_header_save;
- case 81:
- if (buffer[i]==':')
- h_ptr[7]=buffer_big+j+1; /* Organization: */
- parse_state=4;
- goto recv_header_save;
- case 90:
- if (buffer[i]=='b'||buffer[i]=='B')
- parse_state=91;
- else
- parse_state=4;
- goto recv_header_save;
- case 91:
- if (buffer[i]=='j'||buffer[i]=='J')
- parse_state=92;
- else
- parse_state=4;
- goto recv_header_save;
- case 92:
- if (buffer[i]=='e'||buffer[i]=='E')
- parse_state=93;
- else
- parse_state=4;
- goto recv_header_save;
- case 93:
- if (buffer[i]=='c'||buffer[i]=='C')
- parse_state=94;
- else
- parse_state=4;
- goto recv_header_save;
- case 94:
- if (buffer[i]=='t'||buffer[i]=='T')
- parse_state=95;
- else
- parse_state=4;
- goto recv_header_save;
- case 95:
- if (buffer[i]==':')
- h_ptr[6]=buffer_big+j+1; /* Subject: */
- parse_state=4;
- goto recv_header_save;
- default: /* how could we ever get here? */
- goto recv_bad_header;
- }
- continue; /* ugly, branch around save */
- recv_header_save:
- if (j>=BUFFERBIGSIZE)
- {
- fprintf(stderr,"Please increase BUFFERBIGSIZE\n");
- return(0);
- }
- buffer_big[j++]=buffer[i];
- } /* next i */
- if (parse_state!=5)
- goto recv_headers;
-
- return(1);
- recv_bad_header:
- fprintf(stderr,"Unexpected response (expected headers) ");
- if (i)
- {
- fprintf(stderr,"after \"");
- fwrite(buffer,1,i,stderr);
- fprintf(stderr,"\" ");
- }
- if (i<nbytes)
- {
- fprintf(stderr,"before \"");
- fwrite(buffer+i,1,nbytes-i,stderr);
- fprintf(stderr,"\"");
- }
- fprintf(stderr,"\n");
- return(0);
- }
-
- void cbcb_save_headers(void)
- {
- /* now copy old headers to buffer for safekeeping */
- /* only if buffer_big matched the pattern */
-
- /* only Path: is special: no initial space */
- if (h_ptr[0]==NULL) /* no path */
- {
- j=0;
- h_ptr[0]=" ";
- }
- else
- {
- i=h_ptr[0]-buffer_big;
- j=path_num;
- while (buffer_big[i]!=ASCII_LF)
- i++;
- i--;
- /* now go back and look for the last n bang-separated components, or the
- beginning of path */
- while (buffer_big[i]>' ' && j)
- {
- i--;
- if (buffer_big[i]=='!')
- j--;
- }
- i++;
- j=0;
- h_ptr[0]=buffer;
- while (buffer_big[i]!=ASCII_LF)
- buffer[j++]=buffer_big[i++];
- buffer[j++]=0;
- }
-
- t_ptr[2]=buffer+j;
- sprintf(t_ptr[2]," cancel <%s>",msg_queue->msgid);
- j+=strlen(t_ptr[2])+1;
-
- if (h_ptr[1]==NULL) /* no from? Highly unlikely */
- h_ptr[1]=szcabal;
- else
- cbcb_save_header(1);
- if (h_ptr[2]==NULL) /* sender */
- h_ptr[2]=h_ptr[1];
- else
- cbcb_save_header(2);
- if (h_ptr[3]==NULL) /* approved */
- h_ptr[3]=h_ptr[2];
- else
- cbcb_save_header(3);
- if (h_ptr[4]==NULL) /* no newsgroups? */
- h_ptr[4]="control";
- else
- cbcb_save_header(4);
- if (h_ptr[5]==NULL) /* no date??? */
- h_ptr[5]=" 1 Jan 1990 00:00 GMT";
- else
- cbcb_save_header(5);
- /* subject is special - must use flag */
- if (subject_flag=='O')
- {
- if (h_ptr[6]==NULL)
- h_ptr[6]=szcabal; /* no subject??? */
- else
- cbcb_save_header(6);
- t_ptr[0]=szsubject;
- t_ptr[1]=szendl;
- }
- else if (subject_flag=='C')
- {
- h_ptr[6]=t_ptr[2]; /* same as the Control: */
- t_ptr[0]=szsubjectc;
- t_ptr[1]=szendl;
- }
- else /* if (subject_flag=='N') */
- {
- t_ptr[0]=t_ptr[1]=h_ptr[6]=szempty;
- }
- if (h_ptr[7]==NULL) /* organization */
- h_ptr[7]=szcabal;
- else
- cbcb_save_header(7);
-
- #ifdef DEBUG
- for (i=0; i<8; i++)
- if (h_ptr[i])
- printf("%d:%s\n",i,h_ptr[i]);
- #endif
-
- }
-
- void cbcb_save_header(int k)
- {
- i=h_ptr[k]-buffer_big;
- h_ptr[k]=buffer+j;
- while (buffer_big[i]!=ASCII_LF)
- buffer[j++]=buffer_big[i++];
- buffer[j++]=0;
- }
-
- int cbcb_flush_sock(int sock)
- {
- /* if there is any leftover data in the socket, get it out */
- while (cbcb_test_sock(sock))
- {
- nbytes=recv(sock,buffer,sizeof(buffer),0);
- if (nbytes<0)
- perror_sock("flush recv()"); /* but don't abort */
- else
- fwrite(buffer,1,nbytes,stderr); /* display it, as it may be informative */
- }
- return(1);
- }
-
- /* use select to see if there's data here.
- There don't seem to be any unixes left which understand poll and not select.*/
- int cbcb_test_sock(int sock)
- {
- fd_set setm;
- static struct timeval zerotime={0,0};
-
- FD_ZERO(&setm);
- FD_SET(sock,&setm);
- if (select(sock+1,&setm,NULL,NULL,&zerotime)<0)
- {
- perror_sock("select()");
- }
- if (FD_ISSET(sock,&setm))
- return(1);
- else
- return(0);
- }
-
- int cbcb_recv_resp(int host,char c)
- {
-
- parse_state=0;
-
- nretry=0;
- recv_resp:
- if (!cbcb_test_sock(hosts[host].cfd)) /* nothing to read */
- {
- if (nretry>hosts[host].timeout)
- {
- fprintf(stderr,"timeout waiting to recv response\n");
- return(0);
- }
- fprintf(stderr,".");
- nretry++;
- sleep(1);
- goto recv_resp;
- }
- nbytes=recv(hosts[host].cfd,buffer,sizeof(buffer),0);
- if (nbytes<0) /* an error shouldn't happen here */
- {
- perror_sock("response recv()");
- return(0);
- }
- /* #ifdef DEBUG */
- fwrite(buffer,1,nbytes,stdout); /* for debugging only!! */
- /* #endif */
- /* now see if what we received makes sense */
- for (i=0; i<nbytes; i++)
- {
- switch(parse_state)
- {
- case 0:
- if (buffer[i]==c)
- parse_state=1;
- else
- goto recv_bad_resp;
- break;
- case 1:
- if (buffer[i]==ASCII_CR)
- parse_state=2;
- break;
- case 2:
- if (buffer[i]==ASCII_LF)
- parse_state=3;
- else
- goto recv_bad_resp;
- break;
- case 3: /* more data after final \n */
- goto recv_bad_resp;
- }
- }
-
- if (parse_state!=3)
- goto recv_resp;
- /* normal competion */
- return(1);
-
- recv_bad_resp:
- fprintf(stderr,"Unexpected response (expected %cxx message) ",c);
- if (i)
- {
- fprintf(stderr,"after \"");
- fwrite(buffer,1,i,stderr);
- fprintf(stderr,"\" ");
- }
- if (i<nbytes)
- {
- fprintf(stderr,"before \"");
- fwrite(buffer+i,1,nbytes-i,stderr);
- fprintf(stderr,"\"");
- }
- fprintf(stderr,"\n");
- return(0);
- }
-
- int cbcb_copy_buffer(char *s)
- {
- i=j=0;
- if (nbytes>0&&buffer[nbytes-1]!='\n')
- buffer[nbytes++]='\n';
- buffer[nbytes]=0;
-
- while (buffer[i])
- {
- if (j>=BUFFERSIZE)
- {
- fprintf(stderr,"File too big\n");
- return(0);
- }
- if (buffer[i]=='\n')
- *(s+(j++))='\r';
- *(s+(j++))=buffer[i++];
- }
- *(s+j)=0;
- return(1);
- }
-
- ---------------8<-------cut me loose!-------------->8--------------------------
-
-
-