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