xref: /original-bsd/usr.bin/mail/cmd2.c (revision 62734ea8)
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.10 10/21/82";
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 a message in a file.  Mark the message as saved
96  * so we can discard when the user quits.
97  */
98 save(str)
99 	char str[];
100 {
101 
102 	return(save1(str, 1));
103 }
104 
105 /*
106  * Copy a message to a file without affected its saved-ness
107  */
108 copycmd(str)
109 	char str[];
110 {
111 
112 	return(save1(str, 0));
113 }
114 
115 /*
116  * Save/copy the indicated messages at the end of the passed file name.
117  * If mark is true, mark the message "saved."
118  */
119 save1(str, mark)
120 	char str[];
121 {
122 	register int *ip, mesg;
123 	register struct message *mp;
124 	char *file, *disp, *cmd;
125 	int f, *msgvec, lc, t;
126 	long cc;
127 	FILE *obuf;
128 	struct stat statb;
129 
130 	cmd = mark ? "save" : "copy";
131 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
132 	if ((file = snarf(str, &f)) == NOSTR)
133 		return(1);
134 	if (!f) {
135 		*msgvec = first(0, MMNORM);
136 		if (*msgvec == NULL) {
137 			printf("No messages to %s.\n", cmd);
138 			return(1);
139 		}
140 		msgvec[1] = NULL;
141 	}
142 	if (f && getmsglist(str, msgvec, 0) < 0)
143 		return(1);
144 	if ((file = expand(file)) == NOSTR)
145 		return(1);
146 	printf("\"%s\" ", file);
147 	flush();
148 	if (stat(file, &statb) >= 0)
149 		disp = "[Appended]";
150 	else
151 		disp = "[New file]";
152 	if ((obuf = fopen(file, "a")) == NULL) {
153 		perror(NOSTR);
154 		return(1);
155 	}
156 	cc = 0L;
157 	lc = 0;
158 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
159 		mesg = *ip;
160 		touch(mesg);
161 		mp = &message[mesg-1];
162 		if ((t = send(mp, obuf, 0)) < 0) {
163 			perror(file);
164 			fclose(obuf);
165 			return(1);
166 		}
167 		lc += t;
168 		cc += mp->m_size;
169 		if (mark)
170 			mp->m_flag |= MSAVED;
171 	}
172 	fflush(obuf);
173 	if (ferror(obuf))
174 		perror(file);
175 	fclose(obuf);
176 	printf("%s %d/%ld\n", disp, lc, cc);
177 	return(0);
178 }
179 
180 /*
181  * Write the indicated messages at the end of the passed
182  * file name, minus header and trailing blank line.
183  */
184 
185 swrite(str)
186 	char str[];
187 {
188 	register int *ip, mesg;
189 	register struct message *mp;
190 	register char *file, *disp;
191 	char linebuf[BUFSIZ];
192 	int f, *msgvec, lc, cc, t;
193 	FILE *obuf, *mesf;
194 	struct stat statb;
195 
196 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
197 	if ((file = snarf(str, &f)) == NOSTR)
198 		return(1);
199 	if ((file = expand(file)) == NOSTR)
200 		return(1);
201 	if (!f) {
202 		*msgvec = first(0, MMNORM);
203 		if (*msgvec == NULL) {
204 			printf("No messages to write.\n");
205 			return(1);
206 		}
207 		msgvec[1] = NULL;
208 	}
209 	if (f && getmsglist(str, msgvec, 0) < 0)
210 		return(1);
211 	printf("\"%s\" ", file);
212 	flush();
213 	if (stat(file, &statb) >= 0)
214 		disp = "[Appended]";
215 	else
216 		disp = "[New file]";
217 	if ((obuf = fopen(file, "a")) == NULL) {
218 		perror(NOSTR);
219 		return(1);
220 	}
221 	cc = lc = 0;
222 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
223 		mesg = *ip;
224 		touch(mesg);
225 		mp = &message[mesg-1];
226 		mesf = setinput(mp);
227 		t = mp->m_lines - 2;
228 		readline(mesf, linebuf);
229 		while (t-- > 0) {
230 			fgets(linebuf, BUFSIZ, mesf);
231 			fputs(linebuf, obuf);
232 			cc += strlen(linebuf);
233 		}
234 		lc += mp->m_lines - 2;
235 		mp->m_flag |= MSAVED;
236 	}
237 	fflush(obuf);
238 	if (ferror(obuf))
239 		perror(file);
240 	fclose(obuf);
241 	printf("%s %d/%d\n", disp, lc, cc);
242 	return(0);
243 }
244 
245 /*
246  * Snarf the file from the end of the command line and
247  * return a pointer to it.  If there is no file attached,
248  * just return NOSTR.  Put a null in front of the file
249  * name so that the message list processing won't see it,
250  * unless the file name is the only thing on the line, in
251  * which case, return 0 in the reference flag variable.
252  */
253 
254 char *
255 snarf(linebuf, flag)
256 	char linebuf[];
257 	int *flag;
258 {
259 	register char *cp;
260 
261 	*flag = 1;
262 	cp = strlen(linebuf) + linebuf - 1;
263 
264 	/*
265 	 * Strip away trailing blanks.
266 	 */
267 
268 	while (*cp == ' ' && cp > linebuf)
269 		cp--;
270 	*++cp = 0;
271 
272 	/*
273 	 * Now search for the beginning of the file name.
274 	 */
275 
276 	while (cp > linebuf && !any(*cp, "\t "))
277 		cp--;
278 	if (*cp == '\0') {
279 		printf("No file specified.\n");
280 		return(NOSTR);
281 	}
282 	if (any(*cp, " \t"))
283 		*cp++ = 0;
284 	else
285 		*flag = 0;
286 	return(cp);
287 }
288 
289 /*
290  * Delete messages.
291  */
292 
293 delete(msgvec)
294 	int msgvec[];
295 {
296 	return(delm(msgvec));
297 }
298 
299 /*
300  * Delete messages, then type the new dot.
301  */
302 
303 deltype(msgvec)
304 	int msgvec[];
305 {
306 	int list[2];
307 	int lastdot;
308 
309 	lastdot = dot - &message[0] + 1;
310 	if (delm(msgvec) >= 0) {
311 		list[0] = dot - &message[0];
312 		list[0]++;
313 		if (list[0] > lastdot) {
314 			touch(list[0]);
315 			list[1] = NULL;
316 			return(type(list));
317 		}
318 		printf("At EOF\n");
319 		return(0);
320 	}
321 	else {
322 		printf("No more messages\n");
323 		return(0);
324 	}
325 }
326 
327 /*
328  * Delete the indicated messages.
329  * Set dot to some nice place afterwards.
330  * Internal interface.
331  */
332 
333 delm(msgvec)
334 	int *msgvec;
335 {
336 	register struct message *mp;
337 	register *ip, mesg;
338 	int last;
339 
340 	last = NULL;
341 	for (ip = msgvec; *ip != NULL; ip++) {
342 		mesg = *ip;
343 		touch(mesg);
344 		mp = &message[mesg-1];
345 		mp->m_flag |= MDELETED|MTOUCH;
346 		mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
347 		last = mesg;
348 	}
349 	if (last != NULL) {
350 		dot = &message[last-1];
351 		last = first(0, MDELETED);
352 		if (last != NULL) {
353 			dot = &message[last-1];
354 			return(0);
355 		}
356 		else {
357 			dot = &message[0];
358 			return(-1);
359 		}
360 	}
361 
362 	/*
363 	 * Following can't happen -- it keeps lint happy
364 	 */
365 
366 	return(-1);
367 }
368 
369 /*
370  * Undelete the indicated messages.
371  */
372 
373 undelete(msgvec)
374 	int *msgvec;
375 {
376 	register struct message *mp;
377 	register *ip, mesg;
378 
379 	for (ip = msgvec; ip-msgvec < msgCount; ip++) {
380 		mesg = *ip;
381 		if (mesg == 0)
382 			return;
383 		touch(mesg);
384 		mp = &message[mesg-1];
385 		dot = mp;
386 		mp->m_flag &= ~MDELETED;
387 	}
388 }
389 
390 /*
391  * Interactively dump core on "core"
392  */
393 
394 core()
395 {
396 	register int pid;
397 	int status;
398 
399 	if ((pid = vfork()) == -1) {
400 		perror("fork");
401 		return(1);
402 	}
403 	if (pid == 0) {
404 		sigchild();
405 		abort();
406 		_exit(1);
407 	}
408 	printf("Okie dokie");
409 	fflush(stdout);
410 	while (wait(&status) != pid)
411 		;
412 	if (status & 0200)
413 		printf(" -- Core dumped\n");
414 	else
415 		printf("\n");
416 }
417 
418 /*
419  * Clobber as many bytes of stack as the user requests.
420  */
421 clobber(argv)
422 	char **argv;
423 {
424 	register int times;
425 
426 	if (argv[0] == 0)
427 		times = 1;
428 	else
429 		times = (atoi(argv[0]) + 511) / 512;
430 	clob1(times);
431 }
432 
433 /*
434  * Clobber the stack.
435  */
436 clob1(n)
437 {
438 	char buf[512];
439 	register char *cp;
440 
441 	if (n <= 0)
442 		return;
443 	for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
444 		;
445 	clob1(n - 1);
446 }
447 
448 /*
449  * Add the given header fields to the ignored list.
450  * If no arguments, print the current list of ignored fields.
451  */
452 igfield(list)
453 	char *list[];
454 {
455 	char field[BUFSIZ];
456 	register int h;
457 	register struct ignore *igp;
458 	char **ap;
459 
460 	if (argcount(list) == 0)
461 		return(igshow());
462 	for (ap = list; *ap != 0; ap++) {
463 		if (isign(*ap))
464 			continue;
465 		istrcpy(field, *ap);
466 		h = hash(field);
467 		igp = (struct ignore *) calloc(1, sizeof (struct ignore));
468 		igp->i_field = calloc(strlen(field) + 1, sizeof (char));
469 		strcpy(igp->i_field, field);
470 		igp->i_link = ignore[h];
471 		ignore[h] = igp;
472 	}
473 	return(0);
474 }
475 
476 /*
477  * Print out all currently ignored fields.
478  */
479 igshow()
480 {
481 	register int h, count;
482 	struct ignore *igp;
483 	char **ap, **ring;
484 	int igcomp();
485 
486 	count = 0;
487 	for (h = 0; h < HSHSIZE; h++)
488 		for (igp = ignore[h]; igp != 0; igp = igp->i_link)
489 			count++;
490 	if (count == 0) {
491 		printf("No fields currently being ignored.\n");
492 		return(0);
493 	}
494 	ring = (char **) salloc((count + 1) * sizeof (char *));
495 	ap = ring;
496 	for (h = 0; h < HSHSIZE; h++)
497 		for (igp = ignore[h]; igp != 0; igp = igp->i_link)
498 			*ap++ = igp->i_field;
499 	*ap = 0;
500 	qsort(ring, count, sizeof (char *), igcomp);
501 	for (ap = ring; *ap != 0; ap++)
502 		printf("%s\n", *ap);
503 	return(0);
504 }
505 
506 /*
507  * Compare two names for sorting ignored field list.
508  */
509 igcomp(l, r)
510 	char **l, **r;
511 {
512 
513 	return(strcmp(*l, *r));
514 }
515