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