Added all of the MH sources, including RCS files, in
[mmh] / docs / historical / mh-6.8.5 / uip / mshcmds.c
1 /* mshcmds.c - command handlers in msh */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: mshcmds.c,v 1.32 1995/12/11 18:19:26 jromine Exp $";
4 #endif  /* lint */
5
6 #include "../h/mh.h"
7 #include "../h/dropsbr.h"
8 #include "../h/formatsbr.h"
9 #include "../h/scansbr.h"
10 #include "../zotnet/tws.h"
11 #ifdef  _AIX            /* AIX 1.2.1 <stdio.h> declares getws() */
12 #define getws _getws
13 #endif
14 #include <stdio.h>
15 #ifdef  _AIX
16 #undef getws
17 #endif
18 #include "../zotnet/mts.h"
19 #include <ctype.h>
20 #include <errno.h>
21 #include <setjmp.h>
22 #include <signal.h>
23 #include <sys/types.h>
24 #include <sys/stat.h>
25 #include "../h/mshsbr.h"
26 #ifdef  MIME
27 #include "../h/mhn.h"
28 #endif  /* MIME */
29
30 /* \f */
31
32 extern int errno;
33
34                                 /* BURST */
35 static char delim3[] = "-------";/* from burst.c */
36
37
38                                 /* SHOW */
39 static int  mhlnum;
40 static FILE *mhlfp;
41
42 void clear_screen ();
43 static int     eom_action ();
44 static FP       mhl_action ();
45 #ifdef  MIME
46 static int     nontext();
47 #endif
48
49
50 static burst(), forw(), rmm(), show(), ask(), copy_message(), copy_digest();
51 static int      process();
52                                 /* SORTM */
53 static int      msgsort (), subsort();
54 static int      getws ();
55 static char    *sosmash ();
56
57 #if     defined(NNTP) && defined(MPOP)
58 #undef  MPOP
59 #endif
60 #ifdef  MPOP
61 #ifdef  BPOP
62 extern  int     pmsh;
63 extern  char    response[];
64 #endif
65 #endif /* MPOP */
66
67 /* \f */
68
69 forkcmd (args, pgm)
70 char  **args,
71        *pgm;
72 {
73     int     child_id;
74     char   *vec[MAXARGS];
75
76     vec[0] = r1bindex (pgm, '/');
77     (void) copyip (args, vec + 1);
78
79     if (fmsh) {
80         (void) m_delete (pfolder);
81         m_replace (pfolder, fmsh);
82         m_sync (mp);
83         m_update ();
84     }
85     (void) fflush (stdout);
86     switch (child_id = fork ()) {
87         case NOTOK: 
88             advise ("fork", "unable to");
89             return;
90
91         case OK: 
92             closefds (3);
93             (void) signal (SIGINT, istat);
94             (void) signal (SIGQUIT, qstat);
95
96             execvp (pgm, vec);
97             fprintf (stderr, "unable to exec ");
98             perror (cmd_name);
99             _exit (1);
100
101         default: 
102             (void) pidXwait (child_id, NULLCP);
103             break;
104     }
105     if (fmsh) {                 /* assume the worst case */
106         mp -> msgflags |= MODIFIED;
107         modified++;
108     }
109 }
110
111 /* \f */
112
113 static struct swit distswit[] = {
114 #define DIANSW  0
115     "annotate", 0,
116 #define DINANSW 1
117     "noannotate", 0,
118 #define DIDFSW  2
119     "draftfolder +folder", 0,
120 #define DIDMSW  3
121     "draftmessage msg", 0,
122 #define DINDFSW 4
123     "nodraftfolder", 0,
124 #define DIEDTSW 5
125     "editor editor", 0,
126 #define DINEDSW 6
127     "noedit", 0,
128 #define DIFRMSW 7
129     "form formfile", 0,
130 #define DIINSW  8
131     "inplace", 0,
132 #define DININSW 9
133     "noinplace", 0,
134 #define DIWHTSW 10
135     "whatnowproc program", 0,
136 #define DINWTSW 11
137     "nowhatnowproc", 0,
138 #define DIHELP  12
139     "help", 4,
140
141     NULL, 0
142 };
143
144 /* \f */
145
146 distcmd (args)
147 char  **args;
148 {
149     int     vecp = 1;
150     char   *cp,
151            *msg = NULL,
152             buf[BUFSIZ],
153            *vec[MAXARGS];
154
155     if (fmsh) {
156         forkcmd (args, cmd_name);
157         return;
158     }
159
160     while (cp = *args++) {
161         if (*cp == '-')
162             switch (smatch (++cp, distswit)) {
163                 case AMBIGSW: 
164                     ambigsw (cp, distswit);
165                     return;
166                 case UNKWNSW: 
167                     fprintf (stderr, "-%s unknown\n", cp);
168                     return;
169                 case DIHELP: 
170                     (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
171                     help (buf, distswit);
172                     return;
173
174                 case DIANSW:    /* not implemented */
175                 case DINANSW: 
176                 case DIINSW: 
177                 case DININSW: 
178                     continue;
179
180                 case DINDFSW:
181                 case DINEDSW:
182                 case DINWTSW:
183                     vec[vecp++] = --cp;
184                     continue;
185
186                 case DIEDTSW: 
187                 case DIFRMSW: 
188                 case DIDFSW:
189                 case DIDMSW:
190                 case DIWHTSW:
191                     vec[vecp++] = --cp;
192                     if (!(cp = *args++) || *cp == '-') {
193                         advise (NULLCP, "missing argument to %s", args[-2]);
194                         return;
195                     }
196                     vec[vecp++] = cp;
197                     continue;
198             }
199         if (*cp == '+' || *cp == '@') {
200             advise (NULLCP, "sorry, no folders allowed!");
201             return;
202         }
203         else
204             if (msg) {
205                 advise (NULLCP, "only one message at a time!");
206                 return;
207             }
208             else
209                 msg = cp;
210     }
211
212     vec[0] = cmd_name;
213     vec[vecp++] = "-file";
214     vec[vecp] = NULL;
215     if (!msg)
216         msg = "cur";
217     if (!m_convert (mp, msg))
218         return;
219     m_setseq (mp);
220
221     if (mp -> numsel > 1) {
222         advise (NULLCP, "only one message at a time!");
223         return;
224     }
225     (void) process (mp -> hghsel, cmd_name, vecp, vec);
226     m_setcur (mp, mp -> hghsel);
227 }
228
229 /* \f */
230
231 static struct swit explswit[] = {
232 #define EXINSW  0
233     "inplace", 0,
234 #define EXNINSW 1
235     "noinplace", 0,
236 #define EXQISW  2
237     "quiet", 0,
238 #define EXNQISW 3
239     "noquiet", 0,
240 #define EXVBSW  4
241     "verbose", 0,
242 #define EXNVBSW 5
243     "noverbose", 0,
244 #define EXHELP  6
245     "help", 4,
246
247     NULL, 0
248 };
249
250 /* \f */
251
252 explcmd (args)
253 char  **args;
254 {
255     int     inplace = 0,
256             quietsw = 0,
257             verbosw = 0,
258             msgp = 0,
259             hi,
260             msgnum;
261     char   *cp,
262             buf[BUFSIZ],
263            *msgs[MAXARGS];
264     struct Msg *smsgs;
265
266     if (fmsh) {
267         forkcmd (args, cmd_name);
268         return;
269     }
270
271     while (cp = *args++) {
272         if (*cp == '-')
273             switch (smatch (++cp, explswit)) {
274                 case AMBIGSW: 
275                     ambigsw (cp, explswit);
276                     return;
277                 case UNKWNSW: 
278                     fprintf (stderr, "-%s unknown\n", cp);
279                     return;
280                 case EXHELP: 
281                     (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
282                     help (buf, explswit);
283                     return;
284
285                 case EXINSW: 
286                     inplace++;
287                     continue;
288                 case EXNINSW: 
289                     inplace = 0;
290                     continue;
291                 case EXQISW: 
292                     quietsw++;
293                     continue;
294                 case EXNQISW: 
295                     quietsw = 0;
296                     continue;
297                 case EXVBSW: 
298                     verbosw++;
299                     continue;
300                 case EXNVBSW: 
301                     verbosw = 0;
302                     continue;
303             }
304         if (*cp == '+' || *cp == '@') {
305             advise (NULLCP, "sorry, no folders allowed!");
306             return;
307         }
308         else
309             msgs[msgp++] = cp;
310     }
311
312     if (!msgp)
313         msgs[msgp++] = "cur";
314     for (msgnum = 0; msgnum < msgp; msgnum++)
315         if (!m_convert (mp, msgs[msgnum]))
316             return;
317     m_setseq (mp);
318
319     smsgs = (struct Msg *)
320                 calloc ((unsigned) (MAXFOLDER + 2), sizeof *smsgs);
321     if (smsgs == NULL)
322         adios (NULLCP, "unable to allocate folder storage");
323
324     hi = mp -> hghmsg + 1;
325     interrupted = 0;
326     for (msgnum = mp -> lowsel;
327             msgnum <= mp -> hghsel && !interrupted;
328             msgnum++)
329         if (mp -> msgstats[msgnum] & SELECTED)
330             if (burst (smsgs, msgnum, inplace, quietsw, verbosw) != OK)
331                 break;
332
333     free ((char *) smsgs);
334
335     if (inplace)
336         m_setcur (mp, mp -> lowsel);
337     else
338         if (hi <= mp -> hghmsg)
339             m_setcur (mp, hi);
340
341     mp -> msgflags |= MODIFIED;
342     modified++;
343 }
344
345 /* \f */
346
347 static  burst (smsgs, msgnum, inplace, quietsw, verbosw)
348 struct Msg *smsgs;
349 int     msgnum,
350         inplace,
351         quietsw,
352         verbosw;
353 {
354     int     i,
355             j,
356             ld3,
357             wasdlm,
358             msgp;
359     long    pos;
360     char    c,
361             cc,
362             buffer[BUFSIZ];
363     register FILE *zp;
364
365     ld3 = strlen (delim3);
366
367     if (Msgs[msgnum].m_scanl) {
368         free (Msgs[msgnum].m_scanl);
369         Msgs[msgnum].m_scanl = NULL;
370     }
371
372     pos = ftell (zp = msh_ready (msgnum, 1));
373     for (msgp = 0; msgp <= MAXFOLDER;) {
374         while (fgets (buffer, sizeof buffer, zp) != NULL
375                 && buffer[0] == '\n'
376                 && pos < Msgs[msgnum].m_stop)
377             pos += (long) strlen (buffer);
378         if (feof (zp) || pos >= Msgs[msgnum].m_stop)
379             break;
380         (void) fseek (zp, pos, 0);
381         smsgs[msgp].m_start = pos;
382
383         for (c = 0;
384                 pos < Msgs[msgnum].m_stop
385                 && fgets (buffer, sizeof buffer, zp) != NULL;
386                 c = buffer[0])
387             if (strncmp (buffer, delim3, ld3) == 0
388                     && (msgp == 1 || c == '\n')
389                     && peekc (zp) == '\n')
390                 break;
391             else
392                 pos += (long) strlen (buffer);
393
394         wasdlm = strncmp (buffer, delim3, ld3) == 0;
395         if (smsgs[msgp].m_start != pos)
396             smsgs[msgp++].m_stop = (c == '\n' && wasdlm) ? pos - 1 : pos;
397         if (feof (zp) || pos >= Msgs[msgnum].m_stop) {
398             if (wasdlm)
399                 smsgs[msgp - 1].m_stop -= ((long) strlen (buffer) + 1);
400             break;
401         }
402         pos += (long) strlen (buffer);
403     }
404
405     switch (msgp--) {           /* toss "End of XXX Digest" */
406         case 0: 
407             adios (NULLCP, "burst() botch -- you lose big");
408
409         case 1: 
410             if (!quietsw)
411                 printf ("message %d not in digest format\n", msgnum);
412             return OK;
413
414         default: 
415             if (verbosw)
416                 printf ("%d message%s exploded from digest %d\n",
417                         msgp, msgp != 1 ? "s" : "", msgnum);
418             break;
419     }
420
421     if ((i = msgp + mp -> hghmsg) > MAXFOLDER) {
422         advise (NULLCP, "more than %d messages", MAXFOLDER);
423         return NOTOK;
424     }
425     if ((mp = m_remsg (mp, 0, i)) == NULL)
426         adios (NULLCP, "unable to allocate folder storage");
427
428     j = mp -> hghmsg;
429     mp -> hghmsg += msgp;
430     mp -> nummsg += msgp;
431     if (mp -> hghsel > msgnum)
432         mp -> hghsel += msgp;
433
434     if (inplace)
435         for (i = mp -> hghmsg; j > msgnum; i--, j--) {
436             if (verbosw)
437                 printf ("message %d becomes message %d\n", j, i);
438
439             Msgs[i].m_bboard_id = Msgs[j].m_bboard_id;
440             Msgs[i].m_top = Msgs[j].m_top;
441             Msgs[i].m_start = Msgs[j].m_start;
442             Msgs[i].m_stop = Msgs[j].m_stop;
443             Msgs[i].m_scanl = NULL;
444             if (Msgs[j].m_scanl) {
445                 free (Msgs[j].m_scanl);
446                 Msgs[j].m_scanl = NULL;
447             }
448             mp -> msgstats[i] = mp -> msgstats[j];
449         }
450
451     if (Msgs[msgnum].m_bboard_id == 0)
452         (void) readid (msgnum);
453
454     mp -> msgstats[msgnum] &= ~SELECTED;
455     i = inplace ? msgnum + msgp : mp -> hghmsg;
456     for (j = msgp; j >= (inplace ? 0 : 1); i--, j--) {
457         if (verbosw && i != msgnum)
458             printf ("message %d of digest %d becomes message %d\n",
459                     j, msgnum, i);
460
461         Msgs[i].m_bboard_id = Msgs[msgnum].m_bboard_id;
462         Msgs[i].m_top = Msgs[j].m_top;
463         Msgs[i].m_start = smsgs[j].m_start;
464         Msgs[i].m_stop = smsgs[j].m_stop;
465         Msgs[i].m_scanl = NULL;
466         mp -> msgstats[i] = mp -> msgstats[msgnum];
467     }
468
469     return OK;
470 }
471
472 /* \f */
473
474 static struct swit fileswit[] = {
475 #define FIDRFT  0
476     "draft", 0,
477 #define FILINK  1
478     "link", 0,
479 #define FINLINK 2
480     "nolink", 0,
481 #define FIPRES  3
482     "preserve", 0,
483 #define FINPRES 4
484     "nopreserve", 0,
485 #define FISRC   5
486     "src +folder", 0,
487 #define FIFILE  6
488     "file file", 0,
489 #define FIPROC  7
490     "rmmproc program", 0,
491 #define FINPRC  8
492     "normmproc", 0,
493 #define FIHELP  9
494     "help", 4,
495
496     NULL, 0
497 };
498
499 /* \f */
500
501 filecmd (args)
502 char  **args;
503 {
504     int     linksw = 0,
505             msgp = 0,
506             vecp = 1,
507             i,
508             msgnum;
509     char   *cp,
510             buf[BUFSIZ],
511            *msgs[MAXARGS],
512            *vec[MAXARGS];
513
514     if (fmsh) {
515         forkcmd (args, cmd_name);
516         return;
517     }
518
519     while (cp = *args++) {
520         if (*cp == '-')
521             switch (i = smatch (++cp, fileswit)) {
522                 case AMBIGSW: 
523                     ambigsw (cp, fileswit);
524                     return;
525                 case UNKWNSW: 
526                     fprintf (stderr, "-%s unknown\n", cp);
527                     return;
528                 case FIHELP: 
529                     (void) sprintf (buf, "%s +folder... [msgs] [switches]",
530                             cmd_name);
531                     help (buf, fileswit);
532                     return;
533
534                 case FILINK:
535                     linksw++;
536                     continue;
537                 case FINLINK: 
538                     linksw = 0;
539                     continue;
540
541                 case FIPRES: 
542                 case FINPRES: 
543                     continue;
544
545                 case FISRC: 
546                 case FIDRFT:
547                 case FIFILE: 
548                 case FIPROC:
549                 case FINPRC:
550                     advise (NULLCP, "sorry, -%s not allowed!", fileswit[i].sw);
551                     return;
552             }
553         if (*cp == '+' || *cp == '@')
554             vec[vecp++] = cp;
555         else
556             msgs[msgp++] = cp;
557     }
558
559     vec[0] = cmd_name;
560     vec[vecp++] = "-file";
561     vec[vecp] = NULL;
562     if (!msgp)
563         msgs[msgp++] = "cur";
564     for (msgnum = 0; msgnum < msgp; msgnum++)
565         if (!m_convert (mp, msgs[msgnum]))
566             return;
567     m_setseq (mp);
568
569     interrupted = 0;
570     for (msgnum = mp -> lowsel;
571             msgnum <= mp -> hghsel && !interrupted;
572             msgnum++)
573         if (mp -> msgstats[msgnum] & SELECTED)
574             if (process (msgnum, fileproc, vecp, vec)) {
575                 mp -> msgstats[msgnum] &= ~SELECTED;
576                 mp -> numsel--;
577             }
578
579     if (mp -> numsel != mp -> nummsg || linksw)
580         m_setcur (mp, mp -> hghsel);
581     if (!linksw)
582         rmm ();
583 }
584
585 /* \f */
586
587 int     filehak (args)
588 char  **args;
589 {
590     int     result,
591             vecp = 0;
592     char   *cp,
593            *cwd,
594            *vec[MAXARGS];
595
596     while (cp = *args++) {
597         if (*cp == '-')
598             switch (smatch (++cp, fileswit)) {
599                 case AMBIGSW: 
600                 case UNKWNSW: 
601                 case FIHELP: 
602                     return NOTOK;
603
604                 case FILINK:
605                 case FINLINK: 
606                 case FIPRES: 
607                 case FINPRES: 
608                     continue;
609
610                 case FISRC: 
611                 case FIDRFT:
612                 case FIFILE: 
613                     return NOTOK;
614             }
615         if (*cp == '+' || *cp == '@')
616             vec[vecp++] = cp;
617     }
618     vec[vecp] = NULL;
619
620     result = NOTOK;
621     cwd = NULL;
622     for (vecp = 0; (cp = vec[vecp]) && result == NOTOK; vecp++) {
623         if (cwd == NULL)
624             cwd = getcpy (pwd ());
625         (void) chdir (m_maildir (""));
626         cp = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
627         if (access (m_maildir (cp), 0) == NOTOK)
628             result = OK;
629         free (cp);
630     }
631     if (cwd)
632         (void) chdir (cwd);
633
634     return result;
635 }
636
637 /* \f */
638
639 static struct swit foldswit[] = {
640 #define FLALSW  0
641     "all", 0,
642 #define FLFASW  1
643     "fast", 0,
644 #define FLNFASW 2
645     "nofast", 0,
646 #define FLHDSW  3
647     "header", 0,
648 #define FLNHDSW 4
649     "noheader", 0,
650 #define FLPKSW  5
651     "pack", 0,
652 #define FLNPKSW 6
653     "nopack", 0,
654 #define FLRCSW  7
655     "recurse", 0,
656 #define FLNRCSW 8
657     "norecurse", 0,
658 #define FLTLSW  9
659     "total", 0,
660 #define FLNTLSW 10
661     "nototal", 0,
662 #define FLPRSW  11
663     "print", 0,
664 #define FLPUSW  12
665     "push", 0,
666 #define FLPOSW  13
667     "pop", 0,
668 #define FLLISW  14
669     "list", 0,
670 #define FLHELP  15
671     "help", 4,
672
673     NULL, 0
674 };
675
676 /* \f */
677
678 foldcmd (args)
679 char  **args;
680 {
681     int     fastsw = 0,
682             headersw = 0,
683             packsw = 0,
684             hole,
685             msgnum;
686     char   *cp,
687            *folder = NULL,
688            *msg = NULL,
689             buf[BUFSIZ],
690           **vec = args;
691
692     if (args == NULL)
693         goto fast;
694
695     while (cp = *args++) {
696         if (*cp == '-')
697             switch (smatch (++cp, foldswit)) {
698                 case AMBIGSW: 
699                     ambigsw (cp, foldswit);
700                     return;
701                 case UNKWNSW: 
702                     fprintf (stderr, "-%s unknown\n", cp);
703                     return;
704                 case FLHELP: 
705                     (void) sprintf (buf, "%s [+folder] [msg] [switches]",
706                             cmd_name);
707                     help (buf, foldswit);
708                     return;
709
710                 case FLALSW:    /* not implemented */
711                 case FLRCSW: 
712                 case FLNRCSW: 
713                 case FLTLSW: 
714                 case FLNTLSW: 
715                 case FLPRSW:
716                 case FLPUSW:
717                 case FLPOSW:
718                 case FLLISW:
719                     continue;
720
721                 case FLFASW: 
722                     fastsw++;
723                     continue;
724                 case FLNFASW: 
725                     fastsw = 0;
726                     continue;
727                 case FLHDSW: 
728                     headersw++;
729                     continue;
730                 case FLNHDSW: 
731                     headersw = 0;
732                     continue;
733                 case FLPKSW: 
734                     packsw++;
735                     continue;
736                 case FLNPKSW: 
737                     packsw = 0;
738                     continue;
739             }
740         if (*cp == '+' || *cp == '@')
741             if (folder) {
742                 advise (NULLCP, "only one folder at a time!\n");
743                 return;
744             }
745             else
746                 folder = fmsh ? path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF)
747                             : cp + 1;
748         else
749             if (msg) {
750                 advise (NULLCP, "only one message at a time!\n");
751                 return;
752             }
753             else
754                 msg = cp;
755     }
756
757     if (folder) {
758         if (*folder == 0) {
759             advise (NULLCP, "null folder names are not permitted");
760             return;
761         }
762         if (fmsh) {
763             if (access (m_maildir (folder), 04) == NOTOK) {
764                 advise (folder, "unable to read");
765                 return;
766             }
767         }
768         else {
769             (void) strcpy (buf, folder);
770             if (expand (buf) == NOTOK)
771                 return;
772             folder = buf;
773             if (access (folder, 04) == NOTOK) {
774                 advise (folder, "unable to read");
775                 return;
776             }
777         }
778         m_reset ();
779
780         if (fmsh)
781             fsetup (folder);
782         else
783             setup (folder);
784         readids (0);
785         display_info (0);
786     }
787
788     if (msg) {
789         if (!m_convert (mp, msg))
790             return;
791         m_setseq (mp);
792
793         if (mp -> numsel > 1) {
794             advise (NULLCP, "only one message at a time!");
795             return;
796         }
797         m_setcur (mp, mp -> hghsel);
798     }
799
800     if (packsw) {
801         if (fmsh) {
802             forkcmd (vec, cmd_name);
803             return;
804         }
805
806         if (mp -> lowmsg > 1 && (mp = m_remsg (mp, 1, mp -> hghmsg)) == NULL)
807             adios (NULLCP, "unable to allocate folder storage");
808         for (msgnum = mp -> lowmsg, hole = 1; msgnum <= mp -> hghmsg; msgnum++)
809             if (mp -> msgstats[msgnum] & EXISTS) {
810                 if (msgnum != hole) {
811                     Msgs[hole].m_bboard_id = Msgs[msgnum].m_bboard_id;
812                     Msgs[hole].m_top = Msgs[msgnum].m_top;
813                     Msgs[hole].m_start = Msgs[msgnum].m_start;
814                     Msgs[hole].m_stop = Msgs[msgnum].m_stop;
815                     Msgs[hole].m_scanl = NULL;
816                     if (Msgs[msgnum].m_scanl) {
817                         free (Msgs[msgnum].m_scanl);
818                         Msgs[msgnum].m_scanl = NULL;
819                     }
820                     mp -> msgstats[hole] = mp -> msgstats[msgnum];
821                     if (mp -> curmsg == msgnum)
822                         m_setcur (mp, hole);
823                 }
824                 hole++;
825             }
826         if (mp -> nummsg > 0) {
827             mp -> lowmsg = 1;
828             mp -> hghmsg = hole - 1;
829         }
830         mp -> msgflags |= MODIFIED;
831         modified++;
832     }
833
834 fast: ;
835     if (fastsw)
836         printf ("%s\n", fmsh ? fmsh : mp -> foldpath);
837     else {
838         if (headersw)
839             printf ("\t\tFolder  %*s# of messages (%*srange%*s); cur%*smsg\n",
840                 DMAXFOLDER, "", DMAXFOLDER - 2, "", DMAXFOLDER - 2, "",
841                 DMAXFOLDER - 2, "");
842         printf (args ? "%22s  " : "%s ", fmsh ? fmsh : mp -> foldpath);
843         if (mp -> hghmsg == 0)
844             printf ("has   no messages%*s",
845                     mp -> msgflags & OTHERS ? DMAXFOLDER * 2 + 4 : 0, "");
846         else {
847             printf ("has %*d message%s (%*d-%*d)",
848                     DMAXFOLDER, mp -> nummsg, mp -> nummsg != 1 ? "s" : "",
849                     DMAXFOLDER, mp -> lowmsg, DMAXFOLDER, mp -> hghmsg);
850             if (mp -> curmsg >= mp -> lowmsg
851                     && mp -> curmsg <= mp -> hghmsg)
852                 printf ("; cur=%*d", DMAXFOLDER, mp -> curmsg);
853         }
854         printf (".\n");
855     }
856 }
857
858 /* \f */
859
860 #ifndef MIME
861 #define MIMEminc(a)     (a)
862 #else   /* MIME */
863 #define MIMEminc(a)     0
864 #endif  /* MIME */
865
866 static struct swit forwswit[] = {
867 #define FOANSW  0
868     "annotate", 0,
869 #define FONANSW 1
870     "noannotate", 0,
871 #define FODFSW  2
872     "draftfolder +folder", 0,
873 #define FODMSW  3
874     "draftmessage msg", 0,
875 #define FONDFSW 4
876     "nodraftfolder", 0,
877 #define FOEDTSW 5
878     "editor editor", 0,
879 #define FONEDSW 6
880     "noedit", 0,
881 #define FOFTRSW 7
882     "filter filterfile", 0,
883 #define FOFRMSW 8
884     "form formfile", 0,
885 #define FOFTSW  9
886     "format", 5,
887 #define FONFTSW 10
888     "noformat", 7,
889 #define FOINSW  11
890     "inplace", 0,
891 #define FONINSW 12
892     "noinplace", 0,
893 #define FOMISW  13
894     "mime", MIMEminc(-4),
895 #define FONMISW 14
896     "nomime", MIMEminc(-6),
897 #define FOWHTSW 15
898     "whatnowproc program", 0,
899 #define FONWTSW 16
900     "nowhatnow", 0,
901 #define FOHELP  17
902     "help", 4,
903
904     NULL, 0
905 };
906
907 /* \f */
908
909 forwcmd (args)
910 char  **args;
911 {
912     int     msgp = 0,
913             vecp = 1,
914             mime = 0,
915             msgnum;
916     char   *cp,
917            *filter = NULL,
918             buf[BUFSIZ],
919            *msgs[MAXARGS],
920            *vec[MAXARGS];
921
922     if (fmsh) {
923         forkcmd (args, cmd_name);
924         return;
925     }
926
927     while (cp = *args++) {
928         if (*cp == '-')
929             switch (smatch (++cp, forwswit)) {
930                 case AMBIGSW: 
931                     ambigsw (cp, forwswit);
932                     return;
933                 case UNKWNSW: 
934                     fprintf (stderr, "-%s unknown\n", cp);
935                     return;
936                 case FOHELP: 
937                     (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
938                     help (buf, forwswit);
939                     return;
940
941                 case FOANSW:    /* not implemented */
942                 case FONANSW: 
943                 case FOINSW: 
944                 case FONINSW: 
945                     continue;
946
947                 case FOMISW:
948 #ifdef  MIME
949                     mime = 1;
950                     filter = NULL;
951 #endif  /* MIME */
952                     continue;
953                 case FONMISW:
954                     mime = 0;
955                     continue;
956
957                 case FONDFSW:
958                 case FONEDSW:
959                 case FONWTSW:
960                     vec[vecp++] = --cp;
961                     continue;
962
963                 case FOEDTSW: 
964                 case FOFRMSW: 
965                 case FODFSW:
966                 case FODMSW:
967                 case FOWHTSW:
968                     vec[vecp++] = --cp;
969                     if (!(cp = *args++) || *cp == '-') {
970                         advise (NULLCP, "missing argument to %s", args[-2]);
971                         return;
972                     }
973                     vec[vecp++] = cp;
974                     continue;
975                 case FOFTRSW: 
976                     if (!(filter = *args++) || *filter == '-') {
977                         advise (NULLCP, "missing argument to %s", args[-2]);
978                         return;
979                     }
980                     mime = 0;
981                     continue;
982                 case FOFTSW: 
983                     if (access (filter = myfilter, 04) == NOTOK) {
984                         advise (filter, "unable to read default filter file");
985                         return;
986                     }
987                     continue;
988                 case FONFTSW: 
989                     filter = NULL;
990                     continue;
991             }
992         if (*cp == '+' || *cp == '@') {
993             advise (NULLCP, "sorry, no folders allowed!");
994             return;
995         }
996         else
997             msgs[msgp++] = cp;
998     }
999
1000                                         /* foil search of .mh_profile */
1001     (void) sprintf (buf, "%sXXXXXX", invo_name);
1002     vec[0] = (char *)mktemp (buf);
1003     vec[vecp++] = "-file";
1004     vec[vecp] = NULL;
1005     if (!msgp)
1006         msgs[msgp++] = "cur";
1007     for (msgnum = 0; msgnum < msgp; msgnum++)
1008         if (!m_convert (mp, msgs[msgnum]))
1009             return;
1010     m_setseq (mp);
1011
1012     if (filter) {
1013         (void) strcpy (buf, filter);
1014         if (expand (buf) == NOTOK)
1015             return;
1016         if (access (filter = getcpy (libpath (buf)), 04) == NOTOK) {
1017             advise (filter, "unable to read");
1018             free (filter);
1019             return;
1020         }
1021     }
1022     forw (cmd_name, filter, vecp, vec, mime);
1023     m_setcur (mp, mp -> hghsel);
1024     if (filter)
1025         free (filter);
1026 }
1027
1028 /* \f */
1029
1030 static  forw (proc, filter, vecp, vec, mime)
1031 int     vecp,
1032         mime;
1033 char   *proc,
1034        *filter,
1035       **vec;
1036 {
1037     int     i,
1038             child_id,
1039             msgnum,
1040             msgcnt;
1041     char    tmpfil[80],
1042            *args[MAXARGS];
1043     FILE   *out;
1044 #ifdef  MIME
1045     int     nedit = 0;
1046     char   *ed = NULL;
1047 #endif  /* MIME */
1048
1049     (void) strcpy (tmpfil, m_tmpfil (invo_name));
1050     interrupted = 0;
1051     if (filter)
1052         switch (child_id = fork ()) {
1053             case NOTOK: 
1054                 advise ("fork", "unable to");
1055                 return;
1056
1057             case OK:            /* "trust me" */
1058                 if (freopen (tmpfil, "w", stdout) == NULL) {
1059                     fprintf (stderr, "unable to create ");
1060                     perror (tmpfil);
1061                     _exit (1);
1062                 }
1063                 args[0] = r1bindex (mhlproc, '/');
1064                 i = 1;
1065                 args[i++] = "-forwall";
1066                 args[i++] = "-form";
1067                 args[i++] = filter;
1068                 for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
1069                     if (mp -> msgstats[msgnum] & SELECTED)
1070                         args[i++] = getcpy (m_name (msgnum));
1071                 args[i] = NULL;
1072                 (void) mhlsbr (i, args, mhl_action);
1073                 m_eomsbr ((int (*) ()) 0);
1074                 (void) fclose (stdout);
1075                 _exit (0);
1076
1077             default: 
1078                 if (pidXwait (child_id, NULLCP))
1079                     interrupted++;
1080                 break;
1081         }
1082 #ifdef  MIME
1083     else if (mime) {
1084         int     isdf = 0,
1085                 len,
1086                 nwhat = 0;
1087 #define INITIAL_PREFIX  "----- =_aaaaaaaaaa"
1088         char   *cp,
1089                *form = NULL,
1090                 buffer[BUFSIZ],
1091                 prefix[sizeof INITIAL_PREFIX];
1092         FILE   *zp;
1093
1094         proc = whatnowproc;
1095         for (vecp = 1; cp = vec[vecp++]; )
1096             if (*cp == '-')
1097                 switch (smatch (++cp, forwswit)) {
1098                     case FOEDTSW:
1099                         ed = vec[vecp++];
1100                         nedit = 0;
1101                         continue;
1102                     case FONEDSW:
1103                         nedit++;
1104                         continue;
1105
1106                     case FOFRMSW:
1107                         form = vec[vecp++];
1108                         continue;
1109                         
1110                     case FOWHTSW:
1111                         proc = vec[vecp++];
1112                         nwhat = 0;
1113                         continue;
1114                     case FONWTSW:
1115                         nwhat++;
1116                         continue;
1117
1118 /* ignore -draftfolder / -draftmessage / -nodraftfolder */
1119                     case FODFSW:
1120                     case FODMSW:
1121                         vecp++;
1122                     case FONDFSW:
1123                         continue;
1124                 }
1125         (void) strcpy (tmpfil, m_draft (NULLCP, NULLCP, NOUSE, &isdf));
1126         if (!ed && !(ed = m_find ("editor")))
1127             ed = sysed;
1128
1129         (void) strcpy (prefix, INITIAL_PREFIX);
1130         cp = index (prefix, 'a');
1131         len = strlen (prefix);
1132
1133         for (;;) {
1134             int    hit = 0;
1135             long    pos;
1136             
1137             for (msgnum = mp -> lowsel;
1138                      msgnum <= mp -> hghsel && !interrupted && !hit;
1139                      msgnum++)
1140                 if (mp -> msgstats[msgnum] & SELECTED) {
1141                     zp = msh_ready (msgnum, 1);
1142                     if (!fmsh)
1143                         pos = ftell (zp);
1144                     while (fgets (buffer, sizeof buffer, zp) != NULL
1145                                && !fmsh
1146                                && pos < Msgs[msgnum].m_stop) {
1147                         register char   *pp;
1148
1149                         if (buffer[0] != '-' || buffer[1] != '-')
1150                             continue;
1151
1152                         for (pp = buffer + strlen (buffer) - 1;
1153                                  pp >= buffer;
1154                                  pp--)
1155                             if (!isspace (*pp))
1156                                 break;
1157                         *pp++ = '\0';
1158
1159                         if (strncmp (buffer + 2, prefix, len))
1160                             continue;
1161
1162                         hit = 1;
1163                         break;
1164                     }
1165                 }
1166
1167             if (!hit)
1168                 break;
1169
1170             if (*cp < 'z')
1171                 (*cp)++;
1172             else
1173                 if (*++cp == 0) {
1174                     advise (NULLCP,
1175                             "unable to determine unique delimiter string?!?");
1176                     return;
1177                 }
1178                 else
1179                     (*cp)++;
1180         }
1181
1182         if ((out = fopen (tmpfil, "w")) == NULL) {
1183             advise (tmpfil, "unable to create temporary file");
1184             return;
1185         }
1186         (void) chmod (tmpfil, m_gmprot ());
1187
1188         fprintf (out, "%s: %s\n", VRSN_FIELD, VRSN_VALUE);
1189         fprintf (out, "%s: multipart/digest; boundary=\"%s\"\n", TYPE_FIELD,
1190                  prefix);
1191
1192         if (!(zp = fopen (libpath (form ? form : forwcomps), "r"))) {
1193             if (form)
1194                 advise (form, "unable to open form file");
1195             else
1196                 advise (forwcomps, "unable to open default components file");
1197             (void) fclose (out);
1198             (void) unlink (tmpfil);
1199             return;
1200         }
1201         while (fgets (buffer, sizeof buffer, zp))
1202             (void) fputs (buffer, out);
1203         (void) fclose (zp);
1204
1205         for (msgnum = mp -> lowsel;
1206                  msgnum <= mp -> hghsel && !interrupted;
1207                  msgnum++)
1208             if (mp -> msgstats[msgnum] & SELECTED) {
1209                 fprintf (out, "\n--%s\n%s: message/rfc822\n\n", prefix,
1210                          TYPE_FIELD);
1211
1212                 copy_message (msgnum, out);
1213             }
1214         fprintf (out, "\n--%s--\n", prefix);
1215
1216         (void) fclose (out);
1217         if (nwhat)
1218             return;
1219     }
1220 #endif  /* MIME */
1221     else {
1222         if ((out = fopen (tmpfil, "w")) == NULL) {
1223             advise (tmpfil, "unable to create temporary file");
1224             return;
1225         }
1226
1227         msgcnt = 1;
1228         for (msgnum = mp -> lowsel;
1229                 msgnum <= mp -> hghsel && !interrupted;
1230                 msgnum++)
1231             if (mp -> msgstats[msgnum] & SELECTED) {
1232                 fprintf (out, "\n\n-------");
1233                 if (msgnum == mp -> lowsel)
1234                     fprintf (out, " Forwarded Message%s",
1235                             mp -> numsel > 1 ? "s" : "");
1236                 else
1237                     fprintf (out, " Message %d", msgcnt);
1238                 fprintf (out, "\n\n");
1239                 copy_digest (msgnum, out);
1240                 msgcnt++;
1241             }
1242
1243         fprintf (out, "\n\n------- End of Forwarded Message%s\n",
1244                 mp -> numsel > 1 ? "s" : "");
1245         (void) fclose (out);
1246     }
1247
1248     (void) fflush (stdout);
1249     if (!interrupted)
1250         switch (child_id = fork ()) {
1251             case NOTOK: 
1252                 advise ("fork", "unable to");
1253                 break;
1254
1255             case OK: 
1256                 closefds (3);
1257                 (void) signal (SIGINT, istat);
1258                 (void) signal (SIGQUIT, qstat);
1259
1260 #ifdef  MIME
1261                 if (mime) {
1262                     vecp = 0;
1263                     vec[vecp++] = r1bindex (proc, '/');
1264                     (void) m_putenv ("mhdraft", tmpfil);
1265                     (void) unputenv ("mhfolder");
1266                     (void) unputenv ("mhaltmsg");
1267                     (void) m_putenv ("mhdist", "0");
1268                     if (nedit)
1269                         (void) unputenv ("mheditor");
1270                     else
1271                         (void) m_putenv ("mheditor", ed);
1272                     (void) m_putenv ("mhuse", "0");
1273                     (void) unputenv ("mhmessages");
1274                     (void) unputenv ("mhannotate");
1275                     (void) unputenv ("mhinplace");
1276                 }
1277                 else
1278 #endif  /* MIME */
1279
1280                 vec[vecp++] = tmpfil;
1281                 vec[vecp] = NULL;
1282
1283                 execvp (proc, vec);
1284                 fprintf (stderr, "unable to exec ");
1285                 perror (proc);
1286                 _exit (1);
1287
1288             default: 
1289                 (void) pidXwait (child_id, NULLCP);
1290                 break;
1291         }
1292
1293 #ifdef  MIME
1294     if (!mime)
1295 #endif  /* MIME */
1296     (void) unlink (tmpfil);
1297 }
1298
1299 /* \f */
1300
1301 static char *hlpmsg[] = {
1302     "The %s program emulates many of the commands found in the Rand MH",
1303     "system.  Instead of operating on MH folders, commands to %s concern",
1304     "a single file.",
1305     "",
1306     "To see the list of commands available, just type a ``?'' followed by",
1307     "the RETURN key.  To find out what switches each command takes, type",
1308     "the name of the command followed by ``-help''.  To leave %s, use the",
1309     "``quit'' command.",
1310     "",
1311     "Although a lot of MH commands are found in %s, not all are fully",
1312     "implemented.  %s will always recognize all legal switches for a",
1313     "given command though, and will let you know when you ask for an",
1314     "option that it is unable to perform.",
1315     "",
1316     "Running %s is fun, but using MH from your shell is far superior.",
1317     "After you have familiarized yourself with the MH style by using %s,",
1318     "you should try using MH from the shell.  You can still use %s for",
1319     "message files that aren't in MH format, such as BBoard files.",
1320     NULL
1321 };
1322
1323
1324 /* ARGSUSED */
1325
1326 helpcmd (args)
1327 char  **args;
1328 {
1329     int     i;
1330
1331     for (i = 0; hlpmsg[i]; i++) {
1332         printf (hlpmsg[i], invo_name);
1333         (void) putchar ('\n');
1334     }
1335 }
1336
1337 /* \f */
1338
1339 static struct swit markswit[] = {
1340 #define MADDSW  0
1341     "add", 0,
1342 #define MDELSW  1
1343     "delete", 0,
1344 #define MLSTSW  2
1345     "list", 0,
1346 #define MSEQSW  3
1347     "sequence name", 0,
1348 #define MPUBSW  4
1349     "public", 0,
1350 #define MNPUBSW 5
1351     "nopublic", 0,
1352 #define MZERSW  6
1353     "zero", 0,
1354 #define MNZERSW 7
1355     "nozero", 0,
1356 #define MHELP   8
1357     "help", 4,
1358 #define MDBUGSW 9
1359     "debug", -5,
1360
1361     NULL, 0
1362 };
1363
1364 /* \f */
1365
1366 markcmd (args)
1367 char  **args;
1368 {
1369     int     addsw = 0,
1370             deletesw = 0,
1371             debugsw = 0,
1372             listsw = 0,
1373             zerosw = 0,
1374             seqp = 0,
1375             msgp = 0,
1376             i,
1377             msgnum;
1378     char   *cp,
1379             buf[BUFSIZ],
1380            *seqs[NATTRS + 1],
1381            *msgs[MAXARGS];
1382
1383     while (cp = *args++) {
1384         if (*cp == '-')
1385             switch (smatch (++cp, markswit)) {
1386                 case AMBIGSW: 
1387                     ambigsw (cp, markswit);
1388                     return;
1389                 case UNKWNSW: 
1390                     fprintf (stderr, "-%s unknown\n", cp);
1391                     return;
1392                 case MHELP: 
1393                     (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
1394                     help (buf, markswit);
1395                     return;
1396
1397                 case MADDSW: 
1398                     addsw++;
1399                     deletesw = listsw = 0;
1400                     continue;
1401                 case MDELSW: 
1402                     deletesw++;
1403                     addsw = listsw = 0;
1404                     continue;
1405                 case MLSTSW: 
1406                     listsw++;
1407                     addsw = deletesw = 0;
1408                     continue;
1409
1410                 case MSEQSW: 
1411                     if (!(cp = *args++) || *cp == '-') {
1412                         advise (NULLCP, "missing argument to %s", args[-2]);
1413                         return;
1414                     }
1415                     if (seqp < NATTRS)
1416                         seqs[seqp++] = cp;
1417                     else {
1418                         advise (NULLCP, "only %d sequences allowed!", NATTRS);
1419                         return;
1420                     }
1421                     continue;
1422
1423                 case MPUBSW:    /* not implemented */
1424                 case MNPUBSW: 
1425                     continue;
1426
1427                 case MDBUGSW: 
1428                     debugsw++;
1429                     continue;
1430
1431                 case MZERSW: 
1432                     zerosw++;
1433                     continue;
1434                 case MNZERSW: 
1435                     zerosw = 0;
1436                     continue;
1437             }
1438         if (*cp == '+' || *cp == '@') {
1439             advise (NULLCP, "sorry, no folders allowed!");
1440             return;
1441         }
1442         else
1443             msgs[msgp++] = cp;
1444     }
1445
1446     if (!addsw && !deletesw && !listsw)
1447         if (seqp)
1448             addsw++;
1449         else
1450             if (debugsw)
1451                 listsw++;
1452             else {
1453                 seqs[seqp++] = "unseen";
1454                 deletesw++;
1455                 zerosw = 0;
1456                 if (!msgp)
1457                     msgs[msgp++] = "all";
1458             }
1459
1460     if (!msgp)
1461         msgs[msgp++] = listsw ? "all" :"cur";
1462     for (msgnum = 0; msgnum < msgp; msgnum++)
1463         if (!m_convert (mp, msgs[msgnum]))
1464             return;
1465
1466     if (debugsw) {
1467         printf ("invo_name=%s mypath=%s defpath=%s\n",
1468                 invo_name, mypath, defpath);
1469         printf ("ctxpath=%s context flags=%s\n",
1470                 ctxpath, sprintb (buf, (unsigned) ctxflags, DBITS));
1471         printf ("foldpath=%s flags=%s\n",
1472                 mp -> foldpath,
1473                 sprintb (buf, (unsigned) mp -> msgflags, FBITS));
1474         printf ("hghmsg=%d lowmsg=%d nummsg=%d curmsg=%d\n",
1475                 mp -> hghmsg, mp -> lowmsg, mp -> nummsg, mp -> curmsg);
1476         printf ("lowsel=%d hghsel=%d numsel=%d\n",
1477                 mp -> lowsel, mp -> hghsel, mp -> numsel);
1478 #ifndef MTR
1479         printf ("lowoff=%d hghoff=%d\n",
1480                 mp -> lowoff, mp -> hghoff);
1481 #else   /* MTR */
1482         printf ("lowoff=%d hghoff=%d msgbase=0x%x msgstats=0x%x\n",
1483                 mp -> lowoff, mp -> hghoff, mp -> msgbase, mp -> msgstats);
1484 #endif  /* MTR */
1485     }
1486
1487     if (seqp == 0 && (addsw || deletesw)) {
1488         advise (NULLCP, "-%s requires at least one -sequence argument",
1489                 addsw ? "add" : "delete");
1490         return;
1491     }
1492     seqs[seqp] = NULL;
1493
1494     if (addsw)
1495         for (seqp = 0; seqs[seqp]; seqp++) {
1496             if (zerosw && !m_seqnew (mp, seqs[seqp], 0))
1497                 return;
1498             for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
1499                 if (mp -> msgstats[msgnum] & SELECTED)
1500                     if (!m_seqadd (mp, seqs[seqp], msgnum, 0))
1501                         return;
1502         }
1503
1504     if (deletesw)
1505         for (seqp = 0; seqs[seqp]; seqp++) {
1506             if (zerosw)
1507                 for (msgnum = mp -> lowmsg; msgnum <= mp -> hghmsg; msgnum++)
1508                     if (mp -> msgstats[msgnum] & EXISTS)
1509                         if (!m_seqadd (mp, seqs[seqp], msgnum, 0))
1510                             return;
1511             for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
1512                 if (mp -> msgstats[msgnum] & SELECTED)
1513                     if (!m_seqdel (mp, seqs[seqp], msgnum))
1514                         return;
1515         }
1516
1517     if (listsw) {
1518         int     bits = FFATTRSLOT;
1519
1520 #define empty(s)        ((s) ? (s) : "")
1521         if (seqp == 0)
1522             for (i = 0; mp -> msgattrs[i]; i++)
1523                 printf ("%s%s: %s\n", mp -> msgattrs[i],
1524                         mp -> attrstats & (1 << (bits + i))
1525                         ? " (private)" : "",
1526                         empty(m_seq (mp, mp -> msgattrs[i])));
1527         else
1528             for (seqp = 0; seqs[seqp]; seqp++)
1529                 printf ("%s%s: %s\n", seqs[seqp],
1530                         empty(m_seq (mp, seqs[seqp])));
1531 #undef  empty
1532
1533         interrupted = 0;
1534         if (debugsw)
1535             for (msgnum = mp -> lowsel;
1536                     msgnum <= mp -> hghsel && !interrupted;
1537                     msgnum++)
1538                 if (mp -> msgstats[msgnum] & SELECTED) {
1539                     printf ("%*d: id=%d top=%d start=%ld stop=%ld %s\n",
1540                             DMAXFOLDER, msgnum,
1541                             Msgs[msgnum].m_bboard_id, Msgs[msgnum].m_top,
1542                             Msgs[msgnum].m_start, Msgs[msgnum].m_stop,
1543                             sprintb (buf, (unsigned) mp -> msgstats[msgnum],
1544                                 m_seqbits (mp)));
1545                     if (Msgs[msgnum].m_scanl)
1546                         printf ("%s", Msgs[msgnum].m_scanl);
1547                 }                           
1548     }
1549 }
1550
1551 /* \f */
1552
1553 #ifdef MIME
1554 static struct swit mhnswit[] = {
1555 #define MHNAUTOSW         0
1556     "auto", 0,
1557 #define MHNNAUTOSW        1
1558     "noauto", 0,
1559 #define MHNDEBUGSW        2
1560     "debug", -5,
1561 #define MHNEBCDICSW      3
1562     "ebcdicsafe", 0,
1563 #define MHNNEBCDICSW     4
1564     "noebcdicsafe", 0,
1565 #define MHNFORMSW         5
1566     "form formfile", 4,
1567 #define MHNHEADSW         6
1568     "headers", 0,
1569 #define MHNNHEADSW        7
1570     "noheaders", 0,
1571 #define MHNLISTSW         8
1572     "list", 0,
1573 #define MHNNLISTSW        9
1574     "nolist", 0,
1575 #define MHNPARTSW        10
1576     "part number", 0,
1577 #define MHNSIZESW        11
1578     "realsize", 0,
1579 #define MHNNSIZESW       12
1580     "norealsize", 0,
1581 #define MHNRFC934SW      13
1582     "rfc934mode", 0,
1583 #define MHNNRFC934SW     14
1584     "norfc934mode", 0,
1585 #define MHNSERIALSW      15
1586     "serialonly", 0,
1587 #define MHNNSERIALSW     16
1588     "noserialonly", 0,
1589 #define MHNSHOWSW        17
1590     "show", 0,
1591 #define MHNNSHOWSW       18
1592     "noshow", 0,
1593 #define MHNSTORESW       19
1594     "store", 0,
1595 #define MHNNSTORESW      20
1596     "nostore", 0,
1597 #define MHNTYPESW        21
1598     "type content", 0,
1599 #define MHNVERBSW        22
1600     "verbose", 0,
1601 #define MHNNVERBSW       23
1602     "noverbose", 0,
1603 #define MHNHELPSW        24
1604     "help", 4,
1605 #define MHNPROGSW        25
1606     "moreproc program", -4,
1607 #define MHNNPROGSW       26
1608     "nomoreproc", -3,
1609 #define MHNLENSW         27
1610     "length lines", -4,
1611 #define MHNWIDSW         28
1612     "width columns", -4,
1613
1614     NULL, 0
1615 };
1616
1617 /* \f */
1618
1619 mhncmd (args)
1620 char  **args;
1621 {
1622     int     msgp = 0,
1623             vecp = 1,
1624             i,
1625             msgnum;
1626     char   *cp,
1627             buf[BUFSIZ],
1628            *msgs[MAXARGS],
1629            *vec[MAXARGS];
1630
1631     if (fmsh) {
1632         forkcmd (args, cmd_name);
1633         return;
1634     }
1635
1636     while (cp = *args++) {
1637         if (*cp == '-')
1638             switch (smatch (++cp, mhnswit)) {
1639                 case AMBIGSW: 
1640                     ambigsw (cp, mhnswit);
1641                     return;
1642                 case UNKWNSW: 
1643                     fprintf (stderr, "-%s unknown\n", cp);
1644                     return;
1645                 case MHNHELPSW:
1646                     (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
1647                     help (buf, mhnswit);
1648                     return;
1649
1650                 case MHNAUTOSW:
1651                 case MHNNAUTOSW:
1652                 case MHNDEBUGSW:
1653                 case MHNEBCDICSW:
1654                 case MHNNEBCDICSW:
1655                 case MHNHEADSW:
1656                 case MHNNHEADSW:
1657                 case MHNLISTSW:
1658                 case MHNNLISTSW:
1659                 case MHNSIZESW:
1660                 case MHNNSIZESW:
1661                 case MHNRFC934SW:
1662                 case MHNNRFC934SW:
1663                 case MHNSERIALSW:
1664                 case MHNNSERIALSW:
1665                 case MHNSHOWSW:
1666                 case MHNNSHOWSW:
1667                 case MHNSTORESW:
1668                 case MHNNSTORESW:
1669                 case MHNVERBSW:
1670                 case MHNNVERBSW:
1671                 case MHNNPROGSW:
1672                     vec[vecp++] = --cp;
1673                     continue;
1674
1675                 case MHNFORMSW:
1676                 case MHNPARTSW:
1677                 case MHNTYPESW:
1678                 case MHNPROGSW:
1679                 case MHNLENSW:
1680                 case MHNWIDSW:
1681                     vec[vecp++] = --cp;
1682                     if (!(cp = *args++) || *cp == '-') {
1683                         advise (NULLCP, "missing argument to %s", args[-2]);
1684                         return;
1685                     }
1686                     vec[vecp++] = cp;
1687                     continue;
1688             }
1689         if (*cp == '+' || *cp == '@') {
1690             advise (NULLCP, "sorry, no folders allowed!");
1691             return;
1692         }
1693         else
1694             msgs[msgp++] = cp;
1695     }
1696
1697     vec[0] = cmd_name;
1698     vec[vecp++] = "-file";
1699     vec[vecp] = NULL;
1700     if (!msgp)
1701         msgs[msgp++] = "cur";
1702     for (msgnum = 0; msgnum < msgp; msgnum++)
1703         if (!m_convert (mp, msgs[msgnum]))
1704             return;
1705     m_setseq (mp);
1706
1707     interrupted = 0;
1708     for (msgnum = mp -> lowsel;
1709             msgnum <= mp -> hghsel && !interrupted;
1710             msgnum++)
1711         if (mp -> msgstats[msgnum] & SELECTED)
1712             if (process (msgnum, cmd_name, vecp, vec)) {
1713                 mp -> msgstats[msgnum] &= ~SELECTED;
1714                 mp -> numsel--;
1715             }
1716
1717     m_setcur (mp, mp -> hghsel);
1718 }
1719
1720 /* \f */
1721
1722 #endif /* MIME */
1723 static struct swit packswit[] = {
1724 #define PAFISW  0
1725     "file name", 0,
1726
1727 #define PAHELP  1
1728     "help", 4,
1729
1730     NULL, 0
1731 };
1732
1733 /* \f */
1734
1735 packcmd (args)
1736 char  **args;
1737 {
1738     int     msgp = 0,
1739             md,
1740             msgnum;
1741     char   *cp,
1742            *file = NULL,
1743             buf[BUFSIZ],
1744            *msgs[MAXARGS];
1745     struct stat st;
1746
1747     if (fmsh) {
1748         forkcmd (args, cmd_name);
1749         return;
1750     }
1751
1752     while (cp = *args++) {
1753         if (*cp == '-')
1754             switch (smatch (++cp, packswit)) {
1755                 case AMBIGSW: 
1756                     ambigsw (cp, packswit);
1757                     return;
1758                 case UNKWNSW: 
1759                     fprintf (stderr, "-%s unknown\n", cp);
1760                     return;
1761                 case PAHELP: 
1762                     (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
1763                     help (buf, packswit);
1764                     return;
1765
1766                 case PAFISW: 
1767                     if (!(file = *args++) || *file == '-') {
1768                         advise (NULLCP, "missing argument to %s", args[-2]);
1769                         return;
1770                     }
1771                     continue;
1772             }
1773         if (*cp == '+' || *cp == '@') {
1774             advise (NULLCP, "sorry, no folders allowed!");
1775             return;
1776         }
1777         else
1778             msgs[msgp++] = cp;
1779     }
1780
1781     if (!file)
1782         file = "./msgbox";
1783     file = path (file, TFILE);
1784     if (stat (file, &st) == NOTOK) {
1785         if (errno != ENOENT) {
1786             advise (file, "error on file");
1787             goto done_pack;
1788         }
1789         md = getanswer (cp = concat ("Create file \"", file, "\"? ", NULLCP));
1790         free (cp);
1791         if (!md)
1792             goto done_pack;
1793     }
1794
1795     if (!msgp)
1796         msgs[msgp++] = "all";
1797     for (msgnum = 0; msgnum < msgp; msgnum++)
1798         if (!m_convert (mp, msgs[msgnum]))
1799             goto done_pack;
1800     m_setseq (mp);
1801
1802     if ((md = mbx_open (file, getuid (), getgid (), m_gmprot ())) == NOTOK) {
1803         advise (file, "unable to open");
1804         goto done_pack;
1805     }
1806     for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
1807         if (mp -> msgstats[msgnum] & SELECTED)
1808             if (pack (file, md, msgnum) == NOTOK)
1809                 break;
1810     (void) mbx_close (file, md);
1811
1812     if (mp -> hghsel != mp -> curmsg)
1813         m_setcur (mp, mp -> lowsel);
1814
1815 done_pack: ;
1816     free (file);
1817 }
1818
1819 /* \f */
1820
1821 int     pack (mailbox, md, msgnum)
1822 char   *mailbox;
1823 int     md,
1824         msgnum;
1825 {
1826     register FILE *zp;
1827
1828     if (Msgs[msgnum].m_bboard_id == 0)
1829         (void) readid (msgnum);
1830
1831     zp = msh_ready (msgnum, 1);
1832     return mbx_write (mailbox, md, zp, Msgs[msgnum].m_bboard_id,
1833             0L, ftell (zp), Msgs[msgnum].m_stop, 1, 1);
1834 }
1835
1836 /* \f */
1837
1838 int     packhak (args)
1839 char  **args;
1840 {
1841     int     result;
1842     char   *cp,
1843            *file = NULL;
1844
1845     while (cp = *args++) {
1846         if (*cp == '-')
1847             switch (smatch (++cp, packswit)) {
1848                 case AMBIGSW: 
1849                 case UNKWNSW: 
1850                 case PAHELP: 
1851                     return NOTOK;
1852
1853                 case PAFISW: 
1854                     if (!(file = *args++) || *file == '-') 
1855                         return NOTOK;
1856                     continue;
1857             }
1858         if (*cp == '+' || *cp == '@')
1859             return NOTOK;
1860     }
1861
1862     file = path (file ? file : "./msgbox", TFILE);
1863     result = access (file, 0) == NOTOK ? OK : NOTOK;
1864     free (file);
1865
1866     return result;
1867 }
1868
1869 /* \f */
1870
1871 static struct swit pickswit[] = {
1872 #define PIANSW  0
1873     "and", 0,
1874 #define PIORSW  1
1875     "or", 0,
1876 #define PINTSW  2
1877     "not", 0,
1878 #define PILBSW  3
1879     "lbrace", 0,
1880 #define PIRBSW  4
1881     "rbrace", 0,
1882
1883 #define PICCSW  5
1884     "cc  pattern", 0,
1885 #define PIDASW  6
1886     "date  pattern", 0,
1887 #define PIFRSW  7
1888     "from  pattern", 0,
1889 #define PISESW  8
1890     "search  pattern", 0,
1891 #define PISUSW  9
1892     "subject  pattern", 0,
1893 #define PITOSW  10
1894     "to  pattern", 0,
1895 #define PIOTSW  11
1896     "-othercomponent  pattern", 15,
1897 #define PIAFSW  12
1898     "after date", 0,
1899 #define PIBFSW  13
1900     "before date", 0,
1901 #define PIDFSW  14
1902     "datefield field", 5,
1903 #define PISQSW  15
1904     "sequence name", 0,
1905 #define PIPUSW  16
1906     "public", 0,
1907 #define PINPUSW 17
1908     "nopublic", 0,
1909 #define PIZRSW  18
1910     "zero", 0,
1911 #define PINZRSW 19
1912     "nozero", 0,
1913 #define PILISW  20
1914     "list", 0,
1915 #define PINLISW 21
1916     "nolist", 0,
1917 #define PIHELP  22
1918     "help", 4,
1919
1920     NULL, 0
1921 };
1922
1923 /* \f */
1924
1925 pickcmd (args)
1926 char  **args;
1927 {
1928     int     zerosw = 1,
1929             msgp = 0,
1930             seqp = 0,
1931             vecp = 0,
1932             hi,
1933             lo,
1934             msgnum;
1935     char   *cp,
1936             buf[BUFSIZ],
1937            *msgs[MAXARGS],
1938            *seqs[NATTRS],
1939            *vec[MAXARGS];
1940     register FILE *zp;
1941
1942     while (cp = *args++) {
1943         if (*cp == '-') {
1944             if (*++cp == '-') {
1945                 vec[vecp++] = --cp;
1946                 goto pattern;
1947             }
1948             switch (smatch (cp, pickswit)) {
1949                 case AMBIGSW: 
1950                     ambigsw (cp, pickswit);
1951                     return;
1952                 case UNKWNSW: 
1953                     fprintf (stderr, "-%s unknown\n", cp);
1954                     return;
1955                 case PIHELP: 
1956                     (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
1957                     help (buf, pickswit);
1958                     return;
1959
1960                 case PICCSW: 
1961                 case PIDASW: 
1962                 case PIFRSW: 
1963                 case PISUSW: 
1964                 case PITOSW: 
1965                 case PIDFSW: 
1966                 case PIAFSW: 
1967                 case PIBFSW: 
1968                 case PISESW: 
1969                     vec[vecp++] = --cp;
1970 pattern: ;
1971                     if (!(cp = *args++)) {/* allow -xyz arguments */
1972                         advise (NULLCP, "missing argument to %s", args[-2]);
1973                         return;
1974                     }
1975                     vec[vecp++] = cp;
1976                     continue;
1977                 case PIOTSW: 
1978                     advise (NULLCP, "internal error!");
1979                     return;
1980                 case PIANSW: 
1981                 case PIORSW: 
1982                 case PINTSW: 
1983                 case PILBSW: 
1984                 case PIRBSW: 
1985                     vec[vecp++] = --cp;
1986                     continue;
1987
1988                 case PISQSW: 
1989                     if (!(cp = *args++) || *cp == '-') {
1990                         advise (NULLCP, "missing argument to %s", args[-2]);
1991                         return;
1992                     }
1993                     if (seqp < NATTRS)
1994                         seqs[seqp++] = cp;
1995                     else {
1996                         advise (NULLCP, "only %d sequences allowed!", NATTRS);
1997                         return;
1998                     }
1999                     continue;
2000                 case PIZRSW: 
2001                     zerosw++;
2002                     continue;
2003                 case PINZRSW: 
2004                     zerosw = 0;
2005                     continue;
2006
2007                 case PIPUSW:    /* not implemented */
2008                 case PINPUSW: 
2009                 case PILISW: 
2010                 case PINLISW: 
2011                     continue;
2012             }
2013         }
2014         if (*cp == '+' || *cp == '@') {
2015             advise (NULLCP, "sorry, no folders allowed!");
2016             return;
2017         }
2018         else
2019             msgs[msgp++] = cp;
2020     }
2021     vec[vecp] = NULL;
2022
2023     if (!msgp)
2024         msgs[msgp++] = "all";
2025     for (msgnum = 0; msgnum < msgp; msgnum++)
2026         if (!m_convert (mp, msgs[msgnum]))
2027             return;
2028     m_setseq (mp);
2029
2030     interrupted = 0;
2031     if (!pcompile (vec, NULLCP))
2032         return;
2033
2034     lo = mp -> lowsel;
2035     hi = mp -> hghsel;
2036
2037     for (msgnum = mp -> lowsel;
2038             msgnum <= mp -> hghsel && !interrupted;
2039             msgnum++)
2040         if (mp -> msgstats[msgnum] & SELECTED) {
2041             zp = msh_ready (msgnum, 1);
2042             if (pmatches (zp, msgnum, fmsh ? 0L : Msgs[msgnum].m_start,
2043                         fmsh ? 0L : Msgs[msgnum].m_stop)) {
2044                 if (msgnum < lo)
2045                     lo = msgnum;
2046                 if (msgnum > hi)
2047                     hi = msgnum;
2048             }
2049             else {
2050                 mp -> msgstats[msgnum] &= ~SELECTED;
2051                 mp -> numsel--;
2052             }
2053         }
2054
2055     if (interrupted)
2056         return;
2057
2058     mp -> lowsel = lo;
2059     mp -> hghsel = hi;
2060
2061     if (mp -> numsel <= 0) {
2062         advise (NULLCP, "no messages match specification");
2063         return;
2064     }
2065
2066     seqs[seqp] = NULL;
2067     for (seqp = 0; seqs[seqp]; seqp++) {
2068         if (zerosw && !m_seqnew (mp, seqs[seqp], 0))
2069             return;
2070         for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
2071             if (mp -> msgstats[msgnum] & SELECTED)
2072                 if (!m_seqadd (mp, seqs[seqp], msgnum, 0))
2073                     return;
2074     }
2075
2076     printf ("%d hit%s\n", mp -> numsel, mp -> numsel == 1 ? "" : "s");
2077 }
2078
2079 /* \f */
2080
2081 static struct swit replswit[] = {
2082 #define REANSW  0
2083     "annotate", 0,
2084 #define RENANSW 1
2085     "noannotate", 0,
2086 #define RECCSW  2
2087     "cc type", 0,
2088 #define RENCCSW 3
2089     "nocc type", 0,
2090 #define REDFSW  4
2091     "draftfolder +folder", 0,
2092 #define REDMSW  5
2093     "draftmessage msg", 0,
2094 #define RENDFSW 6
2095     "nodraftfolder", 0,
2096 #define REEDTSW 7
2097     "editor editor", 0,
2098 #define RENEDSW 8
2099     "noedit", 0,
2100 #define REFCCSW 9
2101     "fcc +folder", 0,
2102 #define REFLTSW 10
2103     "filter filterfile", 0,
2104 #define REFRMSW 11
2105     "form formfile", 0,
2106 #define REINSW  12
2107     "inplace", 0,
2108 #define RENINSW 13
2109     "noinplace", 0,
2110 #define REQUSW  14
2111     "query", 0,
2112 #define RENQUSW 15
2113     "noquery", 0,
2114 #define REWHTSW 16
2115     "whatnowproc program", 0,
2116 #define RENWTSW 17
2117     "nowhatnow", 0,
2118 #define REWIDSW 19
2119     "width columns", 0,
2120 #define REHELP  20
2121     "help", 4,
2122
2123     NULL, 0
2124 };
2125
2126 /* \f */
2127
2128 replcmd (args)
2129 char  **args;
2130 {
2131     int     vecp = 1;
2132     char   *cp,
2133            *msg = NULL,
2134             buf[BUFSIZ],
2135            *vec[MAXARGS];
2136
2137     if (fmsh) {
2138         forkcmd (args, cmd_name);
2139         return;
2140     }
2141
2142     while (cp = *args++) {
2143         if (*cp == '-')
2144             switch (smatch (++cp, replswit)) {
2145                 case AMBIGSW: 
2146                     ambigsw (cp, replswit);
2147                     return;
2148                 case UNKWNSW: 
2149                     fprintf (stderr, "-%s unknown\n", cp);
2150                     return;
2151                 case REHELP: 
2152                     (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
2153                     help (buf, replswit);
2154                     return;
2155
2156                 case REANSW:    /* not implemented */
2157                 case RENANSW: 
2158                 case REINSW: 
2159                 case RENINSW: 
2160                     continue;
2161
2162                 case REQUSW:
2163                 case RENQUSW:
2164                 case RENDFSW:
2165                 case RENEDSW:
2166                 case RENWTSW:
2167                     vec[vecp++] = --cp;
2168                     continue;
2169
2170                 case RECCSW: 
2171                 case RENCCSW: 
2172                 case REEDTSW: 
2173                 case REFCCSW: 
2174                 case REFLTSW:
2175                 case REFRMSW: 
2176                 case REWIDSW: 
2177                 case REDFSW:
2178                 case REDMSW:
2179                 case REWHTSW:
2180                     vec[vecp++] = --cp;
2181                     if (!(cp = *args++) || *cp == '-') {
2182                         advise (NULLCP, "missing argument to %s", args[-2]);
2183                         return;
2184                     }
2185                     vec[vecp++] = cp;
2186                     continue;
2187             }
2188         if (*cp == '+' || *cp == '@') {
2189             advise (NULLCP, "sorry, no folders allowed!");
2190             return;
2191         }
2192         else
2193             if (msg) {
2194                 advise (NULLCP, "only one message at a time!");
2195                 return;
2196             }
2197             else
2198                 msg = cp;
2199     }
2200
2201     vec[0] = cmd_name;
2202     vec[vecp++] = "-file";
2203     vec[vecp] = NULL;
2204     if (!msg)
2205         msg = "cur";
2206     if (!m_convert (mp, msg))
2207         return;
2208     m_setseq (mp);
2209
2210     if (mp -> numsel > 1) {
2211         advise (NULLCP, "only one message at a time!");
2212         return;
2213     }
2214     (void) process (mp -> hghsel, cmd_name, vecp, vec);
2215     m_setcur (mp, mp -> hghsel);
2216 }
2217
2218 /* \f */
2219
2220 static struct swit rmmswit[] = {
2221 #define RMHELP  0
2222     "help", 4,
2223
2224     NULL, 0
2225 };
2226
2227 /* \f */
2228
2229 rmmcmd (args)
2230 char  **args;
2231 {
2232     int     msgp = 0,
2233             msgnum;
2234     char   *cp,
2235             buf[BUFSIZ],
2236            *msgs[MAXARGS];
2237
2238     while (cp = *args++) {
2239         if (*cp == '-')
2240             switch (smatch (++cp, rmmswit)) {
2241                 case AMBIGSW: 
2242                     ambigsw (cp, rmmswit);
2243                     return;
2244                 case UNKWNSW: 
2245                     fprintf (stderr, "-%s unknown\n", cp);
2246                     return;
2247                 case RMHELP: 
2248                     (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
2249                     help (buf, rmmswit);
2250                     return;
2251             }
2252         if (*cp == '+' || *cp == '@') {
2253             advise (NULLCP, "sorry, no folders allowed!");
2254             return;
2255         }
2256         else
2257             msgs[msgp++] = cp;
2258     }
2259
2260     if (!msgp)
2261         msgs[msgp++] = "cur";
2262     for (msgnum = 0; msgnum < msgp; msgnum++)
2263         if (!m_convert (mp, msgs[msgnum]))
2264             return;
2265     m_setseq (mp);
2266
2267     rmm ();
2268 }
2269
2270 /* \f */
2271
2272 static  rmm () {
2273     register int    msgnum,
2274                     vecp;
2275     register char  *cp;
2276     char    buffer[BUFSIZ],
2277            *vec[MAXARGS];
2278
2279     if (fmsh) {
2280         if (rmmproc) {
2281             if (mp -> numsel > MAXARGS - 1) {
2282                 advise (NULLCP, "more than %d messages for %s exec",
2283                         MAXARGS - 1, rmmproc);
2284                 return;
2285             }
2286             vecp = 0;
2287             for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
2288                 if (mp -> msgstats[msgnum] & SELECTED)
2289                     vec[vecp++] = getcpy (m_name (msgnum));
2290             vec[vecp] = NULL;
2291             forkcmd (vec, rmmproc);
2292             for (vecp = 0; vec[vecp]; vecp++)
2293                 free (vec[vecp]);
2294         }
2295         else
2296             for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
2297                 if (mp -> msgstats[msgnum] & SELECTED) {
2298                     (void) strcpy (buffer, m_backup (cp = m_name (msgnum)));
2299                     if (rename (cp, buffer) == NOTOK)
2300                         admonish (buffer, "unable to rename %s to", cp);
2301                 }
2302     }
2303
2304     for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
2305         if (mp -> msgstats[msgnum] & SELECTED) {
2306             mp -> msgstats[msgnum] |= DELETED;
2307             mp -> msgstats[msgnum] &= ~EXISTS;
2308 #ifdef  MPOP
2309 #ifdef  BPOP
2310             if (pmsh && pop_dele (msgnum) != OK)
2311                 fprintf (stderr, "%s", response);
2312 #endif
2313 #endif /* MPOP */
2314         }
2315
2316     if ((mp -> nummsg -= mp -> numsel) <= 0) {
2317         if (fmsh)
2318             admonish (NULLCP, "no messages remaining in +%s", fmsh);
2319         else
2320             admonish (NULLCP, "no messages remaining in %s", mp -> foldpath);
2321         mp -> lowmsg = mp -> hghmsg = mp -> nummsg = 0;
2322     }
2323     if (mp -> lowsel == mp -> lowmsg) {
2324         for (msgnum = mp -> lowmsg + 1; msgnum <= mp -> hghmsg; msgnum++)
2325             if (mp -> msgstats[msgnum] & EXISTS)
2326                 break;
2327         mp -> lowmsg = msgnum;
2328     }
2329     if (mp -> hghsel == mp -> hghmsg) {
2330         for (msgnum = mp -> hghmsg - 1; msgnum >= mp -> lowmsg; msgnum--)
2331             if (mp -> msgstats[msgnum] & EXISTS)
2332                 break;
2333         mp -> hghmsg = msgnum;
2334     }
2335
2336     mp -> msgflags |= MODIFIED;
2337     modified++;
2338 }
2339
2340 /* \f */
2341
2342 static struct swit scanswit[] = {
2343 #define SCCLR   0
2344     "clear", 0,
2345 #define SCNCLR  1
2346     "noclear", 0,
2347 #define SCFORM  2
2348     "form formatfile", 0,
2349 #define SCFMT   3
2350     "format string", 5,
2351 #define SCHEAD  4
2352     "header", 0,
2353 #define SCNHEAD 5
2354     "noheader", 0,
2355 #define SCWID   6
2356     "width columns", 0,
2357 #define SCHELP  7
2358     "help", 4,
2359
2360     NULL, 0
2361 };
2362
2363 /* \f */
2364
2365 scancmd (args)
2366 char  **args;
2367 {
2368 #define equiv(a,b)      (a ? b && !strcmp (a, b) : !b)
2369
2370     int     clearsw = 0,
2371             headersw = 0,
2372             width = 0,
2373             msgp = 0,
2374             msgnum,
2375             optim,
2376             state;
2377     char   *cp,
2378            *form = NULL,
2379            *format = NULL,
2380             buf[BUFSIZ],
2381            *nfs,
2382            *msgs[MAXARGS];
2383     register FILE *zp;
2384 #ifdef  MPOP
2385 #ifdef  BPOP
2386     static int p_optim = 0;
2387 #endif
2388 #endif /* MPOP */
2389     static int s_optim = 0;
2390     static char *s_form = NULL,
2391                 *s_format = NULL;
2392
2393     while (cp = *args++) {
2394         if (*cp == '-')
2395             switch (smatch (++cp, scanswit)) {
2396                 case AMBIGSW: 
2397                     ambigsw (cp, scanswit);
2398                     return;
2399                 case UNKWNSW: 
2400                     fprintf (stderr, "-%s unknown\n", cp);
2401                     return;
2402                 case SCHELP: 
2403                     (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
2404                     help (buf, scanswit);
2405                     return;
2406
2407                 case SCCLR: 
2408                     clearsw++;
2409                     continue;
2410                 case SCNCLR: 
2411                     clearsw = 0;
2412                     continue;
2413                 case SCHEAD: 
2414                     headersw++;
2415                     continue;
2416                 case SCNHEAD: 
2417                     headersw = 0;
2418                     continue;
2419                 case SCFORM: 
2420                     if (!(form = *args++) || *form == '-') {
2421                         advise (NULLCP, "missing argument to %s", args[-2]);
2422                         return;
2423                     }
2424                     format = NULL;
2425                     continue;
2426                 case SCFMT: 
2427                     if (!(format = *args++) || *format == '-') {
2428                         advise (NULLCP, "missing argument to %s", args[-2]);
2429                         return;
2430                     }
2431                     form = NULL;
2432                     continue;
2433                 case SCWID: 
2434                     if (!(cp = *args++) || *cp == '-') {
2435                         advise (NULLCP, "missing argument to %s", args[-2]);
2436                         return;
2437                     }
2438                     width = atoi (cp);
2439                     continue;
2440             }
2441         if (*cp == '+' || *cp == '@') {
2442             advise (NULLCP, "sorry, no folders allowed!");
2443             return;
2444         }
2445         else
2446             msgs[msgp++] = cp;
2447     }
2448
2449     if (!msgp)
2450         msgs[msgp++] = "all";
2451     for (msgnum = 0; msgnum < msgp; msgnum++)
2452         if (!m_convert (mp, msgs[msgnum]))
2453             return;
2454     m_setseq (mp);
2455
2456     nfs = new_fs (form, format, FORMAT);
2457     if (scanl) {                /* force scansbr to (re)compile format */
2458         (void) free (scanl);
2459         scanl = NULL;
2460     }
2461
2462     if (s_optim == 0) {
2463         s_optim = optim = 1;
2464         s_form = form ? getcpy (form) : NULL;
2465         s_format = format ? getcpy (format) : NULL;
2466
2467 #ifdef  MPOP
2468 #ifdef  BPOP
2469         if (pmsh) {
2470             int     i;
2471             char   *dp,
2472                    *ep,
2473                    *fp;
2474
2475             if (width == 0)
2476                 width = sc_width ();
2477
2478             for (dp = nfs, i = 0; *dp; dp++, i++)
2479                 if (*dp == '\\' || *dp == '"' || *dp == '\n')
2480                     i++;
2481             i++;
2482             if ((ep = malloc ((unsigned) i)) == NULL)
2483                 adios (NULLCP, "out of memory");
2484             for (dp = nfs, fp = ep; *dp; dp++) {
2485                 if (*dp == '\n') {
2486                     *fp++ = '\\', *fp++ = 'n';
2487                     continue;
2488                 }
2489                 if (*dp == '"' || *dp == '\\')
2490                     *fp++ = '\\';
2491                 *fp++ = *dp;
2492             }
2493             *fp = NULL;
2494
2495             if (pop_command ("XTND SCAN %d \"%s\"", width, ep) == OK)
2496                 p_optim = 1;
2497
2498             free (ep);
2499         }
2500 #endif
2501 #endif  /* MPOP */
2502     }
2503     else
2504         optim = equiv (s_form, form) && equiv (s_format, format);
2505
2506 #ifdef  MPOP
2507 #ifdef  BPOP
2508     if (p_optim && optim) {
2509         for (msgnum = mp -> lowmsg; msgnum <= mp -> hghmsg; msgnum++)
2510             if (!(mp -> msgstats[msgnum] & SELECTED) || Msgs[msgnum].m_scanl)
2511                 break;
2512         if (msgnum > mp -> hghmsg && pop_command ("LIST") == OK) {
2513             fprintf (stderr, "Stand-by...");
2514             fflush (stderr);
2515
2516             for (;;) {
2517                 int     size;
2518
2519                 switch (pop_multiline ()) {
2520                     case NOTOK:
2521                         fprintf (stderr, "%s", response);
2522                         /* and fall... */
2523                     case DONE:
2524                         fprintf (stderr,"\n");
2525                         break;
2526
2527                     case OK:
2528                         if (sscanf (response, "%d %d", &msgnum, &size) == 2
2529                                 && mp -> lowmsg <= msgnum
2530                                 && msgnum <= mp -> hghmsg
2531                                 && (cp = index (response, '#'))
2532                                 && *++cp)
2533                             Msgs[msgnum].m_scanl = concat (cp, "\n", NULLCP);
2534                         continue;
2535                 }
2536                 break;
2537             }
2538         }
2539     }
2540 #endif
2541 #endif /* MPOP */
2542
2543     interrupted = 0;
2544     for (msgnum = mp -> lowsel;
2545             msgnum <= mp -> hghsel && !interrupted;
2546             msgnum++)
2547         if (mp -> msgstats[msgnum] & SELECTED) {
2548             if (optim && Msgs[msgnum].m_scanl)
2549                 printf ("%s", Msgs[msgnum].m_scanl);
2550             else {
2551 #ifdef  MPOP
2552 #ifdef  BPOP
2553                 if (p_optim
2554                         && optim
2555                         && (mp -> msgstats[msgnum] & VIRTUAL)
2556                         && pop_command ("LIST %d", msgnum) == OK
2557                         && (cp = index (response, '#'))
2558                         && *++cp) {
2559                     Msgs[msgnum].m_scanl = concat (cp, "\n", NULLCP);
2560                     printf ("%s", Msgs[msgnum].m_scanl);                    
2561                     continue;
2562                 }
2563 #endif
2564 #endif /* MPOP */
2565
2566                 zp = msh_ready (msgnum, 0);
2567                 switch (state = scan (zp, msgnum, 0, nfs, width,
2568                         msgnum == mp -> curmsg,
2569                         mp -> msgstats[msgnum] & UNSEEN,        /* ?? */
2570                         headersw, fmsh ? fmsh : mp -> foldpath,
2571                         fmsh ? 0L : (long) (Msgs[msgnum].m_stop - Msgs[msgnum].m_start),
2572                         1)) {
2573                     case SCNMSG:
2574                     case SCNENC:
2575                     case SCNERR:
2576                         if (optim)
2577                             Msgs[msgnum].m_scanl = getcpy (scanl);
2578                         break;
2579
2580                     default:
2581                         advise (NULLCP, "scan() botch (%d)", state);
2582                         return;
2583
2584                     case SCNEOF:
2585                         printf ("%*d  empty\n", DMAXFOLDER, msgnum);
2586                         break;
2587                     }
2588             }
2589             headersw = 0;
2590         }
2591
2592     if (clearsw)
2593         clear_screen ();
2594 }
2595
2596 /* \f */
2597
2598 static struct swit showswit[] = {
2599 #define SHDRAFT 0
2600     "draft", 5,
2601 #define SHFORM  1
2602     "form formfile", 4,
2603 #define SHPROG  2
2604     "moreproc program", 4,
2605 #define SHNPROG 3
2606     "nomoreproc", 3,
2607 #define SHLEN   4
2608     "length lines", 4,
2609 #define SHWID   5
2610     "width columns", 4,
2611 #define SHSHOW  6
2612     "showproc program", 4,
2613 #define SHNSHOW 7
2614     "noshowproc", 3,
2615 #define SHHEAD  8
2616     "header", 4,
2617 #define SHNHEAD 9
2618     "noheader", 3,
2619 #define SHHELP  10
2620     "help", 4,
2621
2622     NULL, 0
2623 };
2624
2625 /* \f */
2626
2627 showcmd (args)
2628 char  **args;
2629 {
2630     int     headersw = 1,
2631             nshow = 0,
2632             msgp = 0,
2633             vecp = 1,
2634             mhl = 0,
2635             seen = 0,
2636             mode = 0,
2637             i,
2638             msgnum;
2639     char   *cp,
2640            *proc = showproc,
2641             buf[BUFSIZ],
2642            *msgs[MAXARGS],
2643            *vec[MAXARGS];
2644
2645     if (uleq (cmd_name, "next"))
2646         mode = 1;
2647     else
2648         if (uleq (cmd_name, "prev"))
2649             mode = -1;
2650     while (cp = *args++) {
2651         if (*cp == '-')
2652             switch (i = smatch (++cp, showswit)) {
2653                 case AMBIGSW: 
2654                     ambigsw (cp, showswit);
2655                     return;
2656                 case UNKWNSW: 
2657                 case SHNPROG:
2658                     vec[vecp++] = --cp;
2659                     continue;
2660                 case SHHELP: 
2661                     (void) sprintf (buf,
2662                             "%s %s[switches] [switches for showproc]",
2663                             cmd_name, mode ? NULL : "[msgs] ");
2664                     help (buf, showswit);
2665                     return;
2666
2667                 case SHFORM: 
2668                 case SHPROG:
2669                 case SHLEN:
2670                 case SHWID:
2671                     vec[vecp++] = --cp;
2672                     if (!(cp = *args++) || *cp == '-') {
2673                         advise (NULLCP, "missing argument to %s", args[-2]);
2674                         return;
2675                     }
2676                     vec[vecp++] = cp;
2677                     continue;
2678                 case SHHEAD: 
2679                     headersw++;
2680                     continue;
2681                 case SHNHEAD: 
2682                     headersw = 0;
2683                     continue;
2684                 case SHSHOW: 
2685                     if (!(proc = *args++) || *proc == '-') {
2686                         advise (NULLCP, "missing argument to %s", args[-2]);
2687                         return;
2688                     }
2689                     nshow = 0;
2690                     continue;
2691                 case SHNSHOW: 
2692                     nshow++;
2693                     continue;
2694
2695                 case SHDRAFT: 
2696                     advise (NULLCP, "sorry, -%s not allowed!", showswit[i].sw);
2697                     return;
2698             }
2699         if (*cp == '+' || *cp == '@') {
2700             advise (NULLCP, "sorry, no folders allowed!");
2701             return;
2702         }
2703         else
2704             if (mode) {
2705                 fprintf (stderr,
2706                         "usage: %s [switches] [switches for showproc]\n",
2707                         cmd_name);
2708                 return;
2709             }
2710             else
2711                 msgs[msgp++] = cp;
2712     }
2713     vec[vecp] = NULL;
2714
2715     if (!msgp)
2716         msgs[msgp++] = mode > 0 ? "next" : mode < 0 ? "prev" : "cur";
2717     for (msgnum = 0; msgnum < msgp; msgnum++)
2718         if (!m_convert (mp, msgs[msgnum]))
2719             return;
2720     m_setseq (mp);
2721
2722 #ifdef  MIME
2723     if (!nshow && !getenv ("NOMHNPROC"))
2724         for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
2725             if ((mp -> msgstats[msgnum] & SELECTED) && nontext (msgnum)) {
2726                 proc = (cp = m_find ("mhnproc")) ? cp : "mhn";
2727                 vec[vecp++] = "-show";
2728                 vec[vecp++] = "-file";
2729                 vec[vecp] = NULL;
2730                 goto finish;
2731             }
2732 #endif  /* MIME */
2733
2734     if (nshow)
2735         proc = "cat";
2736     else
2737         if (strcmp (showproc, "mhl") == 0) {
2738             proc = mhlproc;
2739             mhl++;
2740         }
2741
2742 finish: ;
2743     seen = m_seqflag (mp, "unseen");
2744     vec[0] = r1bindex (proc, '/');
2745     if (mhl) {
2746         msgp = vecp;
2747         for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++)
2748             if (mp -> msgstats[msgnum] & SELECTED) {
2749                 vec[vecp++] = getcpy (m_name (msgnum));
2750                 if (seen)
2751                     (void) m_seqdel (mp, "unseen", msgnum);
2752             }
2753         vec[vecp] = NULL;
2754         if (mp -> numsel == 1 && headersw)
2755             show (mp -> lowsel);
2756         (void) mhlsbr (vecp, vec, mhl_action);
2757         m_eomsbr ((int (*)()) 0);
2758         while (msgp < vecp)
2759             free (vec[msgp++]);
2760     }
2761     else {
2762         interrupted = 0;
2763         for (msgnum = mp -> lowsel;
2764                 msgnum <= mp -> hghsel && !interrupted;
2765                 msgnum++)
2766             if (mp -> msgstats[msgnum] & SELECTED) {
2767                 switch (ask (msgnum)) {
2768                     case NOTOK: /* QUIT */
2769                         break;
2770
2771                     case OK:    /* INTR */
2772                         continue;
2773
2774                     default:
2775                         if (mp -> numsel == 1 && headersw)
2776                             show (msgnum);
2777                         if (nshow)
2778                             copy_message (msgnum, stdout);
2779                         else
2780                             (void) process (msgnum, proc, vecp, vec);
2781
2782                         if (seen)
2783                             (void) m_seqdel (mp, "unseen", msgnum);
2784                         continue;
2785                 }
2786                 break;
2787             }
2788     }
2789
2790     m_setcur (mp, mp -> hghsel);
2791 }
2792
2793 /* \f */
2794
2795 static  show (msgnum)
2796 int     msgnum;
2797 {
2798     if (Msgs[msgnum].m_bboard_id == 0)
2799         (void) readid (msgnum);
2800
2801     printf ("(Message %d", msgnum);
2802     if (Msgs[msgnum].m_bboard_id > 0)
2803         printf (", %s: %d", BBoard_ID, Msgs[msgnum].m_bboard_id);
2804     printf (")\n");
2805 }
2806
2807
2808 /* ARGSUSED */
2809
2810 static  int eom_action (c)
2811 int     c;
2812 {
2813     return (ftell (mhlfp) >= Msgs[mhlnum].m_stop);
2814 }
2815
2816
2817 static  FP mhl_action (name)
2818 char   *name;
2819 {
2820     int     msgnum;
2821
2822     if ((msgnum = m_atoi (name)) < mp -> lowmsg
2823             || msgnum > mp -> hghmsg
2824             || !(mp -> msgstats[msgnum] & EXISTS))
2825         return NULL;
2826     mhlnum = msgnum;
2827
2828     mhlfp = msh_ready (msgnum, 1);
2829     if (!fmsh)
2830         m_eomsbr (eom_action);
2831
2832     return mhlfp;
2833 }
2834
2835
2836 /* \f */
2837
2838 static  ask (msgnum)
2839 int     msgnum;
2840 {
2841     char    buf[BUFSIZ];
2842
2843     if (mp -> numsel == 1 || !interactive || redirected)
2844         return DONE;
2845
2846     if (SOprintf ("Press <return> to list \"%d\"...", msgnum)) {
2847         if (mp -> lowsel != msgnum)
2848             printf ("\n\n\n");
2849         printf ("Press <return> to list \"%d\"...", msgnum);
2850     }
2851     (void) fflush (stdout);
2852     buf[0] = 0;
2853 #ifndef BSD42
2854     (void) read (fileno (stdout), buf, sizeof buf);
2855 #else   /* BSD42 */
2856     switch (setjmp (sigenv)) {
2857         case OK: 
2858             should_intr = 1;
2859             (void) read (fileno (stdout), buf, sizeof buf);/* fall... */
2860
2861         default: 
2862             should_intr = 0;
2863             break;
2864     }
2865 #endif  /* BSD42 */
2866     if (index (buf, '\n') == NULL)
2867         (void) putchar ('\n');
2868
2869     if (told_to_quit) {
2870         told_to_quit = interrupted = 0;
2871         return NOTOK;
2872     }
2873     if (interrupted) {
2874         interrupted = 0;
2875         return OK;
2876     }
2877
2878     return DONE;
2879 }
2880
2881 /* \f */
2882
2883 #ifdef  MIME
2884 #include "../h/mhn.h"
2885
2886
2887 static int  nontext (msgnum)
2888 int     msgnum;
2889 {
2890     int     result,
2891             state;
2892     register char   *bp,
2893                     *dp;
2894     char   *chset,
2895            *cp,
2896             buf[BUFSIZ],
2897             name[NAMESZ];
2898     FILE   *fp;
2899
2900     if (Msgs[msgnum].m_flags & MHNCHK)
2901         return (Msgs[msgnum].m_flags & MHNYES);
2902     Msgs[msgnum].m_flags |= MHNCHK;
2903
2904     fp = msh_ready (msgnum, 1);
2905
2906     if (!(chset = getenv ("MM_CHARSET")))
2907         chset = "us-ascii";
2908
2909     for (state = FLD;;)
2910         switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
2911             case FLD:
2912             case FLDPLUS:
2913             case FLDEOF:
2914                 if (uleq (name, TYPE_FIELD)) {
2915                     int     passno;
2916                     char    c;
2917
2918                     cp = add (buf, NULLCP);
2919                     while (state == FLDPLUS) {
2920                         state = m_getfld (state, name, buf, sizeof buf, fp);
2921                         cp = add (buf, cp);
2922                     }
2923                     bp = cp;
2924                     passno = 1;
2925
2926 again: ;
2927                     for (; isspace (*bp); bp++)
2928                         continue;
2929                     if (*bp == '(') {
2930                         int     i;
2931
2932                         for (bp++, i = 0;;) {
2933                             switch (*bp++) {
2934                                 case '\0':
2935 invalid: ;
2936                                     result = 0;
2937                                     goto out;
2938                                 case '\\':
2939                                     if (*bp++ == '\0')
2940                                         goto invalid;
2941                                     continue;
2942                                 case '(':
2943                                     i++;
2944                                     /* and fall... */
2945                                 default:
2946                                     continue;
2947                                 case ')':
2948                                     if (--i < 0)
2949                                         break;
2950                                 continue;
2951                             }
2952                             break;
2953                         }
2954                     }
2955                     if (passno == 2) {
2956                         if (*bp != '/')
2957                             goto invalid;
2958                         bp++;
2959                         passno = 3;
2960                         goto again;
2961                     }
2962                     for (dp = bp; istoken (*dp); dp++)
2963                         continue;
2964                     c = *dp, *dp = NULL;
2965                     if (*bp == NULL)
2966                         goto invalid;
2967                     if (passno > 1) {
2968                         if (result = !uleq (bp, "plain"))
2969                             goto out;
2970                         *dp = c;
2971                         for (dp++; isspace (*dp); dp++)
2972                             continue;
2973                         if (result = !uprf (dp, "charset"))
2974                             goto invalid;
2975                         dp += sizeof "charset" - 1;
2976                         while (isspace (*dp))
2977                             dp++;
2978                         if (*dp++ != '=')
2979                             goto invalid;
2980                         while (isspace (*dp))
2981                             dp++;
2982                         if (*dp == '"') {
2983                             if (bp = index (++dp, '"'))
2984                                 *bp = NULL;
2985                         }
2986                         else
2987                             for (bp = dp; *bp; bp++)
2988                                 if (isspace (*bp)) {
2989                                     *bp = NULL;
2990                                     break;
2991                                 }
2992                         if ((result = !uleq (dp, chset))
2993                                 && uleq (dp, "us-ascii")
2994                                 && uleq (chset, "iso-8859-1"))
2995                             result = 0;
2996                     }
2997                     else
2998                         if (!(result = !uleq (bp, "text"))) {
2999                             *dp = c;
3000                             bp = dp;
3001                             passno = 2;
3002                             goto again;
3003                         }
3004
3005 out: ;
3006                     free (cp);
3007
3008                     if (result) {
3009                         Msgs[msgnum].m_flags |= MHNYES;
3010                         return result;
3011                     }
3012                     break;
3013                 }
3014                 if (uleq (name, ENCODING_FIELD)) {
3015                     cp = add (buf, NULLCP);
3016                     while (state == FLDPLUS) {
3017                         state = m_getfld (state, name, buf, sizeof buf, fp);
3018                         cp = add (buf, cp);
3019                     }
3020                     for (bp = cp; isspace (*bp); bp++)
3021                         continue;
3022                     for (dp = bp; istoken (*dp); dp++)
3023                         continue;
3024                     *dp = NULL;
3025                     result = !uleq (bp, "7bit")
3026                                 && !uleq (bp, "8bit")
3027                                 && !uleq (bp, "binary");
3028
3029                     free (cp);
3030                     if (result) {
3031                         Msgs[msgnum].m_flags |= MHNYES;
3032                         return result;
3033                     }
3034                     break;
3035                 }
3036                 while (state == FLDPLUS)
3037                     state = m_getfld (state, name, buf, sizeof buf, fp);
3038                 break;
3039
3040             default:
3041                 return 0;
3042         }
3043 }
3044 #endif  /* MIME */
3045
3046 /* \f */
3047
3048 static struct swit sortswit[] = {
3049 #define SODATE  0
3050     "datefield field", 0,
3051 #define SOSUBJ  1
3052     "textfield field", 0,
3053 #define SONSUBJ 2
3054     "notextfield", 0,
3055 #define SOLIMT  3
3056     "limit days", 0,
3057 #define SONLIMT 4
3058     "nolimit", 0,
3059 #define SOVERB  5
3060     "verbose", 0,
3061 #define SONVERB 6
3062     "noverbose", 0,
3063 #define SOHELP  7
3064     "help", 4,
3065
3066     NULL, 0
3067 };
3068
3069 /* \f */
3070
3071 sortcmd (args)
3072 char  **args;
3073 {
3074     int     msgp = 0,
3075             msgnum;
3076     char   *cp,
3077            *datesw = NULL,
3078            *subjsw = NULL,
3079             buf[BUFSIZ],
3080            *msgs[MAXARGS];
3081     struct tws  tb,
3082                *tw;
3083
3084     if (fmsh) {
3085         forkcmd (args, cmd_name);
3086         return;
3087     }
3088
3089     while (cp = *args++) {
3090         if (*cp == '-')
3091             switch (smatch (++cp, sortswit)) {
3092                 case AMBIGSW: 
3093                     ambigsw (cp, sortswit);
3094                     return;
3095                 case UNKWNSW: 
3096                     fprintf (stderr, "-%s unknown\n", cp);
3097                     return;
3098                 case SOHELP: 
3099                     (void) sprintf (buf, "%s [msgs] [switches]", cmd_name);
3100                     help (buf, sortswit);
3101                     return;
3102
3103                 case SODATE: 
3104                     if (datesw) {
3105                         advise (NULLCP, "only one date field at a time!");
3106                         return;
3107                     }
3108                     if (!(datesw = *args++) || *datesw == '-') {
3109                         advise (NULLCP, "missing argument to %s", args[-2]);
3110                         return;
3111                     }
3112                     continue;
3113
3114                 case SOSUBJ:
3115                     if (subjsw) {
3116                         advise (NULLCP, "only one text field at a time!");
3117                         return;
3118                     }
3119                     if (!(subjsw = *args++) || *subjsw == '-') {
3120                         advise (NULLCP, "missing argument to %s", args[-2]);
3121                         return;
3122                     }
3123                     continue;
3124                 case SONSUBJ:
3125                     subjsw = (char *)0;
3126                     continue;
3127
3128                 case SOLIMT:            /* too hard */
3129                     if (!(cp = *args++) || *cp == '-') {
3130                         advise (NULLCP, "missing argument to %s", args[-2]);
3131                         return;
3132                     }
3133                 case SONLIMT:
3134                 case SOVERB:            /* not implemented */
3135                 case SONVERB: 
3136                     continue;
3137             }
3138         if (*cp == '+' || *cp == '@') {
3139             advise (NULLCP, "sorry, no folders allowed!");
3140             return;
3141         }
3142         else
3143             msgs[msgp++] = cp;
3144     }
3145
3146     if (!msgp)
3147         msgs[msgp++] = "all";
3148     if (!datesw)
3149         datesw = "Date";
3150     for (msgnum = 0; msgnum < msgp; msgnum++)
3151         if (!m_convert (mp, msgs[msgnum]))
3152             return;
3153     m_setseq (mp);
3154
3155     twscopy (&tb, dtwstime ());
3156
3157     for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++) {
3158         if (Msgs[msgnum].m_scanl) {
3159             free (Msgs[msgnum].m_scanl);
3160             Msgs[msgnum].m_scanl = NULL;
3161         }
3162         if (mp -> msgstats[msgnum] & SELECTED) {
3163             if (getws (datesw, subjsw, msgnum, &Msgs[msgnum]))
3164                 twscopy (&Msgs[msgnum].m_tb,
3165                         msgnum != mp -> lowsel ? &Msgs[msgnum - 1].m_tb : &tb);
3166         }
3167         else                    /* m_scaln is already NULL */
3168             twscopy (&Msgs[msgnum].m_tb, &tb);
3169         Msgs[msgnum].m_stats = mp -> msgstats[msgnum];
3170         if (mp -> curmsg == msgnum)
3171             Msgs[msgnum].m_stats |= CUR;
3172     }
3173
3174     qsort ((char *) &Msgs[mp -> lowsel], mp -> hghsel - mp -> lowsel + 1,
3175             sizeof (struct Msg),
3176             subjsw ? subsort : msgsort);
3177
3178     for (msgnum = mp -> lowsel; msgnum <= mp -> hghsel; msgnum++) {
3179         if (subjsw && Msgs[msgnum].m_scanl) {
3180             free (Msgs[msgnum].m_scanl);        /* from subjsort */
3181             Msgs[msgnum].m_scanl = NULL;
3182         }
3183         mp -> msgstats[msgnum] = Msgs[msgnum].m_stats & ~CUR;
3184         if (Msgs[msgnum].m_stats & CUR)
3185             m_setcur (mp, msgnum);
3186     }
3187             
3188     mp -> msgflags |= MODIFIED;
3189     modified++;
3190 }
3191
3192 /* \f */
3193
3194 /* 
3195  * getws - parse message, and get date and subject if needed.  We'll use
3196  * the msgp->m_tb tws struct for the date, and overload the msgp->m_scanl
3197  * field with our subject string.
3198  */
3199 static int   getws (datesw, subjsw, msgnum, msgp)
3200 char   *datesw,
3201        *subjsw;
3202 int     msgnum;
3203 struct  Msg     *msgp;
3204 {
3205     int     state,
3206             gotdate = 0;
3207     char   *bp,
3208             buf[BUFSIZ],
3209             name[NAMESZ];
3210     struct tws *tw = (struct tws *)0;
3211     register FILE *zp;
3212
3213     zp = msh_ready (msgnum, 0);
3214     for (state = FLD;;) {
3215         switch (state = m_getfld (state, name, buf, sizeof buf, zp)) {
3216             case FLD: 
3217             case FLDEOF: 
3218             case FLDPLUS: 
3219                 if (uleq (name, datesw)) {
3220                     bp = getcpy (buf);
3221                     while (state == FLDPLUS) {
3222                         state = m_getfld (state, name, buf, sizeof buf, zp);
3223                         bp = add (buf, bp);
3224                     }
3225                     if ((tw = dparsetime (bp)) == NULL)
3226                         admonish (NULLCP,
3227                                 "unable to parse %s field in message %d",
3228                                 datesw, msgnum);
3229                     else
3230                         twscopy (&(msgp->m_tb), tw);
3231                     free (bp);
3232                     if (!subjsw)        /* not using this, or already done */
3233                         break;          /* all done! */
3234                     gotdate++;
3235                 }
3236                 else if (subjsw && uleq(name, subjsw)) {
3237                     bp = getcpy (buf);
3238                     while (state == FLDPLUS) {
3239                         state = m_getfld (state, name, buf, sizeof buf, zp);
3240                         bp = add (buf, bp);
3241                     }
3242                     msgp->m_scanl = sosmash(subjsw, bp);
3243                     if (gotdate)
3244                         break;          /* date done so we're done */
3245                     else
3246                         subjsw = (char *)0;/* subject done, need date */
3247                 } else {
3248                     while (state == FLDPLUS)    /* flush this one */
3249                         state = m_getfld (state, name, buf, sizeof buf, zp);
3250                 }
3251                 continue;
3252
3253             case BODY: 
3254             case BODYEOF: 
3255             case FILEEOF: 
3256                 break;
3257
3258             case LENERR: 
3259             case FMTERR: 
3260                 admonish (NULLCP, "format error in message %d", msgnum);
3261                 if (msgp->m_scanl) {    /* this might need free'd */
3262                     free (msgp->m_scanl); /* probably can't use subj anyway */
3263                     msgp->m_scanl = NULL;
3264                 }
3265                 return NOTOK;
3266
3267             default: 
3268                 adios (NULLCP, "internal error -- you lose");
3269         }
3270         break;
3271     }
3272     if (tw)
3273         return OK;      /* not an error if subj not found */
3274
3275     admonish (NULLCP, "no %s field in message %d", datesw, msgnum);
3276     return NOTOK;       /* NOTOK means use some other date */
3277 }
3278
3279 /* sort routines */
3280
3281 static int  msgsort (a, b)
3282 struct Msg *a,
3283            *b;
3284 {
3285     return twsort (&a -> m_tb, &b -> m_tb);
3286 }
3287
3288 static int  subsort (a, b)
3289 struct Msg *a,
3290            *b;
3291 {
3292         register int i;
3293
3294         if (a->m_scanl && b->m_scanl)
3295             if (i = strcmp (a->m_scanl, b->m_scanl))
3296                 return (i);
3297
3298         return twsort (&a -> m_tb, &b -> m_tb);
3299 }
3300
3301 /*
3302  * try to make the subject "canonical": delete leading "re:", everything
3303  * but letters & smash letters to lower case. 
3304  */
3305 static char *
3306 sosmash (subj, s)
3307 char *subj;
3308 register char *s;
3309 {
3310     register char  *cp,
3311                    *dp,
3312                     c;
3313     if (s) {
3314         cp = s;
3315         dp = s; /* dst pointer */
3316         if (uleq (subj, "subject"))
3317             while (c = *cp) {
3318                 if (! isspace(c)) {
3319                     if(uprf(cp, "re:"))
3320                         cp += 2;
3321                     else {
3322                         if (isalnum(c))
3323                             *dp++ = isupper(c) ? tolower(c) : c;
3324                         break;
3325                     }
3326                 }
3327                 cp++;
3328             }
3329         while (c = *cp++) {
3330             if (isalnum(c))
3331                 *dp++ = isupper(c) ? tolower(c) : c;
3332
3333         }
3334         *dp = '\0';
3335     }
3336     return s;
3337 }
3338
3339 /* \f */
3340
3341 static int  process (msgnum, proc, vecp, vec)
3342 int     msgnum,
3343         vecp;
3344 char   *proc,
3345       **vec;
3346 {
3347     int     child_id,
3348             status;
3349     char    tmpfil[80];
3350     FILE   *out;
3351
3352     if (fmsh) {
3353         (void) strcpy (tmpfil, m_name (msgnum));
3354         (void) m_delete (pfolder);
3355         m_replace (pfolder, fmsh);
3356         m_sync (mp);
3357         m_update ();
3358         goto ready;
3359     }
3360
3361     (void) strcpy (tmpfil, m_scratch ("", invo_name));
3362     if ((out = fopen (tmpfil, "w")) == NULL) {
3363         int     olderr;
3364         extern int  errno;
3365         char    newfil[80];
3366
3367         olderr = errno;
3368         (void) strcpy (newfil, m_tmpfil (invo_name));
3369         if ((out = fopen (newfil, "w")) == NULL) {
3370             errno = olderr;
3371             advise (tmpfil, "unable to create temporary file");
3372             return NOTOK;
3373         }
3374         else
3375             (void) strcpy (tmpfil, newfil);
3376     }
3377     copy_message (msgnum, out);
3378     (void) fclose (out);
3379
3380 ready: ;
3381     (void) fflush (stdout);
3382     switch (child_id = fork ()) {
3383         case NOTOK: 
3384             advise ("fork", "unable to");
3385             status = NOTOK;
3386             break;
3387             
3388         case OK: 
3389             closefds (3);
3390             (void) signal (SIGINT, istat);
3391             (void) signal (SIGQUIT, qstat);
3392
3393             vec[vecp++] = tmpfil;
3394             vec[vecp] = NULL;
3395
3396             execvp (proc, vec);
3397             fprintf (stderr, "unable to exec ");
3398             perror (proc);
3399             _exit (1);
3400
3401         default: 
3402             status = pidXwait (child_id, NULLCP);
3403             break;
3404     }
3405
3406     if (!fmsh)
3407         (void) unlink (tmpfil);
3408     return status;
3409 }
3410
3411 /* \f */
3412
3413 static  copy_message (msgnum, out)
3414 int     msgnum;
3415 FILE * out;
3416 {
3417     long    pos;
3418     static char buffer[BUFSIZ];
3419     register    FILE * zp;
3420
3421     zp = msh_ready (msgnum, 1);
3422     if (fmsh) {
3423         while (fgets (buffer, sizeof buffer, zp) != NULL) {
3424             fputs (buffer, out);
3425             if (interrupted && out == stdout)
3426                 break;
3427         }
3428     }
3429     else {
3430         pos = ftell (zp);
3431         while (fgets (buffer, sizeof buffer, zp) != NULL
3432                 && pos < Msgs[msgnum].m_stop) {
3433             fputs (buffer, out);
3434             pos += (long) strlen (buffer);
3435             if (interrupted && out == stdout)
3436                 break;
3437         }
3438     }
3439 }
3440
3441
3442 static  copy_digest (msgnum, out)
3443 int     msgnum;
3444 FILE * out;
3445 {
3446     char    c;
3447     long    pos;
3448     static char buffer[BUFSIZ];
3449     register FILE *zp;
3450
3451     c = '\n';
3452     zp = msh_ready (msgnum, 1);
3453     if (!fmsh)
3454         pos = ftell (zp);
3455     while (fgets (buffer, sizeof buffer, zp) != NULL
3456             && !fmsh && pos < Msgs[msgnum].m_stop) {
3457         if (c == '\n' && *buffer == '-')
3458             (void) fputc (' ', out);
3459         fputs (buffer, out);
3460         c = buffer[strlen (buffer) - 1];
3461         if (!fmsh)
3462             pos += (long) strlen (buffer);
3463         if (interrupted && out == stdout)
3464             break;
3465     }
3466 }