home *** CD-ROM | disk | FTP | other *** search
/ Black Box 4 / BlackBox.cdr / lan / snuz.arj / SNUZ.C < prev    next >
C/C++ Source or Header  |  1991-06-23  |  33KB  |  1,437 lines

  1. /* Snuz -- an NNTP News Reader for the IBM-PC  */
  2.  
  3.  
  4. /*
  5.  * This program is a vastly enlarged and improved version of the program
  6.  * "red" from the pcip distribution. The new parts are written by J.D.
  7.  * McDonald and are public domain. The older parts are also freely
  8.  * distributable. See the pcip distribution for more details. The version of
  9.  * pcip this compiles with was obtained from husc6.harvard.edu. It probably
  10.  * will not work with other versions. To compile this, use Microsoft C 5.1
  11.  * and the include files provided with pcip - not Microsoft's ones. It is
  12.  * small model and probably needs the /Gs switch. The picp libraries needed
  13.  * are tcp, domain, udp, packet, ip, net, task, and pc. Also needed is the
  14.  * file proto.c.
  15.  */
  16.  
  17. /*
  18.  * Further note: I don't really understand how the Internet works, or the
  19.  * internals of pcip, at least not completely. NNTP itself is fairly easy to
  20.  * understand. Basically, this was cooked up using by expanding on code
  21.  * somebody else had written.
  22.  */
  23.  
  24.  
  25.  
  26. #include <stdio.h>
  27. #include <ctype.h>
  28. #include <process.h>
  29. #include <string.h>
  30.  
  31.  
  32. long            time(long *);
  33. char           *malloc(unsigned);
  34. int             kbhit(void);
  35. int             rename(char *, char *);
  36. int             remove(char *);
  37. void            perror(char *);
  38. int             atoi(char *);
  39.  
  40. extern int      errno;
  41.  
  42. #define NGROUPS 600
  43. #define STRING 512
  44.  
  45.  
  46. char            serverhost[128];
  47. char            newsrc[128] = "snuz.rc";
  48. char            fromline[128];
  49. char            editorpath[128];
  50. char            smtppath[128];
  51. char            tmpdir[128] = "c:";
  52.  
  53.  
  54.  
  55. char           *version = "\nSnuz ver. 1.00\n\n";
  56. char            tmpfil[128];
  57. struct servent *ser;
  58. struct hostent *hp;
  59.  
  60. FILE           *server;
  61. int             serverfd;
  62.  
  63. int             reply;
  64. unsigned long   reparticle;
  65.  
  66. char            cur_gname[STRING];
  67. int             cur_group;
  68. unsigned long   cur_numa, cur_first, cur_last;
  69.  
  70. unsigned long   cur_article;
  71. unsigned long   follow_up_article;
  72. char            cur_articleid[STRING];
  73. char            cur_path[STRING], cur_from[STRING], cur_subject[STRING], cur_replyto[STRING];
  74. char            cur_newsgroups[STRING], cur_message_ID[STRING], cur_references[STRING];
  75. char            cur_date[STRING];
  76.  
  77. char           *groups[NGROUPS];
  78. unsigned long   firsts[NGROUPS];
  79. int             ngroups;
  80. int             bogus = 0;
  81.  
  82. char           *servp;
  83. int             servf;
  84. char            servb[2048];
  85.  
  86. void            startup(int, char **);
  87. void            compactgroups(void);
  88. void            qexit(int);
  89. int             cstat(unsigned long);
  90. void            docommand(void);
  91. void            dumpnewsrc(void);
  92. int             postnews(void);
  93. void            sendmail(void);
  94. int             extract(char *, char *, char *);
  95. void            pcip_exit(void);
  96. int             netsocket(void);
  97. void            getserv(char *, int);
  98. int             saveactive(char *);
  99. void            getnewsrc(void);
  100. int             cgroup(char *);
  101. int             cnext(void);
  102. int             chead(void);
  103. int             checkx(void);
  104. int             ngetc(void);
  105. int             showbody(void);
  106. int             savebody(int);
  107. int             getgroup(char *);
  108. void            putserv(char *);
  109. int             tcpwrite(int, char *, int);
  110. void            usleep(void);
  111. void            xabort(void);
  112. void            clearscreen(void);
  113. int             showindex(int);
  114. void            listgroups(void);
  115. int             getpost(int);
  116. void            reversevideo(char *);
  117. void            normalvideo(void);
  118. void            backline(void);
  119. int             tcpread(int, char *, int);
  120. int             tcpopen(char *, int);
  121. int             valid_header(char *);
  122. char           *getenv(char *);
  123.  
  124. int 
  125. main(int argc, char **argv)
  126. {
  127.     startup(argc, argv);
  128.     docommand();
  129.     dumpnewsrc();
  130.     postnews();
  131.     qexit(0);
  132.     pcip_exit();   /* this routine does all the 'onexit' processing which has
  133.             * been called for when initializing the pcip package */
  134.     sendmail();       /* this routine never returns */
  135.     return 0;
  136. }
  137.  
  138.  
  139. void
  140. startup(int argc, char **argv)
  141. {
  142. char            buf[STRING];
  143. FILE           *cfgfile;
  144. char           *ptr;
  145. int             i;
  146.  
  147.     if (argc == 2 || argc > 3 || (argc == 3 && (!argv[2] ||
  148.                  argv[1][0] != '-' || argv[1][1] != 'S'))) {
  149.     printf("Useage: snuz [-S filename] (-S makes list of newsgroups)\n");
  150.     exit(1);
  151.     }
  152.     ptr = argv[0];
  153.     while (*ptr)
  154.     *ptr++;
  155.     while (*ptr != ':' && *ptr != '\\' && *ptr != '/' && ptr != argv[0])
  156.     *(ptr--) = 0;
  157.     if((ptr  = getenv("SNUZCFG")) == NULL)
  158.         strcpy(buf, argv[0]);
  159.     else {
  160.         strcpy(buf, ptr);
  161.         strcat(buf, "\\");
  162.     }
  163.  
  164.     strcat(buf, "snuz.cfg");    
  165.     if ((cfgfile = fopen(buf, "r")) == NULL) {
  166.     printf("can't open snuz.cfg file %s\n", buf);
  167.     exit(1);
  168.     }
  169.     while (1) {
  170.     if (fgets(buf, 126, cfgfile) == NULL)
  171.         break;
  172.     extract(newsrc, "SNUZRC=", buf);
  173.     extract(serverhost, "NNTPHOST=", buf);
  174.     extract(fromline, "NNTPFROM=", buf);
  175.     extract(editorpath, "EDITOR=", buf);
  176.     extract(tmpdir, "TMP=", buf);
  177.     extract(smtppath, "SMTPPATH=", buf);
  178.     }
  179.     fclose(cfgfile);
  180.     for (i = 0; i < 128; i++) {
  181.     if (newsrc[i] == '\n')
  182.         newsrc[i] = 0;
  183.     if (serverhost[i] == '\n')
  184.         serverhost[i] = 0;
  185.     if (fromline[i] == '\n')
  186.         fromline[i] = 0;
  187.     if (editorpath[i] == '\n')
  188.         editorpath[i] = 0;
  189.     if (tmpdir[i] == '\n')
  190.         tmpdir[i] = 0;
  191.     if (smtppath[i] == '\n')
  192.         smtppath[i] = 0;
  193.     }
  194.     if (!(*serverhost) || !(*fromline) || !(*editorpath) || !(*smtppath)) {
  195.     printf("incomplete snuz.cfg file\n");
  196.     exit(1);
  197.     }
  198.     strcat(tmpdir, "\\");
  199.  
  200.     printf(version);
  201.  
  202.     if (argc == 3) {
  203.     serverfd = netsocket();
  204.     servf = 0;
  205.     getserv(buf, sizeof buf);
  206.     saveactive(argv[2]);
  207.     qexit(1);
  208.     }
  209.     getnewsrc();
  210.     if (ngroups < 2) {
  211.     printf("You need at least two newsgroups\n");
  212.     exit(1);
  213.     }
  214.     serverfd = netsocket();    /* Note: this call does a lot, including
  215.                  * setting up some important onexit routines. */
  216.     servf = 0;
  217.     getserv(buf, sizeof buf);
  218.     buf[77] = '\0';
  219.     printf("[%s]\n", buf);
  220. }
  221.  
  222. void 
  223. docommand()
  224. {
  225. char            buf[128];
  226. char           *ptr;
  227. int             cug, nug;
  228. int             ch, i, qhead;
  229. int             skipgroup = 0;
  230. int             noquery = 0;
  231. int             oldquery = 0;
  232. int             noxpost = 1;
  233. int             skipalready = 0;
  234. FILE           *qfile, *ifile;
  235. long            xtime;
  236. unsigned long   ltemp;
  237. long            save_article;
  238.  
  239.     cug = 0;
  240.     cur_article = firsts[0];
  241.     cur_group = -1;
  242.     nug = 1;
  243.     while (1) {
  244.     if (nug) {
  245.         nug = 0;
  246.         follow_up_article = 0xffffffff;
  247.         if (cug < 0) {
  248.         printf("▒▒▒▒▒▒ trying to read before first group ▒▒▒▒▒▒ *\n");
  249.         cug = 0;
  250.         cur_article = firsts[cug];
  251.         cur_group = -1;
  252.  
  253.         }
  254.         if (cug >= ngroups) {
  255.         printf("▒▒▒▒▒▒ trying to read after last group ▒▒▒▒▒▒ \n");
  256.         cug = ngroups - 1;
  257.         cur_article = firsts[cug];
  258.         cur_group = -1;
  259.         }
  260.         if (cug != cur_group) {
  261.         printf("\n▒▒▒▒▒▒ %s ▒▒▒▒▒▒\n", groups[cug]);
  262.         if (cgroup(groups[cug])) {
  263.             printf("[invalid or deleted group]\n");
  264.             if (++bogus >= 30) {
  265.             qexit(10);
  266.             }
  267.             groups[cug] = NULL;
  268.             firsts[cug] = 0;
  269.             compactgroups();
  270.             cug++;
  271.             cur_group = -1;
  272.             if (cug >= ngroups)
  273.             cug = 0;
  274.             nug++;
  275.             continue;
  276.         }
  277.         printf("First: %U  Last: %U  Current: %U\n\n",
  278.             cur_first, cur_last, firsts[cug] > cur_last ? cur_last :
  279.                firsts[cug]);
  280.         }
  281.         cur_group = cug;
  282.         if (firsts[cug] < cur_first)
  283.         firsts[cug] = cur_first;
  284.         if (firsts[cug] > cur_last + 1)
  285.         firsts[cug] = cur_last + 1;
  286.         if (cur_numa == 0) {
  287.         if (!skipalready || cug >= ngroups - 1 || kbhit()) {
  288.             printf("▒▒▒▒▒▒ no articles in this group ▒▒▒▒▒▒\n");
  289.             skipgroup = 2;
  290.         } else {
  291.             cug++;
  292.             nug++;
  293.             continue;
  294.         }
  295.  
  296.         } else if (cstat(firsts[cug]) && cstat(cur_last)) {
  297.         if (!skipalready || cug >= ngroups - 1 || kbhit()) {
  298.             printf("▒▒▒▒▒▒ group inaccessible ▒▒▒▒▒▒\n");
  299.             skipgroup = 2;
  300.         } else {
  301.             cug++;
  302.             nug++;
  303.             continue;
  304.         }
  305.         } else if (firsts[cug] > cur_last) {
  306.         if (!skipalready || cug >= ngroups - 1 || kbhit()) {
  307.             printf(
  308.                "▒▒▒▒▒▒ already read last article - <RETURN> will skip group ▒▒▒▒▒▒\n");
  309.             skipgroup = 1;
  310.         } else {
  311.             cug++;
  312.             nug++;
  313.             continue;
  314.         }
  315.         }
  316.     } else {
  317.         if (cnext()) {
  318.         printf("▒▒▒▒▒▒ End of group %s ▒▒▒▒▒▒\n", groups[cug]);
  319.         skipgroup = 2;
  320.         firsts[cug] = cur_last + 1;
  321.         }
  322.     }
  323.     qhead = chead();
  324.     if (!skipgroup) {
  325.         if (qhead) {
  326.         printf("[article %U: bad header]\n", cur_article);
  327.         firsts[cug] = cur_article + 1;
  328.         continue;
  329.         }
  330.         if (noxpost && checkx()) {
  331.         firsts[cug] = cur_article + 1;
  332.         continue;
  333.         }
  334.     }
  335. query:
  336.     {
  337.         if (noquery)
  338.         ch = 'y';
  339.         else if (oldquery)
  340.         ch = oldquery;
  341.         else {
  342.         printf(">");
  343.         ch = ngetc();
  344.         }
  345.         oldquery = 0;
  346.         noquery = 0;
  347.         if ((skipgroup && ch == '\r') || (skipgroup == 2 && ch == 'y'))
  348.         ch = 'N';
  349.  
  350.         skipgroup = 0;
  351.  
  352.  
  353.         switch (ch) {
  354.         case '?':
  355.         case 'H':
  356.         case 'h':
  357.         printf("\n<RETURN> or y - read next article\n");
  358.         printf("= - reread current article\n");
  359.         printf("- - read previous article\n");
  360.         printf("g - go to article #\n");
  361.         printf("q - quit\n");
  362.         printf("e - exit without changing .rc file\n");
  363.         printf("s - save article in file\n");
  364.         printf("a - append article to file\n");
  365.         printf("c - mark all articles in group as read\n");
  366.         printf("P - go to previous newsgroup\n");
  367.         printf("N - go to next newsgroup\n");
  368.         printf("G - go to specified new group \n");
  369.         printf("L - list news groups subscribed to \n");
  370.         printf("i - list index \n");
  371.         printf("I - list index with keyword\n");
  372.         printf("X - toggle reading cross posts\n");
  373.         printf("Z - toggle reading already read groups\n");
  374.         printf("F or f - followup, [F includes text] \n");
  375.         printf("M or m - send mail, [M includes text] \n");
  376.         printf("S - Subscribe to new group\n");
  377.         printf("U - unsubscribe current group\n");
  378.         break;
  379.         case 'q':
  380.         return;
  381.         case 'X':
  382.         noxpost ^= 1;
  383.         if (noxpost)
  384.             printf("No cross posts\n");
  385.         else
  386.             printf("Read cross posts\n");
  387.         break;
  388.         case 'Z':
  389.         skipalready ^= 1;
  390.         if (skipalready)
  391.             printf("Skip already read groups\n");
  392.         else
  393.             printf("Don't skip already read groups\n");
  394.         nug++;
  395.         continue;
  396.         case 'e':
  397.         qexit(1);
  398.         case 'y':
  399.         case '\r':
  400.         strncpy(buf, cur_subject, 80);
  401.         buf[80] = 0;
  402.         do {
  403.             clearscreen();
  404.             printf("****** (%U/%U) [%s]******\n%s\n(%s)    %s\n\n",
  405.             cur_article, cur_last, groups[cur_group], buf, cur_from,
  406.                cur_date);
  407.             follow_up_article = cur_article;
  408.         } while ((oldquery = showbody()) == 'a');
  409.         if (oldquery == 'q' || oldquery < 0 ||
  410.             (oldquery == '\r' && cur_article == cur_last))
  411.             oldquery = 0;
  412.         firsts[cug] = cur_article + 1;
  413.         continue;
  414.         case 's':
  415.         case 'a':
  416.         if (follow_up_article == 0xffffffff) {
  417.             printf("Not on an article\n");
  418.         } else {
  419.                     save_article = cur_article;
  420.             cstat(follow_up_article);
  421.             chead();
  422.             (void) savebody(ch == 'a' ? 1 : 0);
  423.                     cur_article = save_article;
  424.             cstat(cur_article);
  425.             chead();
  426.             if(firsts[cug] == cur_last + 1)skipgroup = 2;
  427.         }
  428.         break;
  429.         case 'c':
  430.         firsts[cug] = cur_last + 1;
  431.         cug++;
  432.         nug++;
  433.         continue;
  434.         case 'P':
  435.         cug--;
  436.         nug++;
  437.         continue;
  438.         case 'N':
  439.         cug++;
  440.         nug++;
  441.         continue;
  442.         case '-':
  443.         case '=':
  444.         if (follow_up_article != 0xffffffff) {
  445.             if (ch == '-') {
  446.             if (cur_first != follow_up_article)
  447.                 noquery = 1;
  448.             if (follow_up_article > cur_first)
  449.                 firsts[cug]
  450.                 = follow_up_article - 1;
  451.             } else {
  452.             noquery = 1;
  453.             firsts[cug] = follow_up_article;
  454.             }
  455.             nug++;
  456.             continue;
  457.         }
  458.         printf("Not on an article\n");
  459.         break;
  460.         case 'g':
  461.         fflush(stdin);
  462.         fflush(stdout);
  463.         printf("Article number >");
  464.         fgets(buf, 20, stdin);
  465.         sscanf(buf, "%U", <emp);
  466.         if ((ltemp <= cur_last)) {
  467.             firsts[cug] = ltemp;
  468.             nug++;
  469.             noquery = 1;
  470.             continue;
  471.         }
  472.         printf("[article out of range]\n");
  473.         break;
  474.         case 'S':
  475.         i = getgroup(buf);
  476.         if (i == -2)
  477.             break;
  478.         if (i != -1) {
  479.             printf("Already subscribed!!\n");
  480.         } else if ((ptr = malloc(strlen(buf) + 1)) == NULL ||
  481.                ngroups >= NGROUPS - 2) {
  482.             printf("Out of memory\n");
  483.         } else {
  484.             groups[ngroups] = ptr;
  485.             ptr = buf;
  486.             while (*ptr == ' ')
  487.             ptr++;
  488.             strcpy(groups[ngroups], ptr);
  489.             firsts[ngroups] = 1;
  490.             cug = ngroups++;
  491.             cur_group = -1;
  492.             groups[ngroups] = NULL;
  493.             nug++;
  494.             continue;
  495.         }
  496.         break;
  497.         case 'U':
  498.         if (ngroups <= 2) {
  499.             printf("too few groups to delete one\n");
  500.             break;
  501.         }
  502.         groups[cur_group] = NULL;
  503.         firsts[cur_group] = 0;
  504.         compactgroups();
  505.         cug++;
  506.         nug++;
  507.         cur_group = -1;
  508.         if (cug >= ngroups)
  509.             cug = ngroups - 1;
  510.         continue;
  511.         case 'G':
  512.         i = getgroup(buf);
  513.         if (i == -2)
  514.             break;
  515.         if (i != -1) {
  516.             cug = i;
  517.             nug++;
  518.             continue;
  519.         }
  520.         printf("group not found");
  521.         break;
  522.         case 'i':
  523.         case 'I':
  524.         showindex((ch == 'I') ? 1 : 0);
  525.         if (chead())
  526.             continue;
  527.         break;
  528.         case 'L':
  529.         listgroups();
  530.         break;
  531.         case 'F':
  532.         case 'f':
  533.         case 'M':
  534.         case 'm':
  535.         if (follow_up_article == 0xffffffff) {
  536.             printf("Not on an article\n");
  537.         } else {
  538.                     save_article = cur_article;
  539.             cstat(follow_up_article);
  540.             chead();
  541.             if (!getpost(ch)) {
  542.             errno = 0;
  543.             i = spawnl(P_WAIT, editorpath,
  544.                    editorpath, tmpfil,
  545.                    NULL);
  546.             if (i)
  547.                 printf("error number from spawn = %d\n",
  548.                    errno);
  549.             printf("Type y to actually %s article\n",
  550.                    (ch == 'M' || ch == 'm') ? "mail" : "post");
  551.             if ((i = ngetc()) == 'y' || i == 'Y') {
  552.                 /* postnews(); */
  553.  
  554.                 strcpy(buf, tmpdir);
  555.                 if (ch == 'M' || ch == 'm')
  556.                 strcat(buf, "sendmail.lst");
  557.                 else
  558.                 strcat(buf, "postnews.lst");
  559.  
  560.                 qfile = fopen(buf, "a");
  561.                 if (!qfile) {
  562.                 printf("failed\n");
  563.                 } else {
  564.                 ifile = NULL;
  565.                 strcpy(buf, tmpfil);
  566.                 xtime = time(NULL) & 4194303l;
  567.                 do {
  568.                     xtime++;
  569.                     if (ifile)
  570.                     fclose(ifile);
  571.                     sprintf(tmpfil, "%sx%ld.nuz", tmpdir, xtime);
  572.                 } while (ifile = fopen(tmpfil, "r"));
  573.                 rename(buf, tmpfil);
  574.                 fprintf(qfile, "%s\n", tmpfil);
  575.                 fclose(qfile);
  576.                 }
  577.             } else
  578.                 remove(tmpfil);
  579.             }
  580.                     cur_article = save_article;
  581.             cstat(cur_article);
  582.             chead();
  583.             if(firsts[cug] == cur_last + 1)skipgroup = 2;
  584.         }
  585.         break;
  586.         default:
  587.         printf("[illegal command, try ?]\n");
  588.         break;
  589.         }
  590.     }
  591.     goto query;
  592.     }
  593. }
  594.  
  595. void
  596. getserv(char *b, int sb)
  597. {
  598. char           *p = b;
  599.     sb--;
  600.     while (sb > 0) {
  601.     while (!servf) {
  602.         servp = servb;
  603.         servf = tcpread(serverfd, servb, sizeof servb);
  604.     }
  605.     if (*servp == '\n') {
  606.         *b++ = 0;
  607.         servp++, servf--;
  608.         break;
  609.     } else if (*servp == '\r')
  610.         servp++, servf--;
  611.     else
  612.         *b++ = *servp++, servf--;
  613.     }
  614. }
  615. void
  616. putserv(char *b)
  617. {
  618.     tcpwrite(serverfd, b, strlen(b));
  619. }
  620.  
  621. void 
  622. compactgroups()
  623. {
  624. int             i;
  625.     for (i = 0; i < ngroups; i++)
  626.     if (groups[i] == NULL)
  627.         break;
  628.     if (i != ngroups - 1) {
  629.     for (i++; i < ngroups; i++) {
  630.         groups[i - 1] = groups[i];
  631.         firsts[i - 1] = firsts[i];
  632.     }
  633.     }
  634.     ngroups--;
  635. }
  636.  
  637. void
  638. getnewsrc(void)
  639. {
  640. char            group[STRING];
  641. unsigned long   first;
  642. int             i;
  643. char           *ptr, *ptr2;
  644. FILE           *rec;
  645.  
  646.     rec = fopen(newsrc, "r");
  647.     if (!rec) {
  648.     perror(newsrc);
  649.     exit(1);
  650.     }
  651.     i = 0;
  652.     while ((i < NGROUPS) && (fscanf(rec, "%s %U", group, &first) == 2)) {
  653.     ptr2 = group;
  654.     while (*ptr2 == ' ')
  655.         ptr2++;
  656.     ptr = malloc(strlen(ptr2) + 1);
  657.     if (!ptr) {
  658.         printf("Out of memory for groups\n");
  659.         break;
  660.     }
  661.     groups[i] = strcpy(ptr, ptr2);
  662.     firsts[i] = first;
  663.     i++;
  664.     }
  665.     ngroups = i;
  666. }
  667.  
  668. void 
  669. dumpnewsrc(void)
  670. {
  671. int             i;
  672. FILE           *rec;
  673.  
  674.     rec = fopen(newsrc, "w");
  675.     for (i = 0; i < ngroups; i++)
  676.     if (groups[i])
  677.         fprintf(rec, "%s %U\n", groups[i], firsts[i]);
  678.     fclose(rec);
  679. }
  680.  
  681. int
  682. cgroup(char *s)
  683. {
  684. char            buf[STRING];
  685.  
  686.     sprintf(buf, "GROUP %s\n", s);
  687.     putserv(buf);
  688.     getserv(buf, sizeof buf);
  689.     sscanf(buf, "%d %U", &reply, &reparticle);
  690.     if (reply == 411)
  691.     return -1;
  692.     else if (reply == 211) {
  693.     sscanf(buf, "%d %U %U %U %s",
  694.            &reply, &cur_numa, &cur_first, &cur_last, cur_gname);
  695.     return 0;
  696.     } else
  697.     printf("cgroup: %s\n", buf);
  698.     return -1;
  699. }
  700.  
  701. cstat(i)
  702.     unsigned long   i;
  703. {
  704. char            buf[STRING], *p, *q;
  705.  
  706.     sprintf(buf, "STAT %U\n", i);
  707.     putserv(buf);
  708.     getserv(buf, sizeof buf);
  709.     sscanf(buf, "%d %U", &reply, &reparticle);
  710.     if (reply == 423)
  711.     return -1;
  712.     else if (reply == 223) {
  713.     cur_article = reparticle;
  714.     p = buf;
  715.     q = cur_articleid;
  716.     while ((p < buf + STRING - 2) && (*p != '<'))
  717.         p++;
  718.     while ((p < buf + STRING - 2) && (*p != '>'))
  719.         *q++ = *p++;
  720.     *q++ = '>';
  721.     *q++ = '\0';
  722.     return 0;
  723.     } else
  724.     printf("cstat: %s\n", buf);
  725.     return -1;
  726. }
  727.  
  728. #if 0
  729. int
  730. current(void)
  731. {
  732. char            buf[STRING], *p, *q;
  733.  
  734.     sprintf(buf, "STAT\n");
  735.     putserv(buf);
  736.     getserv(buf, sizeof buf);
  737.     sscanf(buf, "%d %U", &reply, &reparticle);
  738.     if (reply == 423)
  739.     return -1;
  740.     else if (reply == 412)
  741.     return -1;
  742.     else if (reply == 223) {
  743.     cur_article = reparticle;
  744.     p = buf;
  745.     q = cur_articleid;
  746.     while ((p < buf + STRING - 2) && (*p != '<'))
  747.         p++;
  748.     while ((p < buf + STRING - 2) && (*p != '>'))
  749.         *q++ = *p++;
  750.     *q++ = '>';
  751.     *q++ = '\0';
  752.     return 0;
  753.     } else
  754.     printf("current: %s\n", buf);
  755.     return -1;
  756. }
  757. #endif
  758.  
  759. int
  760. cnext(void)
  761. {
  762. char            buf[STRING], *p, *q;
  763.  
  764.     sprintf(buf, "NEXT\n");
  765.     putserv(buf);
  766.     getserv(buf, sizeof buf);
  767.     sscanf(buf, "%d %U", &reply, &reparticle);
  768.     if (reply == 421)
  769.     return -1;
  770.     else if (reply == 223) {
  771.     cur_article = reparticle;
  772.     p = buf;
  773.     q = cur_articleid;
  774.     while ((p < buf + STRING - 2) && (*p != '<'))
  775.         p++;
  776.     while ((p < buf + STRING - 2) && (*p != '>'))
  777.         *q++ = *p++;
  778.     *q++ = '>';
  779.     *q++ = '\0';
  780.     return 0;
  781.     } else
  782.     printf("cnext: %s\n", buf);
  783.     return -1;
  784. }
  785.  
  786. int
  787. extract(char *to, char *key, char *from)
  788. {
  789.     if (!strncmp(from, key, strlen(key))) {
  790.     from += strlen(key);
  791.     while (*from == ' ')
  792.         from++;
  793.     strcpy(to, from);
  794.     return 1;
  795.     } else
  796.     return 0;
  797. }
  798.  
  799. chead()
  800. {
  801. char            buf[STRING];
  802.  
  803.     *cur_path = 0;
  804.     *cur_from = 0;
  805.     *cur_replyto = 0;
  806.     *cur_subject = 0;
  807.     *cur_newsgroups = 0;
  808.     *cur_message_ID = 0;
  809.     *cur_references = 0;
  810.     *cur_date = 0;
  811.  
  812.     sprintf(buf, "HEAD %U\n", cur_article);
  813.     putserv(buf);
  814.     getserv(buf, sizeof buf);
  815.     sscanf(buf, "%d %U", &reply, &reparticle);
  816.     if (reply == 423)
  817.     return -1;
  818.     else if (reply == 221)
  819.     while (1) {
  820.         getserv(buf, sizeof buf);
  821.         if (!strcmp(buf, ".")) {
  822.         if (!*cur_replyto)
  823.             strcpy(cur_replyto, cur_from);
  824.         return 0;
  825.         }
  826.         extract(cur_path, "Path:", buf) ||
  827.         extract(cur_from, "From:", buf) ||
  828.         extract(cur_subject, "Subject:", buf) ||
  829.         extract(cur_replyto, "Reply-To:", buf) ||
  830.         extract(cur_newsgroups, "Newsgroups:", buf) ||
  831.         extract(cur_message_ID, "Message-ID:", buf) ||
  832.         extract(cur_references, "References:", buf) ||
  833.         extract(cur_date, "Date:", buf);
  834.     } else
  835.     printf("chead: %s\n", buf);
  836.     return -1;
  837. }
  838. int
  839. showbody(void)
  840. {
  841. char            buf[STRING];
  842. int             line = 0;
  843. int             ch;
  844.  
  845.     sprintf(buf, "BODY %U\n", cur_article);
  846.     putserv(buf);
  847.     getserv(buf, sizeof buf);
  848.     sscanf(buf, "%d %U", &reply, &reparticle);
  849.     if (reply == 423)
  850.     return -1;
  851.     else if (reply == 222)
  852.     while (1) {
  853.         if (line == 18) {
  854.         reversevideo("more(<SPACE> to continue)?");
  855.         fflush(stdout);
  856.         ch = ngetc();
  857.         if (ch != ' ') {
  858.             while (getserv(buf, sizeof buf), strcmp(buf, "."));
  859.             normalvideo();
  860.             return ch;
  861.         }
  862.         backline();
  863.         line = 0;
  864.         }
  865.         getserv(buf, sizeof buf);
  866.         if (strcmp(buf, ".")) {
  867.     /*    printf("%s", buf); */
  868.                 fputs(buf,stdout);
  869.         if (strlen(buf) != 80)
  870.             printf("\n");
  871.         } else {
  872.         reversevideo(" End of article ");
  873.         printf("\n");
  874.         normalvideo();
  875.         return 0;
  876.         }
  877.         line++;
  878.     } else
  879.     printf("showbody: %d %s\n", reply, buf);
  880.     return -1;
  881. }
  882.  
  883. int
  884. savebody(int type)
  885. {
  886. char            buf[STRING];
  887. FILE           *f;
  888. char            sss[72];
  889. char           *s, *ss;
  890.  
  891.  
  892.     s = &sss[0];
  893.     fflush(stdin);
  894.     fflush(stdout);
  895.     printf("Filename >");
  896.     fgets(s, 70, stdin);
  897.  
  898.     sss[71] = '\n';
  899.     while (*s == ' ')
  900.     s++;
  901.     ss = s;
  902.     while (*ss != '\n')
  903.     ss++;
  904.     *ss = 0;
  905.     if (!(f = fopen(s, type ? "a" : "w"))) {
  906.     perror(s);
  907.     return -1;
  908.     }
  909.     sprintf(buf, "BODY %U\n", cur_article);
  910.     putserv(buf);
  911.     getserv(buf, sizeof buf);
  912.     sscanf(buf, "%d %U", &reply, &reparticle);
  913.     if (reply == 423)
  914.     goto badsave;
  915.     else if (reply == 222) {
  916.     fprintf(f, "Subject: %s\n", cur_subject);
  917.     fprintf(f, "From: %s\n", cur_from);
  918.     fprintf(f, "Path: %s\n", cur_path);
  919.     fprintf(f, "Reply-To: %s\n", cur_replyto);
  920.     fprintf(f, "Newsgroups: %s\n", cur_newsgroups);
  921.     fprintf(f, "Message-ID: %s\n", cur_message_ID);
  922.     fprintf(f, "References: %s\n", cur_references);
  923.     fprintf(f, "Date: %s\n", cur_date);
  924.     fprintf(f, "\n");
  925.     while (1) {
  926.         getserv(buf, sizeof buf);
  927.         if (strcmp(buf, "."))
  928.         fprintf(f, "%s\n", buf);
  929.         else
  930.         break;
  931.     }
  932.     fclose(f);
  933.     return 0;
  934.     } else
  935.     printf("savebody: %d %s\n", reply, buf);
  936. badsave:
  937.     fclose(f);
  938.     return -1;
  939. }
  940.  
  941. int
  942. saveactive(char *s)
  943. {
  944. char            buf[256];
  945. FILE           *f;
  946.  
  947.     if (!(f = fopen(s, "w"))) {
  948.     perror(s);
  949.     return -1;
  950.     }
  951.     sprintf(buf, "LIST\n");
  952.     putserv(buf);
  953.     getserv(buf, sizeof buf);
  954.     sscanf(buf, "%d %U", &reply, &reparticle);
  955.     if (reply == 215) {
  956.     while (1) {
  957. char            group[256];
  958. unsigned long   to, from;
  959. char            act;
  960.  
  961.         getserv(buf, sizeof buf);
  962.         if (!strcmp(buf, "."))
  963.         break;
  964.         sscanf(buf, "%s %U %U %c", group, &to, &from, &act);
  965.         fprintf(f, "%s %U\n", group, to);
  966.     }
  967.     fclose(f);
  968.     return 0;
  969.     } else
  970.     printf("saveactive: %d %s\n", reply, buf);
  971.     fclose(f);
  972.     return -1;
  973. }
  974.  
  975. int
  976. netsocket(void)
  977. {
  978. int             fd;
  979.  
  980.     if ((fd = tcpopen(serverhost, 119)) < 0) {
  981.     fprintf(stderr, "tcpopen failed\n");
  982.     exit(9);
  983.     }
  984.     return (fd);
  985. }
  986.  
  987. int
  988. getgroup(char *buf)
  989. {
  990. char           *s, *ss;
  991. int             i;
  992.  
  993.     fflush(stdin);
  994.     fflush(stdout);
  995.     printf("New group >");
  996.     fgets(buf, 70, stdin);
  997.     if (*buf == 0 || *buf == '\n')
  998.     return -2;
  999.  
  1000.     s = &buf[0];
  1001.  
  1002.     buf[71] = '\n';
  1003.     while (*s == ' ')
  1004.     s++;
  1005.     ss = s;
  1006.     while (*ss != '\n')
  1007.     ss++;
  1008.     *ss = 0;
  1009.  
  1010.     for (i = 0; i < ngroups; i++) {
  1011.     if (!strcmp(s, groups[i]))
  1012.         return i;
  1013.     }
  1014.     return -1;
  1015. }
  1016.  
  1017. void
  1018. listgroups(void)
  1019. {
  1020. int             line = 0;
  1021. int             ch, i;
  1022.  
  1023.     printf("\n\n");
  1024.     for (i = 0; i < ngroups; i++) {
  1025.     if (line == 18) {
  1026.         reversevideo("more(<RETURN> or <SPACE> to continue, q or . to quit)?");
  1027.         fflush(stdout);
  1028.         ch = ngetc();
  1029.         if (ch == 'q' || ch == '.') {
  1030.         normalvideo();
  1031.         return;
  1032.         }
  1033.         backline();
  1034.         line = 0;
  1035.     }
  1036.     printf(" %s   %U\n", groups[i], firsts[i]);
  1037.     line++;
  1038.     }
  1039. }
  1040.  
  1041. int
  1042. showindex(int flag)
  1043. {
  1044. char            buf[80], test_string[80], test_string2[150];
  1045. int             line = 0;
  1046. int             ch, i, j;
  1047. unsigned long   save_article;
  1048.  
  1049.     if (flag) {
  1050.     printf("Enter matching string: ");
  1051.     fgets(test_string, 78, stdin);
  1052.     for (i = 0; test_string[i] != 0; i++) {
  1053.         if (test_string[i] == '\n')
  1054.         test_string[i] = 0;
  1055.         if (test_string[i] >= 'a' && test_string[i] <= 'z')
  1056.         test_string[i] -= 'a' - 'A';
  1057.     }
  1058.     }
  1059.     save_article = cur_article;
  1060.     if (cur_article < cur_first)
  1061.     cur_article = cur_first;
  1062.     printf("\n\n");
  1063.     for (; cur_article <= cur_last; cur_article++) {
  1064.     if (line == 18) {
  1065.         reversevideo("more(<RETURN> or <SPACE> to continue, q or . to quit)?");
  1066.         fflush(stdout);
  1067.         ch = ngetc();
  1068.         if (ch == 'q' || ch == '.') {
  1069.         cur_article = save_article;
  1070.         normalvideo();
  1071.         return 0;
  1072.         }
  1073.         backline();
  1074.         line = 0;
  1075.     }
  1076.     if (chead())
  1077.         continue;
  1078.     strncpy(buf, cur_subject, 70);
  1079.     buf[70] = 0;
  1080.  
  1081.  
  1082.     if (flag) {
  1083.         strcpy(test_string2, buf);
  1084.         strncat(test_string2, cur_from, 70);
  1085.         for (j = 0; j < 145 && test_string2[j] != 0; j++) {
  1086.         if (test_string2[j] >= 'a' && test_string2[j] <= 'z')
  1087.             test_string2[j] -= 'a' - 'A';
  1088.         }
  1089.     }
  1090.     test_string2[j] = 0;
  1091.     if (!flag || strstr(test_string2, test_string)) {
  1092.         printf("%U%c %s\n",
  1093.            cur_article, checkx() ? '*' : ' ', buf);
  1094.         fflush(stdout);
  1095.         line++;
  1096.     }
  1097.     }
  1098.     cur_article = save_article;
  1099.     return 0;
  1100. }
  1101.  
  1102. int
  1103. getpost(int f)
  1104. {
  1105.  
  1106. char            buf[STRING];
  1107. FILE           *ifile = NULL;
  1108.  
  1109.     sprintf(tmpfil, "%stmp.nuz", tmpdir);
  1110.  
  1111.     ifile = fopen(tmpfil, "w");
  1112.     if (!ifile) {
  1113.     printf("Can't open temporary file \n");
  1114.     return 1;
  1115.     }
  1116.     fprintf(ifile, "From: %s\n", fromline);
  1117.     if (f == 'm' || f == 'M') {
  1118.     fprintf(ifile, "To: %s\n", (cur_replyto != NULL) ?
  1119.         cur_replyto : cur_from);
  1120.     }
  1121.     if (!strncmp(cur_subject, "Re:", 3))
  1122.     fprintf(ifile, "Subject: %s\n", cur_subject);
  1123.     else
  1124.     fprintf(ifile, "Subject: Re: %s\n", cur_subject);
  1125.  
  1126.     if (f == 'f' || f == 'F') {
  1127.     fprintf(ifile, "Newsgroups: %s\n", cur_newsgroups);
  1128.     fprintf(ifile, "Summary: \nFollowup-To: \nDistribution: \n");
  1129.     /* fprintf(ifile, "Date: %s\n", cur_date); */
  1130.     fprintf(ifile, "References: %s", cur_message_ID);
  1131.     if (cur_references)
  1132.         fprintf(ifile, " %s", cur_references);
  1133.     fprintf(ifile, "\n");
  1134.     }
  1135.     fprintf(ifile, "\n\n");
  1136.  
  1137.  
  1138.     if (f == 'F' || f == 'M') {
  1139.     fprintf(ifile, "In article %s %s writes:\n", cur_message_ID, cur_from);
  1140.  
  1141.     sprintf(buf, "BODY %U\n", cur_article);
  1142.     putserv(buf);
  1143.     getserv(buf, sizeof buf);
  1144.     sscanf(buf, "%d %U", &reply, &reparticle);
  1145.     if (reply == 222) {
  1146.         while (1) {
  1147.         getserv(buf, sizeof buf);
  1148.         if (strcmp(buf, ".")) {
  1149.             fprintf(ifile, ">%s\n", buf);
  1150.         } else
  1151.             break;
  1152.         }
  1153.     } else {
  1154.         printf("savebody error: %d %s\n", reply, buf);
  1155.         fclose(ifile);
  1156.         return 1;
  1157.     }
  1158.     }
  1159.     fclose(ifile);
  1160.     return 0;
  1161. }
  1162.  
  1163.  
  1164. int
  1165. postnews(void)
  1166. {
  1167.  
  1168. char            buf[STRING], s[STRING], fbuf[128];
  1169. int             seen_fromline, in_header, seen_header;
  1170. FILE           *ifile, *pfile;
  1171. char           *cp, *bp;
  1172. int             count, i;
  1173.  
  1174.  
  1175.     strcpy(fbuf, tmpdir);
  1176.     strcat(fbuf, "postnews.lst");
  1177.     pfile = fopen(fbuf, "r");
  1178.     if (!pfile) {
  1179.     printf("No News to post\n");
  1180.     return 1;
  1181.     } else
  1182.     printf("Now trying to post your News\n");
  1183.  
  1184.     while (1) {
  1185.     if (fgets(fbuf, 126, pfile) == NULL)
  1186.         break;
  1187.     for (i = 0; fbuf[i]; i++)
  1188.         if (fbuf[i] == '\n')
  1189.         fbuf[i] = 0;
  1190.  
  1191.     ifile = fopen(fbuf, "r");
  1192.     if (!ifile) {
  1193.         printf("Can't open temporary file %s\n", fbuf);
  1194.         continue;
  1195.     }
  1196.     putserv("POST\n");
  1197.     getserv(buf, sizeof buf);
  1198.     if (*buf != '3') {
  1199.         if (atoi(buf) == 440) {
  1200.         printf("No posting!\n");
  1201.         } else {
  1202.         printf("Remote error: %s\n", buf);
  1203.         }
  1204.         fclose(pfile);
  1205.         fclose(ifile);
  1206.         return 0;
  1207.     }
  1208.     printf("Sending file\n");
  1209.  
  1210.     in_header = 1;
  1211.     seen_header = 0;
  1212.     seen_fromline = 0;
  1213.  
  1214.  
  1215.     count = 0;
  1216.     bp = buf;
  1217.     while (fgets(s, 510, ifile) != NULL) {
  1218.         s[511] = '\n';
  1219.         cp = s;
  1220.         while (*cp != '\n')
  1221.         cp++;
  1222.         *cp = 0;
  1223.         if (s[0] == '.') {    /* Single . is eof, so put in extra one */
  1224.         *bp++ = '.';
  1225.         if (++count == 512) {
  1226.             tcpwrite(serverfd, buf, 512);
  1227.             usleep();
  1228.             /*
  1229.              * Note on all these 'usleep' calls: Without them this
  1230.              * program crashes our Proteon fiber-optic network
  1231.              * gateway. It is known that this gateway has software
  1232.              * problems. They promise to fix it 'real soon now'. But
  1233.              * on the other hand no other computer crashes is, nor
  1234.              * does NCSA Telnet or NCSA FTP used on my very own PC.
  1235.              * So this appears to be a terrible kludge.
  1236.              */
  1237.             count = 0;
  1238.             bp = buf;
  1239.         }
  1240.         }
  1241.         if (in_header && !strnicmp(s, "From:", sizeof("From:") - 1)) {
  1242.         seen_header = 1;
  1243.         seen_fromline = 1;
  1244.         }
  1245.         if (in_header && s[0] == '\0') {
  1246.         if (seen_header) {
  1247.             in_header = 0;
  1248.             if (!seen_fromline) {
  1249.             strcpy(s, "From: ");
  1250.             strcpy(s, fromline);
  1251.             strcat(s, "\r\n");
  1252.             }
  1253.         } else {
  1254.             continue;
  1255.         }
  1256.         } else if (in_header) {
  1257.         if (valid_header(s))
  1258.             seen_header = 1;
  1259.         else
  1260.             continue;
  1261.         }
  1262.         cp = s;
  1263.         while (*cp) {
  1264.         *bp++ = *cp++;
  1265.         if (++count == 512) {
  1266.             tcpwrite(serverfd, buf, 512);
  1267.             usleep();
  1268.             count = 0;
  1269.             bp = buf;
  1270.         }
  1271.         }
  1272.         cp = "\r\n";
  1273.         while (*cp) {
  1274.         *bp++ = *cp++;
  1275.         if (++count == 512) {
  1276.             tcpwrite(serverfd, buf, 512);
  1277.             usleep();
  1278.             count = 0;
  1279.             bp = buf;
  1280.         }
  1281.         }
  1282.     }
  1283.  
  1284.     fclose(ifile);
  1285.  
  1286.     cp = ".\r\n";
  1287.     while (*cp) {
  1288.         *bp++ = *cp++;
  1289.         if (++count == 512) {
  1290.         tcpwrite(serverfd, buf, 512);
  1291.         usleep();
  1292.         count = 0;
  1293.         bp = buf;
  1294.         }
  1295.     }
  1296.  
  1297.     if (count) {
  1298.         tcpwrite(serverfd, buf, count);
  1299.         usleep();
  1300.     }
  1301.     printf("waiting for reply\n");
  1302.     (void) getserv(buf, sizeof(buf));
  1303.     printf("got reply\n");
  1304.     if (*buf != '2') {
  1305.         if (atoi(buf) == 441) {
  1306.         printf("Article not accepted by server; not post*ed.\n");
  1307.         for (cp = buf + 4; *cp && *cp != '\r'; cp++)
  1308.             if (*cp == '\\')
  1309.             putchar('\n');
  1310.             else
  1311.             putchar(*cp);
  1312.         fclose(pfile);
  1313.         return 0;
  1314.         } else {
  1315.         printf("Remote error: %s\n", buf);
  1316.         fclose(pfile);
  1317.         return 0;
  1318.         }
  1319.     }
  1320.     remove(fbuf);
  1321.     }
  1322.     strcpy(fbuf, tmpdir);
  1323.     strcat(fbuf, "postnews.lst");
  1324.     remove(fbuf);
  1325.     return 0;
  1326. }
  1327.  
  1328.  
  1329.  
  1330.  
  1331. int
  1332. valid_header(char *h)
  1333. {
  1334. char           *colon, *space;
  1335.  
  1336.     /*
  1337.      * blank or tab in first position implies this is a continuation header
  1338.      */
  1339.     if (h[0] == ' ' || h[0] == '\t')
  1340.     return (1);
  1341.  
  1342.     /*
  1343.      * just check for initial letter, colon, and space to make sure we
  1344.      * discard only invalid headers
  1345.      */
  1346.     colon = strchr(h, ':');
  1347.     space = strchr(h, ' ');
  1348.     if (isalpha(h[0]) && colon && space == colon + 1)
  1349.     return (1);
  1350.  
  1351.     /*
  1352.      * anything else is a bad header -- it should be ignored
  1353.      */
  1354.     return (0);
  1355. }
  1356.  
  1357.  
  1358.  
  1359. void
  1360. qexit(int n)
  1361. {
  1362. char            buf[512];
  1363.  
  1364.     if (n >= 10)
  1365.     printf("Horrible error: read manual \n");
  1366.     fflush(stdout);
  1367.     putserv("QUIT\n");
  1368.     getserv(buf, sizeof buf);
  1369.     if (*buf != '2')
  1370.     printf("Tried to quit, but failed\n");
  1371.     if (n)
  1372.     exit(n);
  1373. }
  1374.  
  1375.  
  1376. int
  1377. checkx(void)
  1378. {
  1379. char            buf[256];
  1380. int             i, k;
  1381. char           *ptr, *ptr2, *ptr3;
  1382.  
  1383.     if (cur_group == 0)
  1384.     return 0;
  1385.     ptr = cur_newsgroups;
  1386.     while (*ptr == ' ')
  1387.     ptr++;
  1388.     k = 0;
  1389.     while (1) {
  1390.     if (*ptr == 0)
  1391.         break;
  1392.     if (*ptr == ',')
  1393.         ptr++;
  1394.     while (*ptr == ' ')
  1395.         ptr++;
  1396.     ptr2 = ptr;
  1397.     ptr3 = buf;
  1398.     while (*ptr2 != 0 && *ptr2 != ',')
  1399.         *ptr3++ = *ptr2++;
  1400.     *ptr3 = 0;
  1401.     while (*(--ptr3) == ' ')
  1402.         *ptr3 = 0;
  1403.     ptr = ptr2;
  1404.     for (i = 0; i < cur_group; i++) {
  1405.         if (strcmp(buf, groups[i]) == 0)
  1406.         return 1;
  1407.     }
  1408.     }
  1409.     return 0;
  1410. }
  1411. void
  1412. sendmail()
  1413. {
  1414. char            buf[128];
  1415. FILE           *mfile;
  1416. int             i;
  1417.  
  1418.     strcpy(buf, tmpdir);
  1419.     strcat(buf, "sendmail.lst");
  1420.  
  1421.     mfile = fopen(buf, "r");
  1422.     fclose(mfile);
  1423.  
  1424.     if (mfile != NULL) {
  1425.     printf("Sending mail\n");
  1426.     for (i = 0; i < 10; i++)
  1427.         usleep();
  1428.     spawnl(P_OVERLAY, smtppath, smtppath, buf, serverhost, NULL);
  1429.     /* this does not normally return, but might if some spawn error */
  1430.     } else {
  1431.     printf("No mail to process\n");
  1432.     for (i = 0; i < 4; i++)
  1433.         usleep();
  1434.     }
  1435.     xabort();       /* don't do onexit processing, we already did it */
  1436. }
  1437.