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