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