xref: /original-bsd/usr.bin/mail/edit.c (revision da818fbb)
1 /*
2  * Copyright (c) 1980 Regents of the University of California.
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms are permitted
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.
16  */
17 
18 #ifndef lint
19 static char sccsid[] = "@(#)edit.c	5.13 (Berkeley) 11/24/89";
20 #endif /* not lint */
21 
22 #include "rcv.h"
23 #include <sys/stat.h>
24 
25 /*
26  * Mail -- a mail program
27  *
28  * Perform message editing functions.
29  */
30 
31 /*
32  * Edit a message list.
33  */
34 
35 editor(msgvec)
36 	int *msgvec;
37 {
38 
39 	return edit1(msgvec, 'e');
40 }
41 
42 /*
43  * Invoke the visual editor on a message list.
44  */
45 
46 visual(msgvec)
47 	int *msgvec;
48 {
49 
50 	return edit1(msgvec, 'v');
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  */
58 edit1(msgvec, type)
59 	int *msgvec;
60 	char type;
61 {
62 	register int c;
63 	int i;
64 	FILE *fp;
65 	register struct message *mp;
66 	off_t size;
67 
68 	/*
69 	 * Deal with each message to be edited . . .
70 	 */
71 	for (i = 0; msgvec[i] && i < msgCount; i++) {
72 		sig_t sigint;
73 
74 		if (i > 0) {
75 			char buf[100];
76 			char *p;
77 
78 			printf("Edit message %d [ynq]? ", msgvec[i]);
79 			if (fgets(buf, sizeof buf, stdin) == 0)
80 				break;
81 			for (p = buf; *p == ' ' || *p == '\t'; p++)
82 				;
83 			if (*p == 'q')
84 				break;
85 			if (*p == 'n')
86 				continue;
87 		}
88 		dot = mp = &message[msgvec[i] - 1];
89 		touch(mp);
90 		sigint = signal(SIGINT, SIG_IGN);
91 		fp = run_editor(setinput(mp), mp->m_size, type, readonly);
92 		if (fp != NULL) {
93 			(void) fseek(otf, (long) 0, 2);
94 			size = ftell(otf);
95 			mp->m_block = blockof(size);
96 			mp->m_offset = offsetof(size);
97 			mp->m_size = fsize(fp);
98 			mp->m_lines = 0;
99 			mp->m_flag |= MODIFY;
100 			rewind(fp);
101 			while ((c = getc(fp)) != EOF) {
102 				if (c == '\n')
103 					mp->m_lines++;
104 				if (putc(c, otf) == EOF)
105 					break;
106 			}
107 			if (ferror(otf))
108 				perror("/tmp");
109 			(void) fclose(fp);
110 		}
111 		(void) signal(SIGINT, sigint);
112 	}
113 	return 0;
114 }
115 
116 /*
117  * Run an editor on the file at "fpp" of "size" bytes,
118  * and return a new file pointer.
119  * Signals must be handled by the caller.
120  * "Type" is 'e' for _PATH_EX, 'v' for _PATH_VI.
121  */
122 FILE *
123 run_editor(fp, size, type, readonly)
124 	register FILE *fp;
125 	off_t size;
126 	char type;
127 {
128 	register FILE *nf = NULL;
129 	register int t;
130 	time_t modtime;
131 	char *edit;
132 	struct stat statb;
133 	extern char tempEdit[];
134 
135 	if ((t = creat(tempEdit, readonly ? 0400 : 0600)) < 0) {
136 		perror(tempEdit);
137 		goto out;
138 	}
139 	if ((nf = fdopen(t, "w")) == NULL) {
140 		perror(tempEdit);
141 		(void) unlink(tempEdit);
142 		goto out;
143 	}
144 	if (size >= 0)
145 		while (--size >= 0 && (t = getc(fp)) != EOF)
146 			(void) putc(t, nf);
147 	else
148 		while ((t = getc(fp)) != EOF)
149 			(void) putc(t, nf);
150 	(void) fflush(nf);
151 	if (fstat(fileno(nf), &statb) < 0)
152 		modtime = 0;
153 	else
154 		modtime = statb.st_mtime;
155 	if (ferror(nf) || fclose(nf) < 0) {
156 		perror(tempEdit);
157 		(void) unlink(tempEdit);
158 		nf = NULL;
159 		goto out;
160 	}
161 	nf = NULL;
162 	if ((edit = value(type == 'e' ? "EDITOR" : "VISUAL")) == NOSTR)
163 		edit = type == 'e' ? _PATH_EX : _PATH_VI;
164 	if (run_command(edit, 0, -1, -1, tempEdit, NOSTR) < 0) {
165 		(void) unlink(tempEdit);
166 		goto out;
167 	}
168 	/*
169 	 * If in read only mode or file unchanged, just remove the editor
170 	 * temporary and return.
171 	 */
172 	if (readonly) {
173 		(void) unlink(tempEdit);
174 		goto out;
175 	}
176 	if (stat(tempEdit, &statb) < 0) {
177 		perror(tempEdit);
178 		goto out;
179 	}
180 	if (modtime == statb.st_mtime) {
181 		(void) unlink(tempEdit);
182 		goto out;
183 	}
184 	/*
185 	 * Now switch to new file.
186 	 */
187 	if ((nf = fopen(tempEdit, "a+")) == NULL) {
188 		perror(tempEdit);
189 		(void) unlink(tempEdit);
190 		goto out;
191 	}
192 	(void) unlink(tempEdit);
193 out:
194 	return nf;
195 }
196