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