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