home *** CD-ROM | disk | FTP | other *** search
/ The Hacker's Encyclopedia 1998 / hackers_encyclopedia.iso / zines / phrack2 / p49_09.txt < prev    next >
Encoding:
Text File  |  2003-06-11  |  38.5 KB  |  1,705 lines

  1.                             .oO Phrack Magazine Oo.
  2.  
  3.                         Volume Seven, Issue Forty-Nine
  4.             
  5.                      File 09 of 16
  6.  
  7.                     by Dr.Dimitri Vulis (KOTM)
  8.  
  9.                A Content-Blind Cancelbot for Usenet (CBCB)
  10.  
  11. Usenet News is a popular system for transmitting articles. Historically it
  12. used to propagate over UUCP. However today most of the transmission is done
  13. over the Internet TCP/IP connections using the NNTP protocol (RFC 977).
  14.  
  15. Each article consists of a series of headers of the form
  16. Keyword: value
  17. followed by a blank line, followed by the body of the message.
  18. Some required headers are self-explanatory: From:, Date:, Subject:.
  19.  
  20. The Newsgroups: header identifies a series of keywords that can be used
  21. to search for articles in the newsfeed. For example:
  22. Newsgroups: news.admin.policy,comp.lang.c
  23. identifies a Usenet article relevant to both Usenet administrative policy
  24. and to the C computer language.
  25.  
  26. The Message-Id: header uniquely identifies each article. For example:
  27. Message-Id: <12341223@whitehouse.gov>
  28. The message-ids are not supposed to be recycled.
  29.  
  30. The cancelbot program is supposed to search the user-specified newsgroups for
  31. articles whose headers match user-specified regular expressions and to issue
  32. special 'cancel' control articles. It will copy some of the headers from the
  33. original message and add a special header:
  34. Control: cancel <message-id>
  35.  
  36. This program is an NNTP client. Much of the processing is offloaded to an
  37. NNTP server, to which the cancelbot talks using the Internet sockets protocol.
  38.  
  39. This cancelbot does not look at article bodies and is therefore content-blind.
  40.  
  41. Inputs:
  42.  
  43. argv[1] (required) hosts file
  44.  
  45. A line that starts with # is a comment. Otherwise, each line contains the
  46. following 5 fields:
  47.  
  48. 1. hostname (some.domain.com) or ip address (a.b.c.d)
  49. 2. port (normally 119)
  50. 3. Y/N - do we ask this host for NEWNEWS/HEADER?
  51. 4. I/P/N - do we inject cancels to this host with IHAVE, POST, not at all
  52. 5. Timeout - the number of seconds to wait for a response from this server.
  53.  
  54. Example of a hosts file:
  55.  
  56. # ask the local server for new news and post back the cancels
  57. 127.0.0.1 119 Y P 60
  58. # don't get message-ids from remote server, but give it cancels via IHAVE
  59. news.xx.net 119 N I 300
  60.  
  61.  
  62. argv[2] (required) target file
  63.  
  64. A line that starts with # is a comment. Otherwise, each line contains the
  65. following 9 fields:
  66.  
  67. 1. List of newsgroups to be scanned for new messages. This is not interpreted
  68. by the cancelbot, but passed on to the NNTP server. Per RFC 997, multiple
  69. groups can be separated by commas. Asterisk "*" may be used to match multiple
  70. newsgroup names. The exclamation point "!" (as the first character) may be used
  71. to negate a match. Warning: specifying a single * will generate a lot of data.
  72.  
  73. Example: news.groups,comp.*,sci.*,!sci.math.*
  74.  
  75. 2. A watchword (case-sensitive) that needs to be contained in the article
  76. headers for the cancel to be issued.
  77.  
  78. 3. Format of the Subject: header in the cancel article.
  79.  C - Subject cancel <message-id> (same as Control:)
  80.  O - Subject: header copied from the original article
  81.  N - none.
  82. If N is specified, then Subject: MUST be provided in the file appended to
  83. the header, or the cancel won't propagate.
  84.  
  85. 4. cancel message-id prefix
  86.  normally cancel. or cn.
  87.  
  88. Most cancellation articles follow the so-called $alz convention:
  89. Control: cancel <message.id>
  90. Message-id: <cancel.message.id>
  91. However this is not a requirement.
  92.  
  93. 5. path constant (string to put in path). May be 'none'.
  94. 6. path copy # (number of elements to copy from the right, may be 0)
  95.  
  96. Explanation of these two parameters:
  97. each Usenet article contains the "Path:" header with a list of hosts separated
  98. by explanation marks. For example:
  99. Path: ohost1!ohost2!ohost3!ohost4
  100. If you specify path constant of "nhosta!nhostb" and path copy of 2
  101. then the path written by cbcb will be
  102. Path: nhosta!nhostb!ohost3!ohost4
  103.  
  104. 7. Name of the file appended to the header or 'none'
  105.  
  106. Examples:
  107.  
  108. # should be supplied as a courtesy
  109. X-Cancelled-By: Cancelbot
  110. # if and only if target file field 3 contains 'N':
  111. Subject: Cancelling a Usenet article
  112. # only if posting via IHAVE:
  113. NNTP-Posting-Host: usenet.cabal.org
  114.  
  115. 8. Name of the file that will become the body of the cancel or 'none'
  116.  
  117. If 'none' is specified, the default will be
  118. "Please cancel this article."
  119.  
  120. 9. The string to be prepended to the newsgroups. Normally 'none',
  121. but may be set to something like misc.test (or misc.test,alt.test).
  122.  
  123. Example of a target file:
  124.  
  125. # delete all articles that mention C++ (but not c++)
  126. comp.lang.c.* C++ C cancel. cyberspam 3 can.hdr none none
  127. # no sex in the sci hierarchy, and add misc.test to the cancel
  128. sci.* sex C cn. plutonium 2 can1.hdr can.txt misc.test
  129.  
  130. argv[3] (optional) datestamp, YYMMDD. If not specified, default is 900101. Only
  131. articles after this date are examined. This parameter is not processed by the
  132. cancelbot, but passed on to the NNTP server. It should normally be specified
  133. so as not to look at old Usenet articles.
  134.  
  135. argv[4] (optional) timestamp, digits HHMMSS, where HH is hours on the 24-hour
  136. clock, MM is minutes 00-59, and SS is seconds 00-59. If not specified, default
  137. is 000000. Note that both datestamp and timestamp are in Greenwich mean time.
  138.  
  139. ---------------8<-------cut me loose!-------------->8--------------------------
  140. ed-note:
  141. To compile, you must define an OS type (under gcc, this is accomplished using
  142. the -Dmacro directive).  Under Unix, for example:
  143. gcc -DCBCB_UNIX -o cancelbot cbcb.c
  144.  
  145. ---------------8<-------cut me loose!-------------->8--------------------------
  146.  
  147. cbcb.c:
  148. /*
  149.  
  150. Context-blind CancelBot 0.9 04/01/96
  151.  
  152. Description of operations:
  153.  
  154. Open socket connections to the hosts listed in the hosts file
  155.  
  156. loop on targets
  157.  {
  158.  loop on servers
  159.   {
  160.   if (newnews_flag=='Y')
  161.    {
  162.    send NEWNEWS newsgroups datestamp timestamp GMT to this socket
  163.    receive a list of message-ids and save them in a LIFO linked list
  164.    loop on message-ids
  165.      {
  166.      send HEADER message-id to this server's socket
  167.      receieve a header
  168.      if the header contains the watchword
  169.       {
  170.       compose a cancel according to the target file specifications
  171.       loop on servers
  172.        {
  173.        if post_flag is P or I
  174.         send the cancel to this server's socket using posting method
  175.        }
  176.       }
  177.      delete this message-id from the linked list
  178.      }
  179.     }
  180.    }
  181.   }
  182.  
  183. */
  184.  
  185. #ifndef CBCB_UNIX
  186. #ifndef CBCB_VMS
  187. #ifndef CBCB_NT
  188. #ifndef CBCB_OS2
  189. #error One of (CBCB_UNIX, CBCB_VMS, CBCB_NT, CBCB_OS2) must be defined
  190. #endif
  191. #endif
  192. #endif
  193. #endif
  194.  
  195. #include <stdio.h>
  196. #include <stdlib.h>
  197. #include <signal.h>
  198. #include <string.h>
  199. #include <ctype.h>
  200.  
  201. /* various flavors of Unix */
  202.  
  203. #ifdef CBCB_UNIX
  204. /* gcc -DCBCB_UNIX cbcb.c -o cbcb */
  205. #include <unistd.h>
  206. #include <sys/types.h>
  207. #include <sys/socket.h>
  208. #include <sys/time.h>
  209. #include <netinet/in.h>
  210. #include <arpa/inet.h>
  211. #include <netdb.h>
  212. /* perror to be called after failed socket calls */
  213. #define perror_sock perror
  214. /* how to close a socket */
  215. #define close_sock close
  216. #endif
  217.  
  218. /* Windows NT, /subsystem:console. The executable is supposed to work
  219. under NT and Windows 95, but not under Win32s. */
  220.  
  221. #ifdef CBCB_NT
  222. /* important note: when compiling on NT, say something like
  223.  cl /DCBCB_NT /Ogaityb1 /G5Fs /ML cbcb.c wsock32.lib */
  224. #include <winsock.h>
  225. /* regular perror doesn't work with WinSock under NT */
  226. #define perror_sock(s) fprintf(stderr,"%s : WinSock error %d\n",s,WSAGetLastError())
  227. /* regular close doesn't work with WinSock under NT */
  228. #define close_sock closesocket
  229. /* NT doesn't understand unix-style sleep in seconds */
  230. #define sleep(n) Sleep(n*1000)
  231. #endif
  232.  
  233. /* DEC VAX/VMS */
  234.  
  235. #ifdef CBCB_VMS
  236. /* important note: when compiling on VAX/VMS, say something like
  237.  cc/define=CBCB_VMS cbcb/nodebug/optimize=(disjoint,inline)
  238.  link cbcb/nouserlib/notraceback,sys$library:ucx$ipc.olb/lib,-
  239.   sys$library:vaxcrtl.olb/lib
  240.    (to link in shared routines)
  241.   */
  242. #include <types.h>
  243. #include <socket.h>
  244. #include <netdb.h>
  245. #include <in.h>
  246. #include <inet.h>
  247. #include <time.h>
  248. #include <unixio.h>
  249. #define perror_sock perror
  250. #define close_sock close
  251. #endif
  252.  
  253. /* IBM OS/2  - link with tcpip.lib */
  254.  
  255. #ifdef CBCB_OS2
  256. #define OS2
  257. /* we will use a BSD-like select, not Oleg's hack */
  258. #define BSD_SELECT
  259. #define INCL_DOSPROCESS
  260. #include <bsedos.h> /* DosSleep */
  261. #include <sys\types.h>
  262. #include <sys\socket.h>
  263. #include <sys\select.h>
  264. #include <netinet\in.h>
  265. /*#include <arpa\inet.h>*/
  266. #include <netdb.h>
  267. /* perror to be called after failed socket calls */
  268. #define perror_sock fprintf(stderr,"%s : tcp error %d\n",s,tcperrno())
  269. /* how to close a socket */
  270. #define close_sock soclose
  271. #define sleep(n) DosSleep(n/1000)
  272. #endif
  273.  
  274. /*
  275.  
  276. Future Macintosh notes: Need Apple's MPW (Macintosh Programmer's Workshop).
  277. Build CBCB as an MPW tool. Set the Macintosh file type to MPST and the
  278. Macintosh creator to MPS, so we can use stdout and stderr.
  279.  
  280. Sockets are supposed to be available on the Mac.
  281.  
  282. */
  283.  
  284. #ifndef FD_ZERO
  285. /* macros for select() not defined on VAX or HPUX
  286. However they are defined to be something completely different
  287. under NT WinSock, so we must use macros */
  288. #define fd_set int
  289. #define FD_ZERO(p) {*(p)=0;}
  290. #define FD_SET(s,p) {*(p)|=(1<<(s));}
  291. #define FD_ISSET(s,p) ((*(p)&(1<<(s)))!=0)
  292. #endif
  293.  
  294. /* file pointers */
  295. FILE *sptr, /* hosts file */
  296.      *tptr; /* target file*/
  297.  
  298. /* there's a reason for making all these variables static. If I weren't lazy,
  299. I would have put them in their respective functions with 'static' */
  300.  
  301. #define MAXHOSTS 100
  302.  
  303. struct {
  304. int cfd; /* socket handle */
  305. char newnews_flag;
  306. char post_flag;
  307. int timeout;
  308. } hosts[MAXHOSTS];
  309. int nhosts;
  310.  
  311. short int port;
  312.  
  313. #define ASCII_CR 13
  314. #define ASCII_LF 10
  315.  
  316. #define BUFFERSIZE 2048
  317.  
  318. #define BUFFERBIGSIZE 20480
  319. char buffer_big[BUFFERBIGSIZE];
  320.  
  321. struct _msgidq {
  322. char *msgid;
  323. struct _msgidq *next;
  324. };
  325.  
  326. struct _msgidq *msg_queue,*msg_t;
  327.  
  328. int parse_state, /* for parsing server responses */
  329.  h_flag,d_flag; /* shortcut for states when parsing headers */
  330.  
  331. char hostname[BUFFERSIZE];
  332. char buffer[BUFFERSIZE];
  333. char extra_header[BUFFERSIZE];
  334. char extra_body[BUFFERSIZE];
  335. int file_rec;
  336. char newsgroups[BUFFERSIZE];       /* target field 1 */
  337. char watchword[BUFFERSIZE];        /* target field 2 */
  338. char subject_flag;                 /* target field 3 */
  339. char cmsg_id_prefix[BUFFERSIZE];   /* target field 4 */
  340. char path_const[BUFFERSIZE];       /* target field 5 */
  341. int  path_num;                     /* target field 6 */
  342. char hdr_fname[BUFFERSIZE];        /* target field 7 */
  343. char txt_fname[BUFFERSIZE];        /* target field 8 */
  344. char extra_ngrp[BUFFERSIZE];         /* target field 9 */
  345.  
  346. char *datestamp,*timestamp; /* for the NEWNEWS command */
  347. char *sznone="none";
  348. char *szcabal=" Usenet@Cabal";
  349. char *szsubject="Subject:";
  350. char *szsubjectc="Subject: cmsg";
  351. char *szendl="\r\n";
  352. char *szempty="";
  353.  
  354. int nretry; /* number of retries in various places */
  355. int nbytes;
  356. int host1,host2,i,j;   /* loop indices */
  357.  
  358. #define NOLDHEADERS 8
  359. /* We're interested in 8 original headers :
  360.  
  361. Path:               0         (requires special handling)
  362. From:               1
  363. Sender:             2
  364. Approved:           3
  365. Newsgroups:         4
  366. Date:               5
  367. Subject:            6
  368. Organization:       7
  369.  
  370. */
  371.  
  372. char *h_ptr[NOLDHEADERS];
  373. char *t_ptr[3];
  374.  
  375. /* ANSI function prototypes */
  376. int cbcb_parse_hosts(void);
  377. int cbcb_parse_targets(void);
  378. int cbcb_process_target(void);
  379. int cbcb_parse_message_ids(void);
  380. int cbcb_process_article(char *);
  381. int cbcb_get_headers(void);
  382. void cbcb_save_headers(void);
  383. void cbcb_save_header(int);
  384. int cbcb_flush_sock(int);
  385. int cbcb_test_sock(int);
  386. int cbcb_recv_resp(int,char);
  387. int cbcb_copy_buffer(char *);
  388.  
  389. int main(int argc,char*argv[])
  390. {
  391.  
  392. /* process the arguments */
  393.  
  394. if (argc<3 || argc>5)
  395.  {
  396.  fprintf(stderr,"Usage: cbcb hostfile targetfile [datestamp] [timestamp]\n");
  397.  return(1);
  398.  }
  399.  
  400. if (argc<4)
  401.  datestamp="900101";
  402. else
  403.  datestamp=argv[3];
  404.  
  405. if (argc<5)
  406.  timestamp="000000";
  407. else
  408.  timestamp=argv[4];
  409.  
  410. /* open the hosts file */
  411.  
  412. if (NULL==(sptr=fopen(argv[1],"r")))
  413.  {
  414.  perror("open()");
  415.  fprintf(stderr,"cbcb cannot open hosts file %s\n",argv[1]);
  416.  return(0);
  417.  }
  418.  
  419. /* open the target file */
  420.  
  421. if (NULL==(tptr=fopen(argv[2],"r")))
  422.  {
  423.  perror("open()");
  424.  fprintf(stderr,"cbcb cannot open target file %s\n",argv[2]);
  425.  return(0);
  426.  }
  427.  
  428. #ifdef SIGPIPE
  429. signal(SIGPIPE,SIG_IGN); /* ignore broken pipes if this platform knows them */
  430. #endif
  431.  
  432. /* establish the connections to the NNTP servers */
  433.  
  434. if (0==cbcb_parse_hosts())
  435.  {
  436.  fprintf(stderr,"cbcb unable to connect to any NNTP servers\n");
  437.  return(1);
  438.  }
  439.  
  440. fclose(sptr);
  441.  
  442. if (!cbcb_parse_targets())
  443.  {
  444.  fprintf(stderr,"cbcb encountered an error processing targets\n");
  445.  return(1);
  446.  }
  447.  
  448. fclose(tptr);
  449.  
  450. /* final cleanup */
  451. for (i=0; i<nhosts; i++)
  452.  close_sock(hosts[i].cfd);
  453. #ifdef CBCB_NT
  454. WSACleanup();
  455. #endif
  456.  
  457. return(0);
  458. }
  459.  
  460.  
  461. int cbcb_parse_hosts(void)
  462. {
  463. unsigned long host_ip;
  464. struct hostent *host_struct;
  465. struct in_addr *host_node;
  466. /*
  467. struct servent *sp;
  468. */
  469. struct sockaddr_in serverUaddr;
  470. #ifdef CBCB_NT
  471. WSADATA wsaData; /* needed for WSAStartup */
  472. #endif
  473.  
  474. #ifdef CBCB_NT
  475. if (WSAStartup(MAKEWORD(1,1),&wsaData))
  476.  {
  477.  perror_sock("WSAStartup()");
  478.  fprintf(stderr,"couldn't start up WinSock\n");
  479.  return(0);
  480.  }
  481. fprintf(stderr,"Found WinSock: %s\n",wsaData.szDescription);
  482. #endif
  483.  
  484. #ifdef CBCB_OS2
  485. if (0!=sock_init())
  486.  {
  487.  perror_sock("sock_init()");
  488.  fprintf(stderr,"couldn't start up sockets - is inet.sys running?\n");
  489.  return(0);
  490.  }
  491. #endif
  492.  
  493. /*
  494. if (NULL==(sp=getservbyname("nntp","tcp")))
  495.  {
  496.  fprintf(stderr,"Can't find the NNTP port\n");
  497.  return(0);
  498.  }
  499. ...
  500. serverUaddr.sin_port=(sp->s_port);
  501. */
  502.  
  503. /* loop on the hosts file */
  504. nhosts=0;
  505. file_rec=0;
  506. while(NULL!=fgets(buffer,sizeof(buffer),sptr))
  507.  {
  508.  file_rec++;
  509.  if (*buffer=='#')
  510.   continue;
  511.  if (nhosts>=MAXHOSTS)
  512.   {
  513.   fprintf(stderr,"Please increase MAXHOSTS\n");
  514.   break;
  515.   }
  516.  if (5!=sscanf(buffer,"%2048s %hd %c %c %d",
  517.   hostname,&port,&hosts[nhosts].newnews_flag,&hosts[nhosts].post_flag,
  518.   &hosts[nhosts].timeout))
  519.   {
  520.   fprintf(stderr,"Error parsing host file line %d \"%s\"\n",file_rec,buffer);
  521.   continue;
  522.   }
  523.  /* verify that the newnews flag is Y or N */
  524.  if (hosts[nhosts].newnews_flag=='n')
  525.   hosts[nhosts].newnews_flag='N';
  526.  else if (hosts[nhosts].newnews_flag=='y')
  527.   hosts[nhosts].newnews_flag='Y';
  528.  else if (hosts[nhosts].newnews_flag!='Y'&&hosts[nhosts].newnews_flag!='N')
  529.   {
  530.   fprintf(stderr,"Newnews flag %c, must be Y or N on line %d\n",
  531.    hosts[nhosts].newnews_flag,file_rec);
  532.   continue;
  533.   }
  534.  /* verify that the posting flag is P, or I, or N */
  535.  if (hosts[nhosts].post_flag=='i')
  536.   hosts[nhosts].post_flag='I';
  537.  else if (hosts[nhosts].post_flag=='p')
  538.   hosts[nhosts].post_flag='P';
  539.  else if (hosts[nhosts].post_flag=='n')
  540.   hosts[nhosts].post_flag='N';
  541.  else if (hosts[nhosts].post_flag!='I'&&hosts[nhosts].post_flag!='P'&&hosts[nhosts].post_flag!='N')
  542.   {
  543.   fprintf(stderr,"Posting flag %c, must be I, or P, or N on line %d\n",
  544.    hosts[nhosts].post_flag,file_rec);
  545.   continue;
  546.   }
  547.  /* translate the hostname into an ip address. If it starts with a digit,
  548.  try to interpret it as a A.B.C.D address */
  549.  if (!isdigit(*hostname)||(0xFFFFFFFF==(host_ip=inet_addr(hostname))))
  550.   {
  551.   if (NULL==(host_struct=gethostbyname(hostname)))
  552.    {
  553.    perror("gethostbyname");
  554.    fprintf(stderr,"Can't resolve host name %s to ip on line %d\n",
  555.     hostname,file_rec);
  556.    continue;
  557.    }
  558.   host_node=(struct in_addr*)host_struct->h_addr;
  559.   fprintf(stderr,"Note: Using NNTP server at %s\n",inet_ntoa(*host_node));
  560.   host_ip=host_node->s_addr;
  561.   }
  562.  
  563.  /* fill in the address to connect to */
  564.  memset(&serverUaddr,0,sizeof(serverUaddr));
  565.  serverUaddr.sin_family=PF_INET;
  566.  serverUaddr.sin_addr.s_addr=/*htonl*/(host_ip); /* already in net order */
  567.  serverUaddr.sin_port=htons(port);
  568.  
  569.  /* try to create a socket */
  570.  if ((hosts[nhosts].cfd=socket(AF_INET,SOCK_STREAM,0))<0)
  571.   {
  572.   perror_sock("socket()");
  573.   continue;
  574.   }
  575.  
  576. conn1:
  577.  if (0>=connect(hosts[nhosts].cfd,(struct sockaddr*)&serverUaddr,sizeof(serverUaddr)))
  578.   goto conn2; /* we use goto so we can use continue */
  579.  if (nretry>10)
  580.   {
  581.   fprintf(stderr,"give up trying to connect to %s port %hd on line %d\n",
  582.    hostname,port,file_rec);
  583.   close_sock(hosts[nhosts].cfd);
  584.   hosts[nhosts].newnews_flag=hosts[nhosts].post_flag='N';
  585.   continue;
  586.   }
  587.  perror_sock("connect()");
  588.  nretry++;
  589.  sleep(1);
  590.  goto conn1;
  591. conn2:
  592.  if (!cbcb_recv_resp(nhosts,'2'))
  593.   {
  594.   fprintf(stderr,"NNTP problem after connecting to %s port %hd on line %d\n",
  595.    hostname,port,file_rec);
  596.   close_sock(hosts[nhosts].cfd);
  597.   hosts[nhosts].newnews_flag=hosts[nhosts].post_flag='N';
  598.   continue;
  599.   }
  600.  nhosts++;
  601.  }
  602.  
  603. return(nhosts);
  604. }
  605.  
  606. int cbcb_parse_targets(void)
  607. {
  608.  
  609. file_rec=0;
  610. while(fgets(buffer,sizeof(buffer),tptr)) /* read a target line */
  611.  {
  612.  file_rec++;
  613.  if (*buffer=='#') /* comment */
  614.   continue;
  615.  /* parse the buffer into the 8 fields */
  616.  
  617.  if (9!=sscanf(buffer,"%2048s %2048s %c %2048s %2048s %d %2048s %2048s %2048s",
  618.   newsgroups, watchword, &subject_flag, cmsg_id_prefix, path_const,
  619.   &path_num, hdr_fname, txt_fname, extra_ngrp))
  620.   {
  621.   fprintf(stderr,"Error parsing 8 fields on line %d \"%s\"\n",
  622.   file_rec,buffer);
  623.   continue;
  624.   }
  625.  
  626. /* verify that the subject flag is C, O, or N */
  627.  
  628.  if (subject_flag=='c')
  629.   subject_flag='C';
  630.  else if (subject_flag=='o')
  631.   subject_flag='O';
  632.  else if (subject_flag=='n')
  633.   subject_flag='N';
  634.  else if (subject_flag!='C'&&subject_flag!='O'&&subject_flag!='N')
  635.   {
  636.   fprintf(stderr,"Subject flag %c, must be C, O, or N on line %d\n",
  637.    subject_flag,file_rec);
  638.   continue;
  639.   }
  640.  
  641.   if (0==strcmp(path_const,sznone)) /* if 'none' is specified */
  642.    {
  643.    if (path_num==0)
  644.     {
  645.     fprintf(stderr,"Can't have path_const none and path_num 0\n");
  646.     continue;
  647.     }
  648.    path_const[0]=0;
  649.    }
  650.   else /* if not none, append bang if needed */
  651.    {
  652.    i=strlen(path_const);
  653.    if (path_const[i-1]!='!')
  654.     {
  655.     path_const[i]='!';
  656.     path_const[i+1]=0;
  657.     }
  658.    }
  659.  
  660.   if (0==strcmp(extra_ngrp,sznone)) /* if 'none' is specified */
  661.    extra_ngrp[0]=0;
  662.   else /* if not none, append comma if needed */
  663.    {
  664.    i=strlen(extra_ngrp);
  665.    if (extra_ngrp[i-1]!=',')
  666.     {
  667.     extra_ngrp[i]=',';
  668.     extra_ngrp[i+1]=0;
  669.     }
  670.    }
  671.  
  672.  /* read the extra header lines */
  673.  
  674.   if (0==strcmp(hdr_fname,sznone)) /* if 'none' is specified */
  675.    *extra_header=0;
  676.   else
  677.    {
  678.    /* try to open the specified file */
  679.    if (NULL==(sptr=fopen(hdr_fname,"r")))
  680.     {
  681.     perror("open()");
  682.     fprintf(stderr,"cbcb cannot open extra-header file %s\n",hdr_fname);
  683.     continue;
  684.     }
  685.    nbytes=fread(buffer,1,BUFFERSIZE,sptr);
  686.    fclose(sptr);
  687.    if (nbytes>=BUFFERSIZE)
  688.     fprintf(stderr,"extra-header file %s is too long\n",hdr_fname);
  689.    if (!cbcb_copy_buffer(extra_header))
  690.     {
  691.     fprintf(stderr,"error in header file\n");
  692.     continue;
  693.     }
  694.    }
  695.  
  696.  /* read the body the same way */
  697.  
  698.   if (0==strcmp(txt_fname,sznone)) /* if 'none' is specified */
  699.    strcpy(extra_body,"Please cancel this article\r\n");
  700.   else
  701.    {
  702.    /* try to open the specified file */
  703.    if (NULL==(sptr=fopen(txt_fname,"r")))
  704.     {
  705.     perror("open()");
  706.     fprintf(stderr,"cbcb cannot open body file %s\n",txt_fname);
  707.     continue;
  708.     }
  709.    nbytes=fread(buffer,1,BUFFERSIZE,sptr);
  710.    fclose(sptr);
  711.    if (nbytes>=BUFFERSIZE)
  712.     fprintf(stderr,"body file %s is too long\n",txt_fname);
  713.    if (!cbcb_copy_buffer(extra_body))
  714.     {
  715.     fprintf(stderr,"error in body file\n");
  716.     continue;
  717.     }
  718.   }
  719.  
  720.  if (!cbcb_process_target()) /* process otherwise. warn and go on if error */
  721.   fprintf(stderr,"cbcb encountered a problem processing target, line %d\n",
  722.    file_rec);
  723.  }
  724.  
  725. return(1);
  726. }
  727.  
  728. int cbcb_process_target(void)
  729. {
  730.  
  731. /* loop on hosts */
  732. for (host1=0; host1<nhosts; host1++)
  733.  if (hosts[host1].newnews_flag=='Y') /* if we want to get message-ids from it */
  734.   {
  735.   cbcb_flush_sock(hosts[host1].cfd);
  736.  
  737.   /* compose the rfc 977 newnews command.  Ansi C would let us write
  738.   nbytes=sprintf(..), but gcc has a non-compilant sprintf which return
  739.   buffer instead, so we must use strlen */
  740.   sprintf(buffer,"NEWNEWS %s %s %s GMT\r\n",
  741.    newsgroups,datestamp,timestamp);
  742.   nbytes=strlen(buffer);
  743.   /* send the command to the server */
  744.   if (nbytes!=send(hosts[host1].cfd,buffer,nbytes,0))
  745.    {
  746.    perror_sock("NEWNEWS send()");
  747.    continue;
  748.    }
  749.   /* the server is supposed to return a list of message-ids now */
  750.   if (!cbcb_parse_message_ids())
  751.    fprintf(stderr,"Problem parsing message-ids\n");
  752.    /* no 'continue': even if we return a partial queue, try to process it */
  753.  
  754.   /* loop through headers, newest first */
  755.   while (msg_queue)
  756.    {
  757.    msg_t=msg_queue;
  758.    if (!cbcb_process_article(msg_queue->msgid))
  759.     fprintf(stderr,"Problem processing article <%s>\n",msg_queue->msgid);
  760.    msg_queue=msg_queue->next;
  761.    free(msg_t);
  762.    }
  763.  
  764.   }
  765.  
  766. return(1);
  767. }
  768.  
  769.  
  770. int cbcb_parse_message_ids(void)
  771. {
  772.  
  773. msg_queue=NULL;
  774. parse_state=7;
  775.  
  776. nretry=0;
  777. recv_msgids:
  778.  if (!cbcb_test_sock(hosts[host1].cfd)) /* nothing to read */
  779.  {
  780.  if (nretry>hosts[host1].timeout)
  781.   {
  782.   fprintf(stderr,"timeout waiting to recv message-ids\n");
  783.   return(0);
  784.   }
  785.  fprintf(stderr,".");
  786.  nretry++;
  787.  sleep(1);
  788.  goto recv_msgids;
  789.  }
  790. nbytes=recv(hosts[host1].cfd,buffer,sizeof(buffer),0);
  791. if (nbytes<0) /* an error shouldn't happen here */
  792.  {
  793.  perror_sock("NEWNEWS recv()");
  794.  return(0);
  795.  }
  796. #ifdef DEBUG
  797.  fwrite(buffer,1,nbytes,stdout); /* for debugging only!! */
  798. #endif
  799. /* now see if what we received makes sense */
  800. for (i=0; i<nbytes; i++)
  801.  {
  802.  switch(parse_state)
  803.   {
  804.  case 0:
  805.   if (buffer[i]=='.')
  806.    parse_state=4;
  807.   else if (buffer[i]!='<')
  808.    goto recv_bad_msg_id;
  809.   else
  810.    {
  811.    j=0;
  812.    parse_state=1;
  813.    }
  814.   break;
  815.  case 1:
  816.   if (buffer[i]=='>')
  817.    {
  818. /* add to the queue */
  819.    msg_t=(struct _msgidq*)malloc(sizeof(struct _msgidq));
  820.    if (msg_t==NULL)
  821.     {
  822.     fprintf(stderr,"malloc failed\n");
  823.     return(0);
  824.     }
  825.    msg_t->msgid=(char*)malloc(j+1);
  826.    if (msg_t->msgid==NULL)
  827.     {
  828.     free(msg_t);
  829.     fprintf(stderr,"malloc failed\n");
  830.     return(0);
  831.     }
  832.    memcpy(msg_t->msgid,buffer_big,j);
  833.    *(msg_t->msgid+j)=0;
  834.    msg_t->next=msg_queue;
  835.    msg_queue=msg_t;
  836.  
  837.    parse_state=2;
  838.    }
  839.   else
  840.    {
  841.    if (j>=BUFFERBIGSIZE)
  842.     {
  843.     fprintf(stderr,"Please increase BUFFERBIGSIZE\n");
  844.     return(0);
  845.     }
  846.    buffer_big[j]=buffer[i];
  847.    j++;
  848.    /* parse_state=1; */
  849.    }
  850.   break;
  851.  case 2:
  852.   if (buffer[i]==ASCII_CR)
  853.    parse_state=3;
  854.   else
  855.    goto recv_bad_msg_id;
  856.   break;
  857.  case 3:
  858.   if (buffer[i]==ASCII_LF)
  859.    parse_state=0;
  860.   else
  861.    goto recv_bad_msg_id;
  862.   break;
  863.  case 4:
  864.   if (buffer[i]==ASCII_CR)
  865.    parse_state=5;
  866.   else
  867.    goto recv_bad_msg_id;
  868.   break;
  869.  case 5:
  870.   if (buffer[i]==ASCII_LF)
  871.    parse_state=6;
  872.   else
  873.    goto recv_bad_msg_id;
  874.   break;
  875.  case 6:  /* more data after final . */
  876.    goto recv_bad_msg_id;
  877.  case 7: /* initial, really */
  878.   if (buffer[i]=='2')
  879.    parse_state=8;
  880.   else
  881.    goto recv_bad_msg_id;
  882.   break;
  883.  case 8:
  884.   if (buffer[i]==ASCII_CR)
  885.     parse_state=3;
  886.   break;
  887.   }
  888.  }
  889.  
  890. if (parse_state!=6)
  891.  goto recv_msgids;
  892. /* normal competion */
  893. return(1);
  894.  
  895. recv_bad_msg_id:
  896.  fprintf(stderr,"Unexpected response (expected message-ids) ");
  897.  if (i)
  898.   {
  899.   fprintf(stderr,"after \"");
  900.   fwrite(buffer,1,i,stderr);
  901.   fprintf(stderr,"\" ");
  902.   }
  903.  if (i<nbytes)
  904.   {
  905.   fprintf(stderr,"before \"");
  906.   fwrite(buffer+i,1,nbytes-i,stderr);
  907.   fprintf(stderr,"\"");
  908.   }
  909.  fprintf(stderr,"\n");
  910. return(0);
  911. }
  912.  
  913. int cbcb_process_article(char *msgid)
  914. {
  915.  
  916. /* if there is any leftover data in the socket, get it out */
  917.  cbcb_flush_sock(hosts[host1].cfd);
  918.  
  919. /* compose the rfc 977 head command */
  920. sprintf(buffer,"HEAD <%s>\r\n",msgid);
  921.  
  922. /* send the command to the server */
  923. nbytes=strlen(buffer);
  924. if (nbytes!=send(hosts[host1].cfd,buffer,nbytes,0))
  925.  {
  926.  perror_sock("HEAD send()");
  927.  return(0);
  928.  }
  929.  
  930. /* the server is supposed to return the article headers now */
  931.  
  932. if (!cbcb_get_headers())
  933.  {
  934.  fprintf(stderr,"Problem retrieving headers\n");
  935.  return(0);
  936.  }
  937.  
  938. if (!strstr(buffer_big,watchword))
  939.  return(1); /* no match, nothing to do */
  940.  
  941. /* found the watchword: let's cancel */
  942. cbcb_save_headers();
  943. sprintf(buffer_big,"\
  944. Path: %s%s\r\n\
  945. From:%s\r\n\
  946. Sender:%s\r\n\
  947. Approved:%s\r\n\
  948. Newsgroups: %s%s\r\n\
  949. Date:%s\r\n\
  950. %s%s%s\
  951. Organization:%s\r\n\
  952. Control:%s\r\n\
  953. Message-ID: <%s%s>\r\n\
  954. %s\
  955. \r\n\
  956. %s\
  957. .\r\n",
  958. path_const,
  959. h_ptr[0],h_ptr[1],h_ptr[2],h_ptr[3],extra_ngrp,h_ptr[4],h_ptr[5],
  960. t_ptr[0],h_ptr[6],t_ptr[1],h_ptr[7],t_ptr[2],
  961. cmsg_id_prefix,msgid,extra_header,extra_body);
  962.  
  963. fputs(buffer_big,stderr); /* to see what we're posting */
  964.  
  965. for (host2=0; host2<nhosts; host2++)
  966.  if (hosts[host2].post_flag=='P'||hosts[host2].post_flag=='I')
  967.   {
  968.   cbcb_flush_sock(hosts[host2].cfd);
  969.   if (hosts[host2].post_flag=='P')
  970.    {
  971.    /* send the command to the server */
  972.    if (6!=send(hosts[host2].cfd,"POST\r\n",6,0))
  973.     {
  974.     perror_sock("POST send()");
  975.     continue;
  976.     }
  977.    }
  978.   else /*hosts[host2].post_flag=='I') */
  979.    {
  980.    sprintf(buffer,"IHAVE <%s%s>\r\n",cmsg_id_prefix,msgid);
  981.    nbytes=strlen(buffer);
  982.    /* send the command to the server */
  983.    if (nbytes!=send(hosts[host2].cfd,buffer,nbytes,0))
  984.     {
  985.     perror_sock("IHAVE send()");
  986.     continue;
  987.     }
  988.    }
  989.   if (!cbcb_recv_resp(host2,'3'))
  990.    {
  991.    fprintf(stderr,"NNTP problem while trying to post\n");
  992.    continue;
  993.    }
  994.   nbytes=strlen(buffer_big);
  995.   if (nbytes!=send(hosts[host2].cfd,buffer_big,nbytes,0))
  996.    {
  997.    perror_sock("article send()");
  998.    continue;
  999.    }
  1000.   if (!cbcb_recv_resp(host2,'2'))
  1001.    {
  1002.    fprintf(stderr,"NNTP problem after posting\n");
  1003.    continue;
  1004.    }
  1005.   }
  1006.  
  1007. return(1); /* all's well */
  1008. }
  1009.  
  1010. int cbcb_get_headers(void)
  1011. {
  1012.  
  1013. 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;
  1014. h_flag=d_flag=parse_state=0;
  1015. nretry=0;
  1016. j=0;
  1017. /* recv */
  1018. recv_headers:
  1019.  
  1020.  if (!cbcb_test_sock(hosts[host1].cfd)) /* nothing to read */
  1021.  {
  1022.  if (nretry>hosts[host1].timeout)
  1023.   {
  1024.   fprintf(stderr,"timeout waiting to recv article headers\n");
  1025.   return(0);
  1026.   }
  1027.  fprintf(stderr,".");
  1028.  nretry++;
  1029.  sleep(1);
  1030.  goto recv_headers;
  1031.  }
  1032.  
  1033. nbytes=recv(hosts[host1].cfd,buffer,sizeof(buffer),0);
  1034. if (nbytes<0) /* an error shouldn't happen here */
  1035.  {
  1036.  perror_sock("headers recv()");
  1037.  return(0);
  1038.  }
  1039. #ifdef DEBUG
  1040.  fwrite(buffer,1,nbytes,stdout); /* for debugging only!! */
  1041. #endif
  1042. /* see if what we received makes sense */
  1043. for (i=0; i<nbytes; i++)
  1044.  {
  1045.  switch(parse_state)
  1046.   {
  1047.  case 0:
  1048.   if (buffer[i]=='2')
  1049.    parse_state=1;
  1050.   else
  1051.    goto recv_bad_header;
  1052.   break;
  1053.  case 1:
  1054.   if (buffer[i]=='2')
  1055.    parse_state=2;
  1056.   else
  1057.    goto recv_bad_header;
  1058.   break;
  1059.  case 2:
  1060.   if (buffer[i]==ASCII_CR)
  1061.    parse_state=3;
  1062.  /*
  1063.   else
  1064.    parse_state=2;
  1065.  */
  1066.   break;
  1067.  case 3:
  1068.   if (buffer[i]==ASCII_LF)
  1069.    {
  1070.    if (d_flag)
  1071.     parse_state=5;
  1072.    else
  1073.     {
  1074.     h_flag=1;
  1075.     parse_state=4;
  1076.     goto recv_header_save;
  1077.     }
  1078.    }
  1079.   else
  1080.    goto recv_bad_header;
  1081.   break;
  1082.  case 4:
  1083.   if (buffer[i]==ASCII_CR) /* don't save cr's */
  1084.    parse_state=3;
  1085.   else
  1086.    {
  1087.    if (h_flag)
  1088.     {
  1089.     d_flag=0;
  1090.     if (buffer[i]=='.')
  1091.      d_flag=1;
  1092.     else if (buffer[i]=='p'||buffer[i]=='P')
  1093.      parse_state=10;
  1094.     else if (buffer[i]=='f'||buffer[i]=='F')
  1095.      parse_state=20;
  1096.     else if (buffer[i]=='s'||buffer[i]=='S')
  1097.      parse_state=30;
  1098.     else if (buffer[i]=='a'||buffer[i]=='A')
  1099.      parse_state=40;
  1100.     else if (buffer[i]=='n'||buffer[i]=='N')
  1101.      parse_state=50;
  1102.     else if (buffer[i]=='d'||buffer[i]=='D')
  1103.      parse_state=60;
  1104.     else if (buffer[i]=='o'||buffer[i]=='O')
  1105.      parse_state=70;
  1106.     else if (buffer[i]==' '||buffer[i]=='\t') /* space means continuation */
  1107.      j--; /* backup over the lf */
  1108.     h_flag=0;
  1109.     }
  1110.    else
  1111.     d_flag=0;
  1112.    goto recv_header_save;
  1113.    }
  1114.   break;
  1115.  case 5:  /* more data after the final . */
  1116.    goto recv_bad_header;
  1117. /* we recognize these headers on the fly */
  1118.  case 10:
  1119.     if (buffer[i]=='a'||buffer[i]=='A')
  1120.      parse_state=11;
  1121.     else
  1122.      parse_state=4;
  1123.    goto recv_header_save;
  1124.  case 11:
  1125.     if (buffer[i]=='t'||buffer[i]=='t')
  1126.      parse_state=12;
  1127.     else
  1128.      parse_state=4;
  1129.    goto recv_header_save;
  1130.  case 12:
  1131.     if (buffer[i]=='h'||buffer[i]=='H')
  1132.      parse_state=13;
  1133.     else
  1134.      parse_state=4;
  1135.    goto recv_header_save;
  1136.  case 13:
  1137.     if (buffer[i]==':')
  1138.      h_ptr[0]=buffer_big+j+1; /* Path: */
  1139.     parse_state=4;
  1140.    goto recv_header_save;
  1141.  case 20:
  1142.     if (buffer[i]=='r'||buffer[i]=='R')
  1143.      parse_state=21;
  1144.     else
  1145.      parse_state=4;
  1146.    goto recv_header_save;
  1147.  case 21:
  1148.     if (buffer[i]=='o'||buffer[i]=='O')
  1149.      parse_state=22;
  1150.     else
  1151.      parse_state=4;
  1152.    goto recv_header_save;
  1153.  case 22:
  1154.     if (buffer[i]=='m'||buffer[i]=='M')
  1155.      parse_state=23;
  1156.     else
  1157.      parse_state=4;
  1158.    goto recv_header_save;
  1159.  case 23:
  1160.     if (buffer[i]==':')
  1161.      h_ptr[1]=buffer_big+j+1; /* From: */
  1162.     parse_state=4;
  1163.    goto recv_header_save;
  1164.  case 30:
  1165.     if (buffer[i]=='e'||buffer[i]=='E')
  1166.      parse_state=31;
  1167.     else if (buffer[i]=='u'||buffer[i]=='U')
  1168.      parse_state=90;
  1169.     else
  1170.      parse_state=4;
  1171.    goto recv_header_save;
  1172.  case 31:
  1173.     if (buffer[i]=='n'||buffer[i]=='N')
  1174.      parse_state=32;
  1175.     else
  1176.      parse_state=4;
  1177.    goto recv_header_save;
  1178.  case 32:
  1179.     if (buffer[i]=='d'||buffer[i]=='D')
  1180.      parse_state=33;
  1181.     else
  1182.      parse_state=4;
  1183.    goto recv_header_save;
  1184.  case 33:
  1185.     if (buffer[i]=='e'||buffer[i]=='E')
  1186.      parse_state=34;
  1187.     else
  1188.      parse_state=4;
  1189.    goto recv_header_save;
  1190.  case 34:
  1191.     if (buffer[i]=='r'||buffer[i]=='R')
  1192.      parse_state=35;
  1193.     else
  1194.      parse_state=4;
  1195.    goto recv_header_save;
  1196.  case 35:
  1197.     if (buffer[i]==':')
  1198.      h_ptr[2]=buffer_big+j+1; /* Sender: */
  1199.     parse_state=4;
  1200.    goto recv_header_save;
  1201.  case 40:
  1202.     if (buffer[i]=='p'||buffer[i]=='P')
  1203.      parse_state=41;
  1204.     else
  1205.      parse_state=4;
  1206.    goto recv_header_save;
  1207.  case 41:
  1208.     if (buffer[i]=='p'||buffer[i]=='P')
  1209.      parse_state=42;
  1210.     else
  1211.      parse_state=4;
  1212.    goto recv_header_save;
  1213.  case 42:
  1214.     if (buffer[i]=='r'||buffer[i]=='R')
  1215.      parse_state=43;
  1216.     else
  1217.      parse_state=4;
  1218.    goto recv_header_save;
  1219.  case 43:
  1220.     if (buffer[i]=='o'||buffer[i]=='O')
  1221.      parse_state=44;
  1222.     else
  1223.      parse_state=4;
  1224.    goto recv_header_save;
  1225.  case 44:
  1226.     if (buffer[i]=='v'||buffer[i]=='V')
  1227.      parse_state=45;
  1228.     else
  1229.      parse_state=4;
  1230.    goto recv_header_save;
  1231.  case 45:
  1232.     if (buffer[i]=='e'||buffer[i]=='E')
  1233.      parse_state=46;
  1234.     else
  1235.      parse_state=4;
  1236.    goto recv_header_save;
  1237.  case 46:
  1238.     if (buffer[i]=='d'||buffer[i]=='D')
  1239.      parse_state=47;
  1240.     else
  1241.      parse_state=4;
  1242.    goto recv_header_save;
  1243.  case 47:
  1244.     if (buffer[i]==':')
  1245.      h_ptr[3]=buffer_big+j+1; /* Approved: */
  1246.     parse_state=4;
  1247.    goto recv_header_save;
  1248.  case 50:
  1249.     if (buffer[i]=='e'||buffer[i]=='E')
  1250.      parse_state=51;
  1251.     else
  1252.      parse_state=4;
  1253.    goto recv_header_save;
  1254.  case 51:
  1255.     if (buffer[i]=='w'||buffer[i]=='W')
  1256.      parse_state=52;
  1257.     else
  1258.      parse_state=4;
  1259.    goto recv_header_save;
  1260.  case 52:
  1261.     if (buffer[i]=='s'||buffer[i]=='S')
  1262.      parse_state=53;
  1263.     else
  1264.      parse_state=4;
  1265.    goto recv_header_save;
  1266.  case 53:
  1267.     if (buffer[i]=='g'||buffer[i]=='G')
  1268.      parse_state=54;
  1269.     else
  1270.      parse_state=4;
  1271.    goto recv_header_save;
  1272.  case 54:
  1273.     if (buffer[i]=='r'||buffer[i]=='R')
  1274.      parse_state=55;
  1275.     else
  1276.      parse_state=4;
  1277.    goto recv_header_save;
  1278.  case 55:
  1279.     if (buffer[i]=='o'||buffer[i]=='O')
  1280.      parse_state=56;
  1281.     else
  1282.      parse_state=4;
  1283.    goto recv_header_save;
  1284.  case 56:
  1285.     if (buffer[i]=='u'||buffer[i]=='U')
  1286.      parse_state=57;
  1287.     else
  1288.      parse_state=4;
  1289.    goto recv_header_save;
  1290.  case 57:
  1291.     if (buffer[i]=='p'||buffer[i]=='P')
  1292.      parse_state=58;
  1293.     else
  1294.      parse_state=4;
  1295.    goto recv_header_save;
  1296.  case 58:
  1297.     if (buffer[i]=='s'||buffer[i]=='S')
  1298.      parse_state=59;
  1299.     else
  1300.      parse_state=4;
  1301.    goto recv_header_save;
  1302.  case 59:
  1303.     if (buffer[i]==':')
  1304.      h_ptr[4]=buffer_big+j+2; /* Newsgroups:, skip space */
  1305.     parse_state=4;
  1306.    goto recv_header_save;
  1307.  case 60:
  1308.     if (buffer[i]=='a'||buffer[i]=='A')
  1309.      parse_state=61;
  1310.     else
  1311.      parse_state=4;
  1312.    goto recv_header_save;
  1313.  case 61:
  1314.     if (buffer[i]=='t'||buffer[i]=='T')
  1315.      parse_state=62;
  1316.     else
  1317.      parse_state=4;
  1318.    goto recv_header_save;
  1319.  case 62:
  1320.     if (buffer[i]=='e'||buffer[i]=='E')
  1321.      parse_state=63;
  1322.     else
  1323.      parse_state=4;
  1324.    goto recv_header_save;
  1325.  case 63:
  1326.     if (buffer[i]==':')
  1327.      h_ptr[5]=buffer_big+j+1; /* Date: */
  1328.     parse_state=4;
  1329.    goto recv_header_save;
  1330.  case 70:
  1331.     if (buffer[i]=='r'||buffer[i]=='R')
  1332.      parse_state=71;
  1333.     else
  1334.      parse_state=4;
  1335.    goto recv_header_save;
  1336.  case 71:
  1337.     if (buffer[i]=='g'||buffer[i]=='G')
  1338.      parse_state=72;
  1339.     else
  1340.      parse_state=4;
  1341.    goto recv_header_save;
  1342.  case 72:
  1343.     if (buffer[i]=='a'||buffer[i]=='A')
  1344.      parse_state=73;
  1345.     else
  1346.      parse_state=4;
  1347.    goto recv_header_save;
  1348.  case 73:
  1349.     if (buffer[i]=='n'||buffer[i]=='N')
  1350.      parse_state=74;
  1351.     else
  1352.      parse_state=4;
  1353.    goto recv_header_save;
  1354.  case 74:
  1355.     if (buffer[i]=='i'||buffer[i]=='I')
  1356.      parse_state=75;
  1357.     else
  1358.      parse_state=4;
  1359.    goto recv_header_save;
  1360.  case 75:
  1361.     if (buffer[i]=='z'||buffer[i]=='Z')
  1362.      parse_state=76;
  1363.     else
  1364.      parse_state=4;
  1365.    goto recv_header_save;
  1366.  case 76:
  1367.     if (buffer[i]=='a'||buffer[i]=='A')
  1368.      parse_state=77;
  1369.     else
  1370.      parse_state=4;
  1371.    goto recv_header_save;
  1372.  case 77:
  1373.     if (buffer[i]=='t'||buffer[i]=='T')
  1374.      parse_state=78;
  1375.     else
  1376.      parse_state=4;
  1377.    goto recv_header_save;
  1378.  case 78:
  1379.     if (buffer[i]=='i'||buffer[i]=='I')
  1380.      parse_state=79;
  1381.     else
  1382.      parse_state=4;
  1383.    goto recv_header_save;
  1384.  case 79:
  1385.     if (buffer[i]=='o'||buffer[i]=='O')
  1386.      parse_state=80;
  1387.     else
  1388.      parse_state=4;
  1389.    goto recv_header_save;
  1390.  case 80:
  1391.     if (buffer[i]=='n'||buffer[i]=='N')
  1392.      parse_state=81;
  1393.     else
  1394.      parse_state=4;
  1395.    goto recv_header_save;
  1396.  case 81:
  1397.     if (buffer[i]==':')
  1398.      h_ptr[7]=buffer_big+j+1; /* Organization: */
  1399.     parse_state=4;
  1400.    goto recv_header_save;
  1401.  case 90:
  1402.     if (buffer[i]=='b'||buffer[i]=='B')
  1403.      parse_state=91;
  1404.     else
  1405.      parse_state=4;
  1406.    goto recv_header_save;
  1407.  case 91:
  1408.     if (buffer[i]=='j'||buffer[i]=='J')
  1409.      parse_state=92;
  1410.     else
  1411.      parse_state=4;
  1412.    goto recv_header_save;
  1413.  case 92:
  1414.     if (buffer[i]=='e'||buffer[i]=='E')
  1415.      parse_state=93;
  1416.     else
  1417.      parse_state=4;
  1418.    goto recv_header_save;
  1419.  case 93:
  1420.     if (buffer[i]=='c'||buffer[i]=='C')
  1421.      parse_state=94;
  1422.     else
  1423.      parse_state=4;
  1424.    goto recv_header_save;
  1425.  case 94:
  1426.     if (buffer[i]=='t'||buffer[i]=='T')
  1427.      parse_state=95;
  1428.     else
  1429.      parse_state=4;
  1430.    goto recv_header_save;
  1431.  case 95:
  1432.     if (buffer[i]==':')
  1433.      h_ptr[6]=buffer_big+j+1; /* Subject: */
  1434.    parse_state=4;
  1435.    goto recv_header_save;
  1436.  default: /* how could we ever get here? */
  1437.   goto recv_bad_header;
  1438.   }
  1439.  continue; /* ugly, branch around save */
  1440. recv_header_save:
  1441.  if (j>=BUFFERBIGSIZE)
  1442.   {
  1443.   fprintf(stderr,"Please increase BUFFERBIGSIZE\n");
  1444.   return(0);
  1445.   }
  1446.  buffer_big[j++]=buffer[i];
  1447.  } /* next i */
  1448. if (parse_state!=5)
  1449.  goto recv_headers;
  1450.  
  1451. return(1);
  1452. recv_bad_header:
  1453.  fprintf(stderr,"Unexpected response (expected headers) ");
  1454.  if (i)
  1455.   {
  1456.   fprintf(stderr,"after \"");
  1457.   fwrite(buffer,1,i,stderr);
  1458.   fprintf(stderr,"\" ");
  1459.   }
  1460.  if (i<nbytes)
  1461.   {
  1462.   fprintf(stderr,"before \"");
  1463.   fwrite(buffer+i,1,nbytes-i,stderr);
  1464.   fprintf(stderr,"\"");
  1465.   }
  1466.  fprintf(stderr,"\n");
  1467. return(0);
  1468. }
  1469.  
  1470. void cbcb_save_headers(void)
  1471. {
  1472. /* now copy old headers to buffer for safekeeping */
  1473. /* only if buffer_big matched the pattern */
  1474.  
  1475. /* only Path: is special: no initial space */
  1476. if (h_ptr[0]==NULL) /* no path */
  1477.  {
  1478.  j=0;
  1479.  h_ptr[0]=" ";
  1480.  }
  1481. else
  1482.  {
  1483.  i=h_ptr[0]-buffer_big;
  1484.  j=path_num;
  1485.  while (buffer_big[i]!=ASCII_LF)
  1486.   i++;
  1487.  i--;
  1488.  /* now go back and look for the last n bang-separated components, or the
  1489.  beginning of path */
  1490.  while (buffer_big[i]>' ' && j)
  1491.   {
  1492.   i--;
  1493.   if (buffer_big[i]=='!')
  1494.    j--;
  1495.   }
  1496.  i++;
  1497.  j=0;
  1498.  h_ptr[0]=buffer;
  1499.  while (buffer_big[i]!=ASCII_LF)
  1500.   buffer[j++]=buffer_big[i++];
  1501.  buffer[j++]=0;
  1502.  }
  1503.  
  1504. t_ptr[2]=buffer+j;
  1505. sprintf(t_ptr[2]," cancel <%s>",msg_queue->msgid);
  1506. j+=strlen(t_ptr[2])+1;
  1507.  
  1508. if (h_ptr[1]==NULL) /* no from? Highly unlikely */
  1509.  h_ptr[1]=szcabal;
  1510. else
  1511.  cbcb_save_header(1);
  1512. if (h_ptr[2]==NULL) /* sender */
  1513.  h_ptr[2]=h_ptr[1];
  1514. else
  1515.  cbcb_save_header(2);
  1516. if (h_ptr[3]==NULL) /* approved */
  1517.  h_ptr[3]=h_ptr[2];
  1518. else
  1519.  cbcb_save_header(3);
  1520. if (h_ptr[4]==NULL) /* no newsgroups? */
  1521.  h_ptr[4]="control";
  1522. else
  1523.  cbcb_save_header(4);
  1524. if (h_ptr[5]==NULL) /* no date??? */
  1525.  h_ptr[5]=" 1 Jan 1990 00:00 GMT";
  1526. else
  1527.  cbcb_save_header(5);
  1528. /* subject is special - must use flag */
  1529. if (subject_flag=='O')
  1530.  {
  1531.  if (h_ptr[6]==NULL)
  1532.   h_ptr[6]=szcabal; /* no subject??? */
  1533.  else
  1534.   cbcb_save_header(6);
  1535.  t_ptr[0]=szsubject;
  1536.  t_ptr[1]=szendl;
  1537.  }
  1538. else if (subject_flag=='C')
  1539.  {
  1540.  h_ptr[6]=t_ptr[2]; /* same as the Control: */
  1541.  t_ptr[0]=szsubjectc;
  1542.  t_ptr[1]=szendl;
  1543.  }
  1544. else /* if (subject_flag=='N') */
  1545.  {
  1546. t_ptr[0]=t_ptr[1]=h_ptr[6]=szempty;
  1547.  }
  1548. if (h_ptr[7]==NULL) /* organization */
  1549.  h_ptr[7]=szcabal;
  1550. else
  1551.  cbcb_save_header(7);
  1552.  
  1553. #ifdef DEBUG
  1554. for (i=0; i<8; i++)
  1555.  if (h_ptr[i])
  1556.   printf("%d:%s\n",i,h_ptr[i]);
  1557. #endif
  1558.  
  1559. }
  1560.  
  1561. void cbcb_save_header(int k)
  1562. {
  1563. i=h_ptr[k]-buffer_big;
  1564. h_ptr[k]=buffer+j;
  1565. while (buffer_big[i]!=ASCII_LF)
  1566.  buffer[j++]=buffer_big[i++];
  1567. buffer[j++]=0;
  1568. }
  1569.  
  1570. int cbcb_flush_sock(int sock)
  1571. {
  1572.   /* if there is any leftover data in the socket, get it out */
  1573.   while (cbcb_test_sock(sock))
  1574.    {
  1575.    nbytes=recv(sock,buffer,sizeof(buffer),0);
  1576.    if (nbytes<0)
  1577.     perror_sock("flush recv()"); /* but don't abort */
  1578.    else
  1579.     fwrite(buffer,1,nbytes,stderr); /* display it, as it may be informative */
  1580.    }
  1581. return(1);
  1582. }
  1583.  
  1584. /* use select to see if there's data here.
  1585. There don't seem to be any unixes left which understand poll and not select.*/
  1586. int cbcb_test_sock(int sock)
  1587. {
  1588. fd_set setm;
  1589. static struct timeval zerotime={0,0};
  1590.  
  1591. FD_ZERO(&setm);
  1592. FD_SET(sock,&setm);
  1593. if (select(sock+1,&setm,NULL,NULL,&zerotime)<0)
  1594.  {
  1595.  perror_sock("select()");
  1596.  }
  1597. if (FD_ISSET(sock,&setm))
  1598.  return(1);
  1599. else
  1600.  return(0);
  1601. }
  1602.  
  1603. int cbcb_recv_resp(int host,char c)
  1604. {
  1605.  
  1606. parse_state=0;
  1607.  
  1608. nretry=0;
  1609. recv_resp:
  1610.  if (!cbcb_test_sock(hosts[host].cfd)) /* nothing to read */
  1611.  {
  1612.  if (nretry>hosts[host].timeout)
  1613.   {
  1614.   fprintf(stderr,"timeout waiting to recv response\n");
  1615.   return(0);
  1616.   }
  1617.  fprintf(stderr,".");
  1618.  nretry++;
  1619.  sleep(1);
  1620.  goto recv_resp;
  1621.  }
  1622. nbytes=recv(hosts[host].cfd,buffer,sizeof(buffer),0);
  1623. if (nbytes<0) /* an error shouldn't happen here */
  1624.  {
  1625.  perror_sock("response recv()");
  1626.  return(0);
  1627.  }
  1628. /* #ifdef DEBUG */
  1629.  fwrite(buffer,1,nbytes,stdout); /* for debugging only!! */
  1630. /* #endif */
  1631. /* now see if what we received makes sense */
  1632. for (i=0; i<nbytes; i++)
  1633.  {
  1634.  switch(parse_state)
  1635.   {
  1636.  case 0:
  1637.   if (buffer[i]==c)
  1638.    parse_state=1;
  1639.   else
  1640.    goto recv_bad_resp;
  1641.   break;
  1642.  case 1:
  1643.   if (buffer[i]==ASCII_CR)
  1644.     parse_state=2;
  1645.   break;
  1646.  case 2:
  1647.   if (buffer[i]==ASCII_LF)
  1648.    parse_state=3;
  1649.   else
  1650.    goto recv_bad_resp;
  1651.   break;
  1652.  case 3:  /* more data after final \n */
  1653.    goto recv_bad_resp;
  1654.   }
  1655.  }
  1656.  
  1657. if (parse_state!=3)
  1658.  goto recv_resp;
  1659. /* normal competion */
  1660. return(1);
  1661.  
  1662. recv_bad_resp:
  1663.  fprintf(stderr,"Unexpected response (expected %cxx message) ",c);
  1664.  if (i)
  1665.   {
  1666.   fprintf(stderr,"after \"");
  1667.   fwrite(buffer,1,i,stderr);
  1668.   fprintf(stderr,"\" ");
  1669.   }
  1670.  if (i<nbytes)
  1671.   {
  1672.   fprintf(stderr,"before \"");
  1673.   fwrite(buffer+i,1,nbytes-i,stderr);
  1674.   fprintf(stderr,"\"");
  1675.   }
  1676.  fprintf(stderr,"\n");
  1677. return(0);
  1678. }
  1679.  
  1680. int cbcb_copy_buffer(char *s)
  1681. {
  1682. i=j=0;
  1683.    if (nbytes>0&&buffer[nbytes-1]!='\n')
  1684.     buffer[nbytes++]='\n';
  1685.   buffer[nbytes]=0;
  1686.  
  1687. while (buffer[i])
  1688.  {
  1689.  if (j>=BUFFERSIZE)
  1690.   {
  1691.   fprintf(stderr,"File too big\n");
  1692.   return(0);
  1693.   }
  1694.  if (buffer[i]=='\n')
  1695.   *(s+(j++))='\r';
  1696.  *(s+(j++))=buffer[i++];
  1697.  }
  1698. *(s+j)=0;
  1699. return(1);
  1700. }
  1701.  
  1702. ---------------8<-------cut me loose!-------------->8--------------------------
  1703.  
  1704.  
  1705.