3 * mshcmds.c -- command handlers in msh
7 * This code is Copyright (c) 2002, by the authors of nmh. See the
8 * COPYRIGHT file in the root directory of the nmh distribution for
9 * complete copyright information.
13 #include <h/signals.h>
14 #include <h/dropsbr.h>
15 #include <h/fmt_scan.h>
16 #include <h/scansbr.h>
23 #include <h/picksbr.h>
27 static char delim3[] = "-------"; /* from burst.c */
32 #if defined(NNTP) && defined(MPOP)
39 extern char response[];
44 * Type for a compare function for qsort. This keeps
47 typedef int (*qsort_comp) (const void *, const void *);
52 void clear_screen (void); /* from termsbr.c */
53 int SOprintf (char *, ...); /* from termsbr.c */
54 int sc_width (void); /* from termsbr.c */
59 static int burst (struct Msg *, int, int, int, int);
60 static void forw (char *, char *, int, char **);
61 static void rmm (void);
62 static void show (int);
63 static int eom_action (int);
64 static FILE *mhl_action (char *);
66 static int is_nontext (int);
67 static int get_fields (char *, char *, int, struct Msg *);
68 static int msgsort (struct Msg *, struct Msg *);
69 static int subsort (struct Msg *, struct Msg *);
70 static char *sosmash (char *, char *);
71 static int process (int, char *, int, char **);
72 static void copy_message (int, FILE *);
73 static void copy_digest (int, FILE *);
76 int mhlsbr (int, char **, FILE *(*)());
79 forkcmd (char **args, char *pgm)
84 vec[0] = r1bindex (pgm, '/');
85 copyip (args, vec + 1, MAXARGS - 1);
88 context_del (pfolder);
89 context_replace (pfolder, fmsh);/* update current folder */
91 context_save (); /* save the context file */
94 switch (child_id = fork ()) {
96 advise ("fork", "unable to");
101 SIGNAL (SIGINT, istat);
102 SIGNAL (SIGQUIT, qstat);
105 fprintf (stderr, "unable to exec ");
110 pidXwait (child_id, NULL);
113 if (fmsh) { /* assume the worst case */
114 mp->msgflags |= MODIFIED;
120 static struct swit distswit[] = {
126 { "draftfolder +folder", 0 },
128 { "draftmessage msg", 0 },
130 { "nodraftfolder", 0 },
132 { "editor editor", 0 },
136 { "form formfile", 0 },
142 { "whatnowproc program", 0 },
144 { "nowhatnowproc", 0 },
152 distcmd (char **args)
155 char *cp, *msg = NULL;
156 char buf[BUFSIZ], *vec[MAXARGS];
159 forkcmd (args, cmd_name);
163 while ((cp = *args++)) {
165 switch (smatch (++cp, distswit)) {
167 ambigsw (cp, distswit);
170 fprintf (stderr, "-%s unknown\n", cp);
173 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
174 print_help (buf, distswit, 1);
177 case DIANSW: /* not implemented */
195 if (!(cp = *args++) || *cp == '-') {
196 advise (NULL, "missing argument to %s", args[-2]);
202 if (*cp == '+' || *cp == '@') {
203 advise (NULL, "sorry, no folders allowed!");
208 advise (NULL, "only one message at a time!");
216 vec[vecp++] = "-file";
220 if (!m_convert (mp, msg))
224 if (mp->numsel > 1) {
225 advise (NULL, "only one message at a time!");
228 process (mp->hghsel, cmd_name, vecp, vec);
229 seq_setcur (mp, mp->hghsel);
233 static struct swit explswit[] = {
253 explcmd (char **args)
255 int inplace = 0, quietsw = 0, verbosw = 0;
256 int msgp = 0, hi, msgnum;
257 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
261 forkcmd (args, cmd_name);
265 while ((cp = *args++)) {
267 switch (smatch (++cp, explswit)) {
269 ambigsw (cp, explswit);
272 fprintf (stderr, "-%s unknown\n", cp);
275 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
276 print_help (buf, explswit, 1);
298 if (*cp == '+' || *cp == '@') {
299 advise (NULL, "sorry, no folders allowed!");
307 msgs[msgp++] = "cur";
308 for (msgnum = 0; msgnum < msgp; msgnum++)
309 if (!m_convert (mp, msgs[msgnum]))
313 smsgs = (struct Msg *)
314 calloc ((size_t) (MAXFOLDER + 2), sizeof *smsgs);
316 adios (NULL, "unable to allocate folder storage");
320 for (msgnum = mp->lowsel;
321 msgnum <= mp->hghsel && !interrupted;
323 if (is_selected (mp, msgnum))
324 if (burst (smsgs, msgnum, inplace, quietsw, verbosw) != OK)
327 free ((char *) smsgs);
330 seq_setcur (mp, mp->lowsel);
332 if (hi <= mp->hghmsg)
335 mp->msgflags |= MODIFIED;
341 burst (struct Msg *smsgs, int msgnum, int inplace, int quietsw, int verbosw)
343 int i, j, ld3, wasdlm, msgp;
345 char c, buffer[BUFSIZ];
348 ld3 = strlen (delim3);
350 if (Msgs[msgnum].m_scanl) {
351 free (Msgs[msgnum].m_scanl);
352 Msgs[msgnum].m_scanl = NULL;
355 pos = ftell (zp = msh_ready (msgnum, 1));
356 for (msgp = 0; msgp <= MAXFOLDER;) {
357 while (fgets (buffer, sizeof buffer, zp) != NULL
359 && pos < Msgs[msgnum].m_stop)
360 pos += (long) strlen (buffer);
361 if (feof (zp) || pos >= Msgs[msgnum].m_stop)
363 fseek (zp, pos, SEEK_SET);
364 smsgs[msgp].m_start = pos;
367 pos < Msgs[msgnum].m_stop
368 && fgets (buffer, sizeof buffer, zp) != NULL;
370 if (strncmp (buffer, delim3, ld3) == 0
371 && (msgp == 1 || c == '\n')
372 && peekc (zp) == '\n')
375 pos += (long) strlen (buffer);
377 wasdlm = strncmp (buffer, delim3, ld3) == 0;
378 if (smsgs[msgp].m_start != pos)
379 smsgs[msgp++].m_stop = (c == '\n' && wasdlm) ? pos - 1 : pos;
380 if (feof (zp) || pos >= Msgs[msgnum].m_stop) {
382 smsgs[msgp - 1].m_stop -= ((long) strlen (buffer) + 1);
385 pos += (long) strlen (buffer);
388 switch (msgp--) { /* toss "End of XXX Digest" */
390 adios (NULL, "burst() botch -- you lose big");
394 printf ("message %d not in digest format\n", msgnum);
399 printf ("%d message%s exploded from digest %d\n",
400 msgp, msgp != 1 ? "s" : "", msgnum);
404 if ((i = msgp + mp->hghmsg) > MAXFOLDER) {
405 advise (NULL, "more than %d messages", MAXFOLDER);
408 if (!(mp = folder_realloc (mp, mp->lowoff, i)))
409 adios (NULL, "unable to allocate folder storage");
414 if (mp->hghsel > msgnum)
418 for (i = mp->hghmsg; j > msgnum; i--, j--) {
420 printf ("message %d becomes message %d\n", j, i);
422 Msgs[i].m_bboard_id = Msgs[j].m_bboard_id;
423 Msgs[i].m_top = Msgs[j].m_top;
424 Msgs[i].m_start = Msgs[j].m_start;
425 Msgs[i].m_stop = Msgs[j].m_stop;
426 Msgs[i].m_scanl = NULL;
427 if (Msgs[j].m_scanl) {
428 free (Msgs[j].m_scanl);
429 Msgs[j].m_scanl = NULL;
431 copy_msg_flags (mp, i, j);
434 if (Msgs[msgnum].m_bboard_id == 0)
437 unset_selected (mp, msgnum);
438 i = inplace ? msgnum + msgp : mp->hghmsg;
439 for (j = msgp; j >= (inplace ? 0 : 1); i--, j--) {
440 if (verbosw && i != msgnum)
441 printf ("message %d of digest %d becomes message %d\n",
444 Msgs[i].m_bboard_id = Msgs[msgnum].m_bboard_id;
445 Msgs[i].m_top = Msgs[j].m_top;
446 Msgs[i].m_start = smsgs[j].m_start;
447 Msgs[i].m_stop = smsgs[j].m_stop;
448 Msgs[i].m_scanl = NULL;
449 copy_msg_flags (mp, i, msgnum);
456 static struct swit fileswit[] = {
468 { "src +folder", 0 },
472 { "rmmproc program", 0 },
482 filecmd (char **args)
484 int linksw = 0, msgp = 0;
485 int vecp = 1, i, msgnum;
486 char *cp, buf[BUFSIZ];
487 char *msgs[MAXARGS], *vec[MAXARGS];
490 forkcmd (args, cmd_name);
494 while ((cp = *args++)) {
496 switch (i = smatch (++cp, fileswit)) {
498 ambigsw (cp, fileswit);
501 fprintf (stderr, "-%s unknown\n", cp);
504 snprintf (buf, sizeof(buf), "%s +folder... [msgs] [switches]", cmd_name);
505 print_help (buf, fileswit, 1);
524 advise (NULL, "sorry, -%s not allowed!", fileswit[i].sw);
527 if (*cp == '+' || *cp == '@')
534 vec[vecp++] = "-file";
537 msgs[msgp++] = "cur";
538 for (msgnum = 0; msgnum < msgp; msgnum++)
539 if (!m_convert (mp, msgs[msgnum]))
544 for (msgnum = mp->lowsel;
545 msgnum <= mp->hghsel && !interrupted;
547 if (is_selected (mp, msgnum))
548 if (process (msgnum, fileproc, vecp, vec)) {
549 unset_selected (mp, msgnum);
553 if (mp->numsel != mp->nummsg || linksw)
554 seq_setcur (mp, mp->hghsel);
561 filehak (char **args)
563 int result, vecp = 0;
564 char *cp, *cwd, *vec[MAXARGS];
566 while ((cp = *args++)) {
568 switch (smatch (++cp, fileswit)) {
585 if (*cp == '+' || *cp == '@')
592 for (vecp = 0; (cp = vec[vecp]) && result == NOTOK; vecp++) {
594 cwd = getcpy (pwd ());
595 chdir (m_maildir (""));
597 if (access (m_maildir (cp), F_OK) == NOTOK)
608 static struct swit foldswit[] = {
646 foldcmd (char **args)
648 int fastsw = 0, headersw = 0, packsw = 0;
650 char *cp, *folder = NULL, *msg = NULL;
651 char buf[BUFSIZ], **vec = args;
656 while ((cp = *args++)) {
658 switch (smatch (++cp, foldswit)) {
660 ambigsw (cp, foldswit);
663 fprintf (stderr, "-%s unknown\n", cp);
666 snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]", cmd_name);
667 print_help (buf, foldswit, 1);
670 case FLALSW: /* not implemented */
700 if (*cp == '+' || *cp == '@') {
702 advise (NULL, "only one folder at a time!\n");
706 folder = fmsh ? pluspath (cp)
711 advise (NULL, "only one message at a time!\n");
720 advise (NULL, "null folder names are not permitted");
724 if (access (m_maildir (folder), R_OK) == NOTOK) {
725 advise (folder, "unable to read");
730 strncpy (buf, folder, sizeof(buf));
731 if (expand (buf) == NOTOK)
734 if (access (folder, R_OK) == NOTOK) {
735 advise (folder, "unable to read");
750 if (!m_convert (mp, msg))
754 if (mp->numsel > 1) {
755 advise (NULL, "only one message at a time!");
758 seq_setcur (mp, mp->hghsel);
763 forkcmd (vec, cmd_name);
767 if (mp->lowoff > 1 && !(mp = folder_realloc (mp, 1, mp->hghmsg)))
768 adios (NULL, "unable to allocate folder storage");
770 for (msgnum = mp->lowmsg, hole = 1; msgnum <= mp->hghmsg; msgnum++)
771 if (does_exist (mp, msgnum)) {
772 if (msgnum != hole) {
773 Msgs[hole].m_bboard_id = Msgs[msgnum].m_bboard_id;
774 Msgs[hole].m_top = Msgs[msgnum].m_top;
775 Msgs[hole].m_start = Msgs[msgnum].m_start;
776 Msgs[hole].m_stop = Msgs[msgnum].m_stop;
777 Msgs[hole].m_scanl = NULL;
778 if (Msgs[msgnum].m_scanl) {
779 free (Msgs[msgnum].m_scanl);
780 Msgs[msgnum].m_scanl = NULL;
782 copy_msg_flags (mp, hole, msgnum);
783 if (mp->curmsg == msgnum)
784 seq_setcur (mp, hole);
788 if (mp->nummsg > 0) {
790 mp->hghmsg = hole - 1;
792 mp->msgflags |= MODIFIED;
798 printf ("%s\n", fmsh ? fmsh : mp->foldpath);
801 printf ("\t\tFolder %*s# of messages (%*srange%*s); cur%*smsg\n",
802 DMAXFOLDER, "", DMAXFOLDER - 2, "", DMAXFOLDER - 2, "",
804 printf (args ? "%22s " : "%s ", fmsh ? fmsh : mp->foldpath);
806 /* check for empty folder */
807 if (mp->nummsg == 0) {
808 printf ("has no messages%*s",
809 mp->msgflags & OTHERS ? DMAXFOLDER * 2 + 4 : 0, "");
811 printf ("has %*d message%s (%*d-%*d)",
812 DMAXFOLDER, mp->nummsg, mp->nummsg != 1 ? "s" : "",
813 DMAXFOLDER, mp->lowmsg, DMAXFOLDER, mp->hghmsg);
814 if (mp->curmsg >= mp->lowmsg
815 && mp->curmsg <= mp->hghmsg)
816 printf ("; cur=%*d", DMAXFOLDER, mp->curmsg);
823 static struct swit forwswit[] = {
829 { "draftfolder +folder", 0 },
831 { "draftmessage msg", 0 },
833 { "nodraftfolder", 0 },
835 { "editor editor", 0 },
839 { "filter filterfile", 0 },
841 { "form formfile", 0 },
855 { "whatnowproc program", 0 },
865 forwcmd (char **args)
867 int msgp = 0, vecp = 1, msgnum;
868 char *cp, *filter = NULL, buf[BUFSIZ];
869 char *msgs[MAXARGS], *vec[MAXARGS];
874 forkcmd (args, cmd_name);
878 while ((cp = *args++)) {
880 switch (smatch (++cp, forwswit)) {
882 ambigsw (cp, forwswit);
885 fprintf (stderr, "-%s unknown\n", cp);
888 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
889 print_help (buf, forwswit, 1);
892 case FOANSW: /* not implemented */
912 if (!(cp = *args++) || *cp == '-') {
913 advise (NULL, "missing argument to %s", args[-2]);
919 if (!(filter = *args++) || *filter == '-') {
920 advise (NULL, "missing argument to %s", args[-2]);
925 if (access (filter = myfilter, R_OK) == NOTOK) {
926 advise (filter, "unable to read default filter file");
934 if (*cp == '+' || *cp == '@') {
935 advise (NULL, "sorry, no folders allowed!");
942 /* foil search of .mh_profile */
943 snprintf (buf, sizeof(buf), "%sXXXXXX", invo_name);
945 tfile = m_mktemp(buf, NULL, NULL);
946 if (tfile == NULL) adios("forwcmd", "unable to create temporary file");
947 strncpy (tmpfil, tfile, sizeof(tmpfil));
950 vec[vecp++] = "-file";
953 msgs[msgp++] = "cur";
954 for (msgnum = 0; msgnum < msgp; msgnum++)
955 if (!m_convert (mp, msgs[msgnum]))
960 strncpy (buf, filter, sizeof(buf));
961 if (expand (buf) == NOTOK)
963 if (access (filter = getcpy (etcpath (buf)), R_OK) == NOTOK) {
964 advise (filter, "unable to read");
969 forw (cmd_name, filter, vecp, vec);
970 seq_setcur (mp, mp->hghsel);
977 forw (char *proc, char *filter, int vecp, char **vec)
979 int i, child_id, msgnum, msgcnt;
980 char tmpfil[BUFSIZ], *args[MAXARGS];
984 tfile = m_mktemp2(NULL, invo_name, NULL, NULL);
985 if (tfile == NULL) adios("forw", "unable to create temporary file");
986 strncpy (tmpfil, tfile, sizeof(tmpfil));
990 switch (child_id = fork ()) {
992 advise ("fork", "unable to");
995 case OK: /* "trust me" */
996 if (freopen (tmpfil, "w", stdout) == NULL) {
997 fprintf (stderr, "unable to create ");
1001 args[0] = r1bindex (mhlproc, '/');
1003 args[i++] = "-forwall";
1004 args[i++] = "-form";
1006 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1007 if (is_selected (mp, msgnum))
1008 args[i++] = getcpy (m_name (msgnum));
1010 mhlsbr (i, args, mhl_action);
1011 m_eomsbr ((int (*) ()) 0);
1016 if (pidXwait (child_id, NULL))
1021 if ((out = fopen (tmpfil, "w")) == NULL) {
1022 advise (tmpfil, "unable to create temporary file");
1027 for (msgnum = mp->lowsel;
1028 msgnum <= mp->hghsel && !interrupted;
1030 if (is_selected (mp, msgnum)) {
1031 fprintf (out, "\n\n-------");
1032 if (msgnum == mp->lowsel)
1033 fprintf (out, " Forwarded Message%s",
1034 mp->numsel > 1 ? "s" : "");
1036 fprintf (out, " Message %d", msgcnt);
1037 fprintf (out, "\n\n");
1038 copy_digest (msgnum, out);
1042 fprintf (out, "\n\n------- End of Forwarded Message%s\n",
1043 mp->numsel > 1 ? "s" : "");
1049 switch (child_id = fork ()) {
1051 advise ("fork", "unable to");
1056 SIGNAL (SIGINT, istat);
1057 SIGNAL (SIGQUIT, qstat);
1059 vec[vecp++] = tmpfil;
1063 fprintf (stderr, "unable to exec ");
1068 pidXwait (child_id, NULL);
1076 static char *hlpmsg[] = {
1077 "The %s program emulates many of the commands found in the nmh",
1078 "system. Instead of operating on nmh folders, commands to %s concern",
1081 "To see the list of commands available, just type a ``?'' followed by",
1082 "the RETURN key. To find out what switches each command takes, type",
1083 "the name of the command followed by ``-help''. To leave %s, use the",
1084 "``quit'' command.",
1086 "Although a lot of nmh commands are found in %s, not all are fully",
1087 "implemented. %s will always recognize all legal switches for a",
1088 "given command though, and will let you know when you ask for an",
1089 "option that it is unable to perform.",
1091 "Running %s is fun, but using nmh from your shell is far superior.",
1092 "After you have familiarized yourself with the nmh style by using %s,",
1093 "you should try using nmh from the shell. You can still use %s for",
1094 "message files that aren't in nmh format, such as BBoard files.",
1100 helpcmd (char **args)
1104 for (i = 0; hlpmsg[i]; i++) {
1105 printf (hlpmsg[i], invo_name);
1111 static struct swit markswit[] = {
1119 { "sequence name", 0 },
1137 markcmd (char **args)
1139 int addsw = 0, deletesw = 0, debugsw = 0;
1140 int listsw = 0, zerosw = 0, seqp = 0;
1141 int msgp = 0, msgnum;
1142 char *cp, buf[BUFSIZ];
1143 char *seqs[NUMATTRS + 1], *msgs[MAXARGS];
1145 while ((cp = *args++)) {
1147 switch (smatch (++cp, markswit)) {
1149 ambigsw (cp, markswit);
1152 fprintf (stderr, "-%s unknown\n", cp);
1155 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1156 print_help (buf, markswit, 1);
1161 deletesw = listsw = 0;
1169 addsw = deletesw = 0;
1173 if (!(cp = *args++) || *cp == '-') {
1174 advise (NULL, "missing argument to %s", args[-2]);
1177 if (seqp < NUMATTRS)
1180 advise (NULL, "only %d sequences allowed!", NUMATTRS);
1185 case MPUBSW: /* not implemented */
1201 if (*cp == '+' || *cp == '@') {
1202 advise (NULL, "sorry, no folders allowed!");
1209 if (!addsw && !deletesw && !listsw) {
1216 seqs[seqp++] = "unseen";
1220 msgs[msgp++] = "all";
1225 msgs[msgp++] = listsw ? "all" :"cur";
1226 for (msgnum = 0; msgnum < msgp; msgnum++)
1227 if (!m_convert (mp, msgs[msgnum]))
1231 printf ("invo_name=%s mypath=%s defpath=%s\n",
1232 invo_name, mypath, defpath);
1233 printf ("ctxpath=%s context flags=%s\n",
1234 ctxpath, snprintb (buf, sizeof(buf), (unsigned) ctxflags, DBITS));
1235 printf ("foldpath=%s flags=%s\n",
1237 snprintb (buf, sizeof(buf), (unsigned) mp->msgflags, FBITS));
1238 printf ("hghmsg=%d lowmsg=%d nummsg=%d curmsg=%d\n",
1239 mp->hghmsg, mp->lowmsg, mp->nummsg, mp->curmsg);
1240 printf ("lowsel=%d hghsel=%d numsel=%d\n",
1241 mp->lowsel, mp->hghsel, mp->numsel);
1242 printf ("lowoff=%d hghoff=%d\n", mp->lowoff, mp->hghoff);
1245 if (seqp == 0 && (addsw || deletesw)) {
1246 advise (NULL, "-%s requires at least one -sequence argument",
1247 addsw ? "add" : "delete");
1253 for (seqp = 0; seqs[seqp]; seqp++)
1254 if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
1259 for (seqp = 0; seqs[seqp]; seqp++)
1260 if (!seq_delsel (mp, seqs[seqp], 0, zerosw))
1264 /* Listing messages in sequences */
1267 /* list the given sequences */
1268 for (seqp = 0; seqs[seqp]; seqp++)
1269 seq_print (mp, seqs[seqp]);
1271 /* else list them all */
1277 for (msgnum = mp->lowsel;
1278 msgnum <= mp->hghsel && !interrupted;
1280 if (is_selected (mp, msgnum)) {
1281 printf ("%*d: id=%d top=%d start=%ld stop=%ld %s\n",
1284 Msgs[msgnum].m_bboard_id,
1286 (long) Msgs[msgnum].m_start,
1287 (long) Msgs[msgnum].m_stop,
1288 snprintb (buf, sizeof(buf),
1289 (unsigned) mp->msgstats[msgnum - mp->lowoff],
1291 if (Msgs[msgnum].m_scanl)
1292 printf ("%s", Msgs[msgnum].m_scanl);
1298 static struct swit mhnswit[] = {
1301 #define MHNNAUTOSW 1
1303 #define MHNDEBUGSW 2
1305 #define MHNEBCDICSW 3
1306 { "ebcdicsafe", 0 },
1307 #define MHNNEBCDICSW 4
1308 { "noebcdicsafe", 0 },
1310 { "form formfile", 4 },
1313 #define MHNNHEADSW 7
1317 #define MHNNLISTSW 9
1319 #define MHNPARTSW 10
1320 { "part number", 0 },
1321 #define MHNSIZESW 11
1323 #define MHNNSIZESW 12
1324 { "norealsize", 0 },
1325 #define MHNRFC934SW 13
1326 { "rfc934mode", 0 },
1327 #define MHNNRFC934SW 14
1328 { "norfc934mode", 0 },
1329 #define MHNSERIALSW 15
1330 { "serialonly", 0 },
1331 #define MHNNSERIALSW 16
1332 { "noserialonly", 0 },
1333 #define MHNSHOWSW 17
1335 #define MHNNSHOWSW 18
1337 #define MHNSTORESW 19
1339 #define MHNNSTORESW 20
1341 #define MHNTYPESW 21
1342 { "type content", 0 },
1343 #define MHNVERBSW 22
1345 #define MHNNVERBSW 23
1347 #define MHNHELPSW 24
1349 #define MHNPROGSW 25
1350 { "moreproc program", -4 },
1351 #define MHNNPROGSW 26
1352 { "nomoreproc", -3 },
1354 { "length lines", -4 },
1356 { "width columns", -4 },
1362 mhncmd (char **args)
1364 int msgp = 0, vecp = 1;
1366 char *cp, buf[BUFSIZ];
1367 char *msgs[MAXARGS], *vec[MAXARGS];
1370 forkcmd (args, cmd_name);
1373 while ((cp = *args++)) {
1375 switch (smatch (++cp, mhnswit)) {
1377 ambigsw (cp, mhnswit);
1380 fprintf (stderr, "-%s unknown\n", cp);
1383 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1384 print_help (buf, mhnswit, 1);
1419 if (!(cp = *args++) || *cp == '-') {
1420 advise (NULL, "missing argument to %s", args[-2]);
1427 if (*cp == '+' || *cp == '@') {
1428 advise (NULL, "sorry, no folders allowed!");
1436 vec[vecp++] = "-file";
1439 msgs[msgp++] = "cur";
1440 for (msgnum = 0; msgnum < msgp; msgnum++)
1441 if (!m_convert (mp, msgs[msgnum]))
1446 for (msgnum = mp->lowsel;
1447 msgnum <= mp->hghsel && !interrupted;
1449 if (is_selected (mp, msgnum))
1450 if (process (msgnum, cmd_name, vecp, vec)) {
1451 unset_selected (mp, msgnum);
1455 seq_setcur (mp, mp->hghsel);
1459 static struct swit packswit[] = {
1467 static int mbx_style = MMDF_FORMAT;
1470 packcmd (char **args)
1472 int msgp = 0, md, msgnum;
1473 char *cp, *file = NULL;
1474 char buf[BUFSIZ], *msgs[MAXARGS];
1478 forkcmd (args, cmd_name);
1482 while ((cp = *args++)) {
1484 switch (smatch (++cp, packswit)) {
1486 ambigsw (cp, packswit);
1489 fprintf (stderr, "-%s unknown\n", cp);
1492 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1493 print_help (buf, packswit, 1);
1497 if (!(file = *args++) || *file == '-') {
1498 advise (NULL, "missing argument to %s", args[-2]);
1503 if (*cp == '+' || *cp == '@') {
1504 advise (NULL, "sorry, no folders allowed!");
1513 file = path (file, TFILE);
1514 if (stat (file, &st) == NOTOK) {
1515 if (errno != ENOENT) {
1516 advise (file, "error on file");
1519 md = getanswer (cp = concat ("Create file \"", file, "\"? ", NULL));
1526 msgs[msgp++] = "all";
1527 for (msgnum = 0; msgnum < msgp; msgnum++)
1528 if (!m_convert (mp, msgs[msgnum]))
1532 if ((md = mbx_open (file, mbx_style, getuid (), getgid (), m_gmprot ())) == NOTOK) {
1533 advise (file, "unable to open");
1536 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1537 if (is_selected (mp, msgnum))
1538 if (pack (file, md, msgnum) == NOTOK)
1540 mbx_close (file, md);
1542 if (mp->hghsel != mp->curmsg)
1543 seq_setcur (mp, mp->lowsel);
1551 pack (char *mailbox, int md, int msgnum)
1555 if (Msgs[msgnum].m_bboard_id == 0)
1558 zp = msh_ready (msgnum, 1);
1559 return mbx_write (mailbox, md, zp, Msgs[msgnum].m_bboard_id,
1560 0L, ftell (zp), Msgs[msgnum].m_stop, 1, 1);
1565 packhak (char **args)
1568 char *cp, *file = NULL;
1570 while ((cp = *args++)) {
1572 switch (smatch (++cp, packswit)) {
1579 if (!(file = *args++) || *file == '-')
1583 if (*cp == '+' || *cp == '@')
1587 file = path (file ? file : "./msgbox", TFILE);
1588 result = access (file, F_OK) == NOTOK ? OK : NOTOK;
1595 static struct swit pickswit[] = {
1607 { "cc pattern", 0 },
1609 { "date pattern", 0 },
1611 { "from pattern", 0 },
1613 { "search pattern", 0 },
1615 { "subject pattern", 0 },
1617 { "to pattern", 0 },
1619 { "-othercomponent pattern", 15 },
1621 { "after date", 0 },
1623 { "before date", 0 },
1625 { "datefield field", 5 },
1627 { "sequence name", 0 },
1647 pickcmd (char **args)
1649 int zerosw = 1, msgp = 0, seqp = 0;
1650 int vecp = 0, hi, lo, msgnum;
1651 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
1652 char *seqs[NUMATTRS], *vec[MAXARGS];
1655 while ((cp = *args++)) {
1661 switch (smatch (cp, pickswit)) {
1663 ambigsw (cp, pickswit);
1666 fprintf (stderr, "-%s unknown\n", cp);
1669 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1670 print_help (buf, pickswit, 1);
1684 if (!(cp = *args++)) {/* allow -xyz arguments */
1685 advise (NULL, "missing argument to %s", args[-2]);
1691 advise (NULL, "internal error!");
1702 if (!(cp = *args++) || *cp == '-') {
1703 advise (NULL, "missing argument to %s", args[-2]);
1706 if (seqp < NUMATTRS)
1709 advise (NULL, "only %d sequences allowed!", NUMATTRS);
1720 case PIPUSW: /* not implemented */
1727 if (*cp == '+' || *cp == '@') {
1728 advise (NULL, "sorry, no folders allowed!");
1737 msgs[msgp++] = "all";
1738 for (msgnum = 0; msgnum < msgp; msgnum++)
1739 if (!m_convert (mp, msgs[msgnum]))
1744 if (!pcompile (vec, NULL))
1750 for (msgnum = mp->lowsel;
1751 msgnum <= mp->hghsel && !interrupted;
1753 if (is_selected (mp, msgnum)) {
1754 zp = msh_ready (msgnum, 1);
1755 if (pmatches (zp, msgnum, fmsh ? 0L : Msgs[msgnum].m_start,
1756 fmsh ? 0L : Msgs[msgnum].m_stop)) {
1763 unset_selected (mp, msgnum);
1774 if (mp->numsel <= 0) {
1775 advise (NULL, "no messages match specification");
1780 for (seqp = 0; seqs[seqp]; seqp++)
1781 if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
1784 printf ("%d hit%s\n", mp->numsel, mp->numsel == 1 ? "" : "s");
1788 static struct swit replswit[] = {
1792 { "noannotate", 0 },
1798 { "draftfolder +folder", 0 },
1800 { "draftmessage msg", 0 },
1802 { "nodraftfolder", 0 },
1804 { "editor editor", 0 },
1808 { "fcc +folder", 0 },
1810 { "filter filterfile", 0 },
1812 { "form formfile", 0 },
1822 { "whatnowproc program", 0 },
1826 { "width columns", 0 },
1834 replcmd (char **args)
1837 char *cp, *msg = NULL;
1838 char buf[BUFSIZ], *vec[MAXARGS];
1841 forkcmd (args, cmd_name);
1845 while ((cp = *args++)) {
1847 switch (smatch (++cp, replswit)) {
1849 ambigsw (cp, replswit);
1852 fprintf (stderr, "-%s unknown\n", cp);
1855 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1856 print_help (buf, replswit, 1);
1859 case REANSW: /* not implemented */
1884 if (!(cp = *args++) || *cp == '-') {
1885 advise (NULL, "missing argument to %s", args[-2]);
1891 if (*cp == '+' || *cp == '@') {
1892 advise (NULL, "sorry, no folders allowed!");
1897 advise (NULL, "only one message at a time!");
1905 vec[vecp++] = "-file";
1909 if (!m_convert (mp, msg))
1913 if (mp->numsel > 1) {
1914 advise (NULL, "only one message at a time!");
1917 process (mp->hghsel, cmd_name, vecp, vec);
1918 seq_setcur (mp, mp->hghsel);
1922 static struct swit rmmswit[] = {
1930 rmmcmd (char **args)
1932 int msgp = 0, msgnum;
1933 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
1935 while ((cp = *args++)) {
1937 switch (smatch (++cp, rmmswit)) {
1939 ambigsw (cp, rmmswit);
1942 fprintf (stderr, "-%s unknown\n", cp);
1945 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1946 print_help (buf, rmmswit, 1);
1949 if (*cp == '+' || *cp == '@') {
1950 advise (NULL, "sorry, no folders allowed!");
1958 msgs[msgp++] = "cur";
1959 for (msgnum = 0; msgnum < msgp; msgnum++)
1960 if (!m_convert (mp, msgs[msgnum]))
1971 register int msgnum, vecp;
1973 char buffer[BUFSIZ], *vec[MAXARGS];
1977 if (mp->numsel > MAXARGS - 1) {
1978 advise (NULL, "more than %d messages for %s exec",
1979 MAXARGS - 1, rmmproc);
1983 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1984 if (is_selected (mp, msgnum))
1985 vec[vecp++] = getcpy (m_name (msgnum));
1987 forkcmd (vec, rmmproc);
1988 for (vecp = 0; vec[vecp]; vecp++)
1992 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1993 if (is_selected (mp, msgnum)) {
1994 strncpy (buffer, m_backup (cp = m_name (msgnum)), sizeof(buffer));
1995 if (rename (cp, buffer) == NOTOK)
1996 admonish (buffer, "unable to rename %s to", cp);
2000 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
2001 if (is_selected (mp, msgnum)) {
2002 set_deleted (mp, msgnum);
2003 unset_exists (mp, msgnum);
2006 if (pmsh && pop_dele (msgnum) != OK)
2007 fprintf (stderr, "%s", response);
2012 if ((mp->nummsg -= mp->numsel) <= 0) {
2014 admonish (NULL, "no messages remaining in +%s", fmsh);
2016 admonish (NULL, "no messages remaining in %s", mp->foldpath);
2017 mp->lowmsg = mp->hghmsg = mp->nummsg = 0;
2019 if (mp->lowsel == mp->lowmsg) {
2020 for (msgnum = mp->lowmsg + 1; msgnum <= mp->hghmsg; msgnum++)
2021 if (does_exist (mp, msgnum))
2023 mp->lowmsg = msgnum;
2025 if (mp->hghsel == mp->hghmsg) {
2026 for (msgnum = mp->hghmsg - 1; msgnum >= mp->lowmsg; msgnum--)
2027 if (does_exist (mp, msgnum))
2029 mp->hghmsg = msgnum;
2032 mp->msgflags |= MODIFIED;
2037 static struct swit scanswit[] = {
2043 { "form formatfile", 0 },
2045 { "format string", 5 },
2051 { "width columns", 0 },
2059 scancmd (char **args)
2061 #define equiv(a,b) (a ? b && !strcmp (a, b) : !b)
2063 int clearsw = 0, headersw = 0, width = 0, msgp = 0;
2064 int msgnum, optim, state;
2065 char *cp, *form = NULL, *format = NULL;
2066 char buf[BUFSIZ], *nfs, *msgs[MAXARGS];
2070 static int p_optim = 0;
2073 static int s_optim = 0;
2074 static char *s_form = NULL, *s_format = NULL;
2076 while ((cp = *args++)) {
2078 switch (smatch (++cp, scanswit)) {
2080 ambigsw (cp, scanswit);
2083 fprintf (stderr, "-%s unknown\n", cp);
2086 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
2087 print_help (buf, scanswit, 1);
2103 if (!(form = *args++) || *form == '-') {
2104 advise (NULL, "missing argument to %s", args[-2]);
2110 if (!(format = *args++) || *format == '-') {
2111 advise (NULL, "missing argument to %s", args[-2]);
2117 if (!(cp = *args++) || *cp == '-') {
2118 advise (NULL, "missing argument to %s", args[-2]);
2124 if (*cp == '+' || *cp == '@') {
2125 advise (NULL, "sorry, no folders allowed!");
2133 msgs[msgp++] = "all";
2134 for (msgnum = 0; msgnum < msgp; msgnum++)
2135 if (!m_convert (mp, msgs[msgnum]))
2139 /* Get new format string */
2140 nfs = new_fs (form, format, FORMAT);
2142 /* force scansbr to (re)compile format */
2149 s_optim = optim = 1;
2150 s_form = form ? getcpy (form) : NULL;
2151 s_format = format ? getcpy (format) : NULL;
2160 width = sc_width ();
2162 for (dp = nfs, i = 0; *dp; dp++, i++)
2163 if (*dp == '\\' || *dp == '"' || *dp == '\n')
2166 ep = mh_xmalloc ((unsigned) i);
2167 for (dp = nfs, fp = ep; *dp; dp++) {
2169 *fp++ = '\\', *fp++ = 'n';
2172 if (*dp == '"' || *dp == '\\')
2178 if (pop_command ("XTND SCAN %d \"%s\"", width, ep) == OK)
2187 optim = equiv (s_form, form) && equiv (s_format, format);
2191 if (p_optim && optim) {
2192 for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++)
2193 if (!is_selected(mp, msgnum) || Msgs[msgnum].m_scanl)
2195 if (msgnum > mp->hghmsg && pop_command ("LIST") == OK) {
2196 fprintf (stderr, "Stand-by...");
2202 switch (pop_multiline ()) {
2204 fprintf (stderr, "%s", response);
2207 fprintf (stderr,"\n");
2211 if (sscanf (response, "%d %d", &msgnum, &size) == 2
2212 && mp->lowmsg <= msgnum
2213 && msgnum <= mp->hghmsg
2214 && (cp = strchr(response, '#'))
2216 Msgs[msgnum].m_scanl = concat (cp, "\n", NULL);
2227 for (msgnum = mp->lowsel;
2228 msgnum <= mp->hghsel && !interrupted;
2230 if (is_selected (mp, msgnum)) {
2231 if (optim && Msgs[msgnum].m_scanl)
2232 printf ("%s", Msgs[msgnum].m_scanl);
2238 && is_virtual (mp, msgnum)
2239 && pop_command ("LIST %d", msgnum) == OK
2240 && (cp = strchr(response, '#'))
2242 Msgs[msgnum].m_scanl = concat (cp, "\n", NULL);
2243 printf ("%s", Msgs[msgnum].m_scanl);
2249 zp = msh_ready (msgnum, 0);
2250 switch (state = scan (zp, msgnum, 0, nfs, width,
2251 msgnum == mp->curmsg,
2252 is_unseen (mp, msgnum),
2253 headersw ? (fmsh ? fmsh : mp->foldpath) : NULL,
2254 fmsh ? 0L : (long) (Msgs[msgnum].m_stop - Msgs[msgnum].m_start),
2260 Msgs[msgnum].m_scanl = getcpy (scanl);
2264 advise (NULL, "scan() botch (%d)", state);
2268 printf ("%*d empty\n", DMAXFOLDER, msgnum);
2280 static struct swit showswit[] = {
2284 { "form formfile", 4 },
2286 { "moreproc program", 4 },
2288 { "nomoreproc", 3 },
2290 { "length lines", 4 },
2292 { "width columns", 4 },
2294 { "showproc program", 4 },
2296 { "noshowproc", 3 },
2308 showcmd (char **args)
2310 int headersw = 1, nshow = 0, msgp = 0, vecp = 1;
2311 int mhl = 0, seqnum = -1, mode = 0, i, msgnum;
2312 char *cp, *proc = showproc, buf[BUFSIZ];
2313 char *msgs[MAXARGS], *vec[MAXARGS];
2315 if (!mh_strcasecmp (cmd_name, "next"))
2318 if (!mh_strcasecmp (cmd_name, "prev"))
2320 while ((cp = *args++)) {
2322 switch (i = smatch (++cp, showswit)) {
2324 ambigsw (cp, showswit);
2331 snprintf (buf, sizeof(buf), "%s %s[switches] [switches for showproc]",
2332 cmd_name, mode ? NULL : "[msgs] ");
2333 print_help (buf, showswit, 1);
2341 if (!(cp = *args++) || *cp == '-') {
2342 advise (NULL, "missing argument to %s", args[-2]);
2354 if (!(proc = *args++) || *proc == '-') {
2355 advise (NULL, "missing argument to %s", args[-2]);
2365 advise (NULL, "sorry, -%s not allowed!", showswit[i].sw);
2368 if (*cp == '+' || *cp == '@') {
2369 advise (NULL, "sorry, no folders allowed!");
2375 "usage: %s [switches] [switches for showproc]\n",
2385 msgs[msgp++] = mode > 0 ? "next" : mode < 0 ? "prev" : "cur";
2386 for (msgnum = 0; msgnum < msgp; msgnum++)
2387 if (!m_convert (mp, msgs[msgnum]))
2391 if (!nshow && !getenv ("NOMHNPROC"))
2392 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
2393 if (is_selected (mp, msgnum) && is_nontext (msgnum)) {
2394 proc = showmimeproc;
2395 vec[vecp++] = "-file";
2403 if (strcmp (showproc, "mhl") == 0) {
2409 seqnum = seq_getnum (mp, "unseen");
2410 vec[0] = r1bindex (proc, '/');
2413 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
2414 if (is_selected (mp, msgnum)) {
2415 vec[vecp++] = getcpy (m_name (msgnum));
2417 seq_delmsg (mp, "unseen", msgnum);
2420 if (mp->numsel == 1 && headersw)
2422 mhlsbr (vecp, vec, mhl_action);
2423 m_eomsbr ((int (*)()) 0);
2428 for (msgnum = mp->lowsel;
2429 msgnum <= mp->hghsel && !interrupted;
2431 if (is_selected (mp, msgnum)) {
2432 switch (ask (msgnum)) {
2433 case NOTOK: /* QUIT */
2440 if (mp->numsel == 1 && headersw)
2443 copy_message (msgnum, stdout);
2445 process (msgnum, proc, vecp, vec);
2448 seq_delmsg (mp, "unseen", msgnum);
2455 seq_setcur (mp, mp->hghsel);
2462 if (Msgs[msgnum].m_bboard_id == 0)
2465 printf ("(Message %d", msgnum);
2466 if (Msgs[msgnum].m_bboard_id > 0)
2467 printf (", %s: %d", BBoard_ID, Msgs[msgnum].m_bboard_id);
2476 return (ftell (mhlfp) >= Msgs[mhlnum].m_stop);
2481 mhl_action (char *name)
2485 if ((msgnum = m_atoi (name)) < mp->lowmsg
2486 || msgnum > mp->hghmsg
2487 || !does_exist (mp, msgnum))
2491 mhlfp = msh_ready (msgnum, 1);
2493 m_eomsbr (eom_action);
2505 if (mp->numsel == 1 || !interactive || redirected)
2508 if (SOprintf ("Press <return> to list \"%d\"...", msgnum)) {
2509 if (mp->lowsel != msgnum)
2511 printf ("Press <return> to list \"%d\"...", msgnum);
2517 read (fileno (stdout), buf, sizeof buf);
2519 switch (setjmp (sigenv)) {
2522 read (fileno (stdout), buf, sizeof buf);/* fall... */
2530 if (strchr(buf, '\n') == NULL)
2534 told_to_quit = interrupted = 0;
2549 is_nontext (int msgnum)
2552 unsigned char *bp, *dp;
2554 char buf[BUFSIZ], name[NAMESZ];
2557 if (Msgs[msgnum].m_flags & MHNCHK)
2558 return (Msgs[msgnum].m_flags & MHNYES);
2559 Msgs[msgnum].m_flags |= MHNCHK;
2561 fp = msh_ready (msgnum, 1);
2564 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
2569 * Check Content-Type field
2571 if (!mh_strcasecmp (name, TYPE_FIELD)) {
2575 cp = add (buf, NULL);
2576 while (state == FLDPLUS) {
2577 state = m_getfld (state, name, buf, sizeof buf, fp);
2584 for (; isspace (*bp); bp++)
2589 for (bp++, i = 0;;) {
2619 for (dp = bp; istoken (*dp); dp++)
2626 if ((result = (mh_strcasecmp (bp, "plain") != 0)))
2629 for (dp++; isspace (*dp); dp++)
2632 if ((result = !uprf (dp, "charset")))
2634 dp += sizeof "charset" - 1;
2635 while (isspace (*dp))
2639 while (isspace (*dp))
2642 if ((bp = strchr(++dp, '"')))
2645 for (bp = dp; *bp; bp++)
2646 if (isspace (*bp)) {
2652 /* Default character set */
2655 /* Check the character set */
2656 result = !check_charset (dp, strlen (dp));
2658 if (!(result = (mh_strcasecmp (bp, "text") != 0))) {
2668 Msgs[msgnum].m_flags |= MHNYES;
2675 * Check Content-Transfer-Encoding field
2677 if (!mh_strcasecmp (name, ENCODING_FIELD)) {
2678 cp = add (buf, NULL);
2679 while (state == FLDPLUS) {
2680 state = m_getfld (state, name, buf, sizeof buf, fp);
2683 for (bp = cp; isspace (*bp); bp++)
2685 for (dp = bp; istoken (*dp); dp++)
2688 result = (mh_strcasecmp (bp, "7bit")
2689 && mh_strcasecmp (bp, "8bit")
2690 && mh_strcasecmp (bp, "binary"));
2694 Msgs[msgnum].m_flags |= MHNYES;
2701 * Just skip the rest of this header
2702 * field and go to next one.
2704 while (state == FLDPLUS)
2705 state = m_getfld (state, name, buf, sizeof(buf), fp);
2709 * We've passed the message header,
2710 * so message is just text.
2718 static struct swit sortswit[] = {
2720 { "datefield field", 0 },
2722 { "textfield field", 0 },
2724 { "notextfield", 0 },
2726 { "limit days", 0 },
2740 sortcmd (char **args)
2742 int msgp = 0, msgnum;
2743 char *cp, *datesw = NULL, *subjsw = NULL;
2744 char buf[BUFSIZ], *msgs[MAXARGS];
2748 forkcmd (args, cmd_name);
2752 while ((cp = *args++)) {
2754 switch (smatch (++cp, sortswit)) {
2756 ambigsw (cp, sortswit);
2759 fprintf (stderr, "-%s unknown\n", cp);
2762 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
2763 print_help (buf, sortswit, 1);
2768 advise (NULL, "only one date field at a time!");
2771 if (!(datesw = *args++) || *datesw == '-') {
2772 advise (NULL, "missing argument to %s", args[-2]);
2779 advise (NULL, "only one text field at a time!");
2782 if (!(subjsw = *args++) || *subjsw == '-') {
2783 advise (NULL, "missing argument to %s", args[-2]);
2791 case SOLIMT: /* too hard */
2792 if (!(cp = *args++) || *cp == '-') {
2793 advise (NULL, "missing argument to %s", args[-2]);
2797 case SOVERB: /* not implemented */
2801 if (*cp == '+' || *cp == '@') {
2802 advise (NULL, "sorry, no folders allowed!");
2810 msgs[msgp++] = "all";
2813 for (msgnum = 0; msgnum < msgp; msgnum++)
2814 if (!m_convert (mp, msgs[msgnum]))
2818 twscopy (&tb, dlocaltimenow ());
2820 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
2821 if (Msgs[msgnum].m_scanl) {
2822 free (Msgs[msgnum].m_scanl);
2823 Msgs[msgnum].m_scanl = NULL;
2825 if (is_selected (mp, msgnum)) {
2826 if (get_fields (datesw, subjsw, msgnum, &Msgs[msgnum]))
2827 twscopy (&Msgs[msgnum].m_tb,
2828 msgnum != mp->lowsel ? &Msgs[msgnum - 1].m_tb : &tb);
2830 else /* m_scaln is already NULL */
2831 twscopy (&Msgs[msgnum].m_tb, &tb);
2832 Msgs[msgnum].m_stats = mp->msgstats[msgnum - mp->lowoff];
2833 if (mp->curmsg == msgnum)
2834 Msgs[msgnum].m_stats |= CUR;
2837 qsort ((char *) &Msgs[mp->lowsel], mp->hghsel - mp->lowsel + 1,
2838 sizeof(struct Msg), (qsort_comp) (subjsw ? subsort : msgsort));
2840 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
2841 if (subjsw && Msgs[msgnum].m_scanl) {
2842 free (Msgs[msgnum].m_scanl); /* from subjsort */
2843 Msgs[msgnum].m_scanl = NULL;
2845 mp->msgstats[msgnum - mp->lowoff] = Msgs[msgnum].m_stats & ~CUR;
2846 if (Msgs[msgnum].m_stats & CUR)
2847 seq_setcur (mp, msgnum);
2850 mp->msgflags |= MODIFIED;
2856 * get_fields - parse message, and get date and subject if needed.
2857 * We'll use the msgp->m_tb tws struct for the date, and overload
2858 * the msgp->m_scanl field with our subject string.
2861 get_fields (char *datesw, char *subjsw, int msgnum, struct Msg *msgp)
2863 int state, gotdate = 0;
2864 char *bp, buf[BUFSIZ], name[NAMESZ];
2865 struct tws *tw = (struct tws *) 0;
2868 zp = msh_ready (msgnum, 0);
2869 for (state = FLD;;) {
2870 switch (state = m_getfld (state, name, buf, sizeof buf, zp)) {
2874 if (!mh_strcasecmp (name, datesw)) {
2876 while (state == FLDPLUS) {
2877 state = m_getfld (state, name, buf, sizeof buf, zp);
2880 if ((tw = dparsetime (bp)) == NULL)
2882 "unable to parse %s field in message %d",
2885 twscopy (&(msgp->m_tb), tw);
2887 if (!subjsw) /* not using this, or already done */
2888 break; /* all done! */
2891 else if (subjsw && !mh_strcasecmp(name, subjsw)) {
2893 while (state == FLDPLUS) {
2894 state = m_getfld (state, name, buf, sizeof buf, zp);
2897 msgp->m_scanl = sosmash(subjsw, bp);
2899 break; /* date done so we're done */
2901 subjsw = (char *)0;/* subject done, need date */
2903 while (state == FLDPLUS) /* flush this one */
2904 state = m_getfld (state, name, buf, sizeof buf, zp);
2915 admonish (NULL, "format error in message %d", msgnum);
2916 if (msgp->m_scanl) { /* this might need free'd */
2917 free (msgp->m_scanl); /* probably can't use subj anyway */
2918 msgp->m_scanl = NULL;
2923 adios (NULL, "internal error -- you lose");
2928 return OK; /* not an error if subj not found */
2930 admonish (NULL, "no %s field in message %d", datesw, msgnum);
2931 return NOTOK; /* NOTOK means use some other date */
2940 msgsort (struct Msg *a, struct Msg *b)
2942 return twsort (&a->m_tb, &b->m_tb);
2947 subsort (struct Msg *a, struct Msg *b)
2951 if (a->m_scanl && b->m_scanl)
2952 if ((i = strcmp (a->m_scanl, b->m_scanl)))
2955 return twsort (&a->m_tb, &b->m_tb);
2960 * try to make the subject "canonical": delete leading "re:", everything
2961 * but letters & smash letters to lower case.
2964 sosmash (char *subj, char *s)
2966 register char *cp, *dp;
2967 register unsigned char c;
2971 dp = s; /* dst pointer */
2972 if (!mh_strcasecmp (subj, "subject"))
2979 *dp++ = isupper(c) ? tolower(c) : c;
2985 while ((c = *cp++)) {
2987 *dp++ = isupper(c) ? tolower(c) : c;
2997 process (int msgnum, char *proc, int vecp, char **vec)
2999 int child_id, status;
3000 char tmpfil[BUFSIZ];
3005 strncpy (tmpfil, m_name (msgnum), sizeof(tmpfil));
3006 context_del (pfolder);
3007 context_replace (pfolder, fmsh);/* update current folder */
3009 context_save (); /* save the context file */
3013 cp = m_mktemp(invo_name, NULL, &out);
3015 /* Try again, but try to create under /tmp */
3017 cp = m_mktemp2(NULL, invo_name, NULL, &out);
3020 advise (NULL, "unable to create temporary file");
3024 copy_message (msgnum, out);
3026 strncpy(tmpfil, cp, sizeof(tmpfil));
3030 switch (child_id = fork ()) {
3032 advise ("fork", "unable to");
3038 SIGNAL (SIGINT, istat);
3039 SIGNAL (SIGQUIT, qstat);
3041 vec[vecp++] = tmpfil;
3045 fprintf (stderr, "unable to exec ");
3050 status = pidXwait (child_id, NULL);
3061 copy_message (int msgnum, FILE *out)
3064 static char buffer[BUFSIZ];
3067 zp = msh_ready (msgnum, 1);
3069 while (fgets (buffer, sizeof buffer, zp) != NULL) {
3070 fputs (buffer, out);
3071 if (interrupted && out == stdout)
3077 while (fgets (buffer, sizeof buffer, zp) != NULL
3078 && pos < Msgs[msgnum].m_stop) {
3079 fputs (buffer, out);
3080 pos += (long) strlen (buffer);
3081 if (interrupted && out == stdout)
3089 copy_digest (int msgnum, FILE *out)
3093 static char buffer[BUFSIZ];
3097 zp = msh_ready (msgnum, 1);
3100 while (fgets (buffer, sizeof buffer, zp) != NULL
3101 && !fmsh && pos < Msgs[msgnum].m_stop) {
3102 if (c == '\n' && *buffer == '-')
3104 fputs (buffer, out);
3105 c = buffer[strlen (buffer) - 1];
3107 pos += (long) strlen (buffer);
3108 if (interrupted && out == stdout)