Mercurial > illumos > onarm
annotate usr/src/cmd/mailx/cmd1.c @ 4:1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
author | Koji Uno <koji.uno@sun.com> |
---|---|
date | Mon, 31 Aug 2009 14:38:03 +0900 |
parents | c9caec207d52 |
children |
rev | line source |
---|---|
0 | 1 /* |
2 * CDDL HEADER START | |
3 * | |
4 * The contents of this file are subject to the terms of the | |
5 * Common Development and Distribution License, Version 1.0 only | |
6 * (the "License"). You may not use this file except in compliance | |
7 * with the License. | |
8 * | |
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE | |
10 * or http://www.opensolaris.org/os/licensing. | |
11 * See the License for the specific language governing permissions | |
12 * and limitations under the License. | |
13 * | |
14 * When distributing Covered Code, include this CDDL HEADER in each | |
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE. | |
16 * If applicable, add the following below this CDDL HEADER, with the | |
17 * fields enclosed by brackets "[]" replaced with your own identifying | |
18 * information: Portions Copyright [yyyy] [name of copyright owner] | |
19 * | |
20 * CDDL HEADER END | |
21 */ | |
22 /* | |
23 * Copyright 2001 Sun Microsystems, Inc. All rights reserved. | |
24 * Use is subject to license terms. | |
25 */ | |
26 | |
27 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */ | |
28 /* All Rights Reserved */ | |
29 | |
30 /* | |
31 * University Copyright- Copyright (c) 1982, 1986, 1988 | |
32 * The Regents of the University of California | |
33 * All Rights Reserved | |
34 * | |
35 * University Acknowledgment- Portions of this document are derived from | |
36 * software developed by the University of California, Berkeley, and its | |
37 * contributors. | |
38 */ | |
39 | |
4
1a15d5aaf794
synchronized with onnv_86 (6202) in onnv-gate
Koji Uno <koji.uno@sun.com>
parents:
0
diff
changeset
|
40 #pragma ident "%Z%%M% %I% %E% SMI" |
0 | 41 |
42 #include "rcv.h" | |
43 #include <locale.h> | |
44 | |
45 /* | |
46 * mailx -- a modified version of a University of California at Berkeley | |
47 * mail program | |
48 * | |
49 * User commands. | |
50 */ | |
51 | |
52 static char *dispname(char *hdr); | |
53 static void print(register struct message *mp, FILE *obuf, int doign); | |
54 static int type1(int *msgvec, int doign, int page); | |
55 static int topputs(const char *line, FILE *obuf); | |
56 | |
57 void brokpipe(int sig); | |
58 jmp_buf pipestop; | |
59 | |
60 /* | |
61 * Print the current active headings. | |
62 * Don't change dot if invoker didn't give an argument. | |
63 */ | |
64 | |
65 static int curscreen = 0, oldscreensize = 0; | |
66 | |
67 int | |
68 headers(int *msgvec) | |
69 { | |
70 register int n, mesg, flag; | |
71 register struct message *mp; | |
72 int size; | |
73 | |
74 size = screensize(); | |
75 n = msgvec[0]; | |
76 if (n != 0) | |
77 curscreen = (n-1)/size; | |
78 if (curscreen < 0) | |
79 curscreen = 0; | |
80 mp = &message[curscreen * size]; | |
81 if (mp >= &message[msgCount]) | |
82 mp = &message[msgCount - size]; | |
83 if (mp < &message[0]) | |
84 mp = &message[0]; | |
85 flag = 0; | |
86 mesg = mp - &message[0]; | |
87 if (dot != &message[n-1]) | |
88 dot = mp; | |
89 if (Hflag) | |
90 mp = message; | |
91 for (; mp < &message[msgCount]; mp++) { | |
92 mesg++; | |
93 if (mp->m_flag & MDELETED) | |
94 continue; | |
95 if (flag++ >= size && !Hflag) | |
96 break; | |
97 printhead(mesg); | |
98 sreset(); | |
99 } | |
100 if (flag == 0) { | |
101 printf(gettext("No more mail.\n")); | |
102 return (1); | |
103 } | |
104 return (0); | |
105 } | |
106 | |
107 /* | |
108 * Scroll to the next/previous screen | |
109 */ | |
110 | |
111 int | |
112 scroll(char arg[]) | |
113 { | |
114 register int s, size; | |
115 int cur[1]; | |
116 | |
117 cur[0] = 0; | |
118 size = screensize(); | |
119 s = curscreen; | |
120 switch (*arg) { | |
121 case 0: | |
122 case '+': | |
123 s++; | |
124 if (s * size > msgCount) { | |
125 printf(gettext("On last screenful of messages\n")); | |
126 return (0); | |
127 } | |
128 curscreen = s; | |
129 break; | |
130 | |
131 case '-': | |
132 if (--s < 0) { | |
133 printf(gettext("On first screenful of messages\n")); | |
134 return (0); | |
135 } | |
136 curscreen = s; | |
137 break; | |
138 | |
139 default: | |
140 printf(gettext("Unrecognized scrolling command \"%s\"\n"), arg); | |
141 return (1); | |
142 } | |
143 return (headers(cur)); | |
144 } | |
145 | |
146 /* | |
147 * Compute what the screen size should be. | |
148 * We use the following algorithm: | |
149 * If user specifies with screen option, use that. | |
150 * If baud rate < 1200, use 5 | |
151 * If baud rate = 1200, use 10 | |
152 * If baud rate > 1200, use 20 | |
153 */ | |
154 int | |
155 screensize(void) | |
156 { | |
157 register char *cp; | |
158 register int newscreensize, tmp; | |
159 #ifdef TIOCGWINSZ | |
160 struct winsize ws; | |
161 #endif | |
162 | |
163 if ((cp = value("screen")) != NOSTR && (tmp = atoi(cp)) > 0) | |
164 newscreensize = tmp; | |
165 else if (baud < B1200) | |
166 newscreensize = 5; | |
167 else if (baud == B1200) | |
168 newscreensize = 10; | |
169 #ifdef TIOCGWINSZ | |
170 else if (ioctl(fileno(stdout), TIOCGWINSZ, &ws) == 0 && ws.ws_row > 4) | |
171 newscreensize = ws.ws_row - 4; | |
172 #endif | |
173 else | |
174 newscreensize = 20; | |
175 /* renormalize the value of curscreen */ | |
176 if (newscreensize != oldscreensize) { | |
177 curscreen = curscreen * oldscreensize / newscreensize; | |
178 oldscreensize = newscreensize; | |
179 } | |
180 return (newscreensize); | |
181 } | |
182 | |
183 /* | |
184 * Print out the headlines for each message | |
185 * in the passed message list. | |
186 */ | |
187 | |
188 int | |
189 from(int *msgvec) | |
190 { | |
191 register int *ip; | |
192 | |
193 for (ip = msgvec; *ip != NULL; ip++) { | |
194 printhead(*ip); | |
195 sreset(); | |
196 } | |
197 if (--ip >= msgvec) | |
198 dot = &message[*ip - 1]; | |
199 return (0); | |
200 } | |
201 | |
202 /* | |
203 * Print out the header of a specific message. | |
204 * This is a slight improvement to the standard one. | |
205 */ | |
206 | |
207 void | |
208 printhead(int mesg) | |
209 { | |
210 struct message *mp; | |
211 FILE *ibuf; | |
212 char headline[LINESIZE], *subjline, dispc, curind; | |
213 char *fromline; | |
214 char pbuf[LINESIZE]; | |
215 char name[LINESIZE]; | |
216 struct headline hl; | |
217 register char *cp; | |
218 int showto; | |
219 | |
220 mp = &message[mesg-1]; | |
221 ibuf = setinput(mp); | |
222 readline(ibuf, headline); | |
223 if ((subjline = hfield("subject", mp, addone)) == NOSTR && | |
224 (subjline = hfield("subj", mp, addone)) == NOSTR && | |
225 (subjline = hfield("message-status", mp, addone)) == NOSTR) | |
226 subjline = ""; | |
227 | |
228 curind = (!Hflag && dot == mp) ? '>' : ' '; | |
229 dispc = ' '; | |
230 showto = 0; | |
231 if ((mp->m_flag & (MREAD|MNEW)) == (MREAD|MNEW)) | |
232 dispc = 'R'; | |
233 if (!(int)value("bsdcompat") && (mp->m_flag & (MREAD|MNEW)) == MREAD) | |
234 dispc = 'O'; | |
235 if ((mp->m_flag & (MREAD|MNEW)) == MNEW) | |
236 dispc = 'N'; | |
237 if ((mp->m_flag & (MREAD|MNEW)) == 0) | |
238 dispc = 'U'; | |
239 if (mp->m_flag & MSAVED) | |
240 if ((int)value("bsdcompat")) | |
241 dispc = '*'; | |
242 else | |
243 dispc = 'S'; | |
244 if (mp->m_flag & MPRESERVE) | |
245 if ((int)value("bsdcompat")) | |
246 dispc = 'P'; | |
247 else | |
248 dispc = 'H'; | |
249 if (mp->m_flag & MBOX) | |
250 dispc = 'M'; | |
251 parse(headline, &hl, pbuf); | |
252 if (hl.l_date == NOSTR) | |
253 hl.l_date = "<Unknown date>"; | |
254 | |
255 /* | |
256 * Netnews interface? | |
257 */ | |
258 | |
259 if (newsflg) { | |
260 if ((fromline = hfield("newsgroups", mp, addone)) == NOSTR && | |
261 (fromline = hfield("article-id", mp, addone)) == NOSTR) | |
262 fromline = "<>"; | |
263 else | |
264 for (cp = fromline; *cp; cp++) { /* limit length */ | |
265 if (any(*cp, " ,\n")) { | |
266 *cp = '\0'; | |
267 break; | |
268 } | |
269 } | |
270 /* | |
271 * else regular. | |
272 */ | |
273 | |
274 } else { | |
275 fromline = nameof(mp); | |
276 if (value("showto") && | |
277 samebody(myname, skin(fromline), FALSE) && | |
278 (cp = hfield("to", mp, addto))) { | |
279 showto = 1; | |
280 yankword(cp, fromline = name, sizeof (name), | |
281 docomma(cp)); | |
282 } | |
283 if (value("showname")) | |
284 fromline = dispname(fromline); | |
285 else | |
286 fromline = skin(fromline); | |
287 } | |
288 printf("%c%c%3d ", curind, dispc, mesg); | |
289 if ((int)value("showfull")) { | |
290 if (showto) | |
291 printf("To %-15s ", fromline); | |
292 else | |
293 printf("%-18s ", fromline); | |
294 } else { | |
295 if (showto) | |
296 printf("To %-15.15s ", fromline); | |
297 else | |
298 printf("%-18.18s ", fromline); | |
299 } | |
300 if (mp->m_text) { | |
301 printf("%16.16s %4ld/%-5ld %-.25s\n", | |
302 hl.l_date, mp->m_lines, mp->m_size, subjline); | |
303 } else { | |
304 printf("%16.16s binary/%-5ld %-.25s\n", hl.l_date, mp->m_size, | |
305 subjline); | |
306 } | |
307 } | |
308 | |
309 /* | |
310 * Return the full name from an RFC-822 header line | |
311 * or the last two (or one) component of the address. | |
312 */ | |
313 | |
314 static char * | |
315 dispname(char *hdr) | |
316 { | |
317 char *cp, *cp2; | |
318 | |
319 if (hdr == 0) | |
320 return (0); | |
321 if (((cp = strchr(hdr, '<')) != 0) && (cp > hdr)) { | |
322 *cp = 0; | |
323 if ((*hdr == '"') && ((cp = strrchr(++hdr, '"')) != 0)) | |
324 *cp = 0; | |
325 return (hdr); | |
326 } else if ((cp = strchr(hdr, '(')) != 0) { | |
327 hdr = ++cp; | |
328 if ((cp = strchr(hdr, '+')) != 0) | |
329 *cp = 0; | |
330 if ((cp = strrchr(hdr, ')')) != 0) | |
331 *cp = 0; | |
332 return (hdr); | |
333 } | |
334 cp = skin(hdr); | |
335 if ((cp2 = strrchr(cp, '!')) != 0) { | |
336 while (cp2 >= cp && *--cp2 != '!'); | |
337 cp = ++cp2; | |
338 } | |
339 return (cp); | |
340 } | |
341 | |
342 /* | |
343 * Print out the value of dot. | |
344 */ | |
345 | |
346 int | |
347 pdot(void) | |
348 { | |
349 printf("%d\n", dot - &message[0] + 1); | |
350 return (0); | |
351 } | |
352 | |
353 /* | |
354 * Print out all the possible commands. | |
355 */ | |
356 | |
357 int | |
358 pcmdlist(void) | |
359 { | |
360 register const struct cmd *cp; | |
361 register int cc; | |
362 | |
363 printf("Commands are:\n"); | |
364 for (cc = 0, cp = cmdtab; cp->c_name != NULL; cp++) { | |
365 cc += strlen(cp->c_name) + 2; | |
366 if (cc > 72) { | |
367 printf("\n"); | |
368 cc = strlen(cp->c_name) + 2; | |
369 } | |
370 if ((cp+1)->c_name != NOSTR) | |
371 printf("%s, ", cp->c_name); | |
372 else | |
373 printf("%s\n", cp->c_name); | |
374 } | |
375 return (0); | |
376 } | |
377 | |
378 /* | |
379 * Paginate messages, honor ignored fields. | |
380 */ | |
381 int | |
382 more(int *msgvec) | |
383 { | |
384 return (type1(msgvec, 1, 1)); | |
385 } | |
386 | |
387 /* | |
388 * Paginate messages, even printing ignored fields. | |
389 */ | |
390 int | |
391 More(int *msgvec) | |
392 { | |
393 | |
394 return (type1(msgvec, 0, 1)); | |
395 } | |
396 | |
397 /* | |
398 * Type out messages, honor ignored fields. | |
399 */ | |
400 int | |
401 type(int *msgvec) | |
402 { | |
403 | |
404 return (type1(msgvec, 1, 0)); | |
405 } | |
406 | |
407 /* | |
408 * Type out messages, even printing ignored fields. | |
409 */ | |
410 int | |
411 Type(int *msgvec) | |
412 { | |
413 | |
414 return (type1(msgvec, 0, 0)); | |
415 } | |
416 | |
417 /* | |
418 * Type out the messages requested. | |
419 */ | |
420 static int | |
421 type1(int *msgvec, int doign, int page) | |
422 { | |
423 int *ip; | |
424 register struct message *mp; | |
425 register int mesg; | |
426 register char *cp; | |
427 long nlines; | |
428 FILE *obuf; | |
429 void (*sigint)(int), (*sigpipe)(int); | |
430 int setsigs = 0; | |
431 | |
432 obuf = stdout; | |
433 if (setjmp(pipestop)) { | |
434 if (obuf != stdout) { | |
435 pipef = NULL; | |
436 npclose(obuf); | |
437 } | |
438 goto ret0; | |
439 } | |
440 if (intty && outtty && (page || (cp = value("crt")) != NOSTR)) { | |
441 if (!page) { | |
442 nlines = 0; | |
443 for (ip = msgvec, nlines = 0; | |
444 *ip && ip-msgvec < msgCount; ip++) | |
445 nlines += message[*ip - 1].m_lines; | |
446 } | |
447 if (page || | |
448 nlines > (*cp == '\0' ? screensize() - 2 : atoi(cp))) { | |
449 obuf = npopen(MORE, "w"); | |
450 if (obuf == NULL) { | |
451 perror(MORE); | |
452 obuf = stdout; | |
453 } else { | |
454 pipef = obuf; | |
455 sigint = sigset(SIGINT, SIG_IGN); | |
456 sigpipe = sigset(SIGPIPE, brokpipe); | |
457 setsigs++; | |
458 } | |
459 } | |
460 } | |
461 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { | |
462 mesg = *ip; | |
463 touch(mesg); | |
464 mp = &message[mesg-1]; | |
465 dot = mp; | |
466 print(mp, obuf, doign); | |
467 } | |
468 if (obuf != stdout) { | |
469 pipef = NULL; | |
470 npclose(obuf); | |
471 } | |
472 ret0: | |
473 if (setsigs) { | |
474 sigset(SIGPIPE, sigpipe); | |
475 sigset(SIGINT, sigint); | |
476 } | |
477 return (0); | |
478 } | |
479 | |
480 /* | |
481 * Respond to a broken pipe signal -- | |
482 * probably caused by user quitting more. | |
483 */ | |
484 void | |
485 #ifdef __cplusplus | |
486 brokpipe(int) | |
487 #else | |
488 /* ARGSUSED */ | |
489 brokpipe(int s) | |
490 #endif | |
491 { | |
492 #ifdef OLD_BSD_SIGS | |
493 sigrelse(SIGPIPE); | |
494 #endif | |
495 longjmp(pipestop, 1); | |
496 } | |
497 | |
498 /* | |
499 * Print the indicated message on standard output. | |
500 */ | |
501 | |
502 static void | |
503 print(register struct message *mp, FILE *obuf, int doign) | |
504 { | |
505 | |
506 if (value("quiet") == NOSTR && (!doign || !isign("message", 0))) | |
507 fprintf(obuf, "Message %2d:\n", mp - &message[0] + 1); | |
508 touch(mp - &message[0] + 1); | |
509 if (mp->m_text) { | |
510 (void) msend(mp, obuf, doign ? M_IGNORE : 0, fputs); | |
511 } else { | |
512 fprintf(obuf, "\n%s\n", gettext(binmsg)); | |
513 } | |
514 } | |
515 | |
516 /* | |
517 * Print the top so many lines of each desired message. | |
518 * The number of lines is taken from the variable "toplines" | |
519 * and defaults to 5. | |
520 */ | |
521 | |
522 static long top_linecount, top_maxlines, top_lineb; | |
523 static jmp_buf top_buf; | |
524 | |
525 int | |
526 top(int *msgvec) | |
527 { | |
528 register int *ip; | |
529 register struct message *mp; | |
530 register int mesg; | |
531 char *valtop; | |
532 | |
533 top_maxlines = 5; | |
534 valtop = value("toplines"); | |
535 if (valtop != NOSTR) { | |
536 top_maxlines = atoi(valtop); | |
537 if (top_maxlines < 0 || top_maxlines > 10000) | |
538 top_maxlines = 5; | |
539 } | |
540 top_lineb = 1; | |
541 for (ip = msgvec; *ip && ip-msgvec < msgCount; ip++) { | |
542 mesg = *ip; | |
543 touch(mesg); | |
544 mp = &message[mesg-1]; | |
545 dot = mp; | |
546 if (value("quiet") == NOSTR) | |
547 printf("Message %2d:\n", mesg); | |
548 if (!top_lineb) | |
549 printf("\n"); | |
550 top_linecount = 0; | |
551 if (setjmp(top_buf) == 0) { | |
552 if (mp->m_text) { | |
553 (void) msend(mp, stdout, M_IGNORE, topputs); | |
554 } else { | |
555 printf("\n%s\n", gettext(binmsg)); | |
556 } | |
557 } | |
558 } | |
559 return (0); | |
560 } | |
561 | |
562 int | |
563 topputs(const char *line, FILE *obuf) | |
564 { | |
565 if (top_linecount++ >= top_maxlines) | |
566 longjmp(top_buf, 1); | |
567 top_lineb = blankline(line); | |
568 return (fputs(line, obuf)); | |
569 } | |
570 | |
571 /* | |
572 * Touch all the given messages so that they will | |
573 * get mboxed. | |
574 */ | |
575 | |
576 int | |
577 stouch(int msgvec[]) | |
578 { | |
579 register int *ip; | |
580 | |
581 for (ip = msgvec; *ip != 0; ip++) { | |
582 dot = &message[*ip-1]; | |
583 dot->m_flag |= MTOUCH; | |
584 dot->m_flag &= ~MPRESERVE; | |
585 } | |
586 return (0); | |
587 } | |
588 | |
589 /* | |
590 * Make sure all passed messages get mboxed. | |
591 */ | |
592 | |
593 int | |
594 mboxit(int msgvec[]) | |
595 { | |
596 register int *ip; | |
597 | |
598 for (ip = msgvec; *ip != 0; ip++) { | |
599 dot = &message[*ip-1]; | |
600 dot->m_flag |= MTOUCH|MBOX; | |
601 dot->m_flag &= ~MPRESERVE; | |
602 } | |
603 return (0); | |
604 } | |
605 | |
606 /* | |
607 * List the folders the user currently has. | |
608 */ | |
609 int | |
610 folders(char **arglist) | |
611 { | |
612 char dirname[BUFSIZ], cmd[BUFSIZ]; | |
613 | |
614 if (getfold(dirname) < 0) { | |
615 printf(gettext("No value set for \"folder\"\n")); | |
616 return (-1); | |
617 } | |
618 if (*arglist) { | |
619 nstrcat(dirname, sizeof (dirname), "/"); | |
620 nstrcat(dirname, sizeof (dirname), *arglist); | |
621 } | |
622 snprintf(cmd, sizeof (cmd), "%s %s", LS, dirname); | |
623 return (system(cmd)); | |
624 } |