xref: /original-bsd/usr.bin/mail/cmd2.c (revision 2c12987e)
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[] = "@(#)cmd2.c	5.13 (Berkeley) 06/01/90";
10 #endif /* not lint */
11 
12 #include "rcv.h"
13 #include <sys/wait.h>
14 
15 /*
16  * Mail -- a mail program
17  *
18  * More user commands.
19  */
20 
21 /*
22  * If any arguments were given, go to the next applicable argument
23  * following dot, otherwise, go to the next applicable message.
24  * If given as first command with no arguments, print first message.
25  */
26 
27 next(msgvec)
28 	int *msgvec;
29 {
30 	register struct message *mp;
31 	register int *ip, *ip2;
32 	int list[2], mdot;
33 
34 	if (*msgvec != NULL) {
35 
36 		/*
37 		 * If some messages were supplied, find the
38 		 * first applicable one following dot using
39 		 * wrap around.
40 		 */
41 
42 		mdot = dot - &message[0] + 1;
43 
44 		/*
45 		 * Find the first message in the supplied
46 		 * message list which follows dot.
47 		 */
48 
49 		for (ip = msgvec; *ip != NULL; ip++)
50 			if (*ip > mdot)
51 				break;
52 		if (*ip == NULL)
53 			ip = msgvec;
54 		ip2 = ip;
55 		do {
56 			mp = &message[*ip2 - 1];
57 			if ((mp->m_flag & MDELETED) == 0) {
58 				dot = mp;
59 				goto hitit;
60 			}
61 			if (*ip2 != NULL)
62 				ip2++;
63 			if (*ip2 == NULL)
64 				ip2 = msgvec;
65 		} while (ip2 != ip);
66 		printf("No messages applicable\n");
67 		return(1);
68 	}
69 
70 	/*
71 	 * If this is the first command, select message 1.
72 	 * Note that this must exist for us to get here at all.
73 	 */
74 
75 	if (!sawcom)
76 		goto hitit;
77 
78 	/*
79 	 * Just find the next good message after dot, no
80 	 * wraparound.
81 	 */
82 
83 	for (mp = dot+1; mp < &message[msgCount]; mp++)
84 		if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
85 			break;
86 	if (mp >= &message[msgCount]) {
87 		printf("At EOF\n");
88 		return(0);
89 	}
90 	dot = mp;
91 hitit:
92 	/*
93 	 * Print dot.
94 	 */
95 
96 	list[0] = dot - &message[0] + 1;
97 	list[1] = NULL;
98 	return(type(list));
99 }
100 
101 /*
102  * Save a message in a file.  Mark the message as saved
103  * so we can discard when the user quits.
104  */
105 save(str)
106 	char str[];
107 {
108 
109 	return save1(str, 1, "save", saveignore);
110 }
111 
112 /*
113  * Copy a message to a file without affected its saved-ness
114  */
115 copycmd(str)
116 	char str[];
117 {
118 
119 	return save1(str, 0, "copy", saveignore);
120 }
121 
122 /*
123  * Save/copy the indicated messages at the end of the passed file name.
124  * If mark is true, mark the message "saved."
125  */
126 save1(str, mark, cmd, ignore)
127 	char str[];
128 	char *cmd;
129 	struct ignoretab *ignore;
130 {
131 	register int *ip;
132 	register struct message *mp;
133 	char *file, *disp;
134 	int f, *msgvec;
135 	FILE *obuf;
136 
137 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
138 	if ((file = snarf(str, &f)) == NOSTR)
139 		return(1);
140 	if (!f) {
141 		*msgvec = first(0, MMNORM);
142 		if (*msgvec == NULL) {
143 			printf("No messages to %s.\n", cmd);
144 			return(1);
145 		}
146 		msgvec[1] = NULL;
147 	}
148 	if (f && getmsglist(str, msgvec, 0) < 0)
149 		return(1);
150 	if ((file = expand(file)) == NOSTR)
151 		return(1);
152 	printf("\"%s\" ", file);
153 	fflush(stdout);
154 	if (access(file, 0) >= 0)
155 		disp = "[Appended]";
156 	else
157 		disp = "[New file]";
158 	if ((obuf = fopen(file, "a")) == NULL) {
159 		perror(NOSTR);
160 		return(1);
161 	}
162 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
163 		mp = &message[*ip - 1];
164 		touch(mp);
165 		if (send(mp, obuf, ignore, NOSTR) < 0) {
166 			perror(file);
167 			fclose(obuf);
168 			return(1);
169 		}
170 		if (mark)
171 			mp->m_flag |= MSAVED;
172 	}
173 	fflush(obuf);
174 	if (ferror(obuf))
175 		perror(file);
176 	fclose(obuf);
177 	printf("%s\n", disp);
178 	return(0);
179 }
180 
181 /*
182  * Write the indicated messages at the end of the passed
183  * file name, minus header and trailing blank line.
184  */
185 
186 swrite(str)
187 	char str[];
188 {
189 
190 	return save1(str, 1, "write", ignoreall);
191 }
192 
193 /*
194  * Snarf the file from the end of the command line and
195  * return a pointer to it.  If there is no file attached,
196  * just return NOSTR.  Put a null in front of the file
197  * name so that the message list processing won't see it,
198  * unless the file name is the only thing on the line, in
199  * which case, return 0 in the reference flag variable.
200  */
201 
202 char *
203 snarf(linebuf, flag)
204 	char linebuf[];
205 	int *flag;
206 {
207 	register char *cp;
208 
209 	*flag = 1;
210 	cp = strlen(linebuf) + linebuf - 1;
211 
212 	/*
213 	 * Strip away trailing blanks.
214 	 */
215 
216 	while (cp > linebuf && isspace(*cp))
217 		cp--;
218 	*++cp = 0;
219 
220 	/*
221 	 * Now search for the beginning of the file name.
222 	 */
223 
224 	while (cp > linebuf && !isspace(*cp))
225 		cp--;
226 	if (*cp == '\0') {
227 		printf("No file specified.\n");
228 		return(NOSTR);
229 	}
230 	if (isspace(*cp))
231 		*cp++ = 0;
232 	else
233 		*flag = 0;
234 	return(cp);
235 }
236 
237 /*
238  * Delete messages.
239  */
240 
241 delete(msgvec)
242 	int msgvec[];
243 {
244 	delm(msgvec);
245 	return 0;
246 }
247 
248 /*
249  * Delete messages, then type the new dot.
250  */
251 
252 deltype(msgvec)
253 	int msgvec[];
254 {
255 	int list[2];
256 	int lastdot;
257 
258 	lastdot = dot - &message[0] + 1;
259 	if (delm(msgvec) >= 0) {
260 		list[0] = dot - &message[0] + 1;
261 		if (list[0] > lastdot) {
262 			touch(dot);
263 			list[1] = NULL;
264 			return(type(list));
265 		}
266 		printf("At EOF\n");
267 	} else
268 		printf("No more messages\n");
269 	return(0);
270 }
271 
272 /*
273  * Delete the indicated messages.
274  * Set dot to some nice place afterwards.
275  * Internal interface.
276  */
277 
278 delm(msgvec)
279 	int *msgvec;
280 {
281 	register struct message *mp;
282 	register *ip;
283 	int last;
284 
285 	last = NULL;
286 	for (ip = msgvec; *ip != NULL; ip++) {
287 		mp = &message[*ip - 1];
288 		touch(mp);
289 		mp->m_flag |= MDELETED|MTOUCH;
290 		mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
291 		last = *ip;
292 	}
293 	if (last != NULL) {
294 		dot = &message[last-1];
295 		last = first(0, MDELETED);
296 		if (last != NULL) {
297 			dot = &message[last-1];
298 			return(0);
299 		}
300 		else {
301 			dot = &message[0];
302 			return(-1);
303 		}
304 	}
305 
306 	/*
307 	 * Following can't happen -- it keeps lint happy
308 	 */
309 
310 	return(-1);
311 }
312 
313 /*
314  * Undelete the indicated messages.
315  */
316 
317 undelete(msgvec)
318 	int *msgvec;
319 {
320 	register struct message *mp;
321 	register *ip;
322 
323 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
324 		mp = &message[*ip - 1];
325 		touch(mp);
326 		dot = mp;
327 		mp->m_flag &= ~MDELETED;
328 	}
329 	return 0;
330 }
331 
332 /*
333  * Interactively dump core on "core"
334  */
335 
336 core()
337 {
338 	int pid;
339 	extern union wait wait_status;
340 
341 	switch (pid = vfork()) {
342 	case -1:
343 		perror("fork");
344 		return(1);
345 	case 0:
346 		abort();
347 		_exit(1);
348 	}
349 	printf("Okie dokie");
350 	fflush(stdout);
351 	wait_child(pid);
352 	if (wait_status.w_coredump)
353 		printf(" -- Core dumped.\n");
354 	else
355 		printf(" -- Can't dump core.\n");
356 	return 0;
357 }
358 
359 /*
360  * Clobber as many bytes of stack as the user requests.
361  */
362 clobber(argv)
363 	char **argv;
364 {
365 	register int times;
366 
367 	if (argv[0] == 0)
368 		times = 1;
369 	else
370 		times = (atoi(argv[0]) + 511) / 512;
371 	clob1(times);
372 	return 0;
373 }
374 
375 /*
376  * Clobber the stack.
377  */
378 clob1(n)
379 {
380 	char buf[512];
381 	register char *cp;
382 
383 	if (n <= 0)
384 		return;
385 	for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
386 		;
387 	clob1(n - 1);
388 }
389 
390 /*
391  * Add the given header fields to the retained list.
392  * If no arguments, print the current list of retained fields.
393  */
394 retfield(list)
395 	char *list[];
396 {
397 
398 	return ignore1(list, ignore + 1, "retained");
399 }
400 
401 /*
402  * Add the given header fields to the ignored list.
403  * If no arguments, print the current list of ignored fields.
404  */
405 igfield(list)
406 	char *list[];
407 {
408 
409 	return ignore1(list, ignore, "ignored");
410 }
411 
412 saveretfield(list)
413 	char *list[];
414 {
415 
416 	return ignore1(list, saveignore + 1, "retained");
417 }
418 
419 saveigfield(list)
420 	char *list[];
421 {
422 
423 	return ignore1(list, saveignore, "ignored");
424 }
425 
426 ignore1(list, tab, which)
427 	char *list[];
428 	struct ignoretab *tab;
429 	char *which;
430 {
431 	char field[BUFSIZ];
432 	register int h;
433 	register struct ignore *igp;
434 	char **ap;
435 
436 	if (*list == NOSTR)
437 		return igshow(tab, which);
438 	for (ap = list; *ap != 0; ap++) {
439 		istrcpy(field, *ap);
440 		if (member(field, tab))
441 			continue;
442 		h = hash(field);
443 		igp = (struct ignore *) calloc(1, sizeof (struct ignore));
444 		igp->i_field = calloc((unsigned) strlen(field) + 1,
445 			sizeof (char));
446 		strcpy(igp->i_field, field);
447 		igp->i_link = tab->i_head[h];
448 		tab->i_head[h] = igp;
449 		tab->i_count++;
450 	}
451 	return 0;
452 }
453 
454 /*
455  * Print out all currently retained fields.
456  */
457 igshow(tab, which)
458 	struct ignoretab *tab;
459 	char *which;
460 {
461 	register int h;
462 	struct ignore *igp;
463 	char **ap, **ring;
464 	int igcomp();
465 
466 	if (tab->i_count == 0) {
467 		printf("No fields currently being %s.\n", which);
468 		return 0;
469 	}
470 	ring = (char **) salloc((tab->i_count + 1) * sizeof (char *));
471 	ap = ring;
472 	for (h = 0; h < HSHSIZE; h++)
473 		for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link)
474 			*ap++ = igp->i_field;
475 	*ap = 0;
476 	qsort((char *) ring, tab->i_count, sizeof (char *), igcomp);
477 	for (ap = ring; *ap != 0; ap++)
478 		printf("%s\n", *ap);
479 	return 0;
480 }
481 
482 /*
483  * Compare two names for sorting ignored field list.
484  */
485 igcomp(l, r)
486 	char **l, **r;
487 {
488 
489 	return strcmp(*l, *r);
490 }
491