]>
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 *);
54 extern m_getfld_state_t gstate
; /* use the gstate in scansbr.c */
57 forkcmd (char **args
, char *pgm
)
62 vec
[0] = r1bindex (pgm
, '/');
63 copyip (args
, vec
+ 1, MAXARGS
- 1);
66 context_del (pfolder
);
67 context_replace (pfolder
, fmsh
);/* update current folder */
69 context_save (); /* save the context file */
72 switch (child_id
= fork ()) {
74 advise ("fork", "unable to");
79 SIGNAL (SIGINT
, istat
);
80 SIGNAL (SIGQUIT
, qstat
);
83 fprintf (stderr
, "unable to exec ");
88 pidXwait (child_id
, NULL
);
91 if (fmsh
) { /* assume the worst case */
92 mp
->msgflags
|= MODIFIED
;
98 #define DIST_SWITCHES \
99 X("annotate", 0, DIANSW) \
100 X("noannotate", 0, DINANSW) \
101 X("draftfolder +folder", 0, DIDFSW) \
102 X("draftmessage msg", 0, DIDMSW) \
103 X("nodraftfolder", 0, DINDFSW) \
104 X("editor editor", 0, DIEDTSW) \
105 X("noedit", 0, DINEDSW) \
106 X("form formfile", 0, DIFRMSW) \
107 X("inplace", 0, DIINSW) \
108 X("noinplace", 0, DININSW) \
109 X("whatnowproc program", 0, DIWHTSW) \
110 X("nowhatnowproc", 0, DINWTSW) \
111 X("help", 0, DIHELP) \
113 #define X(sw, minchars, id) id,
114 DEFINE_SWITCH_ENUM(DIST
);
117 #define X(sw, minchars, id) { sw, minchars, id },
118 DEFINE_SWITCH_ARRAY(DIST
, distswit
);
123 distcmd (char **args
)
126 char *cp
, *msg
= NULL
;
127 char buf
[BUFSIZ
], *vec
[MAXARGS
];
130 forkcmd (args
, cmd_name
);
134 while ((cp
= *args
++)) {
136 switch (smatch (++cp
, distswit
)) {
138 ambigsw (cp
, distswit
);
141 fprintf (stderr
, "-%s unknown\n", cp
);
144 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
145 print_help (buf
, distswit
, 1);
148 case DIANSW
: /* not implemented */
166 if (!(cp
= *args
++) || *cp
== '-') {
167 advise (NULL
, "missing argument to %s", args
[-2]);
173 if (*cp
== '+' || *cp
== '@') {
174 advise (NULL
, "sorry, no folders allowed!");
179 advise (NULL
, "only one message at a time!");
187 vec
[vecp
++] = "-file";
191 if (!m_convert (mp
, msg
))
195 if (mp
->numsel
> 1) {
196 advise (NULL
, "only one message at a time!");
199 process (mp
->hghsel
, cmd_name
, vecp
, vec
);
200 seq_setcur (mp
, mp
->hghsel
);
204 #define EXPLODE_SWITCHES \
205 X("inplace", 0, EXINSW) \
206 X("noinplace", 0, EXNINSW) \
207 X("quiet", 0, EXQISW) \
208 X("noquiet", 0, EXNQISW) \
209 X("verbose", 0, EXVBSW) \
210 X("noverbose", 0, EXNVBSW) \
211 X("help", 0, EXHELP) \
213 #define X(sw, minchars, id) id,
214 DEFINE_SWITCH_ENUM(EXPLODE
);
217 #define X(sw, minchars, id) { sw, minchars, id },
218 DEFINE_SWITCH_ARRAY(EXPLODE
, explswit
);
223 explcmd (char **args
)
225 int inplace
= 0, quietsw
= 0, verbosw
= 0;
226 int msgp
= 0, hi
, msgnum
;
227 char *cp
, buf
[BUFSIZ
], *msgs
[MAXARGS
];
231 forkcmd (args
, cmd_name
);
235 while ((cp
= *args
++)) {
237 switch (smatch (++cp
, explswit
)) {
239 ambigsw (cp
, explswit
);
242 fprintf (stderr
, "-%s unknown\n", cp
);
245 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
246 print_help (buf
, explswit
, 1);
268 if (*cp
== '+' || *cp
== '@') {
269 advise (NULL
, "sorry, no folders allowed!");
277 msgs
[msgp
++] = "cur";
278 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
279 if (!m_convert (mp
, msgs
[msgnum
]))
283 smsgs
= (struct Msg
*)
284 calloc ((size_t) (MAXFOLDER
+ 2), sizeof *smsgs
);
286 adios (NULL
, "unable to allocate folder storage");
290 for (msgnum
= mp
->lowsel
;
291 msgnum
<= mp
->hghsel
&& !interrupted
;
293 if (is_selected (mp
, msgnum
))
294 if (burst (smsgs
, msgnum
, inplace
, quietsw
, verbosw
) != OK
)
297 free ((char *) smsgs
);
300 seq_setcur (mp
, mp
->lowsel
);
302 if (hi
<= mp
->hghmsg
)
305 mp
->msgflags
|= MODIFIED
;
311 burst (struct Msg
*smsgs
, int msgnum
, int inplace
, int quietsw
, int verbosw
)
313 int i
, j
, ld3
, wasdlm
, msgp
;
315 char c
, buffer
[BUFSIZ
];
318 ld3
= strlen (delim3
);
320 if (Msgs
[msgnum
].m_scanl
) {
321 free (Msgs
[msgnum
].m_scanl
);
322 Msgs
[msgnum
].m_scanl
= NULL
;
325 pos
= ftell (zp
= msh_ready (msgnum
, 1));
326 for (msgp
= 0; msgp
<= MAXFOLDER
;) {
327 while (fgets (buffer
, sizeof buffer
, zp
) != NULL
329 && pos
< Msgs
[msgnum
].m_stop
)
330 pos
+= (long) strlen (buffer
);
331 if (feof (zp
) || pos
>= Msgs
[msgnum
].m_stop
)
333 fseek (zp
, pos
, SEEK_SET
);
334 smsgs
[msgp
].m_start
= pos
;
337 pos
< Msgs
[msgnum
].m_stop
338 && fgets (buffer
, sizeof buffer
, zp
) != NULL
;
340 if (strncmp (buffer
, delim3
, ld3
) == 0
341 && (msgp
== 1 || c
== '\n')
342 && peekc (zp
) == '\n')
345 pos
+= (long) strlen (buffer
);
347 wasdlm
= strncmp (buffer
, delim3
, ld3
) == 0;
348 if (smsgs
[msgp
].m_start
!= pos
)
349 smsgs
[msgp
++].m_stop
= (c
== '\n' && wasdlm
) ? pos
- 1 : pos
;
350 if (feof (zp
) || pos
>= Msgs
[msgnum
].m_stop
) {
352 smsgs
[msgp
- 1].m_stop
-= ((long) strlen (buffer
) + 1);
355 pos
+= (long) strlen (buffer
);
358 switch (msgp
--) { /* toss "End of XXX Digest" */
360 adios (NULL
, "burst() botch -- you lose big");
364 printf ("message %d not in digest format\n", msgnum
);
369 printf ("%d message%s exploded from digest %d\n",
370 msgp
, msgp
!= 1 ? "s" : "", msgnum
);
374 if ((i
= msgp
+ mp
->hghmsg
) > MAXFOLDER
) {
375 advise (NULL
, "more than %d messages", MAXFOLDER
);
378 if (!(mp
= folder_realloc (mp
, mp
->lowoff
, i
)))
379 adios (NULL
, "unable to allocate folder storage");
384 if (mp
->hghsel
> msgnum
)
388 for (i
= mp
->hghmsg
; j
> msgnum
; i
--, j
--) {
390 printf ("message %d becomes message %d\n", j
, i
);
392 Msgs
[i
].m_bboard_id
= Msgs
[j
].m_bboard_id
;
393 Msgs
[i
].m_top
= Msgs
[j
].m_top
;
394 Msgs
[i
].m_start
= Msgs
[j
].m_start
;
395 Msgs
[i
].m_stop
= Msgs
[j
].m_stop
;
396 Msgs
[i
].m_scanl
= NULL
;
397 if (Msgs
[j
].m_scanl
) {
398 free (Msgs
[j
].m_scanl
);
399 Msgs
[j
].m_scanl
= NULL
;
401 copy_msg_flags (mp
, i
, j
);
404 if (Msgs
[msgnum
].m_bboard_id
== 0)
407 unset_selected (mp
, msgnum
);
408 i
= inplace
? msgnum
+ msgp
: mp
->hghmsg
;
409 for (j
= msgp
; j
>= (inplace
? 0 : 1); i
--, j
--) {
410 if (verbosw
&& i
!= msgnum
)
411 printf ("message %d of digest %d becomes message %d\n",
414 Msgs
[i
].m_bboard_id
= Msgs
[msgnum
].m_bboard_id
;
415 Msgs
[i
].m_top
= Msgs
[j
].m_top
;
416 Msgs
[i
].m_start
= smsgs
[j
].m_start
;
417 Msgs
[i
].m_stop
= smsgs
[j
].m_stop
;
418 Msgs
[i
].m_scanl
= NULL
;
419 copy_msg_flags (mp
, i
, msgnum
);
426 #define FILE_SWITCHES \
427 X("draft", 0, FIDRFT) \
428 X("link", 0, FILINK) \
429 X("nolink", 0, FINLINK) \
430 X("preserve", 0, FIPRES) \
431 X("nopreserve", 0, FINPRES) \
432 X("src +folder", 0, FISRC) \
433 X("file file", 0, FIFILE) \
434 X("rmmproc program", 0, FIPROC) \
435 X("normmproc", 0, FINPRC) \
436 X("help", 0, FIHELP) \
438 #define X(sw, minchars, id) id,
439 DEFINE_SWITCH_ENUM(FILE);
442 #define X(sw, minchars, id) { sw, minchars, id },
443 DEFINE_SWITCH_ARRAY(FILE, fileswit
);
448 filecmd (char **args
)
450 int linksw
= 0, msgp
= 0;
451 int vecp
= 1, i
, msgnum
;
452 char *cp
, buf
[BUFSIZ
];
453 char *msgs
[MAXARGS
], *vec
[MAXARGS
];
456 forkcmd (args
, cmd_name
);
460 while ((cp
= *args
++)) {
462 switch (i
= smatch (++cp
, fileswit
)) {
464 ambigsw (cp
, fileswit
);
467 fprintf (stderr
, "-%s unknown\n", cp
);
470 snprintf (buf
, sizeof(buf
), "%s +folder... [msgs] [switches]", cmd_name
);
471 print_help (buf
, fileswit
, 1);
490 advise (NULL
, "sorry, -%s not allowed!", fileswit
[i
].sw
);
493 if (*cp
== '+' || *cp
== '@')
500 vec
[vecp
++] = "-file";
503 msgs
[msgp
++] = "cur";
504 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
505 if (!m_convert (mp
, msgs
[msgnum
]))
510 for (msgnum
= mp
->lowsel
;
511 msgnum
<= mp
->hghsel
&& !interrupted
;
513 if (is_selected (mp
, msgnum
))
514 if (process (msgnum
, fileproc
, vecp
, vec
)) {
515 unset_selected (mp
, msgnum
);
519 if (mp
->numsel
!= mp
->nummsg
|| linksw
)
520 seq_setcur (mp
, mp
->hghsel
);
527 filehak (char **args
)
529 int result
, vecp
= 0;
530 char *cp
, *cwd
, *vec
[MAXARGS
];
532 while ((cp
= *args
++)) {
534 switch (smatch (++cp
, fileswit
)) {
551 if (*cp
== '+' || *cp
== '@')
558 for (vecp
= 0; (cp
= vec
[vecp
]) && result
== NOTOK
; vecp
++) {
560 cwd
= getcpy (pwd ());
561 chdir (m_maildir (""));
563 if (access (m_maildir (cp
), F_OK
) == NOTOK
)
574 #define FOLDER_SWITCHES \
575 X("all", 0, FLALSW) \
576 X("fast", 0, FLFASW) \
577 X("nofast", 0, FLNFASW) \
578 X("header", 0, FLHDSW) \
579 X("noheader", 0, FLNHDSW) \
580 X("pack", 0, FLPKSW) \
581 X("nopack", 0, FLNPKSW) \
582 X("recurse", 0, FLRCSW) \
583 X("norecurse", 0, FLNRCSW) \
584 X("total", 0, FLTLSW) \
585 X("nototal", 0, FLNTLSW) \
586 X("print", 0, FLPRSW) \
587 X("push", 0, FLPUSW) \
588 X("pop", 0, FLPOSW) \
589 X("list", 0, FLLISW) \
590 X("help", 0, FLHELP) \
592 #define X(sw, minchars, id) id,
593 DEFINE_SWITCH_ENUM(FOLDER
);
596 #define X(sw, minchars, id) { sw, minchars, id },
597 DEFINE_SWITCH_ARRAY(FOLDER
, foldswit
);
602 foldcmd (char **args
)
604 int fastsw
= 0, headersw
= 0, packsw
= 0;
606 char *cp
, *folder
= NULL
, *msg
= NULL
;
607 char buf
[BUFSIZ
], **vec
= args
;
612 while ((cp
= *args
++)) {
614 switch (smatch (++cp
, foldswit
)) {
616 ambigsw (cp
, foldswit
);
619 fprintf (stderr
, "-%s unknown\n", cp
);
622 snprintf (buf
, sizeof(buf
), "%s [+folder] [msg] [switches]", cmd_name
);
623 print_help (buf
, foldswit
, 1);
626 case FLALSW
: /* not implemented */
656 if (*cp
== '+' || *cp
== '@') {
658 advise (NULL
, "only one folder at a time!\n");
662 folder
= fmsh
? pluspath (cp
)
667 advise (NULL
, "only one message at a time!\n");
676 advise (NULL
, "null folder names are not permitted");
680 if (access (m_maildir (folder
), R_OK
) == NOTOK
) {
681 advise (folder
, "unable to read");
686 strncpy (buf
, folder
, sizeof(buf
));
687 if (expand (buf
) == NOTOK
)
690 if (access (folder
, R_OK
) == NOTOK
) {
691 advise (folder
, "unable to read");
706 if (!m_convert (mp
, msg
))
710 if (mp
->numsel
> 1) {
711 advise (NULL
, "only one message at a time!");
714 seq_setcur (mp
, mp
->hghsel
);
719 forkcmd (vec
, cmd_name
);
723 if (mp
->lowoff
> 1 && !(mp
= folder_realloc (mp
, 1, mp
->hghmsg
)))
724 adios (NULL
, "unable to allocate folder storage");
726 for (msgnum
= mp
->lowmsg
, hole
= 1; msgnum
<= mp
->hghmsg
; msgnum
++)
727 if (does_exist (mp
, msgnum
)) {
728 if (msgnum
!= hole
) {
729 Msgs
[hole
].m_bboard_id
= Msgs
[msgnum
].m_bboard_id
;
730 Msgs
[hole
].m_top
= Msgs
[msgnum
].m_top
;
731 Msgs
[hole
].m_start
= Msgs
[msgnum
].m_start
;
732 Msgs
[hole
].m_stop
= Msgs
[msgnum
].m_stop
;
733 Msgs
[hole
].m_scanl
= NULL
;
734 if (Msgs
[msgnum
].m_scanl
) {
735 free (Msgs
[msgnum
].m_scanl
);
736 Msgs
[msgnum
].m_scanl
= NULL
;
738 copy_msg_flags (mp
, hole
, msgnum
);
739 if (mp
->curmsg
== msgnum
)
740 seq_setcur (mp
, hole
);
744 if (mp
->nummsg
> 0) {
746 mp
->hghmsg
= hole
- 1;
748 mp
->msgflags
|= MODIFIED
;
754 printf ("%s\n", fmsh
? fmsh
: mp
->foldpath
);
757 printf ("\t\tFolder %*s# of messages (%*srange%*s); cur%*smsg\n",
758 DMAXFOLDER
, "", DMAXFOLDER
- 2, "", DMAXFOLDER
- 2, "",
760 printf (args
? "%22s " : "%s ", fmsh
? fmsh
: mp
->foldpath
);
762 /* check for empty folder */
763 if (mp
->nummsg
== 0) {
764 printf ("has no messages%*s",
765 mp
->msgflags
& OTHERS
? DMAXFOLDER
* 2 + 4 : 0, "");
767 printf ("has %*d message%s (%*d-%*d)",
768 DMAXFOLDER
, mp
->nummsg
, mp
->nummsg
!= 1 ? "s" : "",
769 DMAXFOLDER
, mp
->lowmsg
, DMAXFOLDER
, mp
->hghmsg
);
770 if (mp
->curmsg
>= mp
->lowmsg
771 && mp
->curmsg
<= mp
->hghmsg
)
772 printf ("; cur=%*d", DMAXFOLDER
, mp
->curmsg
);
779 #define FORW_SWITCHES \
780 X("annotate", 0, FOANSW) \
781 X("noannotate", 0, FONANSW) \
782 X("draftfolder +folder", 0, FODFSW) \
783 X("draftmessage msg", 0, FODMSW) \
784 X("nodraftfolder", 0, FONDFSW) \
785 X("editor editor", 0, FOEDTSW) \
786 X("noedit", 0, FONEDSW) \
787 X("filter filterfile", 0, FOFTRSW) \
788 X("form formfile", 0, FOFRMSW) \
789 X("format", 5, FOFTSW) \
790 X("noformat", 7, FONFTSW) \
791 X("inplace", 0, FOINSW) \
792 X("noinplace", 0, FONINSW) \
793 X("mime", 0, FOMISW) \
794 X("nomime", 0, FONMISW) \
795 X("whatnowproc program", 0, FOWHTSW) \
796 X("nowhatnow", 0, FONWTSW) \
797 X("help", 0, FOHELP) \
799 #define X(sw, minchars, id) id,
800 DEFINE_SWITCH_ENUM(FORW
);
803 #define X(sw, minchars, id) { sw, minchars, id },
804 DEFINE_SWITCH_ARRAY(FORW
, forwswit
);
809 forwcmd (char **args
)
811 int msgp
= 0, vecp
= 1, msgnum
;
812 char *cp
, *filter
= NULL
, buf
[BUFSIZ
];
813 char *msgs
[MAXARGS
], *vec
[MAXARGS
];
818 forkcmd (args
, cmd_name
);
822 while ((cp
= *args
++)) {
824 switch (smatch (++cp
, forwswit
)) {
826 ambigsw (cp
, forwswit
);
829 fprintf (stderr
, "-%s unknown\n", cp
);
832 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
833 print_help (buf
, forwswit
, 1);
836 case FOANSW
: /* not implemented */
856 if (!(cp
= *args
++) || *cp
== '-') {
857 advise (NULL
, "missing argument to %s", args
[-2]);
863 if (!(filter
= *args
++) || *filter
== '-') {
864 advise (NULL
, "missing argument to %s", args
[-2]);
869 if (access (filter
= myfilter
, R_OK
) == NOTOK
) {
870 advise (filter
, "unable to read default filter file");
878 if (*cp
== '+' || *cp
== '@') {
879 advise (NULL
, "sorry, no folders allowed!");
886 /* foil search of .mh_profile */
887 snprintf (buf
, sizeof(buf
), "%sXXXXXX", invo_name
);
889 tfile
= m_mktemp(buf
, NULL
, NULL
);
890 if (tfile
== NULL
) adios("forwcmd", "unable to create temporary file");
891 strncpy (tmpfil
, tfile
, sizeof(tmpfil
));
894 vec
[vecp
++] = "-file";
897 msgs
[msgp
++] = "cur";
898 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
899 if (!m_convert (mp
, msgs
[msgnum
]))
904 strncpy (buf
, filter
, sizeof(buf
));
905 if (expand (buf
) == NOTOK
)
907 if (access (filter
= getcpy (etcpath (buf
)), R_OK
) == NOTOK
) {
908 advise (filter
, "unable to read");
913 forw (cmd_name
, filter
, vecp
, vec
);
914 seq_setcur (mp
, mp
->hghsel
);
921 forw (char *proc
, char *filter
, int vecp
, char **vec
)
923 int i
, child_id
, msgnum
, msgcnt
;
924 char tmpfil
[BUFSIZ
], *args
[MAXARGS
];
928 tfile
= m_mktemp2(NULL
, invo_name
, NULL
, NULL
);
929 if (tfile
== NULL
) adios("forw", "unable to create temporary file");
930 strncpy (tmpfil
, tfile
, sizeof(tmpfil
));
934 switch (child_id
= fork ()) {
936 advise ("fork", "unable to");
939 case OK
: /* "trust me" */
940 if (freopen (tmpfil
, "w", stdout
) == NULL
) {
941 fprintf (stderr
, "unable to create ");
945 args
[0] = r1bindex (mhlproc
, '/');
947 args
[i
++] = "-forwall";
950 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
951 if (is_selected (mp
, msgnum
))
952 args
[i
++] = getcpy (m_name (msgnum
));
954 mhlsbr (i
, args
, mhl_action
);
955 scan_eom_action ((int (*) ()) 0);
960 if (pidXwait (child_id
, NULL
))
965 if ((out
= fopen (tmpfil
, "w")) == NULL
) {
966 advise (tmpfil
, "unable to create temporary file");
971 for (msgnum
= mp
->lowsel
;
972 msgnum
<= mp
->hghsel
&& !interrupted
;
974 if (is_selected (mp
, msgnum
)) {
975 fprintf (out
, "\n\n-------");
976 if (msgnum
== mp
->lowsel
)
977 fprintf (out
, " Forwarded Message%s",
978 mp
->numsel
> 1 ? "s" : "");
980 fprintf (out
, " Message %d", msgcnt
);
981 fprintf (out
, "\n\n");
982 copy_digest (msgnum
, out
);
986 fprintf (out
, "\n\n------- End of Forwarded Message%s\n",
987 mp
->numsel
> 1 ? "s" : "");
993 switch (child_id
= fork ()) {
995 advise ("fork", "unable to");
1000 SIGNAL (SIGINT
, istat
);
1001 SIGNAL (SIGQUIT
, qstat
);
1003 vec
[vecp
++] = tmpfil
;
1007 fprintf (stderr
, "unable to exec ");
1012 pidXwait (child_id
, NULL
);
1020 static char *hlpmsg
[] = {
1021 "The %s program emulates many of the commands found in the nmh",
1022 "system. Instead of operating on nmh folders, commands to %s concern",
1025 "To see the list of commands available, just type a ``?'' followed by",
1026 "the RETURN key. To find out what switches each command takes, type",
1027 "the name of the command followed by ``-help''. To leave %s, use the",
1028 "``quit'' command.",
1030 "Although a lot of nmh commands are found in %s, not all are fully",
1031 "implemented. %s will always recognize all legal switches for a",
1032 "given command though, and will let you know when you ask for an",
1033 "option that it is unable to perform.",
1035 "Running %s is fun, but using nmh from your shell is far superior.",
1036 "After you have familiarized yourself with the nmh style by using %s,",
1037 "you should try using nmh from the shell. You can still use %s for",
1038 "message files that aren't in nmh format, such as BBoard files.",
1044 helpcmd (char **args
)
1049 for (i
= 0; hlpmsg
[i
]; i
++) {
1050 printf (hlpmsg
[i
], invo_name
);
1056 #define MARK_SWITCHES \
1057 X("add", 0, MADDSW) \
1058 X("delete", 0, MDELSW) \
1059 X("list", 0, MLSTSW) \
1060 X("sequence name", 0, MSEQSW) \
1061 X("public", 0, MPUBSW) \
1062 X("nopublic", 0, MNPUBSW) \
1063 X("zero", 0, MZERSW) \
1064 X("nozero", 0, MNZERSW) \
1065 X("help", 0, MHELP) \
1066 X("debug", -5, MDBUGSW) \
1068 #define X(sw, minchars, id) id,
1069 DEFINE_SWITCH_ENUM(MARK
);
1072 #define X(sw, minchars, id) { sw, minchars, id },
1073 DEFINE_SWITCH_ARRAY(MARK
, markswit
);
1078 markcmd (char **args
)
1080 int addsw
= 0, deletesw
= 0, debugsw
= 0;
1081 int listsw
= 0, zerosw
= 0;
1083 int msgp
= 0, msgnum
;
1084 char *cp
, buf
[BUFSIZ
];
1085 char *seqs
[NUMATTRS
+ 1], *msgs
[MAXARGS
];
1087 while ((cp
= *args
++)) {
1089 switch (smatch (++cp
, markswit
)) {
1091 ambigsw (cp
, markswit
);
1094 fprintf (stderr
, "-%s unknown\n", cp
);
1097 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1098 print_help (buf
, markswit
, 1);
1103 deletesw
= listsw
= 0;
1111 addsw
= deletesw
= 0;
1115 if (!(cp
= *args
++) || *cp
== '-') {
1116 advise (NULL
, "missing argument to %s", args
[-2]);
1119 if (seqp
< NUMATTRS
)
1122 advise (NULL
, "only %d sequences allowed!", NUMATTRS
);
1127 case MPUBSW
: /* not implemented */
1143 if (*cp
== '+' || *cp
== '@') {
1144 advise (NULL
, "sorry, no folders allowed!");
1151 if (!addsw
&& !deletesw
&& !listsw
) {
1158 seqs
[seqp
++] = "unseen";
1162 msgs
[msgp
++] = "all";
1167 msgs
[msgp
++] = listsw
? "all" :"cur";
1168 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
1169 if (!m_convert (mp
, msgs
[msgnum
]))
1173 printf ("invo_name=%s mypath=%s defpath=%s\n",
1174 invo_name
, mypath
, defpath
);
1175 printf ("ctxpath=%s context flags=%s\n",
1176 ctxpath
, snprintb (buf
, sizeof(buf
), (unsigned) ctxflags
, DBITS
));
1177 printf ("foldpath=%s flags=%s\n",
1179 snprintb (buf
, sizeof(buf
), (unsigned) mp
->msgflags
, FBITS
));
1180 printf ("hghmsg=%d lowmsg=%d nummsg=%d curmsg=%d\n",
1181 mp
->hghmsg
, mp
->lowmsg
, mp
->nummsg
, mp
->curmsg
);
1182 printf ("lowsel=%d hghsel=%d numsel=%d\n",
1183 mp
->lowsel
, mp
->hghsel
, mp
->numsel
);
1184 printf ("lowoff=%d hghoff=%d\n", mp
->lowoff
, mp
->hghoff
);
1187 if (seqp
== 0 && (addsw
|| deletesw
)) {
1188 advise (NULL
, "-%s requires at least one -sequence argument",
1189 addsw
? "add" : "delete");
1195 for (seqp
= 0; seqs
[seqp
]; seqp
++)
1196 if (!seq_addsel (mp
, seqs
[seqp
], 0, zerosw
))
1201 for (seqp
= 0; seqs
[seqp
]; seqp
++)
1202 if (!seq_delsel (mp
, seqs
[seqp
], 0, zerosw
))
1206 /* Listing messages in sequences */
1209 /* list the given sequences */
1210 for (seqp
= 0; seqs
[seqp
]; seqp
++)
1211 seq_print (mp
, seqs
[seqp
]);
1213 /* else list them all */
1219 for (msgnum
= mp
->lowsel
;
1220 msgnum
<= mp
->hghsel
&& !interrupted
;
1222 if (is_selected (mp
, msgnum
)) {
1223 printf ("%*d: id=%d top=%d start=%ld stop=%ld %s\n",
1226 Msgs
[msgnum
].m_bboard_id
,
1228 (long) Msgs
[msgnum
].m_start
,
1229 (long) Msgs
[msgnum
].m_stop
,
1230 snprintb (buf
, sizeof(buf
),
1231 (unsigned) mp
->msgstats
[msgnum
- mp
->lowoff
],
1233 if (Msgs
[msgnum
].m_scanl
)
1234 printf ("%s", Msgs
[msgnum
].m_scanl
);
1240 #define MHN_SWITCHES \
1241 X("auto", 0, MHNAUTOSW) \
1242 X("noauto", 0, MHNNAUTOSW) \
1243 X("debug", -5, MHNDEBUGSW) \
1244 X("form formfile", 4, MHNFORMSW) \
1245 X("headers", 0, MHNHEADSW) \
1246 X("noheaders", 0, MHNNHEADSW) \
1247 X("list", 0, MHNLISTSW) \
1248 X("nolist", 0, MHNNLISTSW) \
1249 X("part number", 0, MHNPARTSW) \
1250 X("realsize", 0, MHNSIZESW) \
1251 X("norealsize", 0, MHNNSIZESW) \
1252 X("rfc934mode", 0, MHNRFC934SW) \
1253 X("norfc934mode", 0, MHNNRFC934SW) \
1254 X("serialonly", 0, MHNSERIALSW) \
1255 X("noserialonly", 0, MHNNSERIALSW) \
1256 X("show", 0, MHNSHOWSW) \
1257 X("noshow", 0, MHNNSHOWSW) \
1258 X("store", 0, MHNSTORESW) \
1259 X("nostore", 0, MHNNSTORESW) \
1260 X("type content", 0, MHNTYPESW) \
1261 X("verbose", 0, MHNVERBSW) \
1262 X("noverbose", 0, MHNNVERBSW) \
1263 X("help", 0, MHNHELPSW) \
1264 X("moreproc program", -4, MHNPROGSW) \
1265 X("nomoreproc", -3, MHNNPROGSW) \
1266 X("length lines", -4, MHNLENSW) \
1267 X("width columns", -4, MHNWIDSW) \
1269 #define X(sw, minchars, id) id,
1270 DEFINE_SWITCH_ENUM(MHN
);
1273 #define X(sw, minchars, id) { sw, minchars, id },
1274 DEFINE_SWITCH_ARRAY(MHN
, mhnswit
);
1279 mhncmd (char **args
)
1281 int msgp
= 0, vecp
= 1;
1283 char *cp
, buf
[BUFSIZ
];
1284 char *msgs
[MAXARGS
], *vec
[MAXARGS
];
1287 forkcmd (args
, cmd_name
);
1290 while ((cp
= *args
++)) {
1292 switch (smatch (++cp
, mhnswit
)) {
1294 ambigsw (cp
, mhnswit
);
1297 fprintf (stderr
, "-%s unknown\n", cp
);
1300 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1301 print_help (buf
, mhnswit
, 1);
1334 if (!(cp
= *args
++) || *cp
== '-') {
1335 advise (NULL
, "missing argument to %s", args
[-2]);
1342 if (*cp
== '+' || *cp
== '@') {
1343 advise (NULL
, "sorry, no folders allowed!");
1351 vec
[vecp
++] = "-file";
1354 msgs
[msgp
++] = "cur";
1355 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
1356 if (!m_convert (mp
, msgs
[msgnum
]))
1361 for (msgnum
= mp
->lowsel
;
1362 msgnum
<= mp
->hghsel
&& !interrupted
;
1364 if (is_selected (mp
, msgnum
))
1365 if (process (msgnum
, cmd_name
, vecp
, vec
)) {
1366 unset_selected (mp
, msgnum
);
1370 seq_setcur (mp
, mp
->hghsel
);
1374 #define PACK_SWITCHES \
1375 X("file name", 0, PAFISW) \
1376 X("help", 0, PAHELP) \
1378 #define X(sw, minchars, id) id,
1379 DEFINE_SWITCH_ENUM(PACK
);
1382 #define X(sw, minchars, id) { sw, minchars, id },
1383 DEFINE_SWITCH_ARRAY(PACK
, packswit
);
1386 static int mbx_style
= MMDF_FORMAT
;
1389 packcmd (char **args
)
1391 int msgp
= 0, md
, msgnum
;
1392 char *cp
, *file
= NULL
;
1393 char buf
[BUFSIZ
], *msgs
[MAXARGS
];
1397 forkcmd (args
, cmd_name
);
1401 while ((cp
= *args
++)) {
1403 switch (smatch (++cp
, packswit
)) {
1405 ambigsw (cp
, packswit
);
1408 fprintf (stderr
, "-%s unknown\n", cp
);
1411 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1412 print_help (buf
, packswit
, 1);
1416 if (!(file
= *args
++) || *file
== '-') {
1417 advise (NULL
, "missing argument to %s", args
[-2]);
1422 if (*cp
== '+' || *cp
== '@') {
1423 advise (NULL
, "sorry, no folders allowed!");
1432 file
= path (file
, TFILE
);
1433 if (stat (file
, &st
) == NOTOK
) {
1434 if (errno
!= ENOENT
) {
1435 advise (file
, "error on file");
1438 md
= getanswer (cp
= concat ("Create file \"", file
, "\"? ", NULL
));
1445 msgs
[msgp
++] = "all";
1446 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
1447 if (!m_convert (mp
, msgs
[msgnum
]))
1451 if ((md
= mbx_open (file
, mbx_style
, getuid (), getgid (), m_gmprot ())) == NOTOK
) {
1452 advise (file
, "unable to open");
1455 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
1456 if (is_selected (mp
, msgnum
))
1457 if (pack (file
, md
, msgnum
) == NOTOK
)
1459 mbx_close (file
, md
);
1461 if (mp
->hghsel
!= mp
->curmsg
)
1462 seq_setcur (mp
, mp
->lowsel
);
1470 pack (char *mailbox
, int md
, int msgnum
)
1474 if (Msgs
[msgnum
].m_bboard_id
== 0)
1477 zp
= msh_ready (msgnum
, 1);
1478 return mbx_write (mailbox
, md
, zp
, Msgs
[msgnum
].m_bboard_id
,
1479 0L, ftell (zp
), Msgs
[msgnum
].m_stop
, 1, 1);
1484 packhak (char **args
)
1487 char *cp
, *file
= NULL
;
1489 while ((cp
= *args
++)) {
1491 switch (smatch (++cp
, packswit
)) {
1498 if (!(file
= *args
++) || *file
== '-')
1502 if (*cp
== '+' || *cp
== '@')
1506 file
= path (file
? file
: "./msgbox", TFILE
);
1507 result
= access (file
, F_OK
) == NOTOK
? OK
: NOTOK
;
1514 #define PICK_SWITCHES \
1515 X("and", 0, PIANSW) \
1516 X("or", 0, PIORSW) \
1517 X("not", 0, PINTSW) \
1518 X("lbrace", 0, PILBSW) \
1519 X("rbrace", 0, PIRBSW) \
1520 X("cc pattern", 0, PICCSW) \
1521 X("date pattern", 0, PIDASW) \
1522 X("from pattern", 0, PIFRSW) \
1523 X("search pattern", 0, PISESW) \
1524 X("subject pattern", 0, PISUSW) \
1525 X("to pattern", 0, PITOSW) \
1526 X("-othercomponent pattern", 15, PIOTSW) \
1527 X("after date", 0, PIAFSW) \
1528 X("before date", 0, PIBFSW) \
1529 X("datefield field", 5, PIDFSW) \
1530 X("sequence name", 0, PISQSW) \
1531 X("public", 0, PIPUSW) \
1532 X("nopublic", 0, PINPUSW) \
1533 X("zero", 0, PIZRSW) \
1534 X("nozero", 0, PINZRSW) \
1535 X("list", 0, PILISW) \
1536 X("nolist", 0, PINLISW) \
1537 X("help", 0, PIHELP) \
1539 #define X(sw, minchars, id) id,
1540 DEFINE_SWITCH_ENUM(PICK
);
1543 #define X(sw, minchars, id) { sw, minchars, id },
1544 DEFINE_SWITCH_ARRAY(PICK
, pickswit
);
1549 pickcmd (char **args
)
1551 int zerosw
= 1, msgp
= 0;
1553 int vecp
= 0, hi
, lo
, msgnum
;
1554 char *cp
, buf
[BUFSIZ
], *msgs
[MAXARGS
];
1555 char *seqs
[NUMATTRS
], *vec
[MAXARGS
];
1558 while ((cp
= *args
++)) {
1564 switch (smatch (cp
, pickswit
)) {
1566 ambigsw (cp
, pickswit
);
1569 fprintf (stderr
, "-%s unknown\n", cp
);
1572 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1573 print_help (buf
, pickswit
, 1);
1587 if (!(cp
= *args
++)) {/* allow -xyz arguments */
1588 advise (NULL
, "missing argument to %s", args
[-2]);
1594 advise (NULL
, "internal error!");
1605 if (!(cp
= *args
++) || *cp
== '-') {
1606 advise (NULL
, "missing argument to %s", args
[-2]);
1609 if (seqp
< NUMATTRS
)
1612 advise (NULL
, "only %d sequences allowed!", NUMATTRS
);
1623 case PIPUSW
: /* not implemented */
1630 if (*cp
== '+' || *cp
== '@') {
1631 advise (NULL
, "sorry, no folders allowed!");
1640 msgs
[msgp
++] = "all";
1641 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
1642 if (!m_convert (mp
, msgs
[msgnum
]))
1647 if (!pcompile (vec
, NULL
))
1653 for (msgnum
= mp
->lowsel
;
1654 msgnum
<= mp
->hghsel
&& !interrupted
;
1656 if (is_selected (mp
, msgnum
)) {
1657 zp
= msh_ready (msgnum
, 1);
1658 if (pmatches (zp
, msgnum
, fmsh
? 0L : Msgs
[msgnum
].m_start
,
1659 fmsh
? 0L : Msgs
[msgnum
].m_stop
)) {
1666 unset_selected (mp
, msgnum
);
1677 if (mp
->numsel
<= 0) {
1678 advise (NULL
, "no messages match specification");
1683 for (seqp
= 0; seqs
[seqp
]; seqp
++)
1684 if (!seq_addsel (mp
, seqs
[seqp
], 0, zerosw
))
1687 printf ("%d hit%s\n", mp
->numsel
, mp
->numsel
== 1 ? "" : "s");
1691 #define REPL_SWITCHES \
1692 X("annotate", 0, REANSW) \
1693 X("noannotate", 0, RENANSW) \
1694 X("cc type", 0, RECCSW) \
1695 X("nocc type", 0, RENCCSW) \
1696 X("draftfolder +folder", 0, REDFSW) \
1697 X("draftmessage msg", 0, REDMSW) \
1698 X("nodraftfolder", 0, RENDFSW) \
1699 X("editor editor", 0, REEDTSW) \
1700 X("noedit", 0, RENEDSW) \
1701 X("fcc +folder", 0, REFCCSW) \
1702 X("filter filterfile", 0, REFLTSW) \
1703 X("form formfile", 0, REFRMSW) \
1704 X("inplace", 0, REINSW) \
1705 X("noinplace", 0, RENINSW) \
1706 X("query", 0, REQUSW) \
1707 X("noquery", 0, RENQUSW) \
1708 X("whatnowproc program", 0, REWHTSW) \
1709 X("nowhatnow", 0, RENWTSW) \
1710 X("width columns", 0, REWIDSW) \
1711 X("help", 0, REHELP) \
1713 #define X(sw, minchars, id) id,
1714 DEFINE_SWITCH_ENUM(REPL
);
1717 #define X(sw, minchars, id) { sw, minchars, id },
1718 DEFINE_SWITCH_ARRAY(REPL
, replswit
);
1723 replcmd (char **args
)
1726 char *cp
, *msg
= NULL
;
1727 char buf
[BUFSIZ
], *vec
[MAXARGS
];
1730 forkcmd (args
, cmd_name
);
1734 while ((cp
= *args
++)) {
1736 switch (smatch (++cp
, replswit
)) {
1738 ambigsw (cp
, replswit
);
1741 fprintf (stderr
, "-%s unknown\n", cp
);
1744 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1745 print_help (buf
, replswit
, 1);
1748 case REANSW
: /* not implemented */
1773 if (!(cp
= *args
++) || *cp
== '-') {
1774 advise (NULL
, "missing argument to %s", args
[-2]);
1780 if (*cp
== '+' || *cp
== '@') {
1781 advise (NULL
, "sorry, no folders allowed!");
1786 advise (NULL
, "only one message at a time!");
1794 vec
[vecp
++] = "-file";
1798 if (!m_convert (mp
, msg
))
1802 if (mp
->numsel
> 1) {
1803 advise (NULL
, "only one message at a time!");
1806 process (mp
->hghsel
, cmd_name
, vecp
, vec
);
1807 seq_setcur (mp
, mp
->hghsel
);
1811 #define RMM_SWITCHES \
1812 X("help", 0, RMHELP) \
1814 #define X(sw, minchars, id) id,
1815 DEFINE_SWITCH_ENUM(RMM
);
1818 #define X(sw, minchars, id) { sw, minchars, id },
1819 DEFINE_SWITCH_ARRAY(RMM
, rmmswit
);
1824 rmmcmd (char **args
)
1826 int msgp
= 0, msgnum
;
1827 char *cp
, buf
[BUFSIZ
], *msgs
[MAXARGS
];
1829 while ((cp
= *args
++)) {
1831 switch (smatch (++cp
, rmmswit
)) {
1833 ambigsw (cp
, rmmswit
);
1836 fprintf (stderr
, "-%s unknown\n", cp
);
1839 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1840 print_help (buf
, rmmswit
, 1);
1843 if (*cp
== '+' || *cp
== '@') {
1844 advise (NULL
, "sorry, no folders allowed!");
1852 msgs
[msgp
++] = "cur";
1853 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
1854 if (!m_convert (mp
, msgs
[msgnum
]))
1865 register int msgnum
, vecp
;
1867 char buffer
[BUFSIZ
], *vec
[MAXARGS
];
1871 if (mp
->numsel
> MAXARGS
- 1) {
1872 advise (NULL
, "more than %d messages for %s exec",
1873 MAXARGS
- 1, rmmproc
);
1877 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
1878 if (is_selected (mp
, msgnum
))
1879 vec
[vecp
++] = getcpy (m_name (msgnum
));
1881 forkcmd (vec
, rmmproc
);
1882 for (vecp
= 0; vec
[vecp
]; vecp
++)
1886 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
1887 if (is_selected (mp
, msgnum
)) {
1888 strncpy (buffer
, m_backup (cp
= m_name (msgnum
)), sizeof(buffer
));
1889 if (rename (cp
, buffer
) == NOTOK
)
1890 admonish (buffer
, "unable to rename %s to", cp
);
1894 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
1895 if (is_selected (mp
, msgnum
)) {
1896 set_deleted (mp
, msgnum
);
1897 unset_exists (mp
, msgnum
);
1900 if ((mp
->nummsg
-= mp
->numsel
) <= 0) {
1902 admonish (NULL
, "no messages remaining in +%s", fmsh
);
1904 admonish (NULL
, "no messages remaining in %s", mp
->foldpath
);
1905 mp
->lowmsg
= mp
->hghmsg
= mp
->nummsg
= 0;
1907 if (mp
->lowsel
== mp
->lowmsg
) {
1908 for (msgnum
= mp
->lowmsg
+ 1; msgnum
<= mp
->hghmsg
; msgnum
++)
1909 if (does_exist (mp
, msgnum
))
1911 mp
->lowmsg
= msgnum
;
1913 if (mp
->hghsel
== mp
->hghmsg
) {
1914 for (msgnum
= mp
->hghmsg
- 1; msgnum
>= mp
->lowmsg
; msgnum
--)
1915 if (does_exist (mp
, msgnum
))
1917 mp
->hghmsg
= msgnum
;
1920 mp
->msgflags
|= MODIFIED
;
1925 #define SCAN_SWITCHES \
1926 X("clear", 0, SCCLR) \
1927 X("noclear", 0, SCNCLR) \
1928 X("form formatfile", 0, SCFORM) \
1929 X("format string", 5, SCFMT) \
1930 X("header", 0, SCHEAD) \
1931 X("noheader", 0, SCNHEAD) \
1932 X("width columns", 0, SCWID) \
1933 X("help", 0, SCHELP) \
1935 #define X(sw, minchars, id) id,
1936 DEFINE_SWITCH_ENUM(SCAN
);
1939 #define X(sw, minchars, id) { sw, minchars, id },
1940 DEFINE_SWITCH_ARRAY(SCAN
, scanswit
);
1945 scancmd (char **args
)
1947 #define equiv(a,b) (a ? b && !strcmp (a, b) : !b)
1949 int clearsw
= 0, headersw
= 0, width
= 0, msgp
= 0;
1950 int msgnum
, optim
, state
;
1951 char *cp
, *form
= NULL
, *format
= NULL
;
1952 char buf
[BUFSIZ
], *nfs
, *msgs
[MAXARGS
];
1954 static int s_optim
= 0;
1955 static char *s_form
= NULL
, *s_format
= NULL
;
1957 while ((cp
= *args
++)) {
1959 switch (smatch (++cp
, scanswit
)) {
1961 ambigsw (cp
, scanswit
);
1964 fprintf (stderr
, "-%s unknown\n", cp
);
1967 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
1968 print_help (buf
, scanswit
, 1);
1984 if (!(form
= *args
++) || *form
== '-') {
1985 advise (NULL
, "missing argument to %s", args
[-2]);
1991 if (!(format
= *args
++) || *format
== '-') {
1992 advise (NULL
, "missing argument to %s", args
[-2]);
1998 if (!(cp
= *args
++) || *cp
== '-') {
1999 advise (NULL
, "missing argument to %s", args
[-2]);
2005 if (*cp
== '+' || *cp
== '@') {
2006 advise (NULL
, "sorry, no folders allowed!");
2014 msgs
[msgp
++] = "all";
2015 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
2016 if (!m_convert (mp
, msgs
[msgnum
]))
2020 /* Get new format string */
2021 nfs
= new_fs (form
, format
, FORMAT
);
2023 /* force scansbr to (re)compile format */
2030 s_optim
= optim
= 1;
2031 s_form
= form
? getcpy (form
) : NULL
;
2032 s_format
= format
? getcpy (format
) : NULL
;
2036 optim
= equiv (s_form
, form
) && equiv (s_format
, format
);
2039 for (msgnum
= mp
->lowsel
;
2040 msgnum
<= mp
->hghsel
&& !interrupted
;
2042 if (is_selected (mp
, msgnum
)) {
2043 if (optim
&& Msgs
[msgnum
].m_scanl
)
2044 printf ("%s", Msgs
[msgnum
].m_scanl
);
2047 zp
= msh_ready (msgnum
, 0);
2048 switch (state
= scan (zp
, msgnum
, 0, nfs
, width
,
2049 msgnum
== mp
->curmsg
,
2050 is_unseen (mp
, msgnum
),
2051 headersw
? (fmsh
? fmsh
: mp
->foldpath
) : NULL
,
2052 fmsh
? 0L : (long) (Msgs
[msgnum
].m_stop
- Msgs
[msgnum
].m_start
),
2058 Msgs
[msgnum
].m_scanl
= getcpy (scanl
);
2062 advise (NULL
, "scan() botch (%d)", state
);
2066 printf ("%*d empty\n", DMAXFOLDER
, msgnum
);
2078 #define SHOW_SWITCHES \
2079 X("draft", 5, SHDRAFT) \
2080 X("form formfile", 4, SHFORM) \
2081 X("moreproc program", 4, SHPROG) \
2082 X("nomoreproc", 3, SHNPROG) \
2083 X("length lines", 4, SHLEN) \
2084 X("width columns", 4, SHWID) \
2085 X("showproc program", 4, SHSHOW) \
2086 X("noshowproc", 3, SHNSHOW) \
2087 X("header", 4, SHHEAD) \
2088 X("noheader", 3, SHNHEAD) \
2089 X("help", 0, SHHELP) \
2091 #define X(sw, minchars, id) id,
2092 DEFINE_SWITCH_ENUM(SHOW
);
2095 #define X(sw, minchars, id) { sw, minchars, id },
2096 DEFINE_SWITCH_ARRAY(SHOW
, showswit
);
2101 showcmd (char **args
)
2103 int headersw
= 1, nshow
= 0, msgp
= 0, vecp
= 1;
2104 int mhl
= 0, seqnum
= -1, mode
= 0, i
, msgnum
;
2105 char *cp
, *proc
= showproc
, buf
[BUFSIZ
];
2106 char *msgs
[MAXARGS
], *vec
[MAXARGS
];
2108 if (!mh_strcasecmp (cmd_name
, "next"))
2111 if (!mh_strcasecmp (cmd_name
, "prev"))
2113 while ((cp
= *args
++)) {
2115 switch (i
= smatch (++cp
, showswit
)) {
2117 ambigsw (cp
, showswit
);
2124 snprintf (buf
, sizeof(buf
), "%s %s[switches] [switches for showproc]",
2125 cmd_name
, mode
? NULL
: "[msgs] ");
2126 print_help (buf
, showswit
, 1);
2134 if (!(cp
= *args
++) || *cp
== '-') {
2135 advise (NULL
, "missing argument to %s", args
[-2]);
2147 if (!(proc
= *args
++) || *proc
== '-') {
2148 advise (NULL
, "missing argument to %s", args
[-2]);
2158 advise (NULL
, "sorry, -%s not allowed!", showswit
[i
].sw
);
2161 if (*cp
== '+' || *cp
== '@') {
2162 advise (NULL
, "sorry, no folders allowed!");
2168 "usage: %s [switches] [switches for showproc]\n",
2178 msgs
[msgp
++] = mode
> 0 ? "next" : mode
< 0 ? "prev" : "cur";
2179 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
2180 if (!m_convert (mp
, msgs
[msgnum
]))
2185 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
2186 if (is_selected (mp
, msgnum
) && is_nontext (msgnum
)) {
2187 proc
= showmimeproc
;
2188 vec
[vecp
++] = "-file";
2196 if (strcmp (showproc
, "mhl") == 0) {
2202 seqnum
= seq_getnum (mp
, "unseen");
2203 vec
[0] = r1bindex (proc
, '/');
2206 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++)
2207 if (is_selected (mp
, msgnum
)) {
2208 vec
[vecp
++] = getcpy (m_name (msgnum
));
2210 seq_delmsg (mp
, "unseen", msgnum
);
2213 if (mp
->numsel
== 1 && headersw
)
2215 mhlsbr (vecp
, vec
, mhl_action
);
2216 scan_eom_action ((int (*)()) 0);
2221 for (msgnum
= mp
->lowsel
;
2222 msgnum
<= mp
->hghsel
&& !interrupted
;
2224 if (is_selected (mp
, msgnum
)) {
2225 switch (ask (msgnum
)) {
2226 case NOTOK
: /* QUIT */
2233 if (mp
->numsel
== 1 && headersw
)
2236 copy_message (msgnum
, stdout
);
2238 process (msgnum
, proc
, vecp
, vec
);
2241 seq_delmsg (mp
, "unseen", msgnum
);
2248 seq_setcur (mp
, mp
->hghsel
);
2255 if (Msgs
[msgnum
].m_bboard_id
== 0)
2258 printf ("(Message %d", msgnum
);
2259 if (Msgs
[msgnum
].m_bboard_id
> 0)
2260 printf (", %s: %d", BBoard_ID
, Msgs
[msgnum
].m_bboard_id
);
2271 return (ftell (mhlfp
) >= Msgs
[mhlnum
].m_stop
);
2276 mhl_action (char *name
)
2280 if ((msgnum
= m_atoi (name
)) < mp
->lowmsg
2281 || msgnum
> mp
->hghmsg
2282 || !does_exist (mp
, msgnum
))
2286 mhlfp
= msh_ready (msgnum
, 1);
2288 scan_eom_action (eom_action
);
2300 if (mp
->numsel
== 1 || !interactive
|| redirected
)
2303 if (SOprintf ("Press <return> to list \"%d\"...", msgnum
)) {
2304 if (mp
->lowsel
!= msgnum
)
2306 printf ("Press <return> to list \"%d\"...", msgnum
);
2311 read (fileno (stdout
), buf
, sizeof buf
);
2313 if (strchr(buf
, '\n') == NULL
)
2317 told_to_quit
= interrupted
= 0;
2332 is_nontext (int msgnum
)
2336 char buf
[BUFSIZ
], name
[NAMESZ
];
2339 if (Msgs
[msgnum
].m_flags
& MHNCHK
)
2340 return (Msgs
[msgnum
].m_flags
& MHNYES
);
2341 Msgs
[msgnum
].m_flags
|= MHNCHK
;
2343 fp
= msh_ready (msgnum
, 1);
2346 int bufsz
= sizeof buf
;
2347 switch (state
= m_getfld (&gstate
, name
, buf
, &bufsz
, fp
)) {
2351 * Check Content-Type field
2353 if (!mh_strcasecmp (name
, TYPE_FIELD
)) {
2357 cp
= add (buf
, NULL
);
2358 while (state
== FLDPLUS
) {
2360 state
= m_getfld (&gstate
, name
, buf
, &bufsz
, fp
);
2367 for (; isspace ((unsigned char) *bp
); bp
++)
2372 for (bp
++, i
= 0;;) {
2402 for (dp
= bp
; istoken (*dp
); dp
++)
2409 if ((result
= (mh_strcasecmp (bp
, "plain") != 0)))
2412 for (dp
++; isspace ((unsigned char) *dp
); dp
++)
2415 if ((result
= !uprf (dp
, "charset")))
2417 dp
+= sizeof "charset" - 1;
2418 while (isspace ((unsigned char) *dp
))
2422 while (isspace ((unsigned char) *dp
))
2425 if ((bp
= strchr(++dp
, '"')))
2428 for (bp
= dp
; *bp
; bp
++)
2429 if (isspace ((unsigned char) *bp
)) {
2435 /* Default character set */
2438 /* Check the character set */
2439 result
= !check_charset (dp
, strlen (dp
));
2441 if (!(result
= (mh_strcasecmp (bp
, "text") != 0))) {
2451 Msgs
[msgnum
].m_flags
|= MHNYES
;
2458 * Check Content-Transfer-Encoding field
2460 if (!mh_strcasecmp (name
, ENCODING_FIELD
)) {
2461 cp
= add (buf
, NULL
);
2462 while (state
== FLDPLUS
) {
2464 state
= m_getfld (&gstate
, name
, buf
, &bufsz
, fp
);
2467 for (bp
= cp
; isspace ((unsigned char) *bp
); bp
++)
2469 for (dp
= bp
; istoken (*dp
); dp
++)
2472 result
= (mh_strcasecmp (bp
, "7bit")
2473 && mh_strcasecmp (bp
, "8bit")
2474 && mh_strcasecmp (bp
, "binary"));
2478 Msgs
[msgnum
].m_flags
|= MHNYES
;
2485 * Just skip the rest of this header
2486 * field and go to next one.
2488 while (state
== FLDPLUS
) {
2490 state
= m_getfld (&gstate
, name
, buf
, &bufsz
, fp
);
2495 * We've passed the message header,
2496 * so message is just text.
2505 #define SORT_SWITCHES \
2506 X("datefield field", 0, SODATE) \
2507 X("textfield field", 0, SOSUBJ) \
2508 X("notextfield", 0, SONSUBJ) \
2509 X("limit days", 0, SOLIMT) \
2510 X("nolimit", 0, SONLIMT) \
2511 X("verbose", 0, SOVERB) \
2512 X("noverbose", 0, SONVERB) \
2513 X("help", 0, SOHELP) \
2515 #define X(sw, minchars, id) id,
2516 DEFINE_SWITCH_ENUM(SORT
);
2519 #define X(sw, minchars, id) { sw, minchars, id },
2520 DEFINE_SWITCH_ARRAY(SORT
, sortswit
);
2525 sortcmd (char **args
)
2527 int msgp
= 0, msgnum
;
2528 char *cp
, *datesw
= NULL
, *subjsw
= NULL
;
2529 char buf
[BUFSIZ
], *msgs
[MAXARGS
];
2533 forkcmd (args
, cmd_name
);
2537 while ((cp
= *args
++)) {
2539 switch (smatch (++cp
, sortswit
)) {
2541 ambigsw (cp
, sortswit
);
2544 fprintf (stderr
, "-%s unknown\n", cp
);
2547 snprintf (buf
, sizeof(buf
), "%s [msgs] [switches]", cmd_name
);
2548 print_help (buf
, sortswit
, 1);
2553 advise (NULL
, "only one date field at a time!");
2556 if (!(datesw
= *args
++) || *datesw
== '-') {
2557 advise (NULL
, "missing argument to %s", args
[-2]);
2564 advise (NULL
, "only one text field at a time!");
2567 if (!(subjsw
= *args
++) || *subjsw
== '-') {
2568 advise (NULL
, "missing argument to %s", args
[-2]);
2576 case SOLIMT
: /* too hard */
2577 if (!(cp
= *args
++) || *cp
== '-') {
2578 advise (NULL
, "missing argument to %s", args
[-2]);
2582 case SOVERB
: /* not implemented */
2586 if (*cp
== '+' || *cp
== '@') {
2587 advise (NULL
, "sorry, no folders allowed!");
2595 msgs
[msgp
++] = "all";
2598 for (msgnum
= 0; msgnum
< msgp
; msgnum
++)
2599 if (!m_convert (mp
, msgs
[msgnum
]))
2603 twscopy (&tb
, dlocaltimenow ());
2605 for (msgnum
= mp
->lowsel
; msgnum
<= mp
->hghsel
; msgnum
++) {
2606 if (Msgs
[msgnum
].m_scanl
) {
2607 free (Msgs
[msgnum
].m_scanl
);
2608 Msgs
[msgnum
].m_scanl
= NULL
;
2610 if (is_selected (mp
, msgnum
)) {
2611 if (get_fields (datesw
, subjsw
, msgnum
, &Msgs
[msgnum
]))
2612 twscopy (&Msgs
[msgnum
].m_tb
,
2613 msgnum
!= mp
->lowsel
? &Msgs
[msgnum
- 1].m_tb
: &tb
);
2615 else /* m_scaln is already NULL */
2616 twscopy (&Msgs
[msgnum
].m_tb
, &tb
);
2617 Msgs
[msgnum
].m_stats
= mp
->msgstats
[msgnum
- mp
->lowoff
];
2618 if (mp
->curmsg
== msgnum
)
2619 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 mp
->msgstats
[msgnum
- mp
->lowoff
] = Msgs
[msgnum
].m_stats
& ~CUR
;
2631 if (Msgs
[msgnum
].m_stats
& CUR
)
2632 seq_setcur (mp
, msgnum
);
2635 mp
->msgflags
|= MODIFIED
;
2641 * get_fields - parse message, and get date and subject if needed.
2642 * We'll use the msgp->m_tb tws struct for the date, and overload
2643 * the msgp->m_scanl field with our subject string.
2646 get_fields (char *datesw
, char *subjsw
, int msgnum
, struct Msg
*msgp
)
2648 int state
, gotdate
= 0;
2649 char *bp
, buf
[BUFSIZ
], name
[NAMESZ
];
2650 struct tws
*tw
= (struct tws
*) 0;
2653 zp
= msh_ready (msgnum
, 0);
2656 int bufsz
= sizeof buf
;
2657 switch (state
= m_getfld (&gstate
, name
, buf
, &bufsz
, zp
)) {
2660 if (!mh_strcasecmp (name
, datesw
)) {
2662 while (state
== FLDPLUS
) {
2664 state
= m_getfld (&gstate
, name
, buf
, &bufsz
, zp
);
2667 if ((tw
= dparsetime (bp
)) == NULL
)
2669 "unable to parse %s field in message %d",
2672 twscopy (&(msgp
->m_tb
), tw
);
2674 if (!subjsw
) /* not using this, or already done */
2675 break; /* all done! */
2678 else if (subjsw
&& !mh_strcasecmp(name
, subjsw
)) {
2680 while (state
== FLDPLUS
) {
2682 state
= m_getfld (&gstate
, name
, buf
, &bufsz
, zp
);
2685 msgp
->m_scanl
= sosmash(subjsw
, bp
);
2687 break; /* date done so we're done */
2689 subjsw
= (char *)0;/* subject done, need date */
2691 while (state
== FLDPLUS
) { /* flush this one */
2693 state
= m_getfld (&gstate
, name
, buf
, &bufsz
, zp
);
2704 admonish (NULL
, "format error in message %d", msgnum
);
2705 if (msgp
->m_scanl
) { /* this might need free'd */
2706 free (msgp
->m_scanl
); /* probably can't use subj anyway */
2707 msgp
->m_scanl
= NULL
;
2712 adios (NULL
, "internal error -- you lose");
2717 return OK
; /* not an error if subj not found */
2719 admonish (NULL
, "no %s field in message %d", datesw
, msgnum
);
2720 return NOTOK
; /* NOTOK means use some other date */
2729 msgsort (struct Msg
*a
, struct Msg
*b
)
2731 return twsort (&a
->m_tb
, &b
->m_tb
);
2736 subsort (struct Msg
*a
, struct Msg
*b
)
2740 if (a
->m_scanl
&& b
->m_scanl
)
2741 if ((i
= strcmp (a
->m_scanl
, b
->m_scanl
)))
2744 return twsort (&a
->m_tb
, &b
->m_tb
);
2749 * try to make the subject "canonical": delete leading "re:", everything
2750 * but letters & smash letters to lower case.
2753 sosmash (char *subj
, char *s
)
2755 register char *cp
, *dp
;
2756 register unsigned char c
;
2760 dp
= s
; /* dst pointer */
2761 if (!mh_strcasecmp (subj
, "subject"))
2768 *dp
++ = isupper(c
) ? tolower(c
) : c
;
2774 while ((c
= *cp
++)) {
2776 *dp
++ = isupper(c
) ? tolower(c
) : c
;
2786 process (int msgnum
, char *proc
, int vecp
, char **vec
)
2788 int child_id
, status
;
2789 char tmpfil
[BUFSIZ
];
2794 strncpy (tmpfil
, m_name (msgnum
), sizeof(tmpfil
));
2795 context_del (pfolder
);
2796 context_replace (pfolder
, fmsh
);/* update current folder */
2798 context_save (); /* save the context file */
2802 cp
= m_mktemp(invo_name
, NULL
, &out
);
2804 /* Try again, but try to create under /tmp */
2806 cp
= m_mktemp2(NULL
, invo_name
, NULL
, &out
);
2809 advise (NULL
, "unable to create temporary file");
2813 copy_message (msgnum
, out
);
2815 strncpy(tmpfil
, cp
, sizeof(tmpfil
));
2819 switch (child_id
= fork ()) {
2821 advise ("fork", "unable to");
2827 SIGNAL (SIGINT
, istat
);
2828 SIGNAL (SIGQUIT
, qstat
);
2830 vec
[vecp
++] = tmpfil
;
2834 fprintf (stderr
, "unable to exec ");
2839 status
= pidXwait (child_id
, NULL
);
2850 copy_message (int msgnum
, FILE *out
)
2853 static char buffer
[BUFSIZ
];
2856 zp
= msh_ready (msgnum
, 1);
2858 while (fgets (buffer
, sizeof buffer
, zp
) != NULL
) {
2859 fputs (buffer
, out
);
2860 if (interrupted
&& out
== stdout
)
2866 while (fgets (buffer
, sizeof buffer
, zp
) != NULL
2867 && pos
< Msgs
[msgnum
].m_stop
) {
2868 fputs (buffer
, out
);
2869 pos
+= (long) strlen (buffer
);
2870 if (interrupted
&& out
== stdout
)
2878 copy_digest (int msgnum
, FILE *out
)
2882 static char buffer
[BUFSIZ
];
2886 zp
= msh_ready (msgnum
, 1);
2889 while (fgets (buffer
, sizeof buffer
, zp
) != NULL
2890 && !fmsh
&& pos
< Msgs
[msgnum
].m_stop
) {
2891 if (c
== '\n' && *buffer
== '-')
2893 fputs (buffer
, out
);
2894 c
= buffer
[strlen (buffer
) - 1];
2896 pos
+= (long) strlen (buffer
);
2897 if (interrupted
&& out
== stdout
)