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 (""));
596 cp = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
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 ? path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF)
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];
872 forkcmd (args, cmd_name);
876 while ((cp = *args++)) {
878 switch (smatch (++cp, forwswit)) {
880 ambigsw (cp, forwswit);
883 fprintf (stderr, "-%s unknown\n", cp);
886 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
887 print_help (buf, forwswit, 1);
890 case FOANSW: /* not implemented */
910 if (!(cp = *args++) || *cp == '-') {
911 advise (NULL, "missing argument to %s", args[-2]);
917 if (!(filter = *args++) || *filter == '-') {
918 advise (NULL, "missing argument to %s", args[-2]);
923 if (access (filter = myfilter, R_OK) == NOTOK) {
924 advise (filter, "unable to read default filter file");
932 if (*cp == '+' || *cp == '@') {
933 advise (NULL, "sorry, no folders allowed!");
940 /* foil search of .mh_profile */
941 snprintf (buf, sizeof(buf), "%sXXXXXX", invo_name);
943 Mkstemp work postponed until later -Doug
945 vec[0] = (char *)mkstemp (buf);
948 vec[0] = (char *)mktemp (buf);
952 vec[vecp++] = "-file";
955 msgs[msgp++] = "cur";
956 for (msgnum = 0; msgnum < msgp; msgnum++)
957 if (!m_convert (mp, msgs[msgnum]))
962 strncpy (buf, filter, sizeof(buf));
963 if (expand (buf) == NOTOK)
965 if (access (filter = getcpy (etcpath (buf)), R_OK) == NOTOK) {
966 advise (filter, "unable to read");
971 forw (cmd_name, filter, vecp, vec);
972 seq_setcur (mp, mp->hghsel);
979 forw (char *proc, char *filter, int vecp, char **vec)
981 int i, child_id, msgnum, msgcnt;
982 char tmpfil[80], *args[MAXARGS];
985 strncpy (tmpfil, m_tmpfil (invo_name), sizeof(tmpfil));
988 switch (child_id = fork ()) {
990 advise ("fork", "unable to");
993 case OK: /* "trust me" */
994 if (freopen (tmpfil, "w", stdout) == NULL) {
995 fprintf (stderr, "unable to create ");
999 args[0] = r1bindex (mhlproc, '/');
1001 args[i++] = "-forwall";
1002 args[i++] = "-form";
1004 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1005 if (is_selected (mp, msgnum))
1006 args[i++] = getcpy (m_name (msgnum));
1008 mhlsbr (i, args, mhl_action);
1009 m_eomsbr ((int (*) ()) 0);
1014 if (pidXwait (child_id, NULL))
1019 if ((out = fopen (tmpfil, "w")) == NULL) {
1020 advise (tmpfil, "unable to create temporary file");
1025 for (msgnum = mp->lowsel;
1026 msgnum <= mp->hghsel && !interrupted;
1028 if (is_selected (mp, msgnum)) {
1029 fprintf (out, "\n\n-------");
1030 if (msgnum == mp->lowsel)
1031 fprintf (out, " Forwarded Message%s",
1032 mp->numsel > 1 ? "s" : "");
1034 fprintf (out, " Message %d", msgcnt);
1035 fprintf (out, "\n\n");
1036 copy_digest (msgnum, out);
1040 fprintf (out, "\n\n------- End of Forwarded Message%s\n",
1041 mp->numsel > 1 ? "s" : "");
1047 switch (child_id = fork ()) {
1049 advise ("fork", "unable to");
1054 SIGNAL (SIGINT, istat);
1055 SIGNAL (SIGQUIT, qstat);
1057 vec[vecp++] = tmpfil;
1061 fprintf (stderr, "unable to exec ");
1066 pidXwait (child_id, NULL);
1074 static char *hlpmsg[] = {
1075 "The %s program emulates many of the commands found in the nmh",
1076 "system. Instead of operating on nmh folders, commands to %s concern",
1079 "To see the list of commands available, just type a ``?'' followed by",
1080 "the RETURN key. To find out what switches each command takes, type",
1081 "the name of the command followed by ``-help''. To leave %s, use the",
1082 "``quit'' command.",
1084 "Although a lot of nmh commands are found in %s, not all are fully",
1085 "implemented. %s will always recognize all legal switches for a",
1086 "given command though, and will let you know when you ask for an",
1087 "option that it is unable to perform.",
1089 "Running %s is fun, but using nmh from your shell is far superior.",
1090 "After you have familiarized yourself with the nmh style by using %s,",
1091 "you should try using nmh from the shell. You can still use %s for",
1092 "message files that aren't in nmh format, such as BBoard files.",
1098 helpcmd (char **args)
1102 for (i = 0; hlpmsg[i]; i++) {
1103 printf (hlpmsg[i], invo_name);
1109 static struct swit markswit[] = {
1117 { "sequence name", 0 },
1135 markcmd (char **args)
1137 int addsw = 0, deletesw = 0, debugsw = 0;
1138 int listsw = 0, zerosw = 0, seqp = 0;
1139 int msgp = 0, msgnum;
1140 char *cp, buf[BUFSIZ];
1141 char *seqs[NUMATTRS + 1], *msgs[MAXARGS];
1143 while ((cp = *args++)) {
1145 switch (smatch (++cp, markswit)) {
1147 ambigsw (cp, markswit);
1150 fprintf (stderr, "-%s unknown\n", cp);
1153 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1154 print_help (buf, markswit, 1);
1159 deletesw = listsw = 0;
1167 addsw = deletesw = 0;
1171 if (!(cp = *args++) || *cp == '-') {
1172 advise (NULL, "missing argument to %s", args[-2]);
1175 if (seqp < NUMATTRS)
1178 advise (NULL, "only %d sequences allowed!", NUMATTRS);
1183 case MPUBSW: /* not implemented */
1199 if (*cp == '+' || *cp == '@') {
1200 advise (NULL, "sorry, no folders allowed!");
1207 if (!addsw && !deletesw && !listsw) {
1214 seqs[seqp++] = "unseen";
1218 msgs[msgp++] = "all";
1223 msgs[msgp++] = listsw ? "all" :"cur";
1224 for (msgnum = 0; msgnum < msgp; msgnum++)
1225 if (!m_convert (mp, msgs[msgnum]))
1229 printf ("invo_name=%s mypath=%s defpath=%s\n",
1230 invo_name, mypath, defpath);
1231 printf ("ctxpath=%s context flags=%s\n",
1232 ctxpath, snprintb (buf, sizeof(buf), (unsigned) ctxflags, DBITS));
1233 printf ("foldpath=%s flags=%s\n",
1235 snprintb (buf, sizeof(buf), (unsigned) mp->msgflags, FBITS));
1236 printf ("hghmsg=%d lowmsg=%d nummsg=%d curmsg=%d\n",
1237 mp->hghmsg, mp->lowmsg, mp->nummsg, mp->curmsg);
1238 printf ("lowsel=%d hghsel=%d numsel=%d\n",
1239 mp->lowsel, mp->hghsel, mp->numsel);
1240 printf ("lowoff=%d hghoff=%d\n", mp->lowoff, mp->hghoff);
1243 if (seqp == 0 && (addsw || deletesw)) {
1244 advise (NULL, "-%s requires at least one -sequence argument",
1245 addsw ? "add" : "delete");
1251 for (seqp = 0; seqs[seqp]; seqp++)
1252 if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
1257 for (seqp = 0; seqs[seqp]; seqp++)
1258 if (!seq_delsel (mp, seqs[seqp], 0, zerosw))
1262 /* Listing messages in sequences */
1265 /* list the given sequences */
1266 for (seqp = 0; seqs[seqp]; seqp++)
1267 seq_print (mp, seqs[seqp]);
1269 /* else list them all */
1275 for (msgnum = mp->lowsel;
1276 msgnum <= mp->hghsel && !interrupted;
1278 if (is_selected (mp, msgnum)) {
1279 printf ("%*d: id=%d top=%d start=%ld stop=%ld %s\n",
1282 Msgs[msgnum].m_bboard_id,
1284 (long) Msgs[msgnum].m_start,
1285 (long) Msgs[msgnum].m_stop,
1286 snprintb (buf, sizeof(buf),
1287 (unsigned) mp->msgstats[msgnum - mp->lowoff],
1289 if (Msgs[msgnum].m_scanl)
1290 printf ("%s", Msgs[msgnum].m_scanl);
1296 static struct swit mhnswit[] = {
1299 #define MHNNAUTOSW 1
1301 #define MHNDEBUGSW 2
1303 #define MHNEBCDICSW 3
1304 { "ebcdicsafe", 0 },
1305 #define MHNNEBCDICSW 4
1306 { "noebcdicsafe", 0 },
1308 { "form formfile", 4 },
1311 #define MHNNHEADSW 7
1315 #define MHNNLISTSW 9
1317 #define MHNPARTSW 10
1318 { "part number", 0 },
1319 #define MHNSIZESW 11
1321 #define MHNNSIZESW 12
1322 { "norealsize", 0 },
1323 #define MHNRFC934SW 13
1324 { "rfc934mode", 0 },
1325 #define MHNNRFC934SW 14
1326 { "norfc934mode", 0 },
1327 #define MHNSERIALSW 15
1328 { "serialonly", 0 },
1329 #define MHNNSERIALSW 16
1330 { "noserialonly", 0 },
1331 #define MHNSHOWSW 17
1333 #define MHNNSHOWSW 18
1335 #define MHNSTORESW 19
1337 #define MHNNSTORESW 20
1339 #define MHNTYPESW 21
1340 { "type content", 0 },
1341 #define MHNVERBSW 22
1343 #define MHNNVERBSW 23
1345 #define MHNHELPSW 24
1347 #define MHNPROGSW 25
1348 { "moreproc program", -4 },
1349 #define MHNNPROGSW 26
1350 { "nomoreproc", -3 },
1352 { "length lines", -4 },
1354 { "width columns", -4 },
1360 mhncmd (char **args)
1362 int msgp = 0, vecp = 1;
1364 char *cp, buf[BUFSIZ];
1365 char *msgs[MAXARGS], *vec[MAXARGS];
1368 forkcmd (args, cmd_name);
1371 while ((cp = *args++)) {
1373 switch (smatch (++cp, mhnswit)) {
1375 ambigsw (cp, mhnswit);
1378 fprintf (stderr, "-%s unknown\n", cp);
1381 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1382 print_help (buf, mhnswit, 1);
1417 if (!(cp = *args++) || *cp == '-') {
1418 advise (NULL, "missing argument to %s", args[-2]);
1425 if (*cp == '+' || *cp == '@') {
1426 advise (NULL, "sorry, no folders allowed!");
1434 vec[vecp++] = "-file";
1437 msgs[msgp++] = "cur";
1438 for (msgnum = 0; msgnum < msgp; msgnum++)
1439 if (!m_convert (mp, msgs[msgnum]))
1444 for (msgnum = mp->lowsel;
1445 msgnum <= mp->hghsel && !interrupted;
1447 if (is_selected (mp, msgnum))
1448 if (process (msgnum, cmd_name, vecp, vec)) {
1449 unset_selected (mp, msgnum);
1453 seq_setcur (mp, mp->hghsel);
1457 static struct swit packswit[] = {
1465 static int mbx_style = MMDF_FORMAT;
1468 packcmd (char **args)
1470 int msgp = 0, md, msgnum;
1471 char *cp, *file = NULL;
1472 char buf[BUFSIZ], *msgs[MAXARGS];
1476 forkcmd (args, cmd_name);
1480 while ((cp = *args++)) {
1482 switch (smatch (++cp, packswit)) {
1484 ambigsw (cp, packswit);
1487 fprintf (stderr, "-%s unknown\n", cp);
1490 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1491 print_help (buf, packswit, 1);
1495 if (!(file = *args++) || *file == '-') {
1496 advise (NULL, "missing argument to %s", args[-2]);
1501 if (*cp == '+' || *cp == '@') {
1502 advise (NULL, "sorry, no folders allowed!");
1511 file = path (file, TFILE);
1512 if (stat (file, &st) == NOTOK) {
1513 if (errno != ENOENT) {
1514 advise (file, "error on file");
1517 md = getanswer (cp = concat ("Create file \"", file, "\"? ", NULL));
1524 msgs[msgp++] = "all";
1525 for (msgnum = 0; msgnum < msgp; msgnum++)
1526 if (!m_convert (mp, msgs[msgnum]))
1530 if ((md = mbx_open (file, mbx_style, getuid (), getgid (), m_gmprot ())) == NOTOK) {
1531 advise (file, "unable to open");
1534 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1535 if (is_selected (mp, msgnum))
1536 if (pack (file, md, msgnum) == NOTOK)
1538 mbx_close (file, md);
1540 if (mp->hghsel != mp->curmsg)
1541 seq_setcur (mp, mp->lowsel);
1549 pack (char *mailbox, int md, int msgnum)
1553 if (Msgs[msgnum].m_bboard_id == 0)
1556 zp = msh_ready (msgnum, 1);
1557 return mbx_write (mailbox, md, zp, Msgs[msgnum].m_bboard_id,
1558 0L, ftell (zp), Msgs[msgnum].m_stop, 1, 1);
1563 packhak (char **args)
1566 char *cp, *file = NULL;
1568 while ((cp = *args++)) {
1570 switch (smatch (++cp, packswit)) {
1577 if (!(file = *args++) || *file == '-')
1581 if (*cp == '+' || *cp == '@')
1585 file = path (file ? file : "./msgbox", TFILE);
1586 result = access (file, F_OK) == NOTOK ? OK : NOTOK;
1593 static struct swit pickswit[] = {
1605 { "cc pattern", 0 },
1607 { "date pattern", 0 },
1609 { "from pattern", 0 },
1611 { "search pattern", 0 },
1613 { "subject pattern", 0 },
1615 { "to pattern", 0 },
1617 { "-othercomponent pattern", 15 },
1619 { "after date", 0 },
1621 { "before date", 0 },
1623 { "datefield field", 5 },
1625 { "sequence name", 0 },
1645 pickcmd (char **args)
1647 int zerosw = 1, msgp = 0, seqp = 0;
1648 int vecp = 0, hi, lo, msgnum;
1649 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
1650 char *seqs[NUMATTRS], *vec[MAXARGS];
1653 while ((cp = *args++)) {
1659 switch (smatch (cp, pickswit)) {
1661 ambigsw (cp, pickswit);
1664 fprintf (stderr, "-%s unknown\n", cp);
1667 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1668 print_help (buf, pickswit, 1);
1682 if (!(cp = *args++)) {/* allow -xyz arguments */
1683 advise (NULL, "missing argument to %s", args[-2]);
1689 advise (NULL, "internal error!");
1700 if (!(cp = *args++) || *cp == '-') {
1701 advise (NULL, "missing argument to %s", args[-2]);
1704 if (seqp < NUMATTRS)
1707 advise (NULL, "only %d sequences allowed!", NUMATTRS);
1718 case PIPUSW: /* not implemented */
1725 if (*cp == '+' || *cp == '@') {
1726 advise (NULL, "sorry, no folders allowed!");
1735 msgs[msgp++] = "all";
1736 for (msgnum = 0; msgnum < msgp; msgnum++)
1737 if (!m_convert (mp, msgs[msgnum]))
1742 if (!pcompile (vec, NULL))
1748 for (msgnum = mp->lowsel;
1749 msgnum <= mp->hghsel && !interrupted;
1751 if (is_selected (mp, msgnum)) {
1752 zp = msh_ready (msgnum, 1);
1753 if (pmatches (zp, msgnum, fmsh ? 0L : Msgs[msgnum].m_start,
1754 fmsh ? 0L : Msgs[msgnum].m_stop)) {
1761 unset_selected (mp, msgnum);
1772 if (mp->numsel <= 0) {
1773 advise (NULL, "no messages match specification");
1778 for (seqp = 0; seqs[seqp]; seqp++)
1779 if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
1782 printf ("%d hit%s\n", mp->numsel, mp->numsel == 1 ? "" : "s");
1786 static struct swit replswit[] = {
1790 { "noannotate", 0 },
1796 { "draftfolder +folder", 0 },
1798 { "draftmessage msg", 0 },
1800 { "nodraftfolder", 0 },
1802 { "editor editor", 0 },
1806 { "fcc +folder", 0 },
1808 { "filter filterfile", 0 },
1810 { "form formfile", 0 },
1820 { "whatnowproc program", 0 },
1824 { "width columns", 0 },
1832 replcmd (char **args)
1835 char *cp, *msg = NULL;
1836 char buf[BUFSIZ], *vec[MAXARGS];
1839 forkcmd (args, cmd_name);
1843 while ((cp = *args++)) {
1845 switch (smatch (++cp, replswit)) {
1847 ambigsw (cp, replswit);
1850 fprintf (stderr, "-%s unknown\n", cp);
1853 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1854 print_help (buf, replswit, 1);
1857 case REANSW: /* not implemented */
1882 if (!(cp = *args++) || *cp == '-') {
1883 advise (NULL, "missing argument to %s", args[-2]);
1889 if (*cp == '+' || *cp == '@') {
1890 advise (NULL, "sorry, no folders allowed!");
1895 advise (NULL, "only one message at a time!");
1903 vec[vecp++] = "-file";
1907 if (!m_convert (mp, msg))
1911 if (mp->numsel > 1) {
1912 advise (NULL, "only one message at a time!");
1915 process (mp->hghsel, cmd_name, vecp, vec);
1916 seq_setcur (mp, mp->hghsel);
1920 static struct swit rmmswit[] = {
1928 rmmcmd (char **args)
1930 int msgp = 0, msgnum;
1931 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
1933 while ((cp = *args++)) {
1935 switch (smatch (++cp, rmmswit)) {
1937 ambigsw (cp, rmmswit);
1940 fprintf (stderr, "-%s unknown\n", cp);
1943 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1944 print_help (buf, rmmswit, 1);
1947 if (*cp == '+' || *cp == '@') {
1948 advise (NULL, "sorry, no folders allowed!");
1956 msgs[msgp++] = "cur";
1957 for (msgnum = 0; msgnum < msgp; msgnum++)
1958 if (!m_convert (mp, msgs[msgnum]))
1969 register int msgnum, vecp;
1971 char buffer[BUFSIZ], *vec[MAXARGS];
1975 if (mp->numsel > MAXARGS - 1) {
1976 advise (NULL, "more than %d messages for %s exec",
1977 MAXARGS - 1, rmmproc);
1981 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1982 if (is_selected (mp, msgnum))
1983 vec[vecp++] = getcpy (m_name (msgnum));
1985 forkcmd (vec, rmmproc);
1986 for (vecp = 0; vec[vecp]; vecp++)
1990 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1991 if (is_selected (mp, msgnum)) {
1992 strncpy (buffer, m_backup (cp = m_name (msgnum)), sizeof(buffer));
1993 if (rename (cp, buffer) == NOTOK)
1994 admonish (buffer, "unable to rename %s to", cp);
1998 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1999 if (is_selected (mp, msgnum)) {
2000 set_deleted (mp, msgnum);
2001 unset_exists (mp, msgnum);
2004 if (pmsh && pop_dele (msgnum) != OK)
2005 fprintf (stderr, "%s", response);
2010 if ((mp->nummsg -= mp->numsel) <= 0) {
2012 admonish (NULL, "no messages remaining in +%s", fmsh);
2014 admonish (NULL, "no messages remaining in %s", mp->foldpath);
2015 mp->lowmsg = mp->hghmsg = mp->nummsg = 0;
2017 if (mp->lowsel == mp->lowmsg) {
2018 for (msgnum = mp->lowmsg + 1; msgnum <= mp->hghmsg; msgnum++)
2019 if (does_exist (mp, msgnum))
2021 mp->lowmsg = msgnum;
2023 if (mp->hghsel == mp->hghmsg) {
2024 for (msgnum = mp->hghmsg - 1; msgnum >= mp->lowmsg; msgnum--)
2025 if (does_exist (mp, msgnum))
2027 mp->hghmsg = msgnum;
2030 mp->msgflags |= MODIFIED;
2035 static struct swit scanswit[] = {
2041 { "form formatfile", 0 },
2043 { "format string", 5 },
2049 { "width columns", 0 },
2057 scancmd (char **args)
2059 #define equiv(a,b) (a ? b && !strcmp (a, b) : !b)
2061 int clearsw = 0, headersw = 0, width = 0, msgp = 0;
2062 int msgnum, optim, state;
2063 char *cp, *form = NULL, *format = NULL;
2064 char buf[BUFSIZ], *nfs, *msgs[MAXARGS];
2068 static int p_optim = 0;
2071 static int s_optim = 0;
2072 static char *s_form = NULL, *s_format = NULL;
2074 while ((cp = *args++)) {
2076 switch (smatch (++cp, scanswit)) {
2078 ambigsw (cp, scanswit);
2081 fprintf (stderr, "-%s unknown\n", cp);
2084 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
2085 print_help (buf, scanswit, 1);
2101 if (!(form = *args++) || *form == '-') {
2102 advise (NULL, "missing argument to %s", args[-2]);
2108 if (!(format = *args++) || *format == '-') {
2109 advise (NULL, "missing argument to %s", args[-2]);
2115 if (!(cp = *args++) || *cp == '-') {
2116 advise (NULL, "missing argument to %s", args[-2]);
2122 if (*cp == '+' || *cp == '@') {
2123 advise (NULL, "sorry, no folders allowed!");
2131 msgs[msgp++] = "all";
2132 for (msgnum = 0; msgnum < msgp; msgnum++)
2133 if (!m_convert (mp, msgs[msgnum]))
2137 /* Get new format string */
2138 nfs = new_fs (form, format, FORMAT);
2140 /* force scansbr to (re)compile format */
2147 s_optim = optim = 1;
2148 s_form = form ? getcpy (form) : NULL;
2149 s_format = format ? getcpy (format) : NULL;
2158 width = sc_width ();
2160 for (dp = nfs, i = 0; *dp; dp++, i++)
2161 if (*dp == '\\' || *dp == '"' || *dp == '\n')
2164 ep = mh_xmalloc ((unsigned) i);
2165 for (dp = nfs, fp = ep; *dp; dp++) {
2167 *fp++ = '\\', *fp++ = 'n';
2170 if (*dp == '"' || *dp == '\\')
2176 if (pop_command ("XTND SCAN %d \"%s\"", width, ep) == OK)
2185 optim = equiv (s_form, form) && equiv (s_format, format);
2189 if (p_optim && optim) {
2190 for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++)
2191 if (!is_selected(mp, msgnum) || Msgs[msgnum].m_scanl)
2193 if (msgnum > mp->hghmsg && pop_command ("LIST") == OK) {
2194 fprintf (stderr, "Stand-by...");
2200 switch (pop_multiline ()) {
2202 fprintf (stderr, "%s", response);
2205 fprintf (stderr,"\n");
2209 if (sscanf (response, "%d %d", &msgnum, &size) == 2
2210 && mp->lowmsg <= msgnum
2211 && msgnum <= mp->hghmsg
2212 && (cp = strchr(response, '#'))
2214 Msgs[msgnum].m_scanl = concat (cp, "\n", NULL);
2225 for (msgnum = mp->lowsel;
2226 msgnum <= mp->hghsel && !interrupted;
2228 if (is_selected (mp, msgnum)) {
2229 if (optim && Msgs[msgnum].m_scanl)
2230 printf ("%s", Msgs[msgnum].m_scanl);
2236 && is_virtual (mp, msgnum)
2237 && pop_command ("LIST %d", msgnum) == OK
2238 && (cp = strchr(response, '#'))
2240 Msgs[msgnum].m_scanl = concat (cp, "\n", NULL);
2241 printf ("%s", Msgs[msgnum].m_scanl);
2247 zp = msh_ready (msgnum, 0);
2248 switch (state = scan (zp, msgnum, 0, nfs, width,
2249 msgnum == mp->curmsg,
2250 is_unseen (mp, msgnum),
2251 headersw ? (fmsh ? fmsh : mp->foldpath) : NULL,
2252 fmsh ? 0L : (long) (Msgs[msgnum].m_stop - Msgs[msgnum].m_start),
2258 Msgs[msgnum].m_scanl = getcpy (scanl);
2262 advise (NULL, "scan() botch (%d)", state);
2266 printf ("%*d empty\n", DMAXFOLDER, msgnum);
2278 static struct swit showswit[] = {
2282 { "form formfile", 4 },
2284 { "moreproc program", 4 },
2286 { "nomoreproc", 3 },
2288 { "length lines", 4 },
2290 { "width columns", 4 },
2292 { "showproc program", 4 },
2294 { "noshowproc", 3 },
2306 showcmd (char **args)
2308 int headersw = 1, nshow = 0, msgp = 0, vecp = 1;
2309 int mhl = 0, seqnum = -1, mode = 0, i, msgnum;
2310 char *cp, *proc = showproc, buf[BUFSIZ];
2311 char *msgs[MAXARGS], *vec[MAXARGS];
2313 if (!strcasecmp (cmd_name, "next"))
2316 if (!strcasecmp (cmd_name, "prev"))
2318 while ((cp = *args++)) {
2320 switch (i = smatch (++cp, showswit)) {
2322 ambigsw (cp, showswit);
2329 snprintf (buf, sizeof(buf), "%s %s[switches] [switches for showproc]",
2330 cmd_name, mode ? NULL : "[msgs] ");
2331 print_help (buf, showswit, 1);
2339 if (!(cp = *args++) || *cp == '-') {
2340 advise (NULL, "missing argument to %s", args[-2]);
2352 if (!(proc = *args++) || *proc == '-') {
2353 advise (NULL, "missing argument to %s", args[-2]);
2363 advise (NULL, "sorry, -%s not allowed!", showswit[i].sw);
2366 if (*cp == '+' || *cp == '@') {
2367 advise (NULL, "sorry, no folders allowed!");
2373 "usage: %s [switches] [switches for showproc]\n",
2383 msgs[msgp++] = mode > 0 ? "next" : mode < 0 ? "prev" : "cur";
2384 for (msgnum = 0; msgnum < msgp; msgnum++)
2385 if (!m_convert (mp, msgs[msgnum]))
2389 if (!nshow && !getenv ("NOMHNPROC"))
2390 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
2391 if (is_selected (mp, msgnum) && is_nontext (msgnum)) {
2392 proc = showmimeproc;
2393 vec[vecp++] = "-file";
2401 if (strcmp (showproc, "mhl") == 0) {
2407 seqnum = seq_getnum (mp, "unseen");
2408 vec[0] = r1bindex (proc, '/');
2411 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
2412 if (is_selected (mp, msgnum)) {
2413 vec[vecp++] = getcpy (m_name (msgnum));
2415 seq_delmsg (mp, "unseen", msgnum);
2418 if (mp->numsel == 1 && headersw)
2420 mhlsbr (vecp, vec, mhl_action);
2421 m_eomsbr ((int (*)()) 0);
2426 for (msgnum = mp->lowsel;
2427 msgnum <= mp->hghsel && !interrupted;
2429 if (is_selected (mp, msgnum)) {
2430 switch (ask (msgnum)) {
2431 case NOTOK: /* QUIT */
2438 if (mp->numsel == 1 && headersw)
2441 copy_message (msgnum, stdout);
2443 process (msgnum, proc, vecp, vec);
2446 seq_delmsg (mp, "unseen", msgnum);
2453 seq_setcur (mp, mp->hghsel);
2460 if (Msgs[msgnum].m_bboard_id == 0)
2463 printf ("(Message %d", msgnum);
2464 if (Msgs[msgnum].m_bboard_id > 0)
2465 printf (", %s: %d", BBoard_ID, Msgs[msgnum].m_bboard_id);
2474 return (ftell (mhlfp) >= Msgs[mhlnum].m_stop);
2479 mhl_action (char *name)
2483 if ((msgnum = m_atoi (name)) < mp->lowmsg
2484 || msgnum > mp->hghmsg
2485 || !does_exist (mp, msgnum))
2489 mhlfp = msh_ready (msgnum, 1);
2491 m_eomsbr (eom_action);
2503 if (mp->numsel == 1 || !interactive || redirected)
2506 if (SOprintf ("Press <return> to list \"%d\"...", msgnum)) {
2507 if (mp->lowsel != msgnum)
2509 printf ("Press <return> to list \"%d\"...", msgnum);
2515 read (fileno (stdout), buf, sizeof buf);
2517 switch (setjmp (sigenv)) {
2520 read (fileno (stdout), buf, sizeof buf);/* fall... */
2528 if (strchr(buf, '\n') == NULL)
2532 told_to_quit = interrupted = 0;
2547 is_nontext (int msgnum)
2551 char buf[BUFSIZ], name[NAMESZ];
2554 if (Msgs[msgnum].m_flags & MHNCHK)
2555 return (Msgs[msgnum].m_flags & MHNYES);
2556 Msgs[msgnum].m_flags |= MHNCHK;
2558 fp = msh_ready (msgnum, 1);
2561 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
2566 * Check Content-Type field
2568 if (!strcasecmp (name, TYPE_FIELD)) {
2572 cp = add (buf, NULL);
2573 while (state == FLDPLUS) {
2574 state = m_getfld (state, name, buf, sizeof buf, fp);
2581 for (; isspace (*bp); bp++)
2586 for (bp++, i = 0;;) {
2616 for (dp = bp; istoken (*dp); dp++)
2623 if ((result = (strcasecmp (bp, "plain") != 0)))
2626 for (dp++; isspace (*dp); dp++)
2629 if ((result = !uprf (dp, "charset")))
2631 dp += sizeof "charset" - 1;
2632 while (isspace (*dp))
2636 while (isspace (*dp))
2639 if ((bp = strchr(++dp, '"')))
2642 for (bp = dp; *bp; bp++)
2643 if (isspace (*bp)) {
2649 /* Default character set */
2652 /* Check the character set */
2653 result = !check_charset (dp, strlen (dp));
2655 if (!(result = (strcasecmp (bp, "text") != 0))) {
2665 Msgs[msgnum].m_flags |= MHNYES;
2672 * Check Content-Transfer-Encoding field
2674 if (!strcasecmp (name, ENCODING_FIELD)) {
2675 cp = add (buf, NULL);
2676 while (state == FLDPLUS) {
2677 state = m_getfld (state, name, buf, sizeof buf, fp);
2680 for (bp = cp; isspace (*bp); bp++)
2682 for (dp = bp; istoken (*dp); dp++)
2685 result = (strcasecmp (bp, "7bit")
2686 && strcasecmp (bp, "8bit")
2687 && strcasecmp (bp, "binary"));
2691 Msgs[msgnum].m_flags |= MHNYES;
2698 * Just skip the rest of this header
2699 * field and go to next one.
2701 while (state == FLDPLUS)
2702 state = m_getfld (state, name, buf, sizeof(buf), fp);
2706 * We've passed the message header,
2707 * so message is just text.
2715 static struct swit sortswit[] = {
2717 { "datefield field", 0 },
2719 { "textfield field", 0 },
2721 { "notextfield", 0 },
2723 { "limit days", 0 },
2737 sortcmd (char **args)
2739 int msgp = 0, msgnum;
2740 char *cp, *datesw = NULL, *subjsw = NULL;
2741 char buf[BUFSIZ], *msgs[MAXARGS];
2745 forkcmd (args, cmd_name);
2749 while ((cp = *args++)) {
2751 switch (smatch (++cp, sortswit)) {
2753 ambigsw (cp, sortswit);
2756 fprintf (stderr, "-%s unknown\n", cp);
2759 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
2760 print_help (buf, sortswit, 1);
2765 advise (NULL, "only one date field at a time!");
2768 if (!(datesw = *args++) || *datesw == '-') {
2769 advise (NULL, "missing argument to %s", args[-2]);
2776 advise (NULL, "only one text field at a time!");
2779 if (!(subjsw = *args++) || *subjsw == '-') {
2780 advise (NULL, "missing argument to %s", args[-2]);
2788 case SOLIMT: /* too hard */
2789 if (!(cp = *args++) || *cp == '-') {
2790 advise (NULL, "missing argument to %s", args[-2]);
2794 case SOVERB: /* not implemented */
2798 if (*cp == '+' || *cp == '@') {
2799 advise (NULL, "sorry, no folders allowed!");
2807 msgs[msgp++] = "all";
2810 for (msgnum = 0; msgnum < msgp; msgnum++)
2811 if (!m_convert (mp, msgs[msgnum]))
2815 twscopy (&tb, dlocaltimenow ());
2817 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
2818 if (Msgs[msgnum].m_scanl) {
2819 free (Msgs[msgnum].m_scanl);
2820 Msgs[msgnum].m_scanl = NULL;
2822 if (is_selected (mp, msgnum)) {
2823 if (get_fields (datesw, subjsw, msgnum, &Msgs[msgnum]))
2824 twscopy (&Msgs[msgnum].m_tb,
2825 msgnum != mp->lowsel ? &Msgs[msgnum - 1].m_tb : &tb);
2827 else /* m_scaln is already NULL */
2828 twscopy (&Msgs[msgnum].m_tb, &tb);
2829 Msgs[msgnum].m_stats = mp->msgstats[msgnum - mp->lowoff];
2830 if (mp->curmsg == msgnum)
2831 Msgs[msgnum].m_stats |= CUR;
2834 qsort ((char *) &Msgs[mp->lowsel], mp->hghsel - mp->lowsel + 1,
2835 sizeof(struct Msg), (qsort_comp) (subjsw ? subsort : msgsort));
2837 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
2838 if (subjsw && Msgs[msgnum].m_scanl) {
2839 free (Msgs[msgnum].m_scanl); /* from subjsort */
2840 Msgs[msgnum].m_scanl = NULL;
2842 mp->msgstats[msgnum - mp->lowoff] = Msgs[msgnum].m_stats & ~CUR;
2843 if (Msgs[msgnum].m_stats & CUR)
2844 seq_setcur (mp, msgnum);
2847 mp->msgflags |= MODIFIED;
2853 * get_fields - parse message, and get date and subject if needed.
2854 * We'll use the msgp->m_tb tws struct for the date, and overload
2855 * the msgp->m_scanl field with our subject string.
2858 get_fields (char *datesw, char *subjsw, int msgnum, struct Msg *msgp)
2860 int state, gotdate = 0;
2861 char *bp, buf[BUFSIZ], name[NAMESZ];
2862 struct tws *tw = (struct tws *) 0;
2865 zp = msh_ready (msgnum, 0);
2866 for (state = FLD;;) {
2867 switch (state = m_getfld (state, name, buf, sizeof buf, zp)) {
2871 if (!strcasecmp (name, datesw)) {
2873 while (state == FLDPLUS) {
2874 state = m_getfld (state, name, buf, sizeof buf, zp);
2877 if ((tw = dparsetime (bp)) == NULL)
2879 "unable to parse %s field in message %d",
2882 twscopy (&(msgp->m_tb), tw);
2884 if (!subjsw) /* not using this, or already done */
2885 break; /* all done! */
2888 else if (subjsw && !strcasecmp(name, subjsw)) {
2890 while (state == FLDPLUS) {
2891 state = m_getfld (state, name, buf, sizeof buf, zp);
2894 msgp->m_scanl = sosmash(subjsw, bp);
2896 break; /* date done so we're done */
2898 subjsw = (char *)0;/* subject done, need date */
2900 while (state == FLDPLUS) /* flush this one */
2901 state = m_getfld (state, name, buf, sizeof buf, zp);
2912 admonish (NULL, "format error in message %d", msgnum);
2913 if (msgp->m_scanl) { /* this might need free'd */
2914 free (msgp->m_scanl); /* probably can't use subj anyway */
2915 msgp->m_scanl = NULL;
2920 adios (NULL, "internal error -- you lose");
2925 return OK; /* not an error if subj not found */
2927 admonish (NULL, "no %s field in message %d", datesw, msgnum);
2928 return NOTOK; /* NOTOK means use some other date */
2937 msgsort (struct Msg *a, struct Msg *b)
2939 return twsort (&a->m_tb, &b->m_tb);
2944 subsort (struct Msg *a, struct Msg *b)
2948 if (a->m_scanl && b->m_scanl)
2949 if ((i = strcmp (a->m_scanl, b->m_scanl)))
2952 return twsort (&a->m_tb, &b->m_tb);
2957 * try to make the subject "canonical": delete leading "re:", everything
2958 * but letters & smash letters to lower case.
2961 sosmash (char *subj, char *s)
2963 register char *cp, *dp, c;
2967 dp = s; /* dst pointer */
2968 if (!strcasecmp (subj, "subject"))
2975 *dp++ = isupper(c) ? tolower(c) : c;
2981 while ((c = *cp++)) {
2983 *dp++ = isupper(c) ? tolower(c) : c;
2993 process (int msgnum, char *proc, int vecp, char **vec)
2995 int child_id, status;
3000 strncpy (tmpfil, m_name (msgnum), sizeof(tmpfil));
3001 context_del (pfolder);
3002 context_replace (pfolder, fmsh);/* update current folder */
3004 context_save (); /* save the context file */
3008 strncpy (tmpfil, m_scratch ("", invo_name), sizeof(tmpfil));
3009 if ((out = fopen (tmpfil, "w")) == NULL) {
3014 strncpy (newfil, m_tmpfil (invo_name), sizeof(newfil));
3015 if ((out = fopen (newfil, "w")) == NULL) {
3017 advise (tmpfil, "unable to create temporary file");
3020 strncpy (tmpfil, newfil, sizeof(tmpfil));
3023 copy_message (msgnum, out);
3028 switch (child_id = fork ()) {
3030 advise ("fork", "unable to");
3036 SIGNAL (SIGINT, istat);
3037 SIGNAL (SIGQUIT, qstat);
3039 vec[vecp++] = tmpfil;
3043 fprintf (stderr, "unable to exec ");
3048 status = pidXwait (child_id, NULL);
3059 copy_message (int msgnum, FILE *out)
3062 static char buffer[BUFSIZ];
3065 zp = msh_ready (msgnum, 1);
3067 while (fgets (buffer, sizeof buffer, zp) != NULL) {
3068 fputs (buffer, out);
3069 if (interrupted && out == stdout)
3075 while (fgets (buffer, sizeof buffer, zp) != NULL
3076 && pos < Msgs[msgnum].m_stop) {
3077 fputs (buffer, out);
3078 pos += (long) strlen (buffer);
3079 if (interrupted && out == stdout)
3087 copy_digest (int msgnum, FILE *out)
3091 static char buffer[BUFSIZ];
3095 zp = msh_ready (msgnum, 1);
3098 while (fgets (buffer, sizeof buffer, zp) != NULL
3099 && !fmsh && pos < Msgs[msgnum].m_stop) {
3100 if (c == '\n' && *buffer == '-')
3102 fputs (buffer, out);
3103 c = buffer[strlen (buffer) - 1];
3105 pos += (long) strlen (buffer);
3106 if (interrupted && out == stdout)