cmd1.c revision 1.1 1 /*-
2 * Copyright (c) 1980 The 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
35 static char sccsid[] = "@(#)cmd1.c 5.22 (Berkeley) 4/1/91";
36 #endif /* not lint */
37
38 #include "rcv.h"
39
40 /*
41 * Mail -- a mail program
42 *
43 * User commands.
44 */
45
46 /*
47 * Print the current active headings.
48 * Don't change dot if invoker didn't give an argument.
49 */
50
51 static int screen;
52
53 headers(msgvec)
54 int *msgvec;
55 {
56 register int n, mesg, flag;
57 register struct message *mp;
58 int size;
59
60 size = screensize();
61 n = msgvec[0];
62 if (n != 0)
63 screen = (n-1)/size;
64 if (screen < 0)
65 screen = 0;
66 mp = &message[screen * size];
67 if (mp >= &message[msgCount])
68 mp = &message[msgCount - size];
69 if (mp < &message[0])
70 mp = &message[0];
71 flag = 0;
72 mesg = mp - &message[0];
73 if (dot != &message[n-1])
74 dot = mp;
75 for (; mp < &message[msgCount]; mp++) {
76 mesg++;
77 if (mp->m_flag & MDELETED)
78 continue;
79 if (flag++ >= size)
80 break;
81 printhead(mesg);
82 }
83 if (flag == 0) {
84 printf("No more mail.\n");
85 return(1);
86 }
87 return(0);
88 }
89
90 /*
91 * Scroll to the next/previous screen
92 */
93 scroll(arg)
94 char arg[];
95 {
96 register int s, size;
97 int cur[1];
98
99 cur[0] = 0;
100 size = screensize();
101 s = screen;
102 switch (*arg) {
103 case 0:
104 case '+':
105 s++;
106 if (s * size > msgCount) {
107 printf("On last screenful of messages\n");
108 return(0);
109 }
110 screen = s;
111 break;
112
113 case '-':
114 if (--s < 0) {
115 printf("On first screenful of messages\n");
116 return(0);
117 }
118 screen = s;
119 break;
120
121 default:
122 printf("Unrecognized scrolling command \"%s\"\n", arg);
123 return(1);
124 }
125 return(headers(cur));
126 }
127
128 /*
129 * Compute screen size.
130 */
131 screensize()
132 {
133 int s;
134 char *cp;
135
136 if ((cp = value("screen")) != NOSTR && (s = atoi(cp)) > 0)
137 return s;
138 return screenheight - 4;
139 }
140
141 /*
142 * Print out the headlines for each message
143 * in the passed message list.
144 */
145
146 from(msgvec)
147 int *msgvec;
148 {
149 register int *ip;
150
151 for (ip = msgvec; *ip != NULL; ip++)
152 printhead(*ip);
153 if (--ip >= msgvec)
154 dot = &message[*ip - 1];
155 return(0);
156 }
157
158 /*
159 * Print out the header of a specific message.
160 * This is a slight improvement to the standard one.
161 */
162
163 printhead(mesg)
164 {
165 struct message *mp;
166 char headline[LINESIZE], wcount[LINESIZE], *subjline, dispc, curind;
167 char pbuf[BUFSIZ];
168 struct headline hl;
169 int subjlen;
170 char *name;
171
172 mp = &message[mesg-1];
173 (void) readline(setinput(mp), headline, LINESIZE);
174 if ((subjline = hfield("subject", mp)) == NOSTR)
175 subjline = hfield("subj", mp);
176 /*
177 * Bletch!
178 */
179 curind = dot == mp ? '>' : ' ';
180 dispc = ' ';
181 if (mp->m_flag & MSAVED)
182 dispc = '*';
183 if (mp->m_flag & MPRESERVE)
184 dispc = 'P';
185 if ((mp->m_flag & (MREAD|MNEW)) == MNEW)
186 dispc = 'N';
187 if ((mp->m_flag & (MREAD|MNEW)) == 0)
188 dispc = 'U';
189 if (mp->m_flag & MBOX)
190 dispc = 'M';
191 parse(headline, &hl, pbuf);
192 sprintf(wcount, "%3d/%-5ld", mp->m_lines, mp->m_size);
193 subjlen = screenwidth - 50 - strlen(wcount);
194 name = value("show-rcpt") != NOSTR ?
195 skin(hfield("to", mp)) : nameof(mp, 0);
196 if (subjline == NOSTR || subjlen < 0) /* pretty pathetic */
197 printf("%c%c%3d %-20.20s %16.16s %s\n",
198 curind, dispc, mesg, name, hl.l_date, wcount);
199 else
200 printf("%c%c%3d %-20.20s %16.16s %s \"%.*s\"\n",
201 curind, dispc, mesg, name, hl.l_date, wcount,
202 subjlen, subjline);
203 }
204
205 /*
206 * Print out the value of dot.
207 */
208
209 pdot()
210 {
211 printf("%d\n", dot - &message[0] + 1);
212 return(0);
213 }
214
215 /*
216 * Print out all the possible commands.
217 */
218
219 pcmdlist()
220 {
221 register struct cmd *cp;
222 register int cc;
223 extern struct cmd cmdtab[];
224
225 printf("Commands are:\n");
226 for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) {
227 cc += strlen(cp->c_name) + 2;
228 if (cc > 72) {
229 printf("\n");
230 cc = strlen(cp->c_name) + 2;
231 }
232 if ((cp+1)->c_name != NOSTR)
233 printf("%s, ", cp->c_name);
234 else
235 printf("%s\n", cp->c_name);
236 }
237 return(0);
238 }
239
240 /*
241 * Paginate messages, honor ignored fields.
242 */
243 more(msgvec)
244 int *msgvec;
245 {
246 return (type1(msgvec, 1, 1));
247 }
248
249 /*
250 * Paginate messages, even printing ignored fields.
251 */
252 More(msgvec)
253 int *msgvec;
254 {
255
256 return (type1(msgvec, 0, 1));
257 }
258
259 /*
260 * Type out messages, honor ignored fields.
261 */
262 type(msgvec)
263 int *msgvec;
264 {
265
266 return(type1(msgvec, 1, 0));
267 }
268
269 /*
270 * Type out messages, even printing ignored fields.
271 */
272 Type(msgvec)
273 int *msgvec;
274 {
275
276 return(type1(msgvec, 0, 0));
277 }
278
279 /*
280 * Type out the messages requested.
281 */
282 jmp_buf pipestop;
283
284 type1(msgvec, doign, page)
285 int *msgvec;
286 {
287 register *ip;
288 register struct message *mp;
289 register char *cp;
290 int nlines;
291 FILE *obuf;
292 void brokpipe();
293
294 obuf = stdout;
295 if (setjmp(pipestop))
296 goto close_pipe;
297 if (value("interactive") != NOSTR &&
298 (page || (cp = value("crt")) != NOSTR)) {
299 nlines = 0;
300 if (!page) {
301 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++)
302 nlines += message[*ip - 1].m_lines;
303 }
304 if (page || nlines > (*cp ? atoi(cp) : realscreenheight)) {
305 cp = value("PAGER");
306 if (cp == NULL || *cp == '\0')
307 cp = _PATH_MORE;
308 obuf = Popen(cp, "w");
309 if (obuf == NULL) {
310 perror(cp);
311 obuf = stdout;
312 } else
313 signal(SIGPIPE, brokpipe);
314 }
315 }
316 for (ip = msgvec; *ip && ip - msgvec < msgCount; ip++) {
317 mp = &message[*ip - 1];
318 touch(mp);
319 dot = mp;
320 if (value("quiet") == NOSTR)
321 fprintf(obuf, "Message %d:\n", *ip);
322 (void) send(mp, obuf, doign ? ignore : 0, NOSTR);
323 }
324 close_pipe:
325 if (obuf != stdout) {
326 /*
327 * Ignore SIGPIPE so it can't cause a duplicate close.
328 */
329 signal(SIGPIPE, SIG_IGN);
330 Pclose(obuf);
331 signal(SIGPIPE, SIG_DFL);
332 }
333 return(0);
334 }
335
336 /*
337 * Respond to a broken pipe signal --
338 * probably caused by quitting more.
339 */
340
341 void
342 brokpipe()
343 {
344 longjmp(pipestop, 1);
345 }
346
347 /*
348 * Print the top so many lines of each desired message.
349 * The number of lines is taken from the variable "toplines"
350 * and defaults to 5.
351 */
352
353 top(msgvec)
354 int *msgvec;
355 {
356 register int *ip;
357 register struct message *mp;
358 int c, topl, lines, lineb;
359 char *valtop, linebuf[LINESIZE];
360 FILE *ibuf;
361
362 topl = 5;
363 valtop = value("toplines");
364 if (valtop != NOSTR) {
365 topl = atoi(valtop);
366 if (topl < 0 || topl > 10000)
367 topl = 5;
368 }
369 lineb = 1;
370 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) {
371 mp = &message[*ip - 1];
372 touch(mp);
373 dot = mp;
374 if (value("quiet") == NOSTR)
375 printf("Message %d:\n", *ip);
376 ibuf = setinput(mp);
377 c = mp->m_lines;
378 if (!lineb)
379 printf("\n");
380 for (lines = 0; lines < c && lines <= topl; lines++) {
381 if (readline(ibuf, linebuf, LINESIZE) < 0)
382 break;
383 puts(linebuf);
384 lineb = blankline(linebuf);
385 }
386 }
387 return(0);
388 }
389
390 /*
391 * Touch all the given messages so that they will
392 * get mboxed.
393 */
394 stouch(msgvec)
395 int msgvec[];
396 {
397 register int *ip;
398
399 for (ip = msgvec; *ip != 0; ip++) {
400 dot = &message[*ip-1];
401 dot->m_flag |= MTOUCH;
402 dot->m_flag &= ~MPRESERVE;
403 }
404 return(0);
405 }
406
407 /*
408 * Make sure all passed messages get mboxed.
409 */
410
411 mboxit(msgvec)
412 int msgvec[];
413 {
414 register int *ip;
415
416 for (ip = msgvec; *ip != 0; ip++) {
417 dot = &message[*ip-1];
418 dot->m_flag |= MTOUCH|MBOX;
419 dot->m_flag &= ~MPRESERVE;
420 }
421 return(0);
422 }
423
424 /*
425 * List the folders the user currently has.
426 */
427 folders()
428 {
429 char dirname[BUFSIZ];
430 char *cmd;
431
432 if (getfold(dirname) < 0) {
433 printf("No value set for \"folder\"\n");
434 return 1;
435 }
436 if ((cmd = value("LISTER")) == NOSTR)
437 cmd = "ls";
438 (void) run_command(cmd, 0, -1, -1, dirname, NOSTR);
439 return 0;
440 }
441