source: trunk/third/nmh/uip/msh.c @ 12455

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