changed send() to take doignore argument and ignore header fields
[unix-history] / usr / src / usr.bin / mail / cmd2.c
CommitLineData
a13d1f28
KS
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
eed74ec1 12static char *SccsId = "@(#)cmd2.c 2.7 %G%";
a13d1f28
KS
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
20next(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;
30629819
KS
36
37 /*
38 * Find the first message in the supplied
39 * message list which follows dot.
40 */
41
a13d1f28
KS
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 {
a13d1f28
KS
49 mp = &message[*ip2 - 1];
50 if ((mp->m_flag & MDELETED) == 0) {
51 dot = mp;
52 goto hitit;
53 }
30629819
KS
54 if (*ip2 != NULL)
55 ip2++;
56 if (*ip2 == NULL)
57 ip2 = msgvec;
a13d1f28
KS
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
799afc8f 68 if (!sawcom)
a13d1f28 69 goto hitit;
a13d1f28
KS
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;
84hitit:
85 /*
86 * Print dot.
87 */
88
89 list[0] = dot - &message[0] + 1;
90 list[1] = NULL;
91 return(type(list));
92}
93
94/*
c7db23a4
KS
95 * Save a message in a file. Mark the message as saved
96 * so we can discard when the user quits.
a13d1f28 97 */
a13d1f28
KS
98save(str)
99 char str[];
100{
c7db23a4
KS
101
102 return(save1(str, 1));
103}
104
105/*
106 * Copy a message to a file without affected its saved-ness
107 */
108copycmd(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 */
119save1(str, mark)
120 char str[];
121{
a13d1f28
KS
122 register int *ip, mesg;
123 register struct message *mp;
c7db23a4 124 char *file, *disp, *cmd;
a13d1f28
KS
125 int f, *msgvec, lc, cc, t;
126 FILE *obuf;
127 struct stat statb;
128
c7db23a4 129 cmd = mark ? "save" : "copy";
a13d1f28
KS
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) {
c7db23a4 136 printf("No messages to %s.\n", cmd);
a13d1f28
KS
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];
eed74ec1 160 if ((t = send(mp, obuf, 0)) < 0) {
a13d1f28
KS
161 perror(file);
162 fclose(obuf);
163 return(1);
164 }
165 lc += t;
166 cc += msize(mp);
c7db23a4
KS
167 if (mark)
168 mp->m_flag |= MSAVED;
a13d1f28
KS
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
183swrite(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
252char *
253snarf(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
291delete(msgvec)
292 int msgvec[];
293{
294 return(delm(msgvec));
295}
296
297/*
298 * Delete messages, then type the new dot.
299 */
300
301deltype(msgvec)
302 int msgvec[];
303{
304 int list[2];
12c002da 305 int lastdot;
a13d1f28 306
12c002da 307 lastdot = dot - &message[0] + 1;
a13d1f28
KS
308 if (delm(msgvec) >= 0) {
309 list[0] = dot - &message[0];
310 list[0]++;
12c002da
KS
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);
a13d1f28
KS
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
331delm(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];
3c139aaf
KS
343 mp->m_flag |= MDELETED|MTOUCH;
344 mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
a13d1f28
KS
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
371undelete(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
392core()
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) {
64df7743 402 sigchild();
a13d1f28
KS
403 abort();
404 _exit(1);
405 }
406 printf("Okie dokie");
407 fflush(stdout);
408 while (wait(&status) != pid)
409 ;
410 if (status & 0200)
411 printf(" -- Core dumped\n");
412 else
413 printf("\n");
414}
47e37b8b
KS
415
416/*
417 * Clobber as many bytes of stack as the user requests.
418 */
419clobber(argv)
420 char **argv;
421{
422 register int times;
423
424 if (argv[0] == 0)
425 times = 1;
426 else
427 times = (atoi(argv[0]) + 511) / 512;
ab61fde0 428 clob1(times);
47e37b8b
KS
429}
430
431/*
432 * Clobber the stack.
433 */
ab61fde0 434clob1(n)
47e37b8b
KS
435{
436 char buf[512];
437 register char *cp;
438
439 if (n <= 0)
440 return;
441 for (cp = buf; cp < &buf[512]; *cp++ = 0xFF)
442 ;
ab61fde0 443 clob1(n - 1);
47e37b8b 444}
eed74ec1
KS
445
446/*
447 * Add the given header fields to the ignored list.
448 * If no arguments, print the current list of ignored fields.
449 */
450igfield(list)
451 char *list[];
452{
453 char field[BUFSIZ];
454 register int h;
455 register struct ignore *igp;
456 char **ap;
457
458 if (argcount(list) == 0)
459 return(igshow());
460 for (ap = list; *ap != 0; ap++) {
461 istrcpy(field, *ap);
462 h = hash(field);
463 igp = (struct ignore *) calloc(1, sizeof (struct ignore));
464 igp->i_field = calloc(strlen(field) + 1, sizeof (char));
465 strcpy(igp->i_field, field);
466 igp->i_link = ignore[h];
467 ignore[h] = igp;
468 }
469 return(0);
470}
471
472/*
473 * Print out all currently ignored fields.
474 */
475igshow()
476{
477 register int h, did;
478 struct ignore *igp;
479
480 did = 0;
481 for (h = 0; h < HSHSIZE; h++)
482 for (igp = ignore[h]; igp != 0; igp = igp->i_link) {
483 printf("%s\n", igp->i_field);
484 did++;
485 }
486 if (!did)
487 printf("No fields currently being ignored.\n");
488 return(0);
489}