]>
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>
18 #include <h/picksbr.h>
22 static char delim3
[] = "-------"; /* from burst.c */
28 * Type for a compare function for qsort. This keeps
31 typedef int (*qsort_comp
) (const void *, const void *);
36 static int burst (struct Msg
*, int, int, int, int);
37 static void forw (char *, char *, int, char **);
38 static void rmm (void);
39 static void show (int);
40 static int eom_action (int);
41 static FILE *mhl_action (char *);
43 static int is_nontext (int);
44 static int get_fields (char *, char *, int, struct Msg
*);
45 static int msgsort (struct Msg
*, struct Msg
*);
46 static int subsort (struct Msg
*, struct Msg
*);
47 static char *sosmash (char *, char *);
48 static int process (int, char *, int, char **);
49 static void copy_message (int, FILE *);
50 static void copy_digest (int, FILE *);
52 extern m_getfld_state_t gstate
; /* use the gstate in scansbr.c */
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 scan_eom_action ((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) *bvector_bits (msgstat (mp
,
1232 if (Msgs
[msgnum
].m_scanl
)
1233 printf ("%s", Msgs
[msgnum
].m_scanl
);
1239 #define MHN_SWITCHES \
1240 X("auto", 0, MHNAUTOSW) \
1241 X("noauto", 0, MHNNAUTOSW) \
1242 X("debug", -5, MHNDEBUGSW) \
1243 X("form formfile", 4, MHNFORMSW) \
1244 X("headers", 0, MHNHEADSW) \
1245 X("noheaders", 0, MHNNHEADSW) \
1246 X("list", 0, MHNLISTSW) \
1247 X("nolist", 0, MHNNLISTSW) \
1248 X("part number", 0, MHNPARTSW) \
1249 X("realsize", 0, MHNSIZESW) \
1250 X("norealsize", 0, MHNNSIZESW) \
1251 X("rfc934mode", 0, MHNRFC934SW) \
1252 X("norfc934mode", 0, MHNNRFC934SW) \
1253 X("serialonly", 0, MHNSERIALSW) \
1254 X("noserialonly", 0, MHNNSERIALSW) \
1255 X("show", 0, MHNSHOWSW) \
1256 X("noshow", 0, MHNNSHOWSW) \
1257 X("store", 0, MHNSTORESW) \
1258 X("nostore", 0, MHNNSTORESW) \
1259 X("type content", 0, MHNTYPESW) \
1260 X("verbose", 0, MHNVERBSW) \
1261 X("noverbose", 0, MHNNVERBSW) \
1262 X("help", 0, MHNHELPSW) \
1263 X("moreproc program", -4, MHNPROGSW) \
1264 X("nomoreproc", -3, MHNNPROGSW) \
1265 X("length lines", -4, MHNLENSW) \
1266 X("width columns", -4, MHNWIDSW) \
1268 #define X(sw, minchars, id) id,
1269 DEFINE_SWITCH_ENUM(MHN
);
1272 #define X(sw, minchars, id) { sw, minchars, id },
1273 DEFINE_SWITCH_ARRAY(MHN
, mhnswit
);
1278 mhncmd (char **args
)
1280 int msgp
= 0, vecp
= 1;
1282 char *cp
, buf
[BUFSIZ
];
1283 char *msgs
[MAXARGS
], *vec
[MAXARGS
];
1286 forkcmd (args
, cmd_name
);
1289 while ((cp
= *args
++)) {
1291 switch (smatch (++cp
, mhnswit
)) {
1293 ambigsw (cp
, mhnswit
);
1296 fprintf (stderr
, "-%s unknown\n", cp
);
1299 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1300 print_help (buf
, mhnswit
, 1);
1333 if (!(cp
= *args
++) || *cp
== '-') {
1334 advise (NULL
, "missing argument to %s", args
[-2]);
1341 if (*cp
== '+' || *cp
== '@') {
1342 advise (NULL
, "sorry, no folders allowed!");
1350 vec
[vecp
++] = "-file";
1353 msgs
[msgp
++] = "cur";
1354 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
1355 if (!m_convert (mp
, msgs
[msgnum
]))
1360 for (msgnum
= mp
->lowsel
;
1361 msgnum
<= mp
->hghsel
&& !interrupted
;
1363 if (is_selected (mp
, msgnum
))
1364 if (process (msgnum
, cmd_name
, vecp
, vec
)) {
1365 unset_selected (mp
, msgnum
);
1369 seq_setcur (mp
, mp
->hghsel
);
1373 #define PACK_SWITCHES \
1374 X("file name", 0, PAFISW) \
1375 X("help", 0, PAHELP) \
1377 #define X(sw, minchars, id) id,
1378 DEFINE_SWITCH_ENUM(PACK
);
1381 #define X(sw, minchars, id) { sw, minchars, id },
1382 DEFINE_SWITCH_ARRAY(PACK
, packswit
);
1385 static int mbx_style
= MMDF_FORMAT
;
1388 packcmd (char **args
)
1390 int msgp
= 0, md
, msgnum
;
1391 char *cp
, *file
= NULL
;
1392 char buf
[BUFSIZ
], *msgs
[MAXARGS
];
1396 forkcmd (args
, cmd_name
);
1400 while ((cp
= *args
++)) {
1402 switch (smatch (++cp
, packswit
)) {
1404 ambigsw (cp
, packswit
);
1407 fprintf (stderr
, "-%s unknown\n", cp
);
1410 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1411 print_help (buf
, packswit
, 1);
1415 if (!(file
= *args
++) || *file
== '-') {
1416 advise (NULL
, "missing argument to %s", args
[-2]);
1421 if (*cp
== '+' || *cp
== '@') {
1422 advise (NULL
, "sorry, no folders allowed!");
1431 file
= path (file
, TFILE
);
1432 if (stat (file
, &st
) == NOTOK
) {
1433 if (errno
!= ENOENT
) {
1434 advise (file
, "error on file");
1437 md
= getanswer (cp
= concat ("Create file \"", file
, "\"? ", NULL
));
1444 msgs
[msgp
++] = "all";
1445 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
1446 if (!m_convert (mp
, msgs
[msgnum
]))
1450 if ((md
= mbx_open (file
, mbx_style
, getuid (), getgid (), m_gmprot ())) == NOTOK
) {
1451 advise (file
, "unable to open");
1454 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
1455 if (is_selected (mp
, msgnum
))
1456 if (pack (file
, md
, msgnum
) == NOTOK
)
1458 mbx_close (file
, md
);
1460 if (mp
->hghsel
!= mp
->curmsg
)
1461 seq_setcur (mp
, mp
->lowsel
);
1469 pack (char *mailbox
, int md
, int msgnum
)
1473 if (Msgs
[msgnum
].m_bboard_id
== 0)
1476 zp
= msh_ready (msgnum
, 1);
1477 return mbx_write (mailbox
, md
, zp
, Msgs
[msgnum
].m_bboard_id
,
1478 0L, ftell (zp
), Msgs
[msgnum
].m_stop
, 1, 1);
1483 packhak (char **args
)
1486 char *cp
, *file
= NULL
;
1488 while ((cp
= *args
++)) {
1490 switch (smatch (++cp
, packswit
)) {
1497 if (!(file
= *args
++) || *file
== '-')
1501 if (*cp
== '+' || *cp
== '@')
1505 file
= path (file
? file
: "./msgbox", TFILE
);
1506 result
= access (file
, F_OK
) == NOTOK
? OK
: NOTOK
;
1513 #define PICK_SWITCHES \
1514 X("and", 0, PIANSW) \
1515 X("or", 0, PIORSW) \
1516 X("not", 0, PINTSW) \
1517 X("lbrace", 0, PILBSW) \
1518 X("rbrace", 0, PIRBSW) \
1519 X("cc pattern", 0, PICCSW) \
1520 X("date pattern", 0, PIDASW) \
1521 X("from pattern", 0, PIFRSW) \
1522 X("search pattern", 0, PISESW) \
1523 X("subject pattern", 0, PISUSW) \
1524 X("to pattern", 0, PITOSW) \
1525 X("-othercomponent pattern", 15, PIOTSW) \
1526 X("after date", 0, PIAFSW) \
1527 X("before date", 0, PIBFSW) \
1528 X("datefield field", 5, PIDFSW) \
1529 X("sequence name", 0, PISQSW) \
1530 X("public", 0, PIPUSW) \
1531 X("nopublic", 0, PINPUSW) \
1532 X("zero", 0, PIZRSW) \
1533 X("nozero", 0, PINZRSW) \
1534 X("list", 0, PILISW) \
1535 X("nolist", 0, PINLISW) \
1536 X("help", 0, PIHELP) \
1538 #define X(sw, minchars, id) id,
1539 DEFINE_SWITCH_ENUM(PICK
);
1542 #define X(sw, minchars, id) { sw, minchars, id },
1543 DEFINE_SWITCH_ARRAY(PICK
, pickswit
);
1548 pickcmd (char **args
)
1550 int zerosw
= 1, msgp
= 0;
1552 int vecp
= 0, hi
, lo
, msgnum
;
1553 char *cp
, buf
[BUFSIZ
], *msgs
[MAXARGS
];
1554 char *seqs
[NUMATTRS
], *vec
[MAXARGS
];
1557 while ((cp
= *args
++)) {
1563 switch (smatch (cp
, pickswit
)) {
1565 ambigsw (cp
, pickswit
);
1568 fprintf (stderr
, "-%s unknown\n", cp
);
1571 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1572 print_help (buf
, pickswit
, 1);
1586 if (!(cp
= *args
++)) {/* allow -xyz arguments */
1587 advise (NULL
, "missing argument to %s", args
[-2]);
1593 advise (NULL
, "internal error!");
1604 if (!(cp
= *args
++) || *cp
== '-') {
1605 advise (NULL
, "missing argument to %s", args
[-2]);
1608 if (seqp
< NUMATTRS
)
1611 advise (NULL
, "only %d sequences allowed!", NUMATTRS
);
1622 case PIPUSW
: /* not implemented */
1629 if (*cp
== '+' || *cp
== '@') {
1630 advise (NULL
, "sorry, no folders allowed!");
1639 msgs
[msgp
++] = "all";
1640 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
1641 if (!m_convert (mp
, msgs
[msgnum
]))
1646 if (!pcompile (vec
, NULL
))
1652 for (msgnum
= mp
->lowsel
;
1653 msgnum
<= mp
->hghsel
&& !interrupted
;
1655 if (is_selected (mp
, msgnum
)) {
1656 zp
= msh_ready (msgnum
, 1);
1657 if (pmatches (zp
, msgnum
, fmsh
? 0L : Msgs
[msgnum
].m_start
,
1658 fmsh
? 0L : Msgs
[msgnum
].m_stop
)) {
1665 unset_selected (mp
, msgnum
);
1676 if (mp
->numsel
<= 0) {
1677 advise (NULL
, "no messages match specification");
1682 for (seqp
= 0; seqs
[seqp
]; seqp
++)
1683 if (!seq_addsel (mp
, seqs
[seqp
], 0, zerosw
))
1686 printf ("%d hit%s\n", mp
->numsel
, mp
->numsel
== 1 ? "" : "s");
1690 #define REPL_SWITCHES \
1691 X("annotate", 0, REANSW) \
1692 X("noannotate", 0, RENANSW) \
1693 X("cc type", 0, RECCSW) \
1694 X("nocc type", 0, RENCCSW) \
1695 X("draftfolder +folder", 0, REDFSW) \
1696 X("draftmessage msg", 0, REDMSW) \
1697 X("nodraftfolder", 0, RENDFSW) \
1698 X("editor editor", 0, REEDTSW) \
1699 X("noedit", 0, RENEDSW) \
1700 X("fcc +folder", 0, REFCCSW) \
1701 X("filter filterfile", 0, REFLTSW) \
1702 X("form formfile", 0, REFRMSW) \
1703 X("inplace", 0, REINSW) \
1704 X("noinplace", 0, RENINSW) \
1705 X("query", 0, REQUSW) \
1706 X("noquery", 0, RENQUSW) \
1707 X("whatnowproc program", 0, REWHTSW) \
1708 X("nowhatnow", 0, RENWTSW) \
1709 X("width columns", 0, REWIDSW) \
1710 X("help", 0, REHELP) \
1712 #define X(sw, minchars, id) id,
1713 DEFINE_SWITCH_ENUM(REPL
);
1716 #define X(sw, minchars, id) { sw, minchars, id },
1717 DEFINE_SWITCH_ARRAY(REPL
, replswit
);
1722 replcmd (char **args
)
1725 char *cp
, *msg
= NULL
;
1726 char buf
[BUFSIZ
], *vec
[MAXARGS
];
1729 forkcmd (args
, cmd_name
);
1733 while ((cp
= *args
++)) {
1735 switch (smatch (++cp
, replswit
)) {
1737 ambigsw (cp
, replswit
);
1740 fprintf (stderr
, "-%s unknown\n", cp
);
1743 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1744 print_help (buf
, replswit
, 1);
1747 case REANSW
: /* not implemented */
1772 if (!(cp
= *args
++) || *cp
== '-') {
1773 advise (NULL
, "missing argument to %s", args
[-2]);
1779 if (*cp
== '+' || *cp
== '@') {
1780 advise (NULL
, "sorry, no folders allowed!");
1785 advise (NULL
, "only one message at a time!");
1793 vec
[vecp
++] = "-file";
1797 if (!m_convert (mp
, msg
))
1801 if (mp
->numsel
> 1) {
1802 advise (NULL
, "only one message at a time!");
1805 process (mp
->hghsel
, cmd_name
, vecp
, vec
);
1806 seq_setcur (mp
, mp
->hghsel
);
1810 #define RMM_SWITCHES \
1811 X("help", 0, RMHELP) \
1813 #define X(sw, minchars, id) id,
1814 DEFINE_SWITCH_ENUM(RMM
);
1817 #define X(sw, minchars, id) { sw, minchars, id },
1818 DEFINE_SWITCH_ARRAY(RMM
, rmmswit
);
1823 rmmcmd (char **args
)
1825 int msgp
= 0, msgnum
;
1826 char *cp
, buf
[BUFSIZ
], *msgs
[MAXARGS
];
1828 while ((cp
= *args
++)) {
1830 switch (smatch (++cp
, rmmswit
)) {
1832 ambigsw (cp
, rmmswit
);
1835 fprintf (stderr
, "-%s unknown\n", cp
);
1838 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1839 print_help (buf
, rmmswit
, 1);
1842 if (*cp
== '+' || *cp
== '@') {
1843 advise (NULL
, "sorry, no folders allowed!");
1851 msgs
[msgp
++] = "cur";
1852 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
1853 if (!m_convert (mp
, msgs
[msgnum
]))
1864 register int msgnum
, vecp
;
1866 char buffer
[BUFSIZ
], *vec
[MAXARGS
];
1870 if (mp
->numsel
> MAXARGS
- 1) {
1871 advise (NULL
, "more than %d messages for %s exec",
1872 MAXARGS
- 1, rmmproc
);
1876 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
1877 if (is_selected (mp
, msgnum
))
1878 vec
[vecp
++] = getcpy (m_name (msgnum
));
1880 forkcmd (vec
, rmmproc
);
1881 for (vecp
= 0; vec
[vecp
]; vecp
++)
1885 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
1886 if (is_selected (mp
, msgnum
)) {
1887 strncpy (buffer
, m_backup (cp
= m_name (msgnum
)), sizeof(buffer
));
1888 if (rename (cp
, buffer
) == NOTOK
)
1889 admonish (buffer
, "unable to rename %s to", cp
);
1893 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
1894 if (is_selected (mp
, msgnum
)) {
1895 set_deleted (mp
, msgnum
);
1896 unset_exists (mp
, msgnum
);
1899 if ((mp
->nummsg
-= mp
->numsel
) <= 0) {
1901 admonish (NULL
, "no messages remaining in +%s", fmsh
);
1903 admonish (NULL
, "no messages remaining in %s", mp
->foldpath
);
1904 mp
->lowmsg
= mp
->hghmsg
= mp
->nummsg
= 0;
1906 if (mp
->lowsel
== mp
->lowmsg
) {
1907 for (msgnum
= mp
->lowmsg
+ 1; msgnum
<= mp
->hghmsg
; msgnum
++)
1908 if (does_exist (mp
, msgnum
))
1910 mp
->lowmsg
= msgnum
;
1912 if (mp
->hghsel
== mp
->hghmsg
) {
1913 for (msgnum
= mp
->hghmsg
- 1; msgnum
>= mp
->lowmsg
; msgnum
--)
1914 if (does_exist (mp
, msgnum
))
1916 mp
->hghmsg
= msgnum
;
1919 mp
->msgflags
|= MODIFIED
;
1924 #define SCAN_SWITCHES \
1925 X("clear", 0, SCCLR) \
1926 X("noclear", 0, SCNCLR) \
1927 X("form formatfile", 0, SCFORM) \
1928 X("format string", 5, SCFMT) \
1929 X("header", 0, SCHEAD) \
1930 X("noheader", 0, SCNHEAD) \
1931 X("width columns", 0, SCWID) \
1932 X("help", 0, SCHELP) \
1934 #define X(sw, minchars, id) id,
1935 DEFINE_SWITCH_ENUM(SCAN
);
1938 #define X(sw, minchars, id) { sw, minchars, id },
1939 DEFINE_SWITCH_ARRAY(SCAN
, scanswit
);
1944 scancmd (char **args
)
1946 #define equiv(a,b) (a ? b && !strcmp (a, b) : !b)
1948 int clearsw
= 0, headersw
= 0, width
= 0, msgp
= 0;
1949 int msgnum
, optim
, state
;
1950 char *cp
, *form
= NULL
, *format
= NULL
;
1951 char buf
[BUFSIZ
], *nfs
, *msgs
[MAXARGS
];
1953 static int s_optim
= 0;
1954 static char *s_form
= NULL
, *s_format
= NULL
;
1956 while ((cp
= *args
++)) {
1958 switch (smatch (++cp
, scanswit
)) {
1960 ambigsw (cp
, scanswit
);
1963 fprintf (stderr
, "-%s unknown\n", cp
);
1966 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1967 print_help (buf
, scanswit
, 1);
1983 if (!(form
= *args
++) || *form
== '-') {
1984 advise (NULL
, "missing argument to %s", args
[-2]);
1990 if (!(format
= *args
++) || *format
== '-') {
1991 advise (NULL
, "missing argument to %s", args
[-2]);
1997 if (!(cp
= *args
++) || *cp
== '-') {
1998 advise (NULL
, "missing argument to %s", args
[-2]);
2004 if (*cp
== '+' || *cp
== '@') {
2005 advise (NULL
, "sorry, no folders allowed!");
2013 msgs
[msgp
++] = "all";
2014 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
2015 if (!m_convert (mp
, msgs
[msgnum
]))
2019 /* Get new format string */
2020 nfs
= new_fs (form
, format
, FORMAT
);
2022 /* force scansbr to (re)compile format */
2029 s_optim
= optim
= 1;
2030 s_form
= form
? getcpy (form
) : NULL
;
2031 s_format
= format
? getcpy (format
) : NULL
;
2035 optim
= equiv (s_form
, form
) && equiv (s_format
, format
);
2038 for (msgnum
= mp
->lowsel
;
2039 msgnum
<= mp
->hghsel
&& !interrupted
;
2041 if (is_selected (mp
, msgnum
)) {
2042 if (optim
&& Msgs
[msgnum
].m_scanl
)
2043 printf ("%s", Msgs
[msgnum
].m_scanl
);
2046 zp
= msh_ready (msgnum
, 0);
2047 switch (state
= scan (zp
, msgnum
, 0, nfs
, width
,
2048 msgnum
== mp
->curmsg
,
2049 is_unseen (mp
, msgnum
),
2050 headersw
? (fmsh
? fmsh
: mp
->foldpath
) : NULL
,
2051 fmsh
? 0L : (long) (Msgs
[msgnum
].m_stop
- Msgs
[msgnum
].m_start
),
2057 Msgs
[msgnum
].m_scanl
= getcpy (scanl
);
2061 advise (NULL
, "scan() botch (%d)", state
);
2065 printf ("%*d empty\n", DMAXFOLDER
, msgnum
);
2077 #define SHOW_SWITCHES \
2078 X("draft", 5, SHDRAFT) \
2079 X("form formfile", 4, SHFORM) \
2080 X("moreproc program", 4, SHPROG) \
2081 X("nomoreproc", 3, SHNPROG) \
2082 X("length lines", 4, SHLEN) \
2083 X("width columns", 4, SHWID) \
2084 X("showproc program", 4, SHSHOW) \
2085 X("noshowproc", 3, SHNSHOW) \
2086 X("header", 4, SHHEAD) \
2087 X("noheader", 3, SHNHEAD) \
2088 X("help", 0, SHHELP) \
2090 #define X(sw, minchars, id) id,
2091 DEFINE_SWITCH_ENUM(SHOW
);
2094 #define X(sw, minchars, id) { sw, minchars, id },
2095 DEFINE_SWITCH_ARRAY(SHOW
, showswit
);
2100 showcmd (char **args
)
2102 int headersw
= 1, nshow
= 0, msgp
= 0, vecp
= 1;
2103 int mhl
= 0, seqnum
= -1, mode
= 0, i
, msgnum
;
2104 char *cp
, *proc
= showproc
, buf
[BUFSIZ
];
2105 char *msgs
[MAXARGS
], *vec
[MAXARGS
];
2107 if (!strcasecmp (cmd_name
, "next"))
2110 if (!strcasecmp (cmd_name
, "prev"))
2112 while ((cp
= *args
++)) {
2114 switch (i
= smatch (++cp
, showswit
)) {
2116 ambigsw (cp
, showswit
);
2123 snprintf (buf
, sizeof(buf
), "%s %s[switches] [switches for showproc]",
2124 cmd_name
, mode
? NULL
: "[msgs] ");
2125 print_help (buf
, showswit
, 1);
2133 if (!(cp
= *args
++) || *cp
== '-') {
2134 advise (NULL
, "missing argument to %s", args
[-2]);
2146 if (!(proc
= *args
++) || *proc
== '-') {
2147 advise (NULL
, "missing argument to %s", args
[-2]);
2157 advise (NULL
, "sorry, -%s not allowed!", showswit
[i
].sw
);
2160 if (*cp
== '+' || *cp
== '@') {
2161 advise (NULL
, "sorry, no folders allowed!");
2167 "usage: %s [switches] [switches for showproc]\n",
2177 msgs
[msgp
++] = mode
> 0 ? "next" : mode
< 0 ? "prev" : "cur";
2178 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
2179 if (!m_convert (mp
, msgs
[msgnum
]))
2184 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
2185 if (is_selected (mp
, msgnum
) && is_nontext (msgnum
)) {
2186 proc
= showmimeproc
;
2187 vec
[vecp
++] = "-file";
2195 if (strcmp (showproc
, "mhl") == 0) {
2201 seqnum
= seq_getnum (mp
, "unseen");
2202 vec
[0] = r1bindex (proc
, '/');
2205 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
2206 if (is_selected (mp
, msgnum
)) {
2207 vec
[vecp
++] = getcpy (m_name (msgnum
));
2209 seq_delmsg (mp
, "unseen", msgnum
);
2212 if (mp
->numsel
== 1 && headersw
)
2214 mhlsbr (vecp
, vec
, mhl_action
);
2215 scan_eom_action ((int (*)()) 0);
2220 for (msgnum
= mp
->lowsel
;
2221 msgnum
<= mp
->hghsel
&& !interrupted
;
2223 if (is_selected (mp
, msgnum
)) {
2224 switch (ask (msgnum
)) {
2225 case NOTOK
: /* QUIT */
2232 if (mp
->numsel
== 1 && headersw
)
2235 copy_message (msgnum
, stdout
);
2237 process (msgnum
, proc
, vecp
, vec
);
2240 seq_delmsg (mp
, "unseen", msgnum
);
2247 seq_setcur (mp
, mp
->hghsel
);
2254 if (Msgs
[msgnum
].m_bboard_id
== 0)
2257 printf ("(Message %d", msgnum
);
2258 if (Msgs
[msgnum
].m_bboard_id
> 0)
2259 printf (", %s: %d", BBoard_ID
, Msgs
[msgnum
].m_bboard_id
);
2270 return (ftell (mhlfp
) >= Msgs
[mhlnum
].m_stop
);
2275 mhl_action (char *name
)
2279 if ((msgnum
= m_atoi (name
)) < mp
->lowmsg
2280 || msgnum
> mp
->hghmsg
2281 || !does_exist (mp
, msgnum
))
2285 mhlfp
= msh_ready (msgnum
, 1);
2287 scan_eom_action (eom_action
);
2299 if (mp
->numsel
== 1 || !interactive
|| redirected
)
2302 if (SOprintf ("Press <return> to list \"%d\"...", msgnum
)) {
2303 if (mp
->lowsel
!= msgnum
)
2305 printf ("Press <return> to list \"%d\"...", msgnum
);
2310 read (fileno (stdout
), buf
, sizeof buf
);
2312 if (strchr(buf
, '\n') == NULL
)
2316 told_to_quit
= interrupted
= 0;
2331 is_nontext (int msgnum
)
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 int bufsz
= sizeof buf
;
2346 switch (state
= m_getfld (&gstate
, name
, buf
, &bufsz
, fp
)) {
2350 * Check Content-Type field
2352 if (!strcasecmp (name
, TYPE_FIELD
)) {
2356 cp
= add (buf
, NULL
);
2357 while (state
== FLDPLUS
) {
2359 state
= m_getfld (&gstate
, name
, buf
, &bufsz
, fp
);
2366 for (; isspace ((unsigned char) *bp
); bp
++)
2371 for (bp
++, i
= 0;;) {
2401 for (dp
= bp
; istoken (*dp
); dp
++)
2408 if ((result
= (strcasecmp (bp
, "plain") != 0)))
2411 for (dp
++; isspace ((unsigned char) *dp
); dp
++)
2414 if ((result
= !uprf (dp
, "charset")))
2416 dp
+= sizeof "charset" - 1;
2417 while (isspace ((unsigned char) *dp
))
2421 while (isspace ((unsigned char) *dp
))
2424 if ((bp
= strchr(++dp
, '"')))
2427 for (bp
= dp
; *bp
; bp
++)
2428 if (isspace ((unsigned char) *bp
)) {
2434 /* Default character set */
2437 /* Check the character set */
2438 result
= !check_charset (dp
, strlen (dp
));
2440 if (!(result
= (strcasecmp (bp
, "text") != 0))) {
2450 Msgs
[msgnum
].m_flags
|= MHNYES
;
2457 * Check Content-Transfer-Encoding field
2459 if (!strcasecmp (name
, ENCODING_FIELD
)) {
2460 cp
= add (buf
, NULL
);
2461 while (state
== FLDPLUS
) {
2463 state
= m_getfld (&gstate
, name
, buf
, &bufsz
, fp
);
2466 for (bp
= cp
; isspace ((unsigned char) *bp
); bp
++)
2468 for (dp
= bp
; istoken (*dp
); dp
++)
2471 result
= (strcasecmp (bp
, "7bit")
2472 && strcasecmp (bp
, "8bit")
2473 && strcasecmp (bp
, "binary"));
2477 Msgs
[msgnum
].m_flags
|= MHNYES
;
2484 * Just skip the rest of this header
2485 * field and go to next one.
2487 while (state
== FLDPLUS
) {
2489 state
= m_getfld (&gstate
, name
, buf
, &bufsz
, fp
);
2494 * We've passed the message header,
2495 * so message is just text.
2504 #define SORT_SWITCHES \
2505 X("datefield field", 0, SODATE) \
2506 X("textfield field", 0, SOSUBJ) \
2507 X("notextfield", 0, SONSUBJ) \
2508 X("limit days", 0, SOLIMT) \
2509 X("nolimit", 0, SONLIMT) \
2510 X("verbose", 0, SOVERB) \
2511 X("noverbose", 0, SONVERB) \
2512 X("help", 0, SOHELP) \
2514 #define X(sw, minchars, id) id,
2515 DEFINE_SWITCH_ENUM(SORT
);
2518 #define X(sw, minchars, id) { sw, minchars, id },
2519 DEFINE_SWITCH_ARRAY(SORT
, sortswit
);
2524 sortcmd (char **args
)
2526 int msgp
= 0, msgnum
;
2527 char *cp
, *datesw
= NULL
, *subjsw
= NULL
;
2528 char buf
[BUFSIZ
], *msgs
[MAXARGS
];
2532 forkcmd (args
, cmd_name
);
2536 while ((cp
= *args
++)) {
2538 switch (smatch (++cp
, sortswit
)) {
2540 ambigsw (cp
, sortswit
);
2543 fprintf (stderr
, "-%s unknown\n", cp
);
2546 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
2547 print_help (buf
, sortswit
, 1);
2552 advise (NULL
, "only one date field at a time!");
2555 if (!(datesw
= *args
++) || *datesw
== '-') {
2556 advise (NULL
, "missing argument to %s", args
[-2]);
2563 advise (NULL
, "only one text field at a time!");
2566 if (!(subjsw
= *args
++) || *subjsw
== '-') {
2567 advise (NULL
, "missing argument to %s", args
[-2]);
2575 case SOLIMT
: /* too hard */
2576 if (!(cp
= *args
++) || *cp
== '-') {
2577 advise (NULL
, "missing argument to %s", args
[-2]);
2581 case SOVERB
: /* not implemented */
2585 if (*cp
== '+' || *cp
== '@') {
2586 advise (NULL
, "sorry, no folders allowed!");
2594 msgs
[msgp
++] = "all";
2597 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
2598 if (!m_convert (mp
, msgs
[msgnum
]))
2602 twscopy (&tb
, dlocaltimenow ());
2604 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++) {
2605 if (Msgs
[msgnum
].m_scanl
) {
2606 free (Msgs
[msgnum
].m_scanl
);
2607 Msgs
[msgnum
].m_scanl
= NULL
;
2609 if (is_selected (mp
, msgnum
)) {
2610 if (get_fields (datesw
, subjsw
, msgnum
, &Msgs
[msgnum
]))
2611 twscopy (&Msgs
[msgnum
].m_tb
,
2612 msgnum
!= mp
->lowsel
? &Msgs
[msgnum
- 1].m_tb
: &tb
);
2614 else /* m_scaln is already NULL */
2615 twscopy (&Msgs
[msgnum
].m_tb
, &tb
);
2616 Msgs
[msgnum
].m_stats
= bvector_create (0);
2617 bvector_copy (Msgs
[msgnum
].m_stats
, msgstat (mp
, msgnum
));
2618 if (mp
->curmsg
== msgnum
)
2619 bvector_set (Msgs
[msgnum
].m_stats
, CUR
);
2622 qsort ((char *) &Msgs
[mp
->lowsel
], mp
->hghsel
- mp
->lowsel
+ 1,
2623 sizeof(struct Msg
), (qsort_comp
) (subjsw
? subsort
: msgsort
));
2625 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++) {
2626 if (subjsw
&& Msgs
[msgnum
].m_scanl
) {
2627 free (Msgs
[msgnum
].m_scanl
); /* from subjsort */
2628 Msgs
[msgnum
].m_scanl
= NULL
;
2630 bvector_clear (Msgs
[msgnum
].m_stats
, CUR
);
2631 bvector_copy (msgstat (mp
, msgnum
), Msgs
[msgnum
].m_stats
);
2632 if (bvector_at (Msgs
[msgnum
].m_stats
, CUR
))
2633 seq_setcur (mp
, msgnum
);
2636 mp
->msgflags
|= MODIFIED
;
2642 * get_fields - parse message, and get date and subject if needed.
2643 * We'll use the msgp->m_tb tws struct for the date, and overload
2644 * the msgp->m_scanl field with our subject string.
2647 get_fields (char *datesw
, char *subjsw
, int msgnum
, struct Msg
*msgp
)
2649 int state
, gotdate
= 0;
2650 char *bp
, buf
[BUFSIZ
], name
[NAMESZ
];
2651 struct tws
*tw
= (struct tws
*) 0;
2654 zp
= msh_ready (msgnum
, 0);
2657 int bufsz
= sizeof buf
;
2658 switch (state
= m_getfld (&gstate
, name
, buf
, &bufsz
, zp
)) {
2661 if (!strcasecmp (name
, datesw
)) {
2663 while (state
== FLDPLUS
) {
2665 state
= m_getfld (&gstate
, name
, buf
, &bufsz
, zp
);
2668 if ((tw
= dparsetime (bp
)) == NULL
)
2670 "unable to parse %s field in message %d",
2673 twscopy (&(msgp
->m_tb
), tw
);
2675 if (!subjsw
) /* not using this, or already done */
2676 break; /* all done! */
2679 else if (subjsw
&& !strcasecmp(name
, subjsw
)) {
2681 while (state
== FLDPLUS
) {
2683 state
= m_getfld (&gstate
, name
, buf
, &bufsz
, zp
);
2686 msgp
->m_scanl
= sosmash(subjsw
, bp
);
2688 break; /* date done so we're done */
2690 subjsw
= (char *)0;/* subject done, need date */
2692 while (state
== FLDPLUS
) { /* flush this one */
2694 state
= m_getfld (&gstate
, name
, buf
, &bufsz
, zp
);
2705 admonish (NULL
, "format error in message %d", msgnum
);
2706 if (msgp
->m_scanl
) { /* this might need free'd */
2707 free (msgp
->m_scanl
); /* probably can't use subj anyway */
2708 msgp
->m_scanl
= NULL
;
2713 adios (NULL
, "internal error -- you lose");
2718 return OK
; /* not an error if subj not found */
2720 admonish (NULL
, "no %s field in message %d", datesw
, msgnum
);
2721 return NOTOK
; /* NOTOK means use some other date */
2730 msgsort (struct Msg
*a
, struct Msg
*b
)
2732 return twsort (&a
->m_tb
, &b
->m_tb
);
2737 subsort (struct Msg
*a
, struct Msg
*b
)
2741 if (a
->m_scanl
&& b
->m_scanl
)
2742 if ((i
= strcmp (a
->m_scanl
, b
->m_scanl
)))
2745 return twsort (&a
->m_tb
, &b
->m_tb
);
2750 * try to make the subject "canonical": delete leading "re:", everything
2751 * but letters & smash letters to lower case.
2754 sosmash (char *subj
, char *s
)
2756 register char *cp
, *dp
;
2757 register unsigned char c
;
2761 dp
= s
; /* dst pointer */
2762 if (!strcasecmp (subj
, "subject"))
2769 *dp
++ = isupper(c
) ? tolower(c
) : c
;
2775 while ((c
= *cp
++)) {
2777 *dp
++ = isupper(c
) ? tolower(c
) : c
;
2787 process (int msgnum
, char *proc
, int vecp
, char **vec
)
2789 int child_id
, status
;
2790 char tmpfil
[BUFSIZ
];
2795 strncpy (tmpfil
, m_name (msgnum
), sizeof(tmpfil
));
2796 context_del (pfolder
);
2797 context_replace (pfolder
, fmsh
);/* update current folder */
2799 context_save (); /* save the context file */
2803 cp
= m_mktemp(invo_name
, NULL
, &out
);
2805 /* Try again, but try to create under /tmp */
2807 cp
= m_mktemp2(NULL
, invo_name
, NULL
, &out
);
2810 advise (NULL
, "unable to create temporary file");
2814 copy_message (msgnum
, out
);
2816 strncpy(tmpfil
, cp
, sizeof(tmpfil
));
2820 switch (child_id
= fork ()) {
2822 advise ("fork", "unable to");
2828 SIGNAL (SIGINT
, istat
);
2829 SIGNAL (SIGQUIT
, qstat
);
2831 vec
[vecp
++] = tmpfil
;
2835 fprintf (stderr
, "unable to exec ");
2840 status
= pidXwait (child_id
, NULL
);
2851 copy_message (int msgnum
, FILE *out
)
2854 static char buffer
[BUFSIZ
];
2857 zp
= msh_ready (msgnum
, 1);
2859 while (fgets (buffer
, sizeof buffer
, zp
) != NULL
) {
2860 fputs (buffer
, out
);
2861 if (interrupted
&& out
== stdout
)
2867 while (fgets (buffer
, sizeof buffer
, zp
) != NULL
2868 && pos
< Msgs
[msgnum
].m_stop
) {
2869 fputs (buffer
, out
);
2870 pos
+= (long) strlen (buffer
);
2871 if (interrupted
&& out
== stdout
)
2879 copy_digest (int msgnum
, FILE *out
)
2883 static char buffer
[BUFSIZ
];
2887 zp
= msh_ready (msgnum
, 1);
2890 while (fgets (buffer
, sizeof buffer
, zp
) != NULL
2891 && !fmsh
&& pos
< Msgs
[msgnum
].m_stop
) {
2892 if (c
== '\n' && *buffer
== '-')
2894 fputs (buffer
, out
);
2895 c
= buffer
[strlen (buffer
) - 1];
2897 pos
+= (long) strlen (buffer
);
2898 if (interrupted
&& out
== stdout
)