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>
21 #include <h/picksbr.h>
25 static char delim3[] = "-------"; /* from burst.c */
30 #if defined(NNTP) && defined(MPOP)
37 extern char response[];
42 * Type for a compare function for qsort. This keeps
45 typedef int (*qsort_comp) (const void *, const void *);
50 void clear_screen (void); /* from termsbr.c */
51 int SOprintf (char *, ...); /* from termsbr.c */
52 int sc_width (void); /* from termsbr.c */
57 static int burst (struct Msg *, int, int, int, int);
58 static void forw (char *, char *, int, char **);
59 static void rmm (void);
60 static void show (int);
61 static int eom_action (int);
62 static FILE *mhl_action (char *);
64 static int is_nontext (int);
65 static int get_fields (char *, char *, int, struct Msg *);
66 static int msgsort (struct Msg *, struct Msg *);
67 static int subsort (struct Msg *, struct Msg *);
68 static char *sosmash (char *, char *);
69 static int process (int, char *, int, char **);
70 static void copy_message (int, FILE *);
71 static void copy_digest (int, FILE *);
74 int mhlsbr (int, char **, FILE *(*)());
77 forkcmd (char **args, char *pgm)
82 vec[0] = r1bindex (pgm, '/');
83 copyip (args, vec + 1, MAXARGS - 1);
86 context_del (pfolder);
87 context_replace (pfolder, fmsh);/* update current folder */
89 context_save (); /* save the context file */
92 switch (child_id = fork ()) {
94 advise ("fork", "unable to");
99 SIGNAL (SIGINT, istat);
100 SIGNAL (SIGQUIT, qstat);
103 fprintf (stderr, "unable to exec ");
108 pidXwait (child_id, NULL);
111 if (fmsh) { /* assume the worst case */
112 mp->msgflags |= MODIFIED;
118 static struct swit distswit[] = {
124 { "draftfolder +folder", 0 },
126 { "draftmessage msg", 0 },
128 { "nodraftfolder", 0 },
130 { "editor editor", 0 },
134 { "form formfile", 0 },
140 { "whatnowproc program", 0 },
142 { "nowhatnowproc", 0 },
150 distcmd (char **args)
153 char *cp, *msg = NULL;
154 char buf[BUFSIZ], *vec[MAXARGS];
157 forkcmd (args, cmd_name);
161 while ((cp = *args++)) {
163 switch (smatch (++cp, distswit)) {
165 ambigsw (cp, distswit);
168 fprintf (stderr, "-%s unknown\n", cp);
171 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
172 print_help (buf, distswit, 1);
175 case DIANSW: /* not implemented */
193 if (!(cp = *args++) || *cp == '-') {
194 advise (NULL, "missing argument to %s", args[-2]);
200 if (*cp == '+' || *cp == '@') {
201 advise (NULL, "sorry, no folders allowed!");
206 advise (NULL, "only one message at a time!");
214 vec[vecp++] = "-file";
218 if (!m_convert (mp, msg))
222 if (mp->numsel > 1) {
223 advise (NULL, "only one message at a time!");
226 process (mp->hghsel, cmd_name, vecp, vec);
227 seq_setcur (mp, mp->hghsel);
231 static struct swit explswit[] = {
251 explcmd (char **args)
253 int inplace = 0, quietsw = 0, verbosw = 0;
254 int msgp = 0, hi, msgnum;
255 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
259 forkcmd (args, cmd_name);
263 while ((cp = *args++)) {
265 switch (smatch (++cp, explswit)) {
267 ambigsw (cp, explswit);
270 fprintf (stderr, "-%s unknown\n", cp);
273 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
274 print_help (buf, explswit, 1);
296 if (*cp == '+' || *cp == '@') {
297 advise (NULL, "sorry, no folders allowed!");
305 msgs[msgp++] = "cur";
306 for (msgnum = 0; msgnum < msgp; msgnum++)
307 if (!m_convert (mp, msgs[msgnum]))
311 smsgs = (struct Msg *)
312 calloc ((size_t) (MAXFOLDER + 2), sizeof *smsgs);
314 adios (NULL, "unable to allocate folder storage");
318 for (msgnum = mp->lowsel;
319 msgnum <= mp->hghsel && !interrupted;
321 if (is_selected (mp, msgnum))
322 if (burst (smsgs, msgnum, inplace, quietsw, verbosw) != OK)
325 free ((char *) smsgs);
328 seq_setcur (mp, mp->lowsel);
330 if (hi <= mp->hghmsg)
333 mp->msgflags |= MODIFIED;
339 burst (struct Msg *smsgs, int msgnum, int inplace, int quietsw, int verbosw)
341 int i, j, ld3, wasdlm, msgp;
343 char c, buffer[BUFSIZ];
346 ld3 = strlen (delim3);
348 if (Msgs[msgnum].m_scanl) {
349 free (Msgs[msgnum].m_scanl);
350 Msgs[msgnum].m_scanl = NULL;
353 pos = ftell (zp = msh_ready (msgnum, 1));
354 for (msgp = 0; msgp <= MAXFOLDER;) {
355 while (fgets (buffer, sizeof buffer, zp) != NULL
357 && pos < Msgs[msgnum].m_stop)
358 pos += (long) strlen (buffer);
359 if (feof (zp) || pos >= Msgs[msgnum].m_stop)
361 fseek (zp, pos, SEEK_SET);
362 smsgs[msgp].m_start = pos;
365 pos < Msgs[msgnum].m_stop
366 && fgets (buffer, sizeof buffer, zp) != NULL;
368 if (strncmp (buffer, delim3, ld3) == 0
369 && (msgp == 1 || c == '\n')
370 && peekc (zp) == '\n')
373 pos += (long) strlen (buffer);
375 wasdlm = strncmp (buffer, delim3, ld3) == 0;
376 if (smsgs[msgp].m_start != pos)
377 smsgs[msgp++].m_stop = (c == '\n' && wasdlm) ? pos - 1 : pos;
378 if (feof (zp) || pos >= Msgs[msgnum].m_stop) {
380 smsgs[msgp - 1].m_stop -= ((long) strlen (buffer) + 1);
383 pos += (long) strlen (buffer);
386 switch (msgp--) { /* toss "End of XXX Digest" */
388 adios (NULL, "burst() botch -- you lose big");
392 printf ("message %d not in digest format\n", msgnum);
397 printf ("%d message%s exploded from digest %d\n",
398 msgp, msgp != 1 ? "s" : "", msgnum);
402 if ((i = msgp + mp->hghmsg) > MAXFOLDER) {
403 advise (NULL, "more than %d messages", MAXFOLDER);
406 if (!(mp = folder_realloc (mp, mp->lowoff, i)))
407 adios (NULL, "unable to allocate folder storage");
412 if (mp->hghsel > msgnum)
416 for (i = mp->hghmsg; j > msgnum; i--, j--) {
418 printf ("message %d becomes message %d\n", j, i);
420 Msgs[i].m_bboard_id = Msgs[j].m_bboard_id;
421 Msgs[i].m_top = Msgs[j].m_top;
422 Msgs[i].m_start = Msgs[j].m_start;
423 Msgs[i].m_stop = Msgs[j].m_stop;
424 Msgs[i].m_scanl = NULL;
425 if (Msgs[j].m_scanl) {
426 free (Msgs[j].m_scanl);
427 Msgs[j].m_scanl = NULL;
429 copy_msg_flags (mp, i, j);
432 if (Msgs[msgnum].m_bboard_id == 0)
435 unset_selected (mp, msgnum);
436 i = inplace ? msgnum + msgp : mp->hghmsg;
437 for (j = msgp; j >= (inplace ? 0 : 1); i--, j--) {
438 if (verbosw && i != msgnum)
439 printf ("message %d of digest %d becomes message %d\n",
442 Msgs[i].m_bboard_id = Msgs[msgnum].m_bboard_id;
443 Msgs[i].m_top = Msgs[j].m_top;
444 Msgs[i].m_start = smsgs[j].m_start;
445 Msgs[i].m_stop = smsgs[j].m_stop;
446 Msgs[i].m_scanl = NULL;
447 copy_msg_flags (mp, i, msgnum);
454 static struct swit fileswit[] = {
466 { "src +folder", 0 },
470 { "rmmproc program", 0 },
480 filecmd (char **args)
482 int linksw = 0, msgp = 0;
483 int vecp = 1, i, msgnum;
484 char *cp, buf[BUFSIZ];
485 char *msgs[MAXARGS], *vec[MAXARGS];
488 forkcmd (args, cmd_name);
492 while ((cp = *args++)) {
494 switch (i = smatch (++cp, fileswit)) {
496 ambigsw (cp, fileswit);
499 fprintf (stderr, "-%s unknown\n", cp);
502 snprintf (buf, sizeof(buf), "%s +folder... [msgs] [switches]", cmd_name);
503 print_help (buf, fileswit, 1);
522 advise (NULL, "sorry, -%s not allowed!", fileswit[i].sw);
525 if (*cp == '+' || *cp == '@')
532 vec[vecp++] = "-file";
535 msgs[msgp++] = "cur";
536 for (msgnum = 0; msgnum < msgp; msgnum++)
537 if (!m_convert (mp, msgs[msgnum]))
542 for (msgnum = mp->lowsel;
543 msgnum <= mp->hghsel && !interrupted;
545 if (is_selected (mp, msgnum))
546 if (process (msgnum, fileproc, vecp, vec)) {
547 unset_selected (mp, msgnum);
551 if (mp->numsel != mp->nummsg || linksw)
552 seq_setcur (mp, mp->hghsel);
559 filehak (char **args)
561 int result, vecp = 0;
562 char *cp, *cwd, *vec[MAXARGS];
564 while ((cp = *args++)) {
566 switch (smatch (++cp, fileswit)) {
583 if (*cp == '+' || *cp == '@')
590 for (vecp = 0; (cp = vec[vecp]) && result == NOTOK; vecp++) {
592 cwd = getcpy (pwd ());
593 chdir (m_maildir (""));
595 if (access (m_maildir (cp), F_OK) == NOTOK)
606 static struct swit foldswit[] = {
644 foldcmd (char **args)
646 int fastsw = 0, headersw = 0, packsw = 0;
648 char *cp, *folder = NULL, *msg = NULL;
649 char buf[BUFSIZ], **vec = args;
654 while ((cp = *args++)) {
656 switch (smatch (++cp, foldswit)) {
658 ambigsw (cp, foldswit);
661 fprintf (stderr, "-%s unknown\n", cp);
664 snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]", cmd_name);
665 print_help (buf, foldswit, 1);
668 case FLALSW: /* not implemented */
698 if (*cp == '+' || *cp == '@') {
700 advise (NULL, "only one folder at a time!\n");
704 folder = fmsh ? pluspath (cp)
709 advise (NULL, "only one message at a time!\n");
718 advise (NULL, "null folder names are not permitted");
722 if (access (m_maildir (folder), R_OK) == NOTOK) {
723 advise (folder, "unable to read");
728 strncpy (buf, folder, sizeof(buf));
729 if (expand (buf) == NOTOK)
732 if (access (folder, R_OK) == NOTOK) {
733 advise (folder, "unable to read");
748 if (!m_convert (mp, msg))
752 if (mp->numsel > 1) {
753 advise (NULL, "only one message at a time!");
756 seq_setcur (mp, mp->hghsel);
761 forkcmd (vec, cmd_name);
765 if (mp->lowoff > 1 && !(mp = folder_realloc (mp, 1, mp->hghmsg)))
766 adios (NULL, "unable to allocate folder storage");
768 for (msgnum = mp->lowmsg, hole = 1; msgnum <= mp->hghmsg; msgnum++)
769 if (does_exist (mp, msgnum)) {
770 if (msgnum != hole) {
771 Msgs[hole].m_bboard_id = Msgs[msgnum].m_bboard_id;
772 Msgs[hole].m_top = Msgs[msgnum].m_top;
773 Msgs[hole].m_start = Msgs[msgnum].m_start;
774 Msgs[hole].m_stop = Msgs[msgnum].m_stop;
775 Msgs[hole].m_scanl = NULL;
776 if (Msgs[msgnum].m_scanl) {
777 free (Msgs[msgnum].m_scanl);
778 Msgs[msgnum].m_scanl = NULL;
780 copy_msg_flags (mp, hole, msgnum);
781 if (mp->curmsg == msgnum)
782 seq_setcur (mp, hole);
786 if (mp->nummsg > 0) {
788 mp->hghmsg = hole - 1;
790 mp->msgflags |= MODIFIED;
796 printf ("%s\n", fmsh ? fmsh : mp->foldpath);
799 printf ("\t\tFolder %*s# of messages (%*srange%*s); cur%*smsg\n",
800 DMAXFOLDER, "", DMAXFOLDER - 2, "", DMAXFOLDER - 2, "",
802 printf (args ? "%22s " : "%s ", fmsh ? fmsh : mp->foldpath);
804 /* check for empty folder */
805 if (mp->nummsg == 0) {
806 printf ("has no messages%*s",
807 mp->msgflags & OTHERS ? DMAXFOLDER * 2 + 4 : 0, "");
809 printf ("has %*d message%s (%*d-%*d)",
810 DMAXFOLDER, mp->nummsg, mp->nummsg != 1 ? "s" : "",
811 DMAXFOLDER, mp->lowmsg, DMAXFOLDER, mp->hghmsg);
812 if (mp->curmsg >= mp->lowmsg
813 && mp->curmsg <= mp->hghmsg)
814 printf ("; cur=%*d", DMAXFOLDER, mp->curmsg);
821 static struct swit forwswit[] = {
827 { "draftfolder +folder", 0 },
829 { "draftmessage msg", 0 },
831 { "nodraftfolder", 0 },
833 { "editor editor", 0 },
837 { "filter filterfile", 0 },
839 { "form formfile", 0 },
853 { "whatnowproc program", 0 },
863 forwcmd (char **args)
865 int msgp = 0, vecp = 1, msgnum;
866 char *cp, *filter = NULL, buf[BUFSIZ];
867 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 tfile = m_mktemp(buf, NULL, NULL);
944 if (tfile == NULL) adios("forwcmd", "unable to create temporary file");
945 strncpy (tmpfil, tfile, sizeof(tmpfil));
948 vec[vecp++] = "-file";
951 msgs[msgp++] = "cur";
952 for (msgnum = 0; msgnum < msgp; msgnum++)
953 if (!m_convert (mp, msgs[msgnum]))
958 strncpy (buf, filter, sizeof(buf));
959 if (expand (buf) == NOTOK)
961 if (access (filter = getcpy (etcpath (buf)), R_OK) == NOTOK) {
962 advise (filter, "unable to read");
967 forw (cmd_name, filter, vecp, vec);
968 seq_setcur (mp, mp->hghsel);
975 forw (char *proc, char *filter, int vecp, char **vec)
977 int i, child_id, msgnum, msgcnt;
978 char tmpfil[BUFSIZ], *args[MAXARGS];
982 tfile = m_mktemp2(NULL, invo_name, NULL, NULL);
983 if (tfile == NULL) adios("forw", "unable to create temporary file");
984 strncpy (tmpfil, tfile, 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 (!mh_strcasecmp (cmd_name, "next"))
2316 if (!mh_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)
2550 unsigned char *bp, *dp;
2552 char buf[BUFSIZ], name[NAMESZ];
2555 if (Msgs[msgnum].m_flags & MHNCHK)
2556 return (Msgs[msgnum].m_flags & MHNYES);
2557 Msgs[msgnum].m_flags |= MHNCHK;
2559 fp = msh_ready (msgnum, 1);
2562 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
2567 * Check Content-Type field
2569 if (!mh_strcasecmp (name, TYPE_FIELD)) {
2573 cp = add (buf, NULL);
2574 while (state == FLDPLUS) {
2575 state = m_getfld (state, name, buf, sizeof buf, fp);
2582 for (; isspace (*bp); bp++)
2587 for (bp++, i = 0;;) {
2617 for (dp = bp; istoken (*dp); dp++)
2624 if ((result = (mh_strcasecmp (bp, "plain") != 0)))
2627 for (dp++; isspace (*dp); dp++)
2630 if ((result = !uprf (dp, "charset")))
2632 dp += sizeof "charset" - 1;
2633 while (isspace (*dp))
2637 while (isspace (*dp))
2640 if ((bp = strchr(++dp, '"')))
2643 for (bp = dp; *bp; bp++)
2644 if (isspace (*bp)) {
2650 /* Default character set */
2653 /* Check the character set */
2654 result = !check_charset (dp, strlen (dp));
2656 if (!(result = (mh_strcasecmp (bp, "text") != 0))) {
2666 Msgs[msgnum].m_flags |= MHNYES;
2673 * Check Content-Transfer-Encoding field
2675 if (!mh_strcasecmp (name, ENCODING_FIELD)) {
2676 cp = add (buf, NULL);
2677 while (state == FLDPLUS) {
2678 state = m_getfld (state, name, buf, sizeof buf, fp);
2681 for (bp = cp; isspace (*bp); bp++)
2683 for (dp = bp; istoken (*dp); dp++)
2686 result = (mh_strcasecmp (bp, "7bit")
2687 && mh_strcasecmp (bp, "8bit")
2688 && mh_strcasecmp (bp, "binary"));
2692 Msgs[msgnum].m_flags |= MHNYES;
2699 * Just skip the rest of this header
2700 * field and go to next one.
2702 while (state == FLDPLUS)
2703 state = m_getfld (state, name, buf, sizeof(buf), fp);
2707 * We've passed the message header,
2708 * so message is just text.
2716 static struct swit sortswit[] = {
2718 { "datefield field", 0 },
2720 { "textfield field", 0 },
2722 { "notextfield", 0 },
2724 { "limit days", 0 },
2738 sortcmd (char **args)
2740 int msgp = 0, msgnum;
2741 char *cp, *datesw = NULL, *subjsw = NULL;
2742 char buf[BUFSIZ], *msgs[MAXARGS];
2746 forkcmd (args, cmd_name);
2750 while ((cp = *args++)) {
2752 switch (smatch (++cp, sortswit)) {
2754 ambigsw (cp, sortswit);
2757 fprintf (stderr, "-%s unknown\n", cp);
2760 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
2761 print_help (buf, sortswit, 1);
2766 advise (NULL, "only one date field at a time!");
2769 if (!(datesw = *args++) || *datesw == '-') {
2770 advise (NULL, "missing argument to %s", args[-2]);
2777 advise (NULL, "only one text field at a time!");
2780 if (!(subjsw = *args++) || *subjsw == '-') {
2781 advise (NULL, "missing argument to %s", args[-2]);
2789 case SOLIMT: /* too hard */
2790 if (!(cp = *args++) || *cp == '-') {
2791 advise (NULL, "missing argument to %s", args[-2]);
2795 case SOVERB: /* not implemented */
2799 if (*cp == '+' || *cp == '@') {
2800 advise (NULL, "sorry, no folders allowed!");
2808 msgs[msgp++] = "all";
2811 for (msgnum = 0; msgnum < msgp; msgnum++)
2812 if (!m_convert (mp, msgs[msgnum]))
2816 twscopy (&tb, dlocaltimenow ());
2818 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
2819 if (Msgs[msgnum].m_scanl) {
2820 free (Msgs[msgnum].m_scanl);
2821 Msgs[msgnum].m_scanl = NULL;
2823 if (is_selected (mp, msgnum)) {
2824 if (get_fields (datesw, subjsw, msgnum, &Msgs[msgnum]))
2825 twscopy (&Msgs[msgnum].m_tb,
2826 msgnum != mp->lowsel ? &Msgs[msgnum - 1].m_tb : &tb);
2828 else /* m_scaln is already NULL */
2829 twscopy (&Msgs[msgnum].m_tb, &tb);
2830 Msgs[msgnum].m_stats = mp->msgstats[msgnum - mp->lowoff];
2831 if (mp->curmsg == msgnum)
2832 Msgs[msgnum].m_stats |= CUR;
2835 qsort ((char *) &Msgs[mp->lowsel], mp->hghsel - mp->lowsel + 1,
2836 sizeof(struct Msg), (qsort_comp) (subjsw ? subsort : msgsort));
2838 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
2839 if (subjsw && Msgs[msgnum].m_scanl) {
2840 free (Msgs[msgnum].m_scanl); /* from subjsort */
2841 Msgs[msgnum].m_scanl = NULL;
2843 mp->msgstats[msgnum - mp->lowoff] = Msgs[msgnum].m_stats & ~CUR;
2844 if (Msgs[msgnum].m_stats & CUR)
2845 seq_setcur (mp, msgnum);
2848 mp->msgflags |= MODIFIED;
2854 * get_fields - parse message, and get date and subject if needed.
2855 * We'll use the msgp->m_tb tws struct for the date, and overload
2856 * the msgp->m_scanl field with our subject string.
2859 get_fields (char *datesw, char *subjsw, int msgnum, struct Msg *msgp)
2861 int state, gotdate = 0;
2862 char *bp, buf[BUFSIZ], name[NAMESZ];
2863 struct tws *tw = (struct tws *) 0;
2866 zp = msh_ready (msgnum, 0);
2867 for (state = FLD;;) {
2868 switch (state = m_getfld (state, name, buf, sizeof buf, zp)) {
2872 if (!mh_strcasecmp (name, datesw)) {
2874 while (state == FLDPLUS) {
2875 state = m_getfld (state, name, buf, sizeof buf, zp);
2878 if ((tw = dparsetime (bp)) == NULL)
2880 "unable to parse %s field in message %d",
2883 twscopy (&(msgp->m_tb), tw);
2885 if (!subjsw) /* not using this, or already done */
2886 break; /* all done! */
2889 else if (subjsw && !mh_strcasecmp(name, subjsw)) {
2891 while (state == FLDPLUS) {
2892 state = m_getfld (state, name, buf, sizeof buf, zp);
2895 msgp->m_scanl = sosmash(subjsw, bp);
2897 break; /* date done so we're done */
2899 subjsw = (char *)0;/* subject done, need date */
2901 while (state == FLDPLUS) /* flush this one */
2902 state = m_getfld (state, name, buf, sizeof buf, zp);
2913 admonish (NULL, "format error in message %d", msgnum);
2914 if (msgp->m_scanl) { /* this might need free'd */
2915 free (msgp->m_scanl); /* probably can't use subj anyway */
2916 msgp->m_scanl = NULL;
2921 adios (NULL, "internal error -- you lose");
2926 return OK; /* not an error if subj not found */
2928 admonish (NULL, "no %s field in message %d", datesw, msgnum);
2929 return NOTOK; /* NOTOK means use some other date */
2938 msgsort (struct Msg *a, struct Msg *b)
2940 return twsort (&a->m_tb, &b->m_tb);
2945 subsort (struct Msg *a, struct Msg *b)
2949 if (a->m_scanl && b->m_scanl)
2950 if ((i = strcmp (a->m_scanl, b->m_scanl)))
2953 return twsort (&a->m_tb, &b->m_tb);
2958 * try to make the subject "canonical": delete leading "re:", everything
2959 * but letters & smash letters to lower case.
2962 sosmash (char *subj, char *s)
2964 register char *cp, *dp;
2965 register unsigned char c;
2969 dp = s; /* dst pointer */
2970 if (!mh_strcasecmp (subj, "subject"))
2977 *dp++ = isupper(c) ? tolower(c) : c;
2983 while ((c = *cp++)) {
2985 *dp++ = isupper(c) ? tolower(c) : c;
2995 process (int msgnum, char *proc, int vecp, char **vec)
2997 int child_id, status;
2998 char tmpfil[BUFSIZ];
3003 strncpy (tmpfil, m_name (msgnum), sizeof(tmpfil));
3004 context_del (pfolder);
3005 context_replace (pfolder, fmsh);/* update current folder */
3007 context_save (); /* save the context file */
3011 cp = m_mktemp(invo_name, NULL, &out);
3013 /* Try again, but try to create under /tmp */
3015 cp = m_mktemp2(NULL, invo_name, NULL, &out);
3018 advise (NULL, "unable to create temporary file");
3022 copy_message (msgnum, out);
3024 strncpy(tmpfil, cp, sizeof(tmpfil));
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)