1: /* msh.c - The MH shell (sigh) */
   2: 
   3: /* TODO:
   4: 	Keep more status information in maildrop map
   5:  */
   6: 
   7: #include "../h/mh.h"
   8: #include "../h/dropsbr.h"
   9: #include "../h/formatsbr.h"
  10: #include "../h/scansbr.h"
  11: #include "../zotnet/tws.h"
  12: #include <stdio.h>
  13: #include "../zotnet/mts.h"
  14: #include <ctype.h>
  15: #include <sys/types.h>
  16: #include <sys/stat.h>
  17: #ifndef SYS5
  18: #include <sgtty.h>
  19: #else   SYS5
  20: #include <termio.h>
  21: #include <sys/ioctl.h>
  22: #endif	SYS5
  23: #include <pwd.h>
  24: #include <setjmp.h>
  25: #include <signal.h>
  26: #include "../h/mshsbr.h"
  27: #include "../h/vmhsbr.h"
  28: 
  29: 
  30: #define QUOTE   '\\'        /* sigh */
  31: 
  32: 
  33: /*  */
  34: 
  35: static struct swit switches[] = {
  36: #define IDSW    0
  37:     "idstart number", -7,   /* interface from bbc */
  38: #define FDSW    1
  39:     "idstop number", -6,    /*  .. */
  40: #define QDSW    2
  41:     "idquit number", -6,    /*  .. */
  42: #define NMSW    3
  43:     "idname BBoard", -6,    /*  .. */
  44: 
  45: #define PRMPTSW 4
  46:     "prompt string", 0,
  47: 
  48: #define SCANSW  5
  49:     "scan", 0,
  50: #define NSCANSW 6
  51:     "noscan", 0,
  52: 
  53: #define READSW  7
  54:     "vmhread fd", -7,
  55: #define WRITESW 8
  56:     "vmhwrite fd", -8,
  57: 
  58: #define PREADSW 9
  59:     "popread fd", -7,
  60: #define PWRITSW 10
  61:     "popwrite fd", -8,
  62: 
  63: #define TCURSW  11
  64:     "topcur", 0,
  65: #define NTCURSW 12
  66:     "notopcur", 0,
  67: 
  68: #define HELPSW  13
  69:     "help", 4,
  70: 
  71:     NULL, NULL
  72: };
  73: 
  74: /*  */
  75:                 /* FOLDER */
  76: char  *fmsh = NULL;     /* folder instead of file */
  77: int    modified;        /* command modified folder */
  78: struct msgs *mp;        /* used a lot */
  79: static int   nMsgs = 0;
  80: struct Msg  *Msgs = NULL;   /* Msgs[0] not used */
  81: static FILE *fp;        /* input file */
  82: static FILE *yp = NULL;     /* temporary file */
  83: static int  mode;       /* mode of file */
  84: static int  numfds = 0;     /* number of files cached */
  85: static int  maxfds = 0;     /* number of files cached to be cached */
  86: static time_t mtime = (time_t) 0;/* mtime of file */
  87: 
  88: 
  89:                 /* VMH */
  90: #define ALARM   ((unsigned int) 10)
  91: #define ttyN(c) ttyNaux ((c), NULLCP)
  92: 
  93: static int  vmh = 0;
  94: 
  95: static int  vmhpid = OK;
  96: static int  vmhfd0;
  97: static int  vmhfd1;
  98: static int  vmhfd2;
  99: 
 100: static int  vmhtty = NOTOK;
 101: 
 102: #define SCAN    1
 103: #define STATUS  2
 104: #define DISPLAY 3
 105: #define NWIN    DISPLAY
 106: 
 107: static int  topcur = 0;
 108: 
 109: static int  numwins = 0;
 110: static int  windows[NWIN + 1];
 111: 
 112: static jmp_buf peerenv;
 113: 
 114: void    padios (), padvise ();
 115: int alrmser ();
 116: 
 117: 
 118: #ifdef  BPOP
 119:                 /* POP */
 120: 
 121: static int pmsh = 0;        /* BPOP enabled */
 122: 
 123: extern char response[];
 124: #endif	BPOP
 125: 
 126: 
 127:                 /* PARENT */
 128: static int  pfd = NOTOK;    /* fd parent is reading from */
 129: static int  ppid = 0;       /* pid of parent */
 130: 
 131: 
 132:                 /* COMMAND */
 133: int     interactive;        /* running from a /dev/tty */
 134: int     redirected;     /* re-directing output */
 135: FILE  *sp = NULL;       /* original stdout */
 136: 
 137: char   *cmd_name;       /* command being run */
 138: 
 139: char    myfilter[BUFSIZ];   /* path to mhl.forward */
 140: 
 141: static char *myprompt = "(%s) ";/* prompting string */
 142: 
 143: 
 144:                 /* BBOARDS */
 145: static int    gap;      /* gap in BBoard-ID:s */
 146: 
 147: static char *myname = NULL; /* BBoard name */
 148: 
 149: char   *BBoard_ID = "BBoard-ID";/* BBoard-ID constant */
 150: 
 151:                 /* SIGNALS */
 152: int (*istat) ();        /* original SIGINT */
 153: static int  (*pstat) ();    /* current SIGPIPE */
 154: int     (*qstat) ();        /* original SIGQUIT */
 155: #ifdef  SIGTSTP
 156: static int  (*tstat) ();    /* original SIGTSTP */
 157: #endif	SIGTSTP
 158: int     interrupted;        /* SIGINT detected */
 159: int     broken_pipe;        /* SIGPIPE detected */
 160: int     told_to_quit;       /* SIGQUIT detected */
 161: 
 162: #ifdef  BSD42
 163: int     should_intr;        /* signal handler should interrupt call */
 164: jmp_buf sigenv;         /* the environment pointer */
 165: #endif	BSD42
 166: 
 167: int intrser (), pipeser (), quitser ();
 168: 
 169: 
 170: #ifdef  SYS5
 171: struct passwd  *getpwnam ();
 172: #endif	SYS5
 173: 
 174: /*  */
 175: 
 176: /* ARGSUSED */
 177: 
 178: main (argc, argv)
 179: int     argc;
 180: char  **argv;
 181: {
 182:     int     id = 0,
 183:             scansw = 0,
 184:             vmh1 = 0,
 185:             vmh2 = 0;
 186: #ifdef  BPOP
 187:     int     pmsh1 = 0,
 188:         pmsh2 = 0;
 189: #endif	BPOP
 190:     char   *cp,
 191:            *file = NULL,
 192:            *folder = NULL,
 193:           **ap,
 194:           **argp,
 195:             buf[80],
 196:            *arguments[MAXARGS];
 197: 
 198:     invo_name = r1bindex (argv[0], '/');
 199:     mts_init (invo_name);
 200:     if ((cp = m_find (invo_name)) != NULL) {
 201:     ap = brkstring (cp = getcpy (cp), " ", "\n");
 202:     ap = copyip (ap, arguments);
 203:     }
 204:     else
 205:     ap = arguments;
 206:     (void) copyip (argv + 1, ap);
 207:     argp = arguments;
 208: 
 209: /*  */
 210: 
 211:     while (cp = *argp++) {
 212:     if (*cp == '-')
 213:         switch (smatch (++cp, switches)) {
 214:         case AMBIGSW:
 215:             ambigsw (cp, switches);
 216:             done (1);
 217:         case UNKWNSW:
 218:             adios (NULLCP, "-%s unknown", cp);
 219:         case HELPSW:
 220:             (void) sprintf (buf, "%s [switches] file", invo_name);
 221:             help (buf, switches);
 222:             done (1);
 223: 
 224:         case IDSW:
 225:             if (!(cp = *argp++) || *cp == '-')
 226:             adios (NULLCP, "missing argument to %s", argp[-2]);
 227:             if ((id = atoi (cp)) < 1)
 228:             adios (NULLCP, "bad argument %s %s", argp[-2], cp);
 229:             continue;
 230:         case FDSW:
 231:             if (!(cp = *argp++) || *cp == '-')
 232:             adios (NULLCP, "missing argument to %s", argp[-2]);
 233:             if ((pfd = atoi (cp)) <= 1)
 234:             adios (NULLCP, "bad argument %s %s", argp[-2], cp);
 235:             continue;
 236:         case QDSW:
 237:             if (!(cp = *argp++) || *cp == '-')
 238:             adios (NULLCP, "missing argument to %s", argp[-2]);
 239:             if ((ppid = atoi (cp)) <= 1)
 240:             adios (NULLCP, "bad argument %s %s", argp[-2], cp);
 241:             continue;
 242:         case NMSW:
 243:             if (!(myname = *argp++) || *myname == '-')
 244:             adios (NULLCP, "missing argument to %s", argp[-2]);
 245:             continue;
 246: 
 247:         case SCANSW:
 248:             scansw++;
 249:             continue;
 250:         case NSCANSW:
 251:             scansw = 0;
 252:             continue;
 253: 
 254:         case PRMPTSW:
 255:             if (!(myprompt = *argp++) || *myprompt == '-')
 256:             adios (NULLCP, "missing argument to %s", argp[-2]);
 257:             continue;
 258: 
 259:         case READSW:
 260:             if (!(cp = *argp++) || *cp == '-')
 261:             adios (NULLCP, "missing argument to %s", argp[-2]);
 262:             if ((vmh1 = atoi (cp)) < 1)
 263:             adios (NULLCP, "bad argument %s %s", argp[-2], cp);
 264:             continue;
 265:         case WRITESW:
 266:             if (!(cp = *argp++) || *cp == '-')
 267:             adios (NULLCP, "missing argument to %s", argp[-2]);
 268:             if ((vmh2 = atoi (cp)) < 1)
 269:             adios (NULLCP, "bad argument %s %s", argp[-2], cp);
 270:             continue;
 271: 
 272:         case PREADSW:
 273:             if (!(cp = *argp++) || *cp == '-')
 274:             adios (NULLCP, "missing argument to %s", argp[-2]);
 275: #ifdef  BPOP
 276:             if ((pmsh1 = atoi (cp)) < 1)
 277:             adios (NULLCP, "bad argument %s %s", argp[-2], cp);
 278: #endif	BPOP
 279:             continue;
 280:         case PWRITSW:
 281:             if (!(cp = *argp++) || *cp == '-')
 282:             adios (NULLCP, "missing argument to %s", argp[-2]);
 283: #ifdef  BPOP
 284:             if ((pmsh2 = atoi (cp)) < 1)
 285:             adios (NULLCP, "bad argument %s %s", argp[-2], cp);
 286: #endif	BPOP
 287:             continue;
 288: 
 289:         case TCURSW:
 290:             topcur++;
 291:             continue;
 292:         case NTCURSW:
 293:             topcur = 0;
 294:             continue;
 295:         }
 296:     if (*cp == '+' || *cp == '@') {
 297:         if (folder)
 298:         adios (NULLCP, "only one folder at a time!");
 299:         else
 300:         folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
 301:     }
 302:     else
 303:         if (file)
 304:         adios (NULLCP, "only one file at a time!");
 305:         else
 306:         file = cp;
 307:     }
 308: 
 309: /*  */
 310: 
 311:     if (!file && !folder)
 312:     file = "./msgbox";
 313:     if (file && folder)
 314:     adios (NULLCP, "use a file or a folder, not both");
 315:     (void) strcpy (myfilter, libpath (mhlforward));
 316: #ifdef  FIOCLEX
 317:     if (pfd > 1)
 318:     (void) ioctl (pfd, FIOCLEX, NULLCP);
 319: #endif	FIOCLEX
 320: 
 321: #ifdef  BSD42
 322:     should_intr = 0;
 323: #endif	BSD42
 324:     setsigx (istat, SIGINT, intrser);
 325:     setsigx (qstat, SIGQUIT, quitser);
 326: 
 327:     (void) sc_width ();     /* MAGIC... */
 328: 
 329:     if (vmh = vmh1 && vmh2) {
 330:     (void) rcinit (vmh1, vmh2);
 331:     (void) pINI ();
 332:     (void) signal (SIGINT, SIG_IGN);
 333:     (void) signal (SIGQUIT, SIG_IGN);
 334: #ifdef  SIGTSTP
 335:     tstat = signal (SIGTSTP, SIG_IGN);
 336: #endif	SIGTSTP
 337:     }
 338: 
 339: #ifdef  BPOP
 340:     if (pmsh = pmsh1 && pmsh2) {
 341:     cp = getenv ("MHPOPDEBUG");
 342:     if (pop_set (pmsh1, pmsh2, cp && *cp) == NOTOK)
 343:         padios (NULLCP, "%s", response);
 344:     if (folder)
 345:         file = folder, folder = NULL;
 346:     }
 347: #endif	BPOP
 348: 
 349:     if (folder)
 350:     fsetup (folder);
 351:     else
 352:     setup (file);
 353:     readids (id);
 354:     display_info (id > 0 ? scansw : 0);
 355: 
 356:     msh (id > 0 ? scansw : 0);
 357: 
 358:     m_reset ();
 359: 
 360:     done (0);
 361: }
 362: 
 363: /*  */
 364: 
 365: static struct swit mshcmds[] = {
 366: #define ALICMD  0
 367:     "ali", 0,
 368: #define EXPLCMD 1
 369:     "burst", 0,
 370: #define COMPCMD 2
 371:     "comp", 0,
 372: #define DISTCMD 3
 373:     "dist", 0,
 374: #define EXITCMD 4
 375:     "exit", 0,
 376: #define FOLDCMD 5
 377:     "folder", 0,
 378: #define FORWCMD 6
 379:     "forw", 0,
 380: #define HELPCMD 7
 381:     "help", 0,
 382: #define INCMD   8
 383:     "inc", 0,
 384: #define MARKCMD 9
 385:     "mark", 0,
 386: #define MAILCMD 10
 387:     "mhmail", 0,
 388: #define MSGKCMD 11
 389:     "msgchk", 0,
 390: #define NEXTCMD 12
 391:     "next", 0,
 392: #define PACKCMD 13
 393:     "packf", 0,
 394: #define PICKCMD 14
 395:     "pick", 0,
 396: #define PREVCMD 15
 397:     "prev", 0,
 398: #define QUITCMD 16
 399:     "quit", 0,
 400: #define FILECMD 17
 401:     "refile", 0,
 402: #define REPLCMD 18
 403:     "repl", 0,
 404: #define RMMCMD  19
 405:     "rmm", 0,
 406: #define SCANCMD 20
 407:     "scan", 0,
 408: #define SENDCMD 21
 409:     "send", 0,
 410: #define SHOWCMD 22
 411:     "show", 0,
 412: #define SORTCMD 23
 413:     "sortm", 0,
 414: #define WHATCMD 24
 415:     "whatnow", 0,
 416: #define WHOMCMD 25
 417:     "whom", 0,
 418: 
 419:     NULL, NULL
 420: };
 421: 
 422: /*  */
 423: 
 424: static  msh (scansw)
 425: int     scansw;
 426: {
 427:     int     i;
 428:     register char  *cp,
 429:                   **ap;
 430:     char    prompt[BUFSIZ],
 431:            *vec[MAXARGS];
 432:     struct Cmd  typein;
 433:     register struct Cmd *cmdp;
 434: 
 435:     (void) sprintf (prompt, myprompt, invo_name);
 436:     cmdp = &typein;
 437: 
 438:     for (;;) {
 439:     if (yp) {
 440:         (void) fclose (yp);
 441:         yp = NULL;
 442:     }
 443:     if (vmh) {
 444:         if ((i = getcmds (mshcmds, cmdp, scansw)) == EOF) {
 445:         (void) rcdone ();
 446:         return;
 447:         }
 448:     }
 449:     else {
 450:         (void) check_folder (scansw);
 451:         if ((i = getargs (prompt, mshcmds, cmdp)) == EOF) {
 452:         (void) putchar ('\n');
 453:         return;
 454:         }
 455:     }
 456:     cmd_name = mshcmds[i].sw;
 457: 
 458:     switch (i) {
 459:         case QUITCMD:
 460:         quit ();
 461:         return;
 462: 
 463:         case EXITCMD:
 464:         case EXPLCMD:
 465:         case FOLDCMD:
 466:         case FORWCMD:   /* sigh */
 467:         case MARKCMD:
 468:         case NEXTCMD:
 469:         case PACKCMD:
 470:         case PICKCMD:
 471:         case PREVCMD:
 472:         case RMMCMD:
 473:         case SHOWCMD:
 474:         case SCANCMD:
 475:         case SORTCMD:
 476:         if ((cp = m_find (cmd_name)) != NULL) {
 477:             ap = brkstring (cp = getcpy (cp), " ", "\n");
 478:             ap = copyip (ap, vec);
 479:         }
 480:         else
 481:             ap = vec;
 482:         break;
 483: 
 484:         default:
 485:         cp = NULL;
 486:         ap = vec;
 487:         break;
 488:     }
 489:     (void) copyip (cmdp -> args + 1, ap);
 490: 
 491:     m_init ();
 492: 
 493:     if (!vmh && init_io (cmdp, vmh) == NOTOK) {
 494:         if (cp != NULL)
 495:         free (cp);
 496:         continue;
 497:     }
 498:     modified = 0;
 499:     redirected = vmh || cmdp -> direction != STDIO;
 500: 
 501:     switch (i) {
 502:         case ALICMD:
 503:         case COMPCMD:
 504:         case INCMD:
 505:         case MAILCMD:
 506:         case MSGKCMD:
 507:         case SENDCMD:
 508:         case WHATCMD:
 509:         case WHOMCMD:
 510:         if (!vmh || ttyN (cmdp) != NOTOK)
 511:             forkcmd (vec, cmd_name);
 512:         break;
 513: 
 514:         case DISTCMD:
 515:         if (!vmh || ttyN (cmdp) != NOTOK)
 516:             distcmd (vec);
 517:         break;
 518: 
 519:         case EXPLCMD:
 520:         if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
 521:             explcmd (vec);
 522:         break;
 523: 
 524:         case FILECMD:
 525:         if (!vmh
 526:             || (filehak (vec) == OK ? ttyN (cmdp)
 527:                     : winN (cmdp, DISPLAY, 1)) != NOTOK)
 528:             filecmd (vec);
 529:         break;
 530: 
 531:         case FOLDCMD:
 532:         if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
 533:             foldcmd (vec);
 534:         break;
 535: 
 536:         case FORWCMD:
 537:         if (!vmh || ttyN (cmdp) != NOTOK)
 538:             forwcmd (vec);
 539:         break;
 540: 
 541:         case HELPCMD:
 542:         if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
 543:             helpcmd (vec);
 544:         break;
 545: 
 546:         case EXITCMD:
 547:         case MARKCMD:
 548:         if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
 549:             markcmd (vec);
 550:         break;
 551: 
 552:         case NEXTCMD:
 553:         case PREVCMD:
 554:         case SHOWCMD:
 555:         if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
 556:             showcmd (vec);
 557:         break;
 558: 
 559:         case PACKCMD:
 560:         if (!vmh
 561:             || (packhak (vec) == OK ? ttyN (cmdp)
 562:                     : winN (cmdp, DISPLAY, 1)) != NOTOK)
 563:             packcmd (vec);
 564:         break;
 565: 
 566:         case PICKCMD:
 567:         if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
 568:             pickcmd (vec);
 569:         break;
 570: 
 571:         case REPLCMD:
 572:         if (!vmh || ttyN (cmdp) != NOTOK)
 573:             replcmd (vec);
 574:         break;
 575: 
 576:         case RMMCMD:
 577:         if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
 578:             rmmcmd (vec);
 579:         break;
 580: 
 581:         case SCANCMD:
 582:         if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
 583:             scancmd (vec);
 584:         break;
 585: 
 586:         case SORTCMD:
 587:         if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
 588:             sortcmd (vec);
 589:         break;
 590: 
 591:         default:
 592:         padios (NULLCP, "no dispatch for %s", cmd_name);
 593:     }
 594: 
 595:     if (vmh) {
 596:         if (vmhtty != NOTOK)
 597:         (void) ttyR (cmdp);
 598:         if (vmhpid > OK)
 599:         (void) winR (cmdp);
 600:     }
 601:     else
 602:         fin_io (cmdp, vmh);
 603:     if (cp != NULL)
 604:         free (cp);
 605:     if (i == EXITCMD) {
 606:         quit ();
 607:         return;
 608:     }
 609:     }
 610: }
 611: 
 612: /*  */
 613: 
 614: fsetup (folder)
 615: char   *folder;
 616: {
 617:     register int msgnum;
 618:     char   *maildir;
 619:     struct stat st;
 620: 
 621:     maildir = m_maildir (folder);
 622:     if (chdir (maildir) == NOTOK)
 623:     padios (maildir, "unable to change directory to");
 624:     if (!(mp = m_gmsg (folder)))
 625:     padios (NULLCP, "unable to read folder %s", folder);
 626:     if (mp -> hghmsg == 0)
 627:     padios (NULLCP, "no messages in %s", folder);
 628: 
 629:     mode = m_gmprot ();
 630:     mtime = stat (mp -> foldpath, &st) != NOTOK ? st.st_mtime : 0;
 631: 
 632:     m_gMsgs (mp -> hghmsg);
 633: 
 634:     for (msgnum = mp -> lowmsg; msgnum <= mp -> hghmsg; msgnum++) {
 635:     Msgs[msgnum].m_bboard_id = 0;
 636:     Msgs[msgnum].m_top = NOTOK;
 637:     Msgs[msgnum].m_start = Msgs[msgnum].m_stop = 0L;
 638:     Msgs[msgnum].m_scanl = NULL;
 639:     }
 640: 
 641:     m_init ();
 642: 
 643:     fmsh = getcpy (folder);
 644: 
 645: #ifndef BSD42
 646:     maxfds = _NFILE / 2;
 647: #else   BSD42
 648:     maxfds = getdtablesize () / 2;
 649: #endif	BSD42
 650:     if ((maxfds -= 2) < 1)
 651:     maxfds = 1;
 652: }
 653: 
 654: /*  */
 655: 
 656: setup (file)
 657: char   *file;
 658: {
 659:     int     i,
 660:             msgp;
 661: #ifdef  BPOP
 662:     char    tmpfil[BUFSIZ];
 663: #endif	BPOP
 664:     struct stat st;
 665: 
 666: #ifdef  BPOP
 667:     if (pmsh) {
 668:     (void) strcpy (tmpfil, m_tmpfil (invo_name));
 669:     if ((fp = fopen (tmpfil, "w+")) == NULL)
 670:         padios (tmpfil, "unable to create");
 671:     (void) unlink (tmpfil);
 672:     }
 673:     else
 674: #endif	BPOP
 675:     if ((fp = fopen (file, "r")) == NULL)
 676:     padios (file, "unable to read");
 677: #ifdef  FIOCLEX
 678:     (void) ioctl (fileno (fp), FIOCLEX, NULLCP);
 679: #endif	FIOCLEX
 680:     if (fstat (fileno (fp), &st) != NOTOK) {
 681:     mode = (int) (st.st_mode & 0777), mtime = st.st_mtime;
 682:     msgp = read_map (file, (long) st.st_size);
 683:     }
 684:     else {
 685:     mode = m_gmprot (), mtime = 0;
 686:     msgp = 0;
 687:     }
 688: 
 689:     if ((msgp = read_file (msgp ? Msgs[msgp].m_stop : 0L, msgp + 1)) < 1)
 690:     padios (NULLCP, "no messages in %s", myname ? myname : file);
 691: 
 692:     mp = (struct msgs  *) calloc ((unsigned) 1, MSIZE (mp, 1, msgp + 1));
 693:     if (mp == NULL)
 694:     padios (NULLCP, "unable to allocate folder storage");
 695: 
 696:     mp -> hghmsg = msgp;
 697:     mp -> nummsg = msgp;
 698:     mp -> lowmsg = 1;
 699:     mp -> curmsg = 0;
 700: 
 701:     mp -> foldpath = getcpy (myname ? myname : file);
 702:     mp -> msgflags = NULL;
 703: #ifdef  BPOP
 704:     if (pmsh)
 705:     mp -> msgflags |= READONLY;
 706:     else {
 707: #endif	BPOP
 708:     (void) stat (file, &st);
 709:     if (st.st_uid != getuid () || access (file, 02) == NOTOK)
 710:         mp -> msgflags |= READONLY;
 711: #ifdef  BPOP
 712:     }
 713: #endif	BPOP
 714:     mp -> lowoff = 1;
 715:     mp -> hghoff = mp -> hghmsg + 1;
 716: 
 717: #ifdef  MTR
 718:     mp -> msgstats = (short *)
 719:         calloc ((unsigned) 1, MSIZEX (mp, mp -> lowmsg, mp -> hghmsg));
 720:     if (mp -> msgstats == NULL)
 721:     padios (NULLCP, "unable to allocate messages storage");
 722:     mp -> msgstats = (mp -> msgbase = mp -> msgstats) - mp -> lowoff;
 723:     if (mp -> msgstats < 0)
 724:     padios (NULLCP, "setup() botch -- you lose big");
 725: #endif	MTR
 726: #ifdef  BPOP
 727:     if (pmsh) {
 728:     for (i = mp -> lowmsg; i <= mp -> hghmsg; i++) {
 729:         Msgs[i].m_top = i;
 730:         mp -> msgstats[i] = EXISTS | VIRTUAL;
 731:     }
 732:     }
 733:     else
 734: #endif	BPOP
 735:     for (i = mp -> lowmsg; i <= mp -> hghmsg; i++)
 736:     mp -> msgstats[i] = EXISTS;
 737:     m_init ();
 738: 
 739:     mp -> msgattrs[0] = getcpy ("unseen");
 740:     mp -> msgattrs[1] = NULL;
 741: 
 742:     m_unknown (fp);     /* the MAGIC invocation */
 743:     if (fmsh) {
 744:     free (fmsh);
 745:     fmsh = NULL;
 746:     }
 747: }
 748: 
 749: /*  */
 750: 
 751: static int  read_map (file, size)
 752: char   *file;
 753: long    size;
 754: {
 755:     register int    i,
 756:                     msgp;
 757:     register struct drop   *dp,
 758:                            *mp;
 759:     struct drop *rp;
 760: 
 761: #ifdef  BPOP
 762:     if (pmsh)
 763:     return read_pop ();
 764: #endif	BPOP
 765: 
 766:     if ((i = map_read (file, size, &rp, 1)) == 0)
 767:     return 0;
 768: 
 769:     m_gMsgs (i);
 770: 
 771:     msgp = 1;
 772:     for (dp = rp; i-- > 0; msgp++, dp++) {
 773:     mp = &Msgs[msgp].m_drop;
 774:     mp -> d_id = dp -> d_id;
 775:     mp -> d_size = dp -> d_size;
 776:     mp -> d_start = dp -> d_start;
 777:     mp -> d_stop = dp -> d_stop;
 778:     Msgs[msgp].m_scanl = NULL;
 779:     }
 780:     free ((char *) rp);
 781: 
 782:     return (msgp - 1);
 783: }
 784: 
 785: /*  */
 786: 
 787: static  int read_file (pos, msgp)
 788: register long   pos;
 789: register int    msgp;
 790: {
 791:     register int    i;
 792:     register struct drop   *dp,
 793:                            *mp;
 794:     struct drop *rp;
 795: 
 796: #ifdef  BPOP
 797:     if (pmsh)
 798:     return (msgp - 1);
 799: #endif	BPOP
 800: 
 801:     if ((i = mbx_read (fp, pos, &rp, 1)) <= 0)
 802:     return (msgp - 1);
 803: 
 804:     m_gMsgs ((msgp - 1) + i);
 805: 
 806:     for (dp = rp; i-- > 0; msgp++, dp++) {
 807:     mp = &Msgs[msgp].m_drop;
 808:     mp -> d_id = 0;
 809:     mp -> d_size = dp -> d_size;
 810:     mp -> d_start = dp -> d_start;
 811:     mp -> d_stop = dp -> d_stop;
 812:     Msgs[msgp].m_scanl = NULL;
 813:     }
 814:     free ((char *) rp);
 815: 
 816:     return (msgp - 1);
 817: }
 818: 
 819: /*  */
 820: 
 821: #ifdef  BPOP
 822: static int  read_pop () {
 823:     int     nmsgs,
 824:             nbytes;
 825: 
 826:     if (pop_stat (&nmsgs, &nbytes) == NOTOK)
 827:     padios (NULLCP, "%s", response);
 828: 
 829:     m_gMsgs (nmsgs);
 830: 
 831:     return nmsgs;
 832: }
 833: 
 834: 
 835: static int  pop_action (s)
 836: register char  *s;
 837: {
 838:     fprintf (yp, "%s\n", s);
 839: }
 840: #endif	BPOP
 841: 
 842: /*  */
 843: 
 844: static m_gMsgs (n)
 845: int n;
 846: {
 847:     if (Msgs == NULL) {
 848:     nMsgs = n + MAXFOLDER / 2;
 849:     Msgs = (struct Msg *) calloc ((unsigned) (nMsgs + 2), sizeof *Msgs);
 850:     if (Msgs == NULL)
 851:         padios (NULLCP, "unable to allocate Msgs structure");
 852:     return;
 853:     }
 854: 
 855:     if (nMsgs >= n)
 856:     return;
 857: 
 858:     nMsgs = n + MAXFOLDER / 2;
 859:     Msgs = (struct Msg *) realloc ((char *) Msgs,
 860:                         (unsigned) (nMsgs + 2) * sizeof *Msgs);
 861:     if (Msgs == NULL)
 862:     padios (NULLCP, "unable to reallocate Msgs structure");
 863: }
 864: 
 865: /*  */
 866: 
 867: FILE   *msh_ready (msgnum, full)
 868: register int msgnum;
 869: int full;
 870: {
 871:     register int    msgp;
 872:     int     fd;
 873:     long    pos1,
 874:             pos2;
 875:     char   *cp,
 876:             tmpfil[BUFSIZ];
 877: 
 878:     if (yp) {
 879:     (void) fclose (yp);
 880:     yp = NULL;
 881:     }
 882: 
 883:     if (fmsh) {
 884:     if ((fd = Msgs[msgnum].m_top) == NOTOK) {
 885:         if (numfds >= maxfds)
 886:         for (msgp = mp -> lowmsg; msgp <= mp -> hghmsg; msgp++)
 887:             if (Msgs[msgp].m_top != NOTOK) {
 888:             (void) close (Msgs[msgp].m_top);
 889:             Msgs[msgp].m_top = NOTOK;
 890:             numfds--;
 891:             break;
 892:             }
 893: 
 894:         if ((fd = open (cp = m_name (msgnum), 0)) == NOTOK)
 895:         padios (cp, "unable to open message");
 896:         Msgs[msgnum].m_top = fd;
 897:         numfds++;
 898:     }
 899: 
 900:     if ((fd = dup (fd)) == NOTOK)
 901:         padios ("cached message", "unable to dup");
 902:     if ((yp = fdopen (fd, "r")) == NULL)
 903:         padios (NULLCP, "unable to fdopen cached message");
 904:     (void) fseek (yp, 0L, 0);
 905:     return yp;
 906:     }
 907: 
 908: #ifdef  BPOP
 909:     if (pmsh && (mp -> msgstats[msgnum] & VIRTUAL)) {
 910:     if (Msgs[msgnum].m_top == 0)
 911:         padios (NULLCP, "msh_ready (%d, %d) botch", msgnum, full);
 912:     if (!full) {
 913:         (void) strcpy (tmpfil, m_tmpfil (invo_name));
 914:         if ((yp = fopen (tmpfil, "w+")) == NULL)
 915:         padios (tmpfil, "unable to create");
 916:         (void) unlink (tmpfil);
 917: 
 918:         if (pop_top (Msgs[msgnum].m_top, 4, pop_action) == NOTOK)
 919:         padios (NULLCP, "%s", response);
 920: 
 921:         m_eomsbr ((int (*)()) 0);   /* XXX */
 922:         msg_style = MS_DEFAULT; /*  .. */
 923:         (void) fseek (yp, 0L, 0);
 924:         return yp;
 925:     }
 926: 
 927:     (void) fseek (fp, 0L, 2);
 928:     (void) fwrite (mmdlm1, 1, strlen (mmdlm1), fp);
 929:     if (fflush (fp))
 930:         padios ("temporary file", "write error on");
 931:     (void) fseek (fp, 0L, 2);
 932:     pos1 = ftell (fp);
 933: 
 934:     yp = fp;
 935:     if (pop_retr (Msgs[msgnum].m_top, pop_action) == NOTOK)
 936:         padios (NULLCP, "%s", response);
 937:     yp = NULL;
 938: 
 939:     (void) fseek (fp, 0L, 2);
 940:     pos2 = ftell (fp);
 941:     (void) fwrite (mmdlm2, 1, strlen (mmdlm2), fp);
 942:     if (fflush (fp))
 943:         padios ("temporary file", "write error on");
 944: 
 945:     Msgs[msgnum].m_start = pos1;
 946:     Msgs[msgnum].m_stop = pos2;
 947: 
 948:     mp -> msgstats[msgnum] &= ~VIRTUAL;
 949:     }
 950: #endif	BPOP
 951: 
 952:     m_eomsbr ((int (*)()) 0);   /* XXX */
 953:     (void) fseek (fp, Msgs[msgnum].m_start, 0);
 954:     return fp;
 955: }
 956: 
 957: /*  */
 958: 
 959: static int  check_folder (scansw)
 960: int     scansw;
 961: {
 962:     int     flags,
 963:             i,
 964:             low,
 965:             hgh,
 966:             msgp;
 967:     struct stat st;
 968: 
 969: #ifdef  BPOP
 970:     if (pmsh)
 971:     return 0;
 972: #endif	BPOP
 973: 
 974:     if (fmsh) {
 975:     if (stat (mp -> foldpath, &st) == NOTOK)
 976:         padios (mp -> foldpath, "unable to stat");
 977:     if (mtime == st.st_mtime)
 978:         return 0;
 979:     mtime = st.st_mtime;
 980: 
 981:     low = mp -> hghmsg + 1;
 982:     m_fmsg (mp);
 983: 
 984:     if (!(mp = m_gmsg (fmsh)))
 985:         padios (NULLCP, "unable to re-read folder %s", fmsh);
 986: 
 987:     hgh = mp -> hghmsg;
 988: 
 989:     for (msgp = mp -> lowmsg; msgp <= mp -> hghmsg; msgp++) {
 990:         if (Msgs[msgp].m_top != NOTOK) {
 991:         (void) close (Msgs[msgp].m_top);
 992:         Msgs[msgp].m_top = NOTOK;
 993:         numfds--;
 994:         }
 995:         if (Msgs[msgp].m_scanl) {
 996:         free (Msgs[msgp].m_scanl);
 997:         Msgs[msgp].m_scanl = NULL;
 998:         }
 999:     }
1000: 
1001:     m_init ();
1002: 
1003:     if (modified || low > hgh)
1004:         return 1;
1005:     goto check_vmh;
1006:     }
1007:     if (fstat (fileno (fp), &st) == NOTOK)
1008:     padios (mp -> foldpath, "unable to fstat");
1009:     if (mtime == st.st_mtime)
1010:     return 0;
1011:     mode = (int) (st.st_mode & 0777);
1012:     mtime = st.st_mtime;
1013: 
1014:     if ((msgp = read_file (Msgs[mp -> hghmsg].m_stop, mp -> hghmsg + 1)) < 1)
1015:     padios (NULLCP, "no messages in %s", mp -> foldpath);   /* XXX */
1016:     if (msgp >= MAXFOLDER)
1017:     padios (NULLCP, "more than %d messages in %s", MAXFOLDER,
1018:         mp -> foldpath);
1019:     if (msgp <= mp -> hghmsg)
1020:     return 0;       /* XXX */
1021: 
1022:     if ((mp = m_remsg (mp, 0, msgp)) == NULL)
1023:     padios (NULLCP, "unable to allocate folder storage");
1024: 
1025:     low = mp -> hghmsg + 1, hgh = msgp;
1026:     flags = scansw ? m_seqflag (mp, "unseen") : 0;
1027:     for (i = mp -> hghmsg + 1; i <= msgp; i++) {
1028:     mp -> msgstats[i] = EXISTS | flags;
1029:     mp -> nummsg++;
1030:     }
1031:     mp -> hghmsg = msgp;
1032:     m_init ();
1033: 
1034: check_vmh: ;
1035:     if (vmh)
1036:     return 1;
1037: 
1038:     advise (NULLCP, "new messages have arrived!\007");
1039:     if (scansw)
1040:     scanrange (low, hgh);
1041: 
1042:     return 1;
1043: }
1044: 
1045: /*  */
1046: 
1047: static  scanrange (low, hgh)
1048: int low,
1049:     hgh;
1050: {
1051:     char    buffer[BUFSIZ];
1052: 
1053:     (void) sprintf (buffer, "%d-%d", low, hgh);
1054:     scanstring (buffer);
1055: }
1056: 
1057: 
1058: static  scanstring (arg)
1059: char   *arg;
1060: {
1061:     char   *cp,
1062:           **ap,
1063:            *vec[MAXARGS];
1064: 
1065:     if ((cp = m_find (cmd_name = "scan")) != NULL) {
1066:     ap = brkstring (cp = getcpy (cp), " ", "\n");
1067:     ap = copyip (ap, vec);
1068:     }
1069:     else
1070:     ap = vec;
1071:     *ap++ = arg;
1072:     *ap = NULL;
1073:     m_init ();
1074:     scancmd (vec);
1075:     if (cp != NULL)
1076:     free (cp);
1077: }
1078: 
1079: /*  */
1080: 
1081: readids (id)
1082: int     id;
1083: {
1084:     register int    cur,
1085:                     flags,
1086:                     i,
1087:                     msgnum;
1088: 
1089:     if (mp -> curmsg == 0)
1090:     m_setcur (mp, mp -> lowmsg);
1091:     if (id <= 0 || (flags = m_seqflag (mp, "unseen")) == 0)
1092:     return;
1093: 
1094:     for (msgnum = mp -> hghmsg; msgnum >= mp -> lowmsg; msgnum--)
1095:     mp -> msgstats[msgnum] |= flags;
1096: 
1097:     if (id != 1) {
1098:     cur = mp -> curmsg;
1099: 
1100:     for (msgnum = mp -> hghmsg; msgnum >= mp -> lowmsg; msgnum--)
1101:         if ((i = readid (msgnum)) > 0 && i < id) {
1102:         cur = msgnum + 1;
1103:         mp -> msgstats[msgnum] &= ~flags;
1104:         break;
1105:         }
1106:     for (i = mp -> lowmsg; i < msgnum; i++)
1107:         mp -> msgstats[i] &= ~flags;
1108: 
1109:     if (cur > mp -> hghmsg)
1110:         cur = mp -> hghmsg;
1111: 
1112:     m_setcur (mp, cur);
1113:     }
1114: 
1115:     if ((gap = 1 < id && id < (i = readid (mp -> lowmsg)) ? id : 0) && !vmh)
1116:     advise (NULLCP, "gap in ID:s, last seen %d, lowest present %d\n",
1117:         id - 1, i);
1118: }
1119: 
1120: /*  */
1121: 
1122: int     readid (msgnum)
1123: int     msgnum;
1124: {
1125:     int     i,
1126:             state;
1127: #ifdef  BPOP
1128:     int     arg1,
1129:         arg2,
1130:         arg3;
1131: #endif	BPOP
1132:     char   *bp,
1133:             buf[BUFSIZ],
1134:             name[NAMESZ];
1135:     register FILE *zp;
1136: 
1137:     if (Msgs[msgnum].m_bboard_id)
1138:     return Msgs[msgnum].m_bboard_id;
1139: #ifdef  BPOP
1140:     if (pmsh) {
1141:     if (Msgs[msgnum].m_top == 0)
1142:         padios (NULLCP, "readid (%d) botch", msgnum);
1143:     if (pop_list (Msgs[msgnum].m_top, (int *) 0, &arg1, &arg2, &arg3) == OK
1144:         && arg3 > 0)
1145:         return (Msgs[msgnum].m_bboard_id = arg3);
1146:     }
1147: #endif	BPOP
1148: 
1149:     zp = msh_ready (msgnum, 0);
1150:     for (state = FLD;;)
1151:     switch (state = m_getfld (state, name, buf, sizeof buf, zp)) {
1152:         case FLD:
1153:         case FLDEOF:
1154:         case FLDPLUS:
1155:         if (uleq (name, BBoard_ID)) {
1156:             bp = getcpy (buf);
1157:             while (state == FLDPLUS) {
1158:             state = m_getfld (state, name, buf, sizeof buf, zp);
1159:             bp = add (buf, bp);
1160:             }
1161:             i = atoi (bp);
1162:             free (bp);
1163:             if (i > 0)
1164:             return (Msgs[msgnum].m_bboard_id = i);
1165:             else
1166:             continue;
1167:         }
1168:         while (state == FLDPLUS)
1169:             state = m_getfld (state, name, buf, sizeof buf, zp);
1170:         if (state != FLDEOF)
1171:             continue;
1172: 
1173:         default:
1174:         return 0;
1175:     }
1176: }
1177: 
1178: /*  */
1179: 
1180: display_info (scansw)
1181: int     scansw;
1182: {
1183:     int     flags,
1184:             sd;
1185: 
1186:     interactive = isatty (fileno (stdout));
1187:     if (sp == NULL) {
1188:     if ((sd = dup (fileno (stdout))) == NOTOK)
1189:         padios ("standard output", "unable to dup");
1190: #ifndef BSD42           /* XXX */
1191: #ifdef  FIOCLEX
1192:     (void) ioctl (sd, FIOCLEX, NULL);
1193: #endif	FIOCLEX
1194: #endif	not BSD42
1195:     if ((sp = fdopen (sd, "w")) == NULL)
1196:         padios ("standard output", "unable to fdopen");
1197:     }
1198: 
1199:     (void) putenv ("mhfolder", mp -> foldpath);
1200:     if (vmh)
1201:     return;
1202: 
1203:     if (myname) {
1204:     printf ("Reading ");
1205:     if (SOprintf ("%s", myname))
1206:         printf ("%s", myname);
1207:     printf (", currently at message %d of %d\n",
1208:         mp -> curmsg, mp -> hghmsg);
1209:     }
1210:     else {
1211:     printf ("Reading ");
1212:     if (fmsh)
1213:         printf ("+%s", fmsh);
1214:     else
1215:         printf ("%s", mp -> foldpath);
1216:     printf (", currently at message %d of %d\n",
1217:         mp -> curmsg, mp -> hghmsg);
1218:     }
1219: 
1220:     if ((flags = m_seqflag (mp, "unseen"))
1221:         && scansw
1222:         && (mp -> msgstats[mp -> hghmsg] & flags))
1223:     scanstring ("unseen");
1224: }
1225: 
1226: /*  */
1227: 
1228: static  write_ids () {
1229:     int     i = 0,
1230:         flags,
1231:             msgnum;
1232:     char    buffer[80];
1233: 
1234:     if (pfd <= 1)
1235:     return;
1236: 
1237:     if (flags = m_seqflag (mp, "unseen"))
1238:     for (msgnum = mp -> hghmsg; msgnum >= mp -> lowmsg; msgnum--)
1239:         if (!(mp -> msgstats[msgnum] & flags)) {
1240:         if (Msgs[msgnum].m_bboard_id == 0)
1241:             (void) readid (msgnum);
1242:         if ((i = Msgs[msgnum].m_bboard_id) > 0)
1243:             break;
1244:         }
1245: 
1246:     (void) sprintf (buffer, "%d %d\n", i, Msgs[mp -> hghmsg].m_bboard_id);
1247:     (void) write (pfd, buffer, sizeof buffer);
1248:     (void) close (pfd);
1249:     pfd = NOTOK;
1250: }
1251: 
1252: /*  */
1253: 
1254: static  quit () {
1255:     int     i,
1256:             md,
1257:             msgnum;
1258:     char   *cp,
1259:             tmpfil[BUFSIZ],
1260:             map1[BUFSIZ],
1261:             map2[BUFSIZ];
1262:     struct stat st;
1263:     FILE   *dp;
1264: 
1265:     if (!(mp -> msgflags & MODIFIED) || mp -> msgflags & READONLY || fmsh) {
1266:         if (vmh)
1267:         (void) rc2peer (RC_FIN, 0, NULLCP);
1268:     return;
1269:     }
1270: 
1271:     if (vmh)
1272:     (void) ttyNaux (NULLCMD, "FAST");
1273:     cp = NULL;
1274:     if ((dp = lkfopen (mp -> foldpath, "r")) == NULL) {
1275:     advise (mp -> foldpath, "unable to lock");
1276:     if (vmh) {
1277:         (void) ttyR (NULLCMD);
1278:         (void) pFIN ();
1279:     }
1280:     return;
1281:     }
1282:     if (fstat (fileno (dp), &st) == NOTOK) {
1283:     advise (mp -> foldpath, "unable to stat");
1284:     goto release;
1285:     }
1286:     if (mtime != st.st_mtime) {
1287:     advise (NULLCP, "new messages have arrived, no update");
1288:     goto release;
1289:     }
1290:     mode = (int) (st.st_mode & 0777);
1291: 
1292:     if (mp -> nummsg == 0) {
1293:     cp = concat ("Zero file \"", mp -> foldpath, "\"? ", NULLCP);
1294:     if (getanswer (cp)) {
1295:         if ((i = creat (mp -> foldpath, mode)) != NOTOK)
1296:         (void) close (i);
1297:         else
1298:         advise (mp -> foldpath, "error zero'ing");
1299:         (void) unlink (map_name (mp -> foldpath));/* XXX */
1300:     }
1301:     goto release;
1302:     }
1303: 
1304:     cp = concat ("Update file \"", mp -> foldpath, "\"? ", NULLCP);
1305:     if (!getanswer (cp))
1306:     goto release;
1307:     (void) strcpy (tmpfil, m_backup (mp -> foldpath));
1308:     if ((md = mbx_open (tmpfil, st.st_uid, st.st_gid, mode)) == NOTOK) {
1309:     advise (tmpfil, "unable to open");
1310:     goto release;
1311:     }
1312: 
1313:     for (msgnum = mp -> lowmsg; msgnum <= mp -> hghmsg; msgnum++)
1314:     if (mp -> msgstats[msgnum] & EXISTS
1315:         && pack (tmpfil, md, msgnum) == NOTOK) {
1316:         (void) mbx_close (tmpfil, md);
1317:         (void) unlink (tmpfil);
1318:         (void) unlink (map_name (tmpfil));
1319:         goto release;
1320:     }
1321:     (void) mbx_close (tmpfil, md);
1322: 
1323:     if (rename (tmpfil, mp -> foldpath) == NOTOK)
1324:     admonish (mp -> foldpath, "unable to rename %s to", tmpfil);
1325:     else {
1326:     (void) strcpy (map1, map_name (tmpfil));
1327:     (void) strcpy (map2, map_name (mp -> foldpath));
1328: 
1329:     if (rename (map1, map2) == NOTOK) {
1330:         admonish (map2, "unable to rename %s to", map1);
1331:         (void) unlink (map1);
1332:         (void) unlink (map2);
1333:     }
1334:     }
1335: 
1336: release: ;
1337:     if (cp)
1338:     free (cp);
1339:     (void) lkfclose (dp, mp -> foldpath);
1340:     if (vmh) {
1341:     (void) ttyR (NULLCMD);
1342:     (void) pFIN ();
1343:     }
1344: }
1345: 
1346: /*  */
1347: 
1348: static int  getargs (prompt, sw, cmdp)
1349: char   *prompt;
1350: struct swit *sw;
1351: struct Cmd *cmdp;
1352: {
1353:     int     i;
1354:     char   *cp;
1355:     static char buffer[BUFSIZ];
1356: 
1357:     told_to_quit = 0;
1358:     for (;;) {
1359:     interrupted = 0;
1360: #ifdef  BSD42
1361:     switch (setjmp (sigenv)) {
1362:         case OK:
1363:         should_intr = 1;
1364:         break;
1365: 
1366:         default:
1367:         should_intr = 0;
1368:         if (interrupted && !told_to_quit) {
1369:             (void) putchar ('\n');
1370:             continue;
1371:         }
1372:         if (ppid > 0)
1373:             (void) kill (ppid, SIGEMT);
1374:         return EOF;
1375:     }
1376: #endif	BSD42
1377:     if (interactive) {
1378:         printf ("%s", prompt);
1379:         (void) fflush (stdout);
1380:     }
1381:     for (cp = buffer; (i = getchar ()) != '\n';) {
1382: #ifndef BSD42
1383:         if (interrupted && !told_to_quit) {
1384:         buffer[0] = NULL;
1385:         (void) putchar ('\n');
1386:         break;
1387:         }
1388:         if (told_to_quit || i == EOF) {
1389:         if (ppid > 0)
1390:             (void) kill (ppid, SIGEMT);
1391:         return EOF;
1392:         }
1393: #else   BSD42
1394:         if (i == EOF)
1395:         longjmp (sigenv, DONE);
1396: #endif	BSD42
1397:         if (cp < &buffer[sizeof buffer - 2])
1398:         *cp++ = i;
1399:     }
1400:     *cp = NULL;
1401: 
1402:     if (buffer[0] == NULL)
1403:         continue;
1404:     if (buffer[0] == '?') {
1405:         printf ("commands:\n");
1406:         printsw (ALL, sw, "");
1407:         printf ("type CTRL-D or use ``quit'' to leave %s\n",
1408:             invo_name);
1409:         continue;
1410:     }
1411: 
1412:     if (parse (buffer, cmdp) == NOTOK)
1413:         continue;
1414: 
1415:     switch (i = smatch (cmdp -> args[0], sw)) {
1416:         case AMBIGSW:
1417:         ambigsw (cmdp -> args[0], sw);
1418:         continue;
1419:         case UNKWNSW:
1420:         printf ("say what: ``%s'' -- type ? (or help) for help\n",
1421:             cmdp -> args[0]);
1422:         continue;
1423:         default:
1424: #ifdef  BSD42
1425:         should_intr = 0;
1426: #endif	BSD42
1427:         return i;
1428:     }
1429:     }
1430: }
1431: 
1432: /*  */
1433: 
1434: static int  getcmds (sw, cmdp, scansw)
1435: struct swit *sw;
1436: struct Cmd *cmdp;
1437: int scansw;
1438: {
1439:     int     i;
1440:     struct record   rcs,
1441:                    *rc = &rcs;
1442: 
1443:     initrc (rc);
1444: 
1445:     for (;;)
1446:     switch (peer2rc (rc)) {
1447:         case RC_QRY:
1448:         (void) pQRY (rc -> rc_data, scansw);
1449:         break;
1450: 
1451:         case RC_CMD:
1452:         if ((i = pCMD (rc -> rc_data, sw, cmdp)) != NOTOK)
1453:             return i;
1454:         break;
1455: 
1456:         case RC_FIN:
1457:         if (ppid > 0)
1458:             (void) kill (ppid, SIGEMT);
1459:         return EOF;
1460: 
1461:         case RC_XXX:
1462:         padios (NULLCP, "%s", rc -> rc_data);
1463: 
1464:         default:
1465:         (void) fmt2peer (RC_ERR, "pLOOP protocol screw-up");
1466:         done (1);
1467:     }
1468: }
1469: 
1470: /*  */
1471: 
1472: static int  parse (buffer, cmdp)
1473: char   *buffer;
1474: struct Cmd *cmdp;
1475: {
1476:     int     argp = 0;
1477:     char    c,
1478:            *cp,
1479:            *pp;
1480: 
1481:     cmdp -> line[0] = NULL;
1482:     pp = cmdp -> args[argp++] = cmdp -> line;
1483:     cmdp -> redirect = NULL;
1484:     cmdp -> direction = STDIO;
1485:     cmdp -> stream = NULL;
1486: 
1487:     for (cp = buffer; c = *cp; cp++)
1488:     if (!isspace (c))
1489:         break;
1490:     if (c == NULL) {
1491:     if (vmh)
1492:         (void) fmt2peer (RC_EOF, "null command");
1493:     return NOTOK;
1494:     }
1495: 
1496:     while (c = *cp++) {
1497:     if (isspace (c)) {
1498:         while (isspace (c))
1499:         c = *cp++;
1500:         if (c == NULL)
1501:         break;
1502:         *pp++ = NULL;
1503:         cmdp -> args[argp++] = pp;
1504:         *pp = NULL;
1505:     }
1506: 
1507:     switch (c) {
1508:         case '"':
1509:         for (;;) {
1510:             switch (c = *cp++) {
1511:             case NULL:
1512:                 padvise (NULLCP, "unmatched \"");
1513:                 return NOTOK;
1514:             case '"':
1515:                 break;
1516:             case QUOTE:
1517:                 if ((c = *cp++) == NULL)
1518:                 goto no_quoting;
1519:             default:
1520:                 *pp++ = c;
1521:                 continue;
1522:             }
1523:             break;
1524:         }
1525:         continue;
1526: 
1527:         case QUOTE:
1528:         if ((c = *cp++) == NULL) {
1529:         no_quoting: ;
1530:             padvise (NULLCP, "the newline character can not be quoted");
1531:             return NOTOK;
1532:         }
1533: 
1534:         default: ;
1535:         *pp++ = c;
1536:         continue;
1537: 
1538:         case '>':
1539:         case '|':
1540:         if (pp == cmdp -> line) {
1541:             padvise (NULLCP, "invalid null command");
1542:             return NOTOK;
1543:         }
1544:         if (*cmdp -> args[argp - 1] == NULL)
1545:             argp--;
1546:         cmdp -> direction = c == '>' ? CRTIO : PIPIO;
1547:         if (cmdp -> direction == CRTIO && (c = *cp) == '>') {
1548:             cmdp -> direction = APPIO;
1549:             cp++;
1550:         }
1551:         cmdp -> redirect = pp + 1;/* sigh */
1552:         for (; c = *cp; cp++)
1553:             if (!isspace (c))
1554:             break;
1555:         if (c == NULL) {
1556:             padvise (NULLCP, cmdp -> direction != PIPIO
1557:                 ? "missing name for redirect"
1558:                 : "invalid null command");
1559:             return NOTOK;
1560:         }
1561:         (void) strcpy (cmdp -> redirect, cp);
1562:         if (cmdp -> direction != PIPIO) {
1563:             for (; *cp; cp++)
1564:             if (isspace (*cp)) {
1565:                 padvise (NULLCP, "bad name for redirect");
1566:                 return NOTOK;
1567:             }
1568:             if (expand (cmdp -> redirect) == NOTOK)
1569:             return NOTOK;
1570:         }
1571:         break;
1572:     }
1573:     break;
1574:     }
1575: 
1576:     *pp++ = NULL;
1577:     cmdp -> args[argp] = NULL;
1578: 
1579:     return OK;
1580: }
1581: 
1582: /*  */
1583: 
1584: int expand (redirect)
1585: char   *redirect;
1586: {
1587:     char   *cp,
1588:            *pp;
1589:     char    path[BUFSIZ];
1590:     struct passwd  *pw;
1591: 
1592:     if (*redirect != '~')
1593:     return OK;
1594: 
1595:     if (cp = index (pp = redirect + 1, '/'))
1596:     *cp++ = NULL;
1597:     if (*pp == NULL)
1598:     pp = mypath;
1599:     else
1600:     if (pw = getpwnam (pp))
1601:         pp = pw -> pw_dir;
1602:     else {
1603:         padvise (NULLCP, "unknown user: %s", pp);
1604:         return NOTOK;
1605:     }
1606: 
1607:     (void) sprintf (path, "%s/%s", pp, cp ? cp : "");
1608:     (void) strcpy (redirect, path);
1609:     return OK;
1610: }
1611: 
1612: /*  */
1613: 
1614: static int  init_io (cmdp, vio)
1615: register struct Cmd *cmdp;
1616: int vio;
1617: {
1618:     int     io,
1619:             result;
1620: 
1621:     io = vmh;
1622: 
1623:     vmh = vio;
1624:     result = initaux_io (cmdp);
1625:     vmh = io;
1626: 
1627:     return result;
1628: }
1629: 
1630: 
1631: static int  initaux_io (cmdp)
1632: register struct Cmd *cmdp;
1633: {
1634:     char   *mode;
1635: 
1636:     switch (cmdp -> direction) {
1637:     case STDIO:
1638:         return OK;
1639: 
1640:     case CRTIO:
1641:     case APPIO:
1642:         mode = cmdp -> direction == CRTIO ? "write" : "append";
1643:         if ((cmdp -> stream = fopen (cmdp -> redirect, mode)) == NULL) {
1644:         padvise (cmdp -> redirect, "unable to %s ", mode);
1645:         cmdp -> direction = STDIO;
1646:         return NOTOK;
1647:         }
1648:         break;
1649: 
1650:     case PIPIO:
1651:         if ((cmdp -> stream = popen (cmdp -> redirect, "w")) == NULL) {
1652:         padvise (cmdp -> redirect, "unable to pipe");
1653:         cmdp -> direction = STDIO;
1654:         return NOTOK;
1655:         }
1656:         (void) signal (SIGPIPE, pipeser);
1657:         broken_pipe = 0;
1658:         break;
1659: 
1660:     default:
1661:         padios (NULLCP, "unknown redirection for command");
1662:     }
1663: 
1664:     (void) fflush (stdout);
1665:     if (dup2 (fileno (cmdp -> stream), fileno (stdout)) == NOTOK)
1666:     padios ("standard output", "unable to dup2");
1667:     clearerr (stdout);
1668: 
1669:     return OK;
1670: }
1671: 
1672: /*  */
1673: 
1674: static  fin_io (cmdp, vio)
1675: register struct Cmd *cmdp;
1676: int vio;
1677: {
1678:     int     io;
1679: 
1680:     io = vmh;
1681: 
1682:     vmh = vio;
1683:     finaux_io (cmdp);
1684:     vmh = io;
1685: }
1686: 
1687: 
1688: static int  finaux_io (cmdp)
1689: register struct Cmd *cmdp;
1690: {
1691:     switch (cmdp -> direction) {
1692:     case STDIO:
1693:         return;
1694: 
1695:     case CRTIO:
1696:     case APPIO:
1697:         (void) fflush (stdout);
1698:         (void) close (fileno (stdout));
1699:         if (ferror (stdout))
1700:         padvise (NULLCP, "problems writing %s", cmdp -> redirect);
1701:         (void) fclose (cmdp -> stream);
1702:         break;
1703: 
1704:     case PIPIO:
1705:         (void) fflush (stdout);
1706:         (void) close (fileno (stdout));
1707:         (void) pclose (cmdp -> stream);
1708:         (void) signal (SIGPIPE, SIG_DFL);
1709:         break;
1710: 
1711:     default:
1712:         padios (NULLCP, "unknown redirection for command");
1713:     }
1714: 
1715:     if (dup2 (fileno (sp), fileno (stdout)) == NOTOK)
1716:     padios ("standard output", "unable to dup2");
1717:     clearerr (stdout);
1718: 
1719:     cmdp -> direction = STDIO;
1720: }
1721: 
1722: /*  */
1723: 
1724: static  m_init () {
1725:     int     msgnum;
1726: 
1727:     for (msgnum = mp -> lowmsg; msgnum <= mp -> hghmsg; msgnum++)
1728:     mp -> msgstats[msgnum] &= ~SELECTED;
1729:     mp -> lowsel = mp -> hghsel = mp -> numsel = 0;
1730: }
1731: 
1732: 
1733: m_reset () {
1734:     write_ids ();
1735:     m_fmsg (mp);
1736:     myname = NULL;
1737: #ifdef  BPOP
1738:     if (pmsh) {
1739:     (void) pop_done ();
1740:     pmsh = 0;
1741:     }
1742: #endif	BPOP
1743: }
1744: 
1745: /*  */
1746: 
1747: void    m_setcur (mp, msgnum)
1748: register struct msgs *mp;
1749: register int msgnum;
1750: {
1751:     if (mp -> curmsg == msgnum)
1752:     return;
1753: 
1754:     if (mp -> curmsg && Msgs[mp -> curmsg].m_scanl) {
1755:     free (Msgs[mp -> curmsg].m_scanl);
1756:     Msgs[mp -> curmsg].m_scanl = NULL;
1757:     }
1758:     if (Msgs[msgnum].m_scanl) {
1759:     free (Msgs[msgnum].m_scanl);
1760:     Msgs[msgnum].m_scanl = NULL;
1761:     }
1762: 
1763:     mp -> curmsg = msgnum;
1764: }
1765: 
1766: /*  */
1767: 
1768: /* ARGSUSED */
1769: 
1770: static int  intrser (i)
1771: int     i;
1772: {
1773: #ifndef BSD42
1774:     (void) signal (SIGINT, intrser);
1775: #endif	not BSD42
1776: 
1777:     discard (stdout);
1778: 
1779:     interrupted++;
1780: #ifdef  BSD42
1781:     if (should_intr)
1782:     longjmp (sigenv, NOTOK);
1783: #endif	BSD42
1784: }
1785: 
1786: 
1787: /* ARGSUSED */
1788: 
1789: static int  pipeser (i)
1790: int     i;
1791: {
1792: #ifndef BSD42
1793:     (void) signal (SIGPIPE, pipeser);
1794: #endif	not BSD42
1795: 
1796:     if (broken_pipe++ == 0)
1797:     fprintf (stderr, "broken pipe\n");
1798:     told_to_quit++;
1799:     interrupted++;
1800: #ifdef  BSD42
1801:     if (should_intr)
1802:     longjmp (sigenv, NOTOK);
1803: #endif	BSD42
1804: }
1805: 
1806: 
1807: /* ARGSUSED */
1808: 
1809: static int  quitser (i)
1810: int     i;
1811: {
1812: #ifndef BSD42
1813:     (void) signal (SIGQUIT, quitser);
1814: #endif	BSD42
1815: 
1816:     told_to_quit++;
1817:     interrupted++;
1818: #ifdef  BSD42
1819:     if (should_intr)
1820:     longjmp (sigenv, NOTOK);
1821: #endif	BSD42
1822: }
1823: 
1824: /*  */
1825: 
1826: static int  pINI () {
1827:     int     i,
1828:             vrsn;
1829:     char   *bp;
1830:     struct record   rcs,
1831:                    *rc = &rcs;
1832: 
1833:     initrc (rc);
1834: 
1835:     switch (peer2rc (rc)) {
1836:     case RC_INI:
1837:         bp = rc -> rc_data;
1838:         while (isspace (*bp))
1839:         bp++;
1840:         if (sscanf (bp, "%d", &vrsn) != 1) {
1841:     bad_init: ;
1842:         (void) fmt2peer (RC_ERR, "bad init \"%s\"", rc -> rc_data);
1843:         done (1);
1844:         }
1845:         if (vrsn != RC_VRSN) {
1846:         (void) fmt2peer (RC_ERR, "version %d unsupported", vrsn);
1847:         done (1);
1848:         }
1849: 
1850:         while (*bp && !isspace (*bp))
1851:         bp++;
1852:         while (isspace (*bp))
1853:         bp++;
1854:         if (sscanf (bp, "%d", &numwins) != 1 || numwins <= 0)
1855:         goto bad_init;
1856:         if (numwins > NWIN)
1857:         numwins = NWIN;
1858: 
1859:         for (i = 1; i <= numwins; i++) {
1860:         while (*bp && !isspace (*bp))
1861:             bp++;
1862:         while (isspace (*bp))
1863:             bp++;
1864:         if (sscanf (bp, "%d", &windows[i]) != 1 || windows[i] <= 0)
1865:             goto bad_init;
1866:         }
1867:         (void) rc2peer (RC_ACK, 0, NULLCP);
1868:         return OK;
1869: 
1870:     case RC_XXX:
1871:         padios (NULLCP, "%s", rc -> rc_data);
1872: 
1873:     default:
1874:         (void) fmt2peer (RC_ERR, "pINI protocol screw-up");
1875:         done (1);       /* NOTREACHED */
1876:     }
1877: }
1878: 
1879: /*  */
1880: 
1881: /* ARGSUSED */
1882: 
1883: static int  pQRY (str, scansw)
1884: char   *str;
1885: int scansw;
1886: {
1887:     if (pQRY1 (scansw) == NOTOK || pQRY2 () == NOTOK)
1888:     return NOTOK;
1889: 
1890:     (void) rc2peer (RC_EOF, 0, NULLCP);
1891:     return OK;
1892: }
1893: 
1894: /*  */
1895: 
1896: static int  pQRY1 (scansw)
1897: int scansw;
1898: {
1899:     int     oldhgh;
1900:     static int  lastlow = 0,
1901:                 lastcur = 0,
1902:                 lasthgh = 0,
1903:         lastnum = 0;
1904: 
1905:     oldhgh = mp -> hghmsg;
1906:     if (check_folder (scansw) && oldhgh < mp -> hghmsg) {
1907:     switch (winX (STATUS)) {
1908:         case NOTOK:
1909:         return NOTOK;
1910: 
1911:         case OK:
1912:         printf ("new messages have arrived!");
1913:         (void) fflush (stdout);
1914:         (void) fflush (stderr);
1915:         _exit (0);  /* NOTREACHED */
1916: 
1917:         default:
1918:         lastlow = lastcur = lasthgh = lastnum = 0;
1919:         break;
1920:     }
1921: 
1922:     switch (winX (DISPLAY)) {
1923:         case NOTOK:
1924:         return NOTOK;
1925: 
1926:         case OK:
1927:         scanrange (oldhgh + 1, mp -> hghmsg);
1928:         (void) fflush (stdout);
1929:         (void) fflush (stderr);
1930:         _exit (0);  /* NOTREACHED */
1931: 
1932:         default:
1933:         break;
1934:     }
1935:     return OK;
1936:     }
1937: 
1938:     if (gap)
1939:     switch (winX (STATUS)) {
1940:         case NOTOK:
1941:         return NOTOK;
1942: 
1943:         case OK:
1944:         printf ("%s: gap in ID:s, last seen %d, lowest present %d\n",
1945:             myname ? myname : fmsh ? fmsh : mp -> foldpath, gap - 1,
1946:             readid (mp -> lowmsg));
1947:         (void) fflush (stdout);
1948:         (void) fflush (stderr);
1949:         _exit (0);  /* NOTREACHED */
1950: 
1951:         default:
1952:         gap = 0;
1953:         return OK;
1954:     }
1955: 
1956:     if (mp -> lowmsg != lastlow
1957:         || mp -> curmsg != lastcur
1958:         || mp -> hghmsg != lasthgh
1959:         || mp -> nummsg != lastnum)
1960:     switch (winX (STATUS)) {
1961:         case NOTOK:
1962:         return NOTOK;
1963: 
1964:         case OK:
1965:         foldcmd (NULLVP);
1966:         (void) fflush (stdout);
1967:         (void) fflush (stderr);
1968:         _exit (0);  /* NOTREACHED */
1969: 
1970:         default:
1971:         lastlow = mp -> lowmsg;
1972:         lastcur = mp -> curmsg;
1973:         lasthgh = mp -> hghmsg;
1974:         lastnum = mp -> nummsg;
1975:         return OK;
1976:     }
1977: 
1978:     return OK;
1979: }
1980: 
1981: /*  */
1982: 
1983: static int  pQRY2 () {
1984:     int     i,
1985:             j,
1986:         k,
1987:             msgnum,
1988:             n;
1989:     static int  cur = 0,
1990:                 num = 0,
1991:         lo = 0,
1992:         hi = 0;
1993: 
1994:     if (mp -> nummsg == 0 && mp -> nummsg != num)
1995:     switch (winX (SCAN)) {
1996:         case NOTOK:
1997:         return NOTOK;
1998: 
1999:         case OK:
2000:         printf ("empty!");
2001:         (void) fflush (stdout);
2002:         (void) fflush (stderr);
2003:         _exit (0);  /* NOTREACHED */
2004: 
2005:         default:
2006:         num = mp -> nummsg;
2007:         return OK;
2008:     }
2009:     num = mp -> nummsg;
2010: 
2011:     i = 0;
2012:     j = (k = windows[SCAN]) / 2;
2013:     for (msgnum = mp -> curmsg; msgnum <= mp -> hghmsg; msgnum++)
2014:     if (mp -> msgstats[msgnum] & EXISTS)
2015:         i++;
2016:     if (i-- > 0)
2017:     if (topcur)
2018:         k = i >= k ? 1 : k - i;
2019:     else
2020:         k -= i > j ? j : i;
2021: 
2022:     i = j = 0;
2023:     n = 1;
2024:     for (msgnum = mp -> curmsg; msgnum >= mp -> lowmsg; msgnum--)
2025:     if (mp -> msgstats[msgnum] & EXISTS) {
2026:         i = msgnum;
2027:         if (j == 0)
2028:         j = msgnum;
2029:         if (n++ >= k)
2030:         break;
2031:     }
2032:     for (msgnum = mp -> curmsg + 1; msgnum <= mp -> hghmsg; msgnum++)
2033:     if (mp -> msgstats[msgnum] & EXISTS) {
2034:         if (i == 0)
2035:         i = msgnum;
2036:         j = msgnum;
2037:         if (n++ >= windows[SCAN])
2038:         break;
2039:     }
2040:     if (!topcur
2041:         && lo > 0
2042:         && hi > 0
2043:         && mp -> msgstats[lo] & EXISTS
2044:         && mp -> msgstats[hi] & EXISTS
2045:         && (lo < mp -> curmsg
2046:             || (lo == mp -> curmsg && lo == mp -> lowmsg))
2047:         && (mp -> curmsg < hi
2048:             || (hi == mp -> curmsg && hi == mp -> hghmsg))
2049:         && hi - lo == j - i)
2050:     i = lo, j = hi;
2051: 
2052:     if (mp -> curmsg != cur || modified)
2053:     switch (winN (NULLCMD, SCAN, 0)) {
2054:         case NOTOK:
2055:         return NOTOK;
2056: 
2057:         case OK:
2058:         return OK;
2059: 
2060:         default:
2061:         scanrange (lo = i, hi = j);
2062:         cur = mp -> curmsg;
2063:         (void) winR (NULLCMD);
2064:         return OK;
2065:     }
2066: 
2067:     return OK;
2068: }
2069: 
2070: /*  */
2071: 
2072: static int pCMD (str, sw, cmdp)
2073: char   *str;
2074: struct swit *sw;
2075: struct Cmd *cmdp;
2076: {
2077:     int     i;
2078: 
2079:     if (*str == '?')
2080:     switch (winX (DISPLAY)) {
2081:         case NOTOK:
2082:         return NOTOK;
2083: 
2084:         case OK:
2085:         printf ("commands:\n");
2086:         printsw (ALL, sw, "");
2087:         printf ("type ``quit'' to leave %s\n", invo_name);
2088:         (void) fflush (stdout);
2089:         (void) fflush (stderr);
2090:         _exit (0);  /* NOTREACHED */
2091: 
2092:         default:
2093:         (void) rc2peer (RC_EOF, 0, NULLCP);
2094:         return NOTOK;
2095:     }
2096: 
2097:     if (parse (str, cmdp) == NOTOK)
2098:     return NOTOK;
2099: 
2100:     switch (i = smatch (cmdp -> args[0], sw)) {
2101:     case AMBIGSW:
2102:         switch (winX (DISPLAY)) {
2103:         case NOTOK:
2104:             return NOTOK;
2105: 
2106:         case OK:
2107:             ambigsw (cmdp -> args[0], sw);
2108:             (void) fflush (stdout);
2109:             (void) fflush (stderr);
2110:             _exit (0);  /* NOTREACHED */
2111: 
2112:         default:
2113:             (void) rc2peer (RC_EOF, 0, NULLCP);
2114:             return NOTOK;
2115:         }
2116: 
2117:     case UNKWNSW:
2118:         (void) fmt2peer (RC_ERR,
2119:             "say what: ``%s'' -- type ? (or help) for help",
2120:             cmdp -> args[0]);
2121:         return NOTOK;
2122: 
2123:     default:
2124:         return i;
2125:     }
2126: }
2127: 
2128: /*  */
2129: 
2130: static int  pFIN () {
2131:     int     status;
2132: 
2133:     switch (setjmp (peerenv)) {
2134:     case OK:
2135:         (void) signal (SIGALRM, alrmser);
2136:         (void) alarm (ALARM);
2137: 
2138:         status = peerwait ();
2139: 
2140:         (void) alarm (0);
2141:         return status;
2142: 
2143:     default:
2144:         return NOTOK;
2145:     }
2146: }
2147: 
2148: 
2149: static int  peerwait () {
2150:     struct record   rcs,
2151:                    *rc = &rcs;
2152: 
2153:     initrc (rc);
2154: 
2155:     switch (peer2rc (rc)) {
2156:     case RC_QRY:
2157:     case RC_CMD:
2158:         (void) rc2peer (RC_FIN, 0, NULLCP);
2159:         return OK;
2160: 
2161:     case RC_XXX:
2162:         advise (NULLCP, "%s", rc -> rc_data);
2163:         return NOTOK;
2164: 
2165:     default:
2166:         (void) fmt2peer (RC_FIN, "pLOOP protocol screw-up");
2167:         return NOTOK;
2168:     }
2169: }
2170: 
2171: 
2172: /* ARGSUSED */
2173: 
2174: static int alrmser (i)
2175: int i;
2176: {
2177:     longjmp (peerenv, DONE);
2178: }
2179: 
2180: /*  */
2181: 
2182: static int  ttyNaux (cmdp, s)
2183: register struct Cmd *cmdp;
2184: char   *s;
2185: {
2186:     struct record   rcs,
2187:                    *rc = &rcs;
2188: 
2189:     initrc (rc);
2190: 
2191:     if (cmdp && init_io (cmdp, vmh) == NOTOK)
2192:     return NOTOK;
2193: 
2194:     if (!fmsh)
2195:     (void) fseek (fp, 0L, 0);/* XXX: fseek() too tricky for our own good */
2196: 
2197:     vmhtty = NOTOK;
2198:     switch (rc2rc (RC_TTY, s ? strlen (s) : 0, s, rc)) {
2199:     case RC_ACK:
2200:         vmhtty = OK;    /* fall */
2201:     case RC_ERR:
2202:         break;
2203: 
2204:     case RC_XXX:
2205:         padios (NULLCP, "%s", rc -> rc_data);/* NOTREACHED */
2206: 
2207:     default:
2208:         (void) fmt2peer (RC_ERR, "pTTY protocol screw-up");
2209:         done (1);       /* NOTREACHED */
2210:     }
2211: 
2212: #ifdef  SIGTSTP
2213:     (void) signal (SIGTSTP, tstat);
2214: #endif	SIGTSTP
2215:     return vmhtty;
2216: }
2217: 
2218: /*  */
2219: 
2220: static int  ttyR (cmdp)
2221: register struct Cmd *cmdp;
2222: {
2223:     struct record   rcs,
2224:                    *rc = &rcs;
2225: 
2226: #ifdef  SIGTSTP
2227:     (void) signal (SIGTSTP, SIG_IGN);
2228: #endif	SIGTSTP
2229: 
2230:     if (vmhtty != OK)
2231:     return NOTOK;
2232: 
2233:     initrc (rc);
2234: 
2235:     if (cmdp)
2236:     fin_io (cmdp, 0);
2237: 
2238:     vmhtty = NOTOK;
2239:     switch (rc2rc (RC_EOF, 0, NULLCP, rc)) {
2240:     case RC_ACK:
2241:         (void) rc2peer (RC_EOF, 0, NULLCP);
2242:         return OK;
2243: 
2244:     case RC_XXX:
2245:         padios (NULLCP, "%s", rc -> rc_data);/* NOTREACHED */
2246: 
2247:     default:
2248:         (void) fmt2peer (RC_ERR, "pTTY protocol screw-up");
2249:         done (1);       /* NOTREACHED */
2250:     }
2251: }
2252: 
2253: /*  */
2254: 
2255: static int  winN (cmdp, n, eof)
2256: register struct Cmd *cmdp;
2257: int n,
2258:     eof;
2259: {
2260:     int     i,
2261:             pd[2];
2262:     char    buffer[BUFSIZ];
2263:     struct record   rcs,
2264:                    *rc = &rcs;
2265: 
2266:     if (vmhpid == NOTOK)
2267:     return OK;
2268: 
2269:     initrc (rc);
2270: 
2271:     if (!fmsh)
2272:     (void) fseek (fp, 0L, 0);/* XXX: fseek() too tricky for our own good */
2273: 
2274:     vmhpid = OK;
2275: 
2276:     (void) sprintf (buffer, "%d", n);
2277:     switch (str2rc (RC_WIN, buffer, rc)) {
2278:     case RC_ACK:
2279:         break;
2280: 
2281:     case RC_ERR:
2282:         return NOTOK;
2283: 
2284:     case RC_XXX:
2285:         padios (NULLCP, "%s", rc -> rc_data);
2286: 
2287:     default:
2288:         (void) fmt2peer (RC_ERR, "pWIN protocol screw-up");
2289:         done (1);
2290:     }
2291: 
2292:     if (pipe (pd) == NOTOK) {
2293:     (void) err2peer (RC_ERR, "pipe", "unable to");
2294:     return NOTOK;
2295:     }
2296: 
2297:     switch (vmhpid = fork ()) {
2298:     case NOTOK:
2299:         (void) err2peer (RC_ERR, "fork", "unable to");
2300:         (void) close (pd[0]);
2301:         (void) close (pd[1]);
2302:         return NOTOK;
2303: 
2304:     case OK:
2305:         (void) close (pd[1]);
2306:         (void) signal (SIGPIPE, SIG_IGN);
2307:         while ((i = read (pd[0], buffer, sizeof buffer)) > 0)
2308:         switch (rc2rc (RC_DATA, i, buffer, rc)) {
2309:             case RC_ACK:
2310:             break;
2311: 
2312:             case RC_ERR:
2313:             _exit (1);
2314: 
2315:             case RC_XXX:
2316:             advise (NULLCP, "%s", rc -> rc_data);
2317:             _exit (2);
2318: 
2319:             default:
2320:             (void) fmt2peer (RC_ERR, "pWIN protocol screw-up");
2321:             _exit (2);
2322:         }
2323:         if (i == OK)
2324:         switch (rc2rc (RC_EOF, 0, NULLCP, rc)) {
2325:             case RC_ACK:
2326:             if (eof)
2327:                 (void) rc2peer (RC_EOF, 0, NULLCP);
2328:             i = 0;
2329:             break;
2330: 
2331:             case RC_XXX:
2332:             advise (NULLCP, "%s", rc -> rc_data);
2333:             i = 2;
2334:             break;
2335: 
2336:             default:
2337:             (void) fmt2peer (RC_ERR, "pWIN protocol screw-up");
2338:             i = 2;
2339:             break;
2340:         }
2341:         if (i == NOTOK)
2342:         (void) err2peer (RC_ERR, "pipe", "error reading from");
2343:         (void) close (pd[0]);
2344:         _exit (i != NOTOK ? i : 1);
2345: 
2346:     default:
2347:         if ((vmhfd0 = dup (fileno (stdin))) == NOTOK)
2348:         padios ("standard input", "unable to dup");
2349:         if ((vmhfd1 = dup (fileno (stdout))) == NOTOK)
2350:         padios ("standard output", "unable to dup");
2351:         if ((vmhfd2 = dup (fileno (stderr))) == NOTOK)
2352:         padios ("diagnostic output", "unable to dup");
2353: 
2354:         (void) close (0);
2355:         if ((i = open ("/dev/null", 0)) != NOTOK && i != fileno (stdin)) {
2356:         (void) dup2 (i, fileno (stdin));
2357:         (void) close (i);
2358:         }
2359: 
2360:         (void) fflush (stdout);
2361:         if (dup2 (pd[1], fileno (stdout)) == NOTOK)
2362:         padios ("standard output", "unable to dup2");
2363:         clearerr (stdout);
2364: 
2365:         (void) fflush (stderr);
2366:         if (dup2 (pd[1], fileno (stderr)) == NOTOK)
2367:         padios ("diagnostic output", "unable to dup2");
2368:         clearerr (stderr);
2369: 
2370:         if (cmdp && init_io (cmdp, 0) == NOTOK)
2371:         return NOTOK;
2372:         pstat = signal (SIGPIPE, pipeser);
2373:         broken_pipe = 1;
2374: 
2375:         (void) close (pd[0]);
2376:         (void) close (pd[1]);
2377: 
2378:         return vmhpid;
2379:     }
2380: }
2381: 
2382: /*  */
2383: 
2384: static int  winR (cmdp)
2385: register struct Cmd *cmdp;
2386: {
2387:     int     status;
2388: 
2389:     if (vmhpid <= OK)
2390:     return NOTOK;
2391: 
2392:     if (cmdp)
2393:     fin_io (cmdp, 0);
2394: 
2395:     if (dup2 (vmhfd0, fileno (stdin)) == NOTOK)
2396:     padios ("standard input", "unable to dup2");
2397:     clearerr (stdin);
2398:     (void) close (vmhfd0);
2399: 
2400:     (void) fflush (stdout);
2401:     if (dup2 (vmhfd1, fileno (stdout)) == NOTOK)
2402:     padios ("standard output", "unable to dup2");
2403:     clearerr (stdout);
2404:     (void) close (vmhfd1);
2405: 
2406:     (void) fflush (stderr);
2407:     if (dup2 (vmhfd2, fileno (stderr)) == NOTOK)
2408:     padios ("diagnostic output", "unable to dup2");
2409:     clearerr (stderr);
2410:     (void) close (vmhfd2);
2411: 
2412:     (void) signal (SIGPIPE, pstat);
2413: 
2414:     if ((status = pidwait (vmhpid, OK)) == 2)
2415:     done (1);
2416: 
2417:     vmhpid = OK;
2418:     return (status == 0 ? OK : NOTOK);
2419: }
2420: 
2421: /*  */
2422: 
2423: static int  winX (n)
2424: int n;
2425: {
2426:     int     i,
2427:             pid,
2428:             pd[2];
2429:     char    buffer[BUFSIZ];
2430:     struct record   rcs,
2431:                    *rc = &rcs;
2432: 
2433:     initrc (rc);
2434: 
2435:     if (!fmsh)
2436:     (void) fseek (fp, 0L, 0);/* XXX: fseek() too tricky for our own good */
2437: 
2438:     (void) sprintf (buffer, "%d", n);
2439:     switch (str2rc (RC_WIN, buffer, rc)) {
2440:     case RC_ACK:
2441:         break;
2442: 
2443:     case RC_ERR:
2444:         return NOTOK;
2445: 
2446:     case RC_XXX:
2447:         padios (NULLCP, "%s", rc -> rc_data);
2448: 
2449:     default:
2450:         (void) fmt2peer (RC_ERR, "pWIN protocol screw-up");
2451:         done (1);
2452:     }
2453: 
2454:     if (pipe (pd) == NOTOK) {
2455:     (void) err2peer (RC_ERR, "pipe", "unable to");
2456:     return NOTOK;
2457:     }
2458: 
2459:     switch (pid = fork ()) {
2460:     case NOTOK:
2461:         (void) err2peer (RC_ERR, "fork", "unable to");
2462:         (void) close (pd[0]);
2463:         (void) close (pd[1]);
2464:         return NOTOK;
2465: 
2466:     case OK:
2467:         (void) close (fileno (stdin));
2468:         if ((i = open ("/dev/null", 0)) != NOTOK && i != fileno (stdin)) {
2469:         (void) dup2 (i, fileno (stdin));
2470:         (void) close (i);
2471:         }
2472:         (void) dup2 (pd[1], fileno (stdout));
2473:         (void) dup2 (pd[1], fileno (stderr));
2474:         (void) close (pd[0]);
2475:         (void) close (pd[1]);
2476:         vmhpid = NOTOK;
2477:         return OK;
2478: 
2479:     default:
2480:         (void) close (pd[1]);
2481:         while ((i = read (pd[0], buffer, sizeof buffer)) > 0)
2482:         switch (rc2rc (RC_DATA, i, buffer, rc)) {
2483:             case RC_ACK:
2484:             break;
2485: 
2486:             case RC_ERR:
2487:             (void) close (pd[0]);
2488:             (void) pidwait (pid, OK);
2489:             return NOTOK;
2490: 
2491:             case RC_XXX:
2492:             padios (NULLCP, "%s", rc -> rc_data);
2493: 
2494:             default:
2495:             (void) fmt2peer (RC_ERR, "pWIN protocol screw-up");
2496:             done (1);
2497:         }
2498:         if (i == OK)
2499:         switch (rc2rc (RC_EOF, 0, NULLCP, rc)) {
2500:             case RC_ACK:
2501:             break;
2502: 
2503:             case RC_XXX:
2504:             padios (NULLCP, "%s", rc -> rc_data);
2505: 
2506:             default:
2507:             (void) fmt2peer (RC_ERR, "pWIN protocol screw-up");
2508:             done (1);
2509:         }
2510:         if (i == NOTOK)
2511:         (void) err2peer (RC_ERR, "pipe", "error reading from");
2512: 
2513:         (void) close (pd[0]);
2514:         (void) pidwait (pid, OK);
2515:         return (i != NOTOK ? pid : NOTOK);
2516:     }
2517: }
2518: 
2519: /*  */
2520: 
2521: /* VARARGS2 */
2522: 
2523: void    padios (what, fmt, a, b, c, d, e, f)
2524: char   *what,
2525:        *fmt,
2526:        *a,
2527:        *b,
2528:        *c,
2529:        *d,
2530:        *e,
2531:        *f;
2532: {
2533:     if (vmh) {
2534:     (void) err2peer (RC_FIN, what, fmt, a, b, c, d, e, f);
2535:     (void) rcdone ();
2536:     }
2537:     else
2538:     advise (what, fmt, a, b, c, d, e, f);
2539: 
2540:     done (1);
2541: }
2542: 
2543: 
2544: /* VARARGS2 */
2545: 
2546: void    padvise (what, fmt, a, b, c, d, e, f)
2547: char   *what,
2548:        *fmt,
2549:        *a,
2550:        *b,
2551:        *c,
2552:        *d,
2553:        *e,
2554:        *f;
2555: {
2556:     if (vmh)
2557:     (void) err2peer (RC_ERR, what, fmt, a, b, c, d, e, f);
2558:     else
2559:     advise (what, fmt, a, b, c, d, e, f);
2560: }

Defined functions

alrmser defined in line 2174; used 2 times
check_folder defined in line 959; used 2 times
display_info defined in line 1180; used 2 times
expand defined in line 1584; used 3 times
fin_io defined in line 1674; used 3 times
finaux_io defined in line 1688; used 1 times
fsetup defined in line 614; used 2 times
getargs defined in line 1348; used 1 times
getcmds defined in line 1434; used 1 times
init_io defined in line 1614; used 3 times
initaux_io defined in line 1631; used 1 times
intrser defined in line 1770; used 3 times
m_gMsgs defined in line 844; used 4 times
m_init defined in line 1724; used 6 times
m_reset defined in line 1733; used 2 times
main defined in line 178; never used
msh defined in line 424; used 1 times
msh_ready defined in line 867; used 9 times
pCMD defined in line 2072; used 1 times
pFIN defined in line 2130; used 2 times
pINI defined in line 1826; used 1 times
pQRY defined in line 1883; used 1 times
pQRY1 defined in line 1896; used 1 times
pQRY2 defined in line 1983; used 1 times
padios defined in line 2523; used 53 times
padvise defined in line 2546; used 10 times
parse defined in line 1472; used 2 times
peerwait defined in line 2149; used 1 times
pipeser defined in line 1789; used 4 times
pop_action defined in line 835; used 2 times
quit defined in line 1254; used 2 times
quitser defined in line 1809; used 3 times
read_file defined in line 787; used 2 times
read_map defined in line 751; used 1 times
read_pop defined in line 822; used 1 times
readid defined in line 1122; used 7 times
readids defined in line 1081; used 2 times
scanrange defined in line 1047; used 3 times
scanstring defined in line 1058; used 2 times
setup defined in line 656; used 2 times
ttyNaux defined in line 2182; used 2 times
ttyR defined in line 2220; used 3 times
winN defined in line 2255; used 12 times
winR defined in line 2384; used 2 times
winX defined in line 2423; used 7 times
write_ids defined in line 1228; used 1 times

Defined variables

BBoard_ID defined in line 149; used 1 times
Msgs defined in line 80; used 52 times
broken_pipe defined in line 159; used 3 times
cmd_name defined in line 137; used 5 times
fmsh defined in line 76; used 16 times
gap defined in line 145; used 4 times
interactive defined in line 133; used 2 times
interrupted defined in line 158; used 6 times
maxfds defined in line 85; used 5 times
mode defined in line 83; used 11 times
modified defined in line 77; used 3 times
mp defined in line 78; used 177 times
mshcmds defined in line 365; used 3 times
myfilter defined in line 139; used 1 times
myname defined in line 147; used 12 times
myprompt defined in line 141; used 3 times
nMsgs defined in line 79; used 5 times
numfds defined in line 84; used 4 times
numwins defined in line 109; used 5 times
peerenv defined in line 112; used 2 times
pfd defined in line 128; used 7 times
pmsh defined in line 121; used 11 times
ppid defined in line 129; used 7 times
redirected defined in line 134; used 1 times
should_intr defined in line 163; used 7 times
sigenv defined in line 164; used 5 times
switches defined in line 35; used 3 times
told_to_quit defined in line 160; used 6 times
topcur defined in line 107; used 4 times
vmh defined in line 93; used 39 times
vmhfd0 defined in line 96; used 3 times
vmhfd1 defined in line 97; used 3 times
vmhfd2 defined in line 98; used 3 times
vmhpid defined in line 95; used 9 times
vmhtty defined in line 100; used 6 times
windows defined in line 110; used 4 times

Defined macros

ALARM defined in line 90; used 1 times
ALICMD defined in line 366; never used
COMPCMD defined in line 370; never used
DISPLAY defined in line 104; used 15 times
DISTCMD defined in line 372; never used
EXITCMD defined in line 374; used 1 times
EXPLCMD defined in line 368; never used
FDSW defined in line 38; never used
FILECMD defined in line 400; never used
FOLDCMD defined in line 376; never used
FORWCMD defined in line 378; never used
HELPCMD defined in line 380; never used
HELPSW defined in line 68; never used
IDSW defined in line 36; never used
INCMD defined in line 382; never used
MAILCMD defined in line 386; never used
MARKCMD defined in line 384; never used
MSGKCMD defined in line 388; never used
NEXTCMD defined in line 390; never used
NMSW defined in line 42; never used
NSCANSW defined in line 50; never used
NTCURSW defined in line 65; never used
NWIN defined in line 105; used 3 times
PACKCMD defined in line 392; never used
PICKCMD defined in line 394; never used
PREADSW defined in line 58; never used
PREVCMD defined in line 396; never used
PRMPTSW defined in line 45; never used
PWRITSW defined in line 60; never used
QDSW defined in line 40; never used
QUITCMD defined in line 398; never used
QUOTE defined in line 30; never used
READSW defined in line 53; never used
REPLCMD defined in line 402; never used
RMMCMD defined in line 404; never used
SCAN defined in line 102; used 4 times
SCANCMD defined in line 406; never used
SCANSW defined in line 48; never used
SENDCMD defined in line 408; never used
SHOWCMD defined in line 410; never used
SORTCMD defined in line 412; never used
STATUS defined in line 103; used 3 times
TCURSW defined in line 63; never used
WHATCMD defined in line 414; never used
WHOMCMD defined in line 416; never used
WRITESW defined in line 55; never used
ttyN defined in line 91; used 6 times
Last modified: 1986-04-21
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 5583
Valid CSS Valid XHTML 1.0 Strict