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