]>
diplodocus.org Git - nmh/blob - uip/mshcmds.c
3 * mshcmds.c -- command handlers in msh
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
11 #include <h/signals.h>
12 #include <h/dropsbr.h>
13 #include <h/fmt_scan.h>
14 #include <h/scansbr.h>
20 #include <h/picksbr.h>
24 static char delim3
[] = "-------"; /* from burst.c */
30 * Type for a compare function for qsort. This keeps
33 typedef int (*qsort_comp
) (const void *, const void *);
38 static int burst (struct Msg
*, int, int, int, int);
39 static void forw (char *, char *, int, char **);
40 static void rmm (void);
41 static void show (int);
42 static int eom_action (int);
43 static FILE *mhl_action (char *);
45 static int is_nontext (int);
46 static int get_fields (char *, char *, int, struct Msg
*);
47 static int msgsort (struct Msg
*, struct Msg
*);
48 static int subsort (struct Msg
*, struct Msg
*);
49 static char *sosmash (char *, char *);
50 static int process (int, char *, int, char **);
51 static void copy_message (int, FILE *);
52 static void copy_digest (int, FILE *);
55 forkcmd (char **args
, char *pgm
)
60 vec
[0] = r1bindex (pgm
, '/');
61 copyip (args
, vec
+ 1, MAXARGS
- 1);
64 context_del (pfolder
);
65 context_replace (pfolder
, fmsh
);/* update current folder */
67 context_save (); /* save the context file */
70 switch (child_id
= fork ()) {
72 advise ("fork", "unable to");
77 SIGNAL (SIGINT
, istat
);
78 SIGNAL (SIGQUIT
, qstat
);
81 fprintf (stderr
, "unable to exec ");
86 pidXwait (child_id
, NULL
);
89 if (fmsh
) { /* assume the worst case */
90 mp
->msgflags
|= MODIFIED
;
96 #define DIST_SWITCHES \
97 X("annotate", 0, DIANSW) \
98 X("noannotate", 0, DINANSW) \
99 X("draftfolder +folder", 0, DIDFSW) \
100 X("draftmessage msg", 0, DIDMSW) \
101 X("nodraftfolder", 0, DINDFSW) \
102 X("editor editor", 0, DIEDTSW) \
103 X("noedit", 0, DINEDSW) \
104 X("form formfile", 0, DIFRMSW) \
105 X("inplace", 0, DIINSW) \
106 X("noinplace", 0, DININSW) \
107 X("whatnowproc program", 0, DIWHTSW) \
108 X("nowhatnowproc", 0, DINWTSW) \
109 X("help", 0, DIHELP) \
111 #define X(sw, minchars, id) id,
112 DEFINE_SWITCH_ENUM(DIST
);
115 #define X(sw, minchars, id) { sw, minchars, id },
116 DEFINE_SWITCH_ARRAY(DIST
, distswit
);
121 distcmd (char **args
)
124 char *cp
, *msg
= NULL
;
125 char buf
[BUFSIZ
], *vec
[MAXARGS
];
128 forkcmd (args
, cmd_name
);
132 while ((cp
= *args
++)) {
134 switch (smatch (++cp
, distswit
)) {
136 ambigsw (cp
, distswit
);
139 fprintf (stderr
, "-%s unknown\n", cp
);
142 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
143 print_help (buf
, distswit
, 1);
146 case DIANSW
: /* not implemented */
164 if (!(cp
= *args
++) || *cp
== '-') {
165 advise (NULL
, "missing argument to %s", args
[-2]);
171 if (*cp
== '+' || *cp
== '@') {
172 advise (NULL
, "sorry, no folders allowed!");
177 advise (NULL
, "only one message at a time!");
185 vec
[vecp
++] = "-file";
189 if (!m_convert (mp
, msg
))
193 if (mp
->numsel
> 1) {
194 advise (NULL
, "only one message at a time!");
197 process (mp
->hghsel
, cmd_name
, vecp
, vec
);
198 seq_setcur (mp
, mp
->hghsel
);
202 #define EXPLODE_SWITCHES \
203 X("inplace", 0, EXINSW) \
204 X("noinplace", 0, EXNINSW) \
205 X("quiet", 0, EXQISW) \
206 X("noquiet", 0, EXNQISW) \
207 X("verbose", 0, EXVBSW) \
208 X("noverbose", 0, EXNVBSW) \
209 X("help", 0, EXHELP) \
211 #define X(sw, minchars, id) id,
212 DEFINE_SWITCH_ENUM(EXPLODE
);
215 #define X(sw, minchars, id) { sw, minchars, id },
216 DEFINE_SWITCH_ARRAY(EXPLODE
, explswit
);
221 explcmd (char **args
)
223 int inplace
= 0, quietsw
= 0, verbosw
= 0;
224 int msgp
= 0, hi
, msgnum
;
225 char *cp
, buf
[BUFSIZ
], *msgs
[MAXARGS
];
229 forkcmd (args
, cmd_name
);
233 while ((cp
= *args
++)) {
235 switch (smatch (++cp
, explswit
)) {
237 ambigsw (cp
, explswit
);
240 fprintf (stderr
, "-%s unknown\n", cp
);
243 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
244 print_help (buf
, explswit
, 1);
266 if (*cp
== '+' || *cp
== '@') {
267 advise (NULL
, "sorry, no folders allowed!");
275 msgs
[msgp
++] = "cur";
276 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
277 if (!m_convert (mp
, msgs
[msgnum
]))
281 smsgs
= (struct Msg
*)
282 calloc ((size_t) (MAXFOLDER
+ 2), sizeof *smsgs
);
284 adios (NULL
, "unable to allocate folder storage");
288 for (msgnum
= mp
->lowsel
;
289 msgnum
<= mp
->hghsel
&& !interrupted
;
291 if (is_selected (mp
, msgnum
))
292 if (burst (smsgs
, msgnum
, inplace
, quietsw
, verbosw
) != OK
)
295 free ((char *) smsgs
);
298 seq_setcur (mp
, mp
->lowsel
);
300 if (hi
<= mp
->hghmsg
)
303 mp
->msgflags
|= MODIFIED
;
309 burst (struct Msg
*smsgs
, int msgnum
, int inplace
, int quietsw
, int verbosw
)
311 int i
, j
, ld3
, wasdlm
, msgp
;
313 char c
, buffer
[BUFSIZ
];
316 ld3
= strlen (delim3
);
318 if (Msgs
[msgnum
].m_scanl
) {
319 free (Msgs
[msgnum
].m_scanl
);
320 Msgs
[msgnum
].m_scanl
= NULL
;
323 pos
= ftell (zp
= msh_ready (msgnum
, 1));
324 for (msgp
= 0; msgp
<= MAXFOLDER
;) {
325 while (fgets (buffer
, sizeof buffer
, zp
) != NULL
327 && pos
< Msgs
[msgnum
].m_stop
)
328 pos
+= (long) strlen (buffer
);
329 if (feof (zp
) || pos
>= Msgs
[msgnum
].m_stop
)
331 fseek (zp
, pos
, SEEK_SET
);
332 smsgs
[msgp
].m_start
= pos
;
335 pos
< Msgs
[msgnum
].m_stop
336 && fgets (buffer
, sizeof buffer
, zp
) != NULL
;
338 if (strncmp (buffer
, delim3
, ld3
) == 0
339 && (msgp
== 1 || c
== '\n')
340 && peekc (zp
) == '\n')
343 pos
+= (long) strlen (buffer
);
345 wasdlm
= strncmp (buffer
, delim3
, ld3
) == 0;
346 if (smsgs
[msgp
].m_start
!= pos
)
347 smsgs
[msgp
++].m_stop
= (c
== '\n' && wasdlm
) ? pos
- 1 : pos
;
348 if (feof (zp
) || pos
>= Msgs
[msgnum
].m_stop
) {
350 smsgs
[msgp
- 1].m_stop
-= ((long) strlen (buffer
) + 1);
353 pos
+= (long) strlen (buffer
);
356 switch (msgp
--) { /* toss "End of XXX Digest" */
358 adios (NULL
, "burst() botch -- you lose big");
362 printf ("message %d not in digest format\n", msgnum
);
367 printf ("%d message%s exploded from digest %d\n",
368 msgp
, msgp
!= 1 ? "s" : "", msgnum
);
372 if ((i
= msgp
+ mp
->hghmsg
) > MAXFOLDER
) {
373 advise (NULL
, "more than %d messages", MAXFOLDER
);
376 if (!(mp
= folder_realloc (mp
, mp
->lowoff
, i
)))
377 adios (NULL
, "unable to allocate folder storage");
382 if (mp
->hghsel
> msgnum
)
386 for (i
= mp
->hghmsg
; j
> msgnum
; i
--, j
--) {
388 printf ("message %d becomes message %d\n", j
, i
);
390 Msgs
[i
].m_bboard_id
= Msgs
[j
].m_bboard_id
;
391 Msgs
[i
].m_top
= Msgs
[j
].m_top
;
392 Msgs
[i
].m_start
= Msgs
[j
].m_start
;
393 Msgs
[i
].m_stop
= Msgs
[j
].m_stop
;
394 Msgs
[i
].m_scanl
= NULL
;
395 if (Msgs
[j
].m_scanl
) {
396 free (Msgs
[j
].m_scanl
);
397 Msgs
[j
].m_scanl
= NULL
;
399 copy_msg_flags (mp
, i
, j
);
402 if (Msgs
[msgnum
].m_bboard_id
== 0)
405 unset_selected (mp
, msgnum
);
406 i
= inplace
? msgnum
+ msgp
: mp
->hghmsg
;
407 for (j
= msgp
; j
>= (inplace
? 0 : 1); i
--, j
--) {
408 if (verbosw
&& i
!= msgnum
)
409 printf ("message %d of digest %d becomes message %d\n",
412 Msgs
[i
].m_bboard_id
= Msgs
[msgnum
].m_bboard_id
;
413 Msgs
[i
].m_top
= Msgs
[j
].m_top
;
414 Msgs
[i
].m_start
= smsgs
[j
].m_start
;
415 Msgs
[i
].m_stop
= smsgs
[j
].m_stop
;
416 Msgs
[i
].m_scanl
= NULL
;
417 copy_msg_flags (mp
, i
, msgnum
);
424 #define FILE_SWITCHES \
425 X("draft", 0, FIDRFT) \
426 X("link", 0, FILINK) \
427 X("nolink", 0, FINLINK) \
428 X("preserve", 0, FIPRES) \
429 X("nopreserve", 0, FINPRES) \
430 X("src +folder", 0, FISRC) \
431 X("file file", 0, FIFILE) \
432 X("rmmproc program", 0, FIPROC) \
433 X("normmproc", 0, FINPRC) \
434 X("help", 0, FIHELP) \
436 #define X(sw, minchars, id) id,
437 DEFINE_SWITCH_ENUM(FILE);
440 #define X(sw, minchars, id) { sw, minchars, id },
441 DEFINE_SWITCH_ARRAY(FILE, fileswit
);
446 filecmd (char **args
)
448 int linksw
= 0, msgp
= 0;
449 int vecp
= 1, i
, msgnum
;
450 char *cp
, buf
[BUFSIZ
];
451 char *msgs
[MAXARGS
], *vec
[MAXARGS
];
454 forkcmd (args
, cmd_name
);
458 while ((cp
= *args
++)) {
460 switch (i
= smatch (++cp
, fileswit
)) {
462 ambigsw (cp
, fileswit
);
465 fprintf (stderr
, "-%s unknown\n", cp
);
468 snprintf (buf
, sizeof(buf
), "%s +folder... [msgs] [switches]", cmd_name
);
469 print_help (buf
, fileswit
, 1);
488 advise (NULL
, "sorry, -%s not allowed!", fileswit
[i
].sw
);
491 if (*cp
== '+' || *cp
== '@')
498 vec
[vecp
++] = "-file";
501 msgs
[msgp
++] = "cur";
502 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
503 if (!m_convert (mp
, msgs
[msgnum
]))
508 for (msgnum
= mp
->lowsel
;
509 msgnum
<= mp
->hghsel
&& !interrupted
;
511 if (is_selected (mp
, msgnum
))
512 if (process (msgnum
, fileproc
, vecp
, vec
)) {
513 unset_selected (mp
, msgnum
);
517 if (mp
->numsel
!= mp
->nummsg
|| linksw
)
518 seq_setcur (mp
, mp
->hghsel
);
525 filehak (char **args
)
527 int result
, vecp
= 0;
528 char *cp
, *cwd
, *vec
[MAXARGS
];
530 while ((cp
= *args
++)) {
532 switch (smatch (++cp
, fileswit
)) {
549 if (*cp
== '+' || *cp
== '@')
556 for (vecp
= 0; (cp
= vec
[vecp
]) && result
== NOTOK
; vecp
++) {
558 cwd
= getcpy (pwd ());
559 chdir (m_maildir (""));
561 if (access (m_maildir (cp
), F_OK
) == NOTOK
)
572 #define FOLDER_SWITCHES \
573 X("all", 0, FLALSW) \
574 X("fast", 0, FLFASW) \
575 X("nofast", 0, FLNFASW) \
576 X("header", 0, FLHDSW) \
577 X("noheader", 0, FLNHDSW) \
578 X("pack", 0, FLPKSW) \
579 X("nopack", 0, FLNPKSW) \
580 X("recurse", 0, FLRCSW) \
581 X("norecurse", 0, FLNRCSW) \
582 X("total", 0, FLTLSW) \
583 X("nototal", 0, FLNTLSW) \
584 X("print", 0, FLPRSW) \
585 X("push", 0, FLPUSW) \
586 X("pop", 0, FLPOSW) \
587 X("list", 0, FLLISW) \
588 X("help", 0, FLHELP) \
590 #define X(sw, minchars, id) id,
591 DEFINE_SWITCH_ENUM(FOLDER
);
594 #define X(sw, minchars, id) { sw, minchars, id },
595 DEFINE_SWITCH_ARRAY(FOLDER
, foldswit
);
600 foldcmd (char **args
)
602 int fastsw
= 0, headersw
= 0, packsw
= 0;
604 char *cp
, *folder
= NULL
, *msg
= NULL
;
605 char buf
[BUFSIZ
], **vec
= args
;
610 while ((cp
= *args
++)) {
612 switch (smatch (++cp
, foldswit
)) {
614 ambigsw (cp
, foldswit
);
617 fprintf (stderr
, "-%s unknown\n", cp
);
620 snprintf (buf
, sizeof(buf
), "%s [+folder] [msg] [switches]", cmd_name
);
621 print_help (buf
, foldswit
, 1);
624 case FLALSW
: /* not implemented */
654 if (*cp
== '+' || *cp
== '@') {
656 advise (NULL
, "only one folder at a time!\n");
660 folder
= fmsh
? pluspath (cp
)
665 advise (NULL
, "only one message at a time!\n");
674 advise (NULL
, "null folder names are not permitted");
678 if (access (m_maildir (folder
), R_OK
) == NOTOK
) {
679 advise (folder
, "unable to read");
684 strncpy (buf
, folder
, sizeof(buf
));
685 if (expand (buf
) == NOTOK
)
688 if (access (folder
, R_OK
) == NOTOK
) {
689 advise (folder
, "unable to read");
704 if (!m_convert (mp
, msg
))
708 if (mp
->numsel
> 1) {
709 advise (NULL
, "only one message at a time!");
712 seq_setcur (mp
, mp
->hghsel
);
717 forkcmd (vec
, cmd_name
);
721 if (mp
->lowoff
> 1 && !(mp
= folder_realloc (mp
, 1, mp
->hghmsg
)))
722 adios (NULL
, "unable to allocate folder storage");
724 for (msgnum
= mp
->lowmsg
, hole
= 1; msgnum
<= mp
->hghmsg
; msgnum
++)
725 if (does_exist (mp
, msgnum
)) {
726 if (msgnum
!= hole
) {
727 Msgs
[hole
].m_bboard_id
= Msgs
[msgnum
].m_bboard_id
;
728 Msgs
[hole
].m_top
= Msgs
[msgnum
].m_top
;
729 Msgs
[hole
].m_start
= Msgs
[msgnum
].m_start
;
730 Msgs
[hole
].m_stop
= Msgs
[msgnum
].m_stop
;
731 Msgs
[hole
].m_scanl
= NULL
;
732 if (Msgs
[msgnum
].m_scanl
) {
733 free (Msgs
[msgnum
].m_scanl
);
734 Msgs
[msgnum
].m_scanl
= NULL
;
736 copy_msg_flags (mp
, hole
, msgnum
);
737 if (mp
->curmsg
== msgnum
)
738 seq_setcur (mp
, hole
);
742 if (mp
->nummsg
> 0) {
744 mp
->hghmsg
= hole
- 1;
746 mp
->msgflags
|= MODIFIED
;
752 printf ("%s\n", fmsh
? fmsh
: mp
->foldpath
);
755 printf ("\t\tFolder %*s# of messages (%*srange%*s); cur%*smsg\n",
756 DMAXFOLDER
, "", DMAXFOLDER
- 2, "", DMAXFOLDER
- 2, "",
758 printf (args
? "%22s " : "%s ", fmsh
? fmsh
: mp
->foldpath
);
760 /* check for empty folder */
761 if (mp
->nummsg
== 0) {
762 printf ("has no messages%*s",
763 mp
->msgflags
& OTHERS
? DMAXFOLDER
* 2 + 4 : 0, "");
765 printf ("has %*d message%s (%*d-%*d)",
766 DMAXFOLDER
, mp
->nummsg
, mp
->nummsg
!= 1 ? "s" : "",
767 DMAXFOLDER
, mp
->lowmsg
, DMAXFOLDER
, mp
->hghmsg
);
768 if (mp
->curmsg
>= mp
->lowmsg
769 && mp
->curmsg
<= mp
->hghmsg
)
770 printf ("; cur=%*d", DMAXFOLDER
, mp
->curmsg
);
777 #define FORW_SWITCHES \
778 X("annotate", 0, FOANSW) \
779 X("noannotate", 0, FONANSW) \
780 X("draftfolder +folder", 0, FODFSW) \
781 X("draftmessage msg", 0, FODMSW) \
782 X("nodraftfolder", 0, FONDFSW) \
783 X("editor editor", 0, FOEDTSW) \
784 X("noedit", 0, FONEDSW) \
785 X("filter filterfile", 0, FOFTRSW) \
786 X("form formfile", 0, FOFRMSW) \
787 X("format", 5, FOFTSW) \
788 X("noformat", 7, FONFTSW) \
789 X("inplace", 0, FOINSW) \
790 X("noinplace", 0, FONINSW) \
791 X("mime", 0, FOMISW) \
792 X("nomime", 0, FONMISW) \
793 X("whatnowproc program", 0, FOWHTSW) \
794 X("nowhatnow", 0, FONWTSW) \
795 X("help", 0, FOHELP) \
797 #define X(sw, minchars, id) id,
798 DEFINE_SWITCH_ENUM(FORW
);
801 #define X(sw, minchars, id) { sw, minchars, id },
802 DEFINE_SWITCH_ARRAY(FORW
, forwswit
);
807 forwcmd (char **args
)
809 int msgp
= 0, vecp
= 1, msgnum
;
810 char *cp
, *filter
= NULL
, buf
[BUFSIZ
];
811 char *msgs
[MAXARGS
], *vec
[MAXARGS
];
816 forkcmd (args
, cmd_name
);
820 while ((cp
= *args
++)) {
822 switch (smatch (++cp
, forwswit
)) {
824 ambigsw (cp
, forwswit
);
827 fprintf (stderr
, "-%s unknown\n", cp
);
830 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
831 print_help (buf
, forwswit
, 1);
834 case FOANSW
: /* not implemented */
854 if (!(cp
= *args
++) || *cp
== '-') {
855 advise (NULL
, "missing argument to %s", args
[-2]);
861 if (!(filter
= *args
++) || *filter
== '-') {
862 advise (NULL
, "missing argument to %s", args
[-2]);
867 if (access (filter
= myfilter
, R_OK
) == NOTOK
) {
868 advise (filter
, "unable to read default filter file");
876 if (*cp
== '+' || *cp
== '@') {
877 advise (NULL
, "sorry, no folders allowed!");
884 /* foil search of .mh_profile */
885 snprintf (buf
, sizeof(buf
), "%sXXXXXX", invo_name
);
887 tfile
= m_mktemp(buf
, NULL
, NULL
);
888 if (tfile
== NULL
) adios("forwcmd", "unable to create temporary file");
889 strncpy (tmpfil
, tfile
, sizeof(tmpfil
));
892 vec
[vecp
++] = "-file";
895 msgs
[msgp
++] = "cur";
896 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
897 if (!m_convert (mp
, msgs
[msgnum
]))
902 strncpy (buf
, filter
, sizeof(buf
));
903 if (expand (buf
) == NOTOK
)
905 if (access (filter
= getcpy (etcpath (buf
)), R_OK
) == NOTOK
) {
906 advise (filter
, "unable to read");
911 forw (cmd_name
, filter
, vecp
, vec
);
912 seq_setcur (mp
, mp
->hghsel
);
919 forw (char *proc
, char *filter
, int vecp
, char **vec
)
921 int i
, child_id
, msgnum
, msgcnt
;
922 char tmpfil
[BUFSIZ
], *args
[MAXARGS
];
926 tfile
= m_mktemp2(NULL
, invo_name
, NULL
, NULL
);
927 if (tfile
== NULL
) adios("forw", "unable to create temporary file");
928 strncpy (tmpfil
, tfile
, sizeof(tmpfil
));
932 switch (child_id
= fork ()) {
934 advise ("fork", "unable to");
937 case OK
: /* "trust me" */
938 if (freopen (tmpfil
, "w", stdout
) == NULL
) {
939 fprintf (stderr
, "unable to create ");
943 args
[0] = r1bindex (mhlproc
, '/');
945 args
[i
++] = "-forwall";
948 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
949 if (is_selected (mp
, msgnum
))
950 args
[i
++] = getcpy (m_name (msgnum
));
952 mhlsbr (i
, args
, mhl_action
);
953 m_eomsbr ((int (*) ()) 0);
958 if (pidXwait (child_id
, NULL
))
963 if ((out
= fopen (tmpfil
, "w")) == NULL
) {
964 advise (tmpfil
, "unable to create temporary file");
969 for (msgnum
= mp
->lowsel
;
970 msgnum
<= mp
->hghsel
&& !interrupted
;
972 if (is_selected (mp
, msgnum
)) {
973 fprintf (out
, "\n\n-------");
974 if (msgnum
== mp
->lowsel
)
975 fprintf (out
, " Forwarded Message%s",
976 mp
->numsel
> 1 ? "s" : "");
978 fprintf (out
, " Message %d", msgcnt
);
979 fprintf (out
, "\n\n");
980 copy_digest (msgnum
, out
);
984 fprintf (out
, "\n\n------- End of Forwarded Message%s\n",
985 mp
->numsel
> 1 ? "s" : "");
991 switch (child_id
= fork ()) {
993 advise ("fork", "unable to");
998 SIGNAL (SIGINT
, istat
);
999 SIGNAL (SIGQUIT
, qstat
);
1001 vec
[vecp
++] = tmpfil
;
1005 fprintf (stderr
, "unable to exec ");
1010 pidXwait (child_id
, NULL
);
1018 static char *hlpmsg
[] = {
1019 "The %s program emulates many of the commands found in the nmh",
1020 "system. Instead of operating on nmh folders, commands to %s concern",
1023 "To see the list of commands available, just type a ``?'' followed by",
1024 "the RETURN key. To find out what switches each command takes, type",
1025 "the name of the command followed by ``-help''. To leave %s, use the",
1026 "``quit'' command.",
1028 "Although a lot of nmh commands are found in %s, not all are fully",
1029 "implemented. %s will always recognize all legal switches for a",
1030 "given command though, and will let you know when you ask for an",
1031 "option that it is unable to perform.",
1033 "Running %s is fun, but using nmh from your shell is far superior.",
1034 "After you have familiarized yourself with the nmh style by using %s,",
1035 "you should try using nmh from the shell. You can still use %s for",
1036 "message files that aren't in nmh format, such as BBoard files.",
1042 helpcmd (char **args
)
1047 for (i
= 0; hlpmsg
[i
]; i
++) {
1048 printf (hlpmsg
[i
], invo_name
);
1054 #define MARK_SWITCHES \
1055 X("add", 0, MADDSW) \
1056 X("delete", 0, MDELSW) \
1057 X("list", 0, MLSTSW) \
1058 X("sequence name", 0, MSEQSW) \
1059 X("public", 0, MPUBSW) \
1060 X("nopublic", 0, MNPUBSW) \
1061 X("zero", 0, MZERSW) \
1062 X("nozero", 0, MNZERSW) \
1063 X("help", 0, MHELP) \
1064 X("debug", -5, MDBUGSW) \
1066 #define X(sw, minchars, id) id,
1067 DEFINE_SWITCH_ENUM(MARK
);
1070 #define X(sw, minchars, id) { sw, minchars, id },
1071 DEFINE_SWITCH_ARRAY(MARK
, markswit
);
1076 markcmd (char **args
)
1078 int addsw
= 0, deletesw
= 0, debugsw
= 0;
1079 int listsw
= 0, zerosw
= 0;
1081 int msgp
= 0, msgnum
;
1082 char *cp
, buf
[BUFSIZ
];
1083 char *seqs
[NUMATTRS
+ 1], *msgs
[MAXARGS
];
1085 while ((cp
= *args
++)) {
1087 switch (smatch (++cp
, markswit
)) {
1089 ambigsw (cp
, markswit
);
1092 fprintf (stderr
, "-%s unknown\n", cp
);
1095 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1096 print_help (buf
, markswit
, 1);
1101 deletesw
= listsw
= 0;
1109 addsw
= deletesw
= 0;
1113 if (!(cp
= *args
++) || *cp
== '-') {
1114 advise (NULL
, "missing argument to %s", args
[-2]);
1117 if (seqp
< NUMATTRS
)
1120 advise (NULL
, "only %d sequences allowed!", NUMATTRS
);
1125 case MPUBSW
: /* not implemented */
1141 if (*cp
== '+' || *cp
== '@') {
1142 advise (NULL
, "sorry, no folders allowed!");
1149 if (!addsw
&& !deletesw
&& !listsw
) {
1156 seqs
[seqp
++] = "unseen";
1160 msgs
[msgp
++] = "all";
1165 msgs
[msgp
++] = listsw
? "all" :"cur";
1166 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
1167 if (!m_convert (mp
, msgs
[msgnum
]))
1171 printf ("invo_name=%s mypath=%s defpath=%s\n",
1172 invo_name
, mypath
, defpath
);
1173 printf ("ctxpath=%s context flags=%s\n",
1174 ctxpath
, snprintb (buf
, sizeof(buf
), (unsigned) ctxflags
, DBITS
));
1175 printf ("foldpath=%s flags=%s\n",
1177 snprintb (buf
, sizeof(buf
), (unsigned) mp
->msgflags
, FBITS
));
1178 printf ("hghmsg=%d lowmsg=%d nummsg=%d curmsg=%d\n",
1179 mp
->hghmsg
, mp
->lowmsg
, mp
->nummsg
, mp
->curmsg
);
1180 printf ("lowsel=%d hghsel=%d numsel=%d\n",
1181 mp
->lowsel
, mp
->hghsel
, mp
->numsel
);
1182 printf ("lowoff=%d hghoff=%d\n", mp
->lowoff
, mp
->hghoff
);
1185 if (seqp
== 0 && (addsw
|| deletesw
)) {
1186 advise (NULL
, "-%s requires at least one -sequence argument",
1187 addsw
? "add" : "delete");
1193 for (seqp
= 0; seqs
[seqp
]; seqp
++)
1194 if (!seq_addsel (mp
, seqs
[seqp
], 0, zerosw
))
1199 for (seqp
= 0; seqs
[seqp
]; seqp
++)
1200 if (!seq_delsel (mp
, seqs
[seqp
], 0, zerosw
))
1204 /* Listing messages in sequences */
1207 /* list the given sequences */
1208 for (seqp
= 0; seqs
[seqp
]; seqp
++)
1209 seq_print (mp
, seqs
[seqp
]);
1211 /* else list them all */
1217 for (msgnum
= mp
->lowsel
;
1218 msgnum
<= mp
->hghsel
&& !interrupted
;
1220 if (is_selected (mp
, msgnum
)) {
1221 printf ("%*d: id=%d top=%d start=%ld stop=%ld %s\n",
1224 Msgs
[msgnum
].m_bboard_id
,
1226 (long) Msgs
[msgnum
].m_start
,
1227 (long) Msgs
[msgnum
].m_stop
,
1228 snprintb (buf
, sizeof(buf
),
1229 (unsigned) mp
->msgstats
[msgnum
- mp
->lowoff
],
1231 if (Msgs
[msgnum
].m_scanl
)
1232 printf ("%s", Msgs
[msgnum
].m_scanl
);
1238 #define MHN_SWITCHES \
1239 X("auto", 0, MHNAUTOSW) \
1240 X("noauto", 0, MHNNAUTOSW) \
1241 X("debug", -5, MHNDEBUGSW) \
1242 X("form formfile", 4, MHNFORMSW) \
1243 X("headers", 0, MHNHEADSW) \
1244 X("noheaders", 0, MHNNHEADSW) \
1245 X("list", 0, MHNLISTSW) \
1246 X("nolist", 0, MHNNLISTSW) \
1247 X("part number", 0, MHNPARTSW) \
1248 X("realsize", 0, MHNSIZESW) \
1249 X("norealsize", 0, MHNNSIZESW) \
1250 X("rfc934mode", 0, MHNRFC934SW) \
1251 X("norfc934mode", 0, MHNNRFC934SW) \
1252 X("serialonly", 0, MHNSERIALSW) \
1253 X("noserialonly", 0, MHNNSERIALSW) \
1254 X("show", 0, MHNSHOWSW) \
1255 X("noshow", 0, MHNNSHOWSW) \
1256 X("store", 0, MHNSTORESW) \
1257 X("nostore", 0, MHNNSTORESW) \
1258 X("type content", 0, MHNTYPESW) \
1259 X("verbose", 0, MHNVERBSW) \
1260 X("noverbose", 0, MHNNVERBSW) \
1261 X("help", 0, MHNHELPSW) \
1262 X("moreproc program", -4, MHNPROGSW) \
1263 X("nomoreproc", -3, MHNNPROGSW) \
1264 X("length lines", -4, MHNLENSW) \
1265 X("width columns", -4, MHNWIDSW) \
1267 #define X(sw, minchars, id) id,
1268 DEFINE_SWITCH_ENUM(MHN
);
1271 #define X(sw, minchars, id) { sw, minchars, id },
1272 DEFINE_SWITCH_ARRAY(MHN
, mhnswit
);
1277 mhncmd (char **args
)
1279 int msgp
= 0, vecp
= 1;
1281 char *cp
, buf
[BUFSIZ
];
1282 char *msgs
[MAXARGS
], *vec
[MAXARGS
];
1285 forkcmd (args
, cmd_name
);
1288 while ((cp
= *args
++)) {
1290 switch (smatch (++cp
, mhnswit
)) {
1292 ambigsw (cp
, mhnswit
);
1295 fprintf (stderr
, "-%s unknown\n", cp
);
1298 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1299 print_help (buf
, mhnswit
, 1);
1332 if (!(cp
= *args
++) || *cp
== '-') {
1333 advise (NULL
, "missing argument to %s", args
[-2]);
1340 if (*cp
== '+' || *cp
== '@') {
1341 advise (NULL
, "sorry, no folders allowed!");
1349 vec
[vecp
++] = "-file";
1352 msgs
[msgp
++] = "cur";
1353 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
1354 if (!m_convert (mp
, msgs
[msgnum
]))
1359 for (msgnum
= mp
->lowsel
;
1360 msgnum
<= mp
->hghsel
&& !interrupted
;
1362 if (is_selected (mp
, msgnum
))
1363 if (process (msgnum
, cmd_name
, vecp
, vec
)) {
1364 unset_selected (mp
, msgnum
);
1368 seq_setcur (mp
, mp
->hghsel
);
1372 #define PACK_SWITCHES \
1373 X("file name", 0, PAFISW) \
1374 X("help", 0, PAHELP) \
1376 #define X(sw, minchars, id) id,
1377 DEFINE_SWITCH_ENUM(PACK
);
1380 #define X(sw, minchars, id) { sw, minchars, id },
1381 DEFINE_SWITCH_ARRAY(PACK
, packswit
);
1384 static int mbx_style
= MMDF_FORMAT
;
1387 packcmd (char **args
)
1389 int msgp
= 0, md
, msgnum
;
1390 char *cp
, *file
= NULL
;
1391 char buf
[BUFSIZ
], *msgs
[MAXARGS
];
1395 forkcmd (args
, cmd_name
);
1399 while ((cp
= *args
++)) {
1401 switch (smatch (++cp
, packswit
)) {
1403 ambigsw (cp
, packswit
);
1406 fprintf (stderr
, "-%s unknown\n", cp
);
1409 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1410 print_help (buf
, packswit
, 1);
1414 if (!(file
= *args
++) || *file
== '-') {
1415 advise (NULL
, "missing argument to %s", args
[-2]);
1420 if (*cp
== '+' || *cp
== '@') {
1421 advise (NULL
, "sorry, no folders allowed!");
1430 file
= path (file
, TFILE
);
1431 if (stat (file
, &st
) == NOTOK
) {
1432 if (errno
!= ENOENT
) {
1433 advise (file
, "error on file");
1436 md
= getanswer (cp
= concat ("Create file \"", file
, "\"? ", NULL
));
1443 msgs
[msgp
++] = "all";
1444 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
1445 if (!m_convert (mp
, msgs
[msgnum
]))
1449 if ((md
= mbx_open (file
, mbx_style
, getuid (), getgid (), m_gmprot ())) == NOTOK
) {
1450 advise (file
, "unable to open");
1453 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
1454 if (is_selected (mp
, msgnum
))
1455 if (pack (file
, md
, msgnum
) == NOTOK
)
1457 mbx_close (file
, md
);
1459 if (mp
->hghsel
!= mp
->curmsg
)
1460 seq_setcur (mp
, mp
->lowsel
);
1468 pack (char *mailbox
, int md
, int msgnum
)
1472 if (Msgs
[msgnum
].m_bboard_id
== 0)
1475 zp
= msh_ready (msgnum
, 1);
1476 return mbx_write (mailbox
, md
, zp
, Msgs
[msgnum
].m_bboard_id
,
1477 0L, ftell (zp
), Msgs
[msgnum
].m_stop
, 1, 1);
1482 packhak (char **args
)
1485 char *cp
, *file
= NULL
;
1487 while ((cp
= *args
++)) {
1489 switch (smatch (++cp
, packswit
)) {
1496 if (!(file
= *args
++) || *file
== '-')
1500 if (*cp
== '+' || *cp
== '@')
1504 file
= path (file
? file
: "./msgbox", TFILE
);
1505 result
= access (file
, F_OK
) == NOTOK
? OK
: NOTOK
;
1512 #define PICK_SWITCHES \
1513 X("and", 0, PIANSW) \
1514 X("or", 0, PIORSW) \
1515 X("not", 0, PINTSW) \
1516 X("lbrace", 0, PILBSW) \
1517 X("rbrace", 0, PIRBSW) \
1518 X("cc pattern", 0, PICCSW) \
1519 X("date pattern", 0, PIDASW) \
1520 X("from pattern", 0, PIFRSW) \
1521 X("search pattern", 0, PISESW) \
1522 X("subject pattern", 0, PISUSW) \
1523 X("to pattern", 0, PITOSW) \
1524 X("-othercomponent pattern", 15, PIOTSW) \
1525 X("after date", 0, PIAFSW) \
1526 X("before date", 0, PIBFSW) \
1527 X("datefield field", 5, PIDFSW) \
1528 X("sequence name", 0, PISQSW) \
1529 X("public", 0, PIPUSW) \
1530 X("nopublic", 0, PINPUSW) \
1531 X("zero", 0, PIZRSW) \
1532 X("nozero", 0, PINZRSW) \
1533 X("list", 0, PILISW) \
1534 X("nolist", 0, PINLISW) \
1535 X("help", 0, PIHELP) \
1537 #define X(sw, minchars, id) id,
1538 DEFINE_SWITCH_ENUM(PICK
);
1541 #define X(sw, minchars, id) { sw, minchars, id },
1542 DEFINE_SWITCH_ARRAY(PICK
, pickswit
);
1547 pickcmd (char **args
)
1549 int zerosw
= 1, msgp
= 0;
1551 int vecp
= 0, hi
, lo
, msgnum
;
1552 char *cp
, buf
[BUFSIZ
], *msgs
[MAXARGS
];
1553 char *seqs
[NUMATTRS
], *vec
[MAXARGS
];
1556 while ((cp
= *args
++)) {
1562 switch (smatch (cp
, pickswit
)) {
1564 ambigsw (cp
, pickswit
);
1567 fprintf (stderr
, "-%s unknown\n", cp
);
1570 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1571 print_help (buf
, pickswit
, 1);
1585 if (!(cp
= *args
++)) {/* allow -xyz arguments */
1586 advise (NULL
, "missing argument to %s", args
[-2]);
1592 advise (NULL
, "internal error!");
1603 if (!(cp
= *args
++) || *cp
== '-') {
1604 advise (NULL
, "missing argument to %s", args
[-2]);
1607 if (seqp
< NUMATTRS
)
1610 advise (NULL
, "only %d sequences allowed!", NUMATTRS
);
1621 case PIPUSW
: /* not implemented */
1628 if (*cp
== '+' || *cp
== '@') {
1629 advise (NULL
, "sorry, no folders allowed!");
1638 msgs
[msgp
++] = "all";
1639 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
1640 if (!m_convert (mp
, msgs
[msgnum
]))
1645 if (!pcompile (vec
, NULL
))
1651 for (msgnum
= mp
->lowsel
;
1652 msgnum
<= mp
->hghsel
&& !interrupted
;
1654 if (is_selected (mp
, msgnum
)) {
1655 zp
= msh_ready (msgnum
, 1);
1656 if (pmatches (zp
, msgnum
, fmsh
? 0L : Msgs
[msgnum
].m_start
,
1657 fmsh
? 0L : Msgs
[msgnum
].m_stop
)) {
1664 unset_selected (mp
, msgnum
);
1675 if (mp
->numsel
<= 0) {
1676 advise (NULL
, "no messages match specification");
1681 for (seqp
= 0; seqs
[seqp
]; seqp
++)
1682 if (!seq_addsel (mp
, seqs
[seqp
], 0, zerosw
))
1685 printf ("%d hit%s\n", mp
->numsel
, mp
->numsel
== 1 ? "" : "s");
1689 #define REPL_SWITCHES \
1690 X("annotate", 0, REANSW) \
1691 X("noannotate", 0, RENANSW) \
1692 X("cc type", 0, RECCSW) \
1693 X("nocc type", 0, RENCCSW) \
1694 X("draftfolder +folder", 0, REDFSW) \
1695 X("draftmessage msg", 0, REDMSW) \
1696 X("nodraftfolder", 0, RENDFSW) \
1697 X("editor editor", 0, REEDTSW) \
1698 X("noedit", 0, RENEDSW) \
1699 X("fcc +folder", 0, REFCCSW) \
1700 X("filter filterfile", 0, REFLTSW) \
1701 X("form formfile", 0, REFRMSW) \
1702 X("inplace", 0, REINSW) \
1703 X("noinplace", 0, RENINSW) \
1704 X("query", 0, REQUSW) \
1705 X("noquery", 0, RENQUSW) \
1706 X("whatnowproc program", 0, REWHTSW) \
1707 X("nowhatnow", 0, RENWTSW) \
1708 X("width columns", 0, REWIDSW) \
1709 X("help", 0, REHELP) \
1711 #define X(sw, minchars, id) id,
1712 DEFINE_SWITCH_ENUM(REPL
);
1715 #define X(sw, minchars, id) { sw, minchars, id },
1716 DEFINE_SWITCH_ARRAY(REPL
, replswit
);
1721 replcmd (char **args
)
1724 char *cp
, *msg
= NULL
;
1725 char buf
[BUFSIZ
], *vec
[MAXARGS
];
1728 forkcmd (args
, cmd_name
);
1732 while ((cp
= *args
++)) {
1734 switch (smatch (++cp
, replswit
)) {
1736 ambigsw (cp
, replswit
);
1739 fprintf (stderr
, "-%s unknown\n", cp
);
1742 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1743 print_help (buf
, replswit
, 1);
1746 case REANSW
: /* not implemented */
1771 if (!(cp
= *args
++) || *cp
== '-') {
1772 advise (NULL
, "missing argument to %s", args
[-2]);
1778 if (*cp
== '+' || *cp
== '@') {
1779 advise (NULL
, "sorry, no folders allowed!");
1784 advise (NULL
, "only one message at a time!");
1792 vec
[vecp
++] = "-file";
1796 if (!m_convert (mp
, msg
))
1800 if (mp
->numsel
> 1) {
1801 advise (NULL
, "only one message at a time!");
1804 process (mp
->hghsel
, cmd_name
, vecp
, vec
);
1805 seq_setcur (mp
, mp
->hghsel
);
1809 #define RMM_SWITCHES \
1810 X("help", 0, RMHELP) \
1812 #define X(sw, minchars, id) id,
1813 DEFINE_SWITCH_ENUM(RMM
);
1816 #define X(sw, minchars, id) { sw, minchars, id },
1817 DEFINE_SWITCH_ARRAY(RMM
, rmmswit
);
1822 rmmcmd (char **args
)
1824 int msgp
= 0, msgnum
;
1825 char *cp
, buf
[BUFSIZ
], *msgs
[MAXARGS
];
1827 while ((cp
= *args
++)) {
1829 switch (smatch (++cp
, rmmswit
)) {
1831 ambigsw (cp
, rmmswit
);
1834 fprintf (stderr
, "-%s unknown\n", cp
);
1837 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1838 print_help (buf
, rmmswit
, 1);
1841 if (*cp
== '+' || *cp
== '@') {
1842 advise (NULL
, "sorry, no folders allowed!");
1850 msgs
[msgp
++] = "cur";
1851 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
1852 if (!m_convert (mp
, msgs
[msgnum
]))
1863 register int msgnum
, vecp
;
1865 char buffer
[BUFSIZ
], *vec
[MAXARGS
];
1869 if (mp
->numsel
> MAXARGS
- 1) {
1870 advise (NULL
, "more than %d messages for %s exec",
1871 MAXARGS
- 1, rmmproc
);
1875 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
1876 if (is_selected (mp
, msgnum
))
1877 vec
[vecp
++] = getcpy (m_name (msgnum
));
1879 forkcmd (vec
, rmmproc
);
1880 for (vecp
= 0; vec
[vecp
]; vecp
++)
1884 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
1885 if (is_selected (mp
, msgnum
)) {
1886 strncpy (buffer
, m_backup (cp
= m_name (msgnum
)), sizeof(buffer
));
1887 if (rename (cp
, buffer
) == NOTOK
)
1888 admonish (buffer
, "unable to rename %s to", cp
);
1892 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
1893 if (is_selected (mp
, msgnum
)) {
1894 set_deleted (mp
, msgnum
);
1895 unset_exists (mp
, msgnum
);
1898 if ((mp
->nummsg
-= mp
->numsel
) <= 0) {
1900 admonish (NULL
, "no messages remaining in +%s", fmsh
);
1902 admonish (NULL
, "no messages remaining in %s", mp
->foldpath
);
1903 mp
->lowmsg
= mp
->hghmsg
= mp
->nummsg
= 0;
1905 if (mp
->lowsel
== mp
->lowmsg
) {
1906 for (msgnum
= mp
->lowmsg
+ 1; msgnum
<= mp
->hghmsg
; msgnum
++)
1907 if (does_exist (mp
, msgnum
))
1909 mp
->lowmsg
= msgnum
;
1911 if (mp
->hghsel
== mp
->hghmsg
) {
1912 for (msgnum
= mp
->hghmsg
- 1; msgnum
>= mp
->lowmsg
; msgnum
--)
1913 if (does_exist (mp
, msgnum
))
1915 mp
->hghmsg
= msgnum
;
1918 mp
->msgflags
|= MODIFIED
;
1923 #define SCAN_SWITCHES \
1924 X("clear", 0, SCCLR) \
1925 X("noclear", 0, SCNCLR) \
1926 X("form formatfile", 0, SCFORM) \
1927 X("format string", 5, SCFMT) \
1928 X("header", 0, SCHEAD) \
1929 X("noheader", 0, SCNHEAD) \
1930 X("width columns", 0, SCWID) \
1931 X("help", 0, SCHELP) \
1933 #define X(sw, minchars, id) id,
1934 DEFINE_SWITCH_ENUM(SCAN
);
1937 #define X(sw, minchars, id) { sw, minchars, id },
1938 DEFINE_SWITCH_ARRAY(SCAN
, scanswit
);
1943 scancmd (char **args
)
1945 #define equiv(a,b) (a ? b && !strcmp (a, b) : !b)
1947 int clearsw
= 0, headersw
= 0, width
= 0, msgp
= 0;
1948 int msgnum
, optim
, state
;
1949 char *cp
, *form
= NULL
, *format
= NULL
;
1950 char buf
[BUFSIZ
], *nfs
, *msgs
[MAXARGS
];
1952 static int s_optim
= 0;
1953 static char *s_form
= NULL
, *s_format
= NULL
;
1955 while ((cp
= *args
++)) {
1957 switch (smatch (++cp
, scanswit
)) {
1959 ambigsw (cp
, scanswit
);
1962 fprintf (stderr
, "-%s unknown\n", cp
);
1965 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1966 print_help (buf
, scanswit
, 1);
1982 if (!(form
= *args
++) || *form
== '-') {
1983 advise (NULL
, "missing argument to %s", args
[-2]);
1989 if (!(format
= *args
++) || *format
== '-') {
1990 advise (NULL
, "missing argument to %s", args
[-2]);
1996 if (!(cp
= *args
++) || *cp
== '-') {
1997 advise (NULL
, "missing argument to %s", args
[-2]);
2003 if (*cp
== '+' || *cp
== '@') {
2004 advise (NULL
, "sorry, no folders allowed!");
2012 msgs
[msgp
++] = "all";
2013 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
2014 if (!m_convert (mp
, msgs
[msgnum
]))
2018 /* Get new format string */
2019 nfs
= new_fs (form
, format
, FORMAT
);
2021 /* force scansbr to (re)compile format */
2028 s_optim
= optim
= 1;
2029 s_form
= form
? getcpy (form
) : NULL
;
2030 s_format
= format
? getcpy (format
) : NULL
;
2034 optim
= equiv (s_form
, form
) && equiv (s_format
, format
);
2037 for (msgnum
= mp
->lowsel
;
2038 msgnum
<= mp
->hghsel
&& !interrupted
;
2040 if (is_selected (mp
, msgnum
)) {
2041 if (optim
&& Msgs
[msgnum
].m_scanl
)
2042 printf ("%s", Msgs
[msgnum
].m_scanl
);
2045 zp
= msh_ready (msgnum
, 0);
2046 switch (state
= scan (zp
, msgnum
, 0, nfs
, width
,
2047 msgnum
== mp
->curmsg
,
2048 is_unseen (mp
, msgnum
),
2049 headersw
? (fmsh
? fmsh
: mp
->foldpath
) : NULL
,
2050 fmsh
? 0L : (long) (Msgs
[msgnum
].m_stop
- Msgs
[msgnum
].m_start
),
2056 Msgs
[msgnum
].m_scanl
= getcpy (scanl
);
2060 advise (NULL
, "scan() botch (%d)", state
);
2064 printf ("%*d empty\n", DMAXFOLDER
, msgnum
);
2076 #define SHOW_SWITCHES \
2077 X("draft", 5, SHDRAFT) \
2078 X("form formfile", 4, SHFORM) \
2079 X("moreproc program", 4, SHPROG) \
2080 X("nomoreproc", 3, SHNPROG) \
2081 X("length lines", 4, SHLEN) \
2082 X("width columns", 4, SHWID) \
2083 X("showproc program", 4, SHSHOW) \
2084 X("noshowproc", 3, SHNSHOW) \
2085 X("header", 4, SHHEAD) \
2086 X("noheader", 3, SHNHEAD) \
2087 X("help", 0, SHHELP) \
2089 #define X(sw, minchars, id) id,
2090 DEFINE_SWITCH_ENUM(SHOW
);
2093 #define X(sw, minchars, id) { sw, minchars, id },
2094 DEFINE_SWITCH_ARRAY(SHOW
, showswit
);
2099 showcmd (char **args
)
2101 int headersw
= 1, nshow
= 0, msgp
= 0, vecp
= 1;
2102 int mhl
= 0, seqnum
= -1, mode
= 0, i
, msgnum
;
2103 char *cp
, *proc
= showproc
, buf
[BUFSIZ
];
2104 char *msgs
[MAXARGS
], *vec
[MAXARGS
];
2106 if (!mh_strcasecmp (cmd_name
, "next"))
2109 if (!mh_strcasecmp (cmd_name
, "prev"))
2111 while ((cp
= *args
++)) {
2113 switch (i
= smatch (++cp
, showswit
)) {
2115 ambigsw (cp
, showswit
);
2122 snprintf (buf
, sizeof(buf
), "%s %s[switches] [switches for showproc]",
2123 cmd_name
, mode
? NULL
: "[msgs] ");
2124 print_help (buf
, showswit
, 1);
2132 if (!(cp
= *args
++) || *cp
== '-') {
2133 advise (NULL
, "missing argument to %s", args
[-2]);
2145 if (!(proc
= *args
++) || *proc
== '-') {
2146 advise (NULL
, "missing argument to %s", args
[-2]);
2156 advise (NULL
, "sorry, -%s not allowed!", showswit
[i
].sw
);
2159 if (*cp
== '+' || *cp
== '@') {
2160 advise (NULL
, "sorry, no folders allowed!");
2166 "usage: %s [switches] [switches for showproc]\n",
2176 msgs
[msgp
++] = mode
> 0 ? "next" : mode
< 0 ? "prev" : "cur";
2177 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
2178 if (!m_convert (mp
, msgs
[msgnum
]))
2183 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
2184 if (is_selected (mp
, msgnum
) && is_nontext (msgnum
)) {
2185 proc
= showmimeproc
;
2186 vec
[vecp
++] = "-file";
2194 if (strcmp (showproc
, "mhl") == 0) {
2200 seqnum
= seq_getnum (mp
, "unseen");
2201 vec
[0] = r1bindex (proc
, '/');
2204 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
2205 if (is_selected (mp
, msgnum
)) {
2206 vec
[vecp
++] = getcpy (m_name (msgnum
));
2208 seq_delmsg (mp
, "unseen", msgnum
);
2211 if (mp
->numsel
== 1 && headersw
)
2213 mhlsbr (vecp
, vec
, mhl_action
);
2214 m_eomsbr ((int (*)()) 0);
2219 for (msgnum
= mp
->lowsel
;
2220 msgnum
<= mp
->hghsel
&& !interrupted
;
2222 if (is_selected (mp
, msgnum
)) {
2223 switch (ask (msgnum
)) {
2224 case NOTOK
: /* QUIT */
2231 if (mp
->numsel
== 1 && headersw
)
2234 copy_message (msgnum
, stdout
);
2236 process (msgnum
, proc
, vecp
, vec
);
2239 seq_delmsg (mp
, "unseen", msgnum
);
2246 seq_setcur (mp
, mp
->hghsel
);
2253 if (Msgs
[msgnum
].m_bboard_id
== 0)
2256 printf ("(Message %d", msgnum
);
2257 if (Msgs
[msgnum
].m_bboard_id
> 0)
2258 printf (", %s: %d", BBoard_ID
, Msgs
[msgnum
].m_bboard_id
);
2269 return (ftell (mhlfp
) >= Msgs
[mhlnum
].m_stop
);
2274 mhl_action (char *name
)
2278 if ((msgnum
= m_atoi (name
)) < mp
->lowmsg
2279 || msgnum
> mp
->hghmsg
2280 || !does_exist (mp
, msgnum
))
2284 mhlfp
= msh_ready (msgnum
, 1);
2286 m_eomsbr (eom_action
);
2298 if (mp
->numsel
== 1 || !interactive
|| redirected
)
2301 if (SOprintf ("Press <return> to list \"%d\"...", msgnum
)) {
2302 if (mp
->lowsel
!= msgnum
)
2304 printf ("Press <return> to list \"%d\"...", msgnum
);
2309 read (fileno (stdout
), buf
, sizeof buf
);
2311 if (strchr(buf
, '\n') == NULL
)
2315 told_to_quit
= interrupted
= 0;
2330 is_nontext (int msgnum
)
2333 unsigned char *bp
, *dp
;
2335 char buf
[BUFSIZ
], name
[NAMESZ
];
2338 if (Msgs
[msgnum
].m_flags
& MHNCHK
)
2339 return (Msgs
[msgnum
].m_flags
& MHNYES
);
2340 Msgs
[msgnum
].m_flags
|= MHNCHK
;
2342 fp
= msh_ready (msgnum
, 1);
2345 switch (state
= m_getfld (state
, name
, buf
, sizeof buf
, fp
)) {
2350 * Check Content-Type field
2352 if (!mh_strcasecmp (name
, TYPE_FIELD
)) {
2356 cp
= add (buf
, NULL
);
2357 while (state
== FLDPLUS
) {
2358 state
= m_getfld (state
, name
, buf
, sizeof buf
, fp
);
2365 for (; isspace (*bp
); bp
++)
2370 for (bp
++, i
= 0;;) {
2400 for (dp
= bp
; istoken (*dp
); dp
++)
2407 if ((result
= (mh_strcasecmp (bp
, "plain") != 0)))
2410 for (dp
++; isspace (*dp
); dp
++)
2413 if ((result
= !uprf (dp
, "charset")))
2415 dp
+= sizeof "charset" - 1;
2416 while (isspace (*dp
))
2420 while (isspace (*dp
))
2423 if ((bp
= strchr(++dp
, '"')))
2426 for (bp
= dp
; *bp
; bp
++)
2427 if (isspace (*bp
)) {
2433 /* Default character set */
2436 /* Check the character set */
2437 result
= !check_charset (dp
, strlen (dp
));
2439 if (!(result
= (mh_strcasecmp (bp
, "text") != 0))) {
2449 Msgs
[msgnum
].m_flags
|= MHNYES
;
2456 * Check Content-Transfer-Encoding field
2458 if (!mh_strcasecmp (name
, ENCODING_FIELD
)) {
2459 cp
= add (buf
, NULL
);
2460 while (state
== FLDPLUS
) {
2461 state
= m_getfld (state
, name
, buf
, sizeof buf
, fp
);
2464 for (bp
= cp
; isspace (*bp
); bp
++)
2466 for (dp
= bp
; istoken (*dp
); dp
++)
2469 result
= (mh_strcasecmp (bp
, "7bit")
2470 && mh_strcasecmp (bp
, "8bit")
2471 && mh_strcasecmp (bp
, "binary"));
2475 Msgs
[msgnum
].m_flags
|= MHNYES
;
2482 * Just skip the rest of this header
2483 * field and go to next one.
2485 while (state
== FLDPLUS
)
2486 state
= m_getfld (state
, name
, buf
, sizeof(buf
), fp
);
2490 * We've passed the message header,
2491 * so message is just text.
2499 #define SORT_SWITCHES \
2500 X("datefield field", 0, SODATE) \
2501 X("textfield field", 0, SOSUBJ) \
2502 X("notextfield", 0, SONSUBJ) \
2503 X("limit days", 0, SOLIMT) \
2504 X("nolimit", 0, SONLIMT) \
2505 X("verbose", 0, SOVERB) \
2506 X("noverbose", 0, SONVERB) \
2507 X("help", 0, SOHELP) \
2509 #define X(sw, minchars, id) id,
2510 DEFINE_SWITCH_ENUM(SORT
);
2513 #define X(sw, minchars, id) { sw, minchars, id },
2514 DEFINE_SWITCH_ARRAY(SORT
, sortswit
);
2519 sortcmd (char **args
)
2521 int msgp
= 0, msgnum
;
2522 char *cp
, *datesw
= NULL
, *subjsw
= NULL
;
2523 char buf
[BUFSIZ
], *msgs
[MAXARGS
];
2527 forkcmd (args
, cmd_name
);
2531 while ((cp
= *args
++)) {
2533 switch (smatch (++cp
, sortswit
)) {
2535 ambigsw (cp
, sortswit
);
2538 fprintf (stderr
, "-%s unknown\n", cp
);
2541 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
2542 print_help (buf
, sortswit
, 1);
2547 advise (NULL
, "only one date field at a time!");
2550 if (!(datesw
= *args
++) || *datesw
== '-') {
2551 advise (NULL
, "missing argument to %s", args
[-2]);
2558 advise (NULL
, "only one text field at a time!");
2561 if (!(subjsw
= *args
++) || *subjsw
== '-') {
2562 advise (NULL
, "missing argument to %s", args
[-2]);
2570 case SOLIMT
: /* too hard */
2571 if (!(cp
= *args
++) || *cp
== '-') {
2572 advise (NULL
, "missing argument to %s", args
[-2]);
2576 case SOVERB
: /* not implemented */
2580 if (*cp
== '+' || *cp
== '@') {
2581 advise (NULL
, "sorry, no folders allowed!");
2589 msgs
[msgp
++] = "all";
2592 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
2593 if (!m_convert (mp
, msgs
[msgnum
]))
2597 twscopy (&tb
, dlocaltimenow ());
2599 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++) {
2600 if (Msgs
[msgnum
].m_scanl
) {
2601 free (Msgs
[msgnum
].m_scanl
);
2602 Msgs
[msgnum
].m_scanl
= NULL
;
2604 if (is_selected (mp
, msgnum
)) {
2605 if (get_fields (datesw
, subjsw
, msgnum
, &Msgs
[msgnum
]))
2606 twscopy (&Msgs
[msgnum
].m_tb
,
2607 msgnum
!= mp
->lowsel
? &Msgs
[msgnum
- 1].m_tb
: &tb
);
2609 else /* m_scaln is already NULL */
2610 twscopy (&Msgs
[msgnum
].m_tb
, &tb
);
2611 Msgs
[msgnum
].m_stats
= mp
->msgstats
[msgnum
- mp
->lowoff
];
2612 if (mp
->curmsg
== msgnum
)
2613 Msgs
[msgnum
].m_stats
|= CUR
;
2616 qsort ((char *) &Msgs
[mp
->lowsel
], mp
->hghsel
- mp
->lowsel
+ 1,
2617 sizeof(struct Msg
), (qsort_comp
) (subjsw
? subsort
: msgsort
));
2619 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++) {
2620 if (subjsw
&& Msgs
[msgnum
].m_scanl
) {
2621 free (Msgs
[msgnum
].m_scanl
); /* from subjsort */
2622 Msgs
[msgnum
].m_scanl
= NULL
;
2624 mp
->msgstats
[msgnum
- mp
->lowoff
] = Msgs
[msgnum
].m_stats
& ~CUR
;
2625 if (Msgs
[msgnum
].m_stats
& CUR
)
2626 seq_setcur (mp
, msgnum
);
2629 mp
->msgflags
|= MODIFIED
;
2635 * get_fields - parse message, and get date and subject if needed.
2636 * We'll use the msgp->m_tb tws struct for the date, and overload
2637 * the msgp->m_scanl field with our subject string.
2640 get_fields (char *datesw
, char *subjsw
, int msgnum
, struct Msg
*msgp
)
2642 int state
, gotdate
= 0;
2643 char *bp
, buf
[BUFSIZ
], name
[NAMESZ
];
2644 struct tws
*tw
= (struct tws
*) 0;
2647 zp
= msh_ready (msgnum
, 0);
2648 for (state
= FLD
;;) {
2649 switch (state
= m_getfld (state
, name
, buf
, sizeof buf
, zp
)) {
2653 if (!mh_strcasecmp (name
, datesw
)) {
2655 while (state
== FLDPLUS
) {
2656 state
= m_getfld (state
, name
, buf
, sizeof buf
, zp
);
2659 if ((tw
= dparsetime (bp
)) == NULL
)
2661 "unable to parse %s field in message %d",
2664 twscopy (&(msgp
->m_tb
), tw
);
2666 if (!subjsw
) /* not using this, or already done */
2667 break; /* all done! */
2670 else if (subjsw
&& !mh_strcasecmp(name
, subjsw
)) {
2672 while (state
== FLDPLUS
) {
2673 state
= m_getfld (state
, name
, buf
, sizeof buf
, zp
);
2676 msgp
->m_scanl
= sosmash(subjsw
, bp
);
2678 break; /* date done so we're done */
2680 subjsw
= (char *)0;/* subject done, need date */
2682 while (state
== FLDPLUS
) /* flush this one */
2683 state
= m_getfld (state
, name
, buf
, sizeof buf
, zp
);
2694 admonish (NULL
, "format error in message %d", msgnum
);
2695 if (msgp
->m_scanl
) { /* this might need free'd */
2696 free (msgp
->m_scanl
); /* probably can't use subj anyway */
2697 msgp
->m_scanl
= NULL
;
2702 adios (NULL
, "internal error -- you lose");
2707 return OK
; /* not an error if subj not found */
2709 admonish (NULL
, "no %s field in message %d", datesw
, msgnum
);
2710 return NOTOK
; /* NOTOK means use some other date */
2719 msgsort (struct Msg
*a
, struct Msg
*b
)
2721 return twsort (&a
->m_tb
, &b
->m_tb
);
2726 subsort (struct Msg
*a
, struct Msg
*b
)
2730 if (a
->m_scanl
&& b
->m_scanl
)
2731 if ((i
= strcmp (a
->m_scanl
, b
->m_scanl
)))
2734 return twsort (&a
->m_tb
, &b
->m_tb
);
2739 * try to make the subject "canonical": delete leading "re:", everything
2740 * but letters & smash letters to lower case.
2743 sosmash (char *subj
, char *s
)
2745 register char *cp
, *dp
;
2746 register unsigned char c
;
2750 dp
= s
; /* dst pointer */
2751 if (!mh_strcasecmp (subj
, "subject"))
2758 *dp
++ = isupper(c
) ? tolower(c
) : c
;
2764 while ((c
= *cp
++)) {
2766 *dp
++ = isupper(c
) ? tolower(c
) : c
;
2776 process (int msgnum
, char *proc
, int vecp
, char **vec
)
2778 int child_id
, status
;
2779 char tmpfil
[BUFSIZ
];
2784 strncpy (tmpfil
, m_name (msgnum
), sizeof(tmpfil
));
2785 context_del (pfolder
);
2786 context_replace (pfolder
, fmsh
);/* update current folder */
2788 context_save (); /* save the context file */
2792 cp
= m_mktemp(invo_name
, NULL
, &out
);
2794 /* Try again, but try to create under /tmp */
2796 cp
= m_mktemp2(NULL
, invo_name
, NULL
, &out
);
2799 advise (NULL
, "unable to create temporary file");
2803 copy_message (msgnum
, out
);
2805 strncpy(tmpfil
, cp
, sizeof(tmpfil
));
2809 switch (child_id
= fork ()) {
2811 advise ("fork", "unable to");
2817 SIGNAL (SIGINT
, istat
);
2818 SIGNAL (SIGQUIT
, qstat
);
2820 vec
[vecp
++] = tmpfil
;
2824 fprintf (stderr
, "unable to exec ");
2829 status
= pidXwait (child_id
, NULL
);
2840 copy_message (int msgnum
, FILE *out
)
2843 static char buffer
[BUFSIZ
];
2846 zp
= msh_ready (msgnum
, 1);
2848 while (fgets (buffer
, sizeof buffer
, zp
) != NULL
) {
2849 fputs (buffer
, out
);
2850 if (interrupted
&& out
== stdout
)
2856 while (fgets (buffer
, sizeof buffer
, zp
) != NULL
2857 && pos
< Msgs
[msgnum
].m_stop
) {
2858 fputs (buffer
, out
);
2859 pos
+= (long) strlen (buffer
);
2860 if (interrupted
&& out
== stdout
)
2868 copy_digest (int msgnum
, FILE *out
)
2872 static char buffer
[BUFSIZ
];
2876 zp
= msh_ready (msgnum
, 1);
2879 while (fgets (buffer
, sizeof buffer
, zp
) != NULL
2880 && !fmsh
&& pos
< Msgs
[msgnum
].m_stop
) {
2881 if (c
== '\n' && *buffer
== '-')
2883 fputs (buffer
, out
);
2884 c
= buffer
[strlen (buffer
) - 1];
2886 pos
+= (long) strlen (buffer
);
2887 if (interrupted
&& out
== stdout
)