home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Internet Tools 1993 July / Internet Tools.iso / RockRidge / mail / mmdf / mmdf-IIb.43 / uip / ucbmail / fio.c < prev    next >
Encoding:
C/C++ Source or Header  |  1988-03-28  |  12.4 KB  |  658 lines

  1. /*
  2.  *  F I O . 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.6 $
  12.  *
  13.  *  $Log:    fio.c,v $
  14.  * Revision 1.6  86/01/13  13:03:48  galvin
  15.  * Change format of debug output and delete one.
  16.  * 
  17.  * Revision 1.5  85/12/18  13:22:33  galvin
  18.  * Add another argument to send to indicate whether or not this
  19.  * message should be delimited by MMDF message delimiters.
  20.  * 
  21.  * Change all but "temp" file opens/closes to use MMDF locking routines.
  22.  * 
  23.  * Revision 1.4  85/11/20  14:34:38  galvin
  24.  * Added some debugging code -- ifdef'ed with DEBUG and dependent on
  25.  * debug -- and code to parse the MMDF message delimiters.  This code
  26.  * should still support the old style Mail format but since I cannot
  27.  * test this I don't know.
  28.  * 
  29.  * Revision 1.3  85/11/16  16:10:36  galvin
  30.  * Added define for sigmask for backward compatibility from 4.3bsd to 4.2bsd.
  31.  * 
  32.  * Revision 1.2  85/11/16  14:33:45  galvin
  33.  * Added comment header for revision history.
  34.  * 
  35.  *
  36.  */
  37.  
  38. /*
  39.  * Copyright (c) 1980 Regents of the University of California.
  40.  * All rights reserved.  The Berkeley software License Agreement
  41.  * specifies the terms and conditions for redistribution.
  42.  */
  43.  
  44. #ifndef lint
  45. static char *sccsid = "@(#)fio.c    5.2 (Berkeley) 6/21/85";
  46. #endif not lint
  47.  
  48. #include "./rcv.h"
  49. #include "./mmdf.h"
  50. #include <sys/stat.h>
  51. #include <ctype.h>
  52. #include <errno.h>
  53. #include "./sigretro.h"
  54.  
  55. /*
  56.  * Mail -- a mail program
  57.  *
  58.  * File I/O.
  59.  */
  60.  
  61. /*
  62.  * Set up the input pointers while copying the mail file into
  63.  * /tmp.
  64.  */
  65.  
  66. setptr(ibuf)
  67.     FILE *ibuf;
  68. {
  69.     register int c;
  70.     register char *cp, *cp2;
  71.     register int count, l;
  72.     long s;
  73.     off_t offset;
  74.     char linebuf[LINESIZE];
  75.     char wbuf[LINESIZE];
  76.     int maybe, mestmp, flag, inhead, newmsg,
  77.         len1 = strlen(delim1) - 1, len2 = strlen(delim2) - 1;
  78.     struct message this;
  79.     extern char tempSet[];
  80.  
  81.     if ((mestmp = opentemp(tempSet)) < 0)
  82.         exit(1);
  83.     msgCount = 0;
  84.     offset = 0;
  85.     s = 0L;
  86.     l = 0;
  87.     maybe = 1;
  88.     flag = MUSED|MNEW;
  89.     for (;;) {
  90.         cp = linebuf;
  91.         c = getc(ibuf);
  92.         while (c != EOF && c != '\n') {
  93.             if (cp - linebuf >= LINESIZE - 1) {
  94.                 ungetc(c, ibuf);
  95.                 *cp = 0;
  96.                 break;
  97.             }
  98.             *cp++ = c;
  99.             c = getc(ibuf);
  100.         }
  101.         *cp = 0;
  102.         if (cp == linebuf && c == EOF) {
  103. #ifdef DEBUG
  104.             if (debug)
  105.                 printf("setptr: no more messages.\n");
  106. #endif DEBUG
  107.             this.m_flag = flag;
  108.             flag = MUSED|MNEW;
  109.             this.m_offset = offsetof(offset);
  110.             this.m_block = blockof(offset);
  111.             this.m_size = s;
  112.             this.m_lines = l;
  113.             if (append(&this, mestmp)) {
  114.                 perror(tempSet);
  115.                 exit(1);
  116.             }
  117.             makemessage(mestmp);
  118.             close(mestmp);
  119.             return;
  120.         }
  121.         count = cp - linebuf + 1;
  122.         if (strncmp(linebuf, delim1, len1) == 0) {
  123.             maybe = newmsg = 1;
  124.             inhead = 0;
  125.             continue;
  126.         }
  127.         if (strncmp(linebuf, delim2, len2) == 0) {
  128.             inhead = maybe = newmsg = 0;
  129.             continue;
  130.         }
  131.         for (cp = linebuf; *cp;)
  132.             putc(*cp++, otf);
  133.         putc('\n', otf);
  134.         if (ferror(otf)) {
  135.             perror("/tmp");
  136.             exit(1);
  137.         }
  138.         if ((newmsg && !inhead) ||
  139.             (maybe && linebuf[0] == 'F' && ishead(linebuf))) {
  140. #ifdef DEBUG
  141.             if (debug)
  142.                 printf("setptr: new message.\n");
  143. #endif DEBUG
  144.             msgCount++;
  145.             this.m_flag = flag;
  146.             flag = MUSED|MNEW;
  147.             inhead = 1;
  148.             this.m_block = blockof(offset);
  149.             this.m_offset = offsetof(offset);
  150.             this.m_size = s;
  151.             this.m_lines = l;
  152.             s = 0L;
  153.             l = 0;
  154.             if (append(&this, mestmp)) {
  155.                 perror(tempSet);
  156.                 exit(1);
  157.             }
  158.             newmsg = 0;
  159.         }
  160.         if (linebuf[0] == 0)
  161.             inhead = 0;
  162.         if (inhead && index(linebuf, ':')) {
  163.             cp = linebuf;
  164.             cp2 = wbuf;
  165.             while (isalpha(*cp))
  166.                 *cp2++ = *cp++;
  167.             *cp2 = 0;
  168.             if (icequal(wbuf, "status")) {
  169.                 cp = index(linebuf, ':');
  170.                 if (index(cp, 'R'))
  171.                     flag |= MREAD;
  172.                 if (index(cp, 'O'))
  173.                     flag &= ~MNEW;
  174.                 inhead = 0;
  175.             }
  176.         }
  177.         offset += count;
  178.         s += (long) count;
  179.         l++;
  180.         maybe = 0;
  181.         if (linebuf[0] == 0)
  182.             maybe = 1;
  183.     }
  184. }
  185.  
  186. /*
  187.  * Drop the passed line onto the passed output buffer.
  188.  * If a write error occurs, return -1, else the count of
  189.  * characters written, including the newline.
  190.  */
  191.  
  192. putline(obuf, linebuf)
  193.     FILE *obuf;
  194.     char *linebuf;
  195. {
  196.     register int c;
  197.  
  198.     c = strlen(linebuf);
  199.     fputs(linebuf, obuf);
  200.     putc('\n', obuf);
  201.     if (ferror(obuf))
  202.         return(-1);
  203.     return(c+1);
  204. }
  205.  
  206. #ifdef NOT_USED
  207. /*
  208.  * Quickly read a line from the specified input into the line
  209.  * buffer; return characters read.
  210.  */
  211.  
  212. freadline(ibuf, linebuf)
  213.     register FILE *ibuf;
  214.     register char *linebuf;
  215. {
  216.     register int c;
  217.     register char *cp;
  218.  
  219.     c = getc(ibuf);
  220.     cp = linebuf;
  221.     while (c != '\n' && c != EOF) {
  222.         if (c == 0) {
  223.             c = getc(ibuf);
  224.             continue;
  225.         }
  226.         if (cp - linebuf >= BUFSIZ-1) {
  227.             *cp = 0;
  228.             return(cp - linebuf + 1);
  229.         }
  230.         *cp++ = c;
  231.         c = getc(ibuf);
  232.     }
  233.     if (c == EOF && cp == linebuf)
  234.         return(0);
  235.     *cp = 0;
  236.     return(cp - linebuf + 1);
  237. }
  238. #endif NOT_USED
  239.  
  240. /*
  241.  * Read up a line from the specified input into the line
  242.  * buffer.  Return the number of characters read.  Do not
  243.  * include the newline at the end.
  244.  */
  245.  
  246. readline(ibuf, linebuf)
  247.     FILE *ibuf;
  248.     char *linebuf;
  249. {
  250.     register int n;
  251.  
  252.     clearerr(ibuf);
  253.     if (fgets(linebuf, LINESIZE, ibuf) == NULL)
  254.         return(0);
  255.     n = strlen(linebuf);
  256.     if (n >= 1 && linebuf[n-1] == '\n')
  257.         linebuf[n-1] = '\0';
  258.     return(n);
  259. }
  260.  
  261. /*
  262.  * Return a file buffer all ready to read up the
  263.  * passed message pointer.
  264.  */
  265.  
  266. FILE *
  267. setinput(mp)
  268.     register struct message *mp;
  269. {
  270.     off_t off;
  271.  
  272.     fflush(otf);
  273.     off = mp->m_block;
  274.     off <<= 9;
  275.     off += mp->m_offset;
  276.     if (fseek(itf, off, 0) < 0) {
  277.         perror("fseek");
  278.         panic("temporary file seek");
  279.     }
  280.     return(itf);
  281. }
  282.  
  283. /*
  284.  * Take the data out of the passed ghost file and toss it into
  285.  * a dynamically allocated message structure.
  286.  */
  287.  
  288. makemessage(f)
  289. {
  290.     register struct message *m;
  291.     register char *mp;
  292.     register count;
  293.     long lseek();
  294.  
  295.     mp = calloc((unsigned) (msgCount + 1), sizeof *m);
  296.     if (mp == NOSTR) {
  297.         printf("Insufficient memory for %d messages\n", msgCount);
  298.         exit(1);
  299.     }
  300.     if (message != (struct message *) 0)
  301.         cfree((char *) message);
  302.     message = (struct message *) mp;
  303.     dot = message;
  304.     lseek(f, 0L, 0);
  305.     while (count = read(f, mp, BUFSIZ))
  306.         mp += count;
  307.     for (m = &message[0]; m < &message[msgCount]; m++) {
  308.         m->m_size = (m+1)->m_size;
  309.         m->m_lines = (m+1)->m_lines;
  310.         m->m_flag = (m+1)->m_flag;
  311.     }
  312.     message[msgCount].m_size = 0L;
  313.     message[msgCount].m_lines = 0;
  314. }
  315.  
  316. /*
  317.  * Append the passed message descriptor onto the temp file.
  318.  * If the write fails, return 1, else 0
  319.  */
  320.  
  321. append(mp, f)
  322.     struct message *mp;
  323. {
  324.     if (write(f, (char *) mp, sizeof *mp) != sizeof *mp)
  325.         return(1);
  326.     return(0);
  327. }
  328.  
  329. /*
  330.  * Delete a file, but only if the file is a plain file.
  331.  */
  332.  
  333. remove(name)
  334.     char name[];
  335. {
  336.     struct stat statb;
  337.     extern int errno;
  338.  
  339.     if (stat(name, &statb) < 0)
  340.         return(-1);
  341.     if ((statb.st_mode & S_IFMT) != S_IFREG) {
  342.         errno = EISDIR;
  343.         return(-1);
  344.     }
  345.     return(unlink(name));
  346. }
  347.  
  348. /*
  349.  * Terminate an editing session by attempting to write out the user's
  350.  * file from the temporary.  Save any new stuff appended to the file.
  351.  */
  352. edstop()
  353. {
  354.     register int gotcha, c;
  355.     register struct message *mp;
  356.     FILE *obuf, *ibuf, *readstat;
  357.     struct stat statb;
  358.     char tempname[30], *id;
  359.  
  360.     if (readonly)
  361.         return;
  362.     holdsigs();
  363.     if (Tflag != NOSTR) {
  364.         if ((readstat = fopen(Tflag, "w")) == NULL)
  365.             Tflag = NOSTR;
  366.     }
  367.     for (mp = &message[0], gotcha = 0; mp < &message[msgCount]; mp++) {
  368.         if (mp->m_flag & MNEW) {
  369.             mp->m_flag &= ~MNEW;
  370.             mp->m_flag |= MSTATUS;
  371.         }
  372.         if (mp->m_flag & (MODIFY|MDELETED|MSTATUS))
  373.             gotcha++;
  374.         if (Tflag != NOSTR && (mp->m_flag & (MREAD|MDELETED)) != 0) {
  375.             if ((id = hfield("article-id", mp)) != NOSTR)
  376.                 fprintf(readstat, "%s\n", id);
  377.         }
  378.     }
  379.     if (Tflag != NOSTR)
  380.         fclose(readstat);
  381.     if (!gotcha || Tflag != NOSTR)
  382.         goto done;
  383.     ibuf = NULL;
  384.     if (stat(editfile, &statb) >= 0 && statb.st_size > mailsize) {
  385.         strcpy(tempname, "/tmp/mboxXXXXXX");
  386.         mktemp(tempname);
  387.         if ((obuf = fopen(tempname, "w")) == NULL) {
  388.             perror(tempname);
  389.             relsesigs();
  390.             reset(0);
  391.         }
  392.         if ((ibuf = lk_fopen(editfile, "r", (char *) 0, (char *) 0, 5)) == NULL) {
  393.             perror(editfile);
  394.             fclose(obuf);
  395.             remove(tempname);
  396.             relsesigs();
  397.             reset(0);
  398.         }
  399.         fseek(ibuf, mailsize, 0);
  400.         while ((c = getc(ibuf)) != EOF)
  401.             putc(c, obuf);
  402.         lk_fclose(ibuf, editfile, (char *) 0, (char *) 0);
  403.         fclose(obuf);
  404.         if ((ibuf = fopen(tempname, "r")) == NULL) {
  405.             perror(tempname);
  406.             remove(tempname);
  407.             relsesigs();
  408.             reset(0);
  409.         }
  410.         remove(tempname);
  411.     }
  412.     printf("\"%s\" ", editfile);
  413.     fflush(stdout);
  414.     if ((obuf = lk_fopen(editfile, "w+", (char *) 0, (char *) 0, 5)) == NULL) {
  415.         perror(editfile);
  416.         relsesigs();
  417.         reset(0);
  418.     }
  419.     c = 0;
  420.     for (mp = &message[0]; mp < &message[msgCount]; mp++) {
  421.         if ((mp->m_flag & MDELETED) != 0)
  422.             continue;
  423.         c++;
  424.         if (send(mp, obuf, 0, 1) < 0) {
  425.             perror(editfile);
  426.             lk_fclose(obuf, editfile, (char *) 0, (char *) 0);
  427.             relsesigs();
  428.             reset(0);
  429.         }
  430.     }
  431.     gotcha = (c == 0 && ibuf == NULL);
  432.     if (ibuf != NULL) {
  433.         while ((c = getc(ibuf)) != EOF)
  434.             putc(c, obuf);
  435.         fclose(ibuf);
  436.     }
  437.     fflush(obuf);
  438.     if (ferror(obuf)) {
  439.         perror(editfile);
  440.         lk_fclose(obuf, editfile, (char *) 0, (char *) 0);
  441.         relsesigs();
  442.         reset(0);
  443.     }
  444.     lk_fclose(obuf, editfile, (char *) 0, (char *) 0);
  445.     if (gotcha) {
  446.         remove(editfile);
  447.         printf("removed\n");
  448.     }
  449.     else
  450.         printf("complete\n");
  451.     fflush(stdout);
  452.  
  453. done:
  454.     relsesigs();
  455. }
  456.  
  457. static int sigdepth = 0;        /* depth of holdsigs() */
  458. static int omask = 0;
  459. /*
  460.  * Hold signals SIGHUP - SIGQUIT.
  461.  */
  462. holdsigs()
  463. {
  464.  
  465. # ifdef V4_2BSD
  466.     if (sigdepth++ == 0)
  467.         omask = sigblock(sigmask(SIGHUP)|sigmask(SIGINT)|sigmask(SIGQUIT));
  468. # endif V4_2BSD
  469. # ifdef V4_1BSD
  470.     if (sigdepth++ == 0) {
  471.         sighold(SIGHUP);
  472.         sighold(SIGINT);
  473.         sighold(SIGQUIT);
  474.     }
  475. # endif V4_1BSD
  476. }
  477.  
  478. /*
  479.  * Release signals SIGHUP - SIGQUIT
  480.  */
  481. relsesigs()
  482. {
  483.  
  484. # ifdef V4_2BSD
  485.     if (--sigdepth == 0)
  486.         sigsetmask(omask);
  487. # endif V4_2BSD
  488. # ifdef V4_1BSD
  489.     if (--sigdepth == 0) {
  490.         sigrelse(SIGINT);
  491.         sigrelse(SIGHUP);
  492.         sigrelse(SIGQUIT);
  493.     }
  494. # endif V4_1BSD
  495. }
  496.  
  497. /*
  498.  * Open a temp file by creating, closing, unlinking, and
  499.  * reopening.  Return the open file descriptor.
  500.  */
  501.  
  502. opentemp(file)
  503.     char file[];
  504. {
  505.     register int f;
  506.  
  507.     if ((f = creat(file, 0600)) < 0) {
  508.         perror(file);
  509.         return(-1);
  510.     }
  511.     close(f);
  512.     if ((f = open(file, 2)) < 0) {
  513.         perror(file);
  514.         remove(file);
  515.         return(-1);
  516.     }
  517.     remove(file);
  518.     return(f);
  519. }
  520.  
  521. /*
  522.  * Determine the size of the file possessed by
  523.  * the passed buffer.
  524.  */
  525.  
  526. off_t
  527. fsize(iob)
  528.     FILE *iob;
  529. {
  530.     register int f;
  531.     struct stat sbuf;
  532.  
  533.     f = fileno(iob);
  534.     if (fstat(f, &sbuf) < 0)
  535.         return(0);
  536.     return(sbuf.st_size);
  537. }
  538.  
  539. /*
  540.  * Take a file name, possibly with shell meta characters
  541.  * in it and expand it by using "sh -c echo filename"
  542.  * Return the file name as a dynamic string.
  543.  */
  544.  
  545. char *
  546. expand(name)
  547.     char name[];
  548. {
  549.     char xname[BUFSIZ];
  550.     char cmdbuf[BUFSIZ];
  551.     register int pid, l;
  552.     register char *cp, *Shell;
  553.     int s, pivec[2];
  554.     struct stat sbuf;
  555.  
  556.     if (name[0] == '+' && getfold(cmdbuf) >= 0) {
  557.         sprintf(xname, "%s/%s", cmdbuf, name + 1);
  558.         return(expand(savestr(xname)));
  559.     }
  560.     if (!anyof(name, "~{[*?$`'\"\\"))
  561.         return(name);
  562.     if (pipe(pivec) < 0) {
  563.         perror("pipe");
  564.         return(name);
  565.     }
  566.     sprintf(cmdbuf, "echo %s", name);
  567.     if ((pid = vfork()) == 0) {
  568.         sigchild();
  569.         Shell = value("SHELL");
  570.         if (Shell == NOSTR)
  571.             Shell = SHELL;
  572.         close(pivec[0]);
  573.         close(1);
  574.         dup(pivec[1]);
  575.         close(pivec[1]);
  576.         close(2);
  577.         execl(Shell, Shell, "-c", cmdbuf, 0);
  578.         _exit(1);
  579.     }
  580.     if (pid == -1) {
  581.         perror("fork");
  582.         close(pivec[0]);
  583.         close(pivec[1]);
  584.         return(NOSTR);
  585.     }
  586.     close(pivec[1]);
  587.     l = read(pivec[0], xname, BUFSIZ);
  588.     close(pivec[0]);
  589.     while (wait(&s) != pid);
  590.         ;
  591.     s &= 0377;
  592.     if (s != 0 && s != SIGPIPE) {
  593.         fprintf(stderr, "\"Echo\" failed\n");
  594.         goto err;
  595.     }
  596.     if (l < 0) {
  597.         perror("read");
  598.         goto err;
  599.     }
  600.     if (l == 0) {
  601.         fprintf(stderr, "\"%s\": No match\n", name);
  602.         goto err;
  603.     }
  604.     if (l == BUFSIZ) {
  605.         fprintf(stderr, "Buffer overflow expanding \"%s\"\n", name);
  606.         goto err;
  607.     }
  608.     xname[l] = 0;
  609.     for (cp = &xname[l-1]; *cp == '\n' && cp > xname; cp--)
  610.         ;
  611.     *++cp = '\0';
  612.     if (any(' ', xname) && stat(xname, &sbuf) < 0) {
  613.         fprintf(stderr, "\"%s\": Ambiguous\n", name);
  614.         goto err;
  615.     }
  616.     return(savestr(xname));
  617.  
  618. err:
  619.     return(NOSTR);
  620. }
  621.  
  622. /*
  623.  * Determine the current folder directory name.
  624.  */
  625. getfold(name)
  626.     char *name;
  627. {
  628.     char *folder;
  629.  
  630.     if ((folder = value("folder")) == NOSTR)
  631.         return(-1);
  632.     if (*folder == '/')
  633.         strcpy(name, folder);
  634.     else
  635.         sprintf(name, "%s/%s", homedir, folder);
  636.     return(0);
  637. }
  638.  
  639. /*
  640.  * A nicer version of Fdopen, which allows us to fclose
  641.  * without losing the open file.
  642.  */
  643.  
  644. FILE *
  645. Fdopen(fildes, mode)
  646.     char *mode;
  647. {
  648.     register int f;
  649.     FILE *fdopen();
  650.  
  651.     f = dup(fildes);
  652.     if (f < 0) {
  653.         perror("dup");
  654.         return(NULL);
  655.     }
  656.     return(fdopen(f, mode));
  657. }
  658.