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>
26 static char delim3[] = "-------"; /* from burst.c */
31 #if defined(NNTP) && defined(MPOP)
38 extern char response[];
43 * Type for a compare function for qsort. This keeps
46 typedef int (*qsort_comp) (const void *, const void *);
51 void clear_screen (void); /* from termsbr.c */
52 int SOprintf (char *, ...); /* from termsbr.c */
53 int sc_width (void); /* from termsbr.c */
58 static int burst (struct Msg *, int, int, int, int);
59 static void forw (char *, char *, int, char **);
60 static void rmm (void);
61 static void show (int);
62 static int eom_action (int);
63 static FILE *mhl_action (char *);
65 static int is_nontext (int);
66 static int get_fields (char *, char *, int, struct Msg *);
67 static int msgsort (struct Msg *, struct Msg *);
68 static int subsort (struct Msg *, struct Msg *);
69 static char *sosmash (char *, char *);
70 static int process (int, char *, int, char **);
71 static void copy_message (int, FILE *);
72 static void copy_digest (int, FILE *);
75 int mhlsbr (int, char **, FILE *(*)());
78 forkcmd (char **args, char *pgm)
83 vec[0] = r1bindex (pgm, '/');
84 copyip (args, vec + 1, MAXARGS - 1);
87 context_del (pfolder);
88 context_replace (pfolder, fmsh);/* update current folder */
90 context_save (); /* save the context file */
93 switch (child_id = fork ()) {
95 advise ("fork", "unable to");
100 SIGNAL (SIGINT, istat);
101 SIGNAL (SIGQUIT, qstat);
104 fprintf (stderr, "unable to exec ");
109 pidXwait (child_id, NULL);
112 if (fmsh) { /* assume the worst case */
113 mp->msgflags |= MODIFIED;
119 static struct swit distswit[] = {
125 { "draftfolder +folder", 0 },
127 { "draftmessage msg", 0 },
129 { "nodraftfolder", 0 },
131 { "editor editor", 0 },
135 { "form formfile", 0 },
141 { "whatnowproc program", 0 },
143 { "nowhatnowproc", 0 },
151 distcmd (char **args)
154 char *cp, *msg = NULL;
155 char buf[BUFSIZ], *vec[MAXARGS];
158 forkcmd (args, cmd_name);
162 while ((cp = *args++)) {
164 switch (smatch (++cp, distswit)) {
166 ambigsw (cp, distswit);
169 fprintf (stderr, "-%s unknown\n", cp);
172 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
173 print_help (buf, distswit, 1);
176 case DIANSW: /* not implemented */
194 if (!(cp = *args++) || *cp == '-') {
195 advise (NULL, "missing argument to %s", args[-2]);
201 if (*cp == '+' || *cp == '@') {
202 advise (NULL, "sorry, no folders allowed!");
207 advise (NULL, "only one message at a time!");
215 vec[vecp++] = "-file";
219 if (!m_convert (mp, msg))
223 if (mp->numsel > 1) {
224 advise (NULL, "only one message at a time!");
227 process (mp->hghsel, cmd_name, vecp, vec);
228 seq_setcur (mp, mp->hghsel);
232 static struct swit explswit[] = {
252 explcmd (char **args)
254 int inplace = 0, quietsw = 0, verbosw = 0;
255 int msgp = 0, hi, msgnum;
256 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
260 forkcmd (args, cmd_name);
264 while ((cp = *args++)) {
266 switch (smatch (++cp, explswit)) {
268 ambigsw (cp, explswit);
271 fprintf (stderr, "-%s unknown\n", cp);
274 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
275 print_help (buf, explswit, 1);
297 if (*cp == '+' || *cp == '@') {
298 advise (NULL, "sorry, no folders allowed!");
306 msgs[msgp++] = "cur";
307 for (msgnum = 0; msgnum < msgp; msgnum++)
308 if (!m_convert (mp, msgs[msgnum]))
312 smsgs = (struct Msg *)
313 calloc ((size_t) (MAXFOLDER + 2), sizeof *smsgs);
315 adios (NULL, "unable to allocate folder storage");
319 for (msgnum = mp->lowsel;
320 msgnum <= mp->hghsel && !interrupted;
322 if (is_selected (mp, msgnum))
323 if (burst (smsgs, msgnum, inplace, quietsw, verbosw) != OK)
326 free ((char *) smsgs);
329 seq_setcur (mp, mp->lowsel);
331 if (hi <= mp->hghmsg)
334 mp->msgflags |= MODIFIED;
340 burst (struct Msg *smsgs, int msgnum, int inplace, int quietsw, int verbosw)
342 int i, j, ld3, wasdlm, msgp;
344 char c, buffer[BUFSIZ];
347 ld3 = strlen (delim3);
349 if (Msgs[msgnum].m_scanl) {
350 free (Msgs[msgnum].m_scanl);
351 Msgs[msgnum].m_scanl = NULL;
354 pos = ftell (zp = msh_ready (msgnum, 1));
355 for (msgp = 0; msgp <= MAXFOLDER;) {
356 while (fgets (buffer, sizeof buffer, zp) != NULL
358 && pos < Msgs[msgnum].m_stop)
359 pos += (long) strlen (buffer);
360 if (feof (zp) || pos >= Msgs[msgnum].m_stop)
362 fseek (zp, pos, SEEK_SET);
363 smsgs[msgp].m_start = pos;
366 pos < Msgs[msgnum].m_stop
367 && fgets (buffer, sizeof buffer, zp) != NULL;
369 if (strncmp (buffer, delim3, ld3) == 0
370 && (msgp == 1 || c == '\n')
371 && peekc (zp) == '\n')
374 pos += (long) strlen (buffer);
376 wasdlm = strncmp (buffer, delim3, ld3) == 0;
377 if (smsgs[msgp].m_start != pos)
378 smsgs[msgp++].m_stop = (c == '\n' && wasdlm) ? pos - 1 : pos;
379 if (feof (zp) || pos >= Msgs[msgnum].m_stop) {
381 smsgs[msgp - 1].m_stop -= ((long) strlen (buffer) + 1);
384 pos += (long) strlen (buffer);
387 switch (msgp--) { /* toss "End of XXX Digest" */
389 adios (NULL, "burst() botch -- you lose big");
393 printf ("message %d not in digest format\n", msgnum);
398 printf ("%d message%s exploded from digest %d\n",
399 msgp, msgp != 1 ? "s" : "", msgnum);
403 if ((i = msgp + mp->hghmsg) > MAXFOLDER) {
404 advise (NULL, "more than %d messages", MAXFOLDER);
407 if (!(mp = folder_realloc (mp, mp->lowoff, i)))
408 adios (NULL, "unable to allocate folder storage");
413 if (mp->hghsel > msgnum)
417 for (i = mp->hghmsg; j > msgnum; i--, j--) {
419 printf ("message %d becomes message %d\n", j, i);
421 Msgs[i].m_bboard_id = Msgs[j].m_bboard_id;
422 Msgs[i].m_top = Msgs[j].m_top;
423 Msgs[i].m_start = Msgs[j].m_start;
424 Msgs[i].m_stop = Msgs[j].m_stop;
425 Msgs[i].m_scanl = NULL;
426 if (Msgs[j].m_scanl) {
427 free (Msgs[j].m_scanl);
428 Msgs[j].m_scanl = NULL;
430 copy_msg_flags (mp, i, j);
433 if (Msgs[msgnum].m_bboard_id == 0)
436 unset_selected (mp, msgnum);
437 i = inplace ? msgnum + msgp : mp->hghmsg;
438 for (j = msgp; j >= (inplace ? 0 : 1); i--, j--) {
439 if (verbosw && i != msgnum)
440 printf ("message %d of digest %d becomes message %d\n",
443 Msgs[i].m_bboard_id = Msgs[msgnum].m_bboard_id;
444 Msgs[i].m_top = Msgs[j].m_top;
445 Msgs[i].m_start = smsgs[j].m_start;
446 Msgs[i].m_stop = smsgs[j].m_stop;
447 Msgs[i].m_scanl = NULL;
448 copy_msg_flags (mp, i, msgnum);
455 static struct swit fileswit[] = {
467 { "src +folder", 0 },
471 { "rmmproc program", 0 },
481 filecmd (char **args)
483 int linksw = 0, msgp = 0;
484 int vecp = 1, i, msgnum;
485 char *cp, buf[BUFSIZ];
486 char *msgs[MAXARGS], *vec[MAXARGS];
489 forkcmd (args, cmd_name);
493 while ((cp = *args++)) {
495 switch (i = smatch (++cp, fileswit)) {
497 ambigsw (cp, fileswit);
500 fprintf (stderr, "-%s unknown\n", cp);
503 snprintf (buf, sizeof(buf), "%s +folder... [msgs] [switches]", cmd_name);
504 print_help (buf, fileswit, 1);
523 advise (NULL, "sorry, -%s not allowed!", fileswit[i].sw);
526 if (*cp == '+' || *cp == '@')
533 vec[vecp++] = "-file";
536 msgs[msgp++] = "cur";
537 for (msgnum = 0; msgnum < msgp; msgnum++)
538 if (!m_convert (mp, msgs[msgnum]))
543 for (msgnum = mp->lowsel;
544 msgnum <= mp->hghsel && !interrupted;
546 if (is_selected (mp, msgnum))
547 if (process (msgnum, fileproc, vecp, vec)) {
548 unset_selected (mp, msgnum);
552 if (mp->numsel != mp->nummsg || linksw)
553 seq_setcur (mp, mp->hghsel);
560 filehak (char **args)
562 int result, vecp = 0;
563 char *cp, *cwd, *vec[MAXARGS];
565 while ((cp = *args++)) {
567 switch (smatch (++cp, fileswit)) {
584 if (*cp == '+' || *cp == '@')
591 for (vecp = 0; (cp = vec[vecp]) && result == NOTOK; vecp++) {
593 cwd = getcpy (pwd ());
594 chdir (m_maildir (""));
595 cp = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
596 if (access (m_maildir (cp), F_OK) == NOTOK)
607 static struct swit foldswit[] = {
645 foldcmd (char **args)
647 int fastsw = 0, headersw = 0, packsw = 0;
649 char *cp, *folder = NULL, *msg = NULL;
650 char buf[BUFSIZ], **vec = args;
655 while ((cp = *args++)) {
657 switch (smatch (++cp, foldswit)) {
659 ambigsw (cp, foldswit);
662 fprintf (stderr, "-%s unknown\n", cp);
665 snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]", cmd_name);
666 print_help (buf, foldswit, 1);
669 case FLALSW: /* not implemented */
699 if (*cp == '+' || *cp == '@') {
701 advise (NULL, "only one folder at a time!\n");
705 folder = fmsh ? path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF)
710 advise (NULL, "only one message at a time!\n");
719 advise (NULL, "null folder names are not permitted");
723 if (access (m_maildir (folder), R_OK) == NOTOK) {
724 advise (folder, "unable to read");
729 strncpy (buf, folder, sizeof(buf));
730 if (expand (buf) == NOTOK)
733 if (access (folder, R_OK) == NOTOK) {
734 advise (folder, "unable to read");
749 if (!m_convert (mp, msg))
753 if (mp->numsel > 1) {
754 advise (NULL, "only one message at a time!");
757 seq_setcur (mp, mp->hghsel);
762 forkcmd (vec, cmd_name);
766 if (mp->lowoff > 1 && !(mp = folder_realloc (mp, 1, mp->hghmsg)))
767 adios (NULL, "unable to allocate folder storage");
769 for (msgnum = mp->lowmsg, hole = 1; msgnum <= mp->hghmsg; msgnum++)
770 if (does_exist (mp, msgnum)) {
771 if (msgnum != hole) {
772 Msgs[hole].m_bboard_id = Msgs[msgnum].m_bboard_id;
773 Msgs[hole].m_top = Msgs[msgnum].m_top;
774 Msgs[hole].m_start = Msgs[msgnum].m_start;
775 Msgs[hole].m_stop = Msgs[msgnum].m_stop;
776 Msgs[hole].m_scanl = NULL;
777 if (Msgs[msgnum].m_scanl) {
778 free (Msgs[msgnum].m_scanl);
779 Msgs[msgnum].m_scanl = NULL;
781 copy_msg_flags (mp, hole, msgnum);
782 if (mp->curmsg == msgnum)
783 seq_setcur (mp, hole);
787 if (mp->nummsg > 0) {
789 mp->hghmsg = hole - 1;
791 mp->msgflags |= MODIFIED;
797 printf ("%s\n", fmsh ? fmsh : mp->foldpath);
800 printf ("\t\tFolder %*s# of messages (%*srange%*s); cur%*smsg\n",
801 DMAXFOLDER, "", DMAXFOLDER - 2, "", DMAXFOLDER - 2, "",
803 printf (args ? "%22s " : "%s ", fmsh ? fmsh : mp->foldpath);
805 /* check for empty folder */
806 if (mp->nummsg == 0) {
807 printf ("has no messages%*s",
808 mp->msgflags & OTHERS ? DMAXFOLDER * 2 + 4 : 0, "");
810 printf ("has %*d message%s (%*d-%*d)",
811 DMAXFOLDER, mp->nummsg, mp->nummsg != 1 ? "s" : "",
812 DMAXFOLDER, mp->lowmsg, DMAXFOLDER, mp->hghmsg);
813 if (mp->curmsg >= mp->lowmsg
814 && mp->curmsg <= mp->hghmsg)
815 printf ("; cur=%*d", DMAXFOLDER, mp->curmsg);
822 static struct swit forwswit[] = {
828 { "draftfolder +folder", 0 },
830 { "draftmessage msg", 0 },
832 { "nodraftfolder", 0 },
834 { "editor editor", 0 },
838 { "filter filterfile", 0 },
840 { "form formfile", 0 },
854 { "whatnowproc program", 0 },
864 forwcmd (char **args)
866 int msgp = 0, vecp = 1, msgnum;
867 char *cp, *filter = NULL, buf[BUFSIZ];
868 char *msgs[MAXARGS], *vec[MAXARGS];
871 forkcmd (args, cmd_name);
875 while ((cp = *args++)) {
877 switch (smatch (++cp, forwswit)) {
879 ambigsw (cp, forwswit);
882 fprintf (stderr, "-%s unknown\n", cp);
885 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
886 print_help (buf, forwswit, 1);
889 case FOANSW: /* not implemented */
909 if (!(cp = *args++) || *cp == '-') {
910 advise (NULL, "missing argument to %s", args[-2]);
916 if (!(filter = *args++) || *filter == '-') {
917 advise (NULL, "missing argument to %s", args[-2]);
922 if (access (filter = myfilter, R_OK) == NOTOK) {
923 advise (filter, "unable to read default filter file");
931 if (*cp == '+' || *cp == '@') {
932 advise (NULL, "sorry, no folders allowed!");
939 /* foil search of .mh_profile */
940 snprintf (buf, sizeof(buf), "%sXXXXXX", invo_name);
942 Mkstemp work postponed until later -Doug
944 vec[0] = (char *)mkstemp (buf);
947 vec[0] = (char *)mktemp (buf);
951 vec[vecp++] = "-file";
954 msgs[msgp++] = "cur";
955 for (msgnum = 0; msgnum < msgp; msgnum++)
956 if (!m_convert (mp, msgs[msgnum]))
961 strncpy (buf, filter, sizeof(buf));
962 if (expand (buf) == NOTOK)
964 if (access (filter = getcpy (etcpath (buf)), R_OK) == NOTOK) {
965 advise (filter, "unable to read");
970 forw (cmd_name, filter, vecp, vec);
971 seq_setcur (mp, mp->hghsel);
978 forw (char *proc, char *filter, int vecp, char **vec)
980 int i, child_id, msgnum, msgcnt;
981 char tmpfil[80], *args[MAXARGS];
984 strncpy (tmpfil, m_tmpfil (invo_name), sizeof(tmpfil));
987 switch (child_id = fork ()) {
989 advise ("fork", "unable to");
992 case OK: /* "trust me" */
993 if (freopen (tmpfil, "w", stdout) == NULL) {
994 fprintf (stderr, "unable to create ");
998 args[0] = r1bindex (mhlproc, '/');
1000 args[i++] = "-forwall";
1001 args[i++] = "-form";
1003 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1004 if (is_selected (mp, msgnum))
1005 args[i++] = getcpy (m_name (msgnum));
1007 mhlsbr (i, args, mhl_action);
1008 m_eomsbr ((int (*) ()) 0);
1013 if (pidXwait (child_id, NULL))
1018 if ((out = fopen (tmpfil, "w")) == NULL) {
1019 advise (tmpfil, "unable to create temporary file");
1024 for (msgnum = mp->lowsel;
1025 msgnum <= mp->hghsel && !interrupted;
1027 if (is_selected (mp, msgnum)) {
1028 fprintf (out, "\n\n-------");
1029 if (msgnum == mp->lowsel)
1030 fprintf (out, " Forwarded Message%s",
1031 mp->numsel > 1 ? "s" : "");
1033 fprintf (out, " Message %d", msgcnt);
1034 fprintf (out, "\n\n");
1035 copy_digest (msgnum, out);
1039 fprintf (out, "\n\n------- End of Forwarded Message%s\n",
1040 mp->numsel > 1 ? "s" : "");
1046 switch (child_id = fork ()) {
1048 advise ("fork", "unable to");
1053 SIGNAL (SIGINT, istat);
1054 SIGNAL (SIGQUIT, qstat);
1056 vec[vecp++] = tmpfil;
1060 fprintf (stderr, "unable to exec ");
1065 pidXwait (child_id, NULL);
1073 static char *hlpmsg[] = {
1074 "The %s program emulates many of the commands found in the nmh",
1075 "system. Instead of operating on nmh folders, commands to %s concern",
1078 "To see the list of commands available, just type a ``?'' followed by",
1079 "the RETURN key. To find out what switches each command takes, type",
1080 "the name of the command followed by ``-help''. To leave %s, use the",
1081 "``quit'' command.",
1083 "Although a lot of nmh commands are found in %s, not all are fully",
1084 "implemented. %s will always recognize all legal switches for a",
1085 "given command though, and will let you know when you ask for an",
1086 "option that it is unable to perform.",
1088 "Running %s is fun, but using nmh from your shell is far superior.",
1089 "After you have familiarized yourself with the nmh style by using %s,",
1090 "you should try using nmh from the shell. You can still use %s for",
1091 "message files that aren't in nmh format, such as BBoard files.",
1097 helpcmd (char **args)
1101 for (i = 0; hlpmsg[i]; i++) {
1102 printf (hlpmsg[i], invo_name);
1108 static struct swit markswit[] = {
1116 { "sequence name", 0 },
1134 markcmd (char **args)
1136 int addsw = 0, deletesw = 0, debugsw = 0;
1137 int listsw = 0, zerosw = 0, seqp = 0;
1138 int msgp = 0, msgnum;
1139 char *cp, buf[BUFSIZ];
1140 char *seqs[NUMATTRS + 1], *msgs[MAXARGS];
1142 while ((cp = *args++)) {
1144 switch (smatch (++cp, markswit)) {
1146 ambigsw (cp, markswit);
1149 fprintf (stderr, "-%s unknown\n", cp);
1152 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1153 print_help (buf, markswit, 1);
1158 deletesw = listsw = 0;
1166 addsw = deletesw = 0;
1170 if (!(cp = *args++) || *cp == '-') {
1171 advise (NULL, "missing argument to %s", args[-2]);
1174 if (seqp < NUMATTRS)
1177 advise (NULL, "only %d sequences allowed!", NUMATTRS);
1182 case MPUBSW: /* not implemented */
1198 if (*cp == '+' || *cp == '@') {
1199 advise (NULL, "sorry, no folders allowed!");
1206 if (!addsw && !deletesw && !listsw) {
1213 seqs[seqp++] = "unseen";
1217 msgs[msgp++] = "all";
1222 msgs[msgp++] = listsw ? "all" :"cur";
1223 for (msgnum = 0; msgnum < msgp; msgnum++)
1224 if (!m_convert (mp, msgs[msgnum]))
1228 printf ("invo_name=%s mypath=%s defpath=%s\n",
1229 invo_name, mypath, defpath);
1230 printf ("ctxpath=%s context flags=%s\n",
1231 ctxpath, snprintb (buf, sizeof(buf), (unsigned) ctxflags, DBITS));
1232 printf ("foldpath=%s flags=%s\n",
1234 snprintb (buf, sizeof(buf), (unsigned) mp->msgflags, FBITS));
1235 printf ("hghmsg=%d lowmsg=%d nummsg=%d curmsg=%d\n",
1236 mp->hghmsg, mp->lowmsg, mp->nummsg, mp->curmsg);
1237 printf ("lowsel=%d hghsel=%d numsel=%d\n",
1238 mp->lowsel, mp->hghsel, mp->numsel);
1239 printf ("lowoff=%d hghoff=%d\n", mp->lowoff, mp->hghoff);
1242 if (seqp == 0 && (addsw || deletesw)) {
1243 advise (NULL, "-%s requires at least one -sequence argument",
1244 addsw ? "add" : "delete");
1250 for (seqp = 0; seqs[seqp]; seqp++)
1251 if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
1256 for (seqp = 0; seqs[seqp]; seqp++)
1257 if (!seq_delsel (mp, seqs[seqp], 0, zerosw))
1261 /* Listing messages in sequences */
1264 /* list the given sequences */
1265 for (seqp = 0; seqs[seqp]; seqp++)
1266 seq_print (mp, seqs[seqp]);
1268 /* else list them all */
1274 for (msgnum = mp->lowsel;
1275 msgnum <= mp->hghsel && !interrupted;
1277 if (is_selected (mp, msgnum)) {
1278 printf ("%*d: id=%d top=%d start=%ld stop=%ld %s\n",
1281 Msgs[msgnum].m_bboard_id,
1283 (long) Msgs[msgnum].m_start,
1284 (long) Msgs[msgnum].m_stop,
1285 snprintb (buf, sizeof(buf),
1286 (unsigned) mp->msgstats[msgnum - mp->lowoff],
1288 if (Msgs[msgnum].m_scanl)
1289 printf ("%s", Msgs[msgnum].m_scanl);
1295 static struct swit mhnswit[] = {
1298 #define MHNNAUTOSW 1
1300 #define MHNDEBUGSW 2
1302 #define MHNEBCDICSW 3
1303 { "ebcdicsafe", 0 },
1304 #define MHNNEBCDICSW 4
1305 { "noebcdicsafe", 0 },
1307 { "form formfile", 4 },
1310 #define MHNNHEADSW 7
1314 #define MHNNLISTSW 9
1316 #define MHNPARTSW 10
1317 { "part number", 0 },
1318 #define MHNSIZESW 11
1320 #define MHNNSIZESW 12
1321 { "norealsize", 0 },
1322 #define MHNRFC934SW 13
1323 { "rfc934mode", 0 },
1324 #define MHNNRFC934SW 14
1325 { "norfc934mode", 0 },
1326 #define MHNSERIALSW 15
1327 { "serialonly", 0 },
1328 #define MHNNSERIALSW 16
1329 { "noserialonly", 0 },
1330 #define MHNSHOWSW 17
1332 #define MHNNSHOWSW 18
1334 #define MHNSTORESW 19
1336 #define MHNNSTORESW 20
1338 #define MHNTYPESW 21
1339 { "type content", 0 },
1340 #define MHNVERBSW 22
1342 #define MHNNVERBSW 23
1344 #define MHNHELPSW 24
1346 #define MHNPROGSW 25
1347 { "moreproc program", -4 },
1348 #define MHNNPROGSW 26
1349 { "nomoreproc", -3 },
1351 { "length lines", -4 },
1353 { "width columns", -4 },
1359 mhncmd (char **args)
1361 int msgp = 0, vecp = 1;
1363 char *cp, buf[BUFSIZ];
1364 char *msgs[MAXARGS], *vec[MAXARGS];
1367 forkcmd (args, cmd_name);
1370 while ((cp = *args++)) {
1372 switch (smatch (++cp, mhnswit)) {
1374 ambigsw (cp, mhnswit);
1377 fprintf (stderr, "-%s unknown\n", cp);
1380 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1381 print_help (buf, mhnswit, 1);
1416 if (!(cp = *args++) || *cp == '-') {
1417 advise (NULL, "missing argument to %s", args[-2]);
1424 if (*cp == '+' || *cp == '@') {
1425 advise (NULL, "sorry, no folders allowed!");
1433 vec[vecp++] = "-file";
1436 msgs[msgp++] = "cur";
1437 for (msgnum = 0; msgnum < msgp; msgnum++)
1438 if (!m_convert (mp, msgs[msgnum]))
1443 for (msgnum = mp->lowsel;
1444 msgnum <= mp->hghsel && !interrupted;
1446 if (is_selected (mp, msgnum))
1447 if (process (msgnum, cmd_name, vecp, vec)) {
1448 unset_selected (mp, msgnum);
1452 seq_setcur (mp, mp->hghsel);
1456 static struct swit packswit[] = {
1464 static int mbx_style = MMDF_FORMAT;
1467 packcmd (char **args)
1469 int msgp = 0, md, msgnum;
1470 char *cp, *file = NULL;
1471 char buf[BUFSIZ], *msgs[MAXARGS];
1475 forkcmd (args, cmd_name);
1479 while ((cp = *args++)) {
1481 switch (smatch (++cp, packswit)) {
1483 ambigsw (cp, packswit);
1486 fprintf (stderr, "-%s unknown\n", cp);
1489 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1490 print_help (buf, packswit, 1);
1494 if (!(file = *args++) || *file == '-') {
1495 advise (NULL, "missing argument to %s", args[-2]);
1500 if (*cp == '+' || *cp == '@') {
1501 advise (NULL, "sorry, no folders allowed!");
1510 file = path (file, TFILE);
1511 if (stat (file, &st) == NOTOK) {
1512 if (errno != ENOENT) {
1513 advise (file, "error on file");
1516 md = getanswer (cp = concat ("Create file \"", file, "\"? ", NULL));
1523 msgs[msgp++] = "all";
1524 for (msgnum = 0; msgnum < msgp; msgnum++)
1525 if (!m_convert (mp, msgs[msgnum]))
1529 if ((md = mbx_open (file, mbx_style, getuid (), getgid (), m_gmprot ())) == NOTOK) {
1530 advise (file, "unable to open");
1533 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1534 if (is_selected (mp, msgnum))
1535 if (pack (file, md, msgnum) == NOTOK)
1537 mbx_close (file, md);
1539 if (mp->hghsel != mp->curmsg)
1540 seq_setcur (mp, mp->lowsel);
1548 pack (char *mailbox, int md, int msgnum)
1552 if (Msgs[msgnum].m_bboard_id == 0)
1555 zp = msh_ready (msgnum, 1);
1556 return mbx_write (mailbox, md, zp, Msgs[msgnum].m_bboard_id,
1557 0L, ftell (zp), Msgs[msgnum].m_stop, 1, 1);
1562 packhak (char **args)
1565 char *cp, *file = NULL;
1567 while ((cp = *args++)) {
1569 switch (smatch (++cp, packswit)) {
1576 if (!(file = *args++) || *file == '-')
1580 if (*cp == '+' || *cp == '@')
1584 file = path (file ? file : "./msgbox", TFILE);
1585 result = access (file, F_OK) == NOTOK ? OK : NOTOK;
1592 static struct swit pickswit[] = {
1604 { "cc pattern", 0 },
1606 { "date pattern", 0 },
1608 { "from pattern", 0 },
1610 { "search pattern", 0 },
1612 { "subject pattern", 0 },
1614 { "to pattern", 0 },
1616 { "-othercomponent pattern", 15 },
1618 { "after date", 0 },
1620 { "before date", 0 },
1622 { "datefield field", 5 },
1624 { "sequence name", 0 },
1644 pickcmd (char **args)
1646 int zerosw = 1, msgp = 0, seqp = 0;
1647 int vecp = 0, hi, lo, msgnum;
1648 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
1649 char *seqs[NUMATTRS], *vec[MAXARGS];
1652 while ((cp = *args++)) {
1658 switch (smatch (cp, pickswit)) {
1660 ambigsw (cp, pickswit);
1663 fprintf (stderr, "-%s unknown\n", cp);
1666 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1667 print_help (buf, pickswit, 1);
1681 if (!(cp = *args++)) {/* allow -xyz arguments */
1682 advise (NULL, "missing argument to %s", args[-2]);
1688 advise (NULL, "internal error!");
1699 if (!(cp = *args++) || *cp == '-') {
1700 advise (NULL, "missing argument to %s", args[-2]);
1703 if (seqp < NUMATTRS)
1706 advise (NULL, "only %d sequences allowed!", NUMATTRS);
1717 case PIPUSW: /* not implemented */
1724 if (*cp == '+' || *cp == '@') {
1725 advise (NULL, "sorry, no folders allowed!");
1734 msgs[msgp++] = "all";
1735 for (msgnum = 0; msgnum < msgp; msgnum++)
1736 if (!m_convert (mp, msgs[msgnum]))
1741 if (!pcompile (vec, NULL))
1747 for (msgnum = mp->lowsel;
1748 msgnum <= mp->hghsel && !interrupted;
1750 if (is_selected (mp, msgnum)) {
1751 zp = msh_ready (msgnum, 1);
1752 if (pmatches (zp, msgnum, fmsh ? 0L : Msgs[msgnum].m_start,
1753 fmsh ? 0L : Msgs[msgnum].m_stop)) {
1760 unset_selected (mp, msgnum);
1771 if (mp->numsel <= 0) {
1772 advise (NULL, "no messages match specification");
1777 for (seqp = 0; seqs[seqp]; seqp++)
1778 if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
1781 printf ("%d hit%s\n", mp->numsel, mp->numsel == 1 ? "" : "s");
1785 static struct swit replswit[] = {
1789 { "noannotate", 0 },
1795 { "draftfolder +folder", 0 },
1797 { "draftmessage msg", 0 },
1799 { "nodraftfolder", 0 },
1801 { "editor editor", 0 },
1805 { "fcc +folder", 0 },
1807 { "filter filterfile", 0 },
1809 { "form formfile", 0 },
1819 { "whatnowproc program", 0 },
1823 { "width columns", 0 },
1831 replcmd (char **args)
1834 char *cp, *msg = NULL;
1835 char buf[BUFSIZ], *vec[MAXARGS];
1838 forkcmd (args, cmd_name);
1842 while ((cp = *args++)) {
1844 switch (smatch (++cp, replswit)) {
1846 ambigsw (cp, replswit);
1849 fprintf (stderr, "-%s unknown\n", cp);
1852 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1853 print_help (buf, replswit, 1);
1856 case REANSW: /* not implemented */
1881 if (!(cp = *args++) || *cp == '-') {
1882 advise (NULL, "missing argument to %s", args[-2]);
1888 if (*cp == '+' || *cp == '@') {
1889 advise (NULL, "sorry, no folders allowed!");
1894 advise (NULL, "only one message at a time!");
1902 vec[vecp++] = "-file";
1906 if (!m_convert (mp, msg))
1910 if (mp->numsel > 1) {
1911 advise (NULL, "only one message at a time!");
1914 process (mp->hghsel, cmd_name, vecp, vec);
1915 seq_setcur (mp, mp->hghsel);
1919 static struct swit rmmswit[] = {
1927 rmmcmd (char **args)
1929 int msgp = 0, msgnum;
1930 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
1932 while ((cp = *args++)) {
1934 switch (smatch (++cp, rmmswit)) {
1936 ambigsw (cp, rmmswit);
1939 fprintf (stderr, "-%s unknown\n", cp);
1942 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1943 print_help (buf, rmmswit, 1);
1946 if (*cp == '+' || *cp == '@') {
1947 advise (NULL, "sorry, no folders allowed!");
1955 msgs[msgp++] = "cur";
1956 for (msgnum = 0; msgnum < msgp; msgnum++)
1957 if (!m_convert (mp, msgs[msgnum]))
1968 register int msgnum, vecp;
1970 char buffer[BUFSIZ], *vec[MAXARGS];
1974 if (mp->numsel > MAXARGS - 1) {
1975 advise (NULL, "more than %d messages for %s exec",
1976 MAXARGS - 1, rmmproc);
1980 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1981 if (is_selected (mp, msgnum))
1982 vec[vecp++] = getcpy (m_name (msgnum));
1984 forkcmd (vec, rmmproc);
1985 for (vecp = 0; vec[vecp]; vecp++)
1989 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1990 if (is_selected (mp, msgnum)) {
1991 strncpy (buffer, m_backup (cp = m_name (msgnum)), sizeof(buffer));
1992 if (rename (cp, buffer) == NOTOK)
1993 admonish (buffer, "unable to rename %s to", cp);
1997 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1998 if (is_selected (mp, msgnum)) {
1999 set_deleted (mp, msgnum);
2000 unset_exists (mp, msgnum);
2003 if (pmsh && pop_dele (msgnum) != OK)
2004 fprintf (stderr, "%s", response);
2009 if ((mp->nummsg -= mp->numsel) <= 0) {
2011 admonish (NULL, "no messages remaining in +%s", fmsh);
2013 admonish (NULL, "no messages remaining in %s", mp->foldpath);
2014 mp->lowmsg = mp->hghmsg = mp->nummsg = 0;
2016 if (mp->lowsel == mp->lowmsg) {
2017 for (msgnum = mp->lowmsg + 1; msgnum <= mp->hghmsg; msgnum++)
2018 if (does_exist (mp, msgnum))
2020 mp->lowmsg = msgnum;
2022 if (mp->hghsel == mp->hghmsg) {
2023 for (msgnum = mp->hghmsg - 1; msgnum >= mp->lowmsg; msgnum--)
2024 if (does_exist (mp, msgnum))
2026 mp->hghmsg = msgnum;
2029 mp->msgflags |= MODIFIED;
2034 static struct swit scanswit[] = {
2040 { "form formatfile", 0 },
2042 { "format string", 5 },
2048 { "width columns", 0 },
2056 scancmd (char **args)
2058 #define equiv(a,b) (a ? b && !strcmp (a, b) : !b)
2060 int clearsw = 0, headersw = 0, width = 0, msgp = 0;
2061 int msgnum, optim, state;
2062 char *cp, *form = NULL, *format = NULL;
2063 char buf[BUFSIZ], *nfs, *msgs[MAXARGS];
2067 static int p_optim = 0;
2070 static int s_optim = 0;
2071 static char *s_form = NULL, *s_format = NULL;
2073 while ((cp = *args++)) {
2075 switch (smatch (++cp, scanswit)) {
2077 ambigsw (cp, scanswit);
2080 fprintf (stderr, "-%s unknown\n", cp);
2083 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
2084 print_help (buf, scanswit, 1);
2100 if (!(form = *args++) || *form == '-') {
2101 advise (NULL, "missing argument to %s", args[-2]);
2107 if (!(format = *args++) || *format == '-') {
2108 advise (NULL, "missing argument to %s", args[-2]);
2114 if (!(cp = *args++) || *cp == '-') {
2115 advise (NULL, "missing argument to %s", args[-2]);
2121 if (*cp == '+' || *cp == '@') {
2122 advise (NULL, "sorry, no folders allowed!");
2130 msgs[msgp++] = "all";
2131 for (msgnum = 0; msgnum < msgp; msgnum++)
2132 if (!m_convert (mp, msgs[msgnum]))
2136 /* Get new format string */
2137 nfs = new_fs (form, format, FORMAT);
2139 /* force scansbr to (re)compile format */
2146 s_optim = optim = 1;
2147 s_form = form ? getcpy (form) : NULL;
2148 s_format = format ? getcpy (format) : NULL;
2157 width = sc_width ();
2159 for (dp = nfs, i = 0; *dp; dp++, i++)
2160 if (*dp == '\\' || *dp == '"' || *dp == '\n')
2163 if ((ep = malloc ((unsigned) i)) == NULL)
2164 adios (NULL, "out of memory");
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)