1 /* msh.c - The MH shell (sigh) */
3 static char ident[] = "@(#)$Id: msh.c,v 2.14 1995/12/06 21:04:11 jromine Exp $";
7 Keep more status information in maildrop map
11 #include "../h/dropsbr.h"
12 #include "../h/formatsbr.h"
13 #include "../h/scansbr.h"
14 #include "../zotnet/tws.h"
16 #include "../zotnet/mts.h"
18 #include <sys/types.h>
25 #include <sys/ioctl.h>
31 #include "../h/mshsbr.h"
32 #include "../h/vmhsbr.h"
38 #define MIMEminc(a) (a)
43 #define QUOTE '\\' /* sigh */
48 static struct swit switches[] = {
50 "idstart number", -7, /* interface from bbc */
52 "idstop number", -6, /* .. */
54 "idquit number", -6, /* .. */
56 "idname BBoard", -6, /* .. */
89 char *fmsh = NULL; /* folder instead of file */
90 int modified; /* command modified folder */
91 struct msgs *mp; /* used a lot */
93 struct Msg *Msgs = NULL; /* Msgs[0] not used */
94 static FILE *fp; /* input file */
95 static FILE *yp = NULL; /* temporary file */
96 static int mode; /* mode of file */
97 static int numfds = 0; /* number of files cached */
98 static int maxfds = 0; /* number of files cached to be cached */
99 static time_t mtime = (time_t) 0;/* mtime of file */
103 #define ALARM ((unsigned int) 10)
104 #define ttyN(c) ttyNaux ((c), NULLCP)
108 static int vmhpid = OK;
113 static int vmhtty = NOTOK;
120 static int topcur = 0;
122 static int numwins = 0;
123 static int windows[NWIN + 1];
125 static jmp_buf peerenv;
127 void padios (), padvise ();
128 static TYPESIG alrmser ();
134 int pmsh = 0; /* BPOP enabled */
136 extern char response[];
141 static int pfd = NOTOK; /* fd parent is reading from */
142 static int ppid = 0; /* pid of parent */
146 int interactive; /* running from a /dev/tty */
147 int redirected; /* re-directing output */
148 FILE *sp = NULL; /* original stdout */
150 char *cmd_name; /* command being run */
152 char myfilter[BUFSIZ]; /* path to mhl.forward */
154 static char *myprompt = "(%s) ";/* prompting string */
158 static int gap; /* gap in BBoard-ID:s */
160 static char *myname = NULL; /* BBoard name */
162 char *BBoard_ID = "BBoard-ID";/* BBoard-ID constant */
165 TYPESIG (*istat) (); /* original SIGINT */
166 static TYPESIG (*pstat) (); /* current SIGPIPE */
167 TYPESIG (*qstat) (); /* original SIGQUIT */
169 static TYPESIG (*tstat) (); /* original SIGTSTP */
171 int interrupted; /* SIGINT detected */
172 int broken_pipe; /* SIGPIPE detected */
173 int told_to_quit; /* SIGQUIT detected */
176 int should_intr; /* signal handler should interrupt call */
177 jmp_buf sigenv; /* the environment pointer */
180 static TYPESIG intrser (), pipeser (), quitser ();
185 struct passwd *getpwnam ();
189 static int read_map(), read_file(), check_folder(), getargs(), parse();
190 static int getcmds(), init_io(), initaux_io(), finaux_io(), peerwait();
191 static int pINI(), pQRY(), pQRY1(), pQRY2(), pCMD(), pFIN();
192 static int ttyR(), ttyNaux(), winN(), winR(), winX();
193 static msh(), m_gMsgs(), scanrange(), scanstring(), quit();
194 static fin_io(), m_init();
196 static int read_pop();
223 setlocale(LC_ALL, "");
225 invo_name = r1bindex (argv[0], '/');
226 mts_init (invo_name);
227 if ((cp = m_find (invo_name)) != NULL) {
228 ap = brkstring (cp = getcpy (cp), " ", "\n");
229 ap = copyip (ap, arguments);
233 (void) copyip (argv + 1, ap);
238 while (cp = *argp++) {
240 switch (smatch (++cp, switches)) {
242 ambigsw (cp, switches);
245 adios (NULLCP, "-%s unknown", cp);
247 (void) sprintf (buf, "%s [switches] file", invo_name);
248 help (buf, switches);
252 if (!(cp = *argp++) || *cp == '-')
253 adios (NULLCP, "missing argument to %s", argp[-2]);
254 if ((id = atoi (cp)) < 1)
255 adios (NULLCP, "bad argument %s %s", argp[-2], cp);
258 if (!(cp = *argp++) || *cp == '-')
259 adios (NULLCP, "missing argument to %s", argp[-2]);
260 if ((pfd = atoi (cp)) <= 1)
261 adios (NULLCP, "bad argument %s %s", argp[-2], cp);
264 if (!(cp = *argp++) || *cp == '-')
265 adios (NULLCP, "missing argument to %s", argp[-2]);
266 if ((ppid = atoi (cp)) <= 1)
267 adios (NULLCP, "bad argument %s %s", argp[-2], cp);
270 if (!(myname = *argp++) || *myname == '-')
271 adios (NULLCP, "missing argument to %s", argp[-2]);
282 if (!(myprompt = *argp++) || *myprompt == '-')
283 adios (NULLCP, "missing argument to %s", argp[-2]);
287 if (!(cp = *argp++) || *cp == '-')
288 adios (NULLCP, "missing argument to %s", argp[-2]);
289 if ((vmh1 = atoi (cp)) < 1)
290 adios (NULLCP, "bad argument %s %s", argp[-2], cp);
293 if (!(cp = *argp++) || *cp == '-')
294 adios (NULLCP, "missing argument to %s", argp[-2]);
295 if ((vmh2 = atoi (cp)) < 1)
296 adios (NULLCP, "bad argument %s %s", argp[-2], cp);
300 if (!(cp = *argp++) || *cp == '-')
301 adios (NULLCP, "missing argument to %s", argp[-2]);
303 if ((pmsh1 = atoi (cp)) < 1)
304 adios (NULLCP, "bad argument %s %s", argp[-2], cp);
308 if (!(cp = *argp++) || *cp == '-')
309 adios (NULLCP, "missing argument to %s", argp[-2]);
311 if ((pmsh2 = atoi (cp)) < 1)
312 adios (NULLCP, "bad argument %s %s", argp[-2], cp);
323 if (*cp == '+' || *cp == '@') {
325 adios (NULLCP, "only one folder at a time!");
327 folder = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
331 adios (NULLCP, "only one file at a time!");
338 if (!file && !folder)
341 adios (NULLCP, "use a file or a folder, not both");
342 (void) strcpy (myfilter, libpath (mhlforward));
345 (void) ioctl (pfd, FIOCLEX, NULLCP);
351 setsigx (istat, SIGINT, intrser);
352 setsigx (qstat, SIGQUIT, quitser);
354 (void) sc_width (); /* MAGIC... */
356 if (vmh = vmh1 && vmh2) {
357 (void) rcinit (vmh1, vmh2);
359 (void) signal (SIGINT, SIG_IGN);
360 (void) signal (SIGQUIT, SIG_IGN);
362 tstat = signal (SIGTSTP, SIG_IGN);
367 if (pmsh = pmsh1 && pmsh2) {
368 cp = getenv ("MHPOPDEBUG");
370 if (pop_set (pmsh1, pmsh2, cp && *cp, myname) == NOTOK)
372 if (pop_set (pmsh1, pmsh2, cp && *cp) == NOTOK)
374 padios (NULLCP, "%s", response);
376 file = folder, folder = NULL;
385 display_info (id > 0 ? scansw : 0);
387 msh (id > 0 ? scansw : 0);
396 static struct swit mshcmds[] = {
468 register struct Cmd *cmdp;
469 static int once_only = ADVCMD;
471 (void) sprintf (prompt, myprompt, invo_name);
480 if ((i = getcmds (mshcmds, cmdp, scansw)) == EOF) {
486 (void) check_folder (scansw);
487 if ((i = getargs (prompt, mshcmds, cmdp)) == EOF) {
488 (void) putchar ('\n');
492 cmd_name = mshcmds[i].sw;
500 if (once_only == ADVCMD)
501 once_only = i = SHOWCMD;
503 i = mp -> curmsg != mp -> hghmsg ? NEXTCMD : EXITCMD;
504 cmd_name = mshcmds[i].sw;
510 case FORWCMD: /* sigh */
520 if ((cp = m_find (cmd_name)) != NULL) {
521 ap = brkstring (cp = getcpy (cp), " ", "\n");
522 ap = copyip (ap, vec);
533 (void) copyip (cmdp -> args + 1, ap);
537 if (!vmh && init_io (cmdp, vmh) == NOTOK) {
543 redirected = vmh || cmdp -> direction != STDIO;
554 if (!vmh || ttyN (cmdp) != NOTOK)
555 forkcmd (vec, cmd_name);
559 if (!vmh || ttyN (cmdp) != NOTOK)
564 if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
570 || (filehak (vec) == OK ? ttyN (cmdp)
571 : winN (cmdp, DISPLAY, 1)) != NOTOK)
576 if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
581 if (!vmh || ttyN (cmdp) != NOTOK)
586 if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
592 if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
598 if (!vmh || ttyN (cmdp) != NOTOK)
606 if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
612 || (packhak (vec) == OK ? ttyN (cmdp)
613 : winN (cmdp, DISPLAY, 1)) != NOTOK)
618 if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
623 if (!vmh || ttyN (cmdp) != NOTOK)
628 if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
633 if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
638 if (!vmh || winN (cmdp, DISPLAY, 1) != NOTOK)
643 padios (NULLCP, "no dispatch for %s", cmd_name);
672 maildir = m_maildir (folder);
673 if (chdir (maildir) == NOTOK)
674 padios (maildir, "unable to change directory to");
675 if (!(mp = m_gmsg (folder)))
676 padios (NULLCP, "unable to read folder %s", folder);
677 if (mp -> hghmsg == 0)
678 padios (NULLCP, "no messages in %s", folder);
681 mtime = stat (mp -> foldpath, &st) != NOTOK ? st.st_mtime : 0;
683 m_gMsgs (mp -> hghmsg);
685 for (msgnum = mp -> lowmsg; msgnum <= mp -> hghmsg; msgnum++) {
686 Msgs[msgnum].m_bboard_id = 0;
687 Msgs[msgnum].m_top = NOTOK;
688 Msgs[msgnum].m_start = Msgs[msgnum].m_stop = 0L;
689 Msgs[msgnum].m_scanl = NULL;
694 fmsh = getcpy (folder);
699 maxfds = getdtablesize () / 2;
701 if ((maxfds -= 2) < 1)
719 (void) strcpy (tmpfil, m_tmpfil (invo_name));
720 if ((fp = fopen (tmpfil, "w+")) == NULL)
721 padios (tmpfil, "unable to create");
722 (void) unlink (tmpfil);
726 if ((fp = fopen (file, "r")) == NULL)
727 padios (file, "unable to read");
729 (void) ioctl (fileno (fp), FIOCLEX, NULLCP);
731 if (fstat (fileno (fp), &st) != NOTOK) {
732 mode = (int) (st.st_mode & 0777), mtime = st.st_mtime;
733 msgp = read_map (file, (long) st.st_size);
736 mode = m_gmprot (), mtime = 0;
740 if ((msgp = read_file (msgp ? Msgs[msgp].m_stop : 0L, msgp + 1)) < 1)
741 padios (NULLCP, "no messages in %s", myname ? myname : file);
743 mp = (struct msgs *) calloc ((unsigned) 1, MHSIZE (mp, 1, msgp + 1));
745 padios (NULLCP, "unable to allocate folder storage");
752 mp -> foldpath = getcpy (myname ? myname : file);
756 mp -> msgflags |= READONLY;
759 (void) stat (file, &st);
760 if (st.st_uid != getuid () || access (file, 02) == NOTOK)
761 mp -> msgflags |= READONLY;
766 mp -> hghoff = mp -> hghmsg + 1;
769 mp -> msgstats = (short *)
770 calloc ((unsigned) 1, MHSIZEX (mp, mp -> lowmsg, mp -> hghmsg));
771 if (mp -> msgstats == NULL)
772 padios (NULLCP, "unable to allocate messages storage");
773 mp -> msgstats = (mp -> msgbase = mp -> msgstats) - mp -> lowoff;
774 if (mp -> msgstats < (short *)0)
775 padios (NULLCP, "setup() botch -- you lose big");
780 for (i = mp -> lowmsg; i <= mp -> hghmsg; i++) {
782 mp -> msgstats[i] = EXISTS | VIRTUAL;
785 for (i = mp -> lowmsg; i <= mp -> hghmsg; i++) {
786 if (Msgs[i].m_top) /* set in read_pop() */
787 mp -> msgstats[i] = EXISTS | VIRTUAL;
793 for (i = mp -> lowmsg; i <= mp -> hghmsg; i++)
794 mp -> msgstats[i] = EXISTS;
797 mp -> msgattrs[0] = getcpy ("unseen");
798 mp -> msgattrs[1] = NULL;
800 m_unknown (fp); /* the MAGIC invocation */
809 static int read_map (file, size)
815 register struct drop *dp,
824 if ((i = map_read (file, size, &rp, 1)) == 0)
830 for (dp = rp + 1; i-- > 0; msgp++, dp++) {
831 mp = &Msgs[msgp].m_drop;
832 mp -> d_id = dp -> d_id;
833 mp -> d_size = dp -> d_size;
834 mp -> d_start = dp -> d_start;
835 mp -> d_stop = dp -> d_stop;
836 Msgs[msgp].m_scanl = NULL;
845 static int read_file (pos, msgp)
850 register struct drop *dp,
859 if ((i = mbx_read (fp, pos, &rp, 1)) <= 0)
862 m_gMsgs ((msgp - 1) + i);
864 for (dp = rp; i-- > 0; msgp++, dp++) {
865 mp = &Msgs[msgp].m_drop;
867 mp -> d_size = dp -> d_size;
868 mp -> d_start = dp -> d_start;
869 mp -> d_stop = dp -> d_stop;
870 Msgs[msgp].m_scanl = NULL;
881 static int pop_base = 0;
883 static int pop_statmsg (s)
888 n = (i = atoi (s)) - pop_base; /* s="nnn header-line..." */
889 Msgs[n].m_top = Msgs[n].m_bboard_id = i;
893 static int read_pop () {
897 if (pop_stat (&nmsgs, &nbytes) == NOTOK)
898 padios (NULLCP, "%s", response);
902 #ifdef NNTP /* this makes read_pop() do some real work... */
903 pop_base = nbytes - 1; /* nmsgs=last-first+1, nbytes=first */
904 pop_exists (pop_statmsg);
910 static int pop_action (s)
913 fprintf (yp, "%s\n", s);
925 nMsgs = n + MAXFOLDER / 2;
926 Msgs = (struct Msg *) calloc ((unsigned) (nMsgs + 2), sizeof *Msgs);
928 padios (NULLCP, "unable to allocate Msgs structure");
935 nmsgs = nMsgs + n + MAXFOLDER / 2;
936 Msgs = (struct Msg *) realloc ((char *) Msgs,
937 (unsigned) (nmsgs + 2) * sizeof *Msgs);
939 padios (NULLCP, "unable to reallocate Msgs structure");
940 bzero ((char *) (Msgs + nMsgs + 2),
941 (unsigned) ((nmsgs - nMsgs) * sizeof *Msgs));
948 FILE *msh_ready (msgnum, full)
965 if ((fd = Msgs[msgnum].m_top) == NOTOK) {
966 if (numfds >= maxfds)
967 for (msgp = mp -> lowmsg; msgp <= mp -> hghmsg; msgp++)
968 if (Msgs[msgp].m_top != NOTOK) {
969 (void) close (Msgs[msgp].m_top);
970 Msgs[msgp].m_top = NOTOK;
975 if ((fd = open (cp = m_name (msgnum), 0)) == NOTOK)
976 padios (cp, "unable to open message");
977 Msgs[msgnum].m_top = fd;
981 if ((fd = dup (fd)) == NOTOK)
982 padios ("cached message", "unable to dup");
983 if ((yp = fdopen (fd, "r")) == NULL)
984 padios (NULLCP, "unable to fdopen cached message");
985 (void) fseek (yp, 0L, 0);
990 if (pmsh && (mp -> msgstats[msgnum] & VIRTUAL)) {
991 if (Msgs[msgnum].m_top == 0)
992 padios (NULLCP, "msh_ready (%d, %d) botch", msgnum, full);
994 (void) strcpy (tmpfil, m_tmpfil (invo_name));
995 if ((yp = fopen (tmpfil, "w+")) == NULL)
996 padios (tmpfil, "unable to create");
997 (void) unlink (tmpfil);
999 if (pop_top (Msgs[msgnum].m_top, 4, pop_action) == NOTOK)
1000 padios (NULLCP, "%s", response);
1002 m_eomsbr ((int (*)()) 0); /* XXX */
1003 msg_style = MS_DEFAULT; /* .. */
1004 (void) fseek (yp, 0L, 0);
1008 (void) fseek (fp, 0L, 2);
1009 (void) fwrite (mmdlm1, 1, strlen (mmdlm1), fp);
1011 padios ("temporary file", "write error on");
1012 (void) fseek (fp, 0L, 2);
1016 if (pop_retr (Msgs[msgnum].m_top, pop_action) == NOTOK)
1017 padios (NULLCP, "%s", response);
1020 (void) fseek (fp, 0L, 2);
1022 (void) fwrite (mmdlm2, 1, strlen (mmdlm2), fp);
1024 padios ("temporary file", "write error on");
1026 Msgs[msgnum].m_start = pos1;
1027 Msgs[msgnum].m_stop = pos2;
1029 mp -> msgstats[msgnum] &= ~VIRTUAL;
1033 m_eomsbr ((int (*)()) 0); /* XXX */
1034 (void) fseek (fp, Msgs[msgnum].m_start, 0);
1040 static int check_folder (scansw)
1056 if (stat (mp -> foldpath, &st) == NOTOK)
1057 padios (mp -> foldpath, "unable to stat");
1058 if (mtime == st.st_mtime)
1060 mtime = st.st_mtime;
1062 low = mp -> hghmsg + 1;
1065 if (!(mp = m_gmsg (fmsh)))
1066 padios (NULLCP, "unable to re-read folder %s", fmsh);
1070 for (msgp = mp -> lowmsg; msgp <= mp -> hghmsg; msgp++) {
1071 if (Msgs[msgp].m_top != NOTOK) {
1072 (void) close (Msgs[msgp].m_top);
1073 Msgs[msgp].m_top = NOTOK;
1076 if (Msgs[msgp].m_scanl) {
1077 free (Msgs[msgp].m_scanl);
1078 Msgs[msgp].m_scanl = NULL;
1084 if (modified || low > hgh)
1088 if (fstat (fileno (fp), &st) == NOTOK)
1089 padios (mp -> foldpath, "unable to fstat");
1090 if (mtime == st.st_mtime)
1092 mode = (int) (st.st_mode & 0777);
1093 mtime = st.st_mtime;
1095 if ((msgp = read_file (Msgs[mp -> hghmsg].m_stop, mp -> hghmsg + 1)) < 1)
1096 padios (NULLCP, "no messages in %s", mp -> foldpath); /* XXX */
1097 if (msgp <= mp -> hghmsg)
1100 if ((mp = m_remsg (mp, 0, msgp)) == NULL)
1101 padios (NULLCP, "unable to allocate folder storage");
1103 low = mp -> hghmsg + 1, hgh = msgp;
1104 flags = scansw ? m_seqflag (mp, "unseen") : 0;
1105 for (i = mp -> hghmsg + 1; i <= msgp; i++) {
1106 mp -> msgstats[i] = EXISTS | flags;
1109 mp -> hghmsg = msgp;
1116 advise (NULLCP, "new messages have arrived!\007");
1118 scanrange (low, hgh);
1125 static scanrange (low, hgh)
1129 char buffer[BUFSIZ];
1131 (void) sprintf (buffer, "%d-%d", low, hgh);
1132 scanstring (buffer);
1136 static scanstring (arg)
1143 if ((cp = m_find (cmd_name = "scan")) != NULL) {
1144 ap = brkstring (cp = getcpy (cp), " ", "\n");
1145 ap = copyip (ap, vec);
1167 if (mp -> curmsg == 0)
1168 m_setcur (mp, mp -> lowmsg);
1169 if (id <= 0 || (flags = m_seqflag (mp, "unseen")) == 0)
1172 for (msgnum = mp -> hghmsg; msgnum >= mp -> lowmsg; msgnum--)
1173 mp -> msgstats[msgnum] |= flags;
1178 for (msgnum = mp -> hghmsg; msgnum >= mp -> lowmsg; msgnum--)
1179 if (mp -> msgstats[msgnum] & EXISTS) /* FIX */
1180 if ((i = readid (msgnum)) > 0 && i < id) {
1182 mp -> msgstats[msgnum] &= ~flags;
1185 for (i = mp -> lowmsg; i < msgnum; i++)
1186 mp -> msgstats[i] &= ~flags;
1188 if (cur > mp -> hghmsg)
1194 if ((gap = 1 < id && id < (i = readid (mp -> lowmsg)) ? id : 0) && !vmh)
1195 advise (NULLCP, "gap in ID:s, last seen %d, lowest present %d\n",
1216 if (Msgs[msgnum].m_bboard_id)
1217 return Msgs[msgnum].m_bboard_id;
1220 if (Msgs[msgnum].m_top == 0)
1221 padios (NULLCP, "readid (%d) botch", msgnum);
1222 if (pop_list (Msgs[msgnum].m_top, (int *) 0, &arg1, &arg2, &arg3) == OK
1224 return (Msgs[msgnum].m_bboard_id = arg3);
1228 zp = msh_ready (msgnum, 0);
1230 switch (state = m_getfld (state, name, buf, sizeof buf, zp)) {
1234 if (uleq (name, BBoard_ID)) {
1236 while (state == FLDPLUS) {
1237 state = m_getfld (state, name, buf, sizeof buf, zp);
1243 return (Msgs[msgnum].m_bboard_id = i);
1247 while (state == FLDPLUS)
1248 state = m_getfld (state, name, buf, sizeof buf, zp);
1249 if (state != FLDEOF)
1259 display_info (scansw)
1265 interactive = isatty (fileno (stdout));
1267 if ((sd = dup (fileno (stdout))) == NOTOK)
1268 padios ("standard output", "unable to dup");
1269 #ifndef BSD42 /* XXX */
1271 (void) ioctl (sd, FIOCLEX, NULL);
1272 #endif /* FIOCLEX */
1273 #endif /* not BSD42 */
1274 if ((sp = fdopen (sd, "w")) == NULL)
1275 padios ("standard output", "unable to fdopen");
1278 (void) m_putenv ("mhfolder", mp -> foldpath);
1283 printf ("Reading ");
1284 if (SOprintf ("%s", myname))
1285 printf ("%s", myname);
1286 printf (", currently at message %d of %d\n",
1287 mp -> curmsg, mp -> hghmsg);
1290 printf ("Reading ");
1292 printf ("+%s", fmsh);
1294 printf ("%s", mp -> foldpath);
1295 printf (", currently at message %d of %d\n",
1296 mp -> curmsg, mp -> hghmsg);
1299 if ((flags = m_seqflag (mp, "unseen"))
1301 && (mp -> msgstats[mp -> hghmsg] & flags))
1302 scanstring ("unseen");
1307 static write_ids () {
1316 if (flags = m_seqflag (mp, "unseen"))
1317 for (msgnum = mp -> hghmsg; msgnum >= mp -> lowmsg; msgnum--)
1318 if (!(mp -> msgstats[msgnum] & flags)) {
1319 if (Msgs[msgnum].m_bboard_id == 0)
1320 (void) readid (msgnum);
1321 if ((i = Msgs[msgnum].m_bboard_id) > 0)
1325 (void) sprintf (buffer, "%d %d\n", i, Msgs[mp -> hghmsg].m_bboard_id);
1326 (void) write (pfd, buffer, sizeof buffer);
1344 if (!(mp -> msgflags & MODIFIED) || mp -> msgflags & READONLY || fmsh) {
1346 (void) rc2peer (RC_FIN, 0, NULLCP);
1351 (void) ttyNaux (NULLCMD, "FAST");
1353 if ((dp = lkfopen (mp -> foldpath, "r")) == NULL) {
1354 advise (mp -> foldpath, "unable to lock");
1356 (void) ttyR (NULLCMD);
1361 if (fstat (fileno (dp), &st) == NOTOK) {
1362 advise (mp -> foldpath, "unable to stat");
1365 if (mtime != st.st_mtime) {
1366 advise (NULLCP, "new messages have arrived, no update");
1369 mode = (int) (st.st_mode & 0777);
1371 if (mp -> nummsg == 0) {
1372 cp = concat ("Zero file \"", mp -> foldpath, "\"? ", NULLCP);
1373 if (getanswer (cp)) {
1374 if ((i = creat (mp -> foldpath, mode)) != NOTOK)
1377 advise (mp -> foldpath, "error zero'ing");
1378 (void) unlink (map_name (mp -> foldpath));/* XXX */
1383 cp = concat ("Update file \"", mp -> foldpath, "\"? ", NULLCP);
1384 if (!getanswer (cp))
1386 (void) strcpy (tmpfil, m_backup (mp -> foldpath));
1387 if ((md = mbx_open (tmpfil, st.st_uid, st.st_gid, mode)) == NOTOK) {
1388 advise (tmpfil, "unable to open");
1392 for (msgnum = mp -> lowmsg; msgnum <= mp -> hghmsg; msgnum++)
1393 if (mp -> msgstats[msgnum] & EXISTS
1394 && pack (tmpfil, md, msgnum) == NOTOK) {
1395 (void) mbx_close (tmpfil, md);
1396 (void) unlink (tmpfil);
1397 (void) unlink (map_name (tmpfil));
1400 (void) mbx_close (tmpfil, md);
1402 if (rename (tmpfil, mp -> foldpath) == NOTOK)
1403 admonish (mp -> foldpath, "unable to rename %s to", tmpfil);
1405 (void) strcpy (map1, map_name (tmpfil));
1406 (void) strcpy (map2, map_name (mp -> foldpath));
1408 if (rename (map1, map2) == NOTOK) {
1409 admonish (map2, "unable to rename %s to", map1);
1410 (void) unlink (map1);
1411 (void) unlink (map2);
1418 (void) lkfclose (dp, mp -> foldpath);
1420 (void) ttyR (NULLCMD);
1427 static int getargs (prompt, sw, cmdp)
1434 static char buffer[BUFSIZ];
1440 switch (setjmp (sigenv)) {
1447 if (interrupted && !told_to_quit) {
1448 (void) putchar ('\n');
1452 (void) kill (ppid, SIGEMT);
1457 printf ("%s", prompt);
1458 (void) fflush (stdout);
1460 for (cp = buffer; (i = getchar ()) != '\n';) {
1462 if (interrupted && !told_to_quit) {
1464 (void) putchar ('\n');
1467 if (told_to_quit || i == EOF) {
1469 (void) kill (ppid, SIGEMT);
1474 longjmp (sigenv, DONE);
1476 if (cp < &buffer[sizeof buffer - 2])
1483 if (buffer[0] == '?') {
1484 printf ("commands:\n");
1485 printsw (ALL, sw, "");
1486 printf ("type CTRL-D or use ``quit'' to leave %s\n",
1491 if (parse (buffer, cmdp) == NOTOK)
1494 switch (i = smatch (cmdp -> args[0], sw)) {
1496 ambigsw (cmdp -> args[0], sw);
1499 printf ("say what: ``%s'' -- type ? (or help) for help\n",
1513 static int getcmds (sw, cmdp, scansw)
1525 switch (peer2rc (rc)) {
1527 (void) pQRY (rc -> rc_data, scansw);
1531 if ((i = pCMD (rc -> rc_data, sw, cmdp)) != NOTOK)
1537 (void) kill (ppid, SIGEMT);
1541 padios (NULLCP, "%s", rc -> rc_data);
1544 (void) fmt2peer (RC_ERR, "pLOOP protocol screw-up");
1551 static int parse (buffer, cmdp)
1560 cmdp -> line[0] = 0;
1561 pp = cmdp -> args[argp++] = cmdp -> line;
1562 cmdp -> redirect = NULL;
1563 cmdp -> direction = STDIO;
1564 cmdp -> stream = NULL;
1566 for (cp = buffer; c = *cp; cp++)
1571 (void) fmt2peer (RC_EOF, "null command");
1582 cmdp -> args[argp++] = pp;
1589 switch (c = *cp++) {
1591 padvise (NULLCP, "unmatched \"");
1596 if ((c = *cp++) == 0)
1607 if ((c = *cp++) == 0) {
1609 padvise (NULLCP, "the newline character can not be quoted");
1619 if (pp == cmdp -> line) {
1620 padvise (NULLCP, "invalid null command");
1623 if (*cmdp -> args[argp - 1] == 0)
1625 cmdp -> direction = c == '>' ? CRTIO : PIPIO;
1626 if (cmdp -> direction == CRTIO && (c = *cp) == '>') {
1627 cmdp -> direction = APPIO;
1630 cmdp -> redirect = pp + 1;/* sigh */
1631 for (; c = *cp; cp++)
1635 padvise (NULLCP, cmdp -> direction != PIPIO
1636 ? "missing name for redirect"
1637 : "invalid null command");
1640 (void) strcpy (cmdp -> redirect, cp);
1641 if (cmdp -> direction != PIPIO) {
1643 if (isspace (*cp)) {
1644 padvise (NULLCP, "bad name for redirect");
1647 if (expand (cmdp -> redirect) == NOTOK)
1656 cmdp -> args[argp] = NULL;
1663 int expand (redirect)
1671 if (*redirect != '~')
1674 if (cp = index (pp = redirect + 1, '/'))
1679 if (pw = getpwnam (pp))
1682 padvise (NULLCP, "unknown user: %s", pp);
1686 (void) sprintf (path, "%s/%s", pp, cp ? cp : "");
1687 (void) strcpy (redirect, path);
1693 static int init_io (cmdp, vio)
1694 register struct Cmd *cmdp;
1703 result = initaux_io (cmdp);
1710 static int initaux_io (cmdp)
1711 register struct Cmd *cmdp;
1715 switch (cmdp -> direction) {
1721 mode = cmdp -> direction == CRTIO ? "write" : "append";
1722 if ((cmdp -> stream = fopen (cmdp -> redirect, mode)) == NULL) {
1723 padvise (cmdp -> redirect, "unable to %s ", mode);
1724 cmdp -> direction = STDIO;
1730 if ((cmdp -> stream = popen (cmdp -> redirect, "w")) == NULL) {
1731 padvise (cmdp -> redirect, "unable to pipe");
1732 cmdp -> direction = STDIO;
1735 (void) signal (SIGPIPE, pipeser);
1740 padios (NULLCP, "unknown redirection for command");
1743 (void) fflush (stdout);
1744 if (dup2 (fileno (cmdp -> stream), fileno (stdout)) == NOTOK)
1745 padios ("standard output", "unable to dup2");
1753 static fin_io (cmdp, vio)
1754 register struct Cmd *cmdp;
1767 static int finaux_io (cmdp)
1768 register struct Cmd *cmdp;
1770 switch (cmdp -> direction) {
1776 (void) fflush (stdout);
1777 (void) close (fileno (stdout));
1778 if (ferror (stdout))
1779 padvise (NULLCP, "problems writing %s", cmdp -> redirect);
1780 (void) fclose (cmdp -> stream);
1784 (void) fflush (stdout);
1785 (void) close (fileno (stdout));
1786 (void) pclose (cmdp -> stream);
1787 (void) signal (SIGPIPE, SIG_DFL);
1791 padios (NULLCP, "unknown redirection for command");
1794 if (dup2 (fileno (sp), fileno (stdout)) == NOTOK)
1795 padios ("standard output", "unable to dup2");
1798 cmdp -> direction = STDIO;
1806 for (msgnum = mp -> lowmsg; msgnum <= mp -> hghmsg; msgnum++)
1807 mp -> msgstats[msgnum] &= ~SELECTED;
1808 mp -> lowsel = mp -> hghsel = mp -> numsel = 0;
1826 void m_setcur (mp, msgnum)
1827 register struct msgs *mp;
1828 register int msgnum;
1830 if (mp -> curmsg == msgnum)
1833 if (mp -> curmsg && Msgs[mp -> curmsg].m_scanl) {
1834 free (Msgs[mp -> curmsg].m_scanl);
1835 Msgs[mp -> curmsg].m_scanl = NULL;
1837 if (Msgs[msgnum].m_scanl) {
1838 free (Msgs[msgnum].m_scanl);
1839 Msgs[msgnum].m_scanl = NULL;
1842 mp -> curmsg = msgnum;
1849 static TYPESIG intrser (i)
1853 (void) signal (SIGINT, intrser);
1854 #endif /* not BSD42 */
1861 longjmp (sigenv, NOTOK);
1868 static TYPESIG pipeser (i)
1872 (void) signal (SIGPIPE, pipeser);
1873 #endif /* not BSD42 */
1875 if (broken_pipe++ == 0)
1876 fprintf (stderr, "broken pipe\n");
1881 longjmp (sigenv, NOTOK);
1888 static TYPESIG quitser (i)
1892 (void) signal (SIGQUIT, quitser);
1899 longjmp (sigenv, NOTOK);
1905 static int pINI () {
1914 switch (peer2rc (rc)) {
1917 while (isspace (*bp))
1919 if (sscanf (bp, "%d", &vrsn) != 1) {
1921 (void) fmt2peer (RC_ERR, "bad init \"%s\"", rc -> rc_data);
1924 if (vrsn != RC_VRSN) {
1925 (void) fmt2peer (RC_ERR, "version %d unsupported", vrsn);
1929 while (*bp && !isspace (*bp))
1931 while (isspace (*bp))
1933 if (sscanf (bp, "%d", &numwins) != 1 || numwins <= 0)
1938 for (i = 1; i <= numwins; i++) {
1939 while (*bp && !isspace (*bp))
1941 while (isspace (*bp))
1943 if (sscanf (bp, "%d", &windows[i]) != 1 || windows[i] <= 0)
1946 (void) rc2peer (RC_ACK, 0, NULLCP);
1950 padios (NULLCP, "%s", rc -> rc_data);
1953 (void) fmt2peer (RC_ERR, "pINI protocol screw-up");
1954 done (1); /* NOTREACHED */
1962 static int pQRY (str, scansw)
1966 if (pQRY1 (scansw) == NOTOK || pQRY2 () == NOTOK)
1969 (void) rc2peer (RC_EOF, 0, NULLCP);
1975 static int pQRY1 (scansw)
1979 static int lastlow = 0,
1984 oldhgh = mp -> hghmsg;
1985 if (check_folder (scansw) && oldhgh < mp -> hghmsg) {
1986 switch (winX (STATUS)) {
1991 printf ("new messages have arrived!");
1992 (void) fflush (stdout);
1993 (void) fflush (stderr);
1994 _exit (0); /* NOTREACHED */
1997 lastlow = lastcur = lasthgh = lastnum = 0;
2001 switch (winX (DISPLAY)) {
2006 scanrange (oldhgh + 1, mp -> hghmsg);
2007 (void) fflush (stdout);
2008 (void) fflush (stderr);
2009 _exit (0); /* NOTREACHED */
2018 switch (winX (STATUS)) {
2023 printf ("%s: gap in ID:s, last seen %d, lowest present %d\n",
2024 myname ? myname : fmsh ? fmsh : mp -> foldpath, gap - 1,
2025 readid (mp -> lowmsg));
2026 (void) fflush (stdout);
2027 (void) fflush (stderr);
2028 _exit (0); /* NOTREACHED */
2035 if (mp -> lowmsg != lastlow
2036 || mp -> curmsg != lastcur
2037 || mp -> hghmsg != lasthgh
2038 || mp -> nummsg != lastnum)
2039 switch (winX (STATUS)) {
2045 (void) fflush (stdout);
2046 (void) fflush (stderr);
2047 _exit (0); /* NOTREACHED */
2050 lastlow = mp -> lowmsg;
2051 lastcur = mp -> curmsg;
2052 lasthgh = mp -> hghmsg;
2053 lastnum = mp -> nummsg;
2062 static int pQRY2 () {
2073 if (mp -> nummsg == 0 && mp -> nummsg != num)
2074 switch (winX (SCAN)) {
2080 (void) fflush (stdout);
2081 (void) fflush (stderr);
2082 _exit (0); /* NOTREACHED */
2091 j = (k = windows[SCAN]) / 2;
2092 for (msgnum = mp -> curmsg; msgnum <= mp -> hghmsg; msgnum++)
2093 if (mp -> msgstats[msgnum] & EXISTS)
2097 k = i >= k ? 1 : k - i;
2103 for (msgnum = mp -> curmsg; msgnum >= mp -> lowmsg; msgnum--)
2104 if (mp -> msgstats[msgnum] & EXISTS) {
2111 for (msgnum = mp -> curmsg + 1; msgnum <= mp -> hghmsg; msgnum++)
2112 if (mp -> msgstats[msgnum] & EXISTS) {
2116 if (n++ >= windows[SCAN])
2122 && mp -> msgstats[lo] & EXISTS
2123 && mp -> msgstats[hi] & EXISTS
2124 && (lo < mp -> curmsg
2125 || (lo == mp -> curmsg && lo == mp -> lowmsg))
2126 && (mp -> curmsg < hi
2127 || (hi == mp -> curmsg && hi == mp -> hghmsg))
2128 && hi - lo == j - i)
2131 if (mp -> curmsg != cur || modified)
2132 switch (winN (NULLCMD, SCAN, 0)) {
2140 scanrange (lo = i, hi = j);
2142 (void) winR (NULLCMD);
2151 static int pCMD (str, sw, cmdp)
2159 switch (winX (DISPLAY)) {
2164 printf ("commands:\n");
2165 printsw (ALL, sw, "");
2166 printf ("type ``quit'' to leave %s\n", invo_name);
2167 (void) fflush (stdout);
2168 (void) fflush (stderr);
2169 _exit (0); /* NOTREACHED */
2172 (void) rc2peer (RC_EOF, 0, NULLCP);
2176 if (parse (str, cmdp) == NOTOK)
2179 switch (i = smatch (cmdp -> args[0], sw)) {
2181 switch (winX (DISPLAY)) {
2186 ambigsw (cmdp -> args[0], sw);
2187 (void) fflush (stdout);
2188 (void) fflush (stderr);
2189 _exit (0); /* NOTREACHED */
2192 (void) rc2peer (RC_EOF, 0, NULLCP);
2197 (void) fmt2peer (RC_ERR,
2198 "say what: ``%s'' -- type ? (or help) for help",
2209 static int pFIN () {
2212 switch (setjmp (peerenv)) {
2214 (void) signal (SIGALRM, alrmser);
2215 (void) alarm (ALARM);
2217 status = peerwait ();
2228 static int peerwait () {
2234 switch (peer2rc (rc)) {
2237 (void) rc2peer (RC_FIN, 0, NULLCP);
2241 advise (NULLCP, "%s", rc -> rc_data);
2245 (void) fmt2peer (RC_FIN, "pLOOP protocol screw-up");
2253 static TYPESIG alrmser (i)
2256 longjmp (peerenv, DONE);
2261 static int ttyNaux (cmdp, s)
2262 register struct Cmd *cmdp;
2270 if (cmdp && init_io (cmdp, vmh) == NOTOK)
2274 (void) fseek (fp, 0L, 0);/* XXX: fseek() too tricky for our own good */
2277 switch (rc2rc (RC_TTY, s ? strlen (s) : 0, s, rc)) {
2279 vmhtty = OK; /* fall */
2284 padios (NULLCP, "%s", rc -> rc_data);/* NOTREACHED */
2287 (void) fmt2peer (RC_ERR, "pTTY protocol screw-up");
2288 done (1); /* NOTREACHED */
2292 (void) signal (SIGTSTP, tstat);
2293 #endif /* SIGTSTP */
2299 static int ttyR (cmdp)
2300 register struct Cmd *cmdp;
2306 (void) signal (SIGTSTP, SIG_IGN);
2307 #endif /* SIGTSTP */
2318 switch (rc2rc (RC_EOF, 0, NULLCP, rc)) {
2320 (void) rc2peer (RC_EOF, 0, NULLCP);
2324 padios (NULLCP, "%s", rc -> rc_data);/* NOTREACHED */
2327 (void) fmt2peer (RC_ERR, "pTTY protocol screw-up");
2328 done (1); /* NOTREACHED */
2334 static int winN (cmdp, n, eof)
2335 register struct Cmd *cmdp;
2341 char buffer[BUFSIZ];
2345 if (vmhpid == NOTOK)
2351 (void) fseek (fp, 0L, 0);/* XXX: fseek() too tricky for our own good */
2355 (void) sprintf (buffer, "%d", n);
2356 switch (str2rc (RC_WIN, buffer, rc)) {
2364 padios (NULLCP, "%s", rc -> rc_data);
2367 (void) fmt2peer (RC_ERR, "pWIN protocol screw-up");
2371 if (pipe (pd) == NOTOK) {
2372 (void) err2peer (RC_ERR, "pipe", "unable to");
2376 switch (vmhpid = fork ()) {
2378 (void) err2peer (RC_ERR, "fork", "unable to");
2379 (void) close (pd[0]);
2380 (void) close (pd[1]);
2384 (void) close (pd[1]);
2385 (void) signal (SIGPIPE, SIG_IGN);
2386 while ((i = read (pd[0], buffer, sizeof buffer)) > 0)
2387 switch (rc2rc (RC_DATA, i, buffer, rc)) {
2395 advise (NULLCP, "%s", rc -> rc_data);
2399 (void) fmt2peer (RC_ERR, "pWIN protocol screw-up");
2403 switch (rc2rc (RC_EOF, 0, NULLCP, rc)) {
2406 (void) rc2peer (RC_EOF, 0, NULLCP);
2411 advise (NULLCP, "%s", rc -> rc_data);
2416 (void) fmt2peer (RC_ERR, "pWIN protocol screw-up");
2421 (void) err2peer (RC_ERR, "pipe", "error reading from");
2422 (void) close (pd[0]);
2423 _exit (i != NOTOK ? i : 1);
2426 if ((vmhfd0 = dup (fileno (stdin))) == NOTOK)
2427 padios ("standard input", "unable to dup");
2428 if ((vmhfd1 = dup (fileno (stdout))) == NOTOK)
2429 padios ("standard output", "unable to dup");
2430 if ((vmhfd2 = dup (fileno (stderr))) == NOTOK)
2431 padios ("diagnostic output", "unable to dup");
2434 if ((i = open ("/dev/null", 0)) != NOTOK && i != fileno (stdin)) {
2435 (void) dup2 (i, fileno (stdin));
2439 (void) fflush (stdout);
2440 if (dup2 (pd[1], fileno (stdout)) == NOTOK)
2441 padios ("standard output", "unable to dup2");
2444 (void) fflush (stderr);
2445 if (dup2 (pd[1], fileno (stderr)) == NOTOK)
2446 padios ("diagnostic output", "unable to dup2");
2449 if (cmdp && init_io (cmdp, 0) == NOTOK)
2451 pstat = signal (SIGPIPE, pipeser);
2454 (void) close (pd[0]);
2455 (void) close (pd[1]);
2463 static int winR (cmdp)
2464 register struct Cmd *cmdp;
2474 if (dup2 (vmhfd0, fileno (stdin)) == NOTOK)
2475 padios ("standard input", "unable to dup2");
2477 (void) close (vmhfd0);
2479 (void) fflush (stdout);
2480 if (dup2 (vmhfd1, fileno (stdout)) == NOTOK)
2481 padios ("standard output", "unable to dup2");
2483 (void) close (vmhfd1);
2485 (void) fflush (stderr);
2486 if (dup2 (vmhfd2, fileno (stderr)) == NOTOK)
2487 padios ("diagnostic output", "unable to dup2");
2489 (void) close (vmhfd2);
2491 (void) signal (SIGPIPE, pstat);
2493 if ((status = pidwait (vmhpid, OK)) == 2)
2497 return (status == 0 ? OK : NOTOK);
2508 char buffer[BUFSIZ];
2515 (void) fseek (fp, 0L, 0);/* XXX: fseek() too tricky for our own good */
2517 (void) sprintf (buffer, "%d", n);
2518 switch (str2rc (RC_WIN, buffer, rc)) {
2526 padios (NULLCP, "%s", rc -> rc_data);
2529 (void) fmt2peer (RC_ERR, "pWIN protocol screw-up");
2533 if (pipe (pd) == NOTOK) {
2534 (void) err2peer (RC_ERR, "pipe", "unable to");
2538 switch (pid = fork ()) {
2540 (void) err2peer (RC_ERR, "fork", "unable to");
2541 (void) close (pd[0]);
2542 (void) close (pd[1]);
2546 (void) close (fileno (stdin));
2547 if ((i = open ("/dev/null", 0)) != NOTOK && i != fileno (stdin)) {
2548 (void) dup2 (i, fileno (stdin));
2551 (void) dup2 (pd[1], fileno (stdout));
2552 (void) dup2 (pd[1], fileno (stderr));
2553 (void) close (pd[0]);
2554 (void) close (pd[1]);
2559 (void) close (pd[1]);
2560 while ((i = read (pd[0], buffer, sizeof buffer)) > 0)
2561 switch (rc2rc (RC_DATA, i, buffer, rc)) {
2566 (void) close (pd[0]);
2567 (void) pidwait (pid, OK);
2571 padios (NULLCP, "%s", rc -> rc_data);
2574 (void) fmt2peer (RC_ERR, "pWIN protocol screw-up");
2578 switch (rc2rc (RC_EOF, 0, NULLCP, rc)) {
2583 padios (NULLCP, "%s", rc -> rc_data);
2586 (void) fmt2peer (RC_ERR, "pWIN protocol screw-up");
2590 (void) err2peer (RC_ERR, "pipe", "error reading from");
2592 (void) close (pd[0]);
2593 (void) pidwait (pid, OK);
2594 return (i != NOTOK ? pid : NOTOK);
2602 void padios (what, fmt, a, b, c, d, e, f)
2613 (void) err2peer (RC_FIN, what, fmt, a, b, c, d, e, f);
2617 advise (what, fmt, a, b, c, d, e, f);
2625 void padvise (what, fmt, a, b, c, d, e, f)
2636 (void) err2peer (RC_ERR, what, fmt, a, b, c, d, e, f);
2638 advise (what, fmt, a, b, c, d, e, f);