11590Srgrimes/* 21590Srgrimes * Copyright (c) 1980, 1993 31590Srgrimes * The Regents of the University of California. All rights reserved. 41590Srgrimes * 51590Srgrimes * Redistribution and use in source and binary forms, with or without 61590Srgrimes * modification, are permitted provided that the following conditions 71590Srgrimes * are met: 81590Srgrimes * 1. Redistributions of source code must retain the above copyright 91590Srgrimes * notice, this list of conditions and the following disclaimer. 101590Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 111590Srgrimes * notice, this list of conditions and the following disclaimer in the 121590Srgrimes * documentation and/or other materials provided with the distribution. 131590Srgrimes * 4. Neither the name of the University nor the names of its contributors 141590Srgrimes * may be used to endorse or promote products derived from this software 151590Srgrimes * without specific prior written permission. 161590Srgrimes * 171590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 181590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 191590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 201590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 211590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 221590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 231590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 241590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 251590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 261590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 271590Srgrimes * SUCH DAMAGE. 281590Srgrimes */ 291590Srgrimes 301590Srgrimes#ifndef lint 3174769Smikeh#if 0 321590Srgrimesstatic char sccsid[] = "@(#)edit.c 8.1 (Berkeley) 6/6/93"; 3374769Smikeh#endif 341590Srgrimes#endif /* not lint */ 3599112Sobrien#include <sys/cdefs.h> 3699112Sobrien__FBSDID("$FreeBSD$"); 371590Srgrimes 381590Srgrimes#include "rcv.h" 391590Srgrimes#include <fcntl.h> 401590Srgrimes#include "extern.h" 411590Srgrimes 421590Srgrimes/* 431590Srgrimes * Mail -- a mail program 441590Srgrimes * 451590Srgrimes * Perform message editing functions. 461590Srgrimes */ 471590Srgrimes 481590Srgrimes/* 491590Srgrimes * Edit a message list. 501590Srgrimes */ 511590Srgrimesint 52216564Scharniereditor(int *msgvec) 531590Srgrimes{ 541590Srgrimes 5577274Smikeh return (edit1(msgvec, 'e')); 561590Srgrimes} 571590Srgrimes 581590Srgrimes/* 591590Srgrimes * Invoke the visual editor on a message list. 601590Srgrimes */ 611590Srgrimesint 62216564Scharniervisual(int *msgvec) 631590Srgrimes{ 641590Srgrimes 6577274Smikeh return (edit1(msgvec, 'v')); 661590Srgrimes} 671590Srgrimes 681590Srgrimes/* 691590Srgrimes * Edit a message by writing the message into a funnily-named file 701590Srgrimes * (which should not exist) and forking an editor on it. 711590Srgrimes * We get the editor from the stuff above. 721590Srgrimes */ 731590Srgrimesint 74216564Scharnieredit1(int *msgvec, int type) 751590Srgrimes{ 7677274Smikeh int c, i; 771590Srgrimes FILE *fp; 7877274Smikeh struct message *mp; 791590Srgrimes off_t size; 801590Srgrimes 811590Srgrimes /* 821590Srgrimes * Deal with each message to be edited . . . 831590Srgrimes */ 841590Srgrimes for (i = 0; msgvec[i] && i < msgCount; i++) { 851590Srgrimes sig_t sigint; 861590Srgrimes 871590Srgrimes if (i > 0) { 881590Srgrimes char buf[100]; 891590Srgrimes char *p; 901590Srgrimes 911590Srgrimes printf("Edit message %d [ynq]? ", msgvec[i]); 9277274Smikeh if (fgets(buf, sizeof(buf), stdin) == 0) 931590Srgrimes break; 941590Srgrimes for (p = buf; *p == ' ' || *p == '\t'; p++) 951590Srgrimes ; 961590Srgrimes if (*p == 'q') 971590Srgrimes break; 981590Srgrimes if (*p == 'n') 991590Srgrimes continue; 1001590Srgrimes } 1011590Srgrimes dot = mp = &message[msgvec[i] - 1]; 1021590Srgrimes touch(mp); 1031590Srgrimes sigint = signal(SIGINT, SIG_IGN); 1041590Srgrimes fp = run_editor(setinput(mp), mp->m_size, type, readonly); 1051590Srgrimes if (fp != NULL) { 10682793Sache (void)fseeko(otf, (off_t)0, SEEK_END); 10782793Sache size = ftello(otf); 1081590Srgrimes mp->m_block = blockof(size); 10967496Sphk mp->m_offset = boffsetof(size); 11088227Sache mp->m_size = (long)fsize(fp); 1111590Srgrimes mp->m_lines = 0; 1121590Srgrimes mp->m_flag |= MODIFY; 1131590Srgrimes rewind(fp); 1141590Srgrimes while ((c = getc(fp)) != EOF) { 1151590Srgrimes if (c == '\n') 1161590Srgrimes mp->m_lines++; 1171590Srgrimes if (putc(c, otf) == EOF) 1181590Srgrimes break; 1191590Srgrimes } 1201590Srgrimes if (ferror(otf)) 12174769Smikeh warnx("/tmp"); 12277274Smikeh (void)Fclose(fp); 1231590Srgrimes } 12477274Smikeh (void)signal(SIGINT, sigint); 1251590Srgrimes } 12677274Smikeh return (0); 1271590Srgrimes} 1281590Srgrimes 1291590Srgrimes/* 1301590Srgrimes * Run an editor on the file at "fpp" of "size" bytes, 1311590Srgrimes * and return a new file pointer. 1321590Srgrimes * Signals must be handled by the caller. 1331590Srgrimes * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI. 1341590Srgrimes */ 1351590SrgrimesFILE * 136216564Scharnierrun_editor(FILE *fp, off_t size, int type, int readonly) 1371590Srgrimes{ 13877274Smikeh FILE *nf = NULL; 13977274Smikeh int t; 1401590Srgrimes time_t modtime; 14174769Smikeh char *edit, tempname[PATHSIZE]; 1421590Srgrimes struct stat statb; 1431590Srgrimes 14477274Smikeh (void)snprintf(tempname, sizeof(tempname), 14577274Smikeh "%s/mail.ReXXXXXXXXXX", tmpdir); 14674769Smikeh if ((t = mkstemp(tempname)) == -1 || 14774769Smikeh (nf = Fdopen(t, "w")) == NULL) { 14874769Smikeh warn("%s", tempname); 1491590Srgrimes goto out; 1501590Srgrimes } 15174769Smikeh if (readonly && fchmod(t, 0400) == -1) { 15274769Smikeh warn("%s", tempname); 15377274Smikeh (void)rm(tempname); 1541590Srgrimes goto out; 1551590Srgrimes } 1561590Srgrimes if (size >= 0) 1571590Srgrimes while (--size >= 0 && (t = getc(fp)) != EOF) 15877274Smikeh (void)putc(t, nf); 1591590Srgrimes else 1601590Srgrimes while ((t = getc(fp)) != EOF) 16177274Smikeh (void)putc(t, nf); 16277274Smikeh (void)fflush(nf); 1631590Srgrimes if (fstat(fileno(nf), &statb) < 0) 1641590Srgrimes modtime = 0; 1651590Srgrimes else 1661590Srgrimes modtime = statb.st_mtime; 1671590Srgrimes if (ferror(nf)) { 16877274Smikeh (void)Fclose(nf); 16974769Smikeh warnx("%s", tempname); 17077274Smikeh (void)rm(tempname); 1711590Srgrimes nf = NULL; 1721590Srgrimes goto out; 1731590Srgrimes } 1741590Srgrimes if (Fclose(nf) < 0) { 17574769Smikeh warn("%s", tempname); 17677274Smikeh (void)rm(tempname); 1771590Srgrimes nf = NULL; 1781590Srgrimes goto out; 1791590Srgrimes } 1801590Srgrimes nf = NULL; 18177274Smikeh if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NULL) 1821590Srgrimes edit = type == 'e' ? _PATH_EX : _PATH_VI; 18377274Smikeh if (run_command(edit, 0, -1, -1, tempname, NULL, NULL) < 0) { 18477274Smikeh (void)rm(tempname); 1851590Srgrimes goto out; 1861590Srgrimes } 1871590Srgrimes /* 1881590Srgrimes * If in read only mode or file unchanged, just remove the editor 1891590Srgrimes * temporary and return. 1901590Srgrimes */ 1911590Srgrimes if (readonly) { 19277274Smikeh (void)rm(tempname); 1931590Srgrimes goto out; 1941590Srgrimes } 19574769Smikeh if (stat(tempname, &statb) < 0) { 19674769Smikeh warn("%s", tempname); 1971590Srgrimes goto out; 1981590Srgrimes } 1991590Srgrimes if (modtime == statb.st_mtime) { 20077274Smikeh (void)rm(tempname); 2011590Srgrimes goto out; 2021590Srgrimes } 2031590Srgrimes /* 2041590Srgrimes * Now switch to new file. 2051590Srgrimes */ 20674769Smikeh if ((nf = Fopen(tempname, "a+")) == NULL) { 20774769Smikeh warn("%s", tempname); 20877274Smikeh (void)rm(tempname); 2091590Srgrimes goto out; 2101590Srgrimes } 21177274Smikeh (void)rm(tempname); 2121590Srgrimesout: 21377274Smikeh return (nf); 2141590Srgrimes} 215