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