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 40 #pragma ident "%Z%%M% %I% %E% SMI" 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 } 625