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: #if !defined(lint) && defined(DOSCCS) 35: static char sccsid[] = "@(#)edit.c 5.15.1 (2.11BSD) 1996/1/27"; 36: #endif 37: 38: #include "rcv.h" 39: #include <sys/stat.h> 40: 41: /* 42: * Mail -- a mail program 43: * 44: * Perform message editing functions. 45: */ 46: 47: /* 48: * Edit a message list. 49: */ 50: 51: editor(msgvec) 52: int *msgvec; 53: { 54: 55: return edit1(msgvec, 'e'); 56: } 57: 58: /* 59: * Invoke the visual editor on a message list. 60: */ 61: 62: visual(msgvec) 63: int *msgvec; 64: { 65: 66: return edit1(msgvec, 'v'); 67: } 68: 69: /* 70: * Edit a message by writing the message into a funnily-named file 71: * (which should not exist) and forking an editor on it. 72: * We get the editor from the stuff above. 73: */ 74: edit1(msgvec, type) 75: int *msgvec; 76: char type; 77: { 78: register int c; 79: int i; 80: FILE *fp; 81: register struct message *mp; 82: off_t size; 83: 84: /* 85: * Deal with each message to be edited . . . 86: */ 87: for (i = 0; msgvec[i] && i < msgCount; i++) { 88: sig_t sigint; 89: 90: if (i > 0) { 91: char buf[100]; 92: char *p; 93: 94: printf("Edit message %d [ynq]? ", msgvec[i]); 95: if (fgets(buf, sizeof buf, stdin) == 0) 96: break; 97: for (p = buf; *p == ' ' || *p == '\t'; p++) 98: ; 99: if (*p == 'q') 100: break; 101: if (*p == 'n') 102: continue; 103: } 104: dot = mp = &message[msgvec[i] - 1]; 105: touch(mp); 106: sigint = signal(SIGINT, SIG_IGN); 107: fp = run_editor(setinput(mp), mp->m_size, type, readonly); 108: if (fp != NULL) { 109: (void) fseek(otf, (long) 0, 2); 110: size = ftell(otf); 111: mp->m_block = blockof(size); 112: mp->m_offset = offstof(size); 113: mp->m_size = fsize(fp); 114: mp->m_lines = 0; 115: mp->m_flag |= MODIFY; 116: rewind(fp); 117: while ((c = getc(fp)) != EOF) { 118: if (c == '\n') 119: mp->m_lines++; 120: if (putc(c, otf) == EOF) 121: break; 122: } 123: if (ferror(otf)) 124: perror("/tmp"); 125: (void) Fclose(fp); 126: } 127: (void) signal(SIGINT, sigint); 128: } 129: return 0; 130: } 131: 132: /* 133: * Run an editor on the file at "fpp" of "size" bytes, 134: * and return a new file pointer. 135: * Signals must be handled by the caller. 136: * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI. 137: */ 138: FILE * 139: run_editor(fp, size, type, readonly) 140: register FILE *fp; 141: off_t size; 142: char type; 143: { 144: register FILE *nf = NULL; 145: register int t; 146: time_t modtime; 147: char *edit; 148: struct stat statb; 149: extern char tempEdit[]; 150: 151: if ((t = creat(tempEdit, readonly ? 0400 : 0600)) < 0) { 152: perror(tempEdit); 153: goto out; 154: } 155: if ((nf = Fdopen(t, "w")) == NULL) { 156: perror(tempEdit); 157: (void) unlink(tempEdit); 158: goto out; 159: } 160: if (size >= 0) 161: while (--size >= 0 && (t = getc(fp)) != EOF) 162: (void) putc(t, nf); 163: else 164: while ((t = getc(fp)) != EOF) 165: (void) putc(t, nf); 166: (void) fflush(nf); 167: if (fstat(fileno(nf), &statb) < 0) 168: modtime = 0; 169: else 170: modtime = statb.st_mtime; 171: if (ferror(nf)) { 172: (void) Fclose(nf); 173: perror(tempEdit); 174: (void) unlink(tempEdit); 175: nf = NULL; 176: goto out; 177: } 178: if (Fclose(nf) < 0) { 179: perror(tempEdit); 180: (void) unlink(tempEdit); 181: nf = NULL; 182: goto out; 183: } 184: nf = NULL; 185: if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NOSTR) 186: edit = type == 'e' ? _PATH_EX : _PATH_VI; 187: if (run_command(edit, 0L, -1, -1, tempEdit, NOSTR) < 0) { 188: (void) unlink(tempEdit); 189: goto out; 190: } 191: /* 192: * If in read only mode or file unchanged, just remove the editor 193: * temporary and return. 194: */ 195: if (readonly) { 196: (void) unlink(tempEdit); 197: goto out; 198: } 199: if (stat(tempEdit, &statb) < 0) { 200: perror(tempEdit); 201: goto out; 202: } 203: if (modtime == statb.st_mtime) { 204: (void) unlink(tempEdit); 205: goto out; 206: } 207: /* 208: * Now switch to new file. 209: */ 210: if ((nf = Fopen(tempEdit, "a+")) == NULL) { 211: perror(tempEdit); 212: (void) unlink(tempEdit); 213: goto out; 214: } 215: (void) unlink(tempEdit); 216: out: 217: return nf; 218: }