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