Commit | Line | Data |
---|---|---|
d0aeaf5a DF |
1 | /* |
2 | * Copyright (c) 1980 Regents of the University of California. | |
0c5f72fb KB |
3 | * All rights reserved. |
4 | * | |
f15db449 | 5 | * %sccs.include.redist.c% |
d0aeaf5a DF |
6 | */ |
7 | ||
acfc7e9b | 8 | #ifndef lint |
07b0d286 | 9 | static char sccsid[] = "@(#)cmd2.c 5.14 (Berkeley) %G%"; |
acfc7e9b | 10 | #endif /* not lint */ |
a13d1f28 KS |
11 | |
12 | #include "rcv.h" | |
828615a1 | 13 | #include <sys/wait.h> |
a13d1f28 KS |
14 | |
15 | /* | |
16 | * Mail -- a mail program | |
17 | * | |
18 | * More user commands. | |
19 | */ | |
20 | ||
a13d1f28 KS |
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; | |
30629819 KS |
43 | |
44 | /* | |
45 | * Find the first message in the supplied | |
46 | * message list which follows dot. | |
47 | */ | |
48 | ||
a13d1f28 KS |
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 { | |
a13d1f28 KS |
56 | mp = &message[*ip2 - 1]; |
57 | if ((mp->m_flag & MDELETED) == 0) { | |
58 | dot = mp; | |
59 | goto hitit; | |
60 | } | |
30629819 KS |
61 | if (*ip2 != NULL) |
62 | ip2++; | |
63 | if (*ip2 == NULL) | |
64 | ip2 = msgvec; | |
a13d1f28 KS |
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 | ||
799afc8f | 75 | if (!sawcom) |
a13d1f28 | 76 | goto hitit; |
a13d1f28 KS |
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 | /* | |
c7db23a4 KS |
102 | * Save a message in a file. Mark the message as saved |
103 | * so we can discard when the user quits. | |
a13d1f28 | 104 | */ |
a13d1f28 KS |
105 | save(str) |
106 | char str[]; | |
107 | { | |
c7db23a4 | 108 | |
2de8fc95 | 109 | return save1(str, 1, "save", saveignore); |
c7db23a4 KS |
110 | } |
111 | ||
112 | /* | |
113 | * Copy a message to a file without affected its saved-ness | |
114 | */ | |
115 | copycmd(str) | |
116 | char str[]; | |
117 | { | |
118 | ||
2de8fc95 | 119 | return save1(str, 0, "copy", saveignore); |
c7db23a4 KS |
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 | */ | |
2de8fc95 | 126 | save1(str, mark, cmd, ignore) |
c7db23a4 | 127 | char str[]; |
2de8fc95 EW |
128 | char *cmd; |
129 | struct ignoretab *ignore; | |
c7db23a4 | 130 | { |
470c33f3 | 131 | register int *ip; |
a13d1f28 | 132 | register struct message *mp; |
2de8fc95 EW |
133 | char *file, *disp; |
134 | int f, *msgvec; | |
a13d1f28 | 135 | FILE *obuf; |
a13d1f28 KS |
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) { | |
c7db23a4 | 143 | printf("No messages to %s.\n", cmd); |
a13d1f28 KS |
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); | |
80187484 | 153 | fflush(stdout); |
2de8fc95 | 154 | if (access(file, 0) >= 0) |
a13d1f28 KS |
155 | disp = "[Appended]"; |
156 | else | |
157 | disp = "[New file]"; | |
07b0d286 | 158 | if ((obuf = Fopen(file, "a")) == NULL) { |
a13d1f28 KS |
159 | perror(NOSTR); |
160 | return(1); | |
161 | } | |
a13d1f28 | 162 | for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { |
470c33f3 EW |
163 | mp = &message[*ip - 1]; |
164 | touch(mp); | |
2de8fc95 | 165 | if (send(mp, obuf, ignore, NOSTR) < 0) { |
a13d1f28 | 166 | perror(file); |
07b0d286 | 167 | Fclose(obuf); |
a13d1f28 KS |
168 | return(1); |
169 | } | |
c7db23a4 KS |
170 | if (mark) |
171 | mp->m_flag |= MSAVED; | |
a13d1f28 KS |
172 | } |
173 | fflush(obuf); | |
174 | if (ferror(obuf)) | |
175 | perror(file); | |
07b0d286 | 176 | Fclose(obuf); |
2de8fc95 | 177 | printf("%s\n", disp); |
a13d1f28 KS |
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 | { | |
a13d1f28 | 189 | |
2de8fc95 | 190 | return save1(str, 1, "write", ignoreall); |
a13d1f28 KS |
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 | ||
828615a1 | 216 | while (cp > linebuf && isspace(*cp)) |
a13d1f28 KS |
217 | cp--; |
218 | *++cp = 0; | |
219 | ||
220 | /* | |
221 | * Now search for the beginning of the file name. | |
222 | */ | |
223 | ||
828615a1 | 224 | while (cp > linebuf && !isspace(*cp)) |
a13d1f28 KS |
225 | cp--; |
226 | if (*cp == '\0') { | |
227 | printf("No file specified.\n"); | |
228 | return(NOSTR); | |
229 | } | |
828615a1 | 230 | if (isspace(*cp)) |
a13d1f28 KS |
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 | { | |
2ee3bce2 EW |
244 | delm(msgvec); |
245 | return 0; | |
a13d1f28 KS |
246 | } |
247 | ||
248 | /* | |
249 | * Delete messages, then type the new dot. | |
250 | */ | |
251 | ||
252 | deltype(msgvec) | |
253 | int msgvec[]; | |
254 | { | |
255 | int list[2]; | |
12c002da | 256 | int lastdot; |
a13d1f28 | 257 | |
12c002da | 258 | lastdot = dot - &message[0] + 1; |
a13d1f28 | 259 | if (delm(msgvec) >= 0) { |
470c33f3 | 260 | list[0] = dot - &message[0] + 1; |
12c002da | 261 | if (list[0] > lastdot) { |
470c33f3 | 262 | touch(dot); |
12c002da KS |
263 | list[1] = NULL; |
264 | return(type(list)); | |
265 | } | |
266 | printf("At EOF\n"); | |
2ee3bce2 | 267 | } else |
a13d1f28 | 268 | printf("No more messages\n"); |
2ee3bce2 | 269 | return(0); |
a13d1f28 KS |
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; | |
470c33f3 | 282 | register *ip; |
a13d1f28 KS |
283 | int last; |
284 | ||
285 | last = NULL; | |
286 | for (ip = msgvec; *ip != NULL; ip++) { | |
470c33f3 EW |
287 | mp = &message[*ip - 1]; |
288 | touch(mp); | |
3c139aaf KS |
289 | mp->m_flag |= MDELETED|MTOUCH; |
290 | mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX); | |
470c33f3 | 291 | last = *ip; |
a13d1f28 KS |
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; | |
470c33f3 EW |
321 | register *ip; |
322 | ||
323 | for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { | |
324 | mp = &message[*ip - 1]; | |
325 | touch(mp); | |
a13d1f28 KS |
326 | dot = mp; |
327 | mp->m_flag &= ~MDELETED; | |
328 | } | |
0b2e8a24 | 329 | return 0; |
a13d1f28 KS |
330 | } |
331 | ||
332 | /* | |
333 | * Interactively dump core on "core" | |
334 | */ | |
335 | ||
336 | core() | |
337 | { | |
322c8626 EW |
338 | int pid; |
339 | extern union wait wait_status; | |
a13d1f28 | 340 | |
322c8626 EW |
341 | switch (pid = vfork()) { |
342 | case -1: | |
a13d1f28 KS |
343 | perror("fork"); |
344 | return(1); | |
322c8626 | 345 | case 0: |
a13d1f28 KS |
346 | abort(); |
347 | _exit(1); | |
348 | } | |
349 | printf("Okie dokie"); | |
350 | fflush(stdout); | |
322c8626 EW |
351 | wait_child(pid); |
352 | if (wait_status.w_coredump) | |
353 | printf(" -- Core dumped.\n"); | |
a13d1f28 | 354 | else |
322c8626 | 355 | printf(" -- Can't dump core.\n"); |
828615a1 | 356 | return 0; |
a13d1f28 | 357 | } |
47e37b8b KS |
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; | |
ab61fde0 | 371 | clob1(times); |
0b2e8a24 | 372 | return 0; |
47e37b8b KS |
373 | } |
374 | ||
375 | /* | |
376 | * Clobber the stack. | |
377 | */ | |
ab61fde0 | 378 | clob1(n) |
47e37b8b KS |
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 | ; | |
ab61fde0 | 387 | clob1(n - 1); |
47e37b8b | 388 | } |
eed74ec1 | 389 | |
46053c99 S |
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 | { | |
46053c99 | 397 | |
887efe38 | 398 | return ignore1(list, ignore + 1, "retained"); |
46053c99 S |
399 | } |
400 | ||
401 | /* | |
887efe38 EW |
402 | * Add the given header fields to the ignored list. |
403 | * If no arguments, print the current list of ignored fields. | |
46053c99 | 404 | */ |
887efe38 EW |
405 | igfield(list) |
406 | char *list[]; | |
46053c99 | 407 | { |
46053c99 | 408 | |
887efe38 | 409 | return ignore1(list, ignore, "ignored"); |
46053c99 S |
410 | } |
411 | ||
887efe38 EW |
412 | saveretfield(list) |
413 | char *list[]; | |
414 | { | |
415 | ||
416 | return ignore1(list, saveignore + 1, "retained"); | |
417 | } | |
418 | ||
419 | saveigfield(list) | |
eed74ec1 KS |
420 | char *list[]; |
421 | { | |
887efe38 EW |
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 | { | |
eed74ec1 KS |
431 | char field[BUFSIZ]; |
432 | register int h; | |
433 | register struct ignore *igp; | |
434 | char **ap; | |
435 | ||
470c33f3 | 436 | if (*list == NOSTR) |
887efe38 | 437 | return igshow(tab, which); |
eed74ec1 KS |
438 | for (ap = list; *ap != 0; ap++) { |
439 | istrcpy(field, *ap); | |
887efe38 EW |
440 | if (member(field, tab)) |
441 | continue; | |
eed74ec1 KS |
442 | h = hash(field); |
443 | igp = (struct ignore *) calloc(1, sizeof (struct ignore)); | |
828615a1 EW |
444 | igp->i_field = calloc((unsigned) strlen(field) + 1, |
445 | sizeof (char)); | |
eed74ec1 | 446 | strcpy(igp->i_field, field); |
887efe38 EW |
447 | igp->i_link = tab->i_head[h]; |
448 | tab->i_head[h] = igp; | |
449 | tab->i_count++; | |
eed74ec1 | 450 | } |
887efe38 | 451 | return 0; |
eed74ec1 KS |
452 | } |
453 | ||
454 | /* | |
887efe38 | 455 | * Print out all currently retained fields. |
eed74ec1 | 456 | */ |
887efe38 EW |
457 | igshow(tab, which) |
458 | struct ignoretab *tab; | |
459 | char *which; | |
eed74ec1 | 460 | { |
887efe38 | 461 | register int h; |
eed74ec1 | 462 | struct ignore *igp; |
93be40ac KS |
463 | char **ap, **ring; |
464 | int igcomp(); | |
eed74ec1 | 465 | |
887efe38 EW |
466 | if (tab->i_count == 0) { |
467 | printf("No fields currently being %s.\n", which); | |
468 | return 0; | |
93be40ac | 469 | } |
887efe38 | 470 | ring = (char **) salloc((tab->i_count + 1) * sizeof (char *)); |
93be40ac KS |
471 | ap = ring; |
472 | for (h = 0; h < HSHSIZE; h++) | |
887efe38 | 473 | for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link) |
93be40ac KS |
474 | *ap++ = igp->i_field; |
475 | *ap = 0; | |
887efe38 | 476 | qsort((char *) ring, tab->i_count, sizeof (char *), igcomp); |
93be40ac KS |
477 | for (ap = ring; *ap != 0; ap++) |
478 | printf("%s\n", *ap); | |
887efe38 | 479 | return 0; |
eed74ec1 | 480 | } |
93be40ac KS |
481 | |
482 | /* | |
483 | * Compare two names for sorting ignored field list. | |
484 | */ | |
485 | igcomp(l, r) | |
486 | char **l, **r; | |
487 | { | |
488 | ||
887efe38 | 489 | return strcmp(*l, *r); |
93be40ac | 490 | } |