home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / metamail / tahoe / aux.c next >
Encoding:
C/C++ Source or Header  |  1988-02-18  |  11.8 KB  |  689 lines

  1. /*
  2.  * Copyright (c) 1980 Regents of the University of California.
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms are permitted
  6.  * provided that this notice is preserved and that due credit is given
  7.  * to the University of California at Berkeley. The name of the University
  8.  * may not be used to endorse or promote products derived from this
  9.  * software without specific prior written permission. This software
  10.  * is provided ``as is'' without express or implied warranty.
  11.  */
  12.  
  13. #ifdef notdef
  14. static char sccsid[] = "@(#)aux.c    5.7 (Berkeley) 2/18/88";
  15. #endif /* notdef */
  16.  
  17. #include "rcv.h"
  18. #include <sys/stat.h>
  19.  
  20. /*
  21.  * Mail -- a mail program
  22.  *
  23.  * Auxiliary functions.
  24.  */
  25.  
  26. /*
  27.  * Return a pointer to a dynamic copy of the argument.
  28.  */
  29.  
  30. char *
  31. savestr(str)
  32.     char *str;
  33. {
  34.     register char *cp, *cp2, *top;
  35.  
  36.     for (cp = str; *cp; cp++)
  37.         ;
  38.     top = salloc(cp-str + 1);
  39.     if (top == NOSTR)
  40.         return(NOSTR);
  41.     for (cp = str, cp2 = top; *cp; cp++)
  42.         *cp2++ = *cp;
  43.     *cp2 = 0;
  44.     return(top);
  45. }
  46.  
  47. /*
  48.  * Announce a fatal error and die.
  49.  */
  50.  
  51. /*VARARGS1*/
  52. panic(fmt, a, b)
  53.     char *fmt;
  54. {
  55.     fprintf(stderr, "panic: ");
  56.     fprintf(stderr, fmt, a, b);
  57.     putc('\n', stderr);
  58.     exit(1);
  59. }
  60.  
  61. /*
  62.  * Touch the named message by setting its MTOUCH flag.
  63.  * Touched messages have the effect of not being sent
  64.  * back to the system mailbox on exit.
  65.  */
  66.  
  67. touch(mesg)
  68. {
  69.     register struct message *mp;
  70.  
  71.     if (mesg < 1 || mesg > msgCount)
  72.         return;
  73.     mp = &message[mesg-1];
  74.     mp->m_flag |= MTOUCH;
  75.     if ((mp->m_flag & MREAD) == 0)
  76.         mp->m_flag |= MREAD|MSTATUS;
  77. }
  78.  
  79. /*
  80.  * Test to see if the passed file name is a directory.
  81.  * Return true if it is.
  82.  */
  83.  
  84. isdir(name)
  85.     char name[];
  86. {
  87.     struct stat sbuf;
  88.  
  89.     if (stat(name, &sbuf) < 0)
  90.         return(0);
  91.     return((sbuf.st_mode & S_IFMT) == S_IFDIR);
  92. }
  93.  
  94. /*
  95.  * Count the number of arguments in the given string raw list.
  96.  */
  97.  
  98. argcount(argv)
  99.     char **argv;
  100. {
  101.     register char **ap;
  102.  
  103.     for (ap = argv; *ap++ != NOSTR;)
  104.         ;    
  105.     return ap - argv - 1;
  106. }
  107.  
  108. /*
  109.  * Return the desired header line from the passed message
  110.  * pointer (or NOSTR if the desired header field is not available).
  111.  */
  112.  
  113. char *
  114. hfield(field, mp)
  115.     char field[];
  116.     struct message *mp;
  117. {
  118.     register FILE *ibuf;
  119.     char linebuf[LINESIZE];
  120.     register int lc;
  121.     register char *hfield;
  122.     char *colon;
  123.  
  124.     ibuf = setinput(mp);
  125.     if ((lc = mp->m_lines - 1) < 0)
  126.         return NOSTR;
  127.     if (readline(ibuf, linebuf) < 0)
  128.         return NOSTR;
  129.     while (lc > 0) {
  130.         if ((lc = gethfield(ibuf, linebuf, lc, &colon)) < 0)
  131.             return NOSTR;
  132.         if (hfield = ishfield(linebuf, colon, field))
  133.             return savestr(hfield);
  134.     }
  135.     return NOSTR;
  136. }
  137.  
  138. /*
  139.  * Return the next header field found in the given message.
  140.  * Return >= 0 if something found, < 0 elsewise.
  141.  * "colon" is set to point to the colon in the header.
  142.  * Must deal with \ continuations & other such fraud.
  143.  */
  144.  
  145. gethfield(f, linebuf, rem, colon)
  146.     register FILE *f;
  147.     char linebuf[];
  148.     register int rem;
  149.     char **colon;
  150. {
  151.     char line2[LINESIZE];
  152.     register char *cp, *cp2;
  153.     register int c;
  154.  
  155.     for (;;) {
  156.         if (--rem < 0)
  157.             return -1;
  158.         if ((c = readline(f, linebuf)) <= 0)
  159.             return -1;
  160.         for (cp = linebuf; isprint(*cp) && *cp != ' ' && *cp != ':';
  161.              cp++)
  162.             ;
  163.         if (*cp != ':' || cp == linebuf)
  164.             continue;
  165.         /*
  166.          * I guess we got a headline.
  167.          * Handle wraparounding
  168.          */
  169.         *colon = cp;
  170.         cp = linebuf + c;
  171.         for (;;) {
  172.             while (--cp >= linebuf && (*cp == ' ' || *cp == '\t'))
  173.                 ;
  174.             cp++;
  175.             if (rem <= 0)
  176.                 break;
  177.             ungetc(c = getc(f), f);
  178.             if (c != ' ' && c != '\t')
  179.                 break;
  180.             if ((c = readline(f, line2)) < 0)
  181.                 break;
  182.             rem--;
  183.             for (cp2 = line2; *cp2 == ' ' || *cp2 == '\t'; cp2++)
  184.                 ;
  185.             c -= cp2 - line2;
  186.             if (cp + c >= linebuf + LINESIZE - 2)
  187.                 break;
  188.             *cp++ = ' ';
  189.             bcopy(cp2, cp, c);
  190.             cp += c;
  191.         }
  192.         *cp = 0;
  193.         return rem;
  194.     }
  195.     /* NOTREACHED */
  196. }
  197.  
  198. /*
  199.  * Check whether the passed line is a header line of
  200.  * the desired breed.  Return the field body, or 0.
  201.  */
  202.  
  203. char*
  204. ishfield(linebuf, colon, field)
  205.     char linebuf[], field[];
  206.     char *colon;
  207. {
  208.     register char *cp = colon;
  209.  
  210.     *cp = 0;
  211.     if (!icequal(linebuf, field)) {
  212.         *cp = ':';
  213.         return 0;
  214.     }
  215.     *cp = ':';
  216.     for (cp++; *cp == ' ' || *cp == '\t'; cp++)
  217.         ;
  218.     return cp;
  219. }
  220.  
  221. /*
  222.  * Compare two strings, ignoring case.
  223.  */
  224.  
  225. icequal(s1, s2)
  226.     register char *s1, *s2;
  227. {
  228.     register c1, c2;
  229.  
  230.     for (;;) {
  231.         if ((c1 = (unsigned char)*s1++) !=
  232.             (c2 = (unsigned char)*s2++)) {
  233.             if (isupper(c1))
  234.                 c1 = tolower(c1);
  235.             if (c1 != c2)
  236.                 return 0;
  237.         }
  238.         if (c1 == 0)
  239.             return 1;
  240.     }
  241.     /*NOTREACHED*/
  242. }
  243.  
  244. /*
  245.  * Copy a string, lowercasing it as we go.
  246.  */
  247. istrcpy(dest, src)
  248.     register char *dest, *src;
  249. {
  250.  
  251.     do {
  252.         if (isupper(*src))
  253.             *dest++ = tolower(*src);
  254.         else
  255.             *dest++ = *src;
  256.     } while (*src++ != 0);
  257. }
  258.  
  259. /*
  260.  * The following code deals with input stacking to do source
  261.  * commands.  All but the current file pointer are saved on
  262.  * the stack.
  263.  */
  264.  
  265. static    int    ssp = -1;        /* Top of file stack */
  266. struct sstack {
  267.     FILE    *s_file;        /* File we were in. */
  268.     int    s_cond;            /* Saved state of conditionals */
  269.     int    s_loading;        /* Loading .mailrc, etc. */
  270. } sstack[NOFILE];
  271.  
  272. /*
  273.  * Pushdown current input file and switch to a new one.
  274.  * Set the global flag "sourcing" so that others will realize
  275.  * that they are no longer reading from a tty (in all probability).
  276.  */
  277.  
  278. source(name)
  279.     char name[];
  280. {
  281.     register FILE *fi;
  282.     register char *cp;
  283.  
  284.     if ((cp = expand(name)) == NOSTR)
  285.         return(1);
  286.     if ((fi = fopen(cp, "r")) == NULL) {
  287.         perror(cp);
  288.         return(1);
  289.     }
  290.     if (ssp >= NOFILE - 2) {
  291.         printf("Too much \"sourcing\" going on.\n");
  292.         fclose(fi);
  293.         return(1);
  294.     }
  295.     sstack[++ssp].s_file = input;
  296.     sstack[ssp].s_cond = cond;
  297.     sstack[ssp].s_loading = loading;
  298.     loading = 0;
  299.     cond = CANY;
  300.     input = fi;
  301.     sourcing++;
  302.     return(0);
  303. }
  304.  
  305. /*
  306.  * Pop the current input back to the previous level.
  307.  * Update the "sourcing" flag as appropriate.
  308.  */
  309.  
  310. unstack()
  311. {
  312.     if (ssp < 0) {
  313.         printf("\"Source\" stack over-pop.\n");
  314.         sourcing = 0;
  315.         return(1);
  316.     }
  317.     fclose(input);
  318.     if (cond != CANY)
  319.         printf("Unmatched \"if\"\n");
  320.     cond = sstack[ssp].s_cond;
  321.     loading = sstack[ssp].s_loading;
  322.     input = sstack[ssp--].s_file;
  323.     if (ssp < 0)
  324.         sourcing = loading;
  325.     return(0);
  326. }
  327.  
  328. /*
  329.  * Touch the indicated file.
  330.  * This is nifty for the shell.
  331.  * If we have the utime() system call, this is better served
  332.  * by using that, since it will work for empty files.
  333.  * On non-utime systems, we must sleep a second, then read.
  334.  */
  335.  
  336. alter(name)
  337.     char name[];
  338. {
  339. #ifdef UTIME
  340.     struct stat statb;
  341.     long time();
  342.     time_t time_p[2];
  343. #else
  344.     register int pid, f;
  345.     char w;
  346. #endif UTIME
  347.  
  348. #ifdef UTIME
  349.     if (stat(name, &statb) < 0)
  350.         return;
  351.     time_p[0] = time((long *) 0) + 1;
  352.     time_p[1] = statb.st_mtime;
  353.     utime(name, time_p);
  354. #else
  355.     sleep(1);
  356.     if ((f = open(name, 0)) < 0)
  357.         return;
  358.     read(f, &w, 1);
  359.     exit(0);
  360. #endif
  361. }
  362.  
  363. /*
  364.  * Examine the passed line buffer and
  365.  * return true if it is all blanks and tabs.
  366.  */
  367.  
  368. blankline(linebuf)
  369.     char linebuf[];
  370. {
  371.     register char *cp;
  372.  
  373.     for (cp = linebuf; *cp; cp++)
  374.         if (*cp != ' ' && *cp != '\t')
  375.             return(0);
  376.     return(1);
  377. }
  378.  
  379. /*
  380.  * Get sender's name from this message.  If the message has
  381.  * a bunch of arpanet stuff in it, we may have to skin the name
  382.  * before returning it.
  383.  */
  384. char *
  385. nameof(mp, reptype)
  386.     register struct message *mp;
  387. {
  388.     register char *cp, *cp2;
  389.  
  390.     cp = skin(name1(mp, reptype));
  391.     if (reptype != 0 || charcount(cp, '!') < 2)
  392.         return(cp);
  393.     cp2 = rindex(cp, '!');
  394.     cp2--;
  395.     while (cp2 > cp && *cp2 != '!')
  396.         cp2--;
  397.     if (*cp2 == '!')
  398.         return(cp2 + 1);
  399.     return(cp);
  400. }
  401.  
  402. /*
  403.  * Skin an arpa net address according to the RFC 822 interpretation
  404.  * of "host-phrase."
  405.  */
  406. char *
  407. skin(name)
  408.     char *name;
  409. {
  410.     register int c;
  411.     register char *cp, *cp2;
  412.     char *bufend;
  413.     int gotlt, lastsp;
  414.     char nbuf[BUFSIZ];
  415.     int nesting;
  416.  
  417.     if (name == NOSTR)
  418.         return(NOSTR);
  419.     if (index(name, '(') == NOSTR && index(name, '<') == NOSTR
  420.         && index(name, ' ') == NOSTR)
  421.         return(name);
  422.     gotlt = 0;
  423.     lastsp = 0;
  424.     bufend = nbuf;
  425.     for (cp = name, cp2 = bufend; c = *cp++; ) {
  426.         switch (c) {
  427.         case '(':
  428.             /*
  429.              * Start of a "comment".
  430.              * Ignore it.
  431.              */
  432.             nesting = 1;
  433.             while ((c = *cp) != 0) {
  434.                 cp++;
  435.                 switch (c) {
  436.                 case '\\':
  437.                     if (*cp == 0)
  438.                         goto outcm;
  439.                     cp++;
  440.                     break;
  441.                 case '(':
  442.                     nesting++;
  443.                     break;
  444.  
  445.                 case ')':
  446.                     --nesting;
  447.                     break;
  448.                 }
  449.  
  450.                 if (nesting <= 0)
  451.                     break;
  452.             }
  453.         outcm:
  454.             lastsp = 0;
  455.             break;
  456.  
  457.         case '"':
  458.             /*
  459.              * Start of a "quoted-string".
  460.              * Copy it in its entirety.
  461.              */
  462.             while ((c = *cp) != 0) {
  463.                 cp++;
  464.                 switch (c) {
  465.                 case '\\':
  466.                     if ((c = *cp) == 0)
  467.                         goto outqs;
  468.                     cp++;
  469.                     break;
  470.                 case '"':
  471.                     goto outqs;
  472.                 }
  473.                 *cp2++ = c;
  474.             }
  475.         outqs:
  476.             lastsp = 0;
  477.             break;
  478.  
  479.         case ' ':
  480.             if (cp[0] == 'a' && cp[1] == 't' && cp[2] == ' ')
  481.                 cp += 3, *cp2++ = '@';
  482.             else
  483.             if (cp[0] == '@' && cp[1] == ' ')
  484.                 cp += 2, *cp2++ = '@';
  485.             else
  486.                 lastsp = 1;
  487.             break;
  488.  
  489.         case '<':
  490.             cp2 = bufend;
  491.             gotlt++;
  492.             lastsp = 0;
  493.             break;
  494.  
  495.         case '>':
  496.             if (gotlt) {
  497.                 gotlt = 0;
  498.                 while (*cp != ',' && *cp != 0)
  499.                     cp++;
  500.                 if (*cp == 0 )
  501.                     goto done;
  502.                 *cp2++ = ',';
  503.                 *cp2++ = ' ';
  504.                 bufend = cp2;
  505.                 break;
  506.             }
  507.  
  508.             /* Fall into . . . */
  509.  
  510.         default:
  511.             if (lastsp) {
  512.                 lastsp = 0;
  513.                 *cp2++ = ' ';
  514.             }
  515.             *cp2++ = c;
  516.             break;
  517.         }
  518.     }
  519. done:
  520.     *cp2 = 0;
  521.  
  522.     return(savestr(nbuf));
  523. }
  524.  
  525. /*
  526.  * Fetch the sender's name from the passed message.
  527.  * Reptype can be
  528.  *    0 -- get sender's name for display purposes
  529.  *    1 -- get sender's name for reply
  530.  *    2 -- get sender's name for Reply
  531.  */
  532.  
  533. char *
  534. name1(mp, reptype)
  535.     register struct message *mp;
  536. {
  537.     char namebuf[LINESIZE];
  538.     char linebuf[LINESIZE];
  539.     register char *cp, *cp2;
  540.     register FILE *ibuf;
  541.     int first = 1;
  542.  
  543.     if ((cp = hfield("from", mp)) != NOSTR)
  544.         return cp;
  545.     if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
  546.         return cp;
  547.     ibuf = setinput(mp);
  548.     namebuf[0] = 0;
  549.     if (readline(ibuf, linebuf) < 0)
  550.         return(savestr(namebuf));
  551. newname:
  552.     for (cp = linebuf; *cp && *cp != ' '; cp++)
  553.         ;
  554.     for (; *cp == ' ' || *cp == '\t'; cp++)
  555.         ;
  556.     for (cp2 = &namebuf[strlen(namebuf)];
  557.          *cp && *cp != ' ' && *cp != '\t' && cp2 < namebuf + LINESIZE - 1;)
  558.         *cp2++ = *cp++;
  559.     *cp2 = '\0';
  560.     if (readline(ibuf, linebuf) < 0)
  561.         return(savestr(namebuf));
  562.     if ((cp = index(linebuf, 'F')) == NULL)
  563.         return(savestr(namebuf));
  564.     if (strncmp(cp, "From", 4) != 0)
  565.         return(savestr(namebuf));
  566.     while ((cp = index(cp, 'r')) != NULL) {
  567.         if (strncmp(cp, "remote", 6) == 0) {
  568.             if ((cp = index(cp, 'f')) == NULL)
  569.                 break;
  570.             if (strncmp(cp, "from", 4) != 0)
  571.                 break;
  572.             if ((cp = index(cp, ' ')) == NULL)
  573.                 break;
  574.             cp++;
  575.             if (first) {
  576.                 strcpy(namebuf, cp);
  577.                 first = 0;
  578.             } else
  579.                 strcpy(rindex(namebuf, '!')+1, cp);
  580.             strcat(namebuf, "!");
  581.             goto newname;
  582.         }
  583.         cp++;
  584.     }
  585.     return(savestr(namebuf));
  586. }
  587.  
  588. /*
  589.  * Count the occurances of c in str
  590.  */
  591. charcount(str, c)
  592.     char *str;
  593. {
  594.     register char *cp;
  595.     register int i;
  596.  
  597.     for (i = 0, cp = str; *cp; cp++)
  598.         if (*cp == c)
  599.             i++;
  600.     return(i);
  601. }
  602.  
  603. /*
  604.  * Are any of the characters in the two strings the same?
  605.  */
  606.  
  607. anyof(s1, s2)
  608.     register char *s1, *s2;
  609. {
  610.  
  611.     while (*s1)
  612.         if (index(s2, *s1++))
  613.             return 1;
  614.     return 0;
  615. }
  616.  
  617. /*
  618.  * Convert c to upper case
  619.  */
  620.  
  621. raise(c)
  622.     register c;
  623. {
  624.  
  625.     if (islower(c))
  626.         return toupper(c);
  627.     return c;
  628. }
  629.  
  630. /*
  631.  * Copy s1 to s2, return pointer to null in s2.
  632.  */
  633.  
  634. char *
  635. copy(s1, s2)
  636.     register char *s1, *s2;
  637. {
  638.  
  639.     while (*s2++ = *s1++)
  640.         ;
  641.     return s2 - 1;
  642. }
  643.  
  644. /*
  645.  * Add a single character onto a string.
  646.  */
  647.  
  648. stradd(str, c)
  649.     register char *str;
  650. {
  651.  
  652.     while (*str++)
  653.         ;
  654.     str[-1] = c;
  655.     *str = 0;
  656. }
  657.  
  658. /*
  659.  * See if the given header field is supposed to be ignored.
  660.  */
  661. isign(field)
  662.     char *field;
  663. {
  664.     char realfld[BUFSIZ];
  665.  
  666.     /*
  667.      * Lower-case the string, so that "Status" and "status"
  668.      * will hash to the same place.
  669.      */
  670.     istrcpy(realfld, field);
  671.     if (nretained > 0)
  672.         return (!member(realfld, retain));
  673.     else
  674.         return (member(realfld, ignore));
  675. }
  676.  
  677. member(realfield, table)
  678.     register char *realfield;
  679.     struct ignore **table;
  680. {
  681.     register struct ignore *igp;
  682.  
  683.     for (igp = table[hash(realfield)]; igp != 0; igp = igp->i_link)
  684.         if (*igp->i_field == *realfield &&
  685.             equal(igp->i_field, realfield))
  686.             return (1);
  687.     return (0);
  688. }
  689.