Annotation of src/usr.bin/mail/cmd1.c, Revision 1.2
1.2 ! niklas 1: /* $OpenBSD$ */
! 2:
1.1 deraadt 3: /*-
4: * Copyright (c) 1980, 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
10: * 1. Redistributions of source code must retain the above copyright
11: * notice, this list of conditions and the following disclaimer.
12: * 2. Redistributions in binary form must reproduce the above copyright
13: * notice, this list of conditions and the following disclaimer in the
14: * documentation and/or other materials provided with the distribution.
15: * 3. All advertising materials mentioning features or use of this software
16: * must display the following acknowledgement:
17: * This product includes software developed by the University of
18: * California, Berkeley and its contributors.
19: * 4. Neither the name of the University nor the names of its contributors
20: * may be used to endorse or promote products derived from this software
21: * without specific prior written permission.
22: *
23: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33: * SUCH DAMAGE.
34: */
35:
36: #ifndef lint
37: static char sccsid[] = "from: @(#)cmd1.c 8.1 (Berkeley) 6/6/93";
1.2 ! niklas 38: static char rcsid[] = "$OpenBSD$";
1.1 deraadt 39: #endif /* not lint */
40:
41: #include "rcv.h"
42: #include "extern.h"
43:
44: /*
45: * Mail -- a mail program
46: *
47: * User commands.
48: */
49:
50: /*
51: * Print the current active headings.
52: * Don't change dot if invoker didn't give an argument.
53: */
54:
55: static int screen;
56:
57: int
58: headers(msgvec)
59: int *msgvec;
60: {
61: register int n, mesg, flag;
62: register struct message *mp;
63: int size;
64:
65: size = screensize();
66: n = msgvec[0];
67: if (n != 0)
68: screen = (n-1)/size;
69: if (screen < 0)
70: screen = 0;
71: mp = &message[screen * size];
72: if (mp >= &message[msgCount])
73: mp = &message[msgCount - size];
74: if (mp < &message[0])
75: mp = &message[0];
76: flag = 0;
77: mesg = mp - &message[0];
78: if (dot != &message[n-1])
79: dot = mp;
80: for (; mp < &message[msgCount]; mp++) {
81: mesg++;
82: if (mp->m_flag & MDELETED)
83: continue;
84: if (flag++ >= size)
85: break;
86: printhead(mesg);
87: }
88: if (flag == 0) {
89: printf("No more mail.\n");
90: return(1);
91: }
92: return(0);
93: }
94:
95: /*
96: * Scroll to the next/previous screen
97: */
98: int
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 screen size.
136: */
137: int
138: screensize()
139: {
140: int s;
141: char *cp;
142:
143: if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0)
144: return s;
145: return screenheight - 4;
146: }
147:
148: /*
149: * Print out the headlines for each message
150: * in the passed message list.
151: */
152: int
153: from(msgvec)
154: int *msgvec;
155: {
156: register int *ip;
157:
158: for (ip = msgvec; *ip != NULL; ip++)
159: printhead(*ip);
160: if (--ip >= msgvec)
161: dot = &message[*ip - 1];
162: return(0);
163: }
164:
165: /*
166: * Print out the header of a specific message.
167: * This is a slight improvement to the standard one.
168: */
169: void
170: printhead(mesg)
171: int mesg;
172: {
173: struct message *mp;
174: char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
175: char pbuf[BUFSIZ];
176: struct headline hl;
177: int subjlen;
178: char *name;
179:
180: mp = &message[mesg-1];
181: (void) readline(setinput(mp), headline, LINESIZE);
182: if ((subjline = hfield("subject", mp)) == NOSTR)
183: subjline = hfield("subj", mp);
184: /*
185: * Bletch!
186: */
187: curind = dot == mp ? '>' : ' ';
188: dispc = ' ';
189: if (mp->m_flag & MSAVED)
190: dispc = '*';
191: if (mp->m_flag & MPRESERVE)
192: dispc = 'P';
193: if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
194: dispc = 'N';
195: if ((mp->m_flag & (MREAD|MNEW)) == 0)
196: dispc = 'U';
197: if (mp->m_flag & MBOX)
198: dispc = 'M';
199: parse(headline, &hl, pbuf);
200: sprintf(wcount, "%3d/%-5ld", mp->m_lines, mp->m_size);
201: subjlen = screenwidth - 50 - strlen(wcount);
202: name = value("show-rcpt") != NOSTR ?
203: skin(hfield("to", mp)) : nameof(mp, 0);
204: if (subjline == NOSTR || subjlen < 0) /* pretty pathetic */
205: printf("%c%c%3d %-20.20s %16.16s %s\n",
206: curind, dispc, mesg, name, hl.l_date, wcount);
207: else
208: printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n",
209: curind, dispc, mesg, name, hl.l_date, wcount,
210: subjlen, subjline);
211: }
212:
213: /*
214: * Print out the value of dot.
215: */
216: int
217: pdot()
218: {
219: printf("%d\n", dot - &message[0] + 1);
220: return(0);
221: }
222:
223: /*
224: * Print out all the possible commands.
225: */
226: int
227: pcmdlist()
228: {
1.2 ! niklas 229: extern const struct cmd cmdtab[];
! 230: register const struct cmd *cp;
1.1 deraadt 231: register int cc;
232:
233: printf("Commands are:\n");
234: for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
235: cc += strlen(cp->c_name) + 2;
236: if (cc > 72) {
237: printf("\n");
238: cc = strlen(cp->c_name) + 2;
239: }
240: if ((cp+1)->c_name != NOSTR)
241: printf("%s, ", cp->c_name);
242: else
243: printf("%s\n", cp->c_name);
244: }
245: return(0);
246: }
247:
248: /*
249: * Paginate messages, honor ignored fields.
250: */
251: int
252: more(msgvec)
253: int *msgvec;
254: {
255: return (type1(msgvec, 1, 1));
256: }
257:
258: /*
259: * Paginate messages, even printing ignored fields.
260: */
261: int
262: More(msgvec)
263: int *msgvec;
264: {
265:
266: return (type1(msgvec, 0, 1));
267: }
268:
269: /*
270: * Type out messages, honor ignored fields.
271: */
272: int
273: type(msgvec)
274: int *msgvec;
275: {
276:
277: return(type1(msgvec, 1, 0));
278: }
279:
280: /*
281: * Type out messages, even printing ignored fields.
282: */
283: int
284: Type(msgvec)
285: int *msgvec;
286: {
287:
288: return(type1(msgvec, 0, 0));
289: }
290:
291: /*
292: * Type out the messages requested.
293: */
294: jmp_buf pipestop;
295: int
296: type1(msgvec, doign, page)
297: int *msgvec;
298: int doign, page;
299: {
300: register *ip;
301: register struct message *mp;
302: register char *cp;
303: int nlines;
304: FILE *obuf;
305:
306: obuf = stdout;
307: if (setjmp(pipestop))
308: goto close_pipe;
309: if (value("interactive") != NOSTR &&
310: (page || (cp = value("crt")) != NOSTR)) {
311: nlines = 0;
312: if (!page) {
313: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
314: nlines += message[*ip - 1].m_lines;
315: }
316: if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
317: cp = value("PAGER");
318: if (cp == NULL || *cp == '\0')
319: cp = _PATH_MORE;
320: obuf = Popen(cp, "w");
321: if (obuf == NULL) {
322: perror(cp);
323: obuf = stdout;
324: } else
325: signal(SIGPIPE, brokpipe);
326: }
327: }
328: for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
329: mp = &message[*ip - 1];
330: touch(mp);
331: dot = mp;
332: if (value("quiet") == NOSTR)
333: fprintf(obuf, "Message %d:\n", *ip);
334: (void) send(mp, obuf, doign ? ignore : 0, NOSTR);
335: }
336: close_pipe:
337: if (obuf != stdout) {
338: /*
339: * Ignore SIGPIPE so it can't cause a duplicate close.
340: */
341: signal(SIGPIPE, SIG_IGN);
342: Pclose(obuf);
343: signal(SIGPIPE, SIG_DFL);
344: }
345: return(0);
346: }
347:
348: /*
349: * Respond to a broken pipe signal --
350: * probably caused by quitting more.
351: */
352: void
353: brokpipe(signo)
354: int signo;
355: {
356: longjmp(pipestop, 1);
357: }
358:
359: /*
360: * Print the top so many lines of each desired message.
361: * The number of lines is taken from the variable "toplines"
362: * and defaults to 5.
363: */
364: int
365: top(msgvec)
366: int *msgvec;
367: {
368: register int *ip;
369: register struct message *mp;
370: int c, topl, lines, lineb;
371: char *valtop, linebuf[LINESIZE];
372: FILE *ibuf;
373:
374: topl = 5;
375: valtop = value("toplines");
376: if (valtop != NOSTR) {
377: topl = atoi(valtop);
378: if (topl < 0 || topl > 10000)
379: topl = 5;
380: }
381: lineb = 1;
382: for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
383: mp = &message[*ip - 1];
384: touch(mp);
385: dot = mp;
386: if (value("quiet") == NOSTR)
387: printf("Message %d:\n", *ip);
388: ibuf = setinput(mp);
389: c = mp->m_lines;
390: if (!lineb)
391: printf("\n");
392: for (lines = 0; lines < c && lines <= topl; lines++) {
393: if (readline(ibuf, linebuf, LINESIZE) < 0)
394: break;
395: puts(linebuf);
396: lineb = blankline(linebuf);
397: }
398: }
399: return(0);
400: }
401:
402: /*
403: * Touch all the given messages so that they will
404: * get mboxed.
405: */
406: int
407: stouch(msgvec)
408: int msgvec[];
409: {
410: register int *ip;
411:
412: for (ip = msgvec; *ip != 0; ip++) {
413: dot = &message[*ip-1];
414: dot->m_flag |= MTOUCH;
415: dot->m_flag &= ~MPRESERVE;
416: }
417: return(0);
418: }
419:
420: /*
421: * Make sure all passed messages get mboxed.
422: */
423: int
424: mboxit(msgvec)
425: int msgvec[];
426: {
427: register int *ip;
428:
429: for (ip = msgvec; *ip != 0; ip++) {
430: dot = &message[*ip-1];
431: dot->m_flag |= MTOUCH|MBOX;
432: dot->m_flag &= ~MPRESERVE;
433: }
434: return(0);
435: }
436:
437: /*
438: * List the folders the user currently has.
439: */
440: int
441: folders()
442: {
443: char dirname[BUFSIZ];
444: char *cmd;
445:
446: if (getfold(dirname) < 0) {
447: printf("No value set for \"folder\"\n");
448: return 1;
449: }
450: if ((cmd = value("LISTER")) == NOSTR)
451: cmd = "ls";
452: (void) run_command(cmd, 0, -1, -1, dirname, NOSTR, NOSTR);
453: return 0;
454: }