comparison uip/msh.c @ 0:bce86c4163a3

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