|
|
1.1 root 1: #ifndef lint
2: static char *sccsid = "@(#)cmd2.c 2.11 (Berkeley) 8/11/83";
3: #endif
4:
5: #include "rcv.h"
6: #include <sys/stat.h>
7:
8: /*
9: * Mail -- a mail program
10: *
11: * More user commands.
12: */
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: extern int brokpipe();
99: extern jmp_buf pipestop;
100: save(str)
101: char str[];
102: {
103:
104: return(save1(str, 1));
105: }
106:
107: /*
108: * Copy a message to a file without affected its saved-ness
109: */
110: copycmd(str)
111: char str[];
112: {
113:
114: return(save1(str, 0));
115: }
116:
117: /*
118: * Save/copy the indicated messages at the end of the passed file name.
119: * If mark is true, mark the message "saved."
120: */
121: #define PIPE2CMD 2 /* pipe to command instead of file */
122: save1(str, mark)
123: char str[];
124: {
125: register int *ip, mesg;
126: register struct message *mp;
127: char *file, *disp, *cmd;
128: int f, *msgvec, lc, t;
129: long cc;
130: FILE *obuf;
131: struct stat statb;
132: int is_pipe;
133:
134: cmd = mark ? "save" : "copy";
135: msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
136: if ((file = snarf(str, &f)) == NOSTR)
137: return(1);
138: if (is_pipe = f & PIPE2CMD)
139: f &= ~PIPE2CMD;
140: if (!f) {
141: *msgvec = first(0, MMNORM);
142: if (*msgvec == NULL) {
143: printf("No messages to %s.\n", cmd);
144: return(1);
145: }
146: msgvec[1] = NULL;
147: }
148: if (f && getmsglist(str, msgvec, 0) < 0)
149: return(1);
150: if (!is_pipe) {
151: if ((file = expand(file)) == NOSTR)
152: return(1);
153: printf("\"%s\" ", file);
154: flush();
155: if (stat(file, &statb) >= 0)
156: disp = "[Appended]";
157: else
158: disp = "[New file]";
159: if ((obuf = fopen(file, "a")) == NULL) {
160: perror(NOSTR);
161: return(1);
162: }
163: } else {
164: if (setjmp(pipestop)) {
165: pclose(obuf);
166: sigset(SIGPIPE, SIG_DFL);
167: printf("[broken pipe]\n");
168: return(1);
169: }
170: printf("%s ", file);
171: flush();
172: disp = "[completed]";
173: if ((obuf = popen(file, "w")) == NULL) {
174: perror(NOSTR);
175: return(1);
176: }
177: sigset(SIGPIPE, brokpipe);
178: }
179: cc = 0L;
180: lc = 0;
181: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
182: mesg = *ip;
183: touch(mesg);
184: mp = &message[mesg-1];
185: if ((t = send(mp, obuf, 0)) < 0) {
186: perror(file);
187: if (is_pipe) {
188: pclose(obuf);
189: sigset(SIGPIPE, SIG_DFL);
190: } else {
191: fclose(obuf);
192: }
193: return(1);
194: }
195: lc += t;
196: cc += mp->m_size;
197: if (mark)
198: mp->m_flag |= MSAVED;
199: }
200: fflush(obuf);
201: if (ferror(obuf))
202: perror(file);
203: if (is_pipe) {
204: pclose(obuf);
205: sigset(SIGPIPE, SIG_DFL);
206: } else {
207: fclose(obuf);
208: }
209: printf("%s %d/%ld\n", disp, lc, cc);
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:
218: swrite(str)
219: char str[];
220: {
221: register int *ip, mesg;
222: register struct message *mp;
223: register char *file, *disp;
224: char linebuf[BUFSIZ];
225: int f, *msgvec, lc, cc, t;
226: FILE *obuf, *mesf;
227: struct stat statb;
228: int is_pipe;
229:
230: msgvec = (int *) salloc((msgCount + 2) * sizeof *msgvec);
231: if ((file = snarf(str, &f)) == NOSTR)
232: return(1);
233: if (is_pipe = f & PIPE2CMD)
234: f &= ~PIPE2CMD;
235: if (!f) {
236: *msgvec = first(0, MMNORM);
237: if (*msgvec == NULL) {
238: printf("No messages to write.\n");
239: return(1);
240: }
241: msgvec[1] = NULL;
242: }
243: if (f && getmsglist(str, msgvec, 0) < 0)
244: return(1);
245: if (!is_pipe) {
246: if ((file = expand(file)) == NOSTR)
247: return(1);
248: printf("\"%s\" ", file);
249: flush();
250: if (stat(file, &statb) >= 0)
251: disp = "[Appended]";
252: else
253: disp = "[New file]";
254: if ((obuf = fopen(file, "a")) == NULL) {
255: perror(NOSTR);
256: return(1);
257: }
258: } else {
259: if (setjmp(pipestop)) {
260: pclose(obuf);
261: sigset(SIGPIPE, SIG_DFL);
262: printf("[broken pipe]\n");
263: return(1);
264: }
265: printf("%s ", file);
266: flush();
267: disp = "[completed]";
268: if ((obuf = popen(file, "w")) == NULL) {
269: perror(NOSTR);
270: return(1);
271: }
272: sigset(SIGPIPE, brokpipe);
273: }
274: cc = lc = 0;
275: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
276: mesg = *ip;
277: touch(mesg);
278: mp = &message[mesg-1];
279: mesf = setinput(mp);
280: t = mp->m_lines - 2;
281: readline(mesf, linebuf);
282: while (t-- > 0) {
283: fgets(linebuf, BUFSIZ, mesf);
284: fputs(linebuf, obuf);
285: cc += strlen(linebuf);
286: }
287: lc += mp->m_lines - 2;
288: mp->m_flag |= MSAVED;
289: }
290: fflush(obuf);
291: if (ferror(obuf))
292: perror(file);
293: if (is_pipe) {
294: pclose(obuf);
295: sigset(SIGPIPE, SIG_DFL);
296: } else {
297: fclose(obuf);
298: }
299: printf("%s %d/%d\n", disp, lc, cc);
300: return(0);
301: }
302:
303: /*
304: * Snarf the file from the end of the command line and
305: * return a pointer to it. If there is no file attached,
306: * just return NOSTR. Put a null in front of the file
307: * name so that the message list processing won't see it,
308: * unless the file name is the only thing on the line, in
309: * which case, return 0 in the reference flag variable.
310: */
311:
312: char *
313: snarf(linebuf, flag)
314: char linebuf[];
315: int *flag;
316: {
317: register char *cp;
318: char *is_pipe = NULL;
319:
320: *flag = 1;
321: for (cp = linebuf; *cp; cp++) {
322: if (*cp == '|') {
323: is_pipe = cp;
324: break;
325: }
326: }
327: cp = strlen(linebuf) + linebuf - 1;
328:
329: /*
330: * Strip away trailing blanks.
331: */
332:
333: while (*cp == ' ' && cp > linebuf)
334: cp--;
335: *++cp = 0;
336:
337: if (is_pipe) {
338: if (is_pipe == linebuf)
339: *flag = PIPE2CMD | 0;
340: else
341: *flag = PIPE2CMD | 1;
342: *is_pipe = 0;
343: cp = is_pipe;
344: while(any(*++cp, " \t"))
345: ;
346: } else {
347: /*
348: * Now search for the beginning of the file name.
349: */
350:
351: while (cp > linebuf && !any(*cp, "\t "))
352: cp--;
353: if (*cp == '\0') {
354: printf("No file specified.\n");
355: return(NOSTR);
356: }
357: if (any(*cp, " \t"))
358: *cp++ = 0;
359: else
360: *flag = 0;
361: }
362: return(cp);
363: }
364:
365: /*
366: * Delete messages.
367: */
368:
369: delete(msgvec)
370: int msgvec[];
371: {
372: return(delm(msgvec));
373: }
374:
375: /*
376: * Delete messages, then type the new dot.
377: */
378:
379: deltype(msgvec)
380: int msgvec[];
381: {
382: int list[2];
383: int lastdot;
384:
385: lastdot = dot - &message[0] + 1;
386: if (delm(msgvec) >= 0) {
387: list[0] = dot - &message[0];
388: list[0]++;
389: if (list[0] > lastdot) {
390: touch(list[0]);
391: list[1] = NULL;
392: return(type(list));
393: }
394: printf("At EOF\n");
395: return(0);
396: }
397: else {
398: printf("No more messages\n");
399: return(0);
400: }
401: }
402:
403: /*
404: * Delete the indicated messages.
405: * Set dot to some nice place afterwards.
406: * Internal interface.
407: */
408:
409: delm(msgvec)
410: int *msgvec;
411: {
412: register struct message *mp;
413: register *ip, mesg;
414: int last;
415:
416: last = NULL;
417: for (ip = msgvec; *ip != NULL; ip++) {
418: mesg = *ip;
419: touch(mesg);
420: mp = &message[mesg-1];
421: mp->m_flag |= MDELETED|MTOUCH;
422: mp->m_flag &= ~(MPRESERVE|MSAVED|MBOX);
423: last = mesg;
424: }
425: if (last != NULL) {
426: dot = &message[last-1];
427: last = first(0, MDELETED);
428: if (last != NULL) {
429: dot = &message[last-1];
430: return(0);
431: }
432: else {
433: dot = &message[0];
434: return(-1);
435: }
436: }
437:
438: /*
439: * Following can't happen -- it keeps lint happy
440: */
441:
442: return(-1);
443: }
444:
445: /*
446: * Undelete the indicated messages.
447: */
448:
449: undelete(msgvec)
450: int *msgvec;
451: {
452: register struct message *mp;
453: register *ip, mesg;
454:
455: for (ip = msgvec; ip-msgvec < msgCount; ip++) {
456: mesg = *ip;
457: if (mesg == 0)
458: return;
459: touch(mesg);
460: mp = &message[mesg-1];
461: dot = mp;
462: mp->m_flag &= ~MDELETED;
463: }
464: }
465:
466: /*
467: * Interactively dump core on "core"
468: */
469:
470: core()
471: {
472: register int pid;
473: int status;
474:
475: if ((pid = vfork()) == -1) {
476: perror("fork");
477: return(1);
478: }
479: if (pid == 0) {
480: sigchild();
481: abort();
482: _exit(1);
483: }
484: printf("Okie dokie");
485: fflush(stdout);
486: while (wait(&status) != pid)
487: ;
488: if (status & 0200)
489: printf(" -- Core dumped\n");
490: else
491: printf("\n");
492: }
493:
494: /*
495: * Add the given header fields to the ignored list.
496: * If no arguments, print the current list of ignored fields.
497: */
498: igfield(list)
499: char *list[];
500: {
501: char field[BUFSIZ];
502: register int h;
503: register struct ignore *igp;
504: char **ap;
505:
506: if (argcount(list) == 0)
507: return(igshow());
508: for (ap = list; *ap != 0; ap++) {
509: if (isign(*ap))
510: continue;
511: istrcpy(field, *ap);
512: h = hash(field);
513: igp = (struct ignore *) calloc(1, sizeof (struct ignore));
514: igp->i_field = calloc(strlen(field) + 1, sizeof (char));
515: strcpy(igp->i_field, field);
516: igp->i_link = ignore[h];
517: ignore[h] = igp;
518: }
519: return(0);
520: }
521:
522: /*
523: * Print out all currently ignored fields.
524: */
525: igshow()
526: {
527: register int h, count;
528: struct ignore *igp;
529: char **ap, **ring;
530: int igcomp();
531:
532: count = 0;
533: for (h = 0; h < HSHSIZE; h++)
534: for (igp = ignore[h]; igp != 0; igp = igp->i_link)
535: count++;
536: if (count == 0) {
537: printf("No fields currently being ignored.\n");
538: return(0);
539: }
540: ring = (char **) salloc((count + 1) * sizeof (char *));
541: ap = ring;
542: for (h = 0; h < HSHSIZE; h++)
543: for (igp = ignore[h]; igp != 0; igp = igp->i_link)
544: *ap++ = igp->i_field;
545: *ap = 0;
546: qsort(ring, count, sizeof (char *), igcomp);
547: for (ap = ring; *ap != 0; ap++)
548: printf("%s\n", *ap);
549: return(0);
550: }
551:
552: /*
553: * Compare two names for sorting ignored field list.
554: */
555: igcomp(l, r)
556: char **l, **r;
557: {
558:
559: return(strcmp(*l, *r));
560: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.