home *** CD-ROM | disk | FTP | other *** search
/ ftp.wwiv.com / ftp.wwiv.com.zip / ftp.wwiv.com / pub / PPPBCKP / SRC15B24.ZIP / NEWS.C < prev    next >
C/C++ Source or Header  |  1997-04-07  |  45KB  |  1,641 lines

  1. #include <stdio.h>
  2. #include <stdarg.h>
  3. #include <ctype.h>
  4. #include <process.h>
  5. #include <string.h>
  6. #include <time.h>
  7. #include <stdlib.h>
  8. #include <conio.h>
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <io.h>
  12. #include <dos.h>
  13. #include <share.h>
  14. #include <dir.h>
  15. #include <alloc.h>
  16. #include <sys\stat.h>
  17. #include <math.h>
  18. #include "tcp.h"
  19. #include "pop.h"
  20. #include "net.h"
  21. #include "vardec.h"
  22. #include "version.h"
  23.  
  24. extern unsigned _stklen = 16384;
  25.  
  26. #define SHARE_LEVEL 10
  27. #define WAIT_TIME 10
  28. #define TRIES 100
  29.  
  30. #define MT_DESQVIEW 0x01
  31. #define MT_WINDOWS  0x02
  32. #define MT_OS2      0x04
  33. #define MT_NB       0x40
  34.  
  35. #define NGROUPS 100
  36. #define BIGSTR 4096
  37. #define STRING 512
  38. #define STR 129
  39. #define WAIT_TIME 10
  40. #define TRIES 100
  41. #define NUL '\0'
  42. #define LAST(s) s[strlen(s)-1]
  43. #define NNTP_PORT 119
  44. #define free_Mail_Socket(SOCK) if (SOCK!=NULL) {     \
  45.   farfree(SOCK->sock); farfree(SOCK); SOCK=NULL; }
  46.  
  47. tcp_Socket nntpsock;
  48. configrec syscfg;
  49. subboardrec *subboards;
  50.  
  51. static int NNTP_stat;
  52.  
  53. unsigned short reply;
  54. unsigned long reparticle;
  55.  
  56. char serverhost[81], newsrc[81], fromline[121], smtppath[81];
  57. char maindir[181], tmpdir[201], net_data[181];
  58. char *version = "Freeware PPP News Retrieval " VERSION;
  59.  
  60. char cur_gname[STRING], tpktname[121];
  61. char msgto[STRING], msgarea[STRING];
  62. unsigned long cur_numa, cur_first, cur_last;
  63.  
  64. unsigned long cur_article;
  65. char cur_articleid[STRING];
  66. char cur_path[STRING], cur_from[STRING], cur_subject[STRING], cur_replyto[STRING];
  67. char cur_newsgroups[STRING], cur_message_ID[STRING], cur_organization[STRING], cur_references[STRING], cur_lines[STR], cur_date[STRING];
  68. unsigned short sy;
  69. int instance, multitasker = 0, SOCK_DELAY;
  70.  
  71. typedef struct {
  72.   char groupname[60];
  73.   unsigned long lastread;
  74.   unsigned short subtype;
  75. } GROUPFILEREC;
  76.  
  77. GROUPFILEREC *grouprec;
  78. int ngroups;
  79.  
  80. int bogus = 0;
  81.  
  82. #define SOCK_READ_ERR(SOCK) sock_err:                                   \
  83.   switch (NNTP_stat) {                                                  \
  84.     case 1 :                                                            \
  85.       write_groups(1);                                                  \
  86.       log_it("\n ! Connection closed : %s", sockerr(NNTP_sock->sock));  \
  87.       if (SOCK != NULL)                                                 \
  88.         free_Mail_Socket(SOCK);                                         \
  89.       fcloseall();                                                      \
  90.       cursor('R');                                                      \
  91.       exit(EXIT_FAILURE);                                               \
  92.     case -1:                                                            \
  93.       write_groups(1);                                                  \
  94.       log_it("\n ! Session error: %s", sockerr(NNTP_sock->sock));       \
  95.       if (SOCK != NULL)                                                 \
  96.         free_Mail_Socket(SOCK);                                         \
  97.       fcloseall();                                                      \
  98.       cursor('R');                                                      \
  99.       exit(EXIT_FAILURE);                                               \
  100.   }                                                                     \
  101.  
  102. char *texth[] = {"th", "st", "nd", "rd"};
  103.  
  104. char *ordinal_text(int number)
  105. {
  106.   if (((number %= 100) > 9 && number < 20) || (number %= 10) > 3)
  107.     number = 0;
  108.   return texth[number];
  109. }
  110.  
  111. static unsigned cursize;
  112.  
  113. void cursor(int tmp)
  114. {
  115.   union REGS inregs, outregs;
  116.  
  117.   switch (toupper(tmp)) {
  118.     case 'S':                               /* Save */
  119.       inregs.h.ah = 3;
  120.       inregs.h.bh = 0;
  121.       int86(0x10, &inregs, &outregs);
  122.       cursize = outregs.x.cx;
  123.       break;
  124.     case 'R':                               /* Restore */
  125.       inregs.h.ah = 1;
  126.       inregs.x.cx = cursize;
  127.       int86(0x10, &inregs, &outregs);
  128.       break;
  129.     case 'H':                               /* Hide */
  130.       inregs.h.ah = 1;
  131.       inregs.h.ch = 0x20;
  132.       int86(0x10, &inregs, &outregs);
  133.       break;
  134.     case 'N':                               /* Normal */
  135.       inregs.h.ah = 1;
  136.       inregs.h.ch = 6;
  137.       inregs.h.cl = 7;
  138.       int86(0x10, &inregs, &outregs);
  139.       break;
  140.   }
  141. }
  142.  
  143. void dv_pause(void)
  144. {
  145.   __emit__(0xb8, 0x1a, 0x10, 0xcd, 0x15);
  146.   __emit__(0xb8, 0x00, 0x10, 0xcd, 0x15);
  147.   __emit__(0xb8, 0x25, 0x10, 0xcd, 0x15);
  148. }
  149.  
  150. void win_pause(void)
  151. {
  152.   __emit__(0x55, 0xb8, 0x80, 0x16, 0xcd, 0x2f, 0x5d);
  153. }
  154.  
  155. int get_dos_version(void)
  156. {
  157.   _AX = 0x3000;
  158.   geninterrupt(0x21);
  159.   if (_AX % 256 >= 10) {
  160.     multitasker |= MT_OS2;
  161.   }
  162.   return (_AX);
  163. }
  164.  
  165. int get_dv_version(void)
  166. {
  167.   int v;
  168.  
  169.   if (multitasker & MT_OS2)
  170.     return 0;
  171.   _AX = 0x2b01;
  172.   _CX = 0x4445;
  173.   _DX = 0x5351;
  174.   geninterrupt(0x21);
  175.   if (_AL == 0xff) {
  176.     return 0;
  177.   } else {
  178.     v = _BX;
  179.     multitasker |= MT_DESQVIEW;
  180.     return v;
  181.   }
  182. }
  183.  
  184. int get_win_version(void)
  185. {
  186.   int v = 0;
  187.  
  188.   __emit__(0x55, 0x06, 0x53);
  189.   _AX = 0x352f;
  190.   geninterrupt(0x21);
  191.   _AX = _ES;
  192.   if (_AX | _BX) {
  193.     _AX = 0x1600;
  194.     geninterrupt(0x2f);
  195.     v = _AX;
  196.     if (v % 256 <= 1)
  197.       v = 0;
  198.   }
  199.   __emit__(0x5b, 0x07, 0x5d);
  200.   if (v != 0)
  201.     multitasker |= MT_WINDOWS;
  202.   return (v);
  203. }
  204.  
  205. int get_nb_version(void)
  206. {
  207.   _AX = 0;
  208.   geninterrupt(0x2A);
  209.   return (_AH);
  210. }
  211.  
  212. void detect_multitask(void)
  213. {
  214.   get_dos_version();
  215.   get_win_version();
  216.   get_dv_version();
  217. }
  218.  
  219. void giveup_timeslice(void)
  220. {
  221.   if (multitasker) {
  222.     switch (multitasker) {
  223.  case 1: 
  224.  case 3: 
  225.         dv_pause();
  226.         break;
  227.       case 2:
  228.       case 4:
  229.       case 5:
  230.       case 6:
  231.       case 7:
  232.         win_pause();
  233.         break;
  234.       default:
  235.         break;
  236.     }
  237.   }
  238. }
  239.  
  240. void backline(void)
  241. {
  242.   int i;
  243.  
  244.   fprintf(stderr, " ");
  245.   for (i = wherex(); i > 0; i--)
  246.     fprintf(stderr, "\b \b");
  247. }
  248.  
  249. void cd_to(char *s)
  250. {
  251.   char *s1;
  252.   int i, db;
  253.  
  254.   s1 = s;
  255.   i = strlen(s1) - 1;
  256.   db = (s1[i] == '\\');
  257.   if (i == 0)
  258.     db = 0;
  259.   if ((i == 2) && (s1[1] == ':'))
  260.     db = 0;
  261.   if (db)
  262.     s1[i] = 0;
  263.   chdir(s1);
  264.   if (s[1] == ':')
  265.     setdisk(s[0] - 'A');
  266. }
  267.  
  268. void get_dir(char *s, int be)
  269. {
  270.   strcpy(s, "X:\\");
  271.   s[0] = 'A' + getdisk();
  272.   getcurdir(0, s + 3);
  273.   if (be) {
  274.     if (s[strlen(s) - 1] != '\\')
  275.       strcat(s, "\\");
  276.   }
  277. }
  278.  
  279. int sh_write(int handle, void *buffer, unsigned long len)
  280. {
  281.   if (handle == -1) {
  282.     return (-1);
  283.   }
  284.   return (write(handle, buffer, (unsigned) len));
  285. }
  286.  
  287. int sh_open(char *path, int file_access, unsigned fmode)
  288. {
  289.   int handle, count, share;
  290.   char drive[MAXDRIVE], dir[MAXDIR], file[MAXFILE], ext[MAXEXT];
  291.  
  292.   if ((file_access & O_RDWR) || (file_access & O_WRONLY) || (fmode & S_IWRITE)) {
  293.     share = SH_DENYRW;
  294.   } else {
  295.     share = SH_DENYWR;
  296.   }
  297.   handle = open(path, file_access | share, fmode);
  298.   if (handle < 0) {
  299.     count = 1;
  300.     fnsplit(path, drive, dir, file, ext);
  301.     if (access(path, 0) != -1) {
  302.       delay(WAIT_TIME);
  303.       handle = open(path, file_access | share, fmode);
  304.       while (((handle < 0) && (errno == EACCES)) && (count < TRIES)) {
  305.         if (count % 2)
  306.           delay(WAIT_TIME);
  307.         else
  308.           giveup_timeslice();
  309.         count++;
  310.         handle = open(path, file_access | share, fmode);
  311.       }
  312.     }
  313.   }
  314.   return (handle);
  315. }
  316.  
  317. int sh_open1(char *path, int access)
  318. {
  319.   unsigned fmode;
  320.  
  321.   fmode = 0;
  322.   if ((access & O_RDWR) || (access & O_WRONLY))
  323.     fmode |= S_IWRITE;
  324.   if ((access & O_RDWR) || (access & O_RDONLY))
  325.     fmode |= S_IREAD;
  326.   return (sh_open(path, access, fmode));
  327. }
  328.  
  329. int sh_close(int f)
  330. {
  331.   if (f != -1)
  332.     close(f);
  333.   return (-1);
  334. }
  335.  
  336. int sh_read(int handle, void *buf, unsigned len)
  337. {
  338.   if (handle == -1) {
  339.     return (-1);
  340.   }
  341.   return (read(handle, buf, len));
  342. }
  343.  
  344. long sh_lseek(int handle, long offset, int fromwhere)
  345. {
  346.   if (handle == -1) {
  347.     return (-1L);
  348.   }
  349.   return (lseek(handle, offset, fromwhere));
  350. }
  351.  
  352. FILE *fsh_open(char *path, char *fmode)
  353. {
  354.   FILE *f;
  355.   int count, share, md, fd;
  356.   char drive[MAXDRIVE], dir[MAXDIR], file[MAXFILE], ext[MAXEXT];
  357.  
  358.   share = SH_DENYWR;
  359.   md = 0;
  360.   if (((char *) _fstrchr(fmode, 'w')) != NULL) {
  361.     share = SH_DENYRD;
  362.     md = O_RDWR | O_CREAT | O_TRUNC;
  363.   } else
  364.     if (((char *) _fstrchr(fmode, 'a')) != NULL) {
  365.     share = SH_DENYRD;
  366.     md = O_RDWR | O_CREAT;
  367.   } else {
  368.     md = O_RDONLY;
  369.   }
  370.   if (((char *) _fstrchr(fmode, 'b')) != NULL) {
  371.     md |= O_BINARY;
  372.   }
  373.   if (((char *) _fstrchr(fmode, '+')) != NULL) {
  374.     md &= ~O_RDONLY;
  375.     md |= O_RDWR;
  376.     share = SH_DENYRD;
  377.   }
  378.   fd = open(path, md | share, S_IREAD | S_IWRITE);
  379.   if (fd < 0) {
  380.     count = 1;
  381.     fnsplit(path, drive, dir, file, ext);
  382.     if ((access(path, 0)) != -1) {
  383.       delay(WAIT_TIME);
  384.       fd = open(path, md | share, S_IREAD | S_IWRITE);
  385.       while (((fd < 0) && (errno == EACCES)) && (count < TRIES)) {
  386.         delay(WAIT_TIME);
  387.         count++;
  388.         fd = open(path, md | share, S_IREAD | S_IWRITE);
  389.       }
  390.     }
  391.   }
  392.   if (fd > 0) {
  393.     if (((char *) _fstrchr(fmode, 'a')) != NULL)
  394.       sh_lseek(fd, 0L, SEEK_END);
  395.     f = fdopen(fd, fmode);
  396.     if (!f) {
  397.       close(fd);
  398.     }
  399.   } else
  400.     f = 0;
  401.   return (f);
  402. }
  403.  
  404. size_t fsh_write(void *ptr, size_t size, size_t n, FILE *stream)
  405. {
  406.  
  407.   if (stream == NULL) {
  408.     return(0);
  409.   }
  410.   return(fwrite(ptr, size, n, stream));
  411. }
  412.  
  413. int log_it(char *fmt,...)
  414. {
  415.   va_list v;
  416.   char fn[201];
  417.   FILE *fp;
  418.  
  419.   sprintf(fn, "%s\\NEWS.LOG", net_data);
  420.   if ((fp = fsh_open(fn, "at")) == NULL)
  421.     return 1;
  422.   va_start(v, fmt);
  423.   vfprintf(fp, fmt, v);
  424.   vfprintf(stderr, fmt, v);
  425.   va_end(v);
  426.   fclose(fp);
  427.   return 0;
  428. }
  429.  
  430.  
  431. long count_lines(char *s)
  432. {
  433.   FILE *fp;
  434.   char fn[201];
  435.   long int nl = 0;
  436.   const int NEWLINE = '\n';
  437.   int c;
  438.  
  439.   strcpy(fn, s);
  440.   fp = fsh_open(fn, "rt");
  441.   if (fp == NULL) {
  442.     printf("\n ■ Cannot open %s", fn);
  443.     return 0;
  444.   }
  445.   while ((c = getc(fp)) != EOF) {
  446.     if (c == NEWLINE)
  447.       ++nl;
  448.   }
  449.   fclose(fp);
  450.   return nl;
  451. }
  452.  
  453. static unsigned char *trimstr1(unsigned char *s)
  454. {
  455.   int i;
  456.   static char *whitespace = " \r\n\t";
  457.  
  458.   i = strlen(s);
  459.   while ((i > 0) && (_fstrchr(whitespace, s[i - 1])))
  460.     --i;
  461.   while ((i > 0) && (_fstrchr(whitespace, *s))) {
  462.     memmove(s, s + 1, --i);
  463.   }
  464.   s[i] = 0;
  465.   return (s);
  466. }
  467.  
  468. void usleep(void)
  469. {
  470.   tcp_tick(NULL);                           /* occasionally process something */
  471. }
  472.  
  473. int exist(char *s)
  474. {
  475.   int i;
  476.   struct ffblk ff;
  477.  
  478.   i = findfirst(s, &ff, 0);
  479.   if (i)
  480.     return (0);
  481.   else
  482.     return (1);
  483. }
  484.  
  485. void rename_pend(char *dir, char *file)
  486. {
  487.   char s[181], s1[181];
  488.   int i, ok;
  489.  
  490.   sprintf(s, "%s\\%s", dir, file);
  491.   ok = 0;
  492.   for (i = 0; i < 1000 && !ok; i++) {
  493.     sprintf(s1, "%s\\P0-%u.NET", dir, i);
  494.     if (!exist(s1)) {
  495.       rename(s, s1);
  496.       ok = 1;
  497.     }
  498.   }
  499. }
  500.  
  501. void check_packets(void)
  502. {
  503.   char s[181];
  504.   int f1;
  505.   struct ffblk ff;
  506.  
  507.   sprintf(s, "%s\\P0-*.%3.3d", net_data, instance);
  508.   f1 = findfirst(s, &ff, 0);
  509.   while (f1 == 0) {
  510.     rename_pend(net_data, ff.ff_name);
  511.     f1 = findnext(&ff);
  512.   }
  513. }
  514.  
  515.  
  516. void err_exit(int exitlevel, char *fmt,...)
  517. {
  518.   va_list v;
  519.  
  520.   va_start(v, fmt);
  521.   vfprintf(stderr, fmt, v);
  522.   va_end(v);
  523.   check_packets();
  524.   cursor('R');
  525.   exit(exitlevel);
  526. }
  527.  
  528. void write_groups(int display)
  529. {
  530.   int i;
  531.   FILE *groupfp;
  532.  
  533.   groupfp = fsh_open(newsrc, "wt");
  534.   if (!groupfp) {
  535.     fprintf(stderr, "\n ■ Unable to open %s!", newsrc);
  536.     return;
  537.   } else {
  538.     if (display)
  539.       fprintf(stderr, "\n ■ Updating pointers in %s...", newsrc);
  540.   }
  541.   for (i = 0; i < ngroups; i++) {
  542.     if ((grouprec[i].groupname[0]) && (stricmp(grouprec[i].groupname, "newsrc") != 0)) {
  543.       fprintf(groupfp, "%s %ld %hu\n", grouprec[i].groupname,
  544.               grouprec[i].lastread, grouprec[i].subtype);
  545.     }
  546.   }
  547.   fclose(groupfp);
  548. }
  549.  
  550. void far *mallocx(unsigned long l)
  551. {
  552.   void *x;
  553.   char huge *xx;
  554.  
  555.   if (!l)
  556.     l = 1;
  557.   x = farmalloc(l);
  558.   if (!x) {
  559.     fprintf(stderr, "\n ■ Unable to allocate %lu bytes of memory", l);
  560.     cursor('R');
  561.     exit(EXIT_FAILURE);
  562.   }
  563.   xx = (char huge *) x;
  564.   while (l) {
  565.     if (l > 32768L) {
  566.       memset((void *) xx, 0, 32768L);
  567.       l -= 32768L;
  568.       xx += 32768L;
  569.     } else {
  570.       memset((void *) xx, 0, l);
  571.       break;
  572.     }
  573.   }
  574.   return (x);
  575. }
  576.  
  577.  
  578. void far *malloca(unsigned long nbytes)
  579. {
  580.   void *buf;
  581.  
  582.   buf = malloc(nbytes + 1);
  583.   if (buf == NULL)
  584.     fprintf(stderr, "\n ■ Unable to allocate sufficient memory (%ld bytes)", nbytes);
  585.   return (buf);
  586. }
  587.  
  588. void nntp_shutdown(Mail_Socket * NNTP_sock)
  589. {
  590.   sock_printf(NNTP_sock->sock, "QUIT");
  591.   sock_close(NNTP_sock->sock);
  592.   sock_wait_closed(NNTP_sock->sock, SOCK_DELAY, NULL, &NNTP_stat);
  593. sock_err:
  594.   return;
  595. }
  596.  
  597.  
  598. void read_groups(void)
  599. {
  600.   int i = 0, ok;
  601.   unsigned short sn;
  602.   char *ss, fn[101], tmp[101];
  603.   FILE *groupfp;
  604.  
  605.   if (grouprec)
  606.     free((void *) grouprec);
  607.   grouprec = NULL;
  608.   ngroups = count_lines(newsrc);
  609.   if (!ngroups)
  610.     return;
  611.   grouprec = (GROUPFILEREC *) mallocx((ngroups + 1) * sizeof(GROUPFILEREC));
  612.   if (!grouprec) {
  613.     ngroups = 0;
  614.     fprintf(stderr, "\n ■ Unable to allocate memory for reading NEWS.RC!");
  615.     return;
  616.   }
  617.   groupfp = fsh_open(newsrc, "rt");
  618.   if (!groupfp) {
  619.     free((void *) grouprec);
  620.     ngroups = 0;
  621.     return;
  622.   }
  623.   while (fgets(tmp, 120, groupfp)) {
  624.     if (tmp[0]) {
  625.       if (strncmpi(tmp, "newsrc", 6) == 0) {
  626.         strcpy(grouprec[i].groupname, "newsrc");
  627.         ++i;
  628.       } else {
  629.         ss = strtok(tmp, " ");
  630.         strcpy(grouprec[i].groupname, ss);
  631.         ss = strtok(NULL, " ");
  632.         if (ss != NULL) {
  633.           grouprec[i].lastread = atol(ss);
  634.           ss = strtok(NULL, " \n");
  635.           if (ss != NULL) {
  636.             grouprec[i].subtype = atoi(ss);
  637.             ++i;
  638.           }
  639.         }
  640.       }
  641.     }
  642.   }
  643.   ngroups = i;
  644.   fclose(groupfp);
  645.   for (i = 0; i < ngroups; i++) {
  646.     if (grouprec[i].subtype) {
  647.       sprintf(fn, "%s\\N%hu.NET", net_data, grouprec[i].subtype);
  648.       if (!exist(fn))
  649.         log_it("\n ■ N%u.NET does not exist in %s!", grouprec[i].subtype,
  650.                net_data);
  651.       else {
  652.         groupfp = fsh_open(fn, "rt");
  653.         ok = 0;
  654.         while ((fgets(tmp, 25, groupfp)) && !ok) {
  655.           sn = atoi(tmp);
  656.           if (sn == 32767)
  657.             ok = 1;
  658.         }
  659.         fclose(groupfp);
  660.         if (!ok)
  661.           log_it("\n ■ @32767 not list as a subscriber in N%d.NET!",
  662.                  grouprec[i].subtype);
  663.       }
  664.     }
  665.   }
  666. }
  667.  
  668. int cgroup(Mail_Socket * NNTP_sock, char *s)
  669. {
  670.   static char _temp_buffer[STRING];
  671.  
  672.   sock_printf(NNTP_sock->sock, "GROUP %s", s);
  673.   sock_wait_input(NNTP_sock->sock, SOCK_DELAY, NULL, &NNTP_stat);
  674.   sock_gets(NNTP_sock->sock, _temp_buffer, sizeof(_temp_buffer));
  675.   sscanf(_temp_buffer, "%hu %lu", &reply, &reparticle);
  676.   if (reply == 411)
  677.     return -1;
  678.   else
  679.     if (reply == 211) {
  680.     sscanf(_temp_buffer, "%hu %lu %lu %lu %s",
  681.            &reply, &cur_numa, &cur_first, &cur_last, &cur_gname);
  682.     return 0;
  683.     }
  684.   else
  685.     log_it("\n ■ Unknown cgroup response : %s", _temp_buffer);
  686.   SOCK_READ_ERR(NNTP_sock);
  687.   return -1;
  688. }
  689.  
  690. int cstat(Mail_Socket * NNTP_sock, unsigned long i)
  691. {
  692.   char *p, *q;
  693.   static char _temp_buffer[STRING];
  694.  
  695.   sock_printf(NNTP_sock->sock, "STAT %lu", i);
  696.   sock_wait_input(NNTP_sock->sock, SOCK_DELAY, NULL, &NNTP_stat);
  697.   sock_gets(NNTP_sock->sock, _temp_buffer, sizeof(_temp_buffer));
  698.   sscanf(_temp_buffer, "%hu %lu", &reply, &reparticle);
  699.   if (reply == 423)
  700.     return -1;
  701.   else
  702.     if (reply == 223) {
  703.     cur_article = reparticle;
  704.     p = _temp_buffer;
  705.     q = cur_articleid;
  706.     while ((p < _temp_buffer + STRING - 2) && (*p != '<'))
  707.       p++;
  708.     while ((p < _temp_buffer + STRING - 2) && (*p != '>'))
  709.       *q++ = *p++;
  710.     *q++ = '>';
  711.     *q++ = '\0';
  712.     return 0;
  713.     }
  714.   else
  715.     log_it("\n ■ Unknown cstat error : %s", _temp_buffer);
  716.   SOCK_READ_ERR(NNTP_sock);
  717.   return -1;
  718. }
  719.  
  720. int qexit(Mail_Socket * NNTP_sock, int n)
  721. {
  722.   static char _temp_buffer[STR];
  723.  
  724.   if (n >= 10)
  725.     log_it("\n ! Fatal NEWS error: check configuration!");
  726.   fflush(stdout);
  727.   sock_printf(NNTP_sock->sock, "QUIT");
  728.   sock_wait_input(NNTP_sock->sock, SOCK_DELAY, NULL, &NNTP_stat);
  729.   sock_gets(NNTP_sock->sock, _temp_buffer, sizeof(_temp_buffer));
  730.   if (*_temp_buffer != '2')
  731.     log_it("\n ■ Tried to quit host but failed");
  732.   cursor('R');
  733.   check_packets();
  734.   if (n) {
  735.     fcloseall();
  736.     free_Mail_Socket(NNTP_sock);
  737.     exit(n);
  738.   }
  739.   SOCK_READ_ERR(NNTP_sock);
  740.   return 0;
  741. }
  742.  
  743. void treat(char *str)
  744. {
  745.   char *obuf, *nbuf;
  746.  
  747.   if (*str) {
  748.     for (obuf = str, nbuf = str; *obuf && obuf; ++obuf) {
  749.       if (((*obuf >= 32) && (*obuf <= 126)) || (*obuf == 10)) {
  750.         *nbuf++ = *obuf;
  751.       }
  752.     }
  753.   }
  754. }
  755.  
  756. void name_packet(char *pktname)
  757. {
  758.   int ok;
  759.   struct stat info;
  760.   unsigned i;
  761.  
  762.   ok = 0;
  763.   for (i = 0; ((i < 1000) && (!ok)); i++) {
  764.     sprintf(pktname, "%s\\P0-%u.%3.3d", net_data, i, instance);
  765.     if (stat(pktname, &info) == -1)
  766.       ok = 1;
  767.   }
  768. }
  769.  
  770. int savebody(Mail_Socket * NNTP_sock, int cug, int *abort)
  771. {
  772.   char s1[21], s2[21], ch;
  773.   unsigned int curpos, count, part;
  774.   char spin[26];
  775.   int i, place, len;
  776.   unsigned long msgsize;
  777.   struct stat statbuf;
  778.   FILE *tpktfp = NULL;
  779.   static char _temp_buffer[BIGSTR];
  780.  
  781.   strcpy(spin, "||//--\\\\");
  782.   place = count = 0;
  783.   len = strlen(spin);
  784.  
  785.   part = 1;
  786.   if (grouprec[cug].subtype == 0)
  787.     sprintf(tpktname, "%s\\NEWS%d.UUE", tmpdir, cug);
  788.   else {
  789.     sprintf(tpktname, "%s\\INPUT%d.MSG", tmpdir, part++);
  790.     if (stat(tpktname, &statbuf) == 0)
  791.       unlink(tpktname);
  792.   }
  793.   sock_printf(NNTP_sock->sock, "BODY %lu", cur_article);
  794.   sock_wait_input(NNTP_sock->sock, SOCK_DELAY, NULL, &NNTP_stat);
  795.   sock_gets(NNTP_sock->sock, _temp_buffer, sizeof(_temp_buffer));
  796.   sscanf(_temp_buffer, "%hu %lu", &reply, &reparticle);
  797.   if (reply == 423)
  798.     return -1;
  799.   else {
  800.     if (reply == 222) {
  801.       if (grouprec[cug].subtype) {
  802.         if ((tpktfp = fsh_open(tpktname, "wt+")) == NULL) {
  803.           log_it("\n ■ Unable to create temporary packet %s", tpktname);
  804.           qexit(NNTP_sock, 1);
  805.         }
  806.       } else {
  807.         if (tpktfp)
  808.           fclose(tpktfp);
  809.         if ((tpktfp = fsh_open(tpktname, "at+")) == NULL) {
  810.           log_it("\n ■ Unable to create temporary packet %s", tpktname);
  811.           qexit(NNTP_sock, 1);
  812.         } else {
  813.           fputs("\n", tpktfp);
  814.           for (i = 0; i < 79; i++)
  815.             fputs("-", tpktfp);
  816.           fputs("\n", tpktfp);
  817.           sprintf(_temp_buffer, "Art  : %lu\n", cur_article);
  818.           fputs(_temp_buffer, tpktfp);
  819.           sprintf(_temp_buffer, "Date : %s\n", cur_date);
  820.           fputs(_temp_buffer, tpktfp);
  821.           sprintf(_temp_buffer, "From : %s\n", cur_replyto);
  822.           fputs(_temp_buffer, tpktfp);
  823.           sprintf(_temp_buffer, "Subj : %s\n\n", cur_subject);
  824.           fputs(_temp_buffer, tpktfp);
  825.         }
  826.       }
  827.       fnsplit(tpktname, NULL, NULL, s1, s2);
  828.       if (grouprec[cug].subtype)
  829.         fprintf(stderr, "\n ■ Receiving message - <Esc> aborts - <Space> skips group [-]");
  830.       else
  831.         fprintf(stderr, "\n ■ Appending to %s%s - <Esc> aborts - <Space> skips group [-]", s1, s2);
  832.       msgsize = 0L;
  833.       curpos = 0L;
  834.       while (1) {
  835.         if (kbhit()) {
  836.           ch = (getch());
  837.           switch (ch) {
  838.             case 27:
  839.               fprintf(stderr, "\r ■ Abort detected... please wait until message is completed [-]");
  840.               *abort = 1;
  841.               break;
  842.             case 32:
  843.               fprintf(stderr, "\r ■ Skipping group... please wait until message is completed [-]");
  844.               *abort = 2;
  845.               break;
  846.             default:
  847.               break;
  848.           }
  849.         }
  850.         sock_wait_input(NNTP_sock->sock, SOCK_DELAY, NULL, &NNTP_stat);
  851.         sock_gets(NNTP_sock->sock, _temp_buffer, sizeof(_temp_buffer));
  852.         if (_temp_buffer[0] == '.' && _temp_buffer[1] == 0) {
  853.           break;
  854.         } else {
  855.           treat(_temp_buffer);
  856.           strcat(_temp_buffer, "\n");
  857.           curpos = strlen(_temp_buffer);
  858.           fputs(_temp_buffer, tpktfp);
  859.           msgsize += curpos;
  860.         }
  861.         if (count++ > 5) {
  862.           fprintf(stderr, "\b\b%c]", spin[place++]);
  863.           place %= len;
  864.           count = 0;
  865.         }
  866.         if ((msgsize > 30000L) && grouprec[cug].subtype) {
  867.           if (tpktfp)
  868.             fclose(tpktfp);
  869.           sprintf(tpktname, "%s\\INPUT%d.MSG", tmpdir, part++);
  870.           if (stat(tpktname, &statbuf) == 0)
  871.             unlink(tpktname);
  872.           if ((tpktfp = fsh_open(tpktname, "wt+")) == 0) {
  873.             log_it("\n ■ Unable to create temporary packet %s", tpktname);
  874.             qexit(NNTP_sock, 1);
  875.           }
  876.           backline();
  877.           fprintf(stderr, "\r ■ Breaking into %d%s part [ ]", (
  878.                                          part - 1), ordinal_text(part - 1));
  879.           msgsize = 0L;
  880.         }
  881.       }
  882.       if (tpktfp)
  883.         fclose(tpktfp);
  884.       fprintf(stderr, "\b\bX]");
  885.       return 1;
  886.     }
  887.   }
  888.   if (tpktfp)
  889.     fclose(tpktfp);
  890.   SOCK_READ_ERR(NNTP_sock);
  891.   return 0;
  892. }
  893.  
  894. int extract(char *to, char *key, char *from)
  895. {
  896.   if (!strnicmp(from, key, strlen(key))) {
  897.     from += strlen(key);
  898.     while (*from == ' ')
  899.       from++;
  900.     strcpy(to, from);
  901.     return 1;
  902.   } else
  903.     return 0;
  904. }
  905.  
  906.  
  907. int chead(Mail_Socket * NNTP_sock)
  908. {
  909.   static char _temp_buffer[BIGSTR];
  910.  
  911.   *cur_path = 0;
  912.   *cur_from = 0;
  913.   *cur_replyto = 0;
  914.   *cur_subject = 0;
  915.   *cur_newsgroups = 0;
  916.   *cur_message_ID = 0;
  917.   *cur_references = 0;
  918.   *cur_date = 0;
  919.  
  920.   sock_printf(NNTP_sock->sock, "HEAD %lu", cur_article);
  921.   sock_wait_input(NNTP_sock->sock, SOCK_DELAY, NULL, &NNTP_stat);
  922.   sock_gets(NNTP_sock->sock, _temp_buffer, sizeof(_temp_buffer));
  923.   sscanf(_temp_buffer, "%hu %lu", &reply, &reparticle);
  924.   if (reply == 423)
  925.     return 0;
  926.   else
  927.     if (reply == 221)
  928.     while (1) {
  929.       sock_wait_input(NNTP_sock->sock, SOCK_DELAY, NULL, &NNTP_stat);
  930.       sock_gets(NNTP_sock->sock, _temp_buffer, sizeof(_temp_buffer));
  931.       if (strlen(_temp_buffer) > 1024)
  932.         _temp_buffer[1024] = 0;
  933.       if (_temp_buffer[0] == '.' && _temp_buffer[1] == 0) {
  934.         if (cur_replyto[0] == 0)
  935.           strcpy(cur_replyto, cur_from);
  936.         return 1;
  937.       }
  938.       extract(cur_path, "Path:", _temp_buffer) ||
  939.           extract(cur_from, "From:", _temp_buffer) ||
  940.           extract(cur_subject, "Subject:", _temp_buffer) ||
  941.           extract(cur_replyto, "Reply-To:", _temp_buffer) ||
  942.           extract(cur_newsgroups, "Newsgroups:", _temp_buffer) ||
  943.           extract(cur_organization, "Organization:", _temp_buffer) ||
  944.           extract(cur_message_ID, "Message-ID:", _temp_buffer) ||
  945.           extract(cur_references, "References:", _temp_buffer) ||
  946.           extract(cur_lines, "Lines:", _temp_buffer) ||
  947.           extract(cur_date, "Date:", _temp_buffer);
  948.     }
  949.   else {
  950.     log_it("\n ■ Unknown chead error : %s", _temp_buffer);
  951.   }
  952.   SOCK_READ_ERR(NNTP_sock);
  953.   return 0;
  954. }
  955.  
  956. Mail_Socket *netsocket(char *host)
  957. {
  958.   Mail_Socket *NNTP_sock = NULL;
  959.   longword h;
  960.   static char _temp_buffer[STR];
  961.  
  962.   if (!(h = resolve(host)))
  963.     err_exit(EXIT_FAILURE, "\n ■ Could not resolve %s... aborting", host);
  964.   if ((NNTP_sock = (Mail_Socket *) farmalloc(sizeof(Mail_Socket))) == NULL)
  965.     err_exit(EXIT_FAILURE, "\n ■ Insufficient memory for socket... aborting.");
  966.   if ((NNTP_sock->sock = (tcp_Socket *) farmalloc(sizeof(tcp_Socket))) == NULL) {
  967.     farfree(NNTP_sock);
  968.     err_exit(EXIT_FAILURE, "\n ■ Insufficient memory for socket... aborting.");
  969.   }
  970.   if (!tcp_open(NNTP_sock->sock, 0, h, NNTP_PORT, NULL)) {
  971.     free_Mail_Socket(NNTP_sock);
  972.     err_exit(EXIT_FAILURE, "\n ■ TCP socket open failed... aborting");
  973.   }
  974.   sock_mode(NNTP_sock->sock, TCP_MODE_ASCII);
  975.   sock_wait_established(NNTP_sock->sock, SOCK_DELAY, NULL, &NNTP_stat);
  976.   sock_wait_input(NNTP_sock->sock, SOCK_DELAY, NULL, &NNTP_stat);
  977.   sock_gets(NNTP_sock->sock, _temp_buffer, sizeof(_temp_buffer));
  978.   sscanf(_temp_buffer, "%hu %lu", &reply, &reparticle);
  979.   switch (reply) {
  980.     case 200:
  981.       log_it("\n ■ Connection to %s accepted...", host);
  982.       break;
  983.     case 502:
  984.       free_Mail_Socket(NNTP_sock);
  985.       err_exit(EXIT_FAILURE, "\n ■ Connection to %s refused... try again later.", host);
  986.       break;
  987.     case 503:
  988.       free_Mail_Socket(NNTP_sock);
  989.       err_exit(EXIT_FAILURE, "\n ■ NNTP service unavailable. Connection to %s refused.", host);
  990.       break;
  991.     default:
  992.       free_Mail_Socket(NNTP_sock);
  993.       err_exit(EXIT_FAILURE, "\n ■ Unknown NNTP error. Connection to %s failed.", host);
  994.       break;
  995.   }
  996.   SOCK_READ_ERR(NNTP_sock);
  997.   return (NNTP_sock);
  998. }
  999.  
  1000. int cnext(Mail_Socket * NNTP_sock)
  1001. {
  1002.   char *p, *q;
  1003.   static char _temp_buffer[STRING];
  1004.  
  1005.   sock_printf(NNTP_sock->sock, "NEXT");
  1006.   sock_wait_input(NNTP_sock->sock, SOCK_DELAY, NULL, &NNTP_stat);
  1007.   sock_gets(NNTP_sock->sock, _temp_buffer, sizeof(_temp_buffer));
  1008.   sscanf(_temp_buffer, "%hu %lu", &reply, &reparticle);
  1009.   if (reply == 421)
  1010.     return -1;
  1011.   else
  1012.     if (reply == 223) {
  1013.     cur_article = reparticle;
  1014.     p = _temp_buffer;
  1015.     q = cur_articleid;
  1016.     while ((p < _temp_buffer + STRING - 2) && (*p != '<'))
  1017.       p++;
  1018.     while ((p < _temp_buffer + STRING - 2) && (*p != '>'))
  1019.       *q++ = *p++;
  1020.     *q++ = '>';
  1021.     *q++ = '\0';
  1022.     return 0;
  1023.     }
  1024.   else {
  1025.     log_it("\n ■ Unknown cnext error : %s", _temp_buffer);
  1026.   }
  1027.   SOCK_READ_ERR(NNTP_sock);
  1028.   return -1;
  1029. }
  1030.  
  1031. int saveactive(Mail_Socket * NNTP_sock, char *fn)
  1032. {
  1033.   char s[181], group[256], act;
  1034.   unsigned long to, from;
  1035.   int count;
  1036.   FILE *fp;
  1037.   static char _temp_buffer[BIGSTR];
  1038.  
  1039.   if ((fp = fsh_open(fn, "w")) == NULL) {
  1040.     perror(fn);
  1041.     return -1;
  1042.   }
  1043.   sock_printf(NNTP_sock->sock, "LIST");
  1044.   sock_wait_input(NNTP_sock->sock, SOCK_DELAY, NULL, &NNTP_stat);
  1045.   sock_gets(NNTP_sock->sock, _temp_buffer, sizeof(_temp_buffer));
  1046.   sscanf(_temp_buffer, "%hu %lu", &reply, &reparticle);
  1047.   if (reply == 215) {
  1048.     count = 0;
  1049.     while (1) {
  1050.       if (count++ % 25 == 0)
  1051.         fprintf(stderr, "\b\b\b\b\b\b\b%-7d", count);
  1052.       sock_wait_input(NNTP_sock->sock, SOCK_DELAY, NULL, &NNTP_stat);
  1053.       sock_gets(NNTP_sock->sock, _temp_buffer, sizeof(_temp_buffer));
  1054.       if (_temp_buffer[0] == '.' && _temp_buffer[1] == 0)
  1055.         break;
  1056.       sscanf(_temp_buffer, "%s %lu %lu %c", group, &to, &from, &act);
  1057.       sprintf(s, "%s %lu\n", group, to);
  1058.       //fprintf(fp, s);
  1059.       fsh_write(s, sizeof(char), strlen(s), fp);
  1060.     }
  1061.     log_it("\n ■ %d total newsgroups available on %s", count, serverhost);
  1062.     fclose(fp);
  1063.     return 0;
  1064.   } else
  1065.     log_it("\n ■ Unknown saveactive error : %s", _temp_buffer);
  1066.   SOCK_READ_ERR(NNTP_sock);
  1067.   fclose(fp);
  1068.   return -1;
  1069. }
  1070.  
  1071. int checkx(int cug)
  1072. {
  1073.   char *ptr, *ptr2, *ptr3, buf[256];
  1074.   int i, max;
  1075.  
  1076.   if (cug == 0)
  1077.     return 1;
  1078.   ptr = strtok(cur_organization, "*");
  1079.   trimstr1(ptr);
  1080.   if (strcmpi(ptr, syscfg.systemname) == 0) {
  1081.     log_it("\n ■ Skipping message - originally posted on %s.", syscfg.systemname);
  1082.     return 0;
  1083.   }
  1084.   ptr = cur_newsgroups;
  1085.   while (*ptr == ' ')
  1086.     ptr++;
  1087.   max = 0;
  1088.   while (1) {
  1089.     if (*ptr == 0)
  1090.       break;
  1091.     if (*ptr == ',') {
  1092.       ptr++;
  1093.       ++max;
  1094.     }
  1095.     while (*ptr == ' ')
  1096.       ptr++;
  1097.     ptr2 = ptr;
  1098.     ptr3 = buf;
  1099.     while (*ptr2 != 0 && *ptr2 != ',')
  1100.       *ptr3++ = *ptr2++;
  1101.     *ptr3 = 0;
  1102.     while (*(--ptr3) == ' ')
  1103.       *ptr3 = 0;
  1104.     ptr = ptr2;
  1105.     for (i = 0; i < cug; i++) {
  1106.       if (strcmpi(buf, grouprec[i].groupname) == 0) {
  1107.         fprintf(stderr, "\n ■ Skipping message - already posted in %s.",
  1108.                 grouprec[i].groupname);
  1109.         return 0;
  1110.       }
  1111.     }
  1112.     if (max > 10) {
  1113.       fprintf(stderr, "\n ■ Skipping message - crossposted to more than 10 newsgroups.");
  1114.       return 0;
  1115.     }
  1116.   }
  1117.   return 1;
  1118. }
  1119.  
  1120. void good_name(char *name)
  1121. {
  1122.   char *ss;
  1123.   int i;
  1124.  
  1125.   trimstr1(name);
  1126.   if ((strcspn(name, " ") == strlen(name)) && (strcspn(name, "(") == strlen(name)))
  1127.     if (_fstrchr(name, '@') != NULL)
  1128.       return;
  1129.   if (strcspn(name, "<") != strlen(name)) {
  1130.     ss = strtok(name, "<");
  1131.     if (ss)
  1132.       ss = strtok(NULL, ">");
  1133.     strcpy(name, ss);
  1134.     if (name[0] == 0)
  1135.       strcpy(name, "Unknown");
  1136.     return;
  1137.   }
  1138.   if ((i = strcspn(name, "(")) != strlen(name)) {
  1139.     if (name[i - 1] == 32) {
  1140.       ss = strtok(name, " ");
  1141.       if (ss)
  1142.         strcpy(name, ss);
  1143.     } else {
  1144.       ss = strtok(name, "(");
  1145.       if (ss)
  1146.         strcpy(name, ss);
  1147.     }
  1148.     if (name[0] == 0)
  1149.       strcpy(name, "Unknown");
  1150.     return;
  1151.   }
  1152. }
  1153.  
  1154. int postnews(Mail_Socket * NNTP_sock, int cug)
  1155. {
  1156.   char s[181], s1[12], s2[5], fn[201], *ss;
  1157.   int f1, nlines, in_header, len, tlen;
  1158.   FILE *fp;
  1159.   static char _temp_buffer[STR];
  1160.   long clock;
  1161.   struct ffblk ff;
  1162.  
  1163.   sprintf(fn, "%s\\OUTBOUND\\%hu.*", net_data, grouprec[cug].subtype);
  1164.   f1 = findfirst(fn, &ff, 0);
  1165.   if (f1 != 0) {
  1166.     log_it("\n ■ No outbound news articles to post...");
  1167.     return 1;
  1168.   }
  1169.   while (f1 == 0) {
  1170.     sock_printf(NNTP_sock->sock, "POST");
  1171.     sock_wait_input(NNTP_sock->sock, SOCK_DELAY, NULL, &NNTP_stat);
  1172.     sock_gets(NNTP_sock->sock, _temp_buffer, sizeof(_temp_buffer));
  1173.     if (*_temp_buffer != '3') {
  1174.       if (atoi(_temp_buffer) == 440)
  1175.         log_it("\n ■ No posting allowed to %s!", grouprec[cug].groupname);
  1176.       else
  1177.         log_it("\n ■ Remote error: %s", _temp_buffer);
  1178.       return 0;
  1179.     }
  1180.     fprintf(stderr, "\n ■ Posting article to %s\n", grouprec[cug].groupname);
  1181.     sprintf(s, "%s\\OUTBOUND\\%s", net_data, ff.ff_name);
  1182.     fp = fsh_open(s, "rb");
  1183.     nlines = 0;
  1184.     while (fgets(_temp_buffer, 120, fp) != NULL) {
  1185.       if (_temp_buffer[0] == '.' && _temp_buffer[1] == 0) {
  1186.         _temp_buffer[1] = '.';
  1187.         _temp_buffer[2] = 0;
  1188.       }
  1189.       tlen = 0;
  1190.       len = strlen(_temp_buffer);
  1191.       while (tlen < len) {
  1192.         if (!tcp_tick(NNTP_sock->sock)) {
  1193.           fclose(fp);
  1194.           fprintf(stderr, "\n ■ Connection reset by host");
  1195.           return 1;
  1196.         }
  1197.         tlen += sock_fastwrite(NNTP_sock->sock, &_temp_buffer[tlen], len - tlen);
  1198.       }
  1199.       backline();
  1200.       fprintf(stderr, "\r ■ Lines sent : %d", ++nlines);
  1201.     }
  1202.     fclose(fp);
  1203.     sock_printf(NNTP_sock->sock, ".\n");
  1204.     fprintf(stderr, "\n ■ Awaiting acknowledgement - may take several minutes...");
  1205.     log_it("\n ■ Server response : ");
  1206.     sock_wait_input(NNTP_sock->sock, 180, NULL, &NNTP_stat);
  1207.     sock_gets(NNTP_sock->sock, _temp_buffer, sizeof(_temp_buffer));
  1208.     log_it("%s", _temp_buffer);
  1209.     if (*_temp_buffer != '2') {
  1210.       if (atoi(_temp_buffer) == 441) {
  1211.         ss = strtok(_temp_buffer, " ");
  1212.         ss = strtok(NULL, " ");
  1213.         if (atoi(ss) == 435)
  1214.           unlink(s);
  1215.         fnsplit(s, NULL, NULL, s1, s2);
  1216.         log_it("\n ■ %s%s not accepted by server - nothing posted", s1, s2);
  1217.       } else
  1218.         log_it("\n ■ Remote error: %s", _temp_buffer);
  1219.     } else {
  1220.       if (unlink(s) == 0)
  1221.         log_it("\n ■ Deleted sent message - %s", s);
  1222.     }
  1223.     f1 = findnext(&ff);
  1224.   }
  1225.   SOCK_READ_ERR(NNTP_sock);
  1226.   return 0;
  1227. }
  1228.  
  1229. int get_subtype(int sub)
  1230. {
  1231.   int ok;
  1232.   char fn[181], s[81], net_name[21], *ss;
  1233.   FILE *fp;
  1234.  
  1235.   sprintf(fn, "%sSUBS.XTR", syscfg.datadir);
  1236.   fp = fsh_open(fn, "r");
  1237.   if (!fp)
  1238.     return 0;
  1239.   ok = 0;
  1240.   while (fgets(s, 80, fp)) {
  1241.     if (s[0] == '!') {
  1242.       if (sub == atoi(&s[1]))
  1243.         ok = 1;
  1244.     }
  1245.     if (ok && (s[0] == '$')) {
  1246.       ss = strtok(s, " ");
  1247.       strcpy(net_name, &ss[1]);
  1248.       ss = strtok(NULL, " ");
  1249.       fclose(fp);
  1250.       if ((stricmp(net_name, "FILENET") == 0) && (isdigit(ss[0])))
  1251.         return atoi(ss);
  1252.       else
  1253.         return 0;
  1254.     }
  1255.   }
  1256.   fclose(fp);
  1257.   return 0;
  1258. }
  1259.  
  1260. int max_on_sub(int cug)
  1261. {
  1262.   int i, f, max_subs, num_subs, stype;
  1263.   char s[121];
  1264.  
  1265.   if (grouprec[cug].subtype == 0)
  1266.     return 0;
  1267.   max_subs = syscfg.max_subs;
  1268.   subboards = (subboardrec *) mallocx(max_subs * sizeof(subboardrec));
  1269.   sprintf(s, "%sSUBS.DAT", syscfg.datadir);
  1270.   f = sh_open1(s, O_RDONLY | O_BINARY);
  1271.   if (f < 0) {
  1272.     fprintf(stderr, "\n ■ %s NOT FOUND", s);
  1273.     return 0;
  1274.   }
  1275.   num_subs = (sh_read(f, subboards, (max_subs * sizeof(subboardrec)))) /
  1276.       sizeof(subboardrec);
  1277.   f = sh_close(f);
  1278.   for (i = 0; i < num_subs; i++) {
  1279.     fprintf(stderr, "\b\b\b\b%-4d", i);
  1280.     stype = get_subtype(i);
  1281.     if (stype && (grouprec[cug].subtype == stype)) {
  1282.       if (subboards)
  1283.         free(subboards);
  1284.       fprintf(stderr, "\b\b\b\b%hu messages.", subboards[i].maxmsgs);
  1285.       return subboards[i].maxmsgs;
  1286.     }
  1287.   }
  1288.   if (subboards)
  1289.     free(subboards);
  1290.   return 0;
  1291. }
  1292.  
  1293. int getnews(char *hostname)
  1294. {
  1295.   int f1, nup, nug, cug, abort, ok, done, firstrun, new_articles, max_articles, parts;
  1296.   char *p, fn[201], mailname[121], reline[121], s[21], s1[21], pktname[121];
  1297.   char orig_subj[STRING];
  1298.   unsigned int text_len;
  1299.   net_header_rec nh;
  1300.   struct date dt;
  1301.   struct time tm;
  1302.   struct ffblk ff;
  1303.   static FILE *fp;
  1304.   Mail_Socket *nntp_sock;
  1305.   static char _temp_buffer[STR];
  1306.  
  1307.   abort = cug = 0;
  1308.   sock_init();
  1309.   nntp_sock = netsocket(hostname);
  1310.  
  1311.   if (stricmp(grouprec[0].groupname, "newsrc") == 0) {
  1312.     grouprec[0].groupname[0] = 0;
  1313.     write_groups(0);
  1314.     if (grouprec)
  1315.       free(grouprec);
  1316.     sprintf(fn, "%s\\NEWSRC", net_data);
  1317.     log_it("\n ■ Creating newsgroup list : %s...         ", fn);
  1318.     saveactive(nntp_sock, fn);
  1319.     nntp_shutdown(nntp_sock);
  1320.     free_Mail_Socket(nntp_sock);
  1321.     return 0;
  1322.   }
  1323.   nug = nup = 1;
  1324.   while ((cug < ngroups) && (!abort)) {
  1325.     if (kbhit()) {
  1326.       if (getch() == 27) {
  1327.         log_it("\n ■ Aborting news retrieval session...");
  1328.         if (fp)
  1329.           fclose(fp);
  1330.         grouprec[cug].lastread = cur_article;
  1331.         write_groups(1);
  1332.         nntp_shutdown(nntp_sock);
  1333.         free_Mail_Socket(nntp_sock);
  1334.         return 1;
  1335.       }
  1336.     }
  1337.     if (nup) {
  1338.       nup = 0;
  1339.       if (grouprec[cug].subtype) {
  1340.         if (fp)
  1341.           fclose(fp);
  1342.         write_groups(0);
  1343.         name_packet(pktname);
  1344.         if ((fp = fsh_open(pktname, "wb")) == NULL) {
  1345.           log_it("\n ■ Unable to create %s!", pktname);
  1346.           qexit(nntp_sock, 1);
  1347.         } else {
  1348.           fnsplit(pktname, NULL, NULL, s, s1);
  1349.           fprintf(stderr, "\n ■ Creating new packet : %s%s", s, s1);
  1350.         }
  1351.       } else {
  1352.         if (fp) {
  1353.           fclose(fp);
  1354.         }
  1355.       }
  1356.     }
  1357.     if (nug) {
  1358.       cur_article = ++grouprec[cug].lastread;
  1359.       nug = 0;
  1360.       if (cgroup(nntp_sock, grouprec[cug].groupname)) {
  1361.         log_it("\n ■ Invalid newsgroup \"%s\" - removed from NEWS.RC.",
  1362.                grouprec[cug].groupname);
  1363.         grouprec[cug].groupname[0] = 0;
  1364.         if (++bogus >= 10) {
  1365.           log_it("\n ■ More than 10 invalid newsgroups... possible NEWS.RC error!");
  1366.           qexit(nntp_sock, 10);
  1367.         }
  1368.         nug = 1;
  1369.         /* continue;  Removed Beta-24 */
  1370.       }
  1371.       if (!nug) { /* Added Beta-24 */
  1372.         log_it("\n ■ Requesting %s... ", grouprec[cug].groupname);
  1373.         if (grouprec[cug].lastread < cur_first)
  1374.           grouprec[cug].lastread = cur_first;
  1375.         if (grouprec[cug].lastread > cur_last) {
  1376.           grouprec[cug].lastread = cur_last;
  1377.           log_it("no new articles.");
  1378.           nug = 1;
  1379.         } else {
  1380.           new_articles = cur_last - grouprec[cug].lastread + 1;
  1381.           log_it("%lu new article%s.        ",
  1382.                  cur_last - grouprec[cug].lastread + 1,
  1383.                  new_articles == 1 ? "" : "s");
  1384.           if (new_articles > 250) {
  1385.             fprintf(stderr, "\n ■ Checking maximum articles allowed on sub :     ");
  1386.             max_articles = max_on_sub(cug);
  1387.             if (max_articles && (new_articles > max_articles)) {
  1388.               log_it("\n ■ Requesting most recent %d articles", max_articles);
  1389.               grouprec[cug].lastread = (cur_last - max_articles);
  1390.             }
  1391.           }
  1392.         }
  1393.         postnews(nntp_sock, cug);
  1394.         if (!nug) {
  1395.           if (cur_numa == 0) {
  1396.             log_it("\n ■ No articles available in %s...",
  1397.                    grouprec[cug].groupname);
  1398.             nug = 1;
  1399.             continue;
  1400.           } else {
  1401.             if (cstat(nntp_sock, grouprec[cug].lastread) &&
  1402.                 cstat(nntp_sock, cur_last))
  1403.               nug = 1;
  1404.           }
  1405.         }
  1406.       }
  1407.     } else {
  1408.       if (cnext(nntp_sock)) {
  1409.         fprintf(stderr, "\n ■ End of new articles in %s",
  1410.                 grouprec[cug].groupname);
  1411.         nug = 1;
  1412.         write_groups(1);
  1413.       }
  1414.     }
  1415.     if (!nug) {
  1416.       // if ((!chead(nntp_sock)) || (!checkx(cug))) {
  1417.       if ((chead(nntp_sock)) && (checkx(cug))) {
  1418.         if (cur_subject[0]) {
  1419.           treat(cur_subject);
  1420.           if (strlen(cur_subject) > 65)
  1421.             cur_subject[65] = '\0';
  1422.         } else
  1423.           strcpy(cur_subject, "No subject");
  1424.         strcpy(orig_subj, cur_subject);
  1425.         if (cur_from[0]) {
  1426.           treat(cur_from);
  1427.           if (strlen(cur_from) > 45)
  1428.             cur_from[45] = 0;
  1429.         } else
  1430.           strcpy(cur_from, "Unknown");
  1431.         if (cur_replyto[0]) {
  1432.           /* treat(cur_replyto);     */
  1433.           /* good_name(cur_replyto); */
  1434.           if (strlen(cur_replyto) > 45)
  1435.             cur_replyto[45] = 0;
  1436.         }
  1437.         strncpy(_temp_buffer, orig_subj, 55);
  1438.         _temp_buffer[55] = '\0';
  1439.         fprintf(stderr, "\n ■ [%lu/%lu] : %s ", cur_article,
  1440.                 cur_last, _temp_buffer);
  1441.         ok = savebody(nntp_sock, cug, &abort);
  1442.         if (ok && grouprec[cug].subtype) {
  1443.           strcpy(msgarea, grouprec[cug].groupname);
  1444.           sprintf(msgto, "All");
  1445.           sprintf(fn, "%s\\INPUT*.MSG", tmpdir);
  1446.           done = 1;
  1447.           parts = 0;
  1448.           if (findfirst(fn, &ff, 0) == 0) {
  1449.             parts = 1;
  1450.             done = 0;
  1451.           }
  1452.           firstrun = 1;
  1453.           while (!done) {
  1454.             sprintf(fn, "%s\\%s", tmpdir, ff.ff_name);
  1455.             f1 = sh_open1(fn, O_RDONLY | O_BINARY);
  1456.             text_len = (unsigned int) filelength(f1);
  1457.             if (text_len > 32000L) {
  1458.               fprintf(stderr, "\n ■ Truncating %ld bytes from input file",
  1459.                       text_len - 32000L);
  1460.               text_len = 32000L;
  1461.             }
  1462.             p = (char *) malloca(32767);
  1463.             if (!p) {
  1464.               log_it("\n ■ Insufficient memory to read entire message");
  1465.               qexit(nntp_sock, 1);
  1466.             }
  1467.             sh_read(f1, (void *) p, text_len);
  1468.             sh_close(f1);
  1469.             nh.tosys = sy;
  1470.             nh.touser = 0;
  1471.             nh.fromsys = 32767L;
  1472.             nh.fromuser = 0;
  1473.             nh.main_type = main_type_pre_post;
  1474.             nh.minor_type = grouprec[cug].subtype;
  1475.             nh.list_len = 0;
  1476.             gettime(&tm);
  1477.             getdate(&dt);
  1478.             nh.daten = dostounix(&dt, &tm);
  1479.             nh.method = 0;
  1480.             if (parts > 1) {
  1481.               sprintf(_temp_buffer, "%d%s ", parts, ordinal_text(parts));
  1482.               strcat(_temp_buffer, orig_subj);
  1483.               strcpy(cur_subject, _temp_buffer);
  1484.               if (strlen(cur_subject) > 72)
  1485.                 cur_subject[72] = '\0';
  1486.               else
  1487.                 cur_subject[strlen(cur_subject)] = '\0';
  1488.             }
  1489.             nh.length = text_len + strlen(cur_subject) + 1;
  1490.             strncpy(mailname, cur_replyto, 46);
  1491.             strcat(mailname, "\r\n");
  1492.             nh.length += strlen(mailname);
  1493.             nh.length += 24 + 2;
  1494.             if (firstrun) {
  1495.               firstrun = 0;
  1496.               strncpy(reline, cur_articleid, 60);
  1497.               sprintf(cur_articleid, "RE: %s\r\n\r\n", reline);
  1498.             }
  1499.             nh.length += strlen(cur_articleid);
  1500.             fsh_write(&nh, sizeof(net_header_rec), 1, fp);
  1501.             fsh_write(cur_subject, sizeof(char), strlen(cur_subject) +1, fp);
  1502.             fsh_write(mailname, sizeof(char), strlen(mailname), fp);
  1503.             strncpy(_temp_buffer, ctime(&(time_t) nh.daten), 24);
  1504.             _temp_buffer[24] = '\0';
  1505.             strcat(_temp_buffer, "\r\n");
  1506.             fsh_write(_temp_buffer, sizeof(char), strlen(_temp_buffer), fp);
  1507.             sprintf(_temp_buffer, "%s\n\n", cur_articleid);
  1508.             fsh_write(cur_articleid, sizeof(char), strlen(cur_articleid), fp);
  1509.             fsh_write(p, sizeof(char), text_len, fp);
  1510.             if (p)
  1511.               free(p);
  1512.             unlink(fn);
  1513.             if (findnext(&ff) == 0) {
  1514.               done = 0;
  1515.               ++parts;
  1516.             } else
  1517.               done = 1;
  1518.           }
  1519.         }
  1520.         grouprec[cug].lastread = cur_article;
  1521.       } else
  1522.         grouprec[cug].lastread = cur_article + 1;
  1523.       if ((filelength(fileno(fp)) > 250000L) && grouprec[cug].subtype)
  1524.         nup = 1;
  1525.       if (abort == 2) {
  1526.         write_groups(1);
  1527.         nug = 1;
  1528.         abort = 0;
  1529.       }
  1530.     }
  1531.     if (nug) {
  1532.       ++cug;
  1533.       if ((grouprec[cug - 1].subtype == 0) && (grouprec[cug].subtype)) {
  1534.         nup = 1;
  1535.       } else {
  1536.         if ((grouprec[cug - 1].subtype) && (grouprec[cug].subtype == 0)) {
  1537.           if (fp) {
  1538.             fclose(fp);
  1539.           }
  1540.         }
  1541.       }
  1542.     }
  1543.   }
  1544.   if (fp)
  1545.     fclose(fp);
  1546.   if (abort)
  1547.     log_it("\n ■ Session aborted from keyboard");
  1548.   write_groups(1);
  1549.   nntp_shutdown(nntp_sock);
  1550.   free_Mail_Socket(nntp_sock);
  1551.   return 0;
  1552. }
  1553.  
  1554. void main(int argc, char *argv[])
  1555. {
  1556.   int f;
  1557.   char s[201], fn[201], *ss;
  1558.   FILE *fp;
  1559.   struct tm *time_now;
  1560.   time_t some;
  1561.  
  1562.   cursor('S');
  1563.   cursor('H');
  1564.   fprintf(stderr, "\n ■ %s", version);
  1565.   if (argc != 4)
  1566.     err_exit(EXIT_FAILURE, "\n ■ Invalid arguments for %s", argv[0]);
  1567.   ss = getenv("WWIV_INSTANCE");
  1568.   if (ss) {
  1569.     instance = atoi(ss);
  1570.     if ((instance <= 0) || (instance >= 1000)) {
  1571.       log_it("\n ■ WWIV_INSTANCE set to %d.  Can only be 1..999!", instance);
  1572.       instance = 1;
  1573.     }
  1574.   } else
  1575.     instance = 1;
  1576.   SOCK_DELAY = 120;
  1577.   get_dir(maindir, 0);
  1578.   strcpy(net_data, argv[1]);
  1579.   strcpy(serverhost, argv[2]);
  1580.   if (get_nb_version())
  1581.     multitasker = 8;
  1582.   else
  1583.     detect_multitask();
  1584.   switch (multitasker) {
  1585.     case 1:
  1586.       get_dv_version();
  1587.       break;
  1588.     case 2:
  1589.       get_win_version();
  1590.       break;
  1591.     case 3:
  1592.       get_dv_version();
  1593.       break;
  1594.     case 4:
  1595.     case 5:
  1596.     case 6:
  1597.     case 7:
  1598.       break;
  1599.     case 8:
  1600.       multitasker = 1;
  1601.       break;
  1602.     default:
  1603.       break;
  1604.   }
  1605.   time(&some);
  1606.   time_now = localtime(&some);
  1607.   strftime(s, 80, "\n\nNEWS session beginning on %A, %B %d, %Y at %H:%M %p",
  1608.            time_now);
  1609.   sprintf(fn, "%s\\NEWS.LOG", net_data);
  1610.   if ((fp = fsh_open(fn, "at")) != NULL) {
  1611.     fprintf(fp, s);
  1612.     fclose(fp);
  1613.   }
  1614.   sprintf(tmpdir, "%s\\SPOOL", net_data);
  1615.   sy = atoi(argv[3]);
  1616.   sprintf(s, "%s\\CONFIG.DAT", maindir);
  1617.   f = sh_open1(s, O_RDONLY | O_BINARY);
  1618.   if (f < 0)
  1619.     err_exit(EXIT_FAILURE, "\n ■ %s NOT FOUND.", s);
  1620.   sh_read(f, (void *) (&syscfg), sizeof(configrec));
  1621.   sh_close(f);
  1622.   sprintf(newsrc, "%s\\NEWS.RC", net_data);
  1623.   read_groups();
  1624.   if (ngroups == 0)
  1625.     err_exit(EXIT_FAILURE, "\n ■ Unable to access newsgroup file: %s!", newsrc);
  1626.   if (stricmp(grouprec[0].groupname, "newsrc") == 0)
  1627.     log_it("\n ■ Retrieving current newsgroup listing from %s",
  1628.            serverhost);
  1629.   else
  1630.     log_it("\n ■ %d newsgroup%s defined in %s", ngroups,
  1631.            ngroups == 1 ? "" : "s", strlwr(newsrc));
  1632.   if (getnews(serverhost))
  1633.     err_exit(EXIT_FAILURE, "\n ■ Exiting program.");
  1634.   if (grouprec)
  1635.     free(grouprec);
  1636.   grouprec = NULL;
  1637.   cd_to(maindir);
  1638.   log_it("\n ■ NEWS succesfully completed processing %d newsgroups", ngroups);
  1639.   err_exit(EXIT_SUCCESS, "\n ■ Normal program termination");
  1640. }
  1641.