1: /*
2: * Copyright (c) 1980 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: static char *sccsid = "@(#)cmd1.c 5.3 (Berkeley) 9/15/85";
9: #endif not lint
10:
11: #include "rcv.h"
12: #include <sys/stat.h>
13:
14: /*
15: * Mail -- a mail program
16: *
17: * User commands.
18: */
19:
20: /*
21: * Print the current active headings.
22: * Don't change dot if invoker didn't give an argument.
23: */
24:
25: static int screen;
26:
27: (msgvec)
28: int *msgvec;
29: {
30: register int n, mesg, flag;
31: register struct message *mp;
32: int size;
33:
34: size = screensize();
35: n = msgvec[0];
36: if (n != 0)
37: screen = (n-1)/size;
38: if (screen < 0)
39: screen = 0;
40: mp = &message[screen * size];
41: if (mp >= &message[msgCount])
42: mp = &message[msgCount - size];
43: if (mp < &message[0])
44: mp = &message[0];
45: flag = 0;
46: mesg = mp - &message[0];
47: if (dot != &message[n-1])
48: dot = mp;
49: for (; mp < &message[msgCount]; mp++) {
50: mesg++;
51: if (mp->m_flag & MDELETED)
52: continue;
53: if (flag++ >= size)
54: break;
55: printhead(mesg);
56: sreset();
57: }
58: if (flag == 0) {
59: printf("No more mail.\n");
60: return(1);
61: }
62: return(0);
63: }
64:
65: /*
66: * Set the list of alternate names for out host.
67: */
68: local(namelist)
69: char **namelist;
70: {
71: register int c;
72: register char **ap, **ap2, *cp;
73:
74: c = argcount(namelist) + 1;
75: if (c == 1) {
76: if (localnames == 0)
77: return(0);
78: for (ap = localnames; *ap; ap++)
79: printf("%s ", *ap);
80: printf("\n");
81: return(0);
82: }
83: if (localnames != 0)
84: cfree((char *) localnames);
85: localnames = (char **) calloc(c, sizeof (char *));
86: for (ap = namelist, ap2 = localnames; *ap; ap++, ap2++) {
87: cp = (char *) calloc(strlen(*ap) + 1, sizeof (char));
88: strcpy(cp, *ap);
89: *ap2 = cp;
90: }
91: *ap2 = 0;
92: return(0);
93: }
94:
95: /*
96: * Scroll to the next/previous screen
97: */
98:
99: scroll(arg)
100: char arg[];
101: {
102: register int s, size;
103: int cur[1];
104:
105: cur[0] = 0;
106: size = screensize();
107: s = screen;
108: switch (*arg) {
109: case 0:
110: case '+':
111: s++;
112: if (s * size > msgCount) {
113: printf("On last screenful of messages\n");
114: return(0);
115: }
116: screen = s;
117: break;
118:
119: case '-':
120: if (--s < 0) {
121: printf("On first screenful of messages\n");
122: return(0);
123: }
124: screen = s;
125: break;
126:
127: default:
128: printf("Unrecognized scrolling command \"%s\"\n", arg);
129: return(1);
130: }
131: return(headers(cur));
132: }
133:
134: /*
135: * Compute what the screen size should be.
136: * We use the following algorithm:
137: * If user specifies with screen option, use that.
138: * If baud rate < 1200, use 5
139: * If baud rate = 1200, use 10
140: * If baud rate > 1200, use 20
141: */
142: screensize()
143: {
144: register char *cp;
145: register int s;
146: #ifdef TIOCGWINSZ
147: struct winsize ws;
148: #endif
149:
150: if ((cp = value("screen")) != NOSTR) {
151: s = atoi(cp);
152: if (s > 0)
153: return(s);
154: }
155: if (baud < B1200)
156: s = 5;
157: else if (baud == B1200)
158: s = 10;
159: #ifdef TIOCGWINSZ
160: else if (ioctl(fileno(stdout), TIOCGWINSZ, &ws) == 0 && ws.ws_row != 0)
161: s = ws.ws_row - 4;
162: #endif
163: else
164: s = 20;
165: return(s);
166: }
167:
168: /*
169: * Print out the headlines for each message
170: * in the passed message list.
171: */
172:
173: from(msgvec)
174: int *msgvec;
175: {
176: register int *ip;
177:
178: for (ip = msgvec; *ip != NULL; ip++) {
179: printhead(*ip);
180: sreset();
181: }
182: if (--ip >= msgvec)
183: dot = &message[*ip - 1];
184: return(0);
185: }
186:
187: /*
188: * Print out the header of a specific message.
189: * This is a slight improvement to the standard one.
190: */
191:
192: printhead(mesg)
193: {
194: struct message *mp;
195: FILE *ibuf;
196: char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
197: char pbuf[BUFSIZ];
198: int s;
199: struct headline hl;
200: register char *cp;
201:
202: mp = &message[mesg-1];
203: ibuf = setinput(mp);
204: readline(ibuf, headline);
205: subjline = hfield("subject", mp);
206: if (subjline == NOSTR)
207: subjline = hfield("subj", mp);
208:
209: /*
210: * Bletch!
211: */
212:
213: if (subjline != NOSTR && strlen(subjline) > 28)
214: subjline[29] = '\0';
215: curind = dot == mp ? '>' : ' ';
216: dispc = ' ';
217: if (mp->m_flag & MSAVED)
218: dispc = '*';
219: if (mp->m_flag & MPRESERVE)
220: dispc = 'P';
221: if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
222: dispc = 'N';
223: if ((mp->m_flag & (MREAD|MNEW)) == 0)
224: dispc = 'U';
225: if (mp->m_flag & MBOX)
226: dispc = 'M';
227: parse(headline, &hl, pbuf);
228: sprintf(wcount, " %d/%ld", mp->m_lines, mp->m_size);
229: s = strlen(wcount);
230: cp = wcount + s;
231: while (s < 7)
232: s++, *cp++ = ' ';
233: *cp = '\0';
234: if (subjline != NOSTR)
235: printf("%c%c%3d %-8s %16.16s %s \"%s\"\n", curind, dispc, mesg,
236: nameof(mp, 0), hl.l_date, wcount, subjline);
237: else
238: printf("%c%c%3d %-8s %16.16s %s\n", curind, dispc, mesg,
239: nameof(mp, 0), hl.l_date, wcount);
240: }
241:
242: /*
243: * Print out the value of dot.
244: */
245:
246: pdot()
247: {
248: printf("%d\n", dot - &message[0] + 1);
249: return(0);
250: }
251:
252: /*
253: * Print out all the possible commands.
254: */
255:
256: pcmdlist()
257: {
258: register struct cmd *cp;
259: register int cc;
260: extern struct cmd cmdtab[];
261:
262: printf("Commands are:\n");
263: for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
264: cc += strlen(cp->c_name) + 2;
265: if (cc > 72) {
266: printf("\n");
267: cc = strlen(cp->c_name) + 2;
268: }
269: if ((cp+1)->c_name != NOSTR)
270: printf("%s, ", cp->c_name);
271: else
272: printf("%s\n", cp->c_name);
273: }
274: return(0);
275: }
276:
277: /*
278: * Paginate messages, honor ignored fields.
279: */
280: more(msgvec)
281: int *msgvec;
282: {
283: return (type1(msgvec, 1, 1));
284: }
285:
286: /*
287: * Paginate messages, even printing ignored fields.
288: */
289: More(msgvec)
290: int *msgvec;
291: {
292:
293: return (type1(msgvec, 0, 1));
294: }
295:
296: /*
297: * Type out messages, honor ignored fields.
298: */
299: type(msgvec)
300: int *msgvec;
301: {
302:
303: return(type1(msgvec, 1, 0));
304: }
305:
306: /*
307: * Type out messages, even printing ignored fields.
308: */
309: Type(msgvec)
310: int *msgvec;
311: {
312:
313: return(type1(msgvec, 0, 0));
314: }
315:
316: /*
317: * Type out the messages requested.
318: */
319: jmp_buf pipestop;
320:
321: type1(msgvec, doign, page)
322: int *msgvec;
323: {
324: register *ip;
325: register struct message *mp;
326: register int mesg;
327: register char *cp;
328: int c, nlines;
329: int brokpipe();
330: FILE *ibuf, *obuf;
331:
332: obuf = stdout;
333: if (setjmp(pipestop)) {
334: if (obuf != stdout) {
335: pipef = NULL;
336: pclose(obuf);
337: }
338: sigset(SIGPIPE, SIG_DFL);
339: return(0);
340: }
341: if (intty && outtty && (page || (cp = value("crt")) != NOSTR)) {
342: nlines = 0;
343: if (!page) {
344: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
345: nlines += message[*ip - 1].m_lines;
346: }
347: if (page || nlines > atoi(cp)) {
348: cp = value("PAGER");
349: if (cp == NULL || *cp == '\0')
350: cp = MORE;
351: obuf = popen(cp, "w");
352: if (obuf == NULL) {
353: perror(cp);
354: obuf = stdout;
355: }
356: else {
357: pipef = obuf;
358: sigset(SIGPIPE, brokpipe);
359: }
360: }
361: }
362: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
363: mesg = *ip;
364: touch(mesg);
365: mp = &message[mesg-1];
366: dot = mp;
367: print(mp, obuf, doign);
368: }
369: if (obuf != stdout) {
370: pipef = NULL;
371: pclose(obuf);
372: }
373: sigset(SIGPIPE, SIG_DFL);
374: return(0);
375: }
376:
377: /*
378: * Respond to a broken pipe signal --
379: * probably caused by using quitting more.
380: */
381:
382: brokpipe()
383: {
384: # ifndef VMUNIX
385: signal(SIGPIPE, brokpipe);
386: # endif
387: longjmp(pipestop, 1);
388: }
389:
390: /*
391: * Print the indicated message on standard output.
392: */
393:
394: print(mp, obuf, doign)
395: register struct message *mp;
396: FILE *obuf;
397: {
398:
399: if (value("quiet") == NOSTR)
400: fprintf(obuf, "Message %2d:\n", mp - &message[0] + 1);
401: touch(mp - &message[0] + 1);
402: send(mp, obuf, doign);
403: }
404:
405: /*
406: * Print the top so many lines of each desired message.
407: * The number of lines is taken from the variable "toplines"
408: * and defaults to 5.
409: */
410:
411: top(msgvec)
412: int *msgvec;
413: {
414: register int *ip;
415: register struct message *mp;
416: register int mesg;
417: int c, topl, lines, lineb;
418: char *valtop, linebuf[LINESIZE];
419: FILE *ibuf;
420:
421: topl = 5;
422: valtop = value("toplines");
423: if (valtop != NOSTR) {
424: topl = atoi(valtop);
425: if (topl < 0 || topl > 10000)
426: topl = 5;
427: }
428: lineb = 1;
429: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
430: mesg = *ip;
431: touch(mesg);
432: mp = &message[mesg-1];
433: dot = mp;
434: if (value("quiet") == NOSTR)
435: printf("Message %2d:\n", mesg);
436: ibuf = setinput(mp);
437: c = mp->m_lines;
438: if (!lineb)
439: printf("\n");
440: for (lines = 0; lines < c && lines <= topl; lines++) {
441: if (readline(ibuf, linebuf) <= 0)
442: break;
443: puts(linebuf);
444: lineb = blankline(linebuf);
445: }
446: }
447: return(0);
448: }
449:
450: /*
451: * Touch all the given messages so that they will
452: * get mboxed.
453: */
454:
455: stouch(msgvec)
456: int msgvec[];
457: {
458: register int *ip;
459:
460: for (ip = msgvec; *ip != 0; ip++) {
461: dot = &message[*ip-1];
462: dot->m_flag |= MTOUCH;
463: dot->m_flag &= ~MPRESERVE;
464: }
465: return(0);
466: }
467:
468: /*
469: * Make sure all passed messages get mboxed.
470: */
471:
472: mboxit(msgvec)
473: int msgvec[];
474: {
475: register int *ip;
476:
477: for (ip = msgvec; *ip != 0; ip++) {
478: dot = &message[*ip-1];
479: dot->m_flag |= MTOUCH|MBOX;
480: dot->m_flag &= ~MPRESERVE;
481: }
482: return(0);
483: }
484:
485: /*
486: * List the folders the user currently has.
487: */
488: folders()
489: {
490: char dirname[BUFSIZ], cmd[BUFSIZ];
491: int pid, s, e;
492:
493: if (getfold(dirname) < 0) {
494: printf("No value set for \"folder\"\n");
495: return(-1);
496: }
497: switch ((pid = fork())) {
498: case 0:
499: sigchild();
500: execlp("ls", "ls", dirname, 0);
501: _exit(1);
502:
503: case -1:
504: perror("fork");
505: return(-1);
506:
507: default:
508: while ((e = wait(&s)) != -1 && e != pid)
509: ;
510: }
511: return(0);
512: }