1 /* $OpenBSD: edit.c,v 1.7 1997/11/14 00:23:45 millert Exp $ */ 2 /* $NetBSD: edit.c,v 1.5 1996/06/08 19:48:20 christos Exp $ */ 3 4 /* 5 * Copyright (c) 1980, 1993 6 * The Regents of the University of California. All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 */ 36 37 #ifndef lint 38 #if 0 39 static char sccsid[] = "@(#)edit.c 8.1 (Berkeley) 6/6/93"; 40 #else 41 static char rcsid[] = "$OpenBSD: edit.c,v 1.7 1997/11/14 00:23:45 millert Exp $"; 42 #endif 43 #endif /* not lint */ 44 45 #include "rcv.h" 46 #include <fcntl.h> 47 #include "extern.h" 48 49 /* 50 * Mail -- a mail program 51 * 52 * Perform message editing functions. 53 */ 54 55 /* 56 * Edit a message list. 57 */ 58 int 59 editor(v) 60 void *v; 61 { 62 int *msgvec = v; 63 64 return(edit1(msgvec, 'e')); 65 } 66 67 /* 68 * Invoke the visual editor on a message list. 69 */ 70 int 71 visual(v) 72 void *v; 73 { 74 int *msgvec = v; 75 76 return(edit1(msgvec, 'v')); 77 } 78 79 /* 80 * Edit a message by writing the message into a funnily-named file 81 * (which should not exist) and forking an editor on it. 82 * We get the editor from the stuff above. 83 */ 84 int 85 edit1(msgvec, type) 86 int *msgvec; 87 int type; 88 { 89 int c, i; 90 FILE *fp; 91 struct message *mp; 92 off_t size; 93 94 /* 95 * Deal with each message to be edited . . . 96 */ 97 for (i = 0; msgvec[i] && i < msgCount; i++) { 98 sig_t sigint; 99 100 if (i > 0) { 101 char buf[100]; 102 char *p; 103 104 printf("Edit message %d [ynq]? ", msgvec[i]); 105 if (fgets(buf, sizeof(buf), stdin) == 0) 106 break; 107 for (p = buf; *p == ' ' || *p == '\t'; p++) 108 ; 109 if (*p == 'q') 110 break; 111 if (*p == 'n') 112 continue; 113 } 114 dot = mp = &message[msgvec[i] - 1]; 115 touch(mp); 116 sigint = signal(SIGINT, SIG_IGN); 117 fp = run_editor(setinput(mp), mp->m_size, type, readonly); 118 if (fp != NULL) { 119 (void)fseek(otf, 0L, 2); 120 size = ftell(otf); 121 mp->m_block = blockof(size); 122 mp->m_offset = offsetof(size); 123 mp->m_size = fsize(fp); 124 mp->m_lines = 0; 125 mp->m_flag |= MODIFY; 126 rewind(fp); 127 while ((c = getc(fp)) != EOF) { 128 if (c == '\n') 129 mp->m_lines++; 130 if (putc(c, otf) == EOF) 131 break; 132 } 133 if (ferror(otf)) 134 warn("/tmp"); 135 (void)Fclose(fp); 136 } 137 (void)signal(SIGINT, sigint); 138 } 139 return(0); 140 } 141 142 /* 143 * Run an editor on the file at "fpp" of "size" bytes, 144 * and return a new file pointer. 145 * Signals must be handled by the caller. 146 * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI. 147 */ 148 FILE * 149 run_editor(fp, size, type, readonly) 150 FILE *fp; 151 off_t size; 152 int type, readonly; 153 { 154 FILE *nf = NULL; 155 int t; 156 time_t modtime; 157 char *edit, tempname[PATHSIZE]; 158 struct stat statb; 159 160 (void)snprintf(tempname, sizeof(tempname), 161 "%s/mail.ReXXXXXXXXXX", tmpdir); 162 if ((t = mkstemp(tempname)) == -1 || 163 (nf = Fdopen(t, "w")) == NULL) { 164 warn(tempname); 165 goto out; 166 } 167 if (readonly && fchmod(t, 0400) == -1) { 168 warn(tempname); 169 (void)rm(tempname); 170 goto out; 171 } 172 if (size >= 0) 173 while (--size >= 0 && (t = getc(fp)) != EOF) 174 (void)putc(t, nf); 175 else 176 while ((t = getc(fp)) != EOF) 177 (void)putc(t, nf); 178 (void)fflush(nf); 179 if (fstat(fileno(nf), &statb) < 0) 180 modtime = 0; 181 else 182 modtime = statb.st_mtime; 183 if (ferror(nf)) { 184 (void)Fclose(nf); 185 warn(tempname); 186 (void)rm(tempname); 187 nf = NULL; 188 goto out; 189 } 190 if (Fclose(nf) < 0) { 191 warn(tempname); 192 (void)rm(tempname); 193 nf = NULL; 194 goto out; 195 } 196 nf = NULL; 197 if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NULL) 198 edit = type == 'e' ? _PATH_EX : _PATH_VI; 199 if (run_command(edit, 0, -1, -1, tempname, NULL, NULL) < 0) { 200 (void)rm(tempname); 201 goto out; 202 } 203 /* 204 * If in read only mode or file unchanged, just remove the editor 205 * temporary and return. 206 */ 207 if (readonly) { 208 (void)rm(tempname); 209 goto out; 210 } 211 if (stat(tempname, &statb) < 0) { 212 warn(tempname); 213 goto out; 214 } 215 if (modtime == statb.st_mtime) { 216 (void)rm(tempname); 217 goto out; 218 } 219 /* 220 * Now switch to new file. 221 */ 222 if ((nf = Fopen(tempname, "a+")) == NULL) { 223 warn(tempname); 224 (void)rm(tempname); 225 goto out; 226 } 227 (void)rm(tempname); 228 out: 229 return(nf); 230 } 231