xref: /freebsd/usr.bin/mail/edit.c (revision 5e3934b15a2741b2de6b217e77dc9d798d740804)
18a16b7a1SPedro F. Giffuni /*-
28a16b7a1SPedro F. Giffuni  * SPDX-License-Identifier: BSD-3-Clause
38a16b7a1SPedro F. Giffuni  *
49b50d902SRodney W. Grimes  * Copyright (c) 1980, 1993
59b50d902SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
69b50d902SRodney W. Grimes  *
79b50d902SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
89b50d902SRodney W. Grimes  * modification, are permitted provided that the following conditions
99b50d902SRodney W. Grimes  * are met:
109b50d902SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
119b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
129b50d902SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
139b50d902SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
149b50d902SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
15fbbd9655SWarner Losh  * 3. Neither the name of the University nor the names of its contributors
169b50d902SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
179b50d902SRodney W. Grimes  *    without specific prior written permission.
189b50d902SRodney W. Grimes  *
199b50d902SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
209b50d902SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
219b50d902SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
229b50d902SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
239b50d902SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
249b50d902SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
259b50d902SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
269b50d902SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
279b50d902SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
289b50d902SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
299b50d902SRodney W. Grimes  * SUCH DAMAGE.
309b50d902SRodney W. Grimes  */
319b50d902SRodney W. Grimes 
329b50d902SRodney W. Grimes #include "rcv.h"
339b50d902SRodney W. Grimes #include <fcntl.h>
349b50d902SRodney W. Grimes #include "extern.h"
359b50d902SRodney W. Grimes 
369b50d902SRodney W. Grimes /*
379b50d902SRodney W. Grimes  * Mail -- a mail program
389b50d902SRodney W. Grimes  *
399b50d902SRodney W. Grimes  * Perform message editing functions.
409b50d902SRodney W. Grimes  */
419b50d902SRodney W. Grimes 
429b50d902SRodney W. Grimes /*
439b50d902SRodney W. Grimes  * Edit a message list.
449b50d902SRodney W. Grimes  */
459b50d902SRodney W. Grimes int
editor(void * msgvec)46*d28a9551SJohn Baldwin editor(void *msgvec)
479b50d902SRodney W. Grimes {
489b50d902SRodney W. Grimes 
499ce73e90SMike Heffner 	return (edit1(msgvec, 'e'));
509b50d902SRodney W. Grimes }
519b50d902SRodney W. Grimes 
529b50d902SRodney W. Grimes /*
539b50d902SRodney W. Grimes  * Invoke the visual editor on a message list.
549b50d902SRodney W. Grimes  */
559b50d902SRodney W. Grimes int
visual(void * msgvec)56*d28a9551SJohn Baldwin visual(void *msgvec)
579b50d902SRodney W. Grimes {
589b50d902SRodney W. Grimes 
599ce73e90SMike Heffner 	return (edit1(msgvec, 'v'));
609b50d902SRodney W. Grimes }
619b50d902SRodney W. Grimes 
629b50d902SRodney W. Grimes /*
639b50d902SRodney W. Grimes  * Edit a message by writing the message into a funnily-named file
649b50d902SRodney W. Grimes  * (which should not exist) and forking an editor on it.
659b50d902SRodney W. Grimes  * We get the editor from the stuff above.
669b50d902SRodney W. Grimes  */
679b50d902SRodney W. Grimes int
edit1(int * msgvec,int type)686d8484b0SPhilippe Charnier edit1(int *msgvec, int type)
699b50d902SRodney W. Grimes {
709ce73e90SMike Heffner 	int c, i;
719b50d902SRodney W. Grimes 	FILE *fp;
729ce73e90SMike Heffner 	struct message *mp;
739b50d902SRodney W. Grimes 	off_t size;
749b50d902SRodney W. Grimes 
759b50d902SRodney W. Grimes 	/*
769b50d902SRodney W. Grimes 	 * Deal with each message to be edited . . .
779b50d902SRodney W. Grimes 	 */
780fa46a42SPedro F. Giffuni 	for (i = 0; i < msgCount && msgvec[i]; i++) {
799b50d902SRodney W. Grimes 		sig_t sigint;
809b50d902SRodney W. Grimes 
819b50d902SRodney W. Grimes 		if (i > 0) {
829b50d902SRodney W. Grimes 			char buf[100];
839b50d902SRodney W. Grimes 			char *p;
849b50d902SRodney W. Grimes 
859b50d902SRodney W. Grimes 			printf("Edit message %d [ynq]? ", msgvec[i]);
86a3a2bf4bSKevin Lo 			if (fgets(buf, sizeof(buf), stdin) == NULL)
879b50d902SRodney W. Grimes 				break;
889b50d902SRodney W. Grimes 			for (p = buf; *p == ' ' || *p == '\t'; p++)
899b50d902SRodney W. Grimes 				;
909b50d902SRodney W. Grimes 			if (*p == 'q')
919b50d902SRodney W. Grimes 				break;
929b50d902SRodney W. Grimes 			if (*p == 'n')
939b50d902SRodney W. Grimes 				continue;
949b50d902SRodney W. Grimes 		}
959b50d902SRodney W. Grimes 		dot = mp = &message[msgvec[i] - 1];
969b50d902SRodney W. Grimes 		touch(mp);
979b50d902SRodney W. Grimes 		sigint = signal(SIGINT, SIG_IGN);
989b50d902SRodney W. Grimes 		fp = run_editor(setinput(mp), mp->m_size, type, readonly);
999b50d902SRodney W. Grimes 		if (fp != NULL) {
100af8c3262SAndrey A. Chernov 			(void)fseeko(otf, (off_t)0, SEEK_END);
101af8c3262SAndrey A. Chernov 			size = ftello(otf);
1029b50d902SRodney W. Grimes 			mp->m_block = blockof(size);
103c23d986eSPoul-Henning Kamp 			mp->m_offset = boffsetof(size);
1046d48fa43SAndrey A. Chernov 			mp->m_size = (long)fsize(fp);
1059b50d902SRodney W. Grimes 			mp->m_lines = 0;
1069b50d902SRodney W. Grimes 			mp->m_flag |= MODIFY;
1079b50d902SRodney W. Grimes 			rewind(fp);
1089b50d902SRodney W. Grimes 			while ((c = getc(fp)) != EOF) {
1099b50d902SRodney W. Grimes 				if (c == '\n')
1109b50d902SRodney W. Grimes 					mp->m_lines++;
1119b50d902SRodney W. Grimes 				if (putc(c, otf) == EOF)
1129b50d902SRodney W. Grimes 					break;
1139b50d902SRodney W. Grimes 			}
1149b50d902SRodney W. Grimes 			if (ferror(otf))
1150c3a8314SMike Heffner 				warnx("/tmp");
1169b50d902SRodney W. Grimes 			(void)Fclose(fp);
1179b50d902SRodney W. Grimes 		}
1189b50d902SRodney W. Grimes 		(void)signal(SIGINT, sigint);
1199b50d902SRodney W. Grimes 	}
1209ce73e90SMike Heffner 	return (0);
1219b50d902SRodney W. Grimes }
1229b50d902SRodney W. Grimes 
1239b50d902SRodney W. Grimes /*
1249b50d902SRodney W. Grimes  * Run an editor on the file at "fpp" of "size" bytes,
1259b50d902SRodney W. Grimes  * and return a new file pointer.
1269b50d902SRodney W. Grimes  * Signals must be handled by the caller.
1279b50d902SRodney W. Grimes  * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI.
1289b50d902SRodney W. Grimes  */
1299b50d902SRodney W. Grimes FILE *
run_editor(FILE * fp,off_t size,int type,int readonly)1306d8484b0SPhilippe Charnier run_editor(FILE *fp, off_t size, int type, int readonly)
1319b50d902SRodney W. Grimes {
1329ce73e90SMike Heffner 	FILE *nf = NULL;
1339ce73e90SMike Heffner 	int t;
1349b50d902SRodney W. Grimes 	time_t modtime;
1350c3a8314SMike Heffner 	char *edit, tempname[PATHSIZE];
1369b50d902SRodney W. Grimes 	struct stat statb;
1379b50d902SRodney W. Grimes 
1389ce73e90SMike Heffner 	(void)snprintf(tempname, sizeof(tempname),
1399ce73e90SMike Heffner 	    "%s/mail.ReXXXXXXXXXX", tmpdir);
1400c3a8314SMike Heffner 	if ((t = mkstemp(tempname)) == -1 ||
1410c3a8314SMike Heffner 	    (nf = Fdopen(t, "w")) == NULL) {
1420c3a8314SMike Heffner 		warn("%s", tempname);
1439b50d902SRodney W. Grimes 		goto out;
1449b50d902SRodney W. Grimes 	}
1450c3a8314SMike Heffner 	if (readonly && fchmod(t, 0400) == -1) {
1460c3a8314SMike Heffner 		warn("%s", tempname);
1470c3a8314SMike Heffner 		(void)rm(tempname);
1489b50d902SRodney W. Grimes 		goto out;
1499b50d902SRodney W. Grimes 	}
1509b50d902SRodney W. Grimes 	if (size >= 0)
1519b50d902SRodney W. Grimes 		while (--size >= 0 && (t = getc(fp)) != EOF)
1529b50d902SRodney W. Grimes 			(void)putc(t, nf);
1539b50d902SRodney W. Grimes 	else
1549b50d902SRodney W. Grimes 		while ((t = getc(fp)) != EOF)
1559b50d902SRodney W. Grimes 			(void)putc(t, nf);
1569b50d902SRodney W. Grimes 	(void)fflush(nf);
1579b50d902SRodney W. Grimes 	if (fstat(fileno(nf), &statb) < 0)
1589b50d902SRodney W. Grimes 		modtime = 0;
1599b50d902SRodney W. Grimes 	else
1609b50d902SRodney W. Grimes 		modtime = statb.st_mtime;
1619b50d902SRodney W. Grimes 	if (ferror(nf)) {
1629b50d902SRodney W. Grimes 		(void)Fclose(nf);
1630c3a8314SMike Heffner 		warnx("%s", tempname);
1640c3a8314SMike Heffner 		(void)rm(tempname);
1659b50d902SRodney W. Grimes 		nf = NULL;
1669b50d902SRodney W. Grimes 		goto out;
1679b50d902SRodney W. Grimes 	}
1689b50d902SRodney W. Grimes 	if (Fclose(nf) < 0) {
1690c3a8314SMike Heffner 		warn("%s", tempname);
1700c3a8314SMike Heffner 		(void)rm(tempname);
1719b50d902SRodney W. Grimes 		nf = NULL;
1729b50d902SRodney W. Grimes 		goto out;
1739b50d902SRodney W. Grimes 	}
1749b50d902SRodney W. Grimes 	nf = NULL;
1759ce73e90SMike Heffner 	if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NULL)
1769b50d902SRodney W. Grimes 		edit = type == 'e' ? _PATH_EX : _PATH_VI;
177b22a8699SPedro F. Giffuni 	if (run_command(edit, 0, -1, -1, tempname, NULL) < 0) {
1780c3a8314SMike Heffner 		(void)rm(tempname);
1799b50d902SRodney W. Grimes 		goto out;
1809b50d902SRodney W. Grimes 	}
1819b50d902SRodney W. Grimes 	/*
1829b50d902SRodney W. Grimes 	 * If in read only mode or file unchanged, just remove the editor
1839b50d902SRodney W. Grimes 	 * temporary and return.
1849b50d902SRodney W. Grimes 	 */
1859b50d902SRodney W. Grimes 	if (readonly) {
1860c3a8314SMike Heffner 		(void)rm(tempname);
1879b50d902SRodney W. Grimes 		goto out;
1889b50d902SRodney W. Grimes 	}
1890c3a8314SMike Heffner 	if (stat(tempname, &statb) < 0) {
1900c3a8314SMike Heffner 		warn("%s", tempname);
1919b50d902SRodney W. Grimes 		goto out;
1929b50d902SRodney W. Grimes 	}
1939b50d902SRodney W. Grimes 	if (modtime == statb.st_mtime) {
1940c3a8314SMike Heffner 		(void)rm(tempname);
1959b50d902SRodney W. Grimes 		goto out;
1969b50d902SRodney W. Grimes 	}
1979b50d902SRodney W. Grimes 	/*
1989b50d902SRodney W. Grimes 	 * Now switch to new file.
1999b50d902SRodney W. Grimes 	 */
2000c3a8314SMike Heffner 	if ((nf = Fopen(tempname, "a+")) == NULL) {
2010c3a8314SMike Heffner 		warn("%s", tempname);
2020c3a8314SMike Heffner 		(void)rm(tempname);
2039b50d902SRodney W. Grimes 		goto out;
2049b50d902SRodney W. Grimes 	}
2050c3a8314SMike Heffner 	(void)rm(tempname);
2069b50d902SRodney W. Grimes out:
2079ce73e90SMike Heffner 	return (nf);
2089b50d902SRodney W. Grimes }
209