rationalized handling of child processes, cleaned up mail1 some more
[unix-history] / usr / src / usr.bin / mail / edit.c
CommitLineData
9552e6b8
DF
1/*
2 * Copyright (c) 1980 Regents of the University of California.
0c5f72fb
KB
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms are permitted
acfc7e9b
KB
6 * provided that the above copyright notice and this paragraph are
7 * duplicated in all such forms and that any documentation,
8 * advertising materials, and other materials related to such
9 * distribution and use acknowledge that the software was developed
10 * by the University of California, Berkeley. The name of the
11 * University may not be used to endorse or promote products derived
12 * from this software without specific prior written permission.
13 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
14 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
15 * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
9552e6b8
DF
16 */
17
acfc7e9b 18#ifndef lint
4daa70e9 19static char sccsid[] = "@(#)edit.c 5.9 (Berkeley) %G%";
acfc7e9b 20#endif /* not lint */
de0c3def
KS
21
22#include "rcv.h"
de0c3def
KS
23#include <sys/stat.h>
24
25/*
26 * Mail -- a mail program
27 *
28 * Perform message editing functions.
29 */
30
de0c3def
KS
31/*
32 * Edit a message list.
33 */
34
35editor(msgvec)
36 int *msgvec;
37{
de0c3def 38
d33aa50d 39 return edit1(msgvec, 'e');
de0c3def
KS
40}
41
42/*
43 * Invoke the visual editor on a message list.
44 */
45
46visual(msgvec)
47 int *msgvec;
48{
de0c3def 49
d33aa50d 50 return edit1(msgvec, 'v');
de0c3def
KS
51}
52
53/*
54 * Edit a message by writing the message into a funnily-named file
55 * (which should not exist) and forking an editor on it.
56 * We get the editor from the stuff above.
57 */
d33aa50d 58edit1(msgvec, type)
de0c3def 59 int *msgvec;
d33aa50d 60 char type;
de0c3def 61{
d33aa50d 62 int (*sigcont)() = signal(SIGCONT, SIG_DFL);
de0c3def 63 register int c;
d33aa50d 64 int i;
064d7d97 65 FILE *fp;
064d7d97 66 register struct message *mp;
d33aa50d 67 off_t size;
de0c3def 68
de0c3def
KS
69 /*
70 * Deal with each message to be edited . . .
71 */
064d7d97 72 for (i = 0; msgvec[i] && i < msgCount; i++) {
d33aa50d
EW
73 int (*sigint)();
74 int m = msgvec[i];
75
76 if (i > 0) {
77 char buf[100];
78 char *p;
79
80 printf("Edit message %d [ynq]? ", m);
81 if (fgets(buf, sizeof buf, stdin) == 0)
82 break;
83 for (p = buf; any(*p, " \t"); p++)
84 ;
85 if (*p == 'q')
86 break;
87 if (*p == 'n')
88 continue;
de0c3def 89 }
d33aa50d
EW
90 dot = mp = &message[m - 1];
91 touch(m);
92 sigint = signal(SIGINT, SIG_IGN);
93 fp = run_editor(setinput(mp), mp->m_size, type, readonly);
94 if (fp != NULL) {
95 (void) fseek(otf, (long) 0, 2);
96 size = ftell(otf);
97 mp->m_block = blockof(size);
98 mp->m_offset = offsetof(size);
99 mp->m_size = fsize(fp);
100 mp->m_lines = 0;
101 mp->m_flag |= MODIFY;
102 rewind(fp);
103 while ((c = getc(fp)) != EOF) {
104 if (c == '\n')
105 mp->m_lines++;
106 if (putc(c, otf) == EOF)
107 break;
108 }
de0c3def 109 if (ferror(otf))
d33aa50d
EW
110 perror("/tmp");
111 (void) fclose(fp);
de0c3def 112 }
d33aa50d
EW
113 (void) signal(SIGINT, sigint);
114 }
115 (void) signal(SIGCONT, sigcont);
116 return 0;
117}
118
119/*
120 * Run an editor on the file at "fpp" of "size" bytes,
121 * and return a new file pointer.
122 * Signals must be handled by the caller.
123 * "Type" is 'e' for EDITOR, 'v' for VISUAL.
124 */
125FILE *
126run_editor(fp, size, type, readonly)
127 register FILE *fp;
128 off_t size;
129 char type;
130{
131 register FILE *nf = NULL;
132 register int t;
133 time_t modtime;
134 char *edit;
135 struct stat statb;
136 extern char tempEdit[];
137
138 if ((t = creat(tempEdit, readonly ? 0400 : 0600)) < 0) {
139 perror(tempEdit);
140 goto out;
141 }
142 if ((nf = fdopen(t, "w")) == NULL) {
143 perror(tempEdit);
144 (void) unlink(tempEdit);
145 goto out;
146 }
147 if (size >= 0)
148 while (--size >= 0 && (t = getc(fp)) != EOF)
149 (void) putc(t, nf);
150 else
151 while ((t = getc(fp)) != EOF)
152 (void) putc(t, nf);
153 (void) fflush(nf);
154 if (fstat(fileno(nf), &statb) < 0)
155 modtime = 0;
156 else
157 modtime = statb.st_mtime;
158 if (ferror(nf) || fclose(nf) < 0) {
159 perror(tempEdit);
160 (void) unlink(tempEdit);
161 nf = NULL;
162 goto out;
163 }
164 nf = NULL;
165 if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NOSTR)
166 edit = type == 'e' ? EDITOR : VISUAL;
167 if (run_command(edit, 0, -1, -1, tempEdit, NOSTR) < 0) {
168 (void) unlink(tempEdit);
169 goto out;
170 }
171 /*
172 * If in read only mode or file unchanged, just remove the editor
173 * temporary and return.
174 */
175 if (readonly) {
176 (void) unlink(tempEdit);
177 goto out;
178 }
179 if (stat(tempEdit, &statb) < 0) {
180 perror(tempEdit);
181 goto out;
182 }
183 if (modtime == statb.st_mtime) {
184 (void) unlink(tempEdit);
185 goto out;
de0c3def 186 }
de0c3def 187 /*
d33aa50d 188 * Now switch to new file.
de0c3def 189 */
d33aa50d
EW
190 if ((nf = fopen(tempEdit, "a+")) == NULL) {
191 perror(tempEdit);
192 (void) unlink(tempEdit);
193 goto out;
194 }
195 (void) unlink(tempEdit);
de0c3def 196out:
d33aa50d 197 return nf;
de0c3def 198}