home *** CD-ROM | disk | FTP | other *** search
/ Unix System Administration Handbook 1997 October / usah_oct97.iso / news / nn.tar / nn-6.5.1 / contrib / eep-1.81 / eepview.c < prev    next >
C/C++ Source or Header  |  1995-04-29  |  22KB  |  776 lines

  1. /*------------------------------------------------------------------------
  2.        Name: eepview.c
  3.  
  4. This module provides code to open a newsgroup directory, construct a
  5. list of all the messages, and display the list, along with subjects
  6. and names of the posters, plus size of messages.  This will replace the
  7. full screen, and allow scrolling down with a pointer in a similar way
  8. to the main screen.
  9.  
  10. ------------------------------------------------------------------------*/
  11.  
  12. #include <stdio.h>
  13. #include <string.h>
  14. #include <curses.h>
  15.  
  16. #ifdef UNIX
  17. #include <ctype.h>
  18. #include <errno.h>
  19. #include <signal.h>
  20. #endif /* UNIX */
  21.  
  22. #ifdef ANSI
  23. #include <stdlib.h>
  24. #else
  25. #define void int
  26. extern char *malloc();
  27. #endif /* ANSI */
  28.  
  29. #ifdef DIRENT    /* defined in makefile */
  30. #include <dirent.h>    /* or <sys/dirent.h> */
  31. #define direct dirent
  32. #else
  33. #include "ndir.h"
  34. #endif /* DIRENT */
  35.  
  36. #ifdef DOS
  37. #include <dos.h>
  38. #endif /* DOS */
  39.  
  40. #include "eep.h"
  41.  
  42. /* function definitions */
  43. void    showarts();
  44.  
  45. FILE    *farticle;
  46.  
  47. struct newsview    {
  48.  
  49. long    artnum;        /* article number */
  50. long    size;        /* size in bytes */
  51. char    *from;        /* poster */
  52. char    *date;        /* date */
  53. char    *msgid;        /* Msg-id: */
  54. char    *subject;    /* Subject: */
  55. char    *keywords;    /* Keywords: */
  56. char    *references;    /* References: */
  57. };
  58.  
  59. int    news_index;    /* index into newsview */
  60. int    art_count;    /* count of articles */
  61. int    art_current;  /* current article index */
  62. long    artnum_tmp;    /* temporary article number */
  63. char     *dir;        /* pointer to directory name */
  64. int     viewpos = 0;    /* view position */
  65.  
  66. char    nirvana[] = "(null)";
  67.  
  68. extern int eeplines;
  69. extern int eeppage;
  70. extern int eepoint;
  71. extern int current;
  72. extern WINDOW *over;
  73. extern char buffer[];
  74. extern char *shift_lower();
  75. extern char   *wallop();     /* see eepmisc.c */
  76.  
  77. struct newsview *art_ptr; /* pointer to news structure */
  78.  
  79. struct newsview *article[MAXARTS];    /* array of pointers to articles struct */
  80.  
  81. int    artnum_compare(item1,item2)    /* sort by article number */
  82. struct newsview    **item1, **item2;
  83. {
  84. struct newsview *ptr1, *ptr2;
  85. long int diff;
  86.  
  87.     ptr1 = *item1;
  88.     ptr2 = *item2;
  89.     diff = ptr1->artnum - ptr2->artnum;
  90.     if (diff == 0L) return(0);
  91.     if (diff > 0L) return(1);
  92.     if (diff < 0L) return(-1);
  93. }
  94.  
  95. #ifdef DOS
  96.  
  97. /* Note that we do not use wallop() to replace the malloc()
  98.  * calls here because they get freed quickly.
  99.  */
  100. static void free_dircontents (struct _dircontents *);
  101.  
  102. #define ATTRIBUTES    (_A_RDONLY | _A_HIDDEN | _A_SYSTEM | _A_SUBDIR)
  103.  
  104. DIR *
  105. opendir (char *name)
  106. {
  107.   struct find_t find_buf;
  108.   DIR *dirp;
  109.   struct _dircontents *dp;
  110.   char name_buf[_MAX_PATH + 1];
  111.   char *slash = "";
  112.  
  113.   if (!name)
  114.     name = "";
  115.   else if (*name)
  116.     {
  117.       char *s;
  118.       int l = strlen (name);
  119.  
  120.       s = name + l - 1;
  121.       if ( !(l == 2 && *s == ':') && *s != '\\' && *s != '/')
  122.     slash = "/";    /* save to insert slash between path and "*.*" */
  123.     }
  124.  
  125.   strcat (strcat (strcpy (name_buf, name), slash), "*.*");
  126.  
  127.   dirp = (DIR *) malloc (sizeof (DIR));
  128.   if (dirp == (DIR *)0)
  129.     return (DIR *)0;
  130.  
  131.   dirp->dd_loc = 0;
  132.   dirp->dd_contents = dirp->dd_cp = (struct _dircontents *) 0;
  133.  
  134.   if (_dos_findfirst (name_buf, ATTRIBUTES, &find_buf))
  135.     {
  136. /*      free (dirp); */
  137.       return (DIR *)0;
  138.     }
  139.  
  140.   do
  141.     {
  142.       dp = (struct _dircontents *) malloc (sizeof (struct _dircontents));
  143.       if (dp == (struct _dircontents *)0)
  144.     {
  145. /*      free_dircontents (dirp->dd_contents); */
  146.       return (DIR *)0;
  147.     }
  148.  
  149.       dp->_d_entry = (char *)malloc (strlen (find_buf.name) + 1);
  150.       if (dp->_d_entry == (char *)0)
  151.     {
  152. /*      free(dp); */
  153. /*      free_dircontents (dirp->dd_contents); */
  154.       return (DIR *)0;
  155.     }
  156.  
  157.       if (dirp->dd_contents)
  158.     dirp->dd_cp = dirp->dd_cp->_d_next = dp;
  159.       else
  160.     dirp->dd_contents = dirp->dd_cp = dp;
  161.  
  162.       strcpy (dp->_d_entry, find_buf.name);
  163.  
  164.       dp->_d_next = (struct _dircontents *)0;
  165.  
  166.     } while (! _dos_findnext (&find_buf));
  167.  
  168.   dirp->dd_cp = dirp->dd_contents;
  169.  
  170.   return dirp;
  171. }
  172.  
  173.  
  174. void
  175. closedir (DIR *dirp)
  176. {
  177.   free_dircontents (dirp->dd_contents);
  178.   free (dirp);
  179. }
  180.  
  181.  
  182. struct direct *
  183. readdir (DIR *dirp)
  184. {
  185.   static struct direct dp;
  186.  
  187.   if (dirp->dd_cp == (struct _dircontents *)0)
  188.     return (struct direct *)0;
  189.   dp.d_namlen = dp.d_reclen =
  190.     strlen ((char *)strcpy (dp.d_name, dirp->dd_cp->_d_entry));
  191.   strlwr (dp.d_name);        /* JF */
  192.   dp.d_ino = 0;
  193.   dirp->dd_cp = dirp->dd_cp->_d_next;
  194.   dirp->dd_loc++;
  195.  
  196.   return &dp;
  197. }
  198.  
  199.  
  200. void
  201. seekdir (DIR *dirp, long off)
  202. {
  203.   long i = off;
  204.   struct _dircontents *dp;
  205.  
  206.   if (off < 0)
  207.     return;
  208.   for (dp = dirp->dd_contents; --i >= 0 && dp; dp = dp->_d_next)
  209.     ;
  210.   dirp->dd_loc = off - (i + 1);
  211.   dirp->dd_cp = dp;
  212. }
  213.  
  214.  
  215. long
  216. telldir (DIR *dirp)
  217. {
  218.   return dirp->dd_loc;
  219. }
  220.  
  221.  
  222. /* Garbage collection */
  223.  
  224. static void
  225. free_dircontents (struct _dircontents *dp)
  226. {
  227.   struct _dircontents *odp;
  228.  
  229.   while (dp)
  230.     {
  231.       if (dp->_d_entry)
  232.     free ((struct _dirdesc *)dp->_d_entry);
  233.       dp = (odp = dp)->_d_next;
  234.       free ((struct _dirdesc *)odp);
  235.     }
  236. }
  237. #endif /* DOS */
  238.  
  239. /* Main EEP routines start here */
  240.  
  241.  
  242. void    eepview(groupname)
  243. char    *groupname;    /* place to find articles */
  244. {
  245.   static DIR *directory;
  246.   struct direct *entry = (struct direct *)0;
  247.   char *name = "";
  248.  
  249. char    *ptr;        /* general pointer */
  250. char    search[BUFSIZE];    /* search string buffer */
  251. int    found = FALSE,    /* flag to say we've found something */
  252.     quit = FALSE,    /* flag used when ready to quit */
  253.     index,        /* used when searching */
  254.     top = 0,
  255.     counter,    /* used when counting */
  256.     ch;        /* input character */
  257.  
  258.     
  259.     DIR *dirp;
  260.     struct direct *direntp;
  261.  
  262.     if (groupname == (char *)NULL) return;
  263.     if (strlen(groupname) == 0) return;
  264. /* Allow two extra bytes, one for terminating null and
  265.  * the other for the separating '/' if needed. */
  266.     dir = (char *)wallop(strlen(NEWSBASE)+strlen(groupname)+2);
  267.     strcpy(dir,NEWSBASE);
  268.     if (dir[strlen(dir)-1] != '/') strcat(dir,"/");    
  269.     strcat(dir,groupname);
  270.     /* convert newsgroup name to directory name */
  271.     while ((ptr = strchr(dir,'.')) != (char *) NULL)
  272.         *ptr = '/';
  273.     if ((dirp = opendir(dir)) == NULL)
  274.     {
  275.         move(eeplines - 1,0);
  276.         deleteln();
  277.         printw("Cannot open %s",dir);
  278.         move(current,0);
  279.         refresh();
  280.         sleep(2);
  281.         return;
  282.     }
  283.     move(eeplines - 1,0);
  284.     deleteln();
  285.     printw("Opening %s",dir);
  286.     refresh();
  287.     news_index = 0;
  288.     errno = 0;
  289.     while ((direntp = readdir(dirp)) != NULL) {
  290.         artnum_tmp = atol(direntp->d_name);
  291.         if (artnum_tmp <= 0) continue;
  292.  
  293.         /* atol() will be fooled by filenames that start with
  294.          * digits, so let's confirm that it has only digits. */
  295.  
  296.         ptr = direntp->d_name;
  297.         while (isdigit((int)(*ptr))) ptr++;
  298.         if (*ptr != '\0') break; /* should point to terminating null */
  299.  
  300.         if ((art_ptr = (struct newsview *)wallop(sizeof(struct newsview))) == 
  301.             (struct newsview *) NULL) {
  302.             fprintf(stderr,"Memory allocation error!\n");
  303.             cleanup();
  304.         }
  305.         article[news_index] = art_ptr;
  306.         art_ptr->artnum = artnum_tmp;
  307.         art_ptr->size = 0L;
  308.         art_ptr->from = nirvana;
  309.         art_ptr->date = nirvana;
  310.         art_ptr->msgid = nirvana;
  311.         art_ptr->subject = nirvana;
  312.         art_ptr->keywords = nirvana;
  313.         art_ptr->references = nirvana;
  314.         news_index++;
  315.     }
  316. /*    closedir(dirp); */
  317.     if (errno != 0)
  318.         fprintf(stderr,"Error reading directory %s\n",dir);
  319.  
  320.     art_count = news_index;
  321.     if (art_count == 0) {
  322.         move(eeplines - 1,0);
  323.         deleteln();
  324.         printw("No articles found in %s",dir);
  325.         refresh();
  326.         sleep(2);
  327.         return;
  328.     }
  329.  
  330. /* We have now read in the directory, keeping only those file names
  331.  * which are numeric.  (We're ignoring aberrant files with leading
  332.  * zeros -- this assumes standard news files.)
  333.  *   Now we shall sort this into numerical order. */
  334.  
  335.     qsort( article, (unsigned) art_count, 
  336.         (int) sizeof(article[0]), artnum_compare);
  337.  
  338.  /* Now let's read each file to get some basic info on it.  */
  339.  
  340.     news_index = 0;
  341.     while (news_index < art_count) {
  342.         /* Start by initializing the data element */
  343.         art_ptr = article[news_index];
  344.         if (art_ptr == (struct newsview *)NULL) {
  345.             news_index++;
  346.             continue;
  347.         }
  348.         sprintf(buffer, "%s/%ld", dir, art_ptr->artnum); 
  349.         if ((farticle = fopen(buffer,"r")) == (FILE *)NULL) {
  350.             news_index++;
  351.             continue;
  352.         }
  353.         while (fgets(buffer,BUFSIZE,farticle) != (char *)NULL) {
  354.  
  355.             /* Since we're reading headers, break at the first
  356.              * line that isn't part of a header, especially
  357.              * the blank line that separates the header from
  358.              * the body of the message
  359.              */
  360.             if ((buffer[0] == '#') ||
  361.                 (buffer[0] == '\n') ||
  362.                 (buffer[0] == '\r') ||
  363.                 (buffer[0] == '\0'))
  364.                 break;
  365.     
  366.         /* Now allocate memory for article headers */
  367.  
  368.             ptr = shift_lower(strtok(buffer," \t\r\n"));
  369.  
  370.             if (strcmp(ptr,"from:") == 0) {
  371.                 ptr = strtok((char *)NULL,"\r\n");
  372.                 if ((art_ptr->from = (char *) wallop(strlen(ptr)+1)) 
  373.                     == (char *)NULL) {
  374.                     printf("Error while allocating memory!\n");
  375.                     sleep(2);
  376.                     return;
  377.                 }
  378.                 strcpy(art_ptr->from,ptr);
  379.                 continue;
  380.             }
  381.  
  382.             if (strcmp(ptr,"date:") == 0) {
  383.                 ptr = strtok((char *)NULL,"\r\n");
  384.                 if ((art_ptr->date = (char *) wallop(strlen(ptr)+1)) 
  385.                     == (char *)NULL) {
  386.                     printf("Error while allocating memory!\n");
  387.                     sleep(2);
  388.                     return;
  389.                 }
  390.                 strcpy(art_ptr->date,ptr);
  391.                 continue;
  392.             }
  393.  
  394.             if (strcmp(ptr,"message-id:") == 0) {
  395.                 ptr = strtok((char *)NULL,"\r\n");
  396.                 if ((art_ptr->msgid = (char *) wallop(strlen(ptr)+1)) 
  397.                     == (char *)NULL) {
  398.                     printf("Error while allocating memory!\n");
  399.                     sleep(2);
  400.                     return;
  401.                 }
  402.                 strcpy(art_ptr->msgid,ptr);
  403.                 continue;
  404.             }
  405.  
  406.             if (strcmp(ptr,"subject:") == 0) {
  407.                 ptr = strtok((char *)NULL,"\r\n");
  408.                 if ((art_ptr->subject = (char *) wallop(strlen(ptr)+1)) 
  409.                     == (char *)NULL) {
  410.                     printf("Error while allocating memory!\n");
  411.                     sleep(2);
  412.                     return;
  413.                 }
  414.                 strcpy(art_ptr->subject,ptr);
  415.                 continue;
  416.             }
  417.  
  418.             if (strcmp(ptr,"references:") == 0) {
  419.                 ptr = strtok((char *)NULL,"\r\n");
  420.                 if ((art_ptr->references = (char *) wallop(strlen(ptr)+1)) 
  421.                     == (char *)NULL) {
  422.                     printf("Error while allocating memory!\n");
  423.                     sleep(2);
  424.                     return;
  425.                 }
  426.                 strcpy(art_ptr->references,ptr);
  427.                 continue;
  428.             }
  429.  
  430.             if (strcmp(ptr,"keywords:") == 0) {
  431.                 ptr = strtok((char *)NULL,"\r\n");
  432.                 if ((art_ptr->keywords = (char *) wallop(strlen(ptr)+1)) 
  433.                     == (char *)NULL) {
  434.                     printf("Error while allocating memory!\n");
  435.                     sleep(2);
  436.                     return;
  437.                 }
  438.                 strcpy(art_ptr->keywords,ptr);
  439.                 continue;
  440.             }
  441.         }
  442.     fclose(farticle);
  443.         news_index++;
  444.     }
  445.     
  446.  
  447. #ifdef UNIX
  448.     idlok(stdscr,TRUE);
  449. #endif /* UNIX */
  450.  
  451.     showarts(0);
  452.     art_current = 0;
  453.  
  454.     while (quit == FALSE) {
  455.     ch = getch();
  456.     switch(ch) {
  457.         case 'q':    /* quit */
  458.         case 'Q':
  459.         case '\033':    /* ESCAPE by itself */
  460.         case '\003':    /* for those who like ^C */
  461.         case '\177':    /* for those who like INTR */
  462.             quit = TRUE;
  463.             break;
  464.  
  465.         case '?':    /* on-line help */
  466.         case 'h':
  467.         case 'H':
  468.         case KEY_F(1):
  469. #ifdef KEY_HELP
  470.         case KEY_HELP:
  471. #endif
  472.             over = newwin(13,61,8,15);
  473.             if (!eepoint) wstandout(over);
  474.             box(over,'\0','\0');
  475.             if (!eepoint) wstandend(over);
  476.             wmove(over,2,5);
  477.             wstandout(over);
  478.             waddstr(over," EEP! v1.8: helpful .newsrc editor ");
  479.             wstandend(over);
  480.             wmove(over,3,5);
  481.             waddstr(over,"       Newsgroup browser submenu");
  482.             wmove(over,5,5);
  483.             waddstr(over,"t   Top of file     b   Bottom of file");
  484.             wmove(over,6,5);
  485.             waddstr(over,"i   Show info       j   Next line");
  486.             wmove(over,7,5);
  487.             waddstr(over,"k   Previous line   p   Pointer change");
  488.             wmove(over,8,5);
  489.             waddstr(over,"q   Quit to main    r   Redraw screen");
  490.             wmove(over,9,5);
  491.             waddstr(over,"^D  Page down       ^U  Page up");
  492.             wmove(over,10,5);
  493.             waddstr(over,"?   This help");
  494.             wmove(over,12,5);
  495.             wstandout(over);
  496.             waddstr(over," Press SPACE BAR to exit from help ");
  497.             wstandend(over);
  498.             wrefresh(over);
  499.             ch = wgetch(over);
  500.             delwin(over);
  501.             touchwin(stdscr);
  502.             refresh();
  503.             break;
  504.  
  505.         case 'r':    /* redraw */
  506.         case 'R':    /* redraw */
  507.         case '\014':    /* form feed ^L */
  508. #ifdef KEY_REFRESH
  509.         case KEY_REFRESH:
  510. #endif
  511.             touchwin(stdscr);
  512.             clearok(stdscr,TRUE);
  513.             refresh();
  514.             break;
  515.  
  516.         case 'i':
  517.             if ((art_ptr = article[art_current]) == (struct newsview *)NULL) 
  518.                 break;
  519.             over = newwin(18,67,0,2);
  520.             if (!eepoint) wstandout(over);
  521.             box(over,'\0','\0');
  522.             if (!eepoint) wstandend(over);
  523.             wmove(over,2,2);
  524.             wprintw(over,"No. : %ld",art_ptr->artnum);
  525.             wmove(over,3,2);
  526.             wprintw(over,"From: %.57s",art_ptr->from);
  527.             wmove(over,4,2);
  528.             wprintw(over,"Subj: %.57s",art_ptr->subject);
  529.             wmove(over,5,2);
  530.             wprintw(over,"MsID: %.57s",art_ptr->msgid);
  531.             wmove(over,6,2);
  532.             wprintw(over,"Refs: %.57s",art_ptr->references);
  533.             wmove(over,7,2);
  534.             wprintw(over,"Date: %.57s",art_ptr->date);
  535.             wmove(over,8,2);
  536.             wprintw(over,"Keys: %.57s",art_ptr->keywords);
  537.             wmove(over,17,9);
  538.             wstandout(over);
  539.             waddstr(over," Press SPACE BAR to continue ");
  540.             wstandend(over);
  541.             wrefresh(over);
  542.             ch = wgetch(over);
  543.             delwin(over);
  544.             touchwin(stdscr);
  545.             refresh();
  546.             break;
  547.  
  548.  
  549.         case 't':
  550.         case 'T':
  551.         case '^':    /* top of list */
  552. #ifdef KEY_HOME
  553.         case KEY_HOME:
  554. #endif
  555.             art_current = 0;
  556.             viewpos = 0;
  557.             showarts(art_current);
  558.             break;
  559.  
  560.         case 'b':
  561.         case 'B':
  562.         case '$':    /* bottom of list */
  563. #ifdef KEY_SHOME
  564.         case KEY_SHOME:
  565. #endif
  566.             art_current = art_count - 1;
  567.             if (art_current < eeplines - 1) 
  568.                 viewpos = art_current;
  569.             else
  570.                 viewpos = eeplines - 2;
  571.             showarts(art_current);
  572.             break;
  573.  
  574.  
  575.         case ' ':
  576.         case 'j':
  577.         case 'J':    /* join */
  578.         case '\016':    /* for emacs users */
  579. #ifdef KEY_DOWN
  580.         case KEY_DOWN:
  581. #endif
  582. scroll_down:
  583.         /* Don't move if we're at the end. */
  584.             if (art_current == art_count - 1) {
  585.                 beep();
  586.                 break;
  587.             }
  588.             /* remove highlights by redrawing line */
  589.             art_ptr = article[art_current];
  590.             move(viewpos,0);
  591.             clrtoeol();
  592.             if (!eepoint) standend();
  593.             if ((art_current >= 0) && (art_current < art_count)) {
  594.                 printw("  ");
  595.                 art_ptr = article[art_current];
  596.                 printw("%8ld", art_ptr->artnum);
  597.                 move(viewpos,11);
  598.                 printw("%.38s", art_ptr->subject);
  599.                 move(viewpos,50);
  600.                 printw("%.28s", art_ptr->from);
  601.                 move(viewpos,0);
  602.             } else clrtoeol();
  603.             art_current++;
  604.             if (++viewpos == eeplines - 1) { /* scroll up */
  605.                 move(0,0);
  606.                 deleteln();
  607.                 move(eeplines - 2,0);
  608.                 insertln();
  609.                 viewpos = eeplines - 2;
  610.                 top++;
  611.             };
  612.             /* Now paint our new position */
  613.             move(viewpos,0);
  614.             clrtoeol();
  615.             art_ptr = article[art_current];
  616.             if (!eepoint) standout();
  617.             if ((art_current >= 0) && (art_current < art_count)) {
  618.                 printw("->");
  619.                 art_ptr = article[art_current];
  620.                 printw("%8ld", art_ptr->artnum);
  621.                 move(viewpos,11);
  622.                 printw("%.38s", art_ptr->subject);
  623.                 move(viewpos,50);
  624.                 printw("%.28s", art_ptr->from);
  625.                 move(viewpos,0);
  626.             } else clrtoeol();
  627.             if (!eepoint) standend();
  628.             move(viewpos,0);
  629.             refresh();
  630.             break;
  631.  
  632.         case 'k':
  633.         case 'K':
  634.         case '\010':    /* backspace */
  635.         case '\020':    /* for emacs users */
  636. #ifdef KEY_UP
  637.         case KEY_UP:
  638. #endif
  639.         /* Don't move if we're at the top. */
  640.             if (art_current == 0) {
  641.                 beep();
  642.                 break;
  643.             }
  644.             move(viewpos,0);
  645.             clrtoeol();
  646.             if (!eepoint) standend();
  647.             if ((art_current >= 0) && (art_current < art_count)) {
  648.                 printw("  ");
  649.                 art_ptr = article[art_current];
  650.                 printw("%8ld", art_ptr->artnum);
  651.                 move(viewpos,11);
  652.                 printw("%.38s", art_ptr->subject);
  653.                 move(viewpos,50);
  654.                 printw("%.28s", art_ptr->from);
  655.                 move(viewpos,0);
  656.             } else clrtoeol();
  657.             refresh();
  658.             art_current--;
  659.             if (--viewpos == -1) {
  660.                 move(eeplines - 2,0);
  661.                 deleteln();
  662.                 move(0,0);
  663.                 insertln();
  664.                 refresh();
  665.                 move(0,0);
  666.                 viewpos = 0;
  667.                 if (top > 0) top--;
  668.             }; /* cause scroll */
  669.             move(viewpos,0);
  670.             clrtoeol();
  671.             art_ptr = article[art_current];
  672.             if (!eepoint) standout();
  673.             if ((art_current >= 0) && (art_current < art_count)) {
  674.                 printw("->");
  675.                 art_ptr = article[art_current];
  676.                 printw("%8ld", art_ptr->artnum);
  677.                 move(viewpos,11);
  678.                 printw("%.38s", art_ptr->subject);
  679.                 move(viewpos,50);
  680.                 printw("%.28s", art_ptr->from);
  681.                 move(viewpos,0);
  682.             } else clrtoeol();
  683.             if (!eepoint) standend();
  684.             move(viewpos,0);
  685.             refresh();
  686.             break;
  687.  
  688.         case '\004':    /* ^D */
  689.         case '\006':    /* ^F */
  690. #ifdef KEY_NPAGE
  691.         case KEY_NPAGE: /* next page */
  692. #endif
  693.  
  694.             /* If a pagedown will go past the end
  695.             of the list, simply position at the end. */
  696.  
  697.             if (art_current == art_count - 1) {
  698.                 beep();
  699.                 break;
  700.             }
  701.             if ((art_current += eeppage) >= art_count) {
  702.                 art_current = art_count - 1;
  703.                 if ((art_count - art_current) < (eeplines - 2))
  704.                     viewpos = eeplines - 2;
  705.             } else  if (viewpos + eeppage < eeplines - 2)
  706.                     viewpos += eeppage; 
  707.             showarts(art_current);
  708.             break;
  709.  
  710.         case '\025':    /* ^U */
  711.         case '\002':    /* ^B */
  712. #ifdef KEY_PPAGE
  713.         case KEY_PPAGE: /* previous page */
  714. #endif
  715.             if (art_current == 0) {
  716.                 beep();
  717.                 break;
  718.             }
  719.             if ((art_current -= eeppage) < 0) {
  720.                 art_current = 0;
  721.                 viewpos = 0;
  722.             } else  if ((viewpos - eeppage) >= 0)
  723.                     viewpos -= eeppage;
  724.             showarts(art_current);
  725.             break;
  726.  
  727.         case 'p':   /* change type of pointer */
  728.         case 'P':
  729.             if (eepoint) eepoint = FALSE;
  730.             else eepoint = TRUE;
  731.             showarts(art_current);
  732.             break;
  733.  
  734.         }
  735.     }
  736. }
  737.  
  738. /* showarts() -- show list of articles by number */
  739.  
  740. void    showarts(art_current)
  741. int    art_current;
  742. {
  743. int    index, counter;
  744.  
  745.     erase();    /* clear screen */
  746.     counter = 0;
  747.     index = art_current - viewpos;
  748.     while (counter < (eeplines - 1)) {
  749.         move(counter,0);
  750.         if (counter == viewpos) {
  751.             if (!eepoint) standout();
  752.             printw("->");
  753.         } else    printw("  ");
  754.         if ((index >= 0) && (index < art_count)) {
  755.             art_ptr = article[index];
  756.             printw("%8ld", art_ptr->artnum);
  757.             move(counter,11);
  758.             printw("%.38s", art_ptr->subject);
  759.             move(counter,50);
  760.             printw("%.28s", art_ptr->from);
  761.             move(counter,0);
  762.             if ((counter == viewpos) && !eepoint) 
  763.                 standend();
  764.         } else clrtoeol();
  765.         index++;
  766.         counter++;
  767.     }
  768.     move(eeplines - 1,0);
  769.     clrtoeol();
  770.     printw("There are %d articles in %s",art_count,dir);
  771.     move(eeplines - 1,60);
  772.     printw("Press ? for Help");
  773.     move(viewpos,0);
  774.     refresh();
  775. }
  776.