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