xref: /original-bsd/usr.bin/mail/cmd2.c (revision 1e7fda44)
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.4 02/13/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, cc, t;
126 	FILE *obuf;
127 	struct stat statb;
128 
129 	cmd = mark ? "save" : "copy";
130 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
131 	if ((file = snarf(str, &f)) == NOSTR)
132 		return(1);
133 	if (!f) {
134 		*msgvec = first(0, MMNORM);
135 		if (*msgvec == NULL) {
136 			printf("No messages to %s.\n", cmd);
137 			return(1);
138 		}
139 		msgvec[1] = NULL;
140 	}
141 	if (f && getmsglist(str, msgvec, 0) < 0)
142 		return(1);
143 	if ((file = expand(file)) == NOSTR)
144 		return(1);
145 	printf("\"%s\" ", file);
146 	flush();
147 	if (stat(file, &statb) >= 0)
148 		disp = "[Appended]";
149 	else
150 		disp = "[New file]";
151 	if ((obuf = fopen(file, "a")) == NULL) {
152 		perror(NOSTR);
153 		return(1);
154 	}
155 	cc = lc = 0;
156 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
157 		mesg = *ip;
158 		touch(mesg);
159 		mp = &message[mesg-1];
160 		if ((t = send(mp, obuf)) < 0) {
161 			perror(file);
162 			fclose(obuf);
163 			return(1);
164 		}
165 		lc += t;
166 		cc += msize(mp);
167 		if (mark)
168 			mp->m_flag |= MSAVED;
169 	}
170 	fflush(obuf);
171 	if (ferror(obuf))
172 		perror(file);
173 	fclose(obuf);
174 	printf("%s %d/%d\n", disp, lc, cc);
175 	return(0);
176 }
177 
178 /*
179  * Write the indicated messages at the end of the passed
180  * file name, minus header and trailing blank line.
181  */
182 
183 swrite(str)
184 	char str[];
185 {
186 	register int *ip, mesg;
187 	register struct message *mp;
188 	register char *file, *disp;
189 	char linebuf[BUFSIZ];
190 	int f, *msgvec, lc, cc, t;
191 	FILE *obuf, *mesf;
192 	struct stat statb;
193 
194 	msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
195 	if ((file = snarf(str, &f)) == NOSTR)
196 		return(1);
197 	if ((file = expand(file)) == NOSTR)
198 		return(1);
199 	if (!f) {
200 		*msgvec = first(0, MMNORM);
201 		if (*msgvec == NULL) {
202 			printf("No messages to write.\n");
203 			return(1);
204 		}
205 		msgvec[1] = NULL;
206 	}
207 	if (f && getmsglist(str, msgvec, 0) < 0)
208 		return(1);
209 	printf("\"%s\" ", file);
210 	flush();
211 	if (stat(file, &statb) >= 0)
212 		disp = "[Appended]";
213 	else
214 		disp = "[New file]";
215 	if ((obuf = fopen(file, "a")) == NULL) {
216 		perror(NOSTR);
217 		return(1);
218 	}
219 	cc = lc = 0;
220 	for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
221 		mesg = *ip;
222 		touch(mesg);
223 		mp = &message[mesg-1];
224 		mesf = setinput(mp);
225 		t = mp->m_lines - 2;
226 		readline(mesf, linebuf);
227 		while (t-- > 0) {
228 			fgets(linebuf, BUFSIZ, mesf);
229 			fputs(linebuf, obuf);
230 			cc += strlen(linebuf);
231 		}
232 		lc += mp->m_lines - 2;
233 		mp->m_flag |= MSAVED;
234 	}
235 	fflush(obuf);
236 	if (ferror(obuf))
237 		perror(file);
238 	fclose(obuf);
239 	printf("%s %d/%d\n", disp, lc, cc);
240 	return(0);
241 }
242 
243 /*
244  * Snarf the file from the end of the command line and
245  * return a pointer to it.  If there is no file attached,
246  * just return NOSTR.  Put a null in front of the file
247  * name so that the message list processing won't see it,
248  * unless the file name is the only thing on the line, in
249  * which case, return 0 in the reference flag variable.
250  */
251 
252 char *
253 snarf(linebuf, flag)
254 	char linebuf[];
255 	int *flag;
256 {
257 	register char *cp;
258 
259 	*flag = 1;
260 	cp = strlen(linebuf) + linebuf - 1;
261 
262 	/*
263 	 * Strip away trailing blanks.
264 	 */
265 
266 	while (*cp == ' ' && cp > linebuf)
267 		cp--;
268 	*++cp = 0;
269 
270 	/*
271 	 * Now search for the beginning of the file name.
272 	 */
273 
274 	while (cp > linebuf && !any(*cp, "\t "))
275 		cp--;
276 	if (*cp == '\0') {
277 		printf("No file specified.\n");
278 		return(NOSTR);
279 	}
280 	if (any(*cp, " \t"))
281 		*cp++ = 0;
282 	else
283 		*flag = 0;
284 	return(cp);
285 }
286 
287 /*
288  * Delete messages.
289  */
290 
291 delete(msgvec)
292 	int msgvec[];
293 {
294 	return(delm(msgvec));
295 }
296 
297 /*
298  * Delete messages, then type the new dot.
299  */
300 
301 deltype(msgvec)
302 	int msgvec[];
303 {
304 	int list[2];
305 	int lastdot;
306 
307 	lastdot = dot - &message[0] + 1;
308 	if (delm(msgvec) >= 0) {
309 		list[0] = dot - &message[0];
310 		list[0]++;
311 		if (list[0] > lastdot) {
312 			touch(list[0]);
313 			list[1] = NULL;
314 			return(type(list));
315 		}
316 		printf("At EOF\n");
317 		return(0);
318 	}
319 	else {
320 		printf("No more messages\n");
321 		return(0);
322 	}
323 }
324 
325 /*
326  * Delete the indicated messages.
327  * Set dot to some nice place afterwards.
328  * Internal interface.
329  */
330 
331 delm(msgvec)
332 	int *msgvec;
333 {
334 	register struct message *mp;
335 	register *ip, mesg;
336 	int last;
337 
338 	last = NULL;
339 	for (ip = msgvec; *ip != NULL; ip++) {
340 		mesg = *ip;
341 		touch(mesg);
342 		mp = &message[mesg-1];
343 		mp->m_flag |= MDELETED|MTOUCH;
344 		mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
345 		last = mesg;
346 	}
347 	if (last != NULL) {
348 		dot = &message[last-1];
349 		last = first(0, MDELETED);
350 		if (last != NULL) {
351 			dot = &message[last-1];
352 			return(0);
353 		}
354 		else {
355 			dot = &message[0];
356 			return(-1);
357 		}
358 	}
359 
360 	/*
361 	 * Following can't happen -- it keeps lint happy
362 	 */
363 
364 	return(-1);
365 }
366 
367 /*
368  * Undelete the indicated messages.
369  */
370 
371 undelete(msgvec)
372 	int *msgvec;
373 {
374 	register struct message *mp;
375 	register *ip, mesg;
376 
377 	for (ip = msgvec; ip-msgvec < msgCount; ip++) {
378 		mesg = *ip;
379 		if (mesg == 0)
380 			return;
381 		touch(mesg);
382 		mp = &message[mesg-1];
383 		dot = mp;
384 		mp->m_flag &= ~MDELETED;
385 	}
386 }
387 
388 /*
389  * Interactively dump core on "core"
390  */
391 
392 core()
393 {
394 	register int pid;
395 	int status;
396 
397 	if ((pid = vfork()) == -1) {
398 		perror("fork");
399 		return(1);
400 	}
401 	if (pid == 0) {
402 		abort();
403 		_exit(1);
404 	}
405 	printf("Okie dokie");
406 	fflush(stdout);
407 	while (wait(&status) != pid)
408 		;
409 	if (status & 0200)
410 		printf(" -- Core dumped\n");
411 	else
412 		printf("\n");
413 }
414 
415 /*
416  * Clobber as many bytes of stack as the user requests.
417  */
418 clobber(argv)
419 	char **argv;
420 {
421 	register int times;
422 
423 	if (argv[0] == 0)
424 		times = 1;
425 	else
426 		times = (atoi(argv[0]) + 511) / 512;
427 	clobber1(times);
428 }
429 
430 /*
431  * Clobber the stack.
432  */
433 clobber1(n)
434 {
435 	char buf[512];
436 	register char *cp;
437 
438 	if (n <= 0)
439 		return;
440 	for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
441 		;
442 	clobber1(n - 1);
443 }
444