edit.c revision 77274
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 * 3. All advertising materials mentioning features or use of this software 141590Srgrimes * must display the following acknowledgement: 151590Srgrimes * This product includes software developed by the University of 161590Srgrimes * California, Berkeley and its contributors. 171590Srgrimes * 4. Neither the name of the University nor the names of its contributors 181590Srgrimes * may be used to endorse or promote products derived from this software 191590Srgrimes * without specific prior written permission. 201590Srgrimes * 211590Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 221590Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 231590Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 241590Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 251590Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 261590Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 271590Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 281590Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 291590Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 301590Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 311590Srgrimes * SUCH DAMAGE. 3267496Sphk * 3367496Sphk * $FreeBSD: head/usr.bin/mail/edit.c 77274 2001-05-27 20:26:22Z mikeh $ 341590Srgrimes */ 351590Srgrimes 361590Srgrimes#ifndef lint 3774769Smikeh#if 0 381590Srgrimesstatic char sccsid[] = "@(#)edit.c 8.1 (Berkeley) 6/6/93"; 3974769Smikeh#endif 4074769Smikehstatic const char rcsid[] = 4174769Smikeh "$FreeBSD: head/usr.bin/mail/edit.c 77274 2001-05-27 20:26:22Z mikeh $"; 421590Srgrimes#endif /* not lint */ 431590Srgrimes 441590Srgrimes#include "rcv.h" 451590Srgrimes#include <fcntl.h> 461590Srgrimes#include "extern.h" 471590Srgrimes 481590Srgrimes/* 491590Srgrimes * Mail -- a mail program 501590Srgrimes * 511590Srgrimes * Perform message editing functions. 521590Srgrimes */ 531590Srgrimes 541590Srgrimes/* 551590Srgrimes * Edit a message list. 561590Srgrimes */ 571590Srgrimesint 581590Srgrimeseditor(msgvec) 591590Srgrimes int *msgvec; 601590Srgrimes{ 611590Srgrimes 6277274Smikeh return (edit1(msgvec, 'e')); 631590Srgrimes} 641590Srgrimes 651590Srgrimes/* 661590Srgrimes * Invoke the visual editor on a message list. 671590Srgrimes */ 681590Srgrimesint 691590Srgrimesvisual(msgvec) 701590Srgrimes int *msgvec; 711590Srgrimes{ 721590Srgrimes 7377274Smikeh return (edit1(msgvec, 'v')); 741590Srgrimes} 751590Srgrimes 761590Srgrimes/* 771590Srgrimes * Edit a message by writing the message into a funnily-named file 781590Srgrimes * (which should not exist) and forking an editor on it. 791590Srgrimes * We get the editor from the stuff above. 801590Srgrimes */ 811590Srgrimesint 821590Srgrimesedit1(msgvec, type) 831590Srgrimes int *msgvec; 841590Srgrimes int type; 851590Srgrimes{ 8677274Smikeh int c, i; 871590Srgrimes FILE *fp; 8877274Smikeh struct message *mp; 891590Srgrimes off_t size; 901590Srgrimes 911590Srgrimes /* 921590Srgrimes * Deal with each message to be edited . . . 931590Srgrimes */ 941590Srgrimes for (i = 0; msgvec[i] && i < msgCount; i++) { 951590Srgrimes sig_t sigint; 961590Srgrimes 971590Srgrimes if (i > 0) { 981590Srgrimes char buf[100]; 991590Srgrimes char *p; 1001590Srgrimes 1011590Srgrimes printf("Edit message %d [ynq]? ", msgvec[i]); 10277274Smikeh if (fgets(buf, sizeof(buf), stdin) == 0) 1031590Srgrimes break; 1041590Srgrimes for (p = buf; *p == ' ' || *p == '\t'; p++) 1051590Srgrimes ; 1061590Srgrimes if (*p == 'q') 1071590Srgrimes break; 1081590Srgrimes if (*p == 'n') 1091590Srgrimes continue; 1101590Srgrimes } 1111590Srgrimes dot = mp = &message[msgvec[i] - 1]; 1121590Srgrimes touch(mp); 1131590Srgrimes sigint = signal(SIGINT, SIG_IGN); 1141590Srgrimes fp = run_editor(setinput(mp), mp->m_size, type, readonly); 1151590Srgrimes if (fp != NULL) { 11677274Smikeh (void)fseek(otf, 0L, 2); 1171590Srgrimes size = ftell(otf); 1181590Srgrimes mp->m_block = blockof(size); 11967496Sphk mp->m_offset = boffsetof(size); 1201590Srgrimes mp->m_size = fsize(fp); 1211590Srgrimes mp->m_lines = 0; 1221590Srgrimes mp->m_flag |= MODIFY; 1231590Srgrimes rewind(fp); 1241590Srgrimes while ((c = getc(fp)) != EOF) { 1251590Srgrimes if (c == '\n') 1261590Srgrimes mp->m_lines++; 1271590Srgrimes if (putc(c, otf) == EOF) 1281590Srgrimes break; 1291590Srgrimes } 1301590Srgrimes if (ferror(otf)) 13174769Smikeh warnx("/tmp"); 13277274Smikeh (void)Fclose(fp); 1331590Srgrimes } 13477274Smikeh (void)signal(SIGINT, sigint); 1351590Srgrimes } 13677274Smikeh return (0); 1371590Srgrimes} 1381590Srgrimes 1391590Srgrimes/* 1401590Srgrimes * Run an editor on the file at "fpp" of "size" bytes, 1411590Srgrimes * and return a new file pointer. 1421590Srgrimes * Signals must be handled by the caller. 1431590Srgrimes * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI. 1441590Srgrimes */ 1451590SrgrimesFILE * 1461590Srgrimesrun_editor(fp, size, type, readonly) 14777274Smikeh FILE *fp; 1481590Srgrimes off_t size; 1491590Srgrimes int type, readonly; 1501590Srgrimes{ 15177274Smikeh FILE *nf = NULL; 15277274Smikeh int t; 1531590Srgrimes time_t modtime; 15474769Smikeh char *edit, tempname[PATHSIZE]; 1551590Srgrimes struct stat statb; 1561590Srgrimes 15777274Smikeh (void)snprintf(tempname, sizeof(tempname), 15877274Smikeh "%s/mail.ReXXXXXXXXXX", tmpdir); 15974769Smikeh if ((t = mkstemp(tempname)) == -1 || 16074769Smikeh (nf = Fdopen(t, "w")) == NULL) { 16174769Smikeh warn("%s", tempname); 1621590Srgrimes goto out; 1631590Srgrimes } 16474769Smikeh if (readonly && fchmod(t, 0400) == -1) { 16574769Smikeh warn("%s", tempname); 16677274Smikeh (void)rm(tempname); 1671590Srgrimes goto out; 1681590Srgrimes } 1691590Srgrimes if (size >= 0) 1701590Srgrimes while (--size >= 0 && (t = getc(fp)) != EOF) 17177274Smikeh (void)putc(t, nf); 1721590Srgrimes else 1731590Srgrimes while ((t = getc(fp)) != EOF) 17477274Smikeh (void)putc(t, nf); 17577274Smikeh (void)fflush(nf); 1761590Srgrimes if (fstat(fileno(nf), &statb) < 0) 1771590Srgrimes modtime = 0; 1781590Srgrimes else 1791590Srgrimes modtime = statb.st_mtime; 1801590Srgrimes if (ferror(nf)) { 18177274Smikeh (void)Fclose(nf); 18274769Smikeh warnx("%s", tempname); 18377274Smikeh (void)rm(tempname); 1841590Srgrimes nf = NULL; 1851590Srgrimes goto out; 1861590Srgrimes } 1871590Srgrimes if (Fclose(nf) < 0) { 18874769Smikeh warn("%s", tempname); 18977274Smikeh (void)rm(tempname); 1901590Srgrimes nf = NULL; 1911590Srgrimes goto out; 1921590Srgrimes } 1931590Srgrimes nf = NULL; 19477274Smikeh if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NULL) 1951590Srgrimes edit = type == 'e' ? _PATH_EX : _PATH_VI; 19677274Smikeh if (run_command(edit, 0, -1, -1, tempname, NULL, NULL) < 0) { 19777274Smikeh (void)rm(tempname); 1981590Srgrimes goto out; 1991590Srgrimes } 2001590Srgrimes /* 2011590Srgrimes * If in read only mode or file unchanged, just remove the editor 2021590Srgrimes * temporary and return. 2031590Srgrimes */ 2041590Srgrimes if (readonly) { 20577274Smikeh (void)rm(tempname); 2061590Srgrimes goto out; 2071590Srgrimes } 20874769Smikeh if (stat(tempname, &statb) < 0) { 20974769Smikeh warn("%s", tempname); 2101590Srgrimes goto out; 2111590Srgrimes } 2121590Srgrimes if (modtime == statb.st_mtime) { 21377274Smikeh (void)rm(tempname); 2141590Srgrimes goto out; 2151590Srgrimes } 2161590Srgrimes /* 2171590Srgrimes * Now switch to new file. 2181590Srgrimes */ 21974769Smikeh if ((nf = Fopen(tempname, "a+")) == NULL) { 22074769Smikeh warn("%s", tempname); 22177274Smikeh (void)rm(tempname); 2221590Srgrimes goto out; 2231590Srgrimes } 22477274Smikeh (void)rm(tempname); 2251590Srgrimesout: 22677274Smikeh return (nf); 2271590Srgrimes} 228