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