cmd2.c revision 1.3 1 /*
2 * Copyright (c) 1980, 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34 #ifndef lint
35 static char sccsid[] = "from: @(#)cmd2.c 8.1 (Berkeley) 6/6/93";
36 static char rcsid[] = "$Id: cmd2.c,v 1.3 1994/06/29 05:09:09 deraadt Exp $";
37 #endif /* not lint */
38
39 #include "rcv.h"
40 #include <sys/wait.h>
41 #include "extern.h"
42
43 /*
44 * Mail -- a mail program
45 *
46 * More user commands.
47 */
48
49 /*
50 * If any arguments were given, go to the next applicable argument
51 * following dot, otherwise, go to the next applicable message.
52 * If given as first command with no arguments, print first message.
53 */
54 int
55 next(msgvec)
56 int *msgvec;
57 {
58 register struct message *mp;
59 register int *ip, *ip2;
60 int list[2], mdot;
61
62 if (*msgvec != NULL) {
63
64 /*
65 * If some messages were supplied, find the
66 * first applicable one following dot using
67 * wrap around.
68 */
69
70 mdot = dot - &message[0] + 1;
71
72 /*
73 * Find the first message in the supplied
74 * message list which follows dot.
75 */
76
77 for (ip = msgvec; *ip != NULL; ip++)
78 if (*ip > mdot)
79 break;
80 if (*ip == NULL)
81 ip = msgvec;
82 ip2 = ip;
83 do {
84 mp = &message[*ip2 - 1];
85 if ((mp->m_flag & MDELETED) == 0) {
86 dot = mp;
87 goto hitit;
88 }
89 if (*ip2 != NULL)
90 ip2++;
91 if (*ip2 == NULL)
92 ip2 = msgvec;
93 } while (ip2 != ip);
94 printf("No messages applicable\n");
95 return(1);
96 }
97
98 /*
99 * If this is the first command, select message 1.
100 * Note that this must exist for us to get here at all.
101 */
102
103 if (!sawcom)
104 goto hitit;
105
106 /*
107 * Just find the next good message after dot, no
108 * wraparound.
109 */
110
111 for (mp = dot+1; mp < &message[msgCount]; mp++)
112 if ((mp->m_flag & (MDELETED|MSAVED)) == 0)
113 break;
114 if (mp >= &message[msgCount]) {
115 printf("At EOF\n");
116 return(0);
117 }
118 dot = mp;
119 hitit:
120 /*
121 * Print dot.
122 */
123
124 list[0] = dot - &message[0] + 1;
125 list[1] = NULL;
126 return(type(list));
127 }
128
129 /*
130 * Save a message in a file. Mark the message as saved
131 * so we can discard when the user quits.
132 */
133 int
134 save(str)
135 char str[];
136 {
137
138 return save1(str, 1, "save", saveignore);
139 }
140
141 /*
142 * Copy a message to a file without affected its saved-ness
143 */
144 int
145 copycmd(str)
146 char str[];
147 {
148
149 return save1(str, 0, "copy", saveignore);
150 }
151
152 /*
153 * Save/copy the indicated messages at the end of the passed file name.
154 * If mark is true, mark the message "saved."
155 */
156 int
157 save1(str, mark, cmd, ignore)
158 char str[];
159 int mark;
160 char *cmd;
161 struct ignoretab *ignore;
162 {
163 register int *ip;
164 register struct message *mp;
165 char *file, *disp;
166 int f, *msgvec;
167 FILE *obuf;
168
169 msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
170 if ((file = snarf(str, &f)) == NOSTR)
171 return(1);
172 if (!f) {
173 *msgvec = first(0, MMNORM);
174 if (*msgvec == NULL) {
175 printf("No messages to %s.\n", cmd);
176 return(1);
177 }
178 msgvec[1] = NULL;
179 }
180 if (f && getmsglist(str, msgvec, 0) < 0)
181 return(1);
182 if ((file = expand(file)) == NOSTR)
183 return(1);
184 printf("\"%s\" ", file);
185 fflush(stdout);
186 if (access(file, 0) >= 0)
187 disp = "[Appended]";
188 else
189 disp = "[New file]";
190 if ((obuf = Fopen(file, "a")) == NULL) {
191 perror(NOSTR);
192 return(1);
193 }
194 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
195 mp = &message[*ip - 1];
196 touch(mp);
197 if (send(mp, obuf, ignore, NOSTR) < 0) {
198 perror(file);
199 Fclose(obuf);
200 return(1);
201 }
202 if (mark)
203 mp->m_flag |= MSAVED;
204 }
205 fflush(obuf);
206 if (ferror(obuf))
207 perror(file);
208 Fclose(obuf);
209 printf("%s\n", disp);
210 return(0);
211 }
212
213 /*
214 * Write the indicated messages at the end of the passed
215 * file name, minus header and trailing blank line.
216 */
217 int
218 swrite(str)
219 char str[];
220 {
221
222 return save1(str, 1, "write", ignoreall);
223 }
224
225 /*
226 * Snarf the file from the end of the command line and
227 * return a pointer to it. If there is no file attached,
228 * just return NOSTR. Put a null in front of the file
229 * name so that the message list processing won't see it,
230 * unless the file name is the only thing on the line, in
231 * which case, return 0 in the reference flag variable.
232 */
233
234 char *
235 snarf(linebuf, flag)
236 char linebuf[];
237 int *flag;
238 {
239 register char *cp;
240
241 *flag = 1;
242 cp = strlen(linebuf) + linebuf - 1;
243
244 /*
245 * Strip away trailing blanks.
246 */
247
248 while (cp > linebuf && isspace(*cp))
249 cp--;
250 *++cp = 0;
251
252 /*
253 * Now search for the beginning of the file name.
254 */
255
256 while (cp > linebuf && !isspace(*cp))
257 cp--;
258 if (*cp == '\0') {
259 printf("No file specified.\n");
260 return(NOSTR);
261 }
262 if (isspace(*cp))
263 *cp++ = 0;
264 else
265 *flag = 0;
266 return(cp);
267 }
268
269 /*
270 * Delete messages.
271 */
272 int
273 delete(msgvec)
274 int msgvec[];
275 {
276 delm(msgvec);
277 return 0;
278 }
279
280 /*
281 * Delete messages, then type the new dot.
282 */
283 int
284 deltype(msgvec)
285 int msgvec[];
286 {
287 int list[2];
288 int lastdot;
289
290 lastdot = dot - &message[0] + 1;
291 if (delm(msgvec) >= 0) {
292 list[0] = dot - &message[0] + 1;
293 if (list[0] > lastdot) {
294 touch(dot);
295 list[1] = NULL;
296 return(type(list));
297 }
298 printf("At EOF\n");
299 } else
300 printf("No more messages\n");
301 return(0);
302 }
303
304 /*
305 * Delete the indicated messages.
306 * Set dot to some nice place afterwards.
307 * Internal interface.
308 */
309 int
310 delm(msgvec)
311 int *msgvec;
312 {
313 register struct message *mp;
314 register *ip;
315 int last;
316
317 last = NULL;
318 for (ip = msgvec; *ip != NULL; ip++) {
319 mp = &message[*ip - 1];
320 touch(mp);
321 mp->m_flag |= MDELETED|MTOUCH;
322 mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
323 last = *ip;
324 }
325 if (last != NULL) {
326 dot = &message[last-1];
327 last = first(0, MDELETED);
328 if (last != NULL) {
329 dot = &message[last-1];
330 return(0);
331 }
332 else {
333 dot = &message[0];
334 return(-1);
335 }
336 }
337
338 /*
339 * Following can't happen -- it keeps lint happy
340 */
341
342 return(-1);
343 }
344
345 /*
346 * Undelete the indicated messages.
347 */
348 int
349 undelete(msgvec)
350 int *msgvec;
351 {
352 register struct message *mp;
353 register *ip;
354
355 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
356 mp = &message[*ip - 1];
357 touch(mp);
358 dot = mp;
359 mp->m_flag &= ~MDELETED;
360 }
361 return 0;
362 }
363
364 /*
365 * Interactively dump core on "core"
366 */
367 int
368 core()
369 {
370 int pid;
371 extern union wait wait_status;
372
373 switch (pid = vfork()) {
374 case -1:
375 perror("fork");
376 return(1);
377 case 0:
378 abort();
379 _exit(1);
380 }
381 printf("Okie dokie");
382 fflush(stdout);
383 wait_child(pid);
384 if (wait_status.w_coredump)
385 printf(" -- Core dumped.\n");
386 else
387 printf(" -- Can't dump core.\n");
388 return 0;
389 }
390
391 /*
392 * Clobber as many bytes of stack as the user requests.
393 */
394 int
395 clobber(argv)
396 char **argv;
397 {
398 register int times;
399
400 if (argv[0] == 0)
401 times = 1;
402 else
403 times = (atoi(argv[0]) + 511) / 512;
404 clob1(times);
405 return 0;
406 }
407
408 /*
409 * Clobber the stack.
410 */
411 void
412 clob1(n)
413 int n;
414 {
415 char buf[512];
416 register char *cp;
417
418 if (n <= 0)
419 return;
420 for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
421 ;
422 clob1(n - 1);
423 }
424
425 /*
426 * Add the given header fields to the retained list.
427 * If no arguments, print the current list of retained fields.
428 */
429 int
430 retfield(list)
431 char *list[];
432 {
433
434 return ignore1(list, ignore + 1, "retained");
435 }
436
437 /*
438 * Add the given header fields to the ignored list.
439 * If no arguments, print the current list of ignored fields.
440 */
441 int
442 igfield(list)
443 char *list[];
444 {
445
446 return ignore1(list, ignore, "ignored");
447 }
448
449 int
450 saveretfield(list)
451 char *list[];
452 {
453
454 return ignore1(list, saveignore + 1, "retained");
455 }
456
457 int
458 saveigfield(list)
459 char *list[];
460 {
461
462 return ignore1(list, saveignore, "ignored");
463 }
464
465 int
466 ignore1(list, tab, which)
467 char *list[];
468 struct ignoretab *tab;
469 char *which;
470 {
471 char field[BUFSIZ];
472 register int h;
473 register struct ignore *igp;
474 char **ap;
475
476 if (*list == NOSTR)
477 return igshow(tab, which);
478 for (ap = list; *ap != 0; ap++) {
479 istrcpy(field, *ap);
480 if (member(field, tab))
481 continue;
482 h = hash(field);
483 igp = (struct ignore *) calloc(1, sizeof (struct ignore));
484 igp->i_field = calloc((unsigned) strlen(field) + 1,
485 sizeof (char));
486 strcpy(igp->i_field, field);
487 igp->i_link = tab->i_head[h];
488 tab->i_head[h] = igp;
489 tab->i_count++;
490 }
491 return 0;
492 }
493
494 /*
495 * Print out all currently retained fields.
496 */
497 int
498 igshow(tab, which)
499 struct ignoretab *tab;
500 char *which;
501 {
502 register int h;
503 struct ignore *igp;
504 char **ap, **ring;
505 int igcomp();
506
507 if (tab->i_count == 0) {
508 printf("No fields currently being %s.\n", which);
509 return 0;
510 }
511 ring = (char **) salloc((tab->i_count + 1) * sizeof (char *));
512 ap = ring;
513 for (h = 0; h < HSHSIZE; h++)
514 for (igp = tab->i_head[h]; igp != 0; igp = igp->i_link)
515 *ap++ = igp->i_field;
516 *ap = 0;
517 qsort(ring, tab->i_count, sizeof (char *), igcomp);
518 for (ap = ring; *ap != 0; ap++)
519 printf("%s\n", *ap);
520 return 0;
521 }
522
523 /*
524 * Compare two names for sorting ignored field list.
525 */
526 int
527 igcomp(l, r)
528 const void *l, *r;
529 {
530 return (strcmp(*(char **)l, *(char **)r));
531 }
532