home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / metamail / tahoe / fio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-02-18  |  9.7 KB  |  501 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[] = "@(#)fio.c    5.6 (Berkeley) 2/18/88";
  15. #endif /* notdef */
  16.  
  17. #include "rcv.h"
  18. #include <sys/stat.h>
  19. #include <sys/file.h>
  20. #include <sys/wait.h>
  21. #include <errno.h>
  22.  
  23. /*
  24.  * Mail -- a mail program
  25.  *
  26.  * File I/O.
  27.  */
  28.  
  29. /*
  30.  * Set up the input pointers while copying the mail file into
  31.  * /tmp.
  32.  */
  33. setptr(ibuf)
  34.     register FILE *ibuf;
  35. {
  36.     register c;
  37.     register char *cp, *cp2;
  38.     register count;
  39.     char linebuf[LINESIZE];
  40.     int maybe, inhead;
  41.     FILE *mestmp;
  42.     off_t offset;
  43.     struct message this;
  44.     extern char tempSet[];
  45.  
  46.     if ((c = opentemp(tempSet)) < 0)
  47.         exit(1);
  48.     if ((mestmp = fdopen(c, "r+")) == NULL)
  49.         panic("Can't open temporary");
  50.     msgCount = 0;
  51.     maybe = 1;
  52.     inhead = 0;
  53.     offset = 0;
  54.     this.m_flag = MUSED|MNEW;
  55.     this.m_size = 0;
  56.     this.m_lines = 0;
  57.     this.m_block = 0;
  58.     this.m_offset = 0;
  59.     for (;;) {
  60.         if (fgets(linebuf, LINESIZE, ibuf) == NULL) {
  61.             if (append(&this, mestmp)) {
  62.                 perror(tempSet);
  63.                 exit(1);
  64.             }
  65.             fclose(ibuf);
  66.             makemessage(mestmp);
  67.             return;
  68.         }
  69.         count = strlen(linebuf);
  70.         fwrite(linebuf, sizeof *linebuf, count, otf);
  71.         if (ferror(otf)) {
  72.             perror("/tmp");
  73.             exit(1);
  74.         }
  75.         linebuf[count - 1] = 0;
  76.         if (maybe && linebuf[0] == 'F' && ishead(linebuf)) {
  77.             msgCount++;
  78.             if (append(&this, mestmp)) {
  79.                 perror(tempSet);
  80.                 exit(1);
  81.             }
  82.             this.m_flag = MUSED|MNEW;
  83.             this.m_size = 0;
  84.             this.m_lines = 0;
  85.             this.m_block = blockof(offset);
  86.             this.m_offset = offsetof(offset);
  87.             inhead = 1;
  88.         } else if (linebuf[0] == 0) {
  89.             inhead = 0;
  90.         } else if (inhead) {
  91.             for (cp = linebuf, cp2 = "status";; cp++) {
  92.                 if ((c = *cp2++) == 0) {
  93.                     while (isspace(*cp++))
  94.                         ;
  95.                     if (cp[-1] != ':')
  96.                         break;
  97.                     while (c = *cp++)
  98.                         if (c == 'R')
  99.                             this.m_flag |= MREAD;
  100.                         else if (c == 'O')
  101.                             this.m_flag &= ~MNEW;
  102.                     inhead = 0;
  103.                     break;
  104.                 }
  105.                 if (*cp != c && *cp != toupper(c))
  106.                     break;
  107.             }
  108.         }
  109.         offset += count;
  110.         this.m_size += count;
  111.         this.m_lines++;
  112.         maybe = linebuf[0] == 0;
  113.     }
  114. }
  115.  
  116. /*
  117.  * Drop the passed line onto the passed output buffer.
  118.  * If a write error occurs, return -1, else the count of
  119.  * characters written, including the newline.
  120.  */
  121. putline(obuf, linebuf)
  122.     FILE *obuf;
  123.     char *linebuf;
  124. {
  125.     register int c;
  126.  
  127.     c = strlen(linebuf);
  128.     fwrite(linebuf, sizeof *linebuf, c, obuf);
  129.     putc('\n', obuf);
  130.     if (ferror(obuf))
  131.         return (-1);
  132.     return (c + 1);
  133. }
  134.  
  135. /*
  136.  * Read up a line from the specified input into the line
  137.  * buffer.  Return the number of characters read.  Do not
  138.  * include the newline at the end.
  139.  */
  140. readline(ibuf, linebuf)
  141.     FILE *ibuf;
  142.     char *linebuf;
  143. {
  144.     register int n;
  145.  
  146.     clearerr(ibuf);
  147.     if (fgets(linebuf, LINESIZE, ibuf) == NULL)
  148.         return -1;
  149.     n = strlen(linebuf);
  150.     if (n > 0 && linebuf[n - 1] == '\n')
  151.         linebuf[--n] = '\0';
  152.     return n;
  153. }
  154.  
  155. /*
  156.  * Return a file buffer all ready to read up the
  157.  * passed message pointer.
  158.  */
  159. FILE *
  160. setinput(mp)
  161.     register struct message *mp;
  162. {
  163.  
  164.     fflush(otf);
  165.     if (fseek(itf, positionof(mp->m_block, mp->m_offset), 0) < 0) {
  166.         perror("fseek");
  167.         panic("temporary file seek");
  168.     }
  169.     return (itf);
  170. }
  171.  
  172. /*
  173.  * Take the data out of the passed ghost file and toss it into
  174.  * a dynamically allocated message structure.
  175.  */
  176. makemessage(f)
  177.     FILE *f;
  178. {
  179.     register size = (msgCount + 1) * sizeof (struct message);
  180.     off_t lseek();
  181.  
  182.     if (message != 0)
  183.         free((char *) message);
  184.     if ((message = (struct message *) malloc((unsigned) size)) == 0)
  185.         panic("Insufficient memory for %d messages", msgCount);
  186.     dot = message;
  187.     size -= sizeof (struct message);
  188.     fflush(f);
  189.     lseek(fileno(f), (long) sizeof *message, 0);
  190.     if (read(fileno(f), (char *) message, size) != size)
  191.         panic("Message temporary file corrupted");
  192.     message[msgCount].m_size = 0;
  193.     message[msgCount].m_lines = 0;
  194.     fclose(f);
  195. }
  196.  
  197. /*
  198.  * Append the passed message descriptor onto the temp file.
  199.  * If the write fails, return 1, else 0
  200.  */
  201. append(mp, f)
  202.     struct message *mp;
  203.     FILE *f;
  204. {
  205.     return fwrite((char *) mp, sizeof *mp, 1, f) != 1;
  206. }
  207.  
  208. /*
  209.  * Delete a file, but only if the file is a plain file.
  210.  */
  211. remove(name)
  212.     char name[];
  213. {
  214.     struct stat statb;
  215.     extern int errno;
  216.  
  217.     if (stat(name, &statb) < 0)
  218.         return(-1);
  219.     if ((statb.st_mode & S_IFMT) != S_IFREG) {
  220.         errno = EISDIR;
  221.         return(-1);
  222.     }
  223.     return unlink(name);
  224. }
  225.  
  226. /*
  227.  * Terminate an editing session by attempting to write out the user's
  228.  * file from the temporary.  Save any new stuff appended to the file.
  229.  */
  230. edstop()
  231. {
  232.     register int gotcha, c;
  233.     register struct message *mp;
  234.     FILE *obuf, *ibuf, *readstat;
  235.     struct stat statb;
  236.     char tempname[30], *id;
  237.     char *mktemp();
  238.  
  239.     if (readonly)
  240.         return;
  241.     holdsigs();
  242.     if (Tflag != NOSTR) {
  243.         if ((readstat = fopen(Tflag, "w")) == NULL)
  244.             Tflag = NOSTR;
  245.     }
  246.     for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
  247.         if (mp->m_flag & MNEW) {
  248.             mp->m_flag &= ~MNEW;
  249.             mp->m_flag |= MSTATUS;
  250.         }
  251.         if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
  252.             gotcha++;
  253.         if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
  254.             if ((id = hfield("article-id", mp)) != NOSTR)
  255.                 fprintf(readstat, "%s\n", id);
  256.         }
  257.     }
  258.     if (Tflag != NOSTR)
  259.         fclose(readstat);
  260.     if (!gotcha || Tflag != NOSTR)
  261.         goto done;
  262.     ibuf = NULL;
  263.     if (stat(editfile, &statb) >= 0 && statb.st_size > mailsize) {
  264.         strcpy(tempname, "/tmp/mboxXXXXXX");
  265.         mktemp(tempname);
  266.         if ((obuf = fopen(tempname, "w")) == NULL) {
  267.             perror(tempname);
  268.             relsesigs();
  269.             reset(0);
  270.         }
  271.         if ((ibuf = fopen(editfile, "r")) == NULL) {
  272.             perror(editfile);
  273.             fclose(obuf);
  274.             remove(tempname);
  275.             relsesigs();
  276.             reset(0);
  277.         }
  278.         fseek(ibuf, mailsize, 0);
  279.         while ((c = getc(ibuf)) != EOF)
  280.             putc(c, obuf);
  281.         fclose(ibuf);
  282.         fclose(obuf);
  283.         if ((ibuf = fopen(tempname, "r")) == NULL) {
  284.             perror(tempname);
  285.             remove(tempname);
  286.             relsesigs();
  287.             reset(0);
  288.         }
  289.         remove(tempname);
  290.     }
  291.     printf("\"%s\" ", editfile);
  292.     fflush(stdout);
  293.     if ((obuf = fopen(editfile, "r+")) == NULL) {
  294.         perror(editfile);
  295.         relsesigs();
  296.         reset(0);
  297.     }
  298.     trunc(obuf);
  299.     c = 0;
  300.     for (mp = &message[0]; mp < &message[msgCount]; mp++) {
  301.         if ((mp->m_flag & MDELETED) != 0)
  302.             continue;
  303.         c++;
  304.         if (send(mp, obuf, 0) < 0) {
  305.             perror(editfile);
  306.             relsesigs();
  307.             reset(0);
  308.         }
  309.     }
  310.     gotcha = (c == 0 && ibuf == NULL);
  311.     if (ibuf != NULL) {
  312.         while ((c = getc(ibuf)) != EOF)
  313.             putc(c, obuf);
  314.         fclose(ibuf);
  315.     }
  316.     fflush(obuf);
  317.     if (ferror(obuf)) {
  318.         perror(editfile);
  319.         relsesigs();
  320.         reset(0);
  321.     }
  322.     fclose(obuf);
  323.     if (gotcha) {
  324.         remove(editfile);
  325.         printf("removed\n");
  326.     }
  327.     else
  328.         printf("complete\n");
  329.     fflush(stdout);
  330.  
  331. done:
  332.     relsesigs();
  333. }
  334.  
  335. static int sigdepth = 0;        /* depth of holdsigs() */
  336. static int omask = 0;
  337. /*
  338.  * Hold signals SIGHUP, SIGINT, and SIGQUIT.
  339.  */
  340. holdsigs()
  341. {
  342.  
  343.     if (sigdepth++ == 0)
  344.         omask = sigblock(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT));
  345. }
  346.  
  347. /*
  348.  * Release signals SIGHUP, SIGINT, and SIGQUIT.
  349.  */
  350. relsesigs()
  351. {
  352.  
  353.     if (--sigdepth == 0)
  354.         sigsetmask(omask);
  355. }
  356.  
  357. /*
  358.  * Open a temp file by creating and unlinking.
  359.  * Return the open file descriptor.
  360.  */
  361. opentemp(file)
  362.     char file[];
  363. {
  364.     int f;
  365.  
  366.     if ((f = open(file, O_CREAT|O_EXCL|O_RDWR, 0600)) < 0)
  367.         perror(file);
  368.     remove(file);
  369.     return (f);
  370. }
  371.  
  372. /*
  373.  * Determine the size of the file possessed by
  374.  * the passed buffer.
  375.  */
  376. off_t
  377. fsize(iob)
  378.     FILE *iob;
  379. {
  380.     struct stat sbuf;
  381.  
  382.     if (fstat(fileno(iob), &sbuf) < 0)
  383.         return 0;
  384.     return sbuf.st_size;
  385. }
  386.  
  387. /*
  388.  * Take a file name, possibly with shell meta characters
  389.  * in it and expand it by using "sh -c echo filename"
  390.  * Return the file name as a dynamic string.
  391.  */
  392. char *
  393. expand(name)
  394.     char name[];
  395. {
  396.     char xname[BUFSIZ];
  397.     char cmdbuf[BUFSIZ];
  398.     register int pid, l;
  399.     register char *cp, *Shell;
  400.     int pivec[2];
  401.     struct stat sbuf;
  402.     union wait s;
  403.  
  404.     if (name[0] == '+' && getfold(cmdbuf) >= 0) {
  405.         sprintf(xname, "%s/%s", cmdbuf, name + 1);
  406.         return(expand(savestr(xname)));
  407.     }
  408.     if (!anyof(name, "~{[*?$`'\"\\"))
  409.         return(name);
  410.     if (pipe(pivec) < 0) {
  411.         perror("pipe");
  412.         return(name);
  413.     }
  414.     sprintf(cmdbuf, "echo %s", name);
  415.     if ((pid = vfork()) == 0) {
  416.         Shell = value("SHELL");
  417.         if (Shell == NOSTR)
  418.             Shell = SHELL;
  419.         close(pivec[0]);
  420.         close(1);
  421.         dup(pivec[1]);
  422.         close(pivec[1]);
  423.         close(2);
  424.         execl(Shell, Shell, "-c", cmdbuf, 0);
  425.         _exit(1);
  426.     }
  427.     if (pid == -1) {
  428.         perror("fork");
  429.         close(pivec[0]);
  430.         close(pivec[1]);
  431.         return(NOSTR);
  432.     }
  433.     close(pivec[1]);
  434.     l = read(pivec[0], xname, BUFSIZ);
  435.     close(pivec[0]);
  436.     while (wait(&s) != pid);
  437.         ;
  438.     if (s.w_status != 0 && s.w_termsig != SIGPIPE) {
  439.         fprintf(stderr, "\"Echo\" failed\n");
  440.         goto err;
  441.     }
  442.     if (l < 0) {
  443.         perror("read");
  444.         goto err;
  445.     }
  446.     if (l == 0) {
  447.         fprintf(stderr, "\"%s\": No match\n", name);
  448.         goto err;
  449.     }
  450.     if (l == BUFSIZ) {
  451.         fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
  452.         goto err;
  453.     }
  454.     xname[l] = 0;
  455.     for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
  456.         ;
  457.     *++cp = '\0';
  458.     if (any(' ', xname) && stat(xname, &sbuf) < 0) {
  459.         fprintf(stderr, "\"%s\": Ambiguous\n", name);
  460.         goto err;
  461.     }
  462.     return(savestr(xname));
  463.  
  464. err:
  465.     return(NOSTR);
  466. }
  467.  
  468. /*
  469.  * Determine the current folder directory name.
  470.  */
  471. getfold(name)
  472.     char *name;
  473. {
  474.     char *folder;
  475.  
  476.     if ((folder = value("folder")) == NOSTR)
  477.         return (-1);
  478.     if (*folder == '/')
  479.         strcpy(name, folder);
  480.     else
  481.         sprintf(name, "%s/%s", homedir, folder);
  482.     return (0);
  483. }
  484.  
  485. /*
  486.  * A nicer version of Fdopen, which allows us to fclose
  487.  * without losing the open file.
  488.  */
  489. FILE *
  490. Fdopen(fildes, mode)
  491.     char *mode;
  492. {
  493.     int f;
  494.  
  495.     if ((f = dup(fildes)) < 0) {
  496.         perror("dup");
  497.         return (NULL);
  498.     }
  499.     return fdopen(f, mode);
  500. }
  501.