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