home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / msg / msg4.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-05-11  |  17.4 KB  |  852 lines

  1. /*
  2.  *            M S G 4 . C
  3.  *
  4.  * This is the fourth part of the MSG program.
  5.  *
  6.  * Functions -
  7.  *    txtmtch        search for given pattern in text of messages
  8.  *    mainbox        test to see if we are processing home mailbox
  9.  *    gethead        fetch and scan header from message on disk
  10.  *    gothdr        check input line for header field match
  11.  *    prefix        compare string to RFC822 header line prefix
  12.  *    confirm        ask a yes/no question
  13.  *    gather        read in a line
  14.  *    suckup        discard rest of line
  15.  *    echochar
  16.  *    ttychar
  17.  *    tt_init        fetch tty modes
  18.  *    tt_raw        switch to raw mode
  19.  *    tt_norm        switch to cooked mode
  20.  *    onint        interrupt catcher
  21.  *    onnopipe    broken pipe catcher
  22.  *    onhangup    hangup signal catcher
  23.  *    onstop        stop signal catcher
  24.  *    error        error handler
  25.  *    xomsgrc        sets up xtra options when .msgrc file exists
  26.  *    xostat        xtra options status printer
  27.  *    strend        detects keyword at start of str and returns pointer
  28.  *    xfgets        specials fgets that removes nulls
  29.  *
  30.  *        R E V I S I O N   H I S T O R Y
  31.  *
  32.  *    06/09/82  MJM    Split the enormous MSG program into pieces.
  33.  *
  34.  *    11/22/82  HW    Added Xtra options and header keyword stripping.
  35.  *
  36.  *    12/04/82  HW    Added SIGPIPE catcher and fixed SIGINT after pipe
  37.  *            bug.
  38.  *
  39.  *    06/01/84  HW    Added ctrl char filter.
  40.  *
  41.  *    04/20/88  ECB    Added 2-window-answer-mode-filter option.
  42.  */
  43. #include "util.h"
  44. #include "mmdf.h"
  45. #include <pwd.h>
  46. #include <signal.h>
  47. #include <sys/stat.h>
  48. #ifdef SYS5
  49. #include <termio.h>
  50. #include <string.h>
  51. #else SYS5
  52. #include <sgtty.h>
  53. #include <strings.h>
  54. #endif SYS5
  55. #include "./msg.h"
  56.  
  57. char    *keywds[MAXKEYS] = {
  58.     "via",
  59.     "message",
  60.     "remailed-date",
  61.     "remailed-to",
  62.     "sender",
  63.     "mail",
  64.     "article",
  65.     "origin",
  66.     "received",
  67.     0
  68. };
  69.         
  70. /*
  71.  *            T X T M T C H
  72.  */
  73. txtmtch()
  74. {
  75.     long size;
  76.     int retval;
  77.     char line[LINESIZE];
  78.  
  79.     mptr = msgp[msgno];
  80.  
  81.     fseek( filefp, mptr->start, 0);
  82.     retval = FALSE;
  83.     for( size = mptr->len; size > 0; size -= strlen(line))  {
  84.         if( xfgets( line, sizeof( line), filefp) == NULL )
  85.             break;
  86.         if( strindex( key, line) != NOTOK)  {
  87.             retval = TRUE;
  88.             break;
  89.         }
  90.     }
  91.  
  92.     return( retval);
  93. }
  94. /*--------------------------------------------------------------------*/
  95.  
  96. /*--------------------------------------------------------------------*/
  97.  
  98. /*
  99.  *            M A I N B O X
  100.  *
  101.  * last part of filename => main?
  102.  */
  103. mainbox()
  104. {
  105.     register char *cp;
  106.  
  107.     for( cp = filename; *cp++; );        /* get to end of name */
  108.     while( --cp != filename && *cp != '/');
  109.     /* find last part */
  110.     if( *cp == '/')
  111.         cp++;
  112.  
  113.     ismainbox = strcmp(cp, (!isstr(mldflfil) ? username : mldflfil)) == 0;
  114.     return( ismainbox );
  115. }
  116.  
  117. /*
  118.  *            G E T H E A D
  119.  *
  120.  * This routine seeks to the beginning of the message in the disk file,
  121.  * reads in the header, and scans it to find the values of the various
  122.  * fields.  Fields which the caller is not interested are passed as
  123.  * NULLs.
  124.  *
  125.  * NOTE that the fseek() can cause great inefficiency if the message
  126.  * happens to start on an ODD byte in the file...
  127.  *
  128.  * Typical use now is to get info for header on answer/reply.
  129.  */
  130. gethead( datestr, fromstr, sndstr, rplystr, tostr, ccstr, subjstr)
  131. char *datestr;        /* where to save Date     field */
  132. char *fromstr;        /* where to save From     field */
  133. char *sndstr;        /* where to save Sender   field */
  134. char *rplystr;        /* where to save Reply-To field */
  135. char *tostr;        /* where to save To       field */
  136. char *ccstr;        /* where to save cc       field */
  137. char *subjstr;        /* where to save Subj     field */
  138. {
  139.     char line[LINESIZE];
  140.     char curhdr[M_BSIZE];
  141.  
  142.     if( fromstr != 0)
  143.         fromstr[0] = '\0';
  144.     fseek( filefp, mptr->start, 0);            /* deadly! */
  145.     curhdr[0] = '0';
  146.     while(
  147.         xfgets( line, sizeof( line), filefp) != NULL &&
  148.         line[0] != '\n' &&
  149.         strcmp( delim1, line) != 0 &&
  150.         strcmp( delim2, line) != 0
  151.      )  {
  152.         if( datestr != 0)
  153.             if( gothdr( curhdr, "date:", line, datestr))
  154.                 continue;
  155.  
  156.         if( fromstr != 0 && isnull( fromstr[0]))
  157.             if( gothdr( curhdr, "from:", line, fromstr))
  158.                 continue;
  159.  
  160.         if( rplystr != 0)
  161.             if( gothdr( curhdr, "reply-to:", line, rplystr))
  162.                 continue;
  163.  
  164.         if( sndstr != 0)
  165.             if( gothdr( curhdr, "sender:", line, sndstr))
  166.                 continue;
  167.  
  168.         if( tostr != 0)
  169.             if( gothdr( curhdr, "To:", line, tostr))
  170.                 continue;
  171.  
  172.         if( ccstr != 0)
  173.             if( gothdr( curhdr, "cc:", line, ccstr))
  174.                 continue;
  175.  
  176.         if( subjstr != 0)
  177.             if( gothdr( curhdr, "subject:", line, subjstr))
  178.                 continue;
  179.  
  180.         /*
  181.          * If we got here, the line was of a type that we don't
  182.          * care about.  Zap curhdr, as it will not have been updated
  183.          * unless the line was processed by gothdr(), and we want
  184.          * to avoid processing extraneous continuations.
  185.          */
  186.          strcpy( curhdr, "boring-header-line:" );
  187.     }
  188. }
  189.  
  190. /*
  191.  *            G O T H D R
  192.  */
  193. gothdr( curname, name, src, dest)
  194. char *curname;        /* current field name */
  195. char *name;        /* test field name */
  196. char *src;        /* test input line */
  197. char *dest;        /* where to put data part at end */
  198. {
  199.     unsigned int destlen;
  200.  
  201.     if( isspace( *src ))
  202.     {
  203.         /* This is a continuation line.  Check "remembered" field */
  204.         if( strcmp( curname, name ) != 0 )
  205.             return( FALSE );
  206.  
  207.         /* Continuatin of correct header line.  Retain "remembered"
  208.         /* field.  Get rid of name & extra space from input line. */
  209.         compress( src, src);
  210.  
  211.         /*** FALL OUT ***/
  212.     }
  213.     else if (prefix( src, name ))
  214.     {
  215.         /* New line and field name matches, lets go! */
  216.  
  217.         /* Remember the "current field" */
  218.         strcpy( curname, name);
  219.  
  220.         if( strcmp( name, "date:" ) != 0 )
  221.             /* get rid of name & extra space */
  222.             compress( &src[strlen( name )], src);
  223.         else
  224.             /* Don't compress dates! */
  225.             strcpy( src, &src[strlen( name )] );
  226.  
  227.         /*** FALL OUT ***/
  228.     }
  229.     else
  230.     {
  231.         /* New line but field does not match, skip it */
  232.         return(FALSE);
  233.     }
  234.  
  235.     /* Common code for TRUE replies */
  236.     if( isnull( dest[0]))  {
  237.         /* first entry */
  238.         strcpy( dest, src);
  239.     }  else  {
  240.         /* add to end of field, if room */
  241.         destlen = strlen( dest);
  242.         if( (strlen( src) + destlen) < M_BSIZE - 1)
  243.             sprintf( &dest[destlen], "\n%s%c", src, '\0');
  244.     }
  245.     return( TRUE);
  246. }
  247.  
  248. /*
  249.  *            P R E F I X
  250.  */
  251. prefix( target, prefstr)
  252. register char  *target,
  253. *prefstr;
  254. {
  255.     for( ; *prefstr; target++, prefstr++)
  256.         if( uptolow( *target) != uptolow( *prefstr))
  257.             return( FALSE);
  258.  
  259.     return( isnull(*prefstr));
  260. }
  261.  
  262. /*--------------------------------------------------------------------*/
  263.  
  264. /*
  265.  *            C O N F I R M
  266.  *
  267.  * Request a yes/no answer
  268.  */
  269. confirm(msg,lfflag)
  270. char    *msg;
  271. int    lfflag;
  272. {
  273.     register char c;
  274.  
  275.     if(msg == (char *)0)
  276.         printf(" [Confirm] (y) ");
  277.     else
  278.         printf("%s (y) ", msg);
  279.     if( !verbose)
  280.         suckup();            /* BRL */
  281.     c = ttychar();
  282.     if( !verbose)
  283.         suckup();          /* suck up rest of line */
  284.  
  285.     switch( c)  {
  286.  
  287.     case 'Y': 
  288.     case 'y': 
  289.     case '\004':
  290.     case ' ':
  291.     case '\n': 
  292.         if( verbose) {
  293.             if( lfflag == DOLF )
  294.                 printf( "yes\r\n");
  295.             else
  296.                 printf("\r                               \r");
  297.         }
  298.         return( (int) c );
  299.  
  300.     case 'N':
  301.     case 'n': 
  302.     case 003:                /* Ctl/C */
  303.     case 007:                /* Ctl/G, for EMACS types */
  304.     case '/':
  305.         if (verbose) printf( "no\r\n");
  306.         return( FALSE);
  307.  
  308.     default:
  309.     case '?':
  310.         if (verbose)
  311.             printf("\r\nY, SPACE, or RETURN to confirm, N to abort\r\n");
  312.         else
  313.             printf("\r\nY<CR> or just <CR> to confirm, N<CR> to abort\r\n");
  314.         fflush( stdout );
  315.         return( confirm(msg, lfflag) );        /* recurse */
  316.     }
  317. }
  318.  
  319. /*
  320.  *            G A T H E R
  321.  *
  322.  * gobbles a line of max length from user, stores into string 'sp'.
  323.  * ASSUMES first char is already in sp[0].
  324.  */
  325. gather( sp, max)
  326. char *sp;
  327. {
  328.     register char c;
  329.     register char *p;
  330.  
  331.     for( p = sp, c = *sp;; ) {
  332.         if( c == '\003' )        /* Error - cancel */
  333.             error(" ^C\r\n");
  334.         else if( c == '\004' )
  335.             error(" ^D\r\n");
  336.         else if( c == ch_erase ) {    /* Delete previous char */
  337.             if( p > sp ) {
  338.                 p--;
  339.                 printf("\b \b");
  340.             }
  341.         }
  342.         else if( c == '\n' || c == '\r' ) {    /* Done */
  343.             *p = '\0';
  344.             if (verbose) printf("\r\n");
  345.             return;
  346.         }
  347.         else {
  348.             *p++ = c;
  349.             if( (p - sp) >= max )
  350.                 error(" Line too long\r\n");
  351.             if (verbose) putc(c, stdout);
  352.         }
  353.         c = ttychar();
  354.     }
  355. }
  356.  
  357. /*
  358.  *            S U C K U P
  359.  */
  360. suckup()
  361. {
  362.     if( lastc == '\n')
  363.         return;
  364.     while( (nxtchar = echochar()) != '\n' && nxtchar != '\004' );
  365. }
  366.  
  367. /*
  368.  *            E C H O C H A R
  369.  */
  370. echochar()
  371. {
  372.     register char c;
  373.  
  374.     c = ttychar();
  375.     if( verbose)  {
  376.         putchar( c);
  377.         if( c == '\n')
  378.             putchar( '\r');
  379.     }
  380.     return( c);
  381. }
  382.  
  383. /*
  384.  *            T T Y C H A R
  385.  */
  386. ttychar()
  387. {
  388.     register int c;
  389.  
  390.     fflush( stdout);
  391.     if( (c = getchar()) == EOF) {
  392.         if( ferror( stdin)) {
  393.             tt_norm();
  394.             closeup( -1);
  395.         }
  396.         if( feof( stdin) )
  397.             c = '\004';
  398.     }
  399.  
  400.     c = toascii( c);        /* get rid of high bit */
  401.  
  402.     if( c == '\r')
  403.         c = '\n';
  404.  
  405.     return( lastc = c);
  406. }
  407. /*--------------------------------------------------------------------*/
  408.  
  409. #ifdef SYS5
  410. static struct termio orig_ioctl;
  411. static struct termio raw_ioctl;
  412. #define    TIOCSETN TCSETAW        /* Crafty... (be careful!) */
  413. #else SYS5
  414. static struct sgttyb   orig_ioctl;
  415. static struct sgttyb   raw_ioctl;
  416. #endif SYS5
  417.  
  418. /*
  419.  *            T T _ I N I T
  420.  */
  421. tt_init()
  422. {
  423. #ifdef SYS5
  424.     if( ioctl( fileno( stdin), TCGETA, &orig_ioctl) == -1) {
  425. #else
  426.     if( ioctl( fileno( stdin), TIOCGETP, &orig_ioctl) == -1) {
  427. #endif
  428.         verbose = 0;
  429.         istty = FALSE;
  430.     }
  431.     else {
  432.         raw_ioctl = orig_ioctl;
  433. #ifdef SYS5
  434.         ch_erase = orig_ioctl.c_cc[VERASE];
  435.         raw_ioctl.c_iflag &= ~(ISTRIP | INLCR | IGNCR | ICRNL);
  436.         raw_ioctl.c_oflag &= ~OPOST;
  437.         raw_ioctl.c_lflag &= ~(ICANON | ECHO);
  438.         raw_ioctl.c_cc[4] = 1;
  439.         raw_ioctl.c_cc[5] = 0;
  440. #else
  441.         ch_erase = orig_ioctl.sg_erase;
  442.         raw_ioctl.sg_flags |= CBREAK;
  443.         raw_ioctl.sg_flags &= ~ECHO;
  444. #endif
  445.         istty = TRUE;
  446.     }
  447. }
  448.  
  449. /*
  450.  *            T T _ R A W
  451.  */
  452. tt_raw()
  453. {
  454.     if( verbose)  {
  455.         fflush( stdout);
  456.         if( istty == TRUE ) {
  457.             if( ioctl( fileno( stdin), TIOCSETN, &raw_ioctl) == -1) {
  458.                 perror( "problem setting raw terminal modes");
  459.                 verbose = 0;
  460.             }
  461.         }
  462.     }
  463. }
  464.  
  465. /*
  466.  *            T T _ N O R M
  467.  */
  468. tt_norm()
  469. {
  470.     fflush( stdout);
  471.     if( verbose)  {
  472.         if( istty == TRUE ) {
  473.             if( ioctl( fileno( stdin), TIOCSETN, &orig_ioctl) == -1)
  474.                 perror( "problem resetting normal terminal modes" );
  475.         }
  476.     }
  477. }
  478. /*--------------------------------------------------------------------*/
  479.  
  480. /*
  481.  *            O N I N T
  482.  */
  483. onint()
  484. {
  485.     signal( SIGINT, onint);
  486.     error( "\r\n" );
  487. }
  488.  
  489. /*
  490.  *            O N H A N G U P
  491.  *
  492.  * This routine is called when we get a hangup signal.
  493.  */
  494. onhangup()
  495. {
  496.     signal (SIGHUP, SIG_IGN);
  497.     signal (SIGINT, SIG_IGN);
  498. #ifdef SIGTSTP
  499.     signal( SIGTSTP, SIG_IGN);
  500. #endif SIGTSTP
  501.  
  502.     /* Prevent chatter on a closed line */
  503.     close( 1 );
  504.     close( 2 );
  505.     open( "/dev/null", 0 );        /* Assuming fd will be 1 */
  506.     open( "/dev/null", 0 );        /* Assuming fd will be 2 */
  507.     bprint = bdots = OFF;
  508.     fclose( stdout );
  509.  
  510.     /* Overwrite the binary box */
  511.     if( binaryvalid )
  512.         binbuild();
  513.     if( binfp != (FILE *) NULL)
  514.         lk_fclose(binfp, binarybox, (char *)0, (char *)0);
  515.     _exit(0);
  516. }
  517.  
  518. #ifdef SIGTSTP
  519. /*            O N S T O P
  520.  *  
  521.  *  SIGSTOP signal catcher
  522.  */
  523. onstop() {
  524.     int pid;
  525.     int saveverbose = verbose;
  526.     
  527.     pid = getpid();
  528.     if( binsavflag == ON )
  529.         binbuild();
  530.     tt_norm();
  531.     kill(pid,SIGSTOP);
  532.     verbose = 1;
  533.     tt_norm();
  534.     verbose = saveverbose;
  535.     tt_raw();
  536.     signal(SIGTSTP,onstop);
  537.     error("\r\n");
  538. }
  539. #endif SIGTSTP
  540.  
  541. /*            O N N O P I P E
  542.  *
  543.  *    Catches SIGPIPE
  544.  */
  545. onnopipe() {
  546.     signal( SIGPIPE, onnopipe );
  547.     outfd = -1;
  548.     error( " msg: Broken pipe\r\n" );
  549. }
  550.  
  551. /*
  552.  *            E R R O R
  553.  *
  554.  *  An error condition has occured.  Report it to the user, and long-jump
  555.  * back to the top of the mainline.
  556.  *
  557.  *  Note:  We should probably close ALL extraneous file descriptors,
  558.  * to prevent getting hung up with an exclusive-use file being left
  559.  * open.
  560.  */
  561. error( s)
  562. char *s;
  563. {
  564.     if( outfp != NULL && fileno(outfp) > 0 )  {
  565.         fclose( outfp );
  566.         outfp = NULL;
  567.     }
  568.  
  569.     if( exclfd > 0 )  {
  570.         close( exclfd );
  571.         exclfd = -1;
  572.     }
  573.  
  574.     fputs( s, stdout);
  575.     fflush( stdout);
  576.  
  577.     tt_raw();
  578.  
  579.     if( !(verbose || nxtchar == '\n'))
  580.         suckup();
  581.  
  582.     longjmp( savej, 1);
  583. }
  584.  
  585. /*        X O M S G R C
  586.  *
  587.  *    Reads user option file .msgrc and sets options
  588.  */
  589. xomsgrc( filept )
  590.     FILE    *filept;
  591. {
  592.     char    tbuf[LINESIZE];
  593.     int    nkeysrd;
  594.     char    *np, *nc;
  595.     static    char sendprog[LINESIZE];
  596.     
  597.     nkeysrd = 0;
  598.     while( xfgets( tbuf, sizeof(tbuf), filept ) != NULL ) {
  599.  
  600.         if( (np = index( tbuf, '\n' )) == NULL )
  601.             continue;
  602.         *np = '\0';
  603.  
  604.         if( tbuf[0] == '\0' || tbuf[0] == '#' )
  605.             continue;
  606.  
  607.         if( (np = strend( "strip", tbuf )) != NULL ) {
  608.             if( nkeysrd+1 >= sizeof(keywds)/sizeof(char *) )
  609.                 printf("Too many strip lines - %s IGNORED\r\n", tbuf );
  610.             else if( *np != '\0' ) {
  611.                 keywds[nkeysrd] = malloc( strlen( np )+1 );
  612.                 for( nc = np; *nc != '\0'; nc++ )
  613.                     *nc = uptolow( *nc );
  614.                 strcpy( keywds[nkeysrd++], np );
  615.             }
  616.         }
  617.  
  618.         else if( (np = strend( "numberedlist", tbuf )) != NULL )
  619.             prettylist = ON;
  620.  
  621.         else if( (np = strend( "nonumberedlist", tbuf )) != NULL )
  622.             prettylist = OFF;
  623.  
  624.         else if( (np = strend( "nostrip", tbuf )) != NULL )
  625.             keystrip = OFF;
  626.  
  627.         else if( (np = strend( "quicknflag", tbuf )) != NULL )
  628.             quicknflag = ON;
  629.  
  630.         else if( (np = strend( "noquicknflag", tbuf )) != NULL )
  631.             quicknflag = OFF;
  632.  
  633.         else if( (np = strend( "quickexit", tbuf )) != NULL )
  634.             quickexit = ON;
  635.  
  636.         else if( (np = strend( "noquickexit", tbuf )) != NULL )
  637.             quickexit = OFF;
  638.  
  639.         else if( (np = strend( "control-l", tbuf )) != NULL )
  640.             doctrlel = ON;
  641.  
  642.         else if( (np = strend( "nocontrol-l", tbuf )) != NULL )
  643.             doctrlel = OFF;
  644.  
  645.         else if( (np = strend( "zbinsave", tbuf )) != NULL )
  646.             binsavflag = ON;
  647.  
  648.         else if( (np = strend( "nozbinsave", tbuf )) != NULL )
  649.             binsavflag = OFF;
  650.  
  651.         else if( (np = strend( "twowinfil", tbuf )) != NULL ) {
  652.             if( *np != '\0' ) {
  653.                 strcpy( twowinfil, np );
  654.             }
  655.         }
  656.  
  657.         else if( (np = strend( "savebox", tbuf )) != NULL ) {
  658.             if( *np != '\0' ) {
  659.                 strcpy( defoutfile, np );
  660.                 strcpy( defmbox, np );
  661.             }
  662.         }
  663.  
  664.         else if( (np = strend( "draftdir", tbuf )) != NULL ) {
  665.             if( *np != '\0' ) {
  666.                 if( *np == '/' ) {
  667.                     sprintf(draft_work,"%s/draft_work",np);
  668.                     sprintf(draft_original,"%s/%s",np,draftorig);
  669.                 }
  670.                 else {
  671.                     sprintf(draft_work,"%s/%s/draft_work",homedir,np);
  672.                     sprintf(draft_original,"%s/%s/%s",homedir,np,draftorig);
  673.                 }                        
  674.             }
  675.         }
  676.  
  677.         else if( (np = strend( "draftorig", tbuf )) != NULL ) {
  678.             if( *np != '\0' ) {
  679.                 strcpy(draftorig,np);
  680.                 np = rindex(draft_original,'/');
  681.                 *++np = '\0';
  682.                 strcat(draft_original,draftorig);
  683.             }
  684.         }
  685.         
  686.         else if( (np = strend( "sendprog", tbuf )) != NULL ) {
  687.             if( *np != '\0' ) {
  688.                 if( *np == '/' )
  689.                     strcpy(sendprog,np);
  690.                 else
  691.                     sprintf(sendprog,"%s/%s",homedir,np);
  692.  
  693.                 sndname = sendprog;
  694.             }
  695.         }
  696.  
  697.         else if( (np = strend( "pagesize", tbuf )) != NULL )
  698.             pagesize = atoi(np);
  699.  
  700.         else if( (np = strend( "linelength", tbuf )) != NULL )
  701.             linelength = atoi(np);
  702.  
  703.         else if( (np = strend( "writemsg", tbuf )) != NULL )
  704.             wmsgflag = ON;
  705.  
  706.         else if( (np = strend( "nowritemsg", tbuf )) != NULL )
  707.             wmsgflag = OFF;
  708.  
  709.         else if( (np = strend( "ctrlfil", tbuf )) != NULL )
  710.             filoutflag = ON;
  711.  
  712.         else if( (np = strend( "noctrlfil", tbuf )) != NULL )
  713.             filoutflag = OFF;
  714.  
  715.         else if( (np = strend( "mdots", tbuf )) != NULL )
  716.             mdots = ON;
  717.  
  718.         else if( (np = strend( "nomdots", tbuf )) != NULL )
  719.             mdots = OFF;
  720.  
  721.         else if( (np = strend( "bdots", tbuf )) != NULL )
  722.             bdots = ON;
  723.  
  724.         else if( (np = strend( "nobdots", tbuf )) != NULL )
  725.             bdots = OFF;
  726.  
  727.         else if( (np = strend( "bprint", tbuf )) != NULL )
  728.             bprint = ON;
  729.  
  730.         else if( (np = strend( "nobprint", tbuf )) != NULL )
  731.             bprint = OFF;
  732.  
  733.         else if( (np = strend( "paging", tbuf )) != NULL )
  734.             paging = ON;
  735.  
  736.         else if( (np = strend( "nopaging", tbuf )) != NULL )
  737.             paging = OFF;
  738.  
  739.         else if( (np = strend( "verbose", tbuf )) != NULL )
  740.             verbose = ON;
  741.  
  742.         else if( (np = strend( "noverbose", tbuf )) != NULL )
  743.             verbose = OFF;
  744.  
  745.         else
  746.             printf("Unknown .msgrc option: %s\r\n",tbuf);
  747.     }    
  748.     if( nkeysrd > 0 ) 
  749.         keywds[nkeysrd] = 0;
  750. }
  751.  
  752. /*        S T R E N D
  753.  *
  754.  *    searches for str at beginning of target. If not found,
  755.  * returns NULL. If found, skips white space and returns pointer
  756.  * to first character following white space.
  757.  */
  758. char *
  759. strend (str, target)
  760.     char   *str, *target;
  761. {
  762.     register int slen;
  763.  
  764.     if( *target == '\0' )
  765.         return (NULL);
  766.  
  767.     slen = strlen( str );
  768.     if( lexnequ( str, target, slen) != TRUE )
  769.         return( (char *) NULL );
  770.  
  771.     for( target += slen; *target == '\t' || *target == ' '; target++ )
  772.         ;
  773.  
  774.     return (target);
  775. }
  776.  
  777. /*        X O S T A T
  778.  *
  779.  *    Prints Xtra options status
  780.  */
  781. xostat() {
  782.     register int    i;
  783.  
  784.     printf("\r\nMail file: %s   Binary file: %s\r\n",filename,binarybox);
  785.     printf("Save file: %s", defmbox );
  786.     printf("   Send program: %s\r\n",sndname );
  787.     printf("drafts: %s  %s\r\n", draft_work,draft_original);
  788.  
  789.     printf("\nbdots: %s\t\t\t\tmdots: %s",
  790.       bdots?"on.":"off.", mdots?"on.":"off." );
  791.     printf("\r\nbprint: %s\r\n",
  792.       bprint?"on.":"off." );
  793.  
  794.     printf("\nNumbered message list: %s\r\n",prettylist?"on.":"off.");
  795.     printf("Writemsg flag: %s\r\n",wmsgflag?"on.":"off.");
  796.     printf("Ctrl-char filter: %s\t\t\t",filoutflag?"on.":"off.");
  797.     printf("Ctrl-L: %s\r\n",doctrlel?"on.":"off.");
  798.     printf("Paging: %s\t\t\t\tPagesize: %d\r\n",
  799.       paging?"on.":"off.", pagesize);
  800.     printf("Quicknflag: %s\t\t\tLinelength: %d\r\n",
  801.       quicknflag?"on. ":"off.",linelength);
  802.     printf("Strip: %s\t\t\t\tVerbose: %s\r\n",
  803.       keystrip?"on.":"off.", verbose?"on.":"off." );
  804.  
  805.     printf("Strip keywords:\r\n");
  806.     for( i = 0; keywds[i] != 0; i++ )
  807.         printf("\t%s\r\n", keywds[i] );
  808. }
  809. /*            X F G E T S
  810.  *  
  811.  */
  812. char *
  813. xfgets(s, n, iop)
  814. char *s;
  815. register FILE *iop;
  816. {
  817.     register c;
  818.     register char *cs;
  819.  
  820.     cs = s;
  821.     while (--n>0 && (c = getc(iop))>=0) {
  822.         if( c == 0 )
  823.             *cs++ = '@';
  824.         else
  825.             *cs++ = c;
  826.         if (c=='\n')
  827.             break;
  828.     }
  829.     if (c<0 && cs==s)
  830.         return(NULL);
  831.     *cs = '\0';
  832.     return(s);
  833. }
  834.  
  835. /*                                                                      */
  836. /*      Determine if the two given strings are equivalent.              */
  837. /*                                                                      */
  838.  
  839. lexnequ (str1, str2, len)
  840. register char   *str1,
  841.         *str2;
  842. register int    len;
  843. {
  844.     extern char chrcnv[];
  845.  
  846.     while ( (len-- > 0) && (chrcnv[*str1] == chrcnv[*str2++]) ) {
  847.         if (len == 0 || *str1++ == 0)
  848.             return (TRUE);
  849.     }
  850.     return (FALSE);
  851. }
  852.