home *** CD-ROM | disk | FTP | other *** search
/ PC-Online 1998 February / PCOnline_02_1998.iso / filesbbs / os2 / pgp263.arj / PGP263I.SRC / PGP263II.ZIP / src / more.c < prev    next >
C/C++ Source or Header  |  1996-01-06  |  13KB  |  491 lines

  1. /*      more.c  - Unix-style "more" paging output for PGP.
  2.    PGP: Pretty Good(tm) Privacy - public key cryptography for the masses.
  3.  
  4.    (c) Copyright 1990-1996 by Philip Zimmermann.  All rights reserved.
  5.    The author assumes no liability for damages resulting from the use
  6.    of this software, even if the damage results from defects in this
  7.    software.  No warranty is expressed or implied.
  8.  
  9.    Note that while most PGP source modules bear Philip Zimmermann's
  10.    copyright notice, many of them have been revised or entirely written
  11.    by contributors who frequently failed to put their names in their
  12.    code.  Code that has been incorporated into PGP from other authors
  13.    was either originally published in the public domain or is used with
  14.    permission from the various authors.
  15.  
  16.    PGP is available for free to the public under certain restrictions.
  17.    See the PGP User's Guide (included in the release package) for
  18.    important information about licensing, patent restrictions on
  19.    certain algorithms, trademarks, copyrights, and export controls.
  20.  */
  21.  
  22. #include <ctype.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #ifdef UNIX
  27. #include <sys/types.h>
  28. #endif
  29. #ifdef sco
  30. #include <sys/stream.h>
  31. #include <sys/ptem.h>
  32. FILE *popen();
  33. #endif
  34. #include "system.h"
  35. #include "mpilib.h"
  36. #include "language.h"
  37. #include "fileio.h"
  38. #include "pgp.h"
  39. #include "more.h"
  40. #include "charset.h"
  41.  
  42. #ifdef MACTC5
  43. #include "Macutil3.h"
  44. #include "MacPGP.h"
  45. #define DEFAULT_LINES    23
  46. #define DEFAULT_COLUMNS    77
  47. #else
  48. #if defined(MSDOS) || defined(WIN32)
  49. #ifndef __GO32__
  50. #include <conio.h>
  51. #endif
  52. #define DEFAULT_LINES    25    /* MSDOS actually has a 25-line screen */
  53. #else
  54. #define DEFAULT_LINES    24
  55. #endif                /* MSDOS */
  56. #define DEFAULT_COLUMNS    80
  57. #endif /* MACTC5 */
  58.  
  59. static int screen_lines = DEFAULT_LINES, screen_columns = DEFAULT_COLUMNS;
  60.  
  61. #ifndef EBCDIC                  /* already defined in usuals.h */
  62. #define TAB        0x09    /* ASCII tab char */
  63. #define CR        '\r'    /* Carriage return char */
  64. #define LF        '\n'    /* Linefeed */
  65. #endif
  66.  
  67. /* Get the screen size for 'more'.  The environment variables $LINES and
  68.    $COLUMNS will be used if they exist.  If not, then the TIOCGWINSZ call to
  69.    ioctl() is used (if it is defined).  If not, then the TIOCGSIZE call to
  70.    ioctl() is used (if it is defined).  If not, then the WIOCGETD call to
  71.    ioctl() is used (if it is defined).  If not, then get the info from
  72.    terminfo/termcap (if it is there).  Otherwise, assume we have a 24x80
  73.    model 33.
  74.  
  75.    That was for Unix.
  76.  
  77.    For DOS, just assume 24x80. */
  78.  
  79. #ifdef UNIX
  80. /* Try to access terminfo through the termcap-interface in the curses library
  81.    (which requires linking with -lcurses) or use termcap directly (which
  82.    requires linking with -ltermcap) */
  83.  
  84. #ifndef USE_TERMCAP
  85. #ifdef USE_TERMINFO
  86. #define USE_TERMCAP
  87. #endif
  88. #ifdef USE_CURSES
  89. #define USE_TERMCAP
  90. #endif
  91. #endif
  92.  
  93. #ifdef USE_TERMCAP
  94. #define TERMBUFSIZ    1024
  95. #define UNKNOWN_TERM  "unknown"
  96. #define DUMB_TERMBUF  "dumb:co#80:hc:"
  97.  
  98. extern int tgetent(), tgetnum();
  99. #endif
  100.  
  101. /* Try to get TIOCGWINSZ from termios.h, then from sys/ioctl.h */
  102. #ifndef NOTERMIO
  103. #ifdef SVR2
  104. #include <termio.h>
  105. #else
  106. #include <termios.h>
  107. #endif                /* SVR2 */
  108. #endif
  109.  
  110. #ifdef __FreeBSD__
  111. #include <sys/ioctl.h>          /* for ioctl() prototype too */
  112. #else
  113. #ifndef SVR2
  114. #ifndef TIOCGWINSZ
  115. #ifndef TIOCGSIZE
  116. #ifndef WIOCGETD
  117. #include <sys/ioctl.h>
  118. #endif                /* not WIOCGETD */
  119. #endif                /* not TIOCGSIZE */
  120. #endif                /* not TIOCGWINSZ */
  121. #endif
  122.  
  123. /* If we still dont have TIOCGWINSZ (or TIOCGSIZE) try for WIOCGETD */
  124. #ifndef TIOCGWINSZ
  125. #ifndef TIOCGSIZE
  126. #ifndef WIOCGETD
  127. #include <sgtty.h>
  128. #endif                /* not WIOCGETD */
  129. #endif                /* not TIOCGSIZE */
  130. #endif                /* not TIOCGWINSZ */
  131. #endif                /* not SVR2 */
  132. #endif                /* UNIX */
  133. #ifdef __PUREC__
  134. #include <ext.h>
  135. #endif
  136.  
  137. static void getScreenSize(void)
  138. {                /* Rot bilong kargo */
  139.     /* Return the screen size */
  140.     char *envLines, *envColumns;
  141.     long rowTemp = 0, colTemp = 0;
  142. #ifdef UNIX
  143. #ifdef USE_TERMCAP
  144.     char termBuffer[TERMBUFSIZ], *termInfo;
  145. #endif
  146. #ifdef TIOCGWINSZ
  147.     struct winsize windowInfo;
  148. #else
  149. #ifdef TIOCGSIZE
  150.     struct ttysize windowInfo;
  151. #else
  152. #ifdef WIOCGETD
  153.     struct uwdata windowInfo;
  154. #endif                /* WIOCGETD */
  155. #endif                /* TIOCGSIZE */
  156. #endif                /* TIOCGWINSZ */
  157.  
  158.     /* Make sure that we're outputting to a terminal */
  159.     if (!isatty(fileno(stderr))) {
  160.     screen_lines = DEFAULT_LINES;
  161.     screen_columns = DEFAULT_COLUMNS;
  162.     return;
  163.     }
  164.     screen_lines = screen_columns = 0;
  165. #endif                /* UNIX */
  166.  
  167.     /* LINES & COLUMNS environment variables override everything else */
  168.     envLines = getenv("LINES");
  169.     if (envLines != NULL && (rowTemp = atol(envLines)) > 0)
  170.     screen_lines = (int) rowTemp;
  171.  
  172.     envColumns = getenv("COLUMNS");
  173.     if (envColumns != NULL && (colTemp = atol(envColumns)) > 0)
  174.     screen_columns = (int) colTemp;
  175.  
  176. #ifdef UNIX
  177. #ifdef TIOCGWINSZ
  178.     /* See what ioctl() has to say (overrides terminfo & termcap) */
  179.     if ((!screen_lines || !screen_columns) &&
  180.     ioctl(fileno(stderr), TIOCGWINSZ, &windowInfo)
  181.     != -1) {
  182.     if (!screen_lines && windowInfo.ws_row > 0)
  183.         screen_lines = (int) windowInfo.ws_row;
  184.  
  185.     if (!screen_columns && windowInfo.ws_col > 0)
  186.         screen_columns = (int) windowInfo.ws_col;
  187.     }
  188. #else
  189. #ifdef TIOCGSIZE
  190.     /* See what ioctl() has to say (overrides terminfo & termcap) */
  191.     if ((!screen_lines || !screen_columns) &&
  192.     ioctl(fileno(stderr), TIOCGSIZE, &windowInfo) != -1) {
  193.     if (!screen_lines && windowInfo.ts_lines > 0)
  194.         screen_lines = (int) windowInfo.ts_lines;
  195.  
  196.     if (!screen_columns && windowInfo.ts_cols > 0)
  197.         screen_columns = (int) windowInfo.ts_cols;
  198.     }
  199. #else
  200. #ifdef WIOCGETD
  201.     /* See what ioctl() has to say (overrides terminfo & termcap) */
  202.     if ((!screen_lines || !screen_columns) &&
  203.     ioctl(fileno(stderr), WIOCGETD, &windowInfo) != -1) {
  204.     if (!screen_lines && windowInfo.uw_height > 0)
  205.         screen_lines = (int) (windowInfo.uw_height / windowInfo.uw_vs);
  206.  
  207.     if (!screen_columns && windowInfo.uw_width > 0)
  208.         screen_columns = (int) (windowInfo.uw_width / windowInfo.uw_hs);
  209.     }                /* You are in a twisty maze of standards,
  210.                    all different */
  211. #endif
  212. #endif
  213. #endif
  214.  
  215. #ifdef USE_TERMCAP
  216.     /* See what terminfo/termcap has to say */
  217.     if (!screen_lines || !screen_columns) {
  218.     if ((termInfo = getenv("TERM")) == (char *) NULL)
  219.         termInfo = UNKNOWN_TERM;
  220.  
  221.     if ((tgetent(termBuffer, termInfo) <= 0))
  222.         strcpy(termBuffer, DUMB_TERMBUF);
  223.  
  224.     if (!screen_lines && (rowTemp = tgetnum("li")) > 0)
  225.         screen_lines = (int) rowTemp;
  226.  
  227.     if (!screen_columns && (colTemp = tgetnum("co")) > 0)
  228.         screen_columns = (int) colTemp;
  229.     }
  230. #endif
  231.     if (screen_lines == 0)    /* nothing worked, use defaults */
  232.     screen_lines = DEFAULT_LINES;
  233.     if (screen_columns == 0)
  234.     screen_columns = DEFAULT_COLUMNS;
  235. #endif                /* UNIX */
  236. }
  237.  
  238. #ifdef ATARI
  239. #define reverse_attr()    printf("\033p")
  240. #define norm_attr()    printf("\033q")
  241. #else
  242. #define reverse_attr()
  243. #define norm_attr()
  244. #endif
  245.  
  246.  
  247. #ifdef VMS
  248. char pager[80] = "Type/Page";    /* default pager for VMS */
  249. #else                /* not VMS */
  250. char pager[80] = "";
  251. #endif                /* not VMS */
  252.  
  253. /* Blort a file to the screen with page breaks, intelligent handling of line
  254.    terminators, truncation of overly long lines, and zapping of illegal
  255.    chars */
  256. int more_file(char *fileName, boolean eyes_only)
  257. {
  258.     FILE *inFile;
  259.     int lines = 0, ch, i, chars = 0, c;
  260.     long fileLen;
  261.     char cmd[MAX_PATH];
  262.     char buf[16];
  263.     int lineno;
  264.     char *p;
  265.  
  266.     if ((inFile = fopen(fileName, FOPRBIN)) == NULL)
  267.     /* Can't see how this could fail since we just created the file */
  268.     return -1;
  269.  
  270.     fread(buf, 1, 16, inFile);
  271.     if (compressSignature((byte *) buf) >= 0) {
  272.     fprintf(pgpout,
  273.         LANG("\n\007File '%s' is not a text file; cannot display.\n"),
  274.         fileName);
  275.     return -1;
  276.     }
  277.     /* PAGER set in config.txt overrides environment variable, 
  278.        set PAGER in config.txt to 'pgp' to use builtin pager */
  279.     if (pager[0] == '\0') {
  280.     if ((p = getenv("PAGER")) != NULL)
  281.         strncpy(pager, p, sizeof(pager) - 1);
  282.     }
  283.     if (strcmp(pager, "cat") == 0) {
  284.     fclose(inFile);
  285.     writePhantomOutput(fileName);
  286.     return 0;
  287.     }
  288.     /* Use built-in pager if PAGER is not set or if the message
  289.        is for your eyes only */
  290.     if (!eyes_only && (strlen(pager) != 0) && strcmp("pgp", pager)) {
  291.     fclose(inFile);
  292. #ifdef UNIX
  293.     if (strchr(fileName, '\'') != NULL)
  294.         return -1;
  295.     sprintf(cmd, "%s '%s'", pager, fileName);
  296. #else
  297.     sprintf(cmd, "%s %s", pager, fileName);
  298. #if defined(MSDOS) || defined(WIN32)
  299.     for (p = cmd; *p; ++p)
  300.         if (*p == '/')
  301.         *p = '\\';
  302. #endif
  303. #endif
  304.     fflush(pgpout);
  305. #ifdef MACTC5
  306.     return 0;
  307. #else
  308.     return system(cmd);
  309. #endif
  310.     }
  311. #ifdef UNIX
  312.     if (!isatty(fileno(stdout))) {
  313.     fclose(inFile);
  314.     writePhantomOutput(fileName);
  315.     return 0;
  316.     }
  317. #endif                /* UNIX */
  318.  
  319.     getScreenSize();
  320.  
  321.     /* Get file length */
  322.     fseek(inFile, 0L, SEEK_END);
  323.     fileLen = ftell(inFile);
  324.     rewind(inFile);
  325.     lineno = 1;
  326.  
  327.     ttycbreak();
  328.  
  329.     putchar('\n');
  330.     for (;;) {
  331.     ch = getc(inFile);
  332.     if (ch == LF) {
  333.         lines++;
  334.         putchar('\n');
  335.         chars = 0;
  336.         ++lineno;
  337.     } else if (ch == CR) {
  338.         lines++;
  339.         putchar('\n');
  340.         chars = 0;
  341.         ++lineno;
  342.  
  343.         /* Skip following LF if there is one */
  344.         if ((ch = getc(inFile)) != LF && ch != EOF)
  345.         ungetc(ch, inFile);
  346.     } else if (((unsigned char) ch >= ' ' && ch != EOF) || ch == TAB) {
  347.         /* Legal char or tab, print it */
  348.         putchar(ch);
  349.         chars += (ch == TAB) ? 8 : 1;
  350.     }
  351.     /* If we've reach the max.no of columns we can handle, skip the
  352.        rest of the line */
  353.     if (chars == screen_columns - 1) {
  354.         chars = 0;
  355.         while ((ch = getc(inFile)) != CR && ch != LF && ch != EOF);
  356.         if (ch != EOF)
  357.         ungetc(ch, inFile);
  358.     }
  359.     /* If we've reached the max.no of rows we can handle, wait for the
  360.        user to hit a key */
  361.     while (ch == EOF || lines == screen_lines - 1) {
  362.         /* Print prompt at end of screen */
  363.         reverse_attr();
  364.         if (ch == EOF)
  365.         printf(LANG("\nDone...hit any key\r"));
  366.         else
  367. #ifdef MACTC5    /* 203a : ftell() tells us nothing useful */
  368.         printf(LANG("-- More -- Space: next screen, Enter: next line\
  369. , 'B': back, 'Q': quit --\r"));
  370. #else
  371.         printf(
  372. LANG("More -- %d%% -- Space: next screen, Enter: next line\
  373. , 'B': back, 'Q': quit --\r"),
  374.                (100 * ftell(inFile)) / fileLen);
  375. #endif /* MACTC5 */
  376.         norm_attr();
  377.         fflush(stdout);
  378.         c = getch();
  379.         c = toupper(c);
  380.  
  381.         /* Blank out prompt */
  382.         for (i = 0; i < 79; i++)
  383.         putchar(' ');
  384.         putchar('\r');
  385.         fflush(stdout);
  386.         if (c == 'B' && lineno > screen_lines) {
  387.         /* go Back a page */
  388.         int seek_line = lineno - 2 * screen_lines + 3;
  389.         lineno = 1;
  390.         rewind(inFile);
  391.         if (seek_line > 1) {
  392.             printf("...skipping\n");
  393.             while ((ch = getc(inFile)) != EOF)
  394.             if (ch == '\n')
  395.                 if (++lineno == seek_line)
  396.                 break;
  397.         }
  398.         ch = '\0';
  399.         lines = 0;
  400.         } else {
  401. #if defined(MSDOS) || defined(__MSDOS__)
  402.         if (c == 'Q' || c == 0x1B || ch == EOF)
  403. #else
  404.         if (c == 'Q' || ch == EOF)
  405. #endif
  406.             goto done;
  407.         if (c == ' ' || c == '\n' || c == '\r' || c == 'J')
  408.             lines -= (c == ' ') ? screen_lines - 2 : 1; /* Do n more
  409.                                    lines */
  410.         }
  411.     }
  412.     }
  413.   done:
  414.     ttynorm();
  415.  
  416.     fclose(inFile);
  417.     return 0;
  418. }                /* more_file */
  419.  
  420.  
  421. /*
  422.  * open_more() and close_more() redirect pgpout to the pager.
  423.  *
  424.  */
  425.  
  426. static char *mfile = NULL;
  427. static boolean piping = FALSE;
  428. static FILE *savepgpout;
  429.  
  430.  
  431. int open_more(void)
  432. {
  433. #ifdef UNIX
  434.     char *p;
  435. #endif
  436.  
  437.     if (mfile || piping)
  438.     close_more();
  439.  
  440.     savepgpout = pgpout;
  441. #ifdef UNIX
  442.     fflush(pgpout);
  443.     if (pager[0] == '\0') {
  444.     if ((p = getenv("PAGER")) != NULL)
  445.         strncpy(pager, p, sizeof(pager) - 1);
  446.     }
  447.     /* Use built-in pager if PAGER is not set or set to "pgp" */
  448.     if ((strlen(pager) != 0) && strcmp("pgp", pager)) {
  449.     if ((pgpout = popen(pager, "w")) != NULL) {
  450.         piping = TRUE;
  451.         return 0;
  452.     }
  453.     perror("popen");
  454.     pgpout = savepgpout;
  455.     }
  456. #endif
  457.     if ((mfile = tempfile(TMP_TMPDIR | TMP_WIPE)) == NULL)
  458.     return -1;
  459.     if ((pgpout = fopen(mfile, FOPWTXT)) == NULL) {
  460.     pgpout = savepgpout;
  461.     rmtemp(mfile);
  462.     return -1;
  463.     }
  464.     /* user will not see anything until close_more() is called */
  465.     fprintf(savepgpout, LANG("Just a moment..."));
  466.     fflush(savepgpout);
  467.     return 0;
  468. }
  469.  
  470. int close_more(void)
  471. {
  472.     if (!mfile && !piping)
  473.     return 0;
  474.  
  475. #ifdef UNIX
  476.     if (piping)
  477.     pclose(pgpout);
  478.     else
  479. #endif
  480.     fclose(pgpout);
  481.     pgpout = savepgpout;
  482.     if (mfile) {
  483.     fprintf(pgpout, "\n");
  484.     more_file(mfile, FALSE);
  485.     rmtemp(mfile);
  486.     mfile = NULL;
  487.     }
  488.     piping = FALSE;
  489.     return 0;
  490. }
  491.