home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / ucbmail / aux.c next >
Encoding:
C/C++ Source or Header  |  1986-06-03  |  13.4 KB  |  773 lines

  1. /*
  2.  *  A U X . C 
  3.  *
  4.  *  EE/CIS Computer Lab
  5.  *  Department of Computer and Information Sciences
  6.  *  Department of Electrical Engineering
  7.  *  University of Delaware
  8.  *
  9.  *  REVISION HISTORY:
  10.  *
  11.  *  $Revision: 1.4 $
  12.  *
  13.  *  $Log:    aux.c,v $
  14.  * Revision 1.4  86/01/14  14:04:40  galvin
  15.  * 
  16.  * Change nameof so it does not delete the comment associated
  17.  * with an address (it is probably the senders full name).
  18.  * 
  19.  * Change skin() to use MMDF's parsadr to find the route.
  20.  * 
  21.  * Add routeq() to use when comparing routes.  The intent is not to
  22.  * compare the comment part of address when looking for duplicate entries.
  23.  * 
  24.  * Revision 1.3  85/12/18  13:31:12  galvin
  25.  * Change alter to use the MMDF locking routines.
  26.  * 
  27.  * Comment out a call to exit which just didn't look like it belonged.
  28.  * 
  29.  * Revision 1.2  85/12/18  13:28:48  galvin
  30.  * Added comment header for revision history.
  31.  * 
  32.  *
  33.  */
  34.  
  35. /*
  36.  * Copyright (c) 1980 Regents of the University of California.
  37.  * All rights reserved.  The Berkeley software License Agreement
  38.  * specifies the terms and conditions for redistribution.
  39.  */
  40.  
  41. #ifndef lint
  42. static char *sccsid = "@(#)aux.c    5.4 (Berkeley) 1/13/86";
  43. #endif not lint
  44.  
  45. #include "./rcv.h"
  46. #include <sys/stat.h>
  47. #include <ctype.h>
  48.  
  49. /*
  50.  * Mail -- a mail program
  51.  *
  52.  * Auxiliary functions.
  53.  */
  54.  
  55. /*
  56.  * Return a pointer to a dynamic copy of the argument.
  57.  */
  58.  
  59. char *
  60. savestr(str)
  61.     char *str;
  62. {
  63.     register char *cp, *cp2, *top;
  64.  
  65.     for (cp = str; *cp; cp++)
  66.         ;
  67.     top = salloc(cp-str + 1);
  68.     if (top == NOSTR)
  69.         return(NOSTR);
  70.     for (cp = str, cp2 = top; *cp; cp++)
  71.         *cp2++ = *cp;
  72.     *cp2 = 0;
  73.     return(top);
  74. }
  75.  
  76. #ifdef NOT_USED
  77. /*
  78.  * Copy the name from the passed header line into the passed
  79.  * name buffer.  Null pad the name buffer.
  80.  */
  81.  
  82. copyname(linebuf, nbuf)
  83.     char *linebuf, *nbuf;
  84. {
  85.     register char *cp, *cp2;
  86.  
  87.     for (cp = linebuf + 5, cp2 = nbuf; *cp != ' ' && cp2-nbuf < 8; cp++)
  88.         *cp2++ = *cp;
  89.     while (cp2-nbuf < 8)
  90.         *cp2++ = 0;
  91. }
  92. #endif NOT_USED
  93.  
  94. /*
  95.  * Announce a fatal error and die.
  96.  */
  97.  
  98. panic(str)
  99.     char *str;
  100. {
  101.     prs("panic: ");
  102.     prs(str);
  103.     prs("\n");
  104.     exit(1);
  105. }
  106.  
  107. #ifdef NOT_USED
  108. /*
  109.  * Catch stdio errors and report them more nicely.
  110.  */
  111.  
  112. _error(str)
  113.     char *str;
  114. {
  115.     prs("Stdio Error: ");
  116.     prs(str);
  117.     prs("\n");
  118.     abort();
  119. }
  120. #endif NOT_USED
  121.  
  122. /*
  123.  * Print a string on diagnostic output.
  124.  */
  125.  
  126. prs(str)
  127.     char *str;
  128. {
  129.     register char *s;
  130.  
  131.     for (s = str; *s; s++)
  132.         ;
  133.     write(2, str, s-str);
  134. }
  135.  
  136. /*
  137.  * Touch the named message by setting its MTOUCH flag.
  138.  * Touched messages have the effect of not being sent
  139.  * back to the system mailbox on exit.
  140.  */
  141.  
  142. touch(mesg)
  143. {
  144.     register struct message *mp;
  145.  
  146.     if (mesg < 1 || mesg > msgCount)
  147.         return;
  148.     mp = &message[mesg-1];
  149.     mp->m_flag |= MTOUCH;
  150.     if ((mp->m_flag & MREAD) == 0)
  151.         mp->m_flag |= MREAD|MSTATUS;
  152. }
  153.  
  154. /*
  155.  * Test to see if the passed file name is a directory.
  156.  * Return true if it is.
  157.  */
  158.  
  159. isdir(name)
  160.     char name[];
  161. {
  162.     struct stat sbuf;
  163.  
  164.     if (stat(name, &sbuf) < 0)
  165.         return(0);
  166.     return((sbuf.st_mode & S_IFMT) == S_IFDIR);
  167. }
  168.  
  169. /*
  170.  * Count the number of arguments in the given string raw list.
  171.  */
  172.  
  173. argcount(argv)
  174.     char **argv;
  175. {
  176.     register char **ap;
  177.  
  178.     for (ap = argv; *ap != NOSTR; ap++)
  179.         ;    
  180.     return(ap-argv);
  181. }
  182.  
  183. /*
  184.  * Given a file address, determine the
  185.  * block number it represents.
  186.  */
  187.  
  188. blockof(off)
  189.     off_t off;
  190. {
  191.     off_t a;
  192.  
  193.     a = off >> 9;
  194.     a &= 077777;
  195.     return((int) a);
  196. }
  197.  
  198. /*
  199.  * Take a file address, and determine
  200.  * its offset in the current block.
  201.  */
  202.  
  203. offsetof(off)
  204.     off_t off;
  205. {
  206.     off_t a;
  207.  
  208.     a = off & 0777;
  209.     return((int) a);
  210. }
  211.  
  212. /*
  213.  * Return the desired header line from the passed message
  214.  * pointer (or NOSTR if the desired header field is not available).
  215.  */
  216.  
  217. char *
  218. hfield(field, mp)
  219.     char field[];
  220.     struct message *mp;
  221. {
  222.     register FILE *ibuf;
  223.     char linebuf[LINESIZE];
  224.     register int lc;
  225.  
  226.     ibuf = setinput(mp);
  227.     if ((lc = mp->m_lines) <= 0)
  228.         return(NOSTR);
  229.     do {
  230.         lc = gethfield(ibuf, linebuf, lc);
  231. #ifdef DEBUG
  232.         if (debug)
  233.             printf("got header \"%s\"\n", linebuf);
  234. #endif DEBUG
  235.         if (lc == -1)
  236.             return(NOSTR);
  237.         if (ishfield(linebuf, field))
  238.             return(savestr(hcontents(linebuf)));
  239.     } while (lc > 0);
  240.     return(NOSTR);
  241. }
  242.  
  243. /*
  244.  * Return the next header field found in the given message.
  245.  * Return > 0 if something found, <= 0 elsewise.
  246.  * Must deal with \ continuations & other such fraud.
  247.  */
  248.  
  249. gethfield(f, linebuf, rem)
  250.     register FILE *f;
  251.     char linebuf[];
  252.     register int rem;
  253. {
  254.     char line2[LINESIZE];
  255.     long loc;
  256.     register char *cp, *cp2;
  257.     register int c;
  258.  
  259.  
  260.     for (;;) {
  261.         if (rem <= 0)
  262.             return(-1);
  263.         if (readline(f, linebuf) < 0)
  264.             return(-1);
  265.         rem--;
  266.         if (strlen(linebuf) == 0)
  267.             return(-1);
  268.         if (isspace(linebuf[0]))
  269.             continue;
  270.         if (linebuf[0] == '>')
  271.             continue;
  272.         cp = index(linebuf, ':');
  273.         if (cp == NOSTR)
  274.             continue;
  275.         for (cp2 = linebuf; cp2 < cp; cp2++)
  276.             if (isdigit(*cp2))
  277.                 continue;
  278.         
  279.         /*
  280.          * I guess we got a headline.
  281.          * Handle wraparounding
  282.          */
  283.         
  284.         for (;;) {
  285.             if (rem <= 0)
  286.                 break;
  287. #ifdef CANTELL
  288.             loc = ftell(f);
  289.             if (readline(f, line2) < 0)
  290.                 break;
  291.             rem--;
  292.             if (!isspace(line2[0])) {
  293.                 fseek(f, loc, 0);
  294.                 rem++;
  295.                 break;
  296.             }
  297. #else
  298.             c = getc(f);
  299.             ungetc(c, f);
  300.             if (!isspace(c) || c == '\n')
  301.                 break;
  302.             if (readline(f, line2) < 0)
  303.                 break;
  304.             rem--;
  305. #endif
  306.             cp2 = line2;
  307.             for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
  308.                 ;
  309.             if (strlen(linebuf) + strlen(cp2) >= LINESIZE-2)
  310.                 break;
  311.             cp = &linebuf[strlen(linebuf)];
  312.             while (cp > linebuf &&
  313.                 (isspace(cp[-1]) || cp[-1] == '\\'))
  314.                 cp--;
  315.             *cp++ = ' ';
  316.             for (cp2 = line2; *cp2 != 0 && isspace(*cp2); cp2++)
  317.                 ;
  318.             strcpy(cp, cp2);
  319.         }
  320.         if ((c = strlen(linebuf)) > 0) {
  321.             cp = &linebuf[c-1];
  322.             while (cp > linebuf && isspace(*cp))
  323.                 cp--;
  324.             *++cp = 0;
  325.         }
  326.         return(rem);
  327.     }
  328.     /* NOTREACHED */
  329. }
  330.  
  331. /*
  332.  * Check whether the passed line is a header line of
  333.  * the desired breed.
  334.  */
  335.  
  336. ishfield(linebuf, field)
  337.     char linebuf[], field[];
  338. {
  339.     register char *cp;
  340.     register int c;
  341.  
  342.     if ((cp = index(linebuf, ':')) == NOSTR)
  343.         return(0);
  344.     if (cp == linebuf)
  345.         return(0);
  346.     cp--;
  347.     while (cp > linebuf && isspace(*cp))
  348.         cp--;
  349.     c = *++cp;
  350.     *cp = 0;
  351.     if (icequal(linebuf ,field)) {
  352.         *cp = c;
  353.         return(1);
  354.     }
  355.     *cp = c;
  356.     return(0);
  357. }
  358.  
  359. /*
  360.  * Extract the non label information from the given header field
  361.  * and return it.
  362.  */
  363.  
  364. char *
  365. hcontents(hfld)
  366.     char hfld[];
  367. {
  368.     register char *cp;
  369.  
  370.     if ((cp = index(hfld, ':')) == NOSTR)
  371.         return(NOSTR);
  372.     cp++;
  373.     while (*cp && isspace(*cp))
  374.         cp++;
  375.     return(cp);
  376. }
  377.  
  378. /*
  379.  * Compare two strings, ignoring case.
  380.  */
  381.  
  382. icequal(s1, s2)
  383.     register char *s1, *s2;
  384. {
  385.  
  386.     while (raise(*s1++) == raise(*s2))
  387.         if (*s2++ == 0)
  388.             return(1);
  389.     return(0);
  390. }
  391.  
  392. /*
  393.  * Copy a string, lowercasing it as we go.
  394.  */
  395. istrcpy(dest, src)
  396.     char *dest, *src;
  397. {
  398.     register char *cp, *cp2;
  399.  
  400.     cp2 = dest;
  401.     cp = src;
  402.     do {
  403.         *cp2++ = little(*cp);
  404.     } while (*cp++ != 0);
  405. }
  406.  
  407. /*
  408.  * The following code deals with input stacking to do source
  409.  * commands.  All but the current file pointer are saved on
  410.  * the stack.
  411.  */
  412.  
  413. static    int    ssp = -1;        /* Top of file stack */
  414. struct sstack {
  415.     FILE    *s_file;        /* File we were in. */
  416.     int    s_cond;            /* Saved state of conditionals */
  417.     int    s_loading;        /* Loading .mailrc, etc. */
  418. } sstack[NOFILE];
  419.  
  420. /*
  421.  * Pushdown current input file and switch to a new one.
  422.  * Set the global flag "sourcing" so that others will realize
  423.  * that they are no longer reading from a tty (in all probability).
  424.  */
  425.  
  426. source(name)
  427.     char name[];
  428. {
  429.     register FILE *fi;
  430.     register char *cp;
  431.  
  432.     if ((cp = expand(name)) == NOSTR)
  433.         return(1);
  434.     if ((fi = fopen(cp, "r")) == NULL) {
  435.         perror(cp);
  436.         return(1);
  437.     }
  438.     if (ssp >= NOFILE - 2) {
  439.         printf("Too much \"sourcing\" going on.\n");
  440.         fclose(fi);
  441.         return(1);
  442.     }
  443.     sstack[++ssp].s_file = input;
  444.     sstack[ssp].s_cond = cond;
  445.     sstack[ssp].s_loading = loading;
  446.     loading = 0;
  447.     cond = CANY;
  448.     input = fi;
  449.     sourcing++;
  450.     return(0);
  451. }
  452.  
  453. #ifdef NOT_USED
  454. /*
  455.  * Source a file, but do nothing if the file cannot be opened.
  456.  */
  457.  
  458. source1(name)
  459.     char name[];
  460. {
  461.     register int f;
  462.  
  463.     if ((f = open(name, 0)) < 0)
  464.         return(0);
  465.     close(f);
  466.     return(source(name));
  467. }
  468. #endif NOT_USED
  469.  
  470. /*
  471.  * Pop the current input back to the previous level.
  472.  * Update the "sourcing" flag as appropriate.
  473.  */
  474.  
  475. unstack()
  476. {
  477.     if (ssp < 0) {
  478.         printf("\"Source\" stack over-pop.\n");
  479.         sourcing = 0;
  480.         return;
  481.     }
  482.     fclose(input);
  483.     if (cond != CANY)
  484.         printf("Unmatched \"if\"\n");
  485.     cond = sstack[ssp].s_cond;
  486.     loading = sstack[ssp].s_loading;
  487.     input = sstack[ssp--].s_file;
  488.     if (ssp < 0)
  489.         sourcing = loading;
  490. }
  491.  
  492. /*
  493.  * Touch the indicated file.
  494.  * This is nifty for the shell.
  495.  * If we have the utimes() system call, this is better served
  496.  * by using that, since it will work for empty files.
  497.  * The utime() system call can be used if necessary.
  498.  * On non-utime systems, we must sleep a second, then read.
  499.  */
  500. #ifdef UTIMES
  501. #include <sys/time.h>
  502. #endif UTIMES
  503.  
  504. alter(name)
  505.     char name[];
  506. {
  507. #ifdef UTIMES
  508.     struct stat statb;
  509.     struct timeval tp[2];
  510.     struct timezone tzp;
  511. #else  UTIMES
  512. #ifdef UTIME
  513.     struct stat statb;
  514.     time_t time();
  515.     time_t time_p[2];
  516. #else  UTIME
  517.     register int f;
  518.     char w;
  519. #endif UTIME
  520. #endif UTIMES
  521.  
  522. #ifdef UTIMES
  523.     if (stat(name, &statb) < 0)
  524.         return;
  525.     if (gettimeofday(&tp[0], &tzp) < 0)
  526.             return;
  527.     tp[1] = tp[0];
  528.     utimes(name, tp);
  529. #else  UTIMES
  530. #ifdef UTIME
  531.     if (stat(name, &statb) < 0)
  532.         return;
  533.     time_p[0] = time((long *) 0) + 1;
  534.     time_p[1] = statb.st_mtime;
  535.     utime(name, time_p);
  536. #else  UTIME
  537.     sleep(1);
  538.     if ((f = lk_open(name, 0, (char *) 0, (char *) 0, 5)) < 0)
  539.         return;
  540.     read(f, &w, 1);
  541.     lk_close(f, name, (char *) 0, (char *) 0);
  542.     /* exit(0);    /* was this really intended ?? */
  543. #endif UTIME
  544. #endif UTIMES
  545. }
  546.  
  547. /*
  548.  * Examine the passed line buffer and
  549.  * return true if it is all blanks and tabs.
  550.  */
  551.  
  552. blankline(linebuf)
  553.     char linebuf[];
  554. {
  555.     register char *cp;
  556.  
  557.     for (cp = linebuf; *cp; cp++)
  558.         if (*cp != ' ' && *cp != '\t')
  559.             return(0);
  560.     return(1);
  561. }
  562.  
  563. /*
  564.  * Get sender's name from this message.
  565.  */
  566. char *
  567. nameof(mp, reptype)
  568.     register struct message *mp;
  569. {
  570.     register char *cp, *cp2;
  571.  
  572.     cp = name1(mp, reptype);
  573.     if (reptype != 0 || charcount(cp, '!') < 2)
  574.         return(cp);
  575.     cp2 = rindex(cp, '!');
  576.     cp2--;
  577.     while (cp2 > cp && *cp2 != '!')
  578.         cp2--;
  579.     if (*cp2 == '!')
  580.         return(cp2 + 1);
  581.     return(cp);
  582. }
  583.  
  584. #ifdef NOT_USED
  585. /*
  586.  * Skin an arpa net address.
  587.  * 
  588.  * We borrow adrparse from MMDF to do this.
  589.  */
  590. char *
  591. skin(name)
  592.     char *name;
  593. {
  594.     char nbuf[256], namecp[256], mbx[256], host[256];
  595.  
  596.     strcpy(namecp, name);        /* make it local */
  597.     parsadr(namecp, NOSTR, mbx, host);
  598.     if( *host )
  599.         sprintf(nbuf, "%s@%s", mbx, host);
  600.     else
  601.         strcpy(nbuf, mbx);
  602.     return(savestr(nbuf));
  603. }
  604. #endif NOT_USED
  605.   
  606. /*
  607.  * Fetch the sender's name from the passed message.
  608.  * Reptype can be
  609.  *    0 -- get sender's name for display purposes
  610.  *    1 -- get sender's name for reply
  611.  *    2 -- get sender's name for Reply
  612.  */
  613.  
  614. char *
  615. name1(mp, reptype)
  616.     register struct message *mp;
  617. {
  618.     char namebuf[LINESIZE];
  619.     char linebuf[LINESIZE];
  620.     register char *cp, *cp2;
  621.     register FILE *ibuf;
  622.     int first = 1;
  623.  
  624.     if ((cp = hfield("from", mp)) != NOSTR)
  625.         return(cp);
  626.     if (reptype == 0 && (cp = hfield("sender", mp)) != NOSTR)
  627.         return(cp);
  628.     ibuf = setinput(mp);
  629.     copy("", namebuf);
  630.     if (readline(ibuf, linebuf) <= 0)
  631.         return(savestr(namebuf));
  632. newname:
  633.     for (cp = linebuf; *cp != ' '; cp++)
  634.         ;
  635.     while (any(*cp, " \t"))
  636.         cp++;
  637.     for (cp2 = &namebuf[strlen(namebuf)]; *cp && !any(*cp, " \t") &&
  638.         cp2-namebuf < LINESIZE-1; *cp2++ = *cp++)
  639.         ;
  640.     *cp2 = '\0';
  641.     if (readline(ibuf, linebuf) <= 0)
  642.         return(savestr(namebuf));
  643.     if ((cp = index(linebuf, 'F')) == NULL)
  644.         return(savestr(namebuf));
  645.     if (strncmp(cp, "From", 4) != 0)
  646.         return(savestr(namebuf));
  647.     while ((cp = index(cp, 'r')) != NULL) {
  648.         if (strncmp(cp, "remote", 6) == 0) {
  649.             if ((cp = index(cp, 'f')) == NULL)
  650.                 break;
  651.             if (strncmp(cp, "from", 4) != 0)
  652.                 break;
  653.             if ((cp = index(cp, ' ')) == NULL)
  654.                 break;
  655.             cp++;
  656.             if (first) {
  657.                 copy(cp, namebuf);
  658.                 first = 0;
  659.             } else
  660.                 strcpy(rindex(namebuf, '!')+1, cp);
  661.             strcat(namebuf, "!");
  662.             goto newname;
  663.         }
  664.         cp++;
  665.     }
  666.     return(savestr(namebuf));
  667. }
  668.  
  669. /*
  670.  * Count the occurances of c in str
  671.  */
  672. charcount(str, c)
  673.     char *str;
  674. {
  675.     register char *cp;
  676.     register int i;
  677.  
  678.     for (i = 0, cp = str; *cp; cp++)
  679.         if (*cp == c)
  680.             i++;
  681.     return(i);
  682. }
  683.  
  684. #ifdef NOT_USED
  685. /*
  686.  * See if the string is a number.
  687.  */
  688.  
  689. numeric(str)
  690.     char str[];
  691. {
  692.     register char *cp = str;
  693.  
  694.     while (*cp)
  695.         if (!isdigit(*cp++))
  696.             return(0);
  697.     return(1);
  698. }
  699. #endif NOT_USED
  700.  
  701. /*
  702.  * Are any of the characters in the two strings the same?
  703.  */
  704.  
  705. anyof(s1, s2)
  706.     register char *s1, *s2;
  707. {
  708.     register int c;
  709.  
  710.     while (c = *s1++)
  711.         if (any(c, s2))
  712.             return(1);
  713.     return(0);
  714. }
  715.  
  716. /*
  717.  * See if the given header field is supposed to be ignored.
  718.  */
  719. isign(field)
  720.     char *field;
  721. {
  722.     char realfld[BUFSIZ];
  723.  
  724.     /*
  725.      * Lower-case the string, so that "Status" and "status"
  726.      * will hash to the same place.
  727.      */
  728.     istrcpy(realfld, field);
  729.  
  730.     if (nretained > 0)
  731.         return (!member(realfld, retain));
  732.     else
  733.         return (member(realfld, ignore));
  734. }
  735.  
  736. member(realfield, table)
  737.     register char *realfield;
  738.     register struct ignore **table;
  739. {
  740.     register struct ignore *igp;
  741.  
  742.     for (igp = table[hash(realfield)]; igp != 0; igp = igp->i_link)
  743.         if (equal(igp->i_field, realfield))
  744.             return (1);
  745.  
  746.     return (0);
  747. }
  748.  
  749. /*
  750.  * When comparing addresses, let's compare only mailbox@host, not
  751.  * a string compare.  Let's use a case insensitive string compare
  752.  * on the route.  Return values are same as icequal().
  753.  */
  754.  
  755. routeq(adr1, adr2)
  756. char *adr1, *adr2;
  757. {
  758.     char a1[BUFSIZ], a2[BUFSIZ], mbx[BUFSIZ], host[BUFSIZ];
  759.  
  760.     strcpy(a1, adr1); strcpy(a2, adr2); /* make them local */
  761.     parsadr(a1, NOSTR, mbx, host);
  762.     if (*host)
  763.         sprintf(a1, "%s@%s", mbx, host);
  764.     else
  765.         sprintf(a1, "%s", mbx);
  766.     parsadr(a2, NOSTR, mbx, host);
  767.     if (*host)
  768.         sprintf(a2, "%s@%s", mbx, host);
  769.     else
  770.         sprintf(a2, "%s", mbx);
  771.     return(icequal(a1, a2));
  772. }
  773.