BSD 4_3_Net_2 release
[unix-history] / usr / src / usr.bin / mail / edit.c
index fb913a5..8af0437 100644 (file)
@@ -1,17 +1,42 @@
 /*
  * Copyright (c) 1980 Regents of the University of California.
 /*
  * Copyright (c) 1980 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char *sccsid = "@(#)edit.c      5.4 (Berkeley) %G%";
-#endif not lint
+static char sccsid[] = "@(#)edit.c     5.15 (Berkeley) 6/25/90";
+#endif /* not lint */
 
 #include "rcv.h"
 
 #include "rcv.h"
-#include <stdio.h>
 #include <sys/stat.h>
 #include <sys/stat.h>
-#include <sys/wait.h>
 
 /*
  * Mail -- a mail program
 
 /*
  * Mail -- a mail program
@@ -26,11 +51,8 @@ static char *sccsid = "@(#)edit.c    5.4 (Berkeley) %G%";
 editor(msgvec)
        int *msgvec;
 {
 editor(msgvec)
        int *msgvec;
 {
-       char *edname;
 
 
-       if ((edname = value("EDITOR")) == NOSTR)
-               edname = EDITOR;
-       return(edit1(msgvec, edname));
+       return edit1(msgvec, 'e');
 }
 
 /*
 }
 
 /*
@@ -40,11 +62,8 @@ editor(msgvec)
 visual(msgvec)
        int *msgvec;
 {
 visual(msgvec)
        int *msgvec;
 {
-       char *edname;
 
 
-       if ((edname = value("VISUAL")) == NOSTR)
-               edname = VISUAL;
-       return(edit1(msgvec, edname));
+       return edit1(msgvec, 'v');
 }
 
 /*
 }
 
 /*
@@ -52,160 +71,148 @@ visual(msgvec)
  * (which should not exist) and forking an editor on it.
  * We get the editor from the stuff above.
  */
  * (which should not exist) and forking an editor on it.
  * We get the editor from the stuff above.
  */
-
-edit1(msgvec, ed)
+edit1(msgvec, type)
        int *msgvec;
        int *msgvec;
-       char *ed;
+       char type;
 {
        register int c;
 {
        register int c;
-       int *ip, pid, mesg;
-       int (*sigint)(), (*sigquit)();
-       FILE *ibuf, *obuf;
-       char edname[15];
+       int i;
+       FILE *fp;
        register struct message *mp;
        register struct message *mp;
-       extern char tempEdit[];
-       off_t fsize(), size;
-       struct stat statb;
-       long modtime;
-       union wait status;
-
-       /*
-        * Set signals; locate editor.
-        */
-
-       sigint = signal(SIGINT, SIG_IGN);
-       sigquit = signal(SIGQUIT, SIG_IGN);
+       off_t size;
 
        /*
         * Deal with each message to be edited . . .
         */
 
        /*
         * Deal with each message to be edited . . .
         */
+       for (i = 0; msgvec[i] && i < msgCount; i++) {
+               sig_t sigint;
 
 
-       for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
-               mesg = *ip;
-               mp = &message[mesg-1];
-               mp->m_flag |= MODIFY;
-               touch(mesg);
-               dot = mp;
-
-               /*
-                * Make up a name for the edit file of the
-                * form "Message%d" and make sure it doesn't
-                * already exist.
-                */
-               (void) sprintf(edname, "Message%d", mesg);
-               if (!access(edname, 2)) {
-                       printf("%s: file exists\n", edname);
-                       goto out;
-               }
+               if (i > 0) {
+                       char buf[100];
+                       char *p;
 
 
-               /*
-                * Copy the message into the edit file.
-                */
-               (void) close(creat(edname, 0600));
-               if ((obuf = fopen(edname, "w")) == NULL) {
-                       perror(edname);
-                       goto out;
-               }
-               if (send(mp, obuf, 0) < 0) {
-                       perror(edname);
-                       (void) fclose(obuf);
-                       (void) remove(edname);
-                       goto out;
+                       printf("Edit message %d [ynq]? ", msgvec[i]);
+                       if (fgets(buf, sizeof buf, stdin) == 0)
+                               break;
+                       for (p = buf; *p == ' ' || *p == '\t'; p++)
+                               ;
+                       if (*p == 'q')
+                               break;
+                       if (*p == 'n')
+                               continue;
                }
                }
-               (void) fflush(obuf);
-               if (ferror(obuf)) {
-                       (void) remove(edname);
-                       (void) fclose(obuf);
-                       goto out;
+               dot = mp = &message[msgvec[i] - 1];
+               touch(mp);
+               sigint = signal(SIGINT, SIG_IGN);
+               fp = run_editor(setinput(mp), mp->m_size, type, readonly);
+               if (fp != NULL) {
+                       (void) fseek(otf, (long) 0, 2);
+                       size = ftell(otf);
+                       mp->m_block = blockof(size);
+                       mp->m_offset = offsetof(size);
+                       mp->m_size = fsize(fp);
+                       mp->m_lines = 0;
+                       mp->m_flag |= MODIFY;
+                       rewind(fp);
+                       while ((c = getc(fp)) != EOF) {
+                               if (c == '\n')
+                                       mp->m_lines++;
+                               if (putc(c, otf) == EOF)
+                                       break;
+                       }
+                       if (ferror(otf))
+                               perror("/tmp");
+                       (void) Fclose(fp);
                }
                }
-               (void) fclose(obuf);
-
-               /*
-                * If we are in read only mode, make the
-                * temporary message file readonly as well.
-                */
-
-               if (readonly)
-                       (void) chmod(edname, 0400);
+               (void) signal(SIGINT, sigint);
+       }
+       return 0;
+}
 
 
-               /*
-                * Fork/execl the editor on the edit file.
-                */
+/*
+ * Run an editor on the file at "fpp" of "size" bytes,
+ * and return a new file pointer.
+ * Signals must be handled by the caller.
+ * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI.
+ */
+FILE *
+run_editor(fp, size, type, readonly)
+       register FILE *fp;
+       off_t size;
+       char type;
+{
+       register FILE *nf = NULL;
+       register int t;
+       time_t modtime;
+       char *edit;
+       struct stat statb;
+       extern char tempEdit[];
 
 
-               if (stat(edname, &statb) < 0)
-                       modtime = 0;
+       if ((t = creat(tempEdit, readonly ? 0400 : 0600)) < 0) {
+               perror(tempEdit);
+               goto out;
+       }
+       if ((nf = Fdopen(t, "w")) == NULL) {
+               perror(tempEdit);
+               (void) unlink(tempEdit);
+               goto out;
+       }
+       if (size >= 0)
+               while (--size >= 0 && (t = getc(fp)) != EOF)
+                       (void) putc(t, nf);
+       else
+               while ((t = getc(fp)) != EOF)
+                       (void) putc(t, nf);
+       (void) fflush(nf);
+       if (fstat(fileno(nf), &statb) < 0)
+               modtime = 0;
+       else
                modtime = statb.st_mtime;
                modtime = statb.st_mtime;
-               pid = vfork();
-               if (pid == -1) {
-                       perror("fork");
-                       (void) remove(edname);
-                       goto out;
-               }
-               if (pid == 0) {
-                       if (sigint != SIG_IGN)
-                               (void) signal(SIGINT, SIG_DFL);
-                       if (sigquit != SIG_IGN)
-                               (void) signal(SIGQUIT, SIG_DFL);
-                       execl(ed, ed, edname, 0);
-                       perror(ed);
-                       _exit(1);
-               }
-               while (wait(&status) != pid)
-                       ;
-
-               /*
-                * If in read only mode, just remove the editor
-                * temporary and return.
-                */
-
-               if (readonly) {
-                       (void) remove(edname);
-                       continue;
-               }
-
-               /*
-                * Now copy the message to the end of the
-                * temp file.
-                */
-
-               if (stat(edname, &statb) < 0) {
-                       perror(edname);
-                       goto out;
-               }
-               if (modtime == statb.st_mtime) {
-                       (void) remove(edname);
-                       goto out;
-               }
-               if ((ibuf = fopen(edname, "r")) == NULL) {
-                       perror(edname);
-                       (void) remove(edname);
-                       goto out;
-               }
-               (void) remove(edname);
-               (void) fseek(otf, (long) 0, 2);
-               size = ftell(otf);
-               mp->m_block = blockof(size);
-               mp->m_offset = offsetof(size);
-               mp->m_size = fsize(ibuf);
-               mp->m_lines = 0;
-               while ((c = getc(ibuf)) != EOF) {
-                       if (c == '\n')
-                               mp->m_lines++;
-                       (void) putc(c, otf);
-                       if (ferror(otf))
-                               break;
-               }
-               if (ferror(otf))
-                       perror("/tmp");
-               (void) fclose(ibuf);
+       if (ferror(nf)) {
+               (void) Fclose(nf);
+               perror(tempEdit);
+               (void) unlink(tempEdit);
+               nf = NULL;
+               goto out;
+       }
+       if (Fclose(nf) < 0) {
+               perror(tempEdit);
+               (void) unlink(tempEdit);
+               nf = NULL;
+               goto out;
+       }
+       nf = NULL;
+       if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NOSTR)
+               edit = type == 'e' ? _PATH_EX : _PATH_VI;
+       if (run_command(edit, 0, -1, -1, tempEdit, NOSTR) < 0) {
+               (void) unlink(tempEdit);
+               goto out;
        }
        }
-
        /*
        /*
-        * Restore signals and return.
+        * If in read only mode or file unchanged, just remove the editor
+        * temporary and return.
         */
         */
-
+       if (readonly) {
+               (void) unlink(tempEdit);
+               goto out;
+       }
+       if (stat(tempEdit, &statb) < 0) {
+               perror(tempEdit);
+               goto out;
+       }
+       if (modtime == statb.st_mtime) {
+               (void) unlink(tempEdit);
+               goto out;
+       }
+       /*
+        * Now switch to new file.
+        */
+       if ((nf = Fopen(tempEdit, "a+")) == NULL) {
+               perror(tempEdit);
+               (void) unlink(tempEdit);
+               goto out;
+       }
+       (void) unlink(tempEdit);
 out:
 out:
-       (void) signal(SIGINT, sigint);
-       (void) signal(SIGQUIT, sigquit);
-       return 0;
+       return nf;
 }
 }