home *** CD-ROM | disk | FTP | other *** search
/ gdead.berkeley.edu / gdead.berkeley.edu.tar / gdead.berkeley.edu / pub / gdead / miscellaneous / vdig.c < prev    next >
C/C++ Source or Header  |  1991-09-10  |  33KB  |  1,660 lines

  1. /*
  2.  * vdig - Display a digest the way vnews displays news.
  3.  *
  4.  * DESCRIPTION:
  5.  *    vdig is a program that reads an internet digest format message 
  6.  *    (like the Dead-Flames), and displays it like vnews.  For each
  7.  *    message, vdig first displays the subject of the message,
  8.  *    the name of the sender, the number of lines in the message,
  9.  *    and a list of any other newsgroups to which the message cross-posted.
  10.  *    vdig then prints a "more?" prompt in the lower left hand corner
  11.  *    of the screen.  If you want to see the message, type the space bar,
  12.  *    and vdig will display the first page.  If you want to skip the
  13.  *    message, type the n key, and vdig will go on to the next message.
  14.  *    After vdig displays the first page of a message, you can page
  15.  *    through the message by typing the space bar.  After vdig displays
  16.  *    the last page of a message, when you type the space bar, vdig
  17.  *    goes on to the next message.  
  18.  *
  19.  *    vdig has a number of other features like scrolling through a message
  20.  *    a line or page at a time, saving an individual message in a file,
  21.  *    replying to the sender of an individual message with email, etc.
  22.  *    Type the question mark key for a list of what each key does.
  23.  *
  24.  * USAGE:
  25.  *    vdig can read the digest from a named file, or from the standard
  26.  *    input if no filename is given:
  27.  *        % vdig file
  28.  *        % vdig < file
  29.  *    You can also use vdig within the Berkeley mailer (/usr/ucb/Mail)
  30.  *    and just pipe the digest message directly to vdig, without having
  31.  *    to save it in a file:
  32. % Mail
  33. Mail version SMI 4.0 Mon Aug 10 16:41:36 EDT 1992  Type ? for help.
  34. "/usr/spool/mail/juo": 1 message 1 new
  35. >N  1 Dead-Flames-Request@fuggles.acc.virginia.edu Thu Sep 10 00:05  711/26064 Dead-Flames Digest #240
  36. & | vdig
  37. Pipe to: "vdig"
  38.  *    
  39.  *    That also works with the System V mailer mailx.
  40.  *
  41.  * INSTALLATION:
  42.  *    vdig uses the curses library.  On most unix machines, you
  43.  *    can compile it like this:
  44.  *        % cc -o vdig vdig.c -lcurses
  45.  *    On some, curses uses the termcap library, so you have to say
  46.  *    this, instead:
  47.  *        % cc -o vdig vdig.c -lcurses -ltermcap.
  48.  *    I'm not sure how to do this on a PC.
  49.  * HISTORY:
  50.  *    I picked this program up from a friend a while ago and haven't
  51.  *    had to do much of anything to it.  I've been using it for about
  52.  *    a year without any major problems (on rare occasions things get 
  53.  *    hung when I run vdig from vmail and suspend them, but I've never
  54.  *    bothered tracking that down to see if it is a vmail bug or a vdig
  55.  *    bug; in either case it doesn't happen often).  If you find any
  56.  *    problems (or make any improvements) you can send mail to
  57.  *    juo@cs.rutgers.edu.
  58.  *
  59.  *    Version 0.1, 9/11/91
  60.  *        Final "initial" version.
  61.  *    Version 1.1, 9/10/92
  62.  *        Add these comments, no code changes.
  63.  *
  64.  */
  65.  
  66. #include <stdio.h>
  67. #include <curses.h>
  68. #include <signal.h>
  69. #include <setjmp.h>
  70. #include <sys/types.h>
  71. #include <sys/stat.h>
  72.  
  73. extern int errno;
  74. extern char *Malloc();
  75. extern char *Realloc();
  76.  
  77. #define GROWTH (128)
  78. #define MAXLINLEN (1024)
  79.  
  80. /* these shouldn't be hardwired */
  81. int scrwidth = 79;    /* set this to 1 less than your screen width to
  82.                minimize worries about getting screen boundary
  83.                just exactly perfect. */
  84. int scrheight = 24;
  85.  
  86. struct mess
  87. {
  88.     char *subject;
  89.     char *from;
  90.     char *crosspost;
  91.     int lines;
  92.     int len;
  93.     char *headers;
  94.     char *text;
  95.     char **bos;
  96.     char **eos;
  97.     int screenlines;
  98.     int headlines;
  99.     char **screen;
  100. };
  101.  
  102. struct grow
  103. {
  104.     int   curlen;
  105.     int   maxlen;
  106.     char *text;
  107. };
  108.  
  109. struct mess *readmess ();
  110. char *expandfilename ();
  111.  
  112. struct mess **messlist = NULL;
  113. int nummess;
  114.  
  115. void catch ();
  116. void catch2 ();
  117. int caught = 0;
  118.  
  119. int tty_fd;
  120.  
  121. static jmp_buf pipe_env;
  122. char title [128];
  123. char status1 [1024];
  124. char status2 [1024];
  125.  
  126.  
  127. FILE *debug_fp = NULL;
  128.  
  129. main (argc, argv)
  130.     int         argc;
  131.     char    *argv [];
  132. {
  133.  
  134.     FILE *fp;
  135.     struct mess *m;
  136.     char *p;
  137.     char c;
  138.     int notdone;
  139.     int insamemsg;
  140.     char prompt [80];
  141.     char tmps [1024];
  142.     int lastpage;
  143.     int k;
  144.     int curmess;
  145.     int print_flag;
  146.     int prevmess;
  147.     int count;
  148.     int optind;
  149.  
  150.     optind = 1;
  151.     if (optind < argc)
  152.     {
  153.         p = argv [optind];
  154.         if (*p == '-')
  155.         {
  156.             ++p;
  157.             if (*p == 'd')
  158.             {
  159.                 ++p;
  160.                 debug_fp = fopen (p, "w");
  161.                 if (debug_fp == NULL)
  162.                 {
  163.                     perror (argv [0]);
  164.                     exit (1);
  165.                 }
  166.                 ++optind;
  167.             }
  168.         }
  169.     }
  170.     if (optind < argc)
  171.     {
  172.         fp = fopen (argv [optind], "r");
  173.         if (fp == NULL)
  174.         {
  175.             perror (argv [optind]);
  176.             exit (1);
  177.         }
  178.         readallmess (fp);
  179.     }
  180.     else
  181.     {
  182.         readallmess (stdin);
  183.         fp = freopen ("/dev/tty", "r", stdin);
  184.         if (fp == NULL)
  185.         {
  186.             perror (argv [0]);
  187.             exit (1);
  188.         }
  189.     }
  190.     screenon (0);
  191.     signal (SIGINT, catch);
  192.     if ( (nummess > 0) && (messlist [0]) && (messlist [0]->subject) )
  193.     strcpy (title, messlist [0]->subject);
  194.     else
  195.     strcpy (title, "");
  196.     notdone = 1;
  197.     curmess = 0;
  198.     prevmess = 0;
  199.     caught = 0;
  200.     status2 [0] = '\0';
  201.     while (notdone)
  202.     {
  203.         m = messlist [curmess];
  204.         if (m == NULL)
  205.         break;
  206.         setstatus1 (title, curmess, nummess - 1);
  207.         insamemsg = 1;
  208.         m->bos = m->screen;
  209.         m->eos = m->screen;
  210.         /* -1 only header, 1 skip header, 0 figure it */
  211.         print_flag = -1;
  212.         printmoremess (m, print_flag);
  213.         strcpy (prompt, "more? ");
  214.         lastpage = 0;
  215.         while (insamemsg)
  216.         {
  217.             caught = 0;
  218.             c = getcmdchar (prompt, &count);
  219.             switch (c)
  220.             {
  221.                 case ' ' :
  222.                 if (lastpage)
  223.                     {
  224.                     if ( (curmess + 1) < nummess)
  225.                         {
  226.                         ++curmess;
  227.                         insamemsg = 0;
  228.                         }
  229.                     break;
  230.                     }
  231.                 if (print_flag == -1)
  232.                     print_flag = 1;
  233.                 lastpage = printmoremess (m, print_flag);
  234.                 print_flag = 0;
  235.                 if (lastpage)
  236.                     strcpy (prompt, "more? ");
  237.                 else
  238.                     sprintf (prompt, "more(%d%%)? ", percent (m) );
  239.                 break;
  240.                 case 'A' :
  241.                 if ( (count >= 0) && count < nummess)
  242.                     {
  243.                     prevmess = curmess;
  244.                     curmess = count;
  245.                     insamemsg = 0;
  246.                     }
  247.                 break;
  248.                 case 's' :
  249.                 case 'w' :
  250.                 savemess (m, c);
  251.                 break;
  252.                 case 'd' :
  253.                 debug_printmess (m);
  254.                 lastpage = redrawscreen (m, print_flag);
  255.                 break;
  256.                 case 'r' :
  257.                 case 'R' :
  258.                 case 'f' :
  259.                 case 'F' :
  260.                 mailmess (m, c, title);
  261.                 lastpage = redrawscreen (m, print_flag);
  262.                 break;
  263.                 case '|' :
  264.                 pipemess (m);
  265.                 lastpage = redrawscreen (m, print_flag);
  266.                 break;
  267.                 case '?' :
  268.                 printhelp ();
  269.                 break;
  270.                 /* fall through */
  271.                 case '\014' :
  272.                 lastpage = redrawscreen (m, print_flag);
  273. #if 0
  274. main_redraw :
  275.                 m->eos = m->bos;
  276.                 move (0, 0);
  277.                 clear ();
  278.                 refresh ();
  279.                 lastpage = printmoremess (m, print_flag);
  280. #endif
  281.                 break;
  282.  
  283.                 case '\005' :    /* ^E */
  284.                 case '\016' :    /* ^N */
  285.                 case '\004' :    /* ^D */
  286.                 case '\006' :    /* ^F */
  287.                 if (count == 0)
  288.                     count = 1;
  289.                 if (c == '\004')
  290.                     count = count * ( (scrheight - 4) / 2);
  291.                 else if (c == '\006')
  292.                     count = count * (scrheight - 4);
  293.                 scrolldown (m, count);
  294.                 print_flag = 0;
  295.                 lastpage = printmoremess (m, print_flag);
  296.                 if (lastpage)
  297.                     strcpy (prompt, "more? ");
  298.                 else
  299.                     sprintf (prompt, "more(%d%%)? ", percent (m) );
  300.                 break;
  301.                 case '\031' :    /* ^Y */
  302.                 case '\020' :    /* ^P */
  303.                 case '\025' :    /* ^U */
  304.                 case '\002' :    /* ^B */
  305.                 if (count == 0)
  306.                     count = 1;
  307.                 if (c == '\025')
  308.                     count = count * ( (scrheight - 4) / 2);
  309.                 else if (c == '\002')
  310.                     count = count * (scrheight - 4);
  311.                 scrollup (m, count);
  312.                 print_flag = 0;
  313.                 lastpage = printmoremess (m, print_flag);
  314.                 if (lastpage)
  315.                     strcpy (prompt, "more? ");
  316.                 else
  317.                     sprintf (prompt, "more(%d%%)? ", percent (m) );
  318.                 break;
  319.                 case 'n' :
  320.                 case '+' :
  321.                 if (count == 0)
  322.                     count = 1;
  323.                 if ( (curmess + count) < nummess)
  324.                     {
  325.                     prevmess = curmess;
  326.                     curmess = curmess + count;
  327.                     insamemsg = 0;
  328.                     }
  329.                 break;
  330.                 case 'b' :
  331.                 if (count == 0)
  332.                     count = 1;
  333.                 if ( (curmess - count) >= 0)
  334.                     {
  335.                     prevmess = curmess;
  336.                     curmess = curmess - count;
  337.                     insamemsg = 0;
  338.                     }
  339.                 break;
  340.                 case '-' :
  341.                 if (prevmess != curmess)
  342.                     {
  343.                     int    swapmess;
  344.                     swapmess = prevmess;
  345.                     prevmess = curmess;
  346.                     curmess = swapmess;
  347.                     insamemsg = 0;
  348.                     }
  349.                 break;
  350.                 case 'q' :
  351.                 case 'x' :
  352.                 insamemsg = 0;
  353.                 notdone = 0;
  354.                 break;
  355.             }
  356.         }
  357.     }
  358. #if 0
  359.     refresh ();
  360.     echo ();
  361.     nocbreak ();
  362.     move (scrheight - 1, 0);
  363.     addch ('\n');
  364.     refresh ();
  365.     endwin ();
  366. #endif
  367.     screenoff ();
  368.     /* putchar ('\n'); */
  369.     if (debug_fp)
  370.     fclose (debug_fp);
  371. }
  372.     
  373. redrawscreen (m, print_flag)
  374.     struct mess *m;
  375.     int print_flag;
  376. {
  377.     int lastpage;
  378.  
  379.     m->eos = m->bos;
  380.     move (0, 0);
  381.     clear ();
  382.     refresh ();
  383.     lastpage = printmoremess (m, print_flag);
  384.     return (lastpage);
  385. }
  386.  
  387. char *
  388. getsecondcmd (prompt)
  389.     char *prompt;
  390. {
  391.     static char cmline [128];
  392.     int col;
  393.     int basecol;
  394.     char c;
  395.  
  396.     move (scrheight - 2, 0);
  397.     clrtoeol ();
  398.     addstr (prompt);
  399.     basecol = strlen (prompt);
  400.     col = 0;
  401.     refresh ();
  402.     caught = 0;
  403.     c = getch ();
  404.     while ( (c != '\r') && (c != '\n') )
  405.     {
  406.         if (caught)
  407.         return (NULL);
  408.         if ( (c == '\010') || (c == '\377') )
  409.         {
  410.             if (col >0)
  411.             {
  412.                 addch ('\010');
  413.                 --col;
  414.             }
  415.         }
  416.         else if (c < ' ')
  417.         {
  418.         }
  419.         else
  420.         {
  421.             addch (c);
  422.             cmline [col] = c;
  423.             ++col;
  424.         }
  425.         refresh ();
  426.         c = getch ();
  427.     }
  428.     cmline [col] = '\0';
  429.     return (cmline);
  430. }
  431.  
  432. mailmess (m, savetype, title)
  433.     struct mess *m;
  434.     char savetype;
  435.     char *title;
  436. {
  437.     FILE *fp;
  438.     char filename [256];
  439.     char tmps [1024];
  440.     int  lastnl;
  441.     char *p;
  442.     struct stat buf;
  443.     struct stat buf2;
  444.     int k;
  445.     int append;
  446.  
  447.     sprintf (filename, "/tmp/vd%05d", getpid () );
  448.     fp = fopen (filename, "w");
  449.     if (fp == NULL)
  450.     {
  451.         char tmps [1204];
  452.         sprintf (tmps, "Cannot open %s", filename);
  453.         seconderror (tmps);
  454.         return (1);
  455.     }
  456.  
  457.     fprintf (fp, "To: %s\n", m->from);
  458.     fprintf (fp, "Subject: Re: %s\n", m->subject);
  459.     fprintf (fp, "-----\n");
  460.     fprintf (fp, "\n");
  461.     if ( (savetype == 'R') || (savetype == 'F') )
  462.     {
  463.         if (*title)
  464.         fprintf (fp, "In %s, ", title);
  465.         if (savetype == 'R')
  466.         fprintf (fp, "you write:\n");
  467.         else
  468.         fprintf (fp, "%s writes:\n", m->from);
  469.         lastnl = 1;
  470.         p = m->text;
  471.         while (*p)
  472.         {
  473.             if (lastnl)
  474.             {
  475.                 fputc ('>', fp);
  476.                 fputc (' ', fp);
  477.                 lastnl = 0;
  478.             }
  479.             fputc (*p, fp);
  480.             if (*p == '\n')
  481.             lastnl = 1;
  482.             ++p;
  483.         }
  484.     }
  485.     fclose (fp);
  486.     sprintf (tmps, "vi %s", filename);
  487.     screenoff ();
  488.     system (tmps);
  489.     dispose (filename);
  490.     screenon (1);
  491.     unlink (filename);
  492.     return (0);
  493. }
  494.  
  495. dispose (filename)
  496.     char    *filename;
  497. {
  498.     char tmps [1024];
  499.     while (1)
  500.     {
  501.         fprintf (stderr, "What now, [s]end, [d]elete, [e]dit, [q]uit? ");
  502.         fgets (tmps, 1023, stdin);
  503.         if (tmps [0] == 'e')
  504.         {
  505.             sprintf (tmps, "vi %s", filename);
  506.             system (tmps);
  507.         }
  508.         else if (tmps [0] == 'd')
  509.         {
  510.             break;
  511.         }
  512.         else if (tmps [0] == 'q')
  513.         {
  514.             break;
  515.         }
  516.         else if (tmps [0] == 's')
  517.         {
  518.             if (dosend (filename) == 0)
  519.             break;
  520.         }
  521.     }
  522.     return (0);
  523. }
  524.  
  525. dosend (filename)
  526.     char *filename;
  527. {
  528.     FILE *fp;
  529.     FILE *fpmail;
  530.     char *p;
  531.     char *q;
  532.     char tmps [MAXLINLEN + 1];
  533.     char to [MAXLINLEN + 1];
  534.     char cc [MAXLINLEN + 1];
  535.     int haveto;
  536.     int havecc;
  537.     int k;
  538.     int rc;
  539.     int gotdash;
  540.     void (*old_sigpipe)();
  541.     void broken_pipe ();
  542.  
  543.  
  544.     fp = fopen (filename, "r");
  545.     if (fp == NULL)
  546.     {
  547.         perror (filename);
  548.         return (-1);
  549.     }
  550.     haveto = 0;
  551.     havecc = 0;
  552.     while (p = fgets (tmps, MAXLINLEN, fp) )
  553.     {
  554.         if (strncmp (tmps, "To: ", 4) == 0)
  555.         {
  556. #define BINMAIL 1
  557. #ifdef BINMAIL
  558.             if (haveto)
  559.             {
  560.                 fprintf (stderr, "Can not handle multiple To: addresses\n");
  561.                 fclose (fp);
  562.                 return (-1);
  563.             }
  564.             if (parseaddr (tmps + 4, to, "To:") != 0)
  565.             {
  566.                 fclose (fp);
  567.                 return (-1);
  568.             }
  569. #endif
  570.             haveto = 1;
  571.         }
  572. #ifdef BINMAIL
  573.         else if (strncmp (tmps, "Bcc: ", 5) == 0)
  574.         {
  575.             if (havecc)
  576.             {
  577.                 fprintf (stderr, "Can not handle multiple Cc/Bcc: addresses\n");
  578.                 fclose (fp);
  579.                 return (-1);
  580.             }
  581.             if (parseaddr (tmps + 5, cc, "Bcc:") != 0)
  582.             {
  583.                 fclose (fp);
  584.                 return (-1);
  585.             }
  586.             havecc = 1;
  587.         }
  588.         else if (strncmp (tmps, "Cc: ", 4) == 0)
  589.         {
  590.             if (havecc)
  591.             {
  592.                 fprintf (stderr, "Can not handle multiple Cc/Bcc: addresses\n");
  593.                 fclose (fp);
  594.                 return (-1);
  595.             }
  596.             if (parseaddr (tmps + 4, cc, "Cc:") != 0)
  597.             {
  598.                 fclose (fp);
  599.                 return (-1);
  600.             }
  601.             havecc = 1;
  602.         }
  603. #endif
  604.         else if (strcmp (tmps, "-----\n") == 0)
  605.         break;
  606.     }
  607.     if (p == NULL)
  608.     {
  609.         fprintf (stderr, "Missing ----- line, can not send.\n");
  610.         return (1);
  611.     }
  612.     if (haveto == 0)
  613.     {
  614.         fprintf (stderr, "Missing To: address, can not send.\n");
  615.         return (1);
  616.     }
  617. #ifdef BINMAIL
  618.     if (havecc)
  619.     sprintf (tmps, "/bin/mail %s %s", to, cc);
  620.     else
  621.     sprintf (tmps, "/bin/mail %s", to);
  622. #endif
  623.  
  624.     fprintf (stderr, "would: %s\n", tmps);
  625.     fpmail = popen (tmps, "w");
  626.     if (fpmail == NULL)
  627.     {
  628.         perror (tmps);
  629.         fclose (fp);
  630.         return (-1);
  631.     }
  632.     fseek (fp, 0, 0);
  633.  
  634.     old_sigpipe = signal (SIGPIPE, broken_pipe);
  635.     if (setjmp (pipe_env) == 0)
  636.     {
  637.         gotdash = 0;
  638.         while (p = fgets (tmps, MAXLINLEN, fp) )
  639.         {
  640.             if (!gotdash && (strcmp (tmps, "-----\n") == 0) )
  641.             {
  642.                 gotdash = 1;
  643.                 continue;
  644.             }
  645. #ifdef BINMAIL
  646.             if (!gotdash && (strncmp (tmps, "Bcc: ", 5) == 0) )
  647.             continue;
  648. #endif
  649.             fputs (tmps, fpmail);
  650.         }
  651.         rc = 0;
  652.         sprintf (status2, "Reply sent to %s", to);
  653.     }
  654.     else
  655.     {
  656.         rc = 1;
  657.     }
  658.     signal (SIGPIPE, old_sigpipe);
  659.     pclose (fpmail);
  660.     fclose (fp);
  661.     return (rc);
  662. }
  663.  
  664. parseaddr (src, addr, addrname)
  665.     char    *src;
  666.     char    *addr;
  667.     char     *addrname;
  668. {
  669.     int    k;
  670.     char *p;
  671.     char *q;
  672.     char close;
  673.  
  674.     k = 0;
  675.     p = src;
  676.     q = addr;
  677.     while ( (*p != '\n') && (*p != '\0') )
  678.     {
  679.         if (*p == '<')
  680.         break;
  681.         ++p;
  682.     }
  683.     if (*p == '<')
  684.     {
  685.         ++p;
  686.         while ( (*p != '>') && (*p != '\0') && (k < MAXLINLEN) )
  687.         {
  688.             *q++ = *p++;
  689.             ++k;
  690.         }
  691.         if (*p != '>')
  692.         {
  693.             fprintf (stderr, "Missing > in %s address\n", addrname);
  694.             return (-1);
  695.         }
  696.         *q++ = '\0';
  697.         return (0);
  698.     }
  699.     p = src;
  700.     while (*p == ' ')
  701.     ++p;
  702.     if ( (*p == '"') || (*p == '(') )
  703.     {
  704.         if (*p == '"')
  705.         close = '"';
  706.         else
  707.         close = ')';
  708.         while ( (*p != close) && (*p != '\0') )
  709.         ++p;
  710.         if (*p != close)
  711.         {
  712.             fprintf (stderr, "Missing closing %s in %s address\n",
  713.                     close, addrname);
  714.             return (-1);
  715.         }
  716.         while (*p == ' ')
  717.         ++p;
  718.     }
  719.     while ( (*p != '\n') && (*p != '\0') && (*p != '"') &&
  720.         (*p != '(') && (k < MAXLINLEN) )
  721.     {
  722.         *q++ = *p++;
  723.         ++k;
  724.     }
  725.     *q = '\0';
  726.     return (0);
  727. }
  728. savemess (m, savetype)
  729.     struct mess *m;
  730.     char savetype;
  731. {
  732.     FILE *fp;
  733.     char *filename;
  734.     char *p;
  735.     struct stat buf;
  736.     int k;
  737.     int append;
  738.  
  739.     filename = getsecondcmd ("file: ");
  740.     if ( (filename == NULL) || (*filename == '\0') )
  741.     {
  742.         move (scrheight - 2, 0);
  743.         clrtoeol ();
  744.         return (1);
  745.     }
  746.     filename = expandfilename (filename);
  747.     k = stat (filename, &buf);
  748.     if (k == 0)
  749.     append = 1;
  750.     else
  751.     append = 0;
  752.     if (append)
  753.     fp = fopen (filename, "a");
  754.     else
  755.     fp = fopen (filename, "w");
  756.     if (fp == NULL)
  757.     {
  758.         char tmps [1204];
  759.         sprintf (tmps, "Cannot open %s", filename);
  760.         seconderror (tmps);
  761.         return (1);
  762.     }
  763.  
  764.     if (savetype == 's')
  765.     {
  766.         p = m->headers;
  767.         while (*p)
  768.         {
  769.             fputc (*p, fp);
  770.             ++p;
  771.         }
  772.         fputc ('\n', fp);
  773.     }
  774.     p = m->text;
  775.     while (*p)
  776.     {
  777.         fputc (*p, fp);
  778.         ++p;
  779.     }
  780.     fclose (fp);
  781.     if (append)
  782.     addstr (" appended");
  783.     else
  784.     addstr (" created");
  785.     return (0);
  786. }
  787.  
  788. pipemess (m)
  789.     struct mess *m;
  790. {
  791.     FILE *fp;
  792.     char *filename;
  793.     char *p;
  794.     int k;
  795.     void broken_pipe ();
  796.     void (*old_sigpipe)();
  797.  
  798.     filename = getsecondcmd ("|");
  799.     if ( (filename == NULL) || (*filename == '\0') )
  800.     {
  801.         move (scrheight - 2, 0);
  802.         clrtoeol ();
  803.         return (1);
  804.     }
  805.     screenoff ();
  806.     fp = popen (filename, "w");
  807.     if (fp == NULL)
  808.     {
  809.         char tmps [1204];
  810.         sprintf (tmps, "Cannot popen %s\n", filename);
  811.         fputs (tmps, stderr);
  812.         screenon (1);
  813.         return (1);
  814.     }
  815.  
  816.     old_sigpipe = signal (SIGPIPE, broken_pipe);
  817.     if (setjmp (pipe_env) == 0)
  818.     {
  819.         p = m->headers;
  820.         while (*p)
  821.         {
  822.             fputc (*p, fp);
  823.             ++p;
  824.         }
  825.         fputc ('\n', fp);
  826.         p = m->text;
  827.         while (*p)
  828.         {
  829.             fputc (*p, fp);
  830.             ++p;
  831.         }
  832.     }
  833.     signal (SIGPIPE, old_sigpipe);
  834.     pclose (fp);
  835.     screenon (1);
  836.     return (0);
  837. }
  838.  
  839. void
  840. broken_pipe (sig)
  841.     int    sig;
  842. {
  843.     longjmp (pipe_env, 1);
  844. }
  845.  
  846. char *
  847. expandfilename (s)
  848.     char *s;
  849. {
  850.     extern char *getenv ();
  851.  
  852.     static char   filename [1024];
  853.     char *home;
  854.  
  855.     if ( (s [0] != '~') || (s [1] != '/') )
  856.     return (s);
  857.     
  858.     home = getenv ("HOME");
  859.     if (home == NULL)
  860.     return (s);
  861.     strcpy (filename, home);
  862.     strcat (filename, s + 1);
  863.     return (filename);
  864. }
  865.  
  866. printmoremess (m, print_flag)
  867.     struct mess *m;
  868.     int print_flag;
  869. {
  870.     char tmps [128];
  871.     int    lines;
  872.     int width;
  873.     int last_was_nl;
  874.     char *p;
  875.     char *q;
  876.     int k;
  877.     int start_y;
  878.     int more_count;
  879.     char **line;
  880.     int done;
  881.  
  882.     start_y = 0;
  883.     more_count = scrheight - 2;
  884.     line = m->eos;
  885.     if (print_flag != 1)
  886.     m->bos = line;
  887.     if (print_flag == -1)
  888.     {
  889.         move (0, 0);
  890.         clrtobot ();
  891.         for (k = 0; k < m->headlines; ++k)
  892.         {
  893.             addstr (*line);
  894.             addch ('\n');
  895.             ++line;
  896.         }
  897.         done = (*line == NULL);
  898.         if (line != m->screen)
  899.         --line;
  900.         m->eos = line;
  901.         return (done);
  902.     }
  903.     else if (print_flag == 1)
  904.     {
  905.         start_y = m->headlines - 1;
  906.         more_count = (scrheight - 2) - (m->headlines - 1);
  907.     }
  908.     else
  909.     {
  910.         start_y = 0;
  911.         more_count = scrheight - 2;
  912.     }
  913.     move (start_y, 0);
  914.     clrtobot ();
  915.     for (k = 0; k < more_count; ++k)
  916.     {
  917.         if (*line == NULL)
  918.         break;
  919.         if (**line)
  920.         addstr (*line);
  921.         addch ('\n');
  922.         ++line;
  923.     }
  924.     done = (*line == NULL);
  925.     if (line != m->screen)
  926.     --line;
  927.     m->eos = line;
  928.     return (done);
  929. }
  930.  
  931.  
  932.  
  933.  
  934. readallmess (fp)
  935.     FILE *fp;
  936. {
  937.     struct mess *m;
  938.     int maxmess;
  939.  
  940.     maxmess = 50;
  941.     nummess = 0;
  942.     messlist = (struct mess **) Malloc (maxmess * sizeof (struct mess *) );
  943.     while (m = readmess (fp) )
  944.     {
  945.         if ( (nummess + 1) >= maxmess)
  946.         {
  947.             maxmess += 50;
  948.             messlist = (struct mess **) Realloc (maxmess *
  949.                            sizeof (struct mess *) );
  950.         }
  951.         messlist [nummess] = m;
  952.         ++nummess;
  953.         formatmess (m);
  954.     }
  955. }
  956.  
  957. formatmess (m)
  958.     struct mess *m;
  959. {
  960. /* ++curlines; */
  961. #define GROWSCREEN() {\
  962. if (curlines >= (maxlines - 1) )\
  963. {\
  964. maxlines += 20;\
  965. screen = (char **) Realloc (screen, maxlines * sizeof (char *) );\
  966. }\
  967. }
  968.     char **screen;
  969.     int maxlines;
  970.     int curlines;
  971.     int headlines;
  972.     char *p;
  973.     char *q;
  974.     char *s;
  975.     char tmps [MAXLINLEN + 16];
  976.     int n;
  977.  
  978.     maxlines = 20;
  979.     curlines = 0;
  980.     screen = (char **) Malloc (maxlines * sizeof (char *) );
  981.  
  982.     if (m->subject)
  983.     {
  984.         sprintf (tmps, "Subject: %s", m->subject);
  985.         n = strlen (tmps);
  986.         p = tmps;
  987.         while (n >= scrwidth)
  988.         {
  989.             s = Malloc (scrwidth + 1);
  990.             strncpy (s, p, scrwidth);
  991.             /* s [scrwidth - 1] = '\0'; */
  992.             s [scrwidth] = '\0';
  993.             screen [curlines] = s;
  994.             ++curlines;
  995.             GROWSCREEN ();
  996.             n = n - (scrwidth);
  997.             p = p + (scrwidth);
  998.         }
  999.         s = Malloc (n + 1);
  1000.         strcpy (s, p);
  1001.         screen [curlines] = s;
  1002.         ++curlines;
  1003.         GROWSCREEN ();
  1004.     }
  1005.     else
  1006.     {
  1007.         s = screen [curlines];
  1008.         s = Malloc (17);
  1009.         strcpy (s, "Subject: [none]");
  1010.         screen [curlines] = s;
  1011.         ++curlines;
  1012.         GROWSCREEN ();
  1013.     }
  1014.  
  1015.     if (m->from)
  1016.     {
  1017.         sprintf (tmps, "From: %s", m->from);
  1018.         n = strlen (tmps);
  1019.         p = tmps;
  1020.         while (n >= scrwidth)
  1021.         {
  1022.             s = Malloc (scrwidth + 1);
  1023.             strncpy (s, p, scrwidth);
  1024.             s [scrwidth] = '\0';
  1025.             screen [curlines] = s;
  1026.             ++curlines;
  1027.             GROWSCREEN ();
  1028.             n = n - scrwidth;
  1029.             p = p + scrwidth;
  1030.         }
  1031.         s = Malloc (n + 1);
  1032.         strcpy (s, p);
  1033.         screen [curlines] = s;
  1034.         ++curlines;
  1035.         GROWSCREEN ();
  1036.     }
  1037.     else
  1038.     {
  1039.         screen [curlines] = Malloc (17);
  1040.         strcpy (screen [curlines], "From: [unknown]");
  1041.         ++curlines;
  1042.         GROWSCREEN ();
  1043.     }
  1044.  
  1045.     if (m->crosspost)
  1046.     {
  1047.         sprintf (tmps, "Crossposted-To: %s", m->crosspost);
  1048.         n = strlen (tmps);
  1049.         p = tmps;
  1050.         while (n >= scrwidth)
  1051.         {
  1052.             s = Malloc (scrwidth + 1);
  1053.             strncpy (s, p, scrwidth);
  1054.             s [scrwidth] = '\0';
  1055.             screen [curlines] = s;
  1056.             ++curlines;
  1057.             GROWSCREEN ();
  1058.             n = n - scrwidth;
  1059.             p = p + scrwidth;
  1060.         }
  1061.         s = Malloc (n + 1);
  1062.         strcpy (s, p);
  1063.         screen [curlines] = s;
  1064.         ++curlines;
  1065.         GROWSCREEN ();
  1066.     }
  1067.  
  1068.     sprintf (tmps, "(%d lines)", m->lines);
  1069.     s = Malloc (strlen (tmps) + 1);
  1070.     strcpy (s, tmps);
  1071.     screen [curlines] = s;
  1072.     ++curlines;
  1073.     GROWSCREEN ();
  1074.  
  1075.     s = Malloc (2);
  1076.     s [0] = '\0';
  1077.     screen [curlines] = s;
  1078.     ++curlines;
  1079.     GROWSCREEN ();
  1080.  
  1081.     headlines = curlines;
  1082.  
  1083.     if (m->text)
  1084.     {
  1085.         p = m->text;
  1086.         while (*p)
  1087.         {
  1088.             n = linlen (p);
  1089.             while (n >= scrwidth)
  1090.             {
  1091.                 s = Malloc (scrwidth + 1);
  1092.                 strncpy (s, p, scrwidth);
  1093.                 s [scrwidth] = '\0';
  1094.                 screen [curlines] = s;
  1095.                 ++curlines;
  1096.                 GROWSCREEN ();
  1097.                 n = n - scrwidth;
  1098.                 p = p + scrwidth;
  1099.             }
  1100.             s = Malloc (n + 2);
  1101.             if (n > 0)
  1102.             {
  1103.                 strncpy (s, p, n);
  1104.             }
  1105.             s [n] = '\0';
  1106.             screen [curlines] = s;
  1107.             ++curlines;
  1108.             GROWSCREEN ();
  1109.             p = p + n;
  1110.             if (*p)
  1111.             ++p;
  1112.         }
  1113.     }
  1114.  
  1115.     screen [curlines] = NULL;
  1116.     m->screen = screen;
  1117.     m->screenlines = curlines;
  1118.     m->headlines = headlines;
  1119. #undef GROWSCREEN
  1120. }
  1121.  
  1122. linlen (p)
  1123.     char *p;
  1124. {
  1125.     int n;
  1126.  
  1127.     n = 0;
  1128.     while ( (*p != '\n') && (*p != '\r') && (*p != '\0') )
  1129.     {
  1130.         ++p;
  1131.         ++n;
  1132.     }
  1133.     return (n);
  1134. }
  1135. getcmdchar (prompt, count)
  1136.     char *prompt;
  1137.     int *count;
  1138. {
  1139.     char c;
  1140.     int n;
  1141.     n = 0;
  1142.  
  1143.     if (status2 [0] != '\0')
  1144.     {
  1145.         move (scrheight - 2, 0);
  1146.         clrtoeol ();
  1147.         addstr (status2);
  1148.         status2 [0] = '\0';
  1149.     }
  1150.     move (scrheight - 1, 0);
  1151.     clrtoeol ();
  1152.     if (status1 [0] != '\0')
  1153.     {
  1154.         move (scrheight - 1, 10);
  1155.         addstr (status1);
  1156.         move (scrheight - 1, 0);
  1157.     }
  1158.     addstr (prompt);
  1159.     refresh ();
  1160.     c = getch ();
  1161.     while ( ('0' <= c) && (c <= '9') )
  1162.     {
  1163.         n = 10 * n + c - '0';
  1164.         c = getch ();
  1165.     }
  1166.     if (count)
  1167.     *count = n;
  1168.     return (c);
  1169. }
  1170. printmesshead (m)
  1171.     struct mess *m;
  1172. {
  1173.     char tmps [256];
  1174.  
  1175.     move (0, 0);
  1176.     clear ();
  1177.     addstr ("Subject: ");
  1178.     if (m->subject)
  1179.     addstr (m->subject);
  1180.     addch ('\n');
  1181.     addstr ("From: ");
  1182.     if (m->from)
  1183.     addstr (m->from);
  1184.     addch ('\n');
  1185.     sprintf (tmps, "(%d lines)", m->lines);
  1186.     addstr (tmps);
  1187.     addch ('\n');
  1188. }
  1189. struct mess *
  1190. readmess (fp)
  1191.     FILE *fp;
  1192. {
  1193.     struct mess *m;
  1194.     char tmps [1024];
  1195.     int curlen;
  1196.     int maxlen;
  1197.     char *grow;
  1198.     char *p;
  1199.     int n;
  1200.     int line_count;
  1201.     int got_header;
  1202.  
  1203.     do
  1204.     {
  1205.     if (fgets (tmps, 1023, fp) == NULL)
  1206.         {
  1207.         return (NULL);
  1208.         }
  1209.     } while (blank (tmps) );
  1210.     m = (struct mess *) Malloc (sizeof (struct mess) );
  1211.     m->from = NULL;
  1212.     m->subject = NULL;
  1213.     m->crosspost = NULL;
  1214.     m->text = NULL;
  1215.     m->headers = NULL;
  1216.     m->lines = 0;
  1217.     m->screen = NULL;
  1218.     m->screenlines = 0;
  1219.     m->len = 0;
  1220.     grow = (char *) Malloc (GROWTH);
  1221.     maxlen = GROWTH;
  1222.     curlen = 0;
  1223.     *grow = '\0';
  1224.     line_count = 0;
  1225.     got_header = 0;
  1226.     while (!blank (tmps) )
  1227.     {
  1228.         n = strlen (tmps);
  1229.         while ( (curlen + n) >= maxlen)
  1230.         {
  1231.             grow = (char *) Realloc (grow, maxlen + GROWTH);
  1232.             maxlen += GROWTH;
  1233.         }
  1234.         strcpy (grow + curlen, tmps);
  1235.         curlen += n;
  1236.         ++line_count;
  1237.         if (debug_fp)
  1238.         {
  1239.             fprintf (debug_fp, "read 1: \"%s\"\n", tmps);
  1240.         }
  1241.         if (strncmp (tmps, "From: ", 6) == 0)
  1242.         {
  1243.             n = strlen (tmps + 6);
  1244.             m->from = (char *) Malloc (n);
  1245.             strncpy (m->from, tmps + 6, n - 1);
  1246.             m->from [n - 1] = '\0';
  1247.             got_header = 1;
  1248.         }
  1249.         else if (strncmp (tmps, "Subject: ", 9) == 0)
  1250.         {
  1251.             n = strlen (tmps + 9);
  1252.             m->subject = (char *) Malloc (n);
  1253.             strncpy (m->subject, tmps + 9, n - 1);
  1254.             m->subject [n - 1] = '\0';
  1255.             got_header = 1;
  1256.         }
  1257.         else if (strncmp (tmps, "Crossposted-To: ", 16) == 0)
  1258.         {
  1259.             n = strlen (tmps + 16);
  1260.             m->crosspost = (char *) Malloc (n);
  1261.             strncpy (m->crosspost, tmps + 16, n - 1);
  1262.             m->crosspost [n - 1] = '\0';
  1263.             got_header = 1;
  1264.         }
  1265.         if (fgets (tmps, 1023, fp) == NULL)
  1266.         {
  1267.             m->text = grow;
  1268.             m->lines = line_count;
  1269.             m->len = curlen;
  1270.             return (m);
  1271.         }
  1272.     }
  1273.     
  1274.     m->headers = grow;
  1275.     grow = (char *) Malloc (GROWTH);
  1276.     maxlen = GROWTH;
  1277.     curlen = 0;
  1278.     *grow = '\0';
  1279.     line_count = 0;
  1280.     while (fgets (tmps, 1023, fp) != NULL)
  1281.     {
  1282.         if (debug_fp)
  1283.         {
  1284.             fprintf (debug_fp, "read 2:  \"%s\"\n", tmps);
  1285.         }
  1286.         /* if ( (tmps [0] == '-') && (tmps [1] != ' ') ) */
  1287.         if (strncmp (tmps, "------------------------------", 20) == 0)
  1288.         break;
  1289.         n = strlen (tmps);
  1290.         while ( (curlen + n) >= maxlen)
  1291.         {
  1292.             grow = (char *) Realloc (grow, maxlen + GROWTH);
  1293.             maxlen += GROWTH;
  1294.         }
  1295.         strcpy (grow + curlen, tmps);
  1296.         curlen += n;
  1297.         ++line_count;
  1298.     }
  1299.     m->text = grow;
  1300.     m->lines = line_count;
  1301.     m->len = curlen;
  1302.     if (debug_fp)
  1303.     {
  1304.         fprintf (debug_fp, "read 3: m->lines = %d, m->len = %d\n", m->lines,
  1305.                 m->len);
  1306.     }
  1307.     return (m);
  1308. }
  1309.  
  1310. blank (p)
  1311.     char *p;
  1312. {
  1313.     while ( (*p == ' ') || (*p == '\t') || (*p == '\n') )
  1314.     ++p;
  1315.     return (*p == '\0');
  1316. }
  1317. debug_printmess (m)
  1318.     struct mess *m;
  1319. {
  1320.     int    k;
  1321.     char *s;
  1322.     char **line;
  1323.     move (2, 0);
  1324.     clrtobot ();
  1325.     if (m->subject)
  1326.     printw ("subject = \"%s\"\n", m->subject);
  1327.     else
  1328.     printw ("subject = NULL\n");
  1329.     if (m->from)
  1330.     printw ("from = \"%s\"\n", m->from);
  1331.     else
  1332.     printw ("from = NULL\n");
  1333.     printw ("bos = %d = 0x%x\n", m->bos, m->bos);
  1334.     printw ("eos = %d = 0x%x\n", m->eos, m->bos);
  1335.     refresh ();
  1336.     if (m->screen)
  1337.     {
  1338.         line = m->screen;
  1339.         k = 0;
  1340.         while ( (*line) && (k < 9) )
  1341.         {
  1342.             /* printw ("X%sX\n", *line); */
  1343.             printw ("X 0x%x 0x%x %sX\n", line, *line);
  1344.             refresh ();
  1345.             ++line;
  1346.             ++k;
  1347.         }
  1348.     /* printw ("text = \"%s\"\n", m->text); */
  1349.     }
  1350.     else
  1351.     printw ("screen = NULL\n");
  1352.     refresh ();
  1353.     getcmdchar ("continue", NULL);
  1354. }
  1355.     
  1356.  
  1357. scrolldown (m, count)
  1358.     struct mess *m;
  1359.     int count;
  1360. {
  1361.     int    j;
  1362.     int    k;
  1363.     char **line;
  1364.  
  1365.     line = m->eos = m->bos;
  1366.     for (j = 0; (j < count) && (*line != NULL); ++j)
  1367.         ++line;
  1368.     m->eos = line;
  1369. }
  1370.  
  1371. scrollup (m, count)
  1372.     struct mess *m;
  1373.     int count;
  1374. {
  1375.     int    j;
  1376.     int    k;
  1377.     char **line;
  1378.  
  1379.     line = m->eos = m->bos;
  1380.     for (j = 0; (j < count) && (line > m->screen); ++j)
  1381.     --line;
  1382.     m->eos = line;
  1383. }
  1384.  
  1385. percent (m)
  1386.     struct mess *m;
  1387. {
  1388.     int    percent;
  1389.  
  1390.     percent = (100 * (m->eos - m->screen) ) / m->screenlines;
  1391.     if (percent >= 100)
  1392.     percent = 99;
  1393.     return (percent);
  1394. }
  1395.  
  1396. seconderror (s)
  1397.     char *s;
  1398. {
  1399.     move (scrheight - 2, 0);
  1400.     clrtoeol ();
  1401.     addstr (s);
  1402. }
  1403.  
  1404. void
  1405. catch (sig)
  1406.     int    sig;
  1407. {
  1408.     caught = sig;
  1409. }
  1410.  
  1411. void
  1412. catch2 (sig)
  1413.     int    sig;
  1414. {
  1415.     char tmps [1204];
  1416.     sprintf (tmps, "\ncaught sig %d\n", sig);
  1417.     err2 (tmps);
  1418. }
  1419.  
  1420. screenon (needreturn)
  1421.     int    needreturn;
  1422. {
  1423.     char    c;
  1424.     int        x;
  1425.     int        y;
  1426.  
  1427.     fflush (stdin);
  1428.     fflush (stdout);
  1429.     fflush (stderr);
  1430.     if (needreturn)
  1431.     {
  1432.         fputs ("[Hit return to continue]\n", stderr);
  1433.         c = getchar ();
  1434.         while ( (c != '\n') && (c != '\r') )
  1435.         {
  1436.         fputs ("hit return...\n", stderr);
  1437.         c = getchar ();
  1438.         }
  1439.     }
  1440.     initscr ();
  1441. #if 0    /* this doesn't really work quite right anyways, so just
  1442.      * assume 24x80 for now... */
  1443. #ifdef SYSV
  1444.     getmaxyx (stdscr, y, x);
  1445. #else
  1446. #ifdef BSD
  1447.     {
  1448.     struct winsize    ws;
  1449.  
  1450.     if (ioctl (fileno (stdin), TIOCGWINSZ, &ws) == 0)
  1451.         {
  1452.         y = ws.ws_row;
  1453.         x = ws.ws_col;
  1454.         }
  1455.     else
  1456.         {
  1457.         y = 0;
  1458.         x = 0;
  1459.         }
  1460.     }
  1461. #endif
  1462. #endif
  1463.     if (y > 0)
  1464.     scrheight = y;
  1465.     if (x > 0)
  1466.     scrwidth = x - 1;
  1467. #endif
  1468.     cbreak ();
  1469.     noecho ();
  1470.     refresh ();
  1471. }
  1472.  
  1473. screenoff ()
  1474. {
  1475.     refresh ();
  1476.     echo ();
  1477.     nocbreak ();
  1478.     move (scrheight - 1, 0);
  1479.     addch ('\n');
  1480.     refresh ();
  1481.     endwin ();
  1482.     fflush (stdin);
  1483.     fflush (stdout);
  1484.     fflush (stderr);
  1485. }
  1486.  
  1487.  
  1488. err2 (s)
  1489.     char *s;
  1490. {
  1491.     write (2, s, strlen (s) );
  1492. }
  1493.  
  1494.  
  1495. char *
  1496. Malloc (n)
  1497.     int n;
  1498. {
  1499.     void *p;
  1500.  
  1501.     p = (void *) malloc (n);
  1502.     if (p == NULL)
  1503.     {
  1504.         fprintf (stderr, "\nMalloc (%d), out of memory\n", n);
  1505.     }
  1506.     return (p);
  1507. }
  1508.  
  1509. char *
  1510. Realloc (p, n)
  1511.     void *p;
  1512.     int n;
  1513. {
  1514.     void *q;
  1515.  
  1516.     q = (void *) realloc (p, n);
  1517.     if (q == NULL)
  1518.     {
  1519.         fprintf (stderr, "\nRealloc (%d), out of memory\n", n);
  1520.     }
  1521.     return (q);
  1522. }
  1523.  
  1524. setstatus1 (title, curmess, nummess)
  1525.     char    *title;
  1526.     int         curmess;
  1527.     int         nummess;
  1528. {
  1529.     int        j;
  1530.     int        k;
  1531.     int        pad_blanks;
  1532.     char    *p;
  1533.     char    *q;
  1534.     char    tmps [128];
  1535.  
  1536.     sprintf (tmps, "%d/%d", curmess, nummess);
  1537.     j = strlen (title) + 4;
  1538.     k = strlen (tmps);
  1539.     if (j + 20 < scrwidth)
  1540.     {
  1541.         pad_blanks = ( ( (scrwidth - 20) - j) / 2) + 2;
  1542.         q = status1;
  1543.         for (j = 0; j < pad_blanks; ++j)
  1544.             *q++ = ' ';
  1545.         p = title;
  1546.         while (*p)
  1547.             *q++ = *p++;
  1548.         pad_blanks = pad_blanks + (9 - k);
  1549.         for (j = 0; j < pad_blanks; ++j)
  1550.         *q++ = ' ';
  1551.         strcpy (q, tmps);
  1552.     }
  1553.     else if (k + 10 < scrwidth)
  1554.     {
  1555.         pad_blanks = (scrwidth - 10 - strlen (tmps) );
  1556.         q = status1;
  1557.         for (j = 0; j < pad_blanks; ++j)
  1558.         *q++ = ' ';
  1559.         strcpy (q, tmps);
  1560.     }
  1561.     else
  1562.     {
  1563.         status1 [0] = '\0';
  1564.     }
  1565. }
  1566.  
  1567. /*
  1568. Vnews commands: ( may be preceded by a non-negative count) V 2.2 1/17/89
  1569.  
  1570. CR  Next page or article                D   Decrypt a rot 13 joke
  1571. n   Go to next article                  A   Go to article numbered count
  1572. e   Mark current article as unread      <   Go to article with given ID
  1573. + or =  Go forwards count articles      p   Go to parent article
  1574. -   Go to previous article              ug  Unsubscribe to this group
  1575. ^B  Go backwards count pages            ^L  Redraw screen
  1576. ^N  Go forward count lines              v   Print netnews version
  1577. ^P  Go backwards count lines            q   Quit
  1578. ^D  Go forward half a page              x   Quit without updating .newsrc
  1579. ^U  Go backwards half a page            c   Cancel the current article
  1580. h   Display article header              H   Display all article headers
  1581. !   Escape to shell                     ?   Display this message
  1582. r   Reply to article using editor       K   Mark rest of newsgroup read
  1583. R   Reply--put current article in reply b   Go back 1 article in same group
  1584. ESC-r  Reply directly using mailer      m   Move on to next item in a digest
  1585. f   Post a followup article             s   Save article in file
  1586. N   Go to newsgroup (next is default)   w   Save without header
  1587. l   List unread articles in group       L   List all articles in group
  1588.  
  1589. [Press CR to see article, h to see header... (any command will work)]
  1590.  
  1591. */
  1592.  
  1593. /*
  1594. ' '
  1595. A
  1596. s
  1597. w
  1598. r
  1599. R
  1600. f
  1601. F
  1602. |
  1603. ^L
  1604. ^E ^D
  1605. ^Y ^U
  1606. n
  1607. b
  1608. q
  1609. x
  1610.  
  1611. Vdig commands: ( may be preceded by a non-negative count)
  1612.  
  1613. CR  Next page or article                D   
  1614. n   Go to next article                  A   Go to article numbered count
  1615. e                                       <   
  1616. [ + or =  Go forwards count articles ]     p   
  1617. [ -   Go to previous article ]              ug
  1618. ^B  Go backwards count pages            ^L  Redraw screen
  1619. ^N  Go forward count lines              [ v   Print netnews version ]
  1620. ^P  Go backwards count lines            q   Quit
  1621. ^D  Go forward half a page              x   
  1622. ^U  Go backwards half a page            c
  1623. h                                       H
  1624. !   Escape to shell                     ?   Display this message
  1625. r   Reply to article using editor       K   
  1626. R   Reply--put current article in reply b   Go back 1 article in same group
  1627. [ ESC-r  Reply directly using mailer ]      m
  1628. f   Post a followup article             s   Save article in file
  1629. N                                       w   Save without header
  1630. l                                       L 
  1631.  
  1632. [Press CR to see article, h to see header... (any command will work)]
  1633.  
  1634. */
  1635. printhelp ()
  1636. {
  1637.     char *s = "\n\
  1638. \n\
  1639. vdig commands: ( may be preceded by a non-negative count) V 1.1 9/10/92\n\
  1640. CR  Next page or article                A   Go to article numbered count\n\
  1641. n   Go to next article                  b   Go back count articles\n\
  1642. +   Go forwards count articles          -   Go to previous article\n\
  1643. ^B  Go backwards count pages            ^F  Go forwards count pages\n\
  1644. ^D  Go forward half a page              ^U  Go backwards half a page\n\
  1645. ^N  Go forward count lines              ^P  Go backwards count lines\n\
  1646. r   Reply to article using editor       R   Reply--put current article in reply\n\
  1647. f   Post a followup article             ?   Display this message\n\
  1648. s   Save article in file                w   Save without header\n\
  1649. ^L  Redraw screen                       q   Quit\n\
  1650. \n\
  1651. [Press CR to see article, h to see header... (any command will work)]\n\
  1652. ";
  1653.     move (0, 0);
  1654.     clear ();
  1655.     refresh ();
  1656.     addstr (s);
  1657.     refresh ();
  1658. }
  1659.  
  1660.