xref: /original-bsd/usr.bin/mail/cmd2.c (revision 1f3a482a)
1 #
2 
3 #include "rcv.h"
4 #include <sys/stat.h>
5 
6 /*
7  * Mail -- a mail program
8  *
9  * More user commands.
10  */
11 
12 static char *SccsId = "@(#)cmd2.c	2.1 07/01/81";
13 
14 /*
15  * If any arguments were given, go to the next applicable argument
16  * following dot, otherwise, go to the next applicable message.
17  * If given as first command with no arguments, print first message.
18  */
19 
20 next(msgvec)
21 	int *msgvec;
22 {
23 	register struct message *mp;
24 	register int *ip, *ip2;
25 	int list[2], mdot;
26 
27 	if (*msgvec != NULL) {
28 
29 		/*
30 		 * If some messages were supplied, find the
31 		 * first applicable one following dot using
32 		 * wrap around.
33 		 */
34 
35 		mdot = dot - &message[0] + 1;
36 
37 		/*
38 		 * Find the first message in the supplied
39 		 * message list which follows dot.
40 		 */
41 
42 		for (ip = msgvec; *ip != NULL; ip++)
43 			if (*ip > mdot)
44 				break;
45 		if (*ip == NULL)
46 			ip = msgvec;
47 		ip2 = ip;
48 		do {
49 			mp = &message[*ip2 - 1];
50 			if ((mp->m_flag & MDELETED) == 0) {
51 				dot = mp;
52 				goto hitit;
53 			}
54 			if (*ip2 != NULL)
55 				ip2++;
56 			if (*ip2 == NULL)
57 				ip2 = msgvec;
58 		} while (ip2 != ip);
59 		printf("No messages applicable\n");
60 		return(1);
61 	}
62 
63 	/*
64 	 * If this is the first command, select message 1.
65 	 * Note that this must exist for us to get here at all.
66 	 */
67 
68 	if (!sawcom)
69 		goto hitit;
70 
71 	/*
72 	 * Just find the next good message after dot, no
73 	 * wraparound.
74 	 */
75 
76 	for (mp = dot+1; mp < &message[msgCount]; mp++)
77 		if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
78 			break;
79 	if (mp >= &message[msgCount]) {
80 		printf("At EOF\n");
81 		return(0);
82 	}
83 	dot = mp;
84 hitit:
85 	/*
86 	 * Print dot.
87 	 */
88 
89 	list[0] = dot - &message[0] + 1;
90 	list[1] = NULL;
91 	return(type(list));
92 }
93 
94 /*
95  * Save the indicated messages at the end of the passed file name.
96  */
97 
98 save(str)
99 	char str[];
100 {
101 	register int *ip, mesg;
102 	register struct message *mp;
103 	char *file, *disp;
104 	int f, *msgvec, lc, cc, t;
105 	FILE *obuf;
106 	struct stat statb;
107 
108 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
109 	if ((file = snarf(str, &f)) == NOSTR)
110 		return(1);
111 	if (!f) {
112 		*msgvec = first(0, MMNORM);
113 		if (*msgvec == NULL) {
114 			printf("No messages to save.\n");
115 			return(1);
116 		}
117 		msgvec[1] = NULL;
118 	}
119 	if (f && getmsglist(str, msgvec, 0) < 0)
120 		return(1);
121 	if ((file = expand(file)) == NOSTR)
122 		return(1);
123 	printf("\"%s\" ", file);
124 	flush();
125 	if (stat(file, &statb) >= 0)
126 		disp = "[Appended]";
127 	else
128 		disp = "[New file]";
129 	if ((obuf = fopen(file, "a")) == NULL) {
130 		perror(NOSTR);
131 		return(1);
132 	}
133 	cc = lc = 0;
134 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
135 		mesg = *ip;
136 		touch(mesg);
137 		mp = &message[mesg-1];
138 		if ((t = send(mp, obuf)) < 0) {
139 			perror(file);
140 			fclose(obuf);
141 			return(1);
142 		}
143 		lc += t;
144 		cc += msize(mp);
145 		mp->m_flag |= MSAVED;
146 	}
147 	fflush(obuf);
148 	if (ferror(obuf))
149 		perror(file);
150 	fclose(obuf);
151 	printf("%s %d/%d\n", disp, lc, cc);
152 	return(0);
153 }
154 
155 /*
156  * Write the indicated messages at the end of the passed
157  * file name, minus header and trailing blank line.
158  */
159 
160 swrite(str)
161 	char str[];
162 {
163 	register int *ip, mesg;
164 	register struct message *mp;
165 	register char *file, *disp;
166 	char linebuf[BUFSIZ];
167 	int f, *msgvec, lc, cc, t;
168 	FILE *obuf, *mesf;
169 	struct stat statb;
170 
171 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
172 	if ((file = snarf(str, &f)) == NOSTR)
173 		return(1);
174 	if ((file = expand(file)) == NOSTR)
175 		return(1);
176 	if (!f) {
177 		*msgvec = first(0, MMNORM);
178 		if (*msgvec == NULL) {
179 			printf("No messages to write.\n");
180 			return(1);
181 		}
182 		msgvec[1] = NULL;
183 	}
184 	if (f && getmsglist(str, msgvec, 0) < 0)
185 		return(1);
186 	printf("\"%s\" ", file);
187 	flush();
188 	if (stat(file, &statb) >= 0)
189 		disp = "[Appended]";
190 	else
191 		disp = "[New file]";
192 	if ((obuf = fopen(file, "a")) == NULL) {
193 		perror(NOSTR);
194 		return(1);
195 	}
196 	cc = lc = 0;
197 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
198 		mesg = *ip;
199 		touch(mesg);
200 		mp = &message[mesg-1];
201 		mesf = setinput(mp);
202 		t = mp->m_lines - 2;
203 		readline(mesf, linebuf);
204 		while (t-- > 0) {
205 			fgets(linebuf, BUFSIZ, mesf);
206 			fputs(linebuf, obuf);
207 			cc += strlen(linebuf);
208 		}
209 		lc += mp->m_lines - 2;
210 		mp->m_flag |= MSAVED;
211 	}
212 	fflush(obuf);
213 	if (ferror(obuf))
214 		perror(file);
215 	fclose(obuf);
216 	printf("%s %d/%d\n", disp, lc, cc);
217 	return(0);
218 }
219 
220 /*
221  * Snarf the file from the end of the command line and
222  * return a pointer to it.  If there is no file attached,
223  * just return NOSTR.  Put a null in front of the file
224  * name so that the message list processing won't see it,
225  * unless the file name is the only thing on the line, in
226  * which case, return 0 in the reference flag variable.
227  */
228 
229 char *
230 snarf(linebuf, flag)
231 	char linebuf[];
232 	int *flag;
233 {
234 	register char *cp;
235 
236 	*flag = 1;
237 	cp = strlen(linebuf) + linebuf - 1;
238 
239 	/*
240 	 * Strip away trailing blanks.
241 	 */
242 
243 	while (*cp == ' ' && cp > linebuf)
244 		cp--;
245 	*++cp = 0;
246 
247 	/*
248 	 * Now search for the beginning of the file name.
249 	 */
250 
251 	while (cp > linebuf && !any(*cp, "\t "))
252 		cp--;
253 	if (*cp == '\0') {
254 		printf("No file specified.\n");
255 		return(NOSTR);
256 	}
257 	if (any(*cp, " \t"))
258 		*cp++ = 0;
259 	else
260 		*flag = 0;
261 	return(cp);
262 }
263 
264 /*
265  * Delete messages.
266  */
267 
268 delete(msgvec)
269 	int msgvec[];
270 {
271 	return(delm(msgvec));
272 }
273 
274 /*
275  * Delete messages, then type the new dot.
276  */
277 
278 deltype(msgvec)
279 	int msgvec[];
280 {
281 	int list[2];
282 
283 	if (delm(msgvec) >= 0) {
284 		list[0] = dot - &message[0];
285 		list[0]++;
286 		touch(list[0]);
287 		list[1] = NULL;
288 		return(type(list));
289 	}
290 	else {
291 		printf("No more messages\n");
292 		return(0);
293 	}
294 }
295 
296 /*
297  * Delete the indicated messages.
298  * Set dot to some nice place afterwards.
299  * Internal interface.
300  */
301 
302 delm(msgvec)
303 	int *msgvec;
304 {
305 	register struct message *mp;
306 	register *ip, mesg;
307 	int last;
308 
309 	last = NULL;
310 	for (ip = msgvec; *ip != NULL; ip++) {
311 		mesg = *ip;
312 		touch(mesg);
313 		mp = &message[mesg-1];
314 		mp->m_flag |= MDELETED|MTOUCH;
315 		mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
316 		last = mesg;
317 	}
318 	if (last != NULL) {
319 		dot = &message[last-1];
320 		last = first(0, MDELETED);
321 		if (last != NULL) {
322 			dot = &message[last-1];
323 			return(0);
324 		}
325 		else {
326 			dot = &message[0];
327 			return(-1);
328 		}
329 	}
330 
331 	/*
332 	 * Following can't happen -- it keeps lint happy
333 	 */
334 
335 	return(-1);
336 }
337 
338 /*
339  * Undelete the indicated messages.
340  */
341 
342 undelete(msgvec)
343 	int *msgvec;
344 {
345 	register struct message *mp;
346 	register *ip, mesg;
347 
348 	for (ip = msgvec; ip-msgvec < msgCount; ip++) {
349 		mesg = *ip;
350 		if (mesg == 0)
351 			return;
352 		touch(mesg);
353 		mp = &message[mesg-1];
354 		dot = mp;
355 		mp->m_flag &= ~MDELETED;
356 	}
357 }
358 
359 /*
360  * Interactively dump core on "core"
361  */
362 
363 core()
364 {
365 	register int pid;
366 	int status;
367 
368 	if ((pid = vfork()) == -1) {
369 		perror("fork");
370 		return(1);
371 	}
372 	if (pid == 0) {
373 		abort();
374 		_exit(1);
375 	}
376 	printf("Okie dokie");
377 	fflush(stdout);
378 	while (wait(&status) != pid)
379 		;
380 	if (status & 0200)
381 		printf(" -- Core dumped\n");
382 	else
383 		printf("\n");
384 }
385