edit.c revision 82793
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. 321590Srgrimes */ 331590Srgrimes 341590Srgrimes#ifndef lint 3574769Smikeh#if 0 361590Srgrimesstatic char sccsid[] = "@(#)edit.c 8.1 (Berkeley) 6/6/93"; 3774769Smikeh#endif 3874769Smikehstatic const char rcsid[] = 3974769Smikeh "$FreeBSD: head/usr.bin/mail/edit.c 82793 2001-09-02 14:40:51Z ache $"; 401590Srgrimes#endif /* not lint */ 411590Srgrimes 421590Srgrimes#include "rcv.h" 431590Srgrimes#include <fcntl.h> 441590Srgrimes#include "extern.h" 451590Srgrimes 461590Srgrimes/* 471590Srgrimes * Mail -- a mail program 481590Srgrimes * 491590Srgrimes * Perform message editing functions. 501590Srgrimes */ 511590Srgrimes 521590Srgrimes/* 531590Srgrimes * Edit a message list. 541590Srgrimes */ 551590Srgrimesint 561590Srgrimeseditor(msgvec) 571590Srgrimes int *msgvec; 581590Srgrimes{ 591590Srgrimes 6077274Smikeh return (edit1(msgvec, 'e')); 611590Srgrimes} 621590Srgrimes 631590Srgrimes/* 641590Srgrimes * Invoke the visual editor on a message list. 651590Srgrimes */ 661590Srgrimesint 671590Srgrimesvisual(msgvec) 681590Srgrimes int *msgvec; 691590Srgrimes{ 701590Srgrimes 7177274Smikeh return (edit1(msgvec, 'v')); 721590Srgrimes} 731590Srgrimes 741590Srgrimes/* 751590Srgrimes * Edit a message by writing the message into a funnily-named file 761590Srgrimes * (which should not exist) and forking an editor on it. 771590Srgrimes * We get the editor from the stuff above. 781590Srgrimes */ 791590Srgrimesint 801590Srgrimesedit1(msgvec, type) 811590Srgrimes int *msgvec; 821590Srgrimes int type; 831590Srgrimes{ 8477274Smikeh int c, i; 851590Srgrimes FILE *fp; 8677274Smikeh struct message *mp; 871590Srgrimes off_t size; 881590Srgrimes 891590Srgrimes /* 901590Srgrimes * Deal with each message to be edited . . . 911590Srgrimes */ 921590Srgrimes for (i = 0; msgvec[i] && i < msgCount; i++) { 931590Srgrimes sig_t sigint; 941590Srgrimes 951590Srgrimes if (i > 0) { 961590Srgrimes char buf[100]; 971590Srgrimes char *p; 981590Srgrimes 991590Srgrimes printf("Edit message %d [ynq]? ", msgvec[i]); 10077274Smikeh if (fgets(buf, sizeof(buf), stdin) == 0) 1011590Srgrimes break; 1021590Srgrimes for (p = buf; *p == ' ' || *p == '\t'; p++) 1031590Srgrimes ; 1041590Srgrimes if (*p == 'q') 1051590Srgrimes break; 1061590Srgrimes if (*p == 'n') 1071590Srgrimes continue; 1081590Srgrimes } 1091590Srgrimes dot = mp = &message[msgvec[i] - 1]; 1101590Srgrimes touch(mp); 1111590Srgrimes sigint = signal(SIGINT, SIG_IGN); 1121590Srgrimes fp = run_editor(setinput(mp), mp->m_size, type, readonly); 1131590Srgrimes if (fp != NULL) { 11482793Sache (void)fseeko(otf, (off_t)0, SEEK_END); 11582793Sache size = ftello(otf); 1161590Srgrimes mp->m_block = blockof(size); 11767496Sphk mp->m_offset = boffsetof(size); 1181590Srgrimes mp->m_size = fsize(fp); 1191590Srgrimes mp->m_lines = 0; 1201590Srgrimes mp->m_flag |= MODIFY; 1211590Srgrimes rewind(fp); 1221590Srgrimes while ((c = getc(fp)) != EOF) { 1231590Srgrimes if (c == '\n') 1241590Srgrimes mp->m_lines++; 1251590Srgrimes if (putc(c, otf) == EOF) 1261590Srgrimes break; 1271590Srgrimes } 1281590Srgrimes if (ferror(otf)) 12974769Smikeh warnx("/tmp"); 13077274Smikeh (void)Fclose(fp); 1311590Srgrimes } 13277274Smikeh (void)signal(SIGINT, sigint); 1331590Srgrimes } 13477274Smikeh return (0); 1351590Srgrimes} 1361590Srgrimes 1371590Srgrimes/* 1381590Srgrimes * Run an editor on the file at "fpp" of "size" bytes, 1391590Srgrimes * and return a new file pointer. 1401590Srgrimes * Signals must be handled by the caller. 1411590Srgrimes * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI. 1421590Srgrimes */ 1431590SrgrimesFILE * 1441590Srgrimesrun_editor(fp, size, type, readonly) 14577274Smikeh FILE *fp; 1461590Srgrimes off_t size; 1471590Srgrimes int type, readonly; 1481590Srgrimes{ 14977274Smikeh FILE *nf = NULL; 15077274Smikeh int t; 1511590Srgrimes time_t modtime; 15274769Smikeh char *edit, tempname[PATHSIZE]; 1531590Srgrimes struct stat statb; 1541590Srgrimes 15577274Smikeh (void)snprintf(tempname, sizeof(tempname), 15677274Smikeh "%s/mail.ReXXXXXXXXXX", tmpdir); 15774769Smikeh if ((t = mkstemp(tempname)) == -1 || 15874769Smikeh (nf = Fdopen(t, "w")) == NULL) { 15974769Smikeh warn("%s", tempname); 1601590Srgrimes goto out; 1611590Srgrimes } 16274769Smikeh if (readonly && fchmod(t, 0400) == -1) { 16374769Smikeh warn("%s", tempname); 16477274Smikeh (void)rm(tempname); 1651590Srgrimes goto out; 1661590Srgrimes } 1671590Srgrimes if (size >= 0) 1681590Srgrimes while (--size >= 0 && (t = getc(fp)) != EOF) 16977274Smikeh (void)putc(t, nf); 1701590Srgrimes else 1711590Srgrimes while ((t = getc(fp)) != EOF) 17277274Smikeh (void)putc(t, nf); 17377274Smikeh (void)fflush(nf); 1741590Srgrimes if (fstat(fileno(nf), &statb) < 0) 1751590Srgrimes modtime = 0; 1761590Srgrimes else 1771590Srgrimes modtime = statb.st_mtime; 1781590Srgrimes if (ferror(nf)) { 17977274Smikeh (void)Fclose(nf); 18074769Smikeh warnx("%s", tempname); 18177274Smikeh (void)rm(tempname); 1821590Srgrimes nf = NULL; 1831590Srgrimes goto out; 1841590Srgrimes } 1851590Srgrimes if (Fclose(nf) < 0) { 18674769Smikeh warn("%s", tempname); 18777274Smikeh (void)rm(tempname); 1881590Srgrimes nf = NULL; 1891590Srgrimes goto out; 1901590Srgrimes } 1911590Srgrimes nf = NULL; 19277274Smikeh if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NULL) 1931590Srgrimes edit = type == 'e' ? _PATH_EX : _PATH_VI; 19477274Smikeh if (run_command(edit, 0, -1, -1, tempname, NULL, NULL) < 0) { 19577274Smikeh (void)rm(tempname); 1961590Srgrimes goto out; 1971590Srgrimes } 1981590Srgrimes /* 1991590Srgrimes * If in read only mode or file unchanged, just remove the editor 2001590Srgrimes * temporary and return. 2011590Srgrimes */ 2021590Srgrimes if (readonly) { 20377274Smikeh (void)rm(tempname); 2041590Srgrimes goto out; 2051590Srgrimes } 20674769Smikeh if (stat(tempname, &statb) < 0) { 20774769Smikeh warn("%s", tempname); 2081590Srgrimes goto out; 2091590Srgrimes } 2101590Srgrimes if (modtime == statb.st_mtime) { 21177274Smikeh (void)rm(tempname); 2121590Srgrimes goto out; 2131590Srgrimes } 2141590Srgrimes /* 2151590Srgrimes * Now switch to new file. 2161590Srgrimes */ 21774769Smikeh if ((nf = Fopen(tempname, "a+")) == NULL) { 21874769Smikeh warn("%s", tempname); 21977274Smikeh (void)rm(tempname); 2201590Srgrimes goto out; 2211590Srgrimes } 22277274Smikeh (void)rm(tempname); 2231590Srgrimesout: 22477274Smikeh return (nf); 2251590Srgrimes} 226