home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / bsd_srcs / usr.bin / mail / fio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1991-04-18  |  9.5 KB  |  420 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[] = "@(#)fio.c    5.24 (Berkeley) 2/3/91";
  36. #endif /* not lint */
  37.  
  38. #include "rcv.h"
  39. #include <sys/stat.h>
  40. #include <sys/file.h>
  41. #include <sys/wait.h>
  42. #include <paths.h>
  43. #include <errno.h>
  44.  
  45. /*
  46.  * Mail -- a mail program
  47.  *
  48.  * File I/O.
  49.  */
  50.  
  51. /*
  52.  * Set up the input pointers while copying the mail file into /tmp.
  53.  */
  54. setptr(ibuf)
  55.     register FILE *ibuf;
  56. {
  57.     register int c, count;
  58.     register char *cp, *cp2;
  59.     struct message this;
  60.     FILE *mestmp;
  61.     off_t offset;
  62.     int maybe, inhead;
  63.     char linebuf[LINESIZE];
  64.  
  65.     /* Get temporary file. */
  66.     (void)sprintf(linebuf, "%s/mail.XXXXXX", _PATH_TMP);
  67.     if ((c = mkstemp(linebuf)) == -1 ||
  68.         (mestmp = Fdopen(c, "r+")) == NULL) {
  69.         (void)fprintf(stderr, "mail: can't open %s\n", linebuf);
  70.         exit(1);
  71.     }
  72.     (void)unlink(linebuf);
  73.  
  74.     msgCount = 0;
  75.     maybe = 1;
  76.     inhead = 0;
  77.     offset = 0;
  78.     this.m_flag = MUSED|MNEW;
  79.     this.m_size = 0;
  80.     this.m_lines = 0;
  81.     this.m_block = 0;
  82.     this.m_offset = 0;
  83.     for (;;) {
  84.         if (fgets(linebuf, LINESIZE, ibuf) == NULL) {
  85.             if (append(&this, mestmp)) {
  86.                 perror("temporary file");
  87.                 exit(1);
  88.             }
  89.             makemessage(mestmp);
  90.             return;
  91.         }
  92.         count = strlen(linebuf);
  93.         (void) fwrite(linebuf, sizeof *linebuf, count, otf);
  94.         if (ferror(otf)) {
  95.             perror("/tmp");
  96.             exit(1);
  97.         }
  98.         linebuf[count - 1] = 0;
  99.         if (maybe && linebuf[0] == 'F' && ishead(linebuf)) {
  100.             msgCount++;
  101.             if (append(&this, mestmp)) {
  102.                 perror("temporary file");
  103.                 exit(1);
  104.             }
  105.             this.m_flag = MUSED|MNEW;
  106.             this.m_size = 0;
  107.             this.m_lines = 0;
  108.             this.m_block = blockof(offset);
  109.             this.m_offset = offsetof(offset);
  110.             inhead = 1;
  111.         } else if (linebuf[0] == 0) {
  112.             inhead = 0;
  113.         } else if (inhead) {
  114.             for (cp = linebuf, cp2 = "status";; cp++) {
  115.                 if ((c = *cp2++) == 0) {
  116.                     while (isspace(*cp++))
  117.                         ;
  118.                     if (cp[-1] != ':')
  119.                         break;
  120.                     while (c = *cp++)
  121.                         if (c == 'R')
  122.                             this.m_flag |= MREAD;
  123.                         else if (c == 'O')
  124.                             this.m_flag &= ~MNEW;
  125.                     inhead = 0;
  126.                     break;
  127.                 }
  128.                 if (*cp != c && *cp != toupper(c))
  129.                     break;
  130.             }
  131.         }
  132.         offset += count;
  133.         this.m_size += count;
  134.         this.m_lines++;
  135.         maybe = linebuf[0] == 0;
  136.     }
  137. }
  138.  
  139. /*
  140.  * Drop the passed line onto the passed output buffer.
  141.  * If a write error occurs, return -1, else the count of
  142.  * characters written, including the newline.
  143.  */
  144. putline(obuf, linebuf)
  145.     FILE *obuf;
  146.     char *linebuf;
  147. {
  148.     register int c;
  149.  
  150.     c = strlen(linebuf);
  151.     (void) fwrite(linebuf, sizeof *linebuf, c, obuf);
  152.     (void) putc('\n', obuf);
  153.     if (ferror(obuf))
  154.         return (-1);
  155.     return (c + 1);
  156. }
  157.  
  158. /*
  159.  * Read up a line from the specified input into the line
  160.  * buffer.  Return the number of characters read.  Do not
  161.  * include the newline at the end.
  162.  */
  163. readline(ibuf, linebuf, linesize)
  164.     FILE *ibuf;
  165.     char *linebuf;
  166. {
  167.     register int n;
  168.  
  169.     clearerr(ibuf);
  170.     if (fgets(linebuf, linesize, ibuf) == NULL)
  171.         return -1;
  172.     n = strlen(linebuf);
  173.     if (n > 0 && linebuf[n - 1] == '\n')
  174.         linebuf[--n] = '\0';
  175.     return n;
  176. }
  177.  
  178. /*
  179.  * Return a file buffer all ready to read up the
  180.  * passed message pointer.
  181.  */
  182. FILE *
  183. setinput(mp)
  184.     register struct message *mp;
  185. {
  186.  
  187.     fflush(otf);
  188.     if (fseek(itf, positionof(mp->m_block, mp->m_offset), 0) < 0) {
  189.         perror("fseek");
  190.         panic("temporary file seek");
  191.     }
  192.     return (itf);
  193. }
  194.  
  195. /*
  196.  * Take the data out of the passed ghost file and toss it into
  197.  * a dynamically allocated message structure.
  198.  */
  199. makemessage(f)
  200.     FILE *f;
  201. {
  202.     register size = (msgCount + 1) * sizeof (struct message);
  203.     off_t lseek();
  204.  
  205.     if (message != 0)
  206.         free((char *) message);
  207.     if ((message = (struct message *) malloc((unsigned) size)) == 0)
  208.         panic("Insufficient memory for %d messages", msgCount);
  209.     dot = message;
  210.     size -= sizeof (struct message);
  211.     fflush(f);
  212.     (void) lseek(fileno(f), (long) sizeof *message, 0);
  213.     if (read(fileno(f), (char *) message, size) != size)
  214.         panic("Message temporary file corrupted");
  215.     message[msgCount].m_size = 0;
  216.     message[msgCount].m_lines = 0;
  217.     Fclose(f);
  218. }
  219.  
  220. /*
  221.  * Append the passed message descriptor onto the temp file.
  222.  * If the write fails, return 1, else 0
  223.  */
  224. append(mp, f)
  225.     struct message *mp;
  226.     FILE *f;
  227. {
  228.     return fwrite((char *) mp, sizeof *mp, 1, f) != 1;
  229. }
  230.  
  231. /*
  232.  * Delete a file, but only if the file is a plain file.
  233.  */
  234. rm(name)
  235.     char *name;
  236. {
  237.     struct stat sb;
  238.  
  239.     if (stat(name, &sb) < 0)
  240.         return(-1);
  241.     if (!S_ISREG(sb.st_mode)) {
  242.         errno = EISDIR;
  243.         return(-1);
  244.     }
  245.     return(unlink(name));
  246. }
  247.  
  248. static int sigdepth;        /* depth of holdsigs() */
  249. static int omask;
  250. /*
  251.  * Hold signals SIGHUP, SIGINT, and SIGQUIT.
  252.  */
  253. holdsigs()
  254. {
  255.  
  256.     if (sigdepth++ == 0)
  257.         omask = sigblock(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT));
  258. }
  259.  
  260. /*
  261.  * Release signals SIGHUP, SIGINT, and SIGQUIT.
  262.  */
  263. relsesigs()
  264. {
  265.  
  266.     if (--sigdepth == 0)
  267.         sigsetmask(omask);
  268. }
  269.  
  270. /*
  271.  * Determine the size of the file possessed by
  272.  * the passed buffer.
  273.  */
  274. off_t
  275. fsize(iob)
  276.     FILE *iob;
  277. {
  278.     struct stat sbuf;
  279.  
  280.     if (fstat(fileno(iob), &sbuf) < 0)
  281.         return 0;
  282.     return sbuf.st_size;
  283. }
  284.  
  285. /*
  286.  * Evaluate the string given as a new mailbox name.
  287.  * Supported meta characters:
  288.  *    %    for my system mail box
  289.  *    %user    for user's system mail box
  290.  *    #    for previous file
  291.  *    &    invoker's mbox file
  292.  *    +file    file in folder directory
  293.  *    any shell meta character
  294.  * Return the file name as a dynamic string.
  295.  */
  296. char *
  297. expand(name)
  298.     register char *name;
  299. {
  300.     char xname[PATHSIZE];
  301.     char cmdbuf[PATHSIZE];        /* also used for file names */
  302.     register int pid, l;
  303.     register char *cp, *shell;
  304.     int pivec[2];
  305.     struct stat sbuf;
  306.     extern union wait wait_status;
  307.  
  308.     /*
  309.      * The order of evaluation is "%" and "#" expand into constants.
  310.      * "&" can expand into "+".  "+" can expand into shell meta characters.
  311.      * Shell meta characters expand into constants.
  312.      * This way, we make no recursive expansion.
  313.      */
  314.     switch (*name) {
  315.     case '%':
  316.         findmail(name[1] ? name + 1 : myname, xname);
  317.         return savestr(xname);
  318.     case '#':
  319.         if (name[1] != 0)
  320.             break;
  321.         if (prevfile[0] == 0) {
  322.             printf("No previous file\n");
  323.             return NOSTR;
  324.         }
  325.         return savestr(prevfile);
  326.     case '&':
  327.         if (name[1] == 0 && (name = value("MBOX")) == NOSTR)
  328.             name = "~/mbox";
  329.         /* fall through */
  330.     }
  331.     if (name[0] == '+' && getfold(cmdbuf) >= 0) {
  332.         sprintf(xname, "%s/%s", cmdbuf, name + 1);
  333.         name = savestr(xname);
  334.     }
  335.     /* catch the most common shell meta character */
  336.     if (name[0] == '~' && (name[1] == '/' || name[1] == '\0')) {
  337.         sprintf(xname, "%s%s", homedir, name + 1);
  338.         name = savestr(xname);
  339.     }
  340.     if (!anyof(name, "~{[*?$`'\"\\"))
  341.         return name;
  342.     if (pipe(pivec) < 0) {
  343.         perror("pipe");
  344.         return name;
  345.     }
  346.     sprintf(cmdbuf, "echo %s", name);
  347.     if ((shell = value("SHELL")) == NOSTR)
  348.         shell = _PATH_CSHELL;
  349.     pid = start_command(shell, 0, -1, pivec[1], "-c", cmdbuf, NOSTR);
  350.     if (pid < 0) {
  351.         close(pivec[0]);
  352.         close(pivec[1]);
  353.         return NOSTR;
  354.     }
  355.     close(pivec[1]);
  356.     l = read(pivec[0], xname, BUFSIZ);
  357.     close(pivec[0]);
  358.     if (wait_child(pid) < 0 && wait_status.w_termsig != SIGPIPE) {
  359.         fprintf(stderr, "\"%s\": Expansion failed.\n", name);
  360.         return NOSTR;
  361.     }
  362.     if (l < 0) {
  363.         perror("read");
  364.         return NOSTR;
  365.     }
  366.     if (l == 0) {
  367.         fprintf(stderr, "\"%s\": No match.\n", name);
  368.         return NOSTR;
  369.     }
  370.     if (l == BUFSIZ) {
  371.         fprintf(stderr, "\"%s\": Expansion buffer overflow.\n", name);
  372.         return NOSTR;
  373.     }
  374.     xname[l] = 0;
  375.     for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
  376.         ;
  377.     cp[1] = '\0';
  378.     if (index(xname, ' ') && stat(xname, &sbuf) < 0) {
  379.         fprintf(stderr, "\"%s\": Ambiguous.\n", name);
  380.         return NOSTR;
  381.     }
  382.     return savestr(xname);
  383. }
  384.  
  385. /*
  386.  * Determine the current folder directory name.
  387.  */
  388. getfold(name)
  389.     char *name;
  390. {
  391.     char *folder;
  392.  
  393.     if ((folder = value("folder")) == NOSTR)
  394.         return (-1);
  395.     if (*folder == '/')
  396.         strcpy(name, folder);
  397.     else
  398.         sprintf(name, "%s/%s", homedir, folder);
  399.     return (0);
  400. }
  401.  
  402. /*
  403.  * Return the name of the dead.letter file.
  404.  */
  405. char *
  406. getdeadletter()
  407. {
  408.     register char *cp;
  409.  
  410.     if ((cp = value("DEAD")) == NOSTR || (cp = expand(cp)) == NOSTR)
  411.         cp = expand("~/dead.letter");
  412.     else if (*cp != '/') {
  413.         char buf[PATHSIZE];
  414.  
  415.         (void) sprintf(buf, "~/%s", cp);
  416.         cp = expand(buf);
  417.     }
  418.     return cp;
  419. }
  420.