home *** CD-ROM | disk | FTP | other *** search
/ rtsi.com / 2014.01.www.rtsi.com.tar / www.rtsi.com / OS9 / OSK / TELECOM / UUCPBB21 / uucpbb21.lzh / UUCPBB21 / readnews.c < prev    next >
Text File  |  1994-09-25  |  45KB  |  1,518 lines

  1. /*  readnews.c   The main program to read Usenet news.
  2.     Copyright (C) 1990, 1993  Rick Adams and Bob Billson
  3.  
  4.     This file is part of the OS-9 UUCP package, UUCPbb.
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  19.  
  20.     The author of UUCPbb, Bob Billson, can be contacted at:
  21.     bob@kc2wz.bubble.org  or  uunet!kc2wz!bob  or  by snail mail:
  22.     21 Bates Way, Westfield, NJ 07090
  23. */
  24.  
  25. #define MAIN
  26.  
  27. #include "uucp.h"
  28. #ifndef _OSK
  29. #include <os9.h>
  30. #endif
  31. #include <ctype.h>
  32. #include <modes.h>
  33. #include <sgstat.h>
  34. #include <direct.h>
  35.  
  36. #define ON           1
  37. #define OFF          0
  38. #define MAILER     "mailx"
  39.  
  40. extern char temp[], fname[];
  41. extern QQ flag auto_rot;
  42. extern QQ unsigned myuid;
  43.  
  44. QQ FILE *log;
  45. QQ int debuglvl = 0;
  46. QQ int columns, rows, ngroups, curgroup;
  47. QQ flag rot13, valid;
  48. #ifndef TERMCAP
  49. QQ flag t2flag, winopen;
  50. #endif
  51. struct active groups[MAXNEWSGROUPS];
  52. struct Newsrc newsrc[MAXNEWSGROUPS];
  53. char article[20], reference[256], subject[256], returnpath[512];
  54. char sender[512], line[512], newsgroup[100];
  55. char *getword(), getresponse(), *getarticlepath(), *fixgroupname();
  56. char *mailer = MAILER;
  57.  
  58.  
  59. main (argc, argv)
  60. int argc;
  61. char *argv[];
  62. {
  63.      static char newsrcfile[100];
  64.      char sub;
  65.      register int i;
  66.      int count, index, j, c, interrupt();
  67.      FILE *file;
  68.  
  69.      homedir = NULL;
  70.      log = stderr;
  71.  
  72.      if (argc > 1)
  73.           usage();
  74.  
  75.      intercept (interrupt);
  76.  
  77.      if (getparam() == FALSE)
  78.           exit (0);
  79.  
  80.      userparam();
  81.  
  82.      if ((newsdir = getdirs ("newsdir")) == NULL)
  83.           fatal ("newsdir not in Parameters");
  84.  
  85. #ifndef TERMCAP
  86.      t2flag = t2test();
  87.      winopen = FALSE;
  88. #else
  89.      init_term_cap();
  90. #endif
  91.  
  92.      getscreensize();
  93.  
  94.      /* init in-core newsgroups list from active file, release active file */
  95.      if (readactive (S_IREAD|S_ISHARE) == FALSE)
  96.           exit (0);
  97.  
  98.      closeactive();
  99.  
  100.      /* init newsrc from active file info.  Handle special case of empty group
  101.         The "-1" puts the default newsrc index one below the lowest existing
  102.         article.  */
  103.  
  104.      for (i = 0; i < ngroups; i++)
  105.        {
  106.           strcpy (newsrc[i].newsgroup, groups[i].newsgroup);
  107.           newsrc[i].index = groups[i].index - 1;
  108.           newsrc[i].sub = NEWGROUP;
  109.        }
  110.  
  111.      /* Update in-core newsgroup indexes from user's newsrc for index, use
  112.         lowest avail. article # - 1 if higher than newsrc #. */
  113.  
  114. #ifdef _OSK
  115.      sprintf (newsrcfile, "%s/%s", homedir, _NEWSRC);
  116. #else
  117.      sprintf (newsrcfile, "%s/%s/%s", homedir, uudir, _NEWSRC);
  118. #endif
  119.  
  120.      if ((file = fopen (newsrcfile, "r")) != NULL)
  121.        {
  122.           while (fscanf (file, "%100[^:!]%c 1-%d ", newsgroup, &sub, &index)
  123.                     != EOF)
  124.             {
  125.                i = findgroup (newsgroup, TRUE);
  126.                strcpy (newsrc[i].newsgroup, newsgroup);
  127.                newsrc[i].index = max (index, newsrc[i].index);
  128.                newsrc[i].sub = sub;
  129.             }
  130.           fclose (file);
  131.        }
  132.      else
  133.        {
  134.           /* Silently subscribe to newsgroups if new newsrc */
  135.           for (i = 0; i < ngroups; i++)
  136.                if (findstr (1, groups[i].newsgroup, "junk") != 0)
  137.                     newsrc[i].sub = UNSUBSCRIBED;
  138.                else if (findstr (1, groups[i].newsgroup, ".test") != 0)
  139.                     newsrc[i].sub = UNSUBSCRIBED;
  140.                else
  141.                     newsrc[i].sub = SUBSCRIBED;
  142.  
  143.           /* display help file for new users */
  144.           sprintf (temp, "%s", NEWSHELP);
  145.  
  146.           if ((file = fopen (temp, "r")) != NULL)
  147.             {
  148.                putchar ('\n');
  149.  
  150.                while (fgets (line, sizeof (line), file) != NULL)
  151.                     printf ("%s", line);
  152.  
  153.                fclose ( file);
  154.                fputs ("Press any key to continue: ", stdout);
  155.                fflush (stdout);
  156.                getresponse();
  157.                puts ("\n");
  158.             }
  159.         }
  160.  
  161.      /* check for new newsgroups */
  162.      for (i = 0; i < ngroups; i++)
  163.           if (newsrc[i].sub == NEWGROUP)
  164.             {
  165.                printf ("New newsgroup: %s--Subscribe? [yn] ",
  166.                        groups[i].newsgroup);
  167.  
  168.                fflush (stdout);
  169.                sub = getresponse();
  170.                putchar ('\n');
  171.                newsrc[i].sub = (tolower(sub) == 'y') ? SUBSCRIBED
  172.                                                      : UNSUBSCRIBED;
  173.             }
  174.  
  175.      /* summary of unread news */
  176.      for (i = 0; i < ngroups; i++)
  177.           if (newsrc[i].sub == SUBSCRIBED)
  178.             {
  179.                count = groups[i].seq - newsrc[i].index;
  180.  
  181.                if (count > 0)
  182.                     printf ("Unread news in %-25s %4d articles\n",
  183.                               groups[i].newsgroup, count);
  184.             }
  185.      putchar ('\n');
  186.  
  187.      /* cycle through available newsgroups */
  188.      for (i = 0; i < ngroups; i++)
  189.        {
  190.           curgroup = i;
  191.  
  192.           if (newsrc[i].sub == SUBSCRIBED)
  193.                c = readgroup();
  194.  
  195.           switch (c)
  196.             {
  197.                case 'q':                          /* quit */
  198.                     i = ngroups;                  /* Added BRT */
  199.                     break;
  200.  
  201.                case 'p':                          /* previous newsgroup */
  202.                     for (j = i - 1; j != i; j--)
  203.                       {
  204.                          if (j < 0)
  205.                               j = ngroups - 1;
  206.  
  207.                          if (groups[j].seq > newsrc[j].index)
  208.                            {
  209.                               i -= j - 2;           /* Added BRT */
  210.                               break;
  211.                            }
  212.                       }
  213.                     break;
  214.  
  215.                default:
  216.                     i = curgroup;
  217.                     break;
  218.             }
  219.  
  220.           /* Are we done? */
  221.           if (i == ngroups - 1)
  222.             {
  223.                curgroup = ngroups;
  224.                c = readgroup();
  225.                i = curgroup;
  226.  
  227.                if (c != 'p'  &&  c != 'q'  &&  c != ' '  &&  i == ngroups)
  228.                     i = -1;
  229.  
  230.                /* If they pressed SPACE, quit if all is read */
  231.                if ((c == ' ') && (i == ngroups))
  232.                  {
  233.                     for (j = 0; j < ngroups; j++)
  234.                          if (groups[j].seq != newsrc[j].index)
  235.                               break;
  236.  
  237.                     /* Wrap if anything unread */
  238.                     if (j < ngroups)
  239.                          i = -1;
  240.                  }
  241.             }
  242.        }
  243.      cls();                                             /* Added BRT */
  244.      fputs ("updating newsrc...", stdout);
  245.      fflush (stdout);
  246.  
  247.      /* save a copy of the old newsrc file */
  248. #ifdef _OSK
  249.      sprintf (fname, "%s", homedir);
  250. #else
  251.      sprintf (fname, "%s/%s", homedir, uudir);
  252. #endif
  253.      if (chdir (fname) == -1)
  254.        {
  255.           char tmp[80];
  256.  
  257.           sprintf (tmp, "can't change to: %s\n", fname);
  258.           fatal (tmp);
  259.        }
  260. #ifndef _OSK
  261.      filemove ("newsrc", "oldnewsrc");
  262. #else
  263.      filemove (".newsrc", ".oldnewsrc");
  264. #endif
  265.  
  266.      /* so the file can be opened - BAS */
  267.      asetuid (0);
  268.  
  269.      /* update the newsrc file */
  270.      if ((file = fopen (newsrcfile, "w+")) == NULL)         /* changed BRT */
  271. #ifdef _OSK
  272.           fatal ("can't update .newsrc file");
  273. #else
  274.           fatal ("can't update newsrc file");
  275. #endif
  276.  
  277.      /* change the ownership of the file and reset uid -- BAS */
  278.      chown (newsrcfile, myuid);
  279.      asetuid (myuid);
  280.  
  281.      for (i = 0; i < ngroups; i++)
  282.           fprintf (file, "%s%c 1-%d\n",
  283.                          newsrc[i].newsgroup,
  284.                          newsrc[i].sub,
  285.                          newsrc[i].index);
  286.      fclose (file);
  287.      cls();
  288. }
  289.  
  290.  
  291.  
  292. int readgroup()
  293. {
  294.      char c, *sb, *cr, *groupname, **hptr, tmp[60];
  295.      char *ptr;                                         /* Added BTR */
  296.      register int i;
  297.      int seq, indx;
  298.      static char *help1[] = {
  299.                        "ENTER/SPACE  Read unread article",
  300.                        "c\t\tCatch-up, mark all articles read",
  301.                        "d\t\tDirectory of groups",
  302.                        "g <group>    Goto newsgroup <group>",
  303.                        "h or ?       Help",
  304.                        "n\t\tNo, skip this group",
  305.                        "p\t\tPrevious group",
  306.                        "q\t\tQuit",
  307.                        "s <group>    Subscribe to newsgroup <group>",
  308.                        "u [<group>]  Unsubscribe from newsgroup <group>",
  309.                        "\t\t   default is current newsgroup",
  310.                        "y\t\tYes, read unread article",
  311.                        "!\t\tFork a shell",
  312.                        NULL
  313.                     },
  314.  
  315.                  *help2[] = {
  316.                        "SPACE/n/y  Start over, read new news",
  317.                        "d\t    Directory of groups",
  318.                        "g <group>  Goto newsgroup <group>",
  319.                        "h\t    Help",
  320.                        "q\t    Quit",
  321.                        "s <group>  Subscribe to the <group>",
  322.                        "u <group>  Unsubscribe from <group>",
  323.                        NULL
  324.                     };
  325.  
  326.      if (curgroup < ngroups)
  327.        {
  328.           seq = groups[curgroup].seq;
  329.           indx = newsrc[curgroup].index;
  330.        }
  331.  
  332.      c = '\0';
  333.  
  334.      while (seq > indx || curgroup == ngroups)
  335.        {
  336.           char ch, *ngrp;
  337.  
  338.           ngrp == NULL;
  339.  
  340.           if (curgroup == ngroups)
  341.             {
  342.                ReVOn();
  343.                fputs ("**** End of newsgroups [yq] ", stdout);
  344.                ReVOff();
  345.             }
  346.           else
  347.             {
  348.                ReVOn();
  349.                printf ("**** %d articles unread in newsgroup %s--read now? [yncpq] ",
  350.                        seq-indx, newsrc[curgroup].newsgroup);
  351.                ReVOff();
  352.             }
  353.  
  354.           fflush (stdout);
  355.           c = getresponse();
  356.           ch = c = tolower (c);      /* 'ch' is temp used only in switch() */
  357.  
  358.           /* Done? */
  359.           if (curgroup == ngroups)
  360.             {
  361.                if (c == 'c')
  362.                     ch = '*';                         /* Illegal command */
  363.                else if (strchr ("qyn ", c) != NULL)
  364.                  {
  365.                     putchar ('\n');
  366.                     return (c);
  367.                  }
  368.                else if (strchr ("h?", c) != NULL)
  369.                ch = 'H';                          /* Different help */
  370.                     /* Fall through for d, g, h, ?, s, u or illegal */
  371.             }
  372.  
  373.           switch (ch)
  374.             {
  375.                /* Read new articles */
  376.                case 'y':
  377.                case ' ':
  378.                case '\n':
  379.                     putchar ('\n');
  380.                     asetuid (0);
  381.  
  382.                     if (chdir (newsdir) == -1)
  383.                       {
  384.                          char tmp[80];
  385.  
  386.                          sprintf (tmp, "readgroup() can't change to: %s\n",
  387.                                         newsdir);
  388.                          fatal (tmp);
  389.                       }
  390.  
  391.                     asetuid (myuid);
  392.                     strcpy (newsgroup, newsrc[curgroup].newsgroup);
  393.  
  394.                     if ((ngrp = fixgroupname (newsgroup)) != NULL)
  395.                       {
  396.                          makepath (ngrp);
  397.  
  398.                          if (ngrp != NULL)
  399.                            {
  400.                               free (ngrp);
  401.                               ngrp = NULL;
  402.                            }
  403.                          dogroup (indx, seq);
  404.                       }
  405.                     break;
  406.  
  407.                /* Catch up */
  408.                case 'c':
  409.                     puts ("\nMarking all articles as read");
  410.                     newsrc[curgroup].index = seq;
  411.                     break;
  412.  
  413.                /* Directory of all groups */
  414.                case 'd':
  415.                     puts ("\n\n   Sub  #msg  #unread  Newsgroup");
  416.  
  417.                     for (i = 0; i < ngroups; i++)
  418.                       {
  419.                          cr = (i == curgroup) ? ">" : " ";
  420.                          sb = (newsrc[i].sub == SUBSCRIBED) ? "S" : "U";
  421.                          printf ("  %s %s  %5.5d   %5.5d   %-50.50s\n",                                           cr, sb,
  422.                                    groups[i].seq - groups[i].index + 1,
  423.                                    groups[i].seq - newsrc[i].index,
  424.                                    newsrc[i].newsgroup);
  425.                       }
  426.                     break;
  427.  
  428.                /* Subscribe to given group */
  429.                case 's':
  430.                     groupname = getword();
  431.  
  432.                     if (*groupname == '\0'
  433.                          || ((i = findgroup (groupname, FALSE)) == -1))
  434.                       {
  435.                          printf ("\nGroup %s not found\n", groupname);
  436.                          break;
  437.                       }
  438.  
  439.                     if (*groupname == '\0'  &&  curgroup == ngroups)
  440.                       {
  441.                          puts ("\nNo current newsgroup");
  442.                          break;
  443.                       }
  444.  
  445.                     printf ("Subscribing to group %s\n", newsrc[i].newsgroup);
  446.                     newsrc[i].sub = SUBSCRIBED;
  447.                     break;
  448.  
  449.                /* Unsubscribe from group */
  450.                case 'u':
  451.                     groupname = getword();
  452.  
  453.                     /* unsubscribe from current newsgroup? */
  454.                     if (*groupname == '\0')
  455.                          if (curgroup == ngroups)
  456.                            {
  457.                               puts ("\nNo current newsgroup");
  458.                               break;
  459.                            }
  460.                          else
  461.                               i = curgroup;
  462.  
  463.                     /* unsubscribe from specified newsgroup?* /
  464.                     else if ((i = findgroup (groupname, FALSE)) == -1)
  465.                       {
  466.                          printf ("\nGroup %s not found\n", groupname);
  467.                          break;
  468.                       }
  469.  
  470.                     /* unsubscribe from group */
  471.                     printf ("Unsubscribing from group %s\n",
  472.                                newsrc[i].newsgroup);
  473.  
  474.                     newsrc[i].sub = UNSUBSCRIBED;
  475.  
  476.                     /* if current group, move to next group */
  477.                     if (curgroup == i)
  478.                          return ('n');
  479.  
  480.                     break;
  481.  
  482.                /* No, do not read new articles in this group */
  483.                case 'n':
  484.                case 'q':                          /* Quit */
  485.                case 'p':                          /* Previous group */
  486.                     putchar ('\n');
  487.                     return (c);
  488.  
  489.                /* Goto group ____ */
  490.                case 'g':
  491.                     groupname = getword();
  492.  
  493.                     if (*groupname == '\0' ||
  494.                           ((i = findgroup (groupname, FALSE)) == -1))
  495.                       {
  496.                          printf ("\nGroup %s not found\n", groupname);
  497.                          break;
  498.                       }
  499.  
  500.                     curgroup = i;
  501.                     seq = groups[curgroup].seq;
  502.                     indx = newsrc[curgroup].index;
  503.                     asetuid (0);
  504.  
  505.                     if (chdir (newsdir) == -1)
  506.                       {
  507.                          char tmp[80];
  508.  
  509.                          sprintf (tmp, "readgroup(): can't change to: %s\n",
  510.                                        newsdir);
  511.                          fatal (tmp);
  512.                       }
  513.                     asetuid (myuid);
  514.                     strcpy (newsgroup, newsrc[curgroup].newsgroup);
  515.  
  516.                     if ((ngrp = fixgroupname (newsgroup)) != NULL)
  517.                       {
  518.                          makepath (ngrp);
  519.  
  520.                          if (ngrp != NULL)
  521.                            {
  522.                               free (ngrp);
  523.                               ngrp = NULL;
  524.                            }
  525.                          dogroup (indx, seq);
  526.                       }
  527.                     break;
  528.  
  529.                /* Help */
  530.                case 'h':
  531.                case '?':
  532. #ifndef TERMCAP
  533.                     if (!t2flag)
  534.                       {
  535.                          popdoublewindow (29, 0, 49, 15);
  536.                          putdashs (47);
  537.                       }
  538. #endif
  539.                     putchar ('\n');
  540.  
  541.                     for (hptr = help1; *hptr != NULL;  ++hptr)
  542.                          printf (" %s\n", strdetab (strcpy (tmp, *hptr), 6));
  543.  
  544. #ifndef TERMCAP
  545.                     if (!t2flag)
  546.                       {
  547.                          putdashs (47);
  548.                          fflush (stdout);
  549.                          ch = getresponse();
  550.                          closedoublewindow();
  551.                       }
  552.                     else
  553. #endif
  554.                          putchar ('\n');
  555.                     break;
  556.  
  557.                /* Help, when at end of newsgroups */
  558.                case 'H':
  559. #ifndef TERMCAP
  560.                     if (!t2flag)
  561.                       {
  562.                          popdoublewindow (37, 0, 42, 9);
  563.                          putdashs (40);
  564.                       }
  565. #endif
  566.                     putchar ('\n');
  567.  
  568.                     for (hptr = help2; *hptr != NULL;  ++hptr)
  569.                          printf (" %s\n", strdetab (strcpy (tmp, *hptr), 6));
  570.  
  571. #ifndef TERMCAP
  572.                     if (!t2flag)
  573.                       {
  574.                          putdashs (40);
  575.                          fflush (stdout);
  576.                          ch = getresponse();
  577.                          closedoublewindow();
  578.                       }
  579.                     else
  580. #endif
  581.                          putchar ('\n');
  582.                     break;
  583.  
  584.                /* fork a shell */
  585.                case '!':
  586.                     forkshell();
  587. #ifndef TERMCAP
  588.                     if (!t2flag)
  589.                          resetline();
  590.                     break;
  591. #endif
  592.  
  593.                /* Illegal command */
  594.                default:
  595.                     printf ("\nIllegal command: %c\n", c);
  596.                     break;
  597.             }
  598.           seq = groups[curgroup].seq;
  599.           indx = newsrc[curgroup].index;
  600.        }
  601.      return (c);
  602. }
  603.  
  604.  
  605.  
  606. /* dogroup  --scan unread articles in a specific group
  607.               If all articles read, just display prompt. */
  608.  
  609. int dogroup (index, seq)
  610. int index, seq;
  611. {
  612.      register int i = index + 1;            /* Next unread article */
  613.      char c = '\0';                         /* Need a prompt in newscmd() */
  614.      char dspnews();
  615.  
  616.      /* If we got here by 'G'oto, and the group is fully read: */
  617.      if (i == seq + 1)
  618.           i = newscmd (c, seq);              /* i = 0 if Quit */
  619.  
  620.      rot13 = FALSE;
  621.  
  622.      while (i <= seq && i > 0)
  623.        {
  624.           /* display article */
  625.           if ((c = dspnews (i)) == -1)          /* If unavailable, skip to  */
  626.                if (++i <= seq)                  /* next.  When group empty, */
  627.                     continue;                   /* force prompt.  */
  628.  
  629.           newsrc[curgroup].index = max (i, newsrc[curgroup].index);
  630.           rot13 = FALSE;
  631.           i = newscmd (c, i);                           /* i = 0 if Quit */
  632.  
  633.           /* in case new articles posted in newscmd */
  634.           seq = groups[curgroup].seq;
  635.  
  636.           if (i == 0)
  637.                break;
  638.        }
  639. }
  640.  
  641.  
  642.  
  643. char dspnews (artnum)
  644. int artnum;
  645. {
  646.      register char *lp;
  647.      int screenline, k;
  648.      flag go_on, header;
  649.      char **hptr, tmp[60];
  650.      static char ref2[256];
  651.      FILE *file;
  652.      static char *help[] = {
  653.                      "SPACE     Show next screen",
  654.                      "n\t  Next article",
  655.                      "c\t  Catch-up",
  656.                      "p\t  Previous article",
  657.                      "s <file>  Save article to <file>",
  658.                      "w <file>  Save article to <file>",
  659.                      "\t     without header",
  660.                      "v or .    Redisplay current article",
  661.                      "u\t  Redisplay current article,",
  662.                      "\t     rot13'd (unrot)",
  663.                      "q\t  Quit displaying article", 
  664.                      "h or ?    Help",
  665.                      NULL
  666.                   };
  667.  
  668.      sprintf (article, "a%d", artnum);
  669.  
  670.      if ((file = fopen (article, "r")) == NULL)
  671.        {
  672.           /* unavailable article */
  673.           printf ("Article %d of newsgroup %s unavailable\n",
  674.                     artnum, newsgroup);
  675.  
  676.           newsrc[curgroup].index = max (artnum, newsrc[curgroup].index);
  677. #ifdef _OSK
  678.           sleep (1);
  679. #else
  680.           tsleep (60);
  681. #endif    
  682.           return (-1);
  683.        }
  684.  
  685.      cls();
  686.      ReVOn();
  687.      printf ("Article %d of newsgroup %s (%d left):\n",
  688.              artnum, newsgroup,
  689.              max ((groups[curgroup].seq - newsrc[curgroup].index - 1), 0));
  690.  
  691.      ReVOff();
  692.      *subject = *reference = *returnpath = *ref2 = *sender = '\0';
  693.      header = TRUE;
  694.      valid = FALSE;                  /* not known to be valid news article */
  695.      screenline = 0;                 /* was 1.  changed --REB */
  696.      lp = line;
  697.  
  698.      while (fgets (lp, sizeof (line), file) != NULL)
  699.        {
  700.           register char c;
  701.  
  702.           if (screenline > rows  ||  *lp == '\f')         /* was >= --REB */
  703.             {
  704.                go_on = FALSE;
  705.  
  706.                while (!go_on)
  707.                  {
  708. #ifndef TERMCAP
  709.                     if (t2flag)
  710.                          write (1, "\n--MORE--", 9);
  711.                     else
  712.                          write (1, "\n\x1F\x20 --MORE--\x1F\x21", 14);
  713. #else
  714.                     ReVOn();
  715.                     printf(" --MORE--");
  716.                     ReVOff();
  717.                     fflush(stdout);
  718. #endif
  719.                     c = getresponse();
  720. #ifndef TERMCAP
  721.                     if (t2flag)
  722.                          write (1, "\x0D", 1);
  723.                     else
  724.                          write (1, "\x0D\x1F\x31", 3);
  725. #else
  726.                     putchar ('\n');
  727.                     DelLine();
  728. #endif
  729.                     screenline = 0;
  730.  
  731.                     switch (tolower (c))
  732.                       {
  733.                          case 'w':               /* Save without header */
  734.                               fputs ("\nw", stdout);             /* REB */
  735.                               goto goback;                       /*     */
  736.                          case 's':               /* Save */
  737.                               fputs ("\ns", stdout);
  738.                          case 'n':               /* Next */
  739.                          case 'c':               /* Catchup */
  740.                          case 'p':               /* Previous */
  741.                          case 'v':               /* Current */
  742.                          case '.':               /* Current */
  743.                          case 'u':               /* Current, rot13'd */
  744.                          case 'q':               /* Quit displaying article */
  745. goback:                       fclose (file);
  746.                               return (c);
  747.  
  748.                          case 'h':               /* Help */
  749.                          case '?':
  750. #ifndef TERMCAP
  751.                               if (!t2flag)
  752.                                 {
  753.                                    popdoublewindow (9, 0, 54, 15);
  754.                                    putdashs (40);
  755.                                 }
  756. #endif
  757.                               putchar ('\n');
  758.  
  759.                               for (hptr = help; *hptr != NULL; ++hptr)
  760.                                    printf (" %s\n",
  761.                                             strdetab (strcpy (tmp,*hptr), 7));
  762. #ifndef TERMCAP
  763.                               if (!t2flag)
  764.                                 {
  765.                                     putdashs (40);
  766.                                     fflush (stdout);
  767.                                     c = getresponse();
  768.                                     closedoublewindow();
  769.                                 }
  770.                               else
  771. #endif
  772.                                    putchar ('\n');
  773.                               break;
  774.  
  775.                          case ' ':               /* Next screen */
  776.                               go_on = TRUE;
  777.                               break;
  778.  
  779.                          default:
  780.                               printf ("Illegal command: %c\n", c);
  781.                               break;
  782.                       }
  783.                  }
  784.             }
  785.           fixline (line);
  786.           screenline += (strlen (lp) / columns) + 1;
  787.  
  788.           /* If we're still looking at the header */
  789.           if (header)
  790.             {
  791.                int printline = TRUE;
  792.  
  793.                /* don't display initial "Path:" line */
  794.                if (strncmp (lp, "Path: ", 6) == 0)
  795.                  {
  796.                     printline = FALSE;
  797.                     valid = TRUE;                    /* valid news article */
  798.                  }
  799.  
  800.                /* extract "Subject:" */
  801.                if (strncmp (lp, "Subject: ", 9) == 0)
  802.                  {
  803.                     strcpy (temp, getstring (line));
  804.  
  805.                     if (strnucmp (temp, "Re:", 3) != 0)
  806.                          sprintf (subject, "Re: %s", temp);
  807.                     else
  808.                          strcpy (subject, temp);
  809.                  }
  810.  
  811.                /* extract "Message-ID:" */
  812.                if (strncmp (lp, "Message-ID: ", 12) == 0)
  813.                  {
  814.                     reference[0] = '<';
  815.                     strcpy (&reference[1], getval (line));
  816.                  }
  817.  
  818.                /* extract "References:" but don't display it. */
  819.                if (strncmp (lp, "References: ", 12) == 0)
  820.                  {
  821.                     strcpy (ref2, getstring (line));
  822.                     screenline -= (strlen (lp) / columns) + 1;
  823.                     printline = FALSE;
  824.                  }
  825.  
  826.                /* extract "From:" */
  827.                if (strncmp (lp, "From: ", 6) == 0)
  828.                     strcpy (returnpath, getval (line));
  829.  
  830.                /* extract "Reply-To:", overwrites "From:" */
  831.                if (strncmp (lp, "Reply-To: ", 10) == 0)
  832.                     strcpy (returnpath, getval (line));
  833.  
  834.                /* extract "Sender:" */
  835.                if (strncmp (lp, "Sender: ", 8) == 0)
  836.                     strcpy (sender, getval (line));
  837.  
  838.                /* sense rot13 article */ 
  839.                if (strncmp (lp, "Keywords: ", 10) == 0)
  840.                     if (auto_rot && findstr (1, lp, "rot13") != 0)
  841.                          rot13 = TRUE;
  842.  
  843.                if (printline)
  844.                     fputs (lp, stdout);
  845.  
  846.                /* first blank line ends header */
  847.                if (*lp == '\n')
  848.                  {
  849.                     header = FALSE;
  850. #ifndef TERMCAP
  851.                     if (t2flag)
  852.                          write (1, "\n y/n/q? ", 9);
  853.                     else
  854.                          write (1, "\n\x1F\x20 y/n/q?\x1F\x21", 12);
  855. #else
  856.                     putchar ('\n');
  857.                     ReVOn();
  858.                     printf(" y/n/q?  ");
  859.                     ReVOff();
  860.                     fflush(stdout);
  861. #endif
  862.                     c = getresponse();
  863. #ifndef TERMCAP
  864.                     if (!t2flag)
  865.                          write (1, "\x1f\x31", 2);
  866.  
  867.                     backspace (!t2flag ? 7 : 8);
  868. #else
  869.                     DelLine();
  870.                     backspace (8);
  871. #endif
  872.                     switch (tolower (c))
  873.                       {
  874.                          case 'n':
  875.                          case 'p':
  876.                          case 'q':
  877.                               fclose (file);
  878.                               return (c);
  879.  
  880.                          default:
  881.                               break;
  882.                       }
  883.                  }
  884.             }
  885.  
  886.           /* Handling for body of article */
  887.           else
  888.             {
  889.                if (rot13)
  890.                  {
  891.                     for (k = 0; line[k] != '\0'; k++)
  892.                          if (isalpha (line[k]))
  893.                               line[k] += (toupper (line[k]) > 'M')                                                        ? (-13) : 13;
  894.  
  895.                     /* Don't unrot signatures */
  896.                     if (*lp == '-')
  897.                          if (strcmp (lp, "--\n") == 0 || 
  898.                               strcmp (lp, "-- \n") == 0)
  899.                            {
  900.                               rot13 = FALSE;
  901.                            }
  902.                  }
  903.                fputs (lp, stdout);
  904.             }
  905.        }
  906.  
  907.      /* Append previous references */
  908.      strcat (strcat (reference, "> "), ref2);
  909.      fclose (file);
  910.      return ('\0');
  911. }
  912.  
  913.  
  914.  
  915. int newscmd (c, i)
  916. register char c;
  917. int i;
  918. {
  919.      char tmp[60];
  920.      int f;                                                /* added BAS */
  921.      int cin;                                              /* added BRT */
  922.      flag cflag;                                           /* added BAS */
  923.      flag noerror;
  924.      struct fildes fdes;                                   /* added BAS */
  925.      static int seq, index;
  926.      char **hptr, t, *path;
  927.      static char cmd[1024],
  928.                  *help[] = {
  929.                      "a\tadd new article in current group",
  930.                      "s <file>  save article in <file>",
  931.                      "w <file>  save article in <file> without header",
  932.                      "p\tprevious article",
  933.                      "c\tcatchup (Mark all articles read)",
  934.                      "f\tpost followup to current article",
  935.                      "r\treply to article author",
  936.                      "q\tquit",
  937.                      "v or .    redisplay current article",
  938.                      "n\tnext",
  939.                      "#\tdisplay article #",
  940.                      "u\tredisplay current article, rot13'd (unrot)",
  941.                      "h or ?    help",
  942.                      "!\tfork a shell",
  943.                      NULL
  944.                   };
  945.  
  946.      index = groups[curgroup].index;
  947.      seq = groups[curgroup].seq;
  948.  
  949.      for (;;)
  950.        {
  951.           /* Do we need a prompt? */
  952.           if (c == '\0')
  953.             {
  954.                ReVOn();
  955.                printf ("\nEnd of article %d (of %d-%d)--What now? [nq] ",
  956.                        i, index, seq);
  957.                ReVOff();
  958.                putchar (' ');
  959.                fflush (stdout);
  960.                c = getresponse();
  961.             }
  962.  
  963.           switch (tolower (c))
  964.             {
  965.                /* save article with or without header...changed --REB */
  966.                case 's':
  967.                case 'w':
  968.                     /* Set up a flag to remember whether or not we changed
  969.                        our uid.  We can't do this for the general case, as
  970.                        that would allow anyone to put a file anywhere in the
  971.                        file system --BAS */
  972.  
  973.                     cflag = FALSE;
  974.                     path = getword();
  975.  
  976.                     if (path[0] == '/')
  977.                          strcpy (cmd, path);
  978.                     else
  979.                       {
  980.                          sprintf (cmd, "%s/%s", homedir, path);
  981.                          asetuid (0);
  982.                          cflag = FALSE;
  983.                       }
  984.  
  985.                     /* If your system allows user to make links, then you need
  986.                        to check the ownership of the file, if it exists.
  987.                        Otherwise, you can overwrite any file that is on the
  988.                        same disk as the file --BAS 2 */
  989.  
  990.                     if (myuid)
  991.                          if ((f = open (cmd, 1)) > 0)
  992.                            {
  993.                               _gs_gfd (f, &fdes, sizeof (fdes));
  994.                               close (f);
  995.  
  996.                               if (myuid != (unsigned)fdes.fd_own)
  997.                                 {
  998.                                    printf ("readnews: you do not own %s\n",
  999.                                            cmd);
  1000.  
  1001.                                    if (cflag)
  1002.                                         asetuid (myuid);
  1003.  
  1004.                                    continue;
  1005.                                 }
  1006.                            }
  1007.  
  1008.                     /* save article with header or without it --REB */
  1009.                     if (c == 's')
  1010.                          noerror = fileapnd (article, cmd, TRUE);
  1011.                     else
  1012.                          noerror = fileapskp (article, cmd, TRUE);
  1013.  
  1014.                     if (!noerror)
  1015.                       {
  1016.                          fputs ("....can't save article", stdout);
  1017.  
  1018.                          /* Change our uid back, if needed -- BAS 2 */
  1019.                          if (cflag)
  1020.                               asetuid(myuid);
  1021.  
  1022. #ifdef _OSK
  1023.                          sleep (2);
  1024. #else
  1025.                          tsleep (120);
  1026. #endif
  1027.                       }
  1028.  
  1029.                     /* Change the ownership of the file, if needed -- BAS 2 */
  1030.                     if (cflag)
  1031.                       {
  1032.                          chown (cmd, myuid);
  1033.                          asetuid (myuid);
  1034.                       }
  1035.                     break;
  1036.  
  1037.                /* display previous article */
  1038.                case 'p':
  1039.                     i = max (i - 1, index);
  1040.                case 'v':
  1041.                case '.':
  1042.                     return (i);
  1043.  
  1044.                /* redisplay article */
  1045.                case 'u':
  1046.                     rot13 = TRUE;
  1047.                     return (i);
  1048.  
  1049.                /* read specific article */
  1050.                case '0':
  1051.                case '1':
  1052.                case '2':
  1053.                case '3':
  1054.                case '4':
  1055.                case '5':
  1056.                case '6':
  1057.                case '7':
  1058.                case '8':
  1059.                case '9':
  1060.                     cmd[0] = c;
  1061.                     gets (&cmd[1]); 
  1062.                     i = atoi (cmd);
  1063.                     i = min (i, seq);
  1064.                     i = max (i, index);
  1065.                     return (i);
  1066.  
  1067.                /* Catch-Up -- Mark all articles as read */
  1068.                case 'c':
  1069.                     i = newsrc[curgroup].index = seq;
  1070.                     puts ("\nMarking all articles as read");
  1071.                     return (i+1);
  1072.  
  1073.                /* Add a new article in current group */
  1074.                case 'a':
  1075.                     cls();
  1076.                     printf ("add article to group: %s...", newsgroup);
  1077.                     fflush (stdout);
  1078.                     sprintf (cmd, "postnews -n %s", newsgroup);
  1079.                     docmd (cmd);
  1080.                     seq = ++(groups[curgroup].seq);
  1081.                     break;
  1082.  
  1083.                /* Followup -- Post a news reply */
  1084.                case 'f':
  1085.                     cls();
  1086.                     fputs ("post followup article...", stdout);
  1087.                     fflush (stdout);
  1088.  
  1089.                     /* If Subject: line has double quotes ("), change them to
  1090.                        single quotes ('). */
  1091.                     fixquote();
  1092.  
  1093.                     if (valid)
  1094.                       {
  1095.                          if ((path = getarticlepath() ) == NULL)
  1096.                            {
  1097.                               badpost ("can't post followup");
  1098.                               break;
  1099.                            }
  1100.  
  1101.                          sprintf (cmd, "postnews -i \"%s\" -s \"%s\" -n %s -a %s",
  1102.                                        reference, subject,
  1103.                                        newsgroup, article);
  1104.  
  1105.                          freearticlepath();
  1106.  
  1107.                          if (docmd_na (cmd) != 0)
  1108.                               badpost ("can't post followup");
  1109.  
  1110.                          seq = ++(groups[curgroup].seq);
  1111.                       }
  1112.                     /* post reply to news gatewayed from mailing list */
  1113.                     else
  1114.                       {
  1115.                          if ((path = getarticlepath() ) == NULL)
  1116.                            {
  1117.                               badpost ("can't mail reply");
  1118.                               break;
  1119.                            }
  1120.  
  1121.                          /* reply to "sender" address if present */
  1122.                          if (*sender != '\0')
  1123.                               strcpy (returnpath, sender);
  1124.  
  1125.                          sprintf (cmd, "%s %s -s \"%s\" -a %s/%s",
  1126.                                        mailer, returnpath, subject, path,
  1127.                                        article);
  1128.  
  1129.                          freearticlepath (path);
  1130.  
  1131.                          if (docmd_na (cmd) != 0)
  1132.                               badpost ("can't mail followup");
  1133.                       }
  1134.                     break;
  1135.  
  1136.                /* Reply to article author */
  1137.                case 'r':
  1138.                     cls();
  1139.                     fputs ("reply to article by mail...", stdout);
  1140.                     fflush (stdout);
  1141.  
  1142.                     /* If Subject: line as double quotes ("), change them to
  1143.                        single quotes ('). */
  1144.  
  1145.                     fixquote();
  1146.                     if ((path = getarticlepath() ) == NULL)
  1147.                       {
  1148.                          badpost ("can't reply by mail");
  1149.                          break;
  1150.                       }
  1151.                     sprintf (cmd, "%s %s -s \"%s\" -a %s/%s",
  1152.                                   mailer, returnpath, subject, path, article);
  1153.  
  1154.                     freearticlepath (path);
  1155.  
  1156.                     if (docmd (cmd) != 0)
  1157.                          badpost ("can't reply by mail");
  1158.  
  1159.                     break;
  1160.  
  1161.                /* Next */
  1162.                case 'n':
  1163.                case ' ':
  1164.                case '\n':
  1165.                     putchar ('\n');
  1166.  
  1167.                     /* flush keyboard input */
  1168.                     if ((cin = _gs_rdy (0)) > 0)
  1169.                          read (0, temp, cin);
  1170.  
  1171.                     return (++i);
  1172.  
  1173.                /* Quit */
  1174.                case 'q':
  1175.                     putchar ('\n');
  1176.                     return (0);
  1177.  
  1178.                /* Help */
  1179.                case 'h':
  1180.                case '?':
  1181. #ifndef TERMCAP
  1182.                     if (!t2flag)
  1183.                       {
  1184.                          popdoublewindow (23, 0, 54, 16);
  1185.                          putdashs (52);
  1186.                       }
  1187. #endif
  1188.                     putchar ('\n');
  1189.  
  1190.                     for (hptr = help; *hptr != NULL; ++hptr)
  1191.                          printf (" %s\n", strdetab (strcpy (tmp, *hptr), 9));
  1192.  
  1193. #ifndef TERMCAP
  1194.                     if (!t2flag)
  1195.                       {
  1196.                          putdashs (52);
  1197.                          fflush (stdout);
  1198.                          c = getresponse();
  1199.                          closedoublewindow();
  1200.                          putchar ('\x09');
  1201.                       }
  1202.                     else
  1203. #endif
  1204.                          putchar ('\n');
  1205.                     break;
  1206.  
  1207.                /* fork a shell */
  1208.                case '!':
  1209.                     forkshell();
  1210.  
  1211. #ifndef TERMCAP
  1212.                     if (!t2flag)
  1213.                          resetline();
  1214. #else
  1215.                     resetline();
  1216. #endif
  1217.                     break;
  1218.  
  1219.                /* Illegal command */
  1220.                default:
  1221.                     printf ("\nIllegal command: %c\n", c);
  1222.                     break;
  1223.             }
  1224.           c = '\0';       /* We want a prompt for the next command */
  1225.        }
  1226. }
  1227.  
  1228.  
  1229.  
  1230. /* moved from main() --REB */
  1231.  
  1232. int getscreensize()
  1233. {
  1234. #ifdef TERMCAP
  1235.      extern int ncolumns, nrows;
  1236.  
  1237.      columns = ncolumns;
  1238.      rows = nrows;
  1239. #else
  1240. #  ifndef _OSK
  1241.      struct registers regs;
  1242.  
  1243.      /* get screen size */
  1244.      regs.rg_a = 0;
  1245.      regs.rg_b = SS_SCSIZ;
  1246.      _os9 (I_GETSTT, ®s);
  1247.      columns = regs.rg_x - 1;
  1248.      rows = regs.rg_y - 1;
  1249. #  else
  1250.      columns = 80;
  1251.      rows = 24;
  1252. #  endif
  1253. #endif
  1254. }
  1255.  
  1256.  
  1257.  
  1258. /* If the Subject: line has a double quote in it, MAILX and POSTNEWS interpret
  1259.    the quotes as ending the Subject:.  For example, a line passed as:
  1260.  
  1261.        -s \"darn "Bug" story\"
  1262.  
  1263.    gets parsed as: Subject: darn, with 'Bug"' [sic] and 'story' as addresses.
  1264.    By changing the existing double quotes to a single quote, the problem is
  1265.    avoided. */
  1266.  
  1267. int fixquote()
  1268. {
  1269.      register char *p;
  1270.  
  1271.      p = subject;
  1272.  
  1273.      while ((p = strchr (p, '"')) != NULL)
  1274.           *p = '\x27';                                        /* ' */
  1275. }
  1276.  
  1277.  
  1278.  
  1279. char *getword()
  1280. {
  1281.      register char *p;
  1282.  
  1283.      p = line;
  1284.      if (mfgets (p, sizeof (line), stdin) == NULL)
  1285.        {
  1286.           errno = 0;
  1287.           fatal ("<ESC> hit...exiting");
  1288.        }
  1289.  
  1290.      return (skipspace (p));             /* skipspace() is in parse.c --REB */
  1291.  
  1292. }
  1293.  
  1294.  
  1295.  
  1296. int putdashs (howmany)
  1297. int howmany;
  1298. {
  1299.      register int i;
  1300.  
  1301.      putchar (' ');
  1302.  
  1303.      for (i = 0; i < howmany; ++i)
  1304.           putchar ('=');
  1305.  
  1306.      fflush (stdout);
  1307. }
  1308.  
  1309.  
  1310.  
  1311. /* Get a single character response from the user. */
  1312.  
  1313. char getresponse()
  1314. {
  1315.      char c;
  1316.  
  1317.      /* wait for valid input */
  1318.      echo (OFF);
  1319.      do
  1320.        {
  1321.           while (_gs_rdy (0) <= 0)
  1322.                tsleep (4);
  1323.  
  1324.           read (0, &c, 1);
  1325.        }
  1326.      while (c < '\x20'  &&  c > '\x7f');
  1327.  
  1328.      if (c != '\n'  &&  c != ' ')
  1329.        {
  1330.           putchar (c);
  1331.           fflush (stdout);
  1332.        }
  1333.  
  1334.      echo (ON);
  1335.      return (c);
  1336. }
  1337.  
  1338.  
  1339.  
  1340. /* Turn off or on echo on the standard input path */
  1341.  
  1342. int echo (onoroff)
  1343. int onoroff;
  1344. {
  1345.      struct sgbuf stdinpath;
  1346.  
  1347.      _gs_opt (1, &stdinpath);
  1348.      stdinpath.sg_echo = onoroff;             /* switch standard input echo */
  1349.      _ss_opt (1, &stdinpath);                 /* update the path descriptor */
  1350. }
  1351.  
  1352.  
  1353.  
  1354. /* backspace-space-backspace to delete part of a line --REB */
  1355.  
  1356. int backspace (howmany)
  1357. int howmany;
  1358. {
  1359.      register int i;
  1360.  
  1361.      for (i = 0; i < howmany; ++i)
  1362.           fputs ("\b \b", stdout);
  1363.  
  1364.      fflush (stdout);
  1365. }
  1366.  
  1367.  
  1368.  
  1369. int interrupt (sig)
  1370. int sig;
  1371. {
  1372. #ifndef TERMCAP
  1373.      if (winopen)                 /* if a help window is open just close it */
  1374.        {
  1375.           closedoublewindow();
  1376.           return;
  1377.        }
  1378. #endif
  1379.      echo (ON);
  1380.      exit (sig);
  1381. }
  1382.  
  1383.  
  1384.  
  1385. int fatal (msg)
  1386. char *msg;
  1387. {
  1388.      fprintf (stderr, "\nreadnews: %s", msg);
  1389.  
  1390.      if (errno != 0)
  1391.           fprintf (stderr, "...error %d", errno);
  1392.  
  1393.      putc ('\n', stderr);
  1394.      interrupt (0);
  1395. }
  1396.  
  1397.  
  1398.  
  1399. /* Open double overlay windows for keyboard user--white on red over black on
  1400.    black.  Shouldn't be called if using CoCo TERMCAP.  */
  1401.  
  1402. #ifndef TERMCAP
  1403. int popdoublewindow (x, y, width, height)
  1404. int x, y, width, height;
  1405. {
  1406.      char outstr[18];
  1407.  
  1408.      /* turn off the cursor */
  1409.      write (1, "\x05\x20", 2);
  1410.  
  1411.      outstr[0] = outstr[9]  = 0x1b;
  1412.      outstr[1] = outstr[10] = 0x22;
  1413.      outstr[2] = outstr[11] = 1;
  1414.      outstr[5] = outstr[14] = width;
  1415.      outstr[6] = outstr[15] = height;
  1416.  
  1417.      /* bottom window */
  1418.      outstr[3] = x + 1;                    /* offset bottom window */
  1419.      outstr[4] = y + 1;
  1420.      outstr[7] = 2;                        /* black on black */
  1421.      outstr[8] = 2;
  1422.  
  1423.      /* top window */
  1424.      outstr[12] = x;
  1425.      outstr[13] = y;
  1426.      outstr[16] = 0;                        /* white on red */
  1427.      outstr[17] = 4;
  1428.  
  1429.      write (1, outstr, sizeof (outstr));
  1430.      winopen = TRUE;
  1431. }
  1432.  
  1433.  
  1434. /* Close double overlay window */
  1435.  
  1436. int closedoublewindow()
  1437. {
  1438.      write (1, "\x1b\x23\x1b\x23", 4);
  1439.      winopen = FALSE;
  1440.      resetline();
  1441. }
  1442. #endif
  1443.  
  1444.  
  1445. int resetline()
  1446. {
  1447.      puts ("\b  ");
  1448.      CurUp();
  1449.      CurOn();
  1450. }
  1451.  
  1452.  
  1453.  
  1454. int badpost (msg)
  1455. char *msg;
  1456. {
  1457.      printf ("\n%s...error #%d", msg, errno);
  1458.      fflush( stdout);
  1459. #ifdef _OSK
  1460.      sleep (3);
  1461. #else
  1462.      tsleep (180);
  1463. #endif
  1464. }
  1465.  
  1466.  
  1467.  
  1468. char *getarticlepath()
  1469. {
  1470.      register char *ptmp2;
  1471.      char *ptmp;
  1472.  
  1473.      ptmp = (char *) malloc ((strlen (newsdir) + strlen (newsgroup) + 2)
  1474.                               * sizeof (char *));
  1475.      if (ptmp == NULL)
  1476.           return (NULL);
  1477.  
  1478.      sprintf (ptmp, "%s/%s", newsdir, newsgroup);
  1479.      ptmp2 = (ptmp + strlen (ptmp) - 1);
  1480.  
  1481.      while (ptmp2 >= ptmp  &&  *ptmp2 != '/')
  1482.        {
  1483.           if (*ptmp2 == '.')
  1484.                *ptmp2 = '/';
  1485.  
  1486.           --ptmp2;
  1487.        }
  1488.      ptmp2 = ptmp;
  1489.  
  1490.      if ((ptmp = fixgroupname (ptmp)) == NULL)
  1491.           return ((char *) NULL);
  1492.  
  1493.      free (ptmp2);
  1494.      return (ptmp);
  1495. }
  1496.  
  1497.  
  1498.  
  1499. int freearticlepath (ptr)
  1500. char *ptr;
  1501. {
  1502.      if (ptr != NULL)
  1503.           free (ptr);
  1504. }
  1505.  
  1506.  
  1507.  
  1508. int usage()
  1509. {
  1510.      fputs ("readnews: read Usenet news articles\n\n", stderr);
  1511.      fputs ("Usage: readnews\n\n", stderr);
  1512.      fprintf (stderr, "v%s (%s) This is free software released under the GNU General Public\n",
  1513.                       version, VERDATE);
  1514.      fputs ("License.  Please send suggestions/bug reports to:  bob@kc2wz.bubble.org\n", stderr);
  1515.  
  1516.      exit (0);
  1517. }
  1518.