3 * mshcmds.c -- command handlers in msh
10 #include <h/dropsbr.h>
11 #include <h/fmt_scan.h>
12 #include <h/scansbr.h>
13 #include <zotnet/tws/tws.h>
14 #include <zotnet/mts/mts.h>
19 #include <h/picksbr.h>
23 static char delim3[] = "-------"; /* from burst.c */
28 #if defined(NNTP) && defined(MPOP)
35 extern char response[];
40 * Type for a compare function for qsort. This keeps
43 typedef int (*qsort_comp) (const void *, const void *);
48 void clear_screen (void); /* from termsbr.c */
49 int SOprintf (char *, ...); /* from termsbr.c */
50 int sc_width (void); /* from termsbr.c */
55 static int burst (struct Msg *, int, int, int, int);
56 static void forw (char *, char *, int, char **);
57 static void rmm (void);
58 static void show (int);
59 static int eom_action (int);
60 static FILE *mhl_action (char *);
62 static int is_nontext (int);
63 static int get_fields (char *, char *, int, struct Msg *);
64 static int msgsort (struct Msg *, struct Msg *);
65 static int subsort (struct Msg *, struct Msg *);
66 static char *sosmash (char *, char *);
67 static int process (int, char *, int, char **);
68 static void copy_message (int, FILE *);
69 static void copy_digest (int, FILE *);
72 int mhlsbr (int, char **, FILE *(*)());
75 forkcmd (char **args, char *pgm)
80 vec[0] = r1bindex (pgm, '/');
81 copyip (args, vec + 1, MAXARGS - 1);
84 context_del (pfolder);
85 context_replace (pfolder, fmsh);/* update current folder */
87 context_save (); /* save the context file */
90 switch (child_id = fork ()) {
92 advise ("fork", "unable to");
97 SIGNAL (SIGINT, istat);
98 SIGNAL (SIGQUIT, qstat);
101 fprintf (stderr, "unable to exec ");
106 pidXwait (child_id, NULL);
109 if (fmsh) { /* assume the worst case */
110 mp->msgflags |= MODIFIED;
116 static struct swit distswit[] = {
122 { "draftfolder +folder", 0 },
124 { "draftmessage msg", 0 },
126 { "nodraftfolder", 0 },
128 { "editor editor", 0 },
132 { "form formfile", 0 },
138 { "whatnowproc program", 0 },
140 { "nowhatnowproc", 0 },
148 distcmd (char **args)
151 char *cp, *msg = NULL;
152 char buf[BUFSIZ], *vec[MAXARGS];
155 forkcmd (args, cmd_name);
159 while ((cp = *args++)) {
161 switch (smatch (++cp, distswit)) {
163 ambigsw (cp, distswit);
166 fprintf (stderr, "-%s unknown\n", cp);
169 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
170 print_help (buf, distswit, 1);
173 case DIANSW: /* not implemented */
191 if (!(cp = *args++) || *cp == '-') {
192 advise (NULL, "missing argument to %s", args[-2]);
198 if (*cp == '+' || *cp == '@') {
199 advise (NULL, "sorry, no folders allowed!");
204 advise (NULL, "only one message at a time!");
212 vec[vecp++] = "-file";
216 if (!m_convert (mp, msg))
220 if (mp->numsel > 1) {
221 advise (NULL, "only one message at a time!");
224 process (mp->hghsel, cmd_name, vecp, vec);
225 seq_setcur (mp, mp->hghsel);
229 static struct swit explswit[] = {
249 explcmd (char **args)
251 int inplace = 0, quietsw = 0, verbosw = 0;
252 int msgp = 0, hi, msgnum;
253 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
257 forkcmd (args, cmd_name);
261 while ((cp = *args++)) {
263 switch (smatch (++cp, explswit)) {
265 ambigsw (cp, explswit);
268 fprintf (stderr, "-%s unknown\n", cp);
271 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
272 print_help (buf, explswit, 1);
294 if (*cp == '+' || *cp == '@') {
295 advise (NULL, "sorry, no folders allowed!");
303 msgs[msgp++] = "cur";
304 for (msgnum = 0; msgnum < msgp; msgnum++)
305 if (!m_convert (mp, msgs[msgnum]))
309 smsgs = (struct Msg *)
310 calloc ((size_t) (MAXFOLDER + 2), sizeof *smsgs);
312 adios (NULL, "unable to allocate folder storage");
316 for (msgnum = mp->lowsel;
317 msgnum <= mp->hghsel && !interrupted;
319 if (is_selected (mp, msgnum))
320 if (burst (smsgs, msgnum, inplace, quietsw, verbosw) != OK)
323 free ((char *) smsgs);
326 seq_setcur (mp, mp->lowsel);
328 if (hi <= mp->hghmsg)
331 mp->msgflags |= MODIFIED;
337 burst (struct Msg *smsgs, int msgnum, int inplace, int quietsw, int verbosw)
339 int i, j, ld3, wasdlm, msgp;
341 char c, buffer[BUFSIZ];
344 ld3 = strlen (delim3);
346 if (Msgs[msgnum].m_scanl) {
347 free (Msgs[msgnum].m_scanl);
348 Msgs[msgnum].m_scanl = NULL;
351 pos = ftell (zp = msh_ready (msgnum, 1));
352 for (msgp = 0; msgp <= MAXFOLDER;) {
353 while (fgets (buffer, sizeof buffer, zp) != NULL
355 && pos < Msgs[msgnum].m_stop)
356 pos += (long) strlen (buffer);
357 if (feof (zp) || pos >= Msgs[msgnum].m_stop)
359 fseek (zp, pos, SEEK_SET);
360 smsgs[msgp].m_start = pos;
363 pos < Msgs[msgnum].m_stop
364 && fgets (buffer, sizeof buffer, zp) != NULL;
366 if (strncmp (buffer, delim3, ld3) == 0
367 && (msgp == 1 || c == '\n')
368 && peekc (zp) == '\n')
371 pos += (long) strlen (buffer);
373 wasdlm = strncmp (buffer, delim3, ld3) == 0;
374 if (smsgs[msgp].m_start != pos)
375 smsgs[msgp++].m_stop = (c == '\n' && wasdlm) ? pos - 1 : pos;
376 if (feof (zp) || pos >= Msgs[msgnum].m_stop) {
378 smsgs[msgp - 1].m_stop -= ((long) strlen (buffer) + 1);
381 pos += (long) strlen (buffer);
384 switch (msgp--) { /* toss "End of XXX Digest" */
386 adios (NULL, "burst() botch -- you lose big");
390 printf ("message %d not in digest format\n", msgnum);
395 printf ("%d message%s exploded from digest %d\n",
396 msgp, msgp != 1 ? "s" : "", msgnum);
400 if ((i = msgp + mp->hghmsg) > MAXFOLDER) {
401 advise (NULL, "more than %d messages", MAXFOLDER);
404 if (!(mp = folder_realloc (mp, mp->lowoff, i)))
405 adios (NULL, "unable to allocate folder storage");
410 if (mp->hghsel > msgnum)
414 for (i = mp->hghmsg; j > msgnum; i--, j--) {
416 printf ("message %d becomes message %d\n", j, i);
418 Msgs[i].m_bboard_id = Msgs[j].m_bboard_id;
419 Msgs[i].m_top = Msgs[j].m_top;
420 Msgs[i].m_start = Msgs[j].m_start;
421 Msgs[i].m_stop = Msgs[j].m_stop;
422 Msgs[i].m_scanl = NULL;
423 if (Msgs[j].m_scanl) {
424 free (Msgs[j].m_scanl);
425 Msgs[j].m_scanl = NULL;
427 copy_msg_flags (mp, i, j);
430 if (Msgs[msgnum].m_bboard_id == 0)
433 unset_selected (mp, msgnum);
434 i = inplace ? msgnum + msgp : mp->hghmsg;
435 for (j = msgp; j >= (inplace ? 0 : 1); i--, j--) {
436 if (verbosw && i != msgnum)
437 printf ("message %d of digest %d becomes message %d\n",
440 Msgs[i].m_bboard_id = Msgs[msgnum].m_bboard_id;
441 Msgs[i].m_top = Msgs[j].m_top;
442 Msgs[i].m_start = smsgs[j].m_start;
443 Msgs[i].m_stop = smsgs[j].m_stop;
444 Msgs[i].m_scanl = NULL;
445 copy_msg_flags (mp, i, msgnum);
452 static struct swit fileswit[] = {
464 { "src +folder", 0 },
468 { "rmmproc program", 0 },
478 filecmd (char **args)
480 int linksw = 0, msgp = 0;
481 int vecp = 1, i, msgnum;
482 char *cp, buf[BUFSIZ];
483 char *msgs[MAXARGS], *vec[MAXARGS];
486 forkcmd (args, cmd_name);
490 while ((cp = *args++)) {
492 switch (i = smatch (++cp, fileswit)) {
494 ambigsw (cp, fileswit);
497 fprintf (stderr, "-%s unknown\n", cp);
500 snprintf (buf, sizeof(buf), "%s +folder... [msgs] [switches]", cmd_name);
501 print_help (buf, fileswit, 1);
520 advise (NULL, "sorry, -%s not allowed!", fileswit[i].sw);
523 if (*cp == '+' || *cp == '@')
530 vec[vecp++] = "-file";
533 msgs[msgp++] = "cur";
534 for (msgnum = 0; msgnum < msgp; msgnum++)
535 if (!m_convert (mp, msgs[msgnum]))
540 for (msgnum = mp->lowsel;
541 msgnum <= mp->hghsel && !interrupted;
543 if (is_selected (mp, msgnum))
544 if (process (msgnum, fileproc, vecp, vec)) {
545 unset_selected (mp, msgnum);
549 if (mp->numsel != mp->nummsg || linksw)
550 seq_setcur (mp, mp->hghsel);
557 filehak (char **args)
559 int result, vecp = 0;
560 char *cp, *cwd, *vec[MAXARGS];
562 while ((cp = *args++)) {
564 switch (smatch (++cp, fileswit)) {
581 if (*cp == '+' || *cp == '@')
588 for (vecp = 0; (cp = vec[vecp]) && result == NOTOK; vecp++) {
590 cwd = getcpy (pwd ());
591 chdir (m_maildir (""));
592 cp = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
593 if (access (m_maildir (cp), F_OK) == NOTOK)
604 static struct swit foldswit[] = {
642 foldcmd (char **args)
644 int fastsw = 0, headersw = 0, packsw = 0;
646 char *cp, *folder = NULL, *msg = NULL;
647 char buf[BUFSIZ], **vec = args;
652 while ((cp = *args++)) {
654 switch (smatch (++cp, foldswit)) {
656 ambigsw (cp, foldswit);
659 fprintf (stderr, "-%s unknown\n", cp);
662 snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]", cmd_name);
663 print_help (buf, foldswit, 1);
666 case FLALSW: /* not implemented */
696 if (*cp == '+' || *cp == '@') {
698 advise (NULL, "only one folder at a time!\n");
702 folder = fmsh ? path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF)
707 advise (NULL, "only one message at a time!\n");
716 advise (NULL, "null folder names are not permitted");
720 if (access (m_maildir (folder), R_OK) == NOTOK) {
721 advise (folder, "unable to read");
726 strncpy (buf, folder, sizeof(buf));
727 if (expand (buf) == NOTOK)
730 if (access (folder, R_OK) == NOTOK) {
731 advise (folder, "unable to read");
746 if (!m_convert (mp, msg))
750 if (mp->numsel > 1) {
751 advise (NULL, "only one message at a time!");
754 seq_setcur (mp, mp->hghsel);
759 forkcmd (vec, cmd_name);
763 if (mp->lowoff > 1 && !(mp = folder_realloc (mp, 1, mp->hghmsg)))
764 adios (NULL, "unable to allocate folder storage");
766 for (msgnum = mp->lowmsg, hole = 1; msgnum <= mp->hghmsg; msgnum++)
767 if (does_exist (mp, msgnum)) {
768 if (msgnum != hole) {
769 Msgs[hole].m_bboard_id = Msgs[msgnum].m_bboard_id;
770 Msgs[hole].m_top = Msgs[msgnum].m_top;
771 Msgs[hole].m_start = Msgs[msgnum].m_start;
772 Msgs[hole].m_stop = Msgs[msgnum].m_stop;
773 Msgs[hole].m_scanl = NULL;
774 if (Msgs[msgnum].m_scanl) {
775 free (Msgs[msgnum].m_scanl);
776 Msgs[msgnum].m_scanl = NULL;
778 copy_msg_flags (mp, hole, msgnum);
779 if (mp->curmsg == msgnum)
780 seq_setcur (mp, hole);
784 if (mp->nummsg > 0) {
786 mp->hghmsg = hole - 1;
788 mp->msgflags |= MODIFIED;
794 printf ("%s\n", fmsh ? fmsh : mp->foldpath);
797 printf ("\t\tFolder %*s# of messages (%*srange%*s); cur%*smsg\n",
798 DMAXFOLDER, "", DMAXFOLDER - 2, "", DMAXFOLDER - 2, "",
800 printf (args ? "%22s " : "%s ", fmsh ? fmsh : mp->foldpath);
802 /* check for empty folder */
803 if (mp->nummsg == 0) {
804 printf ("has no messages%*s",
805 mp->msgflags & OTHERS ? DMAXFOLDER * 2 + 4 : 0, "");
807 printf ("has %*d message%s (%*d-%*d)",
808 DMAXFOLDER, mp->nummsg, mp->nummsg != 1 ? "s" : "",
809 DMAXFOLDER, mp->lowmsg, DMAXFOLDER, mp->hghmsg);
810 if (mp->curmsg >= mp->lowmsg
811 && mp->curmsg <= mp->hghmsg)
812 printf ("; cur=%*d", DMAXFOLDER, mp->curmsg);
819 static struct swit forwswit[] = {
825 { "draftfolder +folder", 0 },
827 { "draftmessage msg", 0 },
829 { "nodraftfolder", 0 },
831 { "editor editor", 0 },
835 { "filter filterfile", 0 },
837 { "form formfile", 0 },
851 { "whatnowproc program", 0 },
861 forwcmd (char **args)
863 int msgp = 0, vecp = 1, msgnum;
864 char *cp, *filter = NULL, buf[BUFSIZ];
865 char *msgs[MAXARGS], *vec[MAXARGS];
868 forkcmd (args, cmd_name);
872 while ((cp = *args++)) {
874 switch (smatch (++cp, forwswit)) {
876 ambigsw (cp, forwswit);
879 fprintf (stderr, "-%s unknown\n", cp);
882 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
883 print_help (buf, forwswit, 1);
886 case FOANSW: /* not implemented */
906 if (!(cp = *args++) || *cp == '-') {
907 advise (NULL, "missing argument to %s", args[-2]);
913 if (!(filter = *args++) || *filter == '-') {
914 advise (NULL, "missing argument to %s", args[-2]);
919 if (access (filter = myfilter, R_OK) == NOTOK) {
920 advise (filter, "unable to read default filter file");
928 if (*cp == '+' || *cp == '@') {
929 advise (NULL, "sorry, no folders allowed!");
936 /* foil search of .mh_profile */
937 snprintf (buf, sizeof(buf), "%sXXXXXX", invo_name);
939 Mkstemp work postponed until later -Doug
941 vec[0] = (char *)mkstemp (buf);
944 vec[0] = (char *)mktemp (buf);
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[80], *args[MAXARGS];
981 strncpy (tmpfil, m_tmpfil (invo_name), sizeof(tmpfil));
984 switch (child_id = fork ()) {
986 advise ("fork", "unable to");
989 case OK: /* "trust me" */
990 if (freopen (tmpfil, "w", stdout) == NULL) {
991 fprintf (stderr, "unable to create ");
995 args[0] = r1bindex (mhlproc, '/');
997 args[i++] = "-forwall";
1000 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1001 if (is_selected (mp, msgnum))
1002 args[i++] = getcpy (m_name (msgnum));
1004 mhlsbr (i, args, mhl_action);
1005 m_eomsbr ((int (*) ()) 0);
1010 if (pidXwait (child_id, NULL))
1015 if ((out = fopen (tmpfil, "w")) == NULL) {
1016 advise (tmpfil, "unable to create temporary file");
1021 for (msgnum = mp->lowsel;
1022 msgnum <= mp->hghsel && !interrupted;
1024 if (is_selected (mp, msgnum)) {
1025 fprintf (out, "\n\n-------");
1026 if (msgnum == mp->lowsel)
1027 fprintf (out, " Forwarded Message%s",
1028 mp->numsel > 1 ? "s" : "");
1030 fprintf (out, " Message %d", msgcnt);
1031 fprintf (out, "\n\n");
1032 copy_digest (msgnum, out);
1036 fprintf (out, "\n\n------- End of Forwarded Message%s\n",
1037 mp->numsel > 1 ? "s" : "");
1043 switch (child_id = fork ()) {
1045 advise ("fork", "unable to");
1050 SIGNAL (SIGINT, istat);
1051 SIGNAL (SIGQUIT, qstat);
1053 vec[vecp++] = tmpfil;
1057 fprintf (stderr, "unable to exec ");
1062 pidXwait (child_id, NULL);
1070 static char *hlpmsg[] = {
1071 "The %s program emulates many of the commands found in the nmh",
1072 "system. Instead of operating on nmh folders, commands to %s concern",
1075 "To see the list of commands available, just type a ``?'' followed by",
1076 "the RETURN key. To find out what switches each command takes, type",
1077 "the name of the command followed by ``-help''. To leave %s, use the",
1078 "``quit'' command.",
1080 "Although a lot of nmh commands are found in %s, not all are fully",
1081 "implemented. %s will always recognize all legal switches for a",
1082 "given command though, and will let you know when you ask for an",
1083 "option that it is unable to perform.",
1085 "Running %s is fun, but using nmh from your shell is far superior.",
1086 "After you have familiarized yourself with the nmh style by using %s,",
1087 "you should try using nmh from the shell. You can still use %s for",
1088 "message files that aren't in nmh format, such as BBoard files.",
1094 helpcmd (char **args)
1098 for (i = 0; hlpmsg[i]; i++) {
1099 printf (hlpmsg[i], invo_name);
1105 static struct swit markswit[] = {
1113 { "sequence name", 0 },
1131 markcmd (char **args)
1133 int addsw = 0, deletesw = 0, debugsw = 0;
1134 int listsw = 0, zerosw = 0, seqp = 0;
1135 int msgp = 0, msgnum;
1136 char *cp, buf[BUFSIZ];
1137 char *seqs[NUMATTRS + 1], *msgs[MAXARGS];
1139 while ((cp = *args++)) {
1141 switch (smatch (++cp, markswit)) {
1143 ambigsw (cp, markswit);
1146 fprintf (stderr, "-%s unknown\n", cp);
1149 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1150 print_help (buf, markswit, 1);
1155 deletesw = listsw = 0;
1163 addsw = deletesw = 0;
1167 if (!(cp = *args++) || *cp == '-') {
1168 advise (NULL, "missing argument to %s", args[-2]);
1171 if (seqp < NUMATTRS)
1174 advise (NULL, "only %d sequences allowed!", NUMATTRS);
1179 case MPUBSW: /* not implemented */
1195 if (*cp == '+' || *cp == '@') {
1196 advise (NULL, "sorry, no folders allowed!");
1203 if (!addsw && !deletesw && !listsw) {
1210 seqs[seqp++] = "unseen";
1214 msgs[msgp++] = "all";
1219 msgs[msgp++] = listsw ? "all" :"cur";
1220 for (msgnum = 0; msgnum < msgp; msgnum++)
1221 if (!m_convert (mp, msgs[msgnum]))
1225 printf ("invo_name=%s mypath=%s defpath=%s\n",
1226 invo_name, mypath, defpath);
1227 printf ("ctxpath=%s context flags=%s\n",
1228 ctxpath, snprintb (buf, sizeof(buf), (unsigned) ctxflags, DBITS));
1229 printf ("foldpath=%s flags=%s\n",
1231 snprintb (buf, sizeof(buf), (unsigned) mp->msgflags, FBITS));
1232 printf ("hghmsg=%d lowmsg=%d nummsg=%d curmsg=%d\n",
1233 mp->hghmsg, mp->lowmsg, mp->nummsg, mp->curmsg);
1234 printf ("lowsel=%d hghsel=%d numsel=%d\n",
1235 mp->lowsel, mp->hghsel, mp->numsel);
1236 printf ("lowoff=%d hghoff=%d\n", mp->lowoff, mp->hghoff);
1239 if (seqp == 0 && (addsw || deletesw)) {
1240 advise (NULL, "-%s requires at least one -sequence argument",
1241 addsw ? "add" : "delete");
1247 for (seqp = 0; seqs[seqp]; seqp++)
1248 if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
1253 for (seqp = 0; seqs[seqp]; seqp++)
1254 if (!seq_delsel (mp, seqs[seqp], 0, zerosw))
1258 /* Listing messages in sequences */
1261 /* list the given sequences */
1262 for (seqp = 0; seqs[seqp]; seqp++)
1263 seq_print (mp, seqs[seqp]);
1265 /* else list them all */
1271 for (msgnum = mp->lowsel;
1272 msgnum <= mp->hghsel && !interrupted;
1274 if (is_selected (mp, msgnum)) {
1275 printf ("%*d: id=%d top=%d start=%ld stop=%ld %s\n",
1278 Msgs[msgnum].m_bboard_id,
1280 (long) Msgs[msgnum].m_start,
1281 (long) Msgs[msgnum].m_stop,
1282 snprintb (buf, sizeof(buf),
1283 (unsigned) mp->msgstats[msgnum - mp->lowoff],
1285 if (Msgs[msgnum].m_scanl)
1286 printf ("%s", Msgs[msgnum].m_scanl);
1292 static struct swit mhnswit[] = {
1295 #define MHNNAUTOSW 1
1297 #define MHNDEBUGSW 2
1299 #define MHNEBCDICSW 3
1300 { "ebcdicsafe", 0 },
1301 #define MHNNEBCDICSW 4
1302 { "noebcdicsafe", 0 },
1304 { "form formfile", 4 },
1307 #define MHNNHEADSW 7
1311 #define MHNNLISTSW 9
1313 #define MHNPARTSW 10
1314 { "part number", 0 },
1315 #define MHNSIZESW 11
1317 #define MHNNSIZESW 12
1318 { "norealsize", 0 },
1319 #define MHNRFC934SW 13
1320 { "rfc934mode", 0 },
1321 #define MHNNRFC934SW 14
1322 { "norfc934mode", 0 },
1323 #define MHNSERIALSW 15
1324 { "serialonly", 0 },
1325 #define MHNNSERIALSW 16
1326 { "noserialonly", 0 },
1327 #define MHNSHOWSW 17
1329 #define MHNNSHOWSW 18
1331 #define MHNSTORESW 19
1333 #define MHNNSTORESW 20
1335 #define MHNTYPESW 21
1336 { "type content", 0 },
1337 #define MHNVERBSW 22
1339 #define MHNNVERBSW 23
1341 #define MHNHELPSW 24
1343 #define MHNPROGSW 25
1344 { "moreproc program", -4 },
1345 #define MHNNPROGSW 26
1346 { "nomoreproc", -3 },
1348 { "length lines", -4 },
1350 { "width columns", -4 },
1356 mhncmd (char **args)
1358 int msgp = 0, vecp = 1;
1360 char *cp, buf[BUFSIZ];
1361 char *msgs[MAXARGS], *vec[MAXARGS];
1364 forkcmd (args, cmd_name);
1367 while ((cp = *args++)) {
1369 switch (smatch (++cp, mhnswit)) {
1371 ambigsw (cp, mhnswit);
1374 fprintf (stderr, "-%s unknown\n", cp);
1377 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1378 print_help (buf, mhnswit, 1);
1413 if (!(cp = *args++) || *cp == '-') {
1414 advise (NULL, "missing argument to %s", args[-2]);
1421 if (*cp == '+' || *cp == '@') {
1422 advise (NULL, "sorry, no folders allowed!");
1430 vec[vecp++] = "-file";
1433 msgs[msgp++] = "cur";
1434 for (msgnum = 0; msgnum < msgp; msgnum++)
1435 if (!m_convert (mp, msgs[msgnum]))
1440 for (msgnum = mp->lowsel;
1441 msgnum <= mp->hghsel && !interrupted;
1443 if (is_selected (mp, msgnum))
1444 if (process (msgnum, cmd_name, vecp, vec)) {
1445 unset_selected (mp, msgnum);
1449 seq_setcur (mp, mp->hghsel);
1453 static struct swit packswit[] = {
1461 static int mbx_style = MMDF_FORMAT;
1464 packcmd (char **args)
1466 int msgp = 0, md, msgnum;
1467 char *cp, *file = NULL;
1468 char buf[BUFSIZ], *msgs[MAXARGS];
1472 forkcmd (args, cmd_name);
1476 while ((cp = *args++)) {
1478 switch (smatch (++cp, packswit)) {
1480 ambigsw (cp, packswit);
1483 fprintf (stderr, "-%s unknown\n", cp);
1486 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1487 print_help (buf, packswit, 1);
1491 if (!(file = *args++) || *file == '-') {
1492 advise (NULL, "missing argument to %s", args[-2]);
1497 if (*cp == '+' || *cp == '@') {
1498 advise (NULL, "sorry, no folders allowed!");
1507 file = path (file, TFILE);
1508 if (stat (file, &st) == NOTOK) {
1509 if (errno != ENOENT) {
1510 advise (file, "error on file");
1513 md = getanswer (cp = concat ("Create file \"", file, "\"? ", NULL));
1520 msgs[msgp++] = "all";
1521 for (msgnum = 0; msgnum < msgp; msgnum++)
1522 if (!m_convert (mp, msgs[msgnum]))
1526 if ((md = mbx_open (file, mbx_style, getuid (), getgid (), m_gmprot ())) == NOTOK) {
1527 advise (file, "unable to open");
1530 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1531 if (is_selected (mp, msgnum))
1532 if (pack (file, md, msgnum) == NOTOK)
1534 mbx_close (file, md);
1536 if (mp->hghsel != mp->curmsg)
1537 seq_setcur (mp, mp->lowsel);
1545 pack (char *mailbox, int md, int msgnum)
1549 if (Msgs[msgnum].m_bboard_id == 0)
1552 zp = msh_ready (msgnum, 1);
1553 return mbx_write (mailbox, md, zp, Msgs[msgnum].m_bboard_id,
1554 0L, ftell (zp), Msgs[msgnum].m_stop, 1, 1);
1559 packhak (char **args)
1562 char *cp, *file = NULL;
1564 while ((cp = *args++)) {
1566 switch (smatch (++cp, packswit)) {
1573 if (!(file = *args++) || *file == '-')
1577 if (*cp == '+' || *cp == '@')
1581 file = path (file ? file : "./msgbox", TFILE);
1582 result = access (file, F_OK) == NOTOK ? OK : NOTOK;
1589 static struct swit pickswit[] = {
1601 { "cc pattern", 0 },
1603 { "date pattern", 0 },
1605 { "from pattern", 0 },
1607 { "search pattern", 0 },
1609 { "subject pattern", 0 },
1611 { "to pattern", 0 },
1613 { "-othercomponent pattern", 15 },
1615 { "after date", 0 },
1617 { "before date", 0 },
1619 { "datefield field", 5 },
1621 { "sequence name", 0 },
1641 pickcmd (char **args)
1643 int zerosw = 1, msgp = 0, seqp = 0;
1644 int vecp = 0, hi, lo, msgnum;
1645 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
1646 char *seqs[NUMATTRS], *vec[MAXARGS];
1649 while ((cp = *args++)) {
1655 switch (smatch (cp, pickswit)) {
1657 ambigsw (cp, pickswit);
1660 fprintf (stderr, "-%s unknown\n", cp);
1663 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1664 print_help (buf, pickswit, 1);
1678 if (!(cp = *args++)) {/* allow -xyz arguments */
1679 advise (NULL, "missing argument to %s", args[-2]);
1685 advise (NULL, "internal error!");
1696 if (!(cp = *args++) || *cp == '-') {
1697 advise (NULL, "missing argument to %s", args[-2]);
1700 if (seqp < NUMATTRS)
1703 advise (NULL, "only %d sequences allowed!", NUMATTRS);
1714 case PIPUSW: /* not implemented */
1721 if (*cp == '+' || *cp == '@') {
1722 advise (NULL, "sorry, no folders allowed!");
1731 msgs[msgp++] = "all";
1732 for (msgnum = 0; msgnum < msgp; msgnum++)
1733 if (!m_convert (mp, msgs[msgnum]))
1738 if (!pcompile (vec, NULL))
1744 for (msgnum = mp->lowsel;
1745 msgnum <= mp->hghsel && !interrupted;
1747 if (is_selected (mp, msgnum)) {
1748 zp = msh_ready (msgnum, 1);
1749 if (pmatches (zp, msgnum, fmsh ? 0L : Msgs[msgnum].m_start,
1750 fmsh ? 0L : Msgs[msgnum].m_stop)) {
1757 unset_selected (mp, msgnum);
1768 if (mp->numsel <= 0) {
1769 advise (NULL, "no messages match specification");
1774 for (seqp = 0; seqs[seqp]; seqp++)
1775 if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
1778 printf ("%d hit%s\n", mp->numsel, mp->numsel == 1 ? "" : "s");
1782 static struct swit replswit[] = {
1786 { "noannotate", 0 },
1792 { "draftfolder +folder", 0 },
1794 { "draftmessage msg", 0 },
1796 { "nodraftfolder", 0 },
1798 { "editor editor", 0 },
1802 { "fcc +folder", 0 },
1804 { "filter filterfile", 0 },
1806 { "form formfile", 0 },
1816 { "whatnowproc program", 0 },
1820 { "width columns", 0 },
1828 replcmd (char **args)
1831 char *cp, *msg = NULL;
1832 char buf[BUFSIZ], *vec[MAXARGS];
1835 forkcmd (args, cmd_name);
1839 while ((cp = *args++)) {
1841 switch (smatch (++cp, replswit)) {
1843 ambigsw (cp, replswit);
1846 fprintf (stderr, "-%s unknown\n", cp);
1849 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1850 print_help (buf, replswit, 1);
1853 case REANSW: /* not implemented */
1878 if (!(cp = *args++) || *cp == '-') {
1879 advise (NULL, "missing argument to %s", args[-2]);
1885 if (*cp == '+' || *cp == '@') {
1886 advise (NULL, "sorry, no folders allowed!");
1891 advise (NULL, "only one message at a time!");
1899 vec[vecp++] = "-file";
1903 if (!m_convert (mp, msg))
1907 if (mp->numsel > 1) {
1908 advise (NULL, "only one message at a time!");
1911 process (mp->hghsel, cmd_name, vecp, vec);
1912 seq_setcur (mp, mp->hghsel);
1916 static struct swit rmmswit[] = {
1924 rmmcmd (char **args)
1926 int msgp = 0, msgnum;
1927 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
1929 while ((cp = *args++)) {
1931 switch (smatch (++cp, rmmswit)) {
1933 ambigsw (cp, rmmswit);
1936 fprintf (stderr, "-%s unknown\n", cp);
1939 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1940 print_help (buf, rmmswit, 1);
1943 if (*cp == '+' || *cp == '@') {
1944 advise (NULL, "sorry, no folders allowed!");
1952 msgs[msgp++] = "cur";
1953 for (msgnum = 0; msgnum < msgp; msgnum++)
1954 if (!m_convert (mp, msgs[msgnum]))
1965 register int msgnum, vecp;
1967 char buffer[BUFSIZ], *vec[MAXARGS];
1971 if (mp->numsel > MAXARGS - 1) {
1972 advise (NULL, "more than %d messages for %s exec",
1973 MAXARGS - 1, rmmproc);
1977 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1978 if (is_selected (mp, msgnum))
1979 vec[vecp++] = getcpy (m_name (msgnum));
1981 forkcmd (vec, rmmproc);
1982 for (vecp = 0; vec[vecp]; vecp++)
1986 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1987 if (is_selected (mp, msgnum)) {
1988 strncpy (buffer, m_backup (cp = m_name (msgnum)), sizeof(buffer));
1989 if (rename (cp, buffer) == NOTOK)
1990 admonish (buffer, "unable to rename %s to", cp);
1994 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1995 if (is_selected (mp, msgnum)) {
1996 set_deleted (mp, msgnum);
1997 unset_exists (mp, msgnum);
2000 if (pmsh && pop_dele (msgnum) != OK)
2001 fprintf (stderr, "%s", response);
2006 if ((mp->nummsg -= mp->numsel) <= 0) {
2008 admonish (NULL, "no messages remaining in +%s", fmsh);
2010 admonish (NULL, "no messages remaining in %s", mp->foldpath);
2011 mp->lowmsg = mp->hghmsg = mp->nummsg = 0;
2013 if (mp->lowsel == mp->lowmsg) {
2014 for (msgnum = mp->lowmsg + 1; msgnum <= mp->hghmsg; msgnum++)
2015 if (does_exist (mp, msgnum))
2017 mp->lowmsg = msgnum;
2019 if (mp->hghsel == mp->hghmsg) {
2020 for (msgnum = mp->hghmsg - 1; msgnum >= mp->lowmsg; msgnum--)
2021 if (does_exist (mp, msgnum))
2023 mp->hghmsg = msgnum;
2026 mp->msgflags |= MODIFIED;
2031 static struct swit scanswit[] = {
2037 { "form formatfile", 0 },
2039 { "format string", 5 },
2045 { "width columns", 0 },
2053 scancmd (char **args)
2055 #define equiv(a,b) (a ? b && !strcmp (a, b) : !b)
2057 int clearsw = 0, headersw = 0, width = 0, msgp = 0;
2058 int msgnum, optim, state;
2059 char *cp, *form = NULL, *format = NULL;
2060 char buf[BUFSIZ], *nfs, *msgs[MAXARGS];
2064 static int p_optim = 0;
2067 static int s_optim = 0;
2068 static char *s_form = NULL, *s_format = NULL;
2070 while ((cp = *args++)) {
2072 switch (smatch (++cp, scanswit)) {
2074 ambigsw (cp, scanswit);
2077 fprintf (stderr, "-%s unknown\n", cp);
2080 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
2081 print_help (buf, scanswit, 1);
2097 if (!(form = *args++) || *form == '-') {
2098 advise (NULL, "missing argument to %s", args[-2]);
2104 if (!(format = *args++) || *format == '-') {
2105 advise (NULL, "missing argument to %s", args[-2]);
2111 if (!(cp = *args++) || *cp == '-') {
2112 advise (NULL, "missing argument to %s", args[-2]);
2118 if (*cp == '+' || *cp == '@') {
2119 advise (NULL, "sorry, no folders allowed!");
2127 msgs[msgp++] = "all";
2128 for (msgnum = 0; msgnum < msgp; msgnum++)
2129 if (!m_convert (mp, msgs[msgnum]))
2133 /* Get new format string */
2134 nfs = new_fs (form, format, FORMAT);
2136 /* force scansbr to (re)compile format */
2143 s_optim = optim = 1;
2144 s_form = form ? getcpy (form) : NULL;
2145 s_format = format ? getcpy (format) : NULL;
2154 width = sc_width ();
2156 for (dp = nfs, i = 0; *dp; dp++, i++)
2157 if (*dp == '\\' || *dp == '"' || *dp == '\n')
2160 if ((ep = malloc ((unsigned) i)) == NULL)
2161 adios (NULL, "out of memory");
2162 for (dp = nfs, fp = ep; *dp; dp++) {
2164 *fp++ = '\\', *fp++ = 'n';
2167 if (*dp == '"' || *dp == '\\')
2173 if (pop_command ("XTND SCAN %d \"%s\"", width, ep) == OK)
2182 optim = equiv (s_form, form) && equiv (s_format, format);
2186 if (p_optim && optim) {
2187 for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++)
2188 if (!is_selected(mp, msgnum) || Msgs[msgnum].m_scanl)
2190 if (msgnum > mp->hghmsg && pop_command ("LIST") == OK) {
2191 fprintf (stderr, "Stand-by...");
2197 switch (pop_multiline ()) {
2199 fprintf (stderr, "%s", response);
2202 fprintf (stderr,"\n");
2206 if (sscanf (response, "%d %d", &msgnum, &size) == 2
2207 && mp->lowmsg <= msgnum
2208 && msgnum <= mp->hghmsg
2209 && (cp = strchr(response, '#'))
2211 Msgs[msgnum].m_scanl = concat (cp, "\n", NULL);
2222 for (msgnum = mp->lowsel;
2223 msgnum <= mp->hghsel && !interrupted;
2225 if (is_selected (mp, msgnum)) {
2226 if (optim && Msgs[msgnum].m_scanl)
2227 printf ("%s", Msgs[msgnum].m_scanl);
2233 && is_virtual (mp, msgnum)
2234 && pop_command ("LIST %d", msgnum) == OK
2235 && (cp = strchr(response, '#'))
2237 Msgs[msgnum].m_scanl = concat (cp, "\n", NULL);
2238 printf ("%s", Msgs[msgnum].m_scanl);
2244 zp = msh_ready (msgnum, 0);
2245 switch (state = scan (zp, msgnum, 0, nfs, width,
2246 msgnum == mp->curmsg,
2247 is_unseen (mp, msgnum),
2248 headersw ? (fmsh ? fmsh : mp->foldpath) : NULL,
2249 fmsh ? 0L : (long) (Msgs[msgnum].m_stop - Msgs[msgnum].m_start),
2255 Msgs[msgnum].m_scanl = getcpy (scanl);
2259 advise (NULL, "scan() botch (%d)", state);
2263 printf ("%*d empty\n", DMAXFOLDER, msgnum);
2275 static struct swit showswit[] = {
2279 { "form formfile", 4 },
2281 { "moreproc program", 4 },
2283 { "nomoreproc", 3 },
2285 { "length lines", 4 },
2287 { "width columns", 4 },
2289 { "showproc program", 4 },
2291 { "noshowproc", 3 },
2303 showcmd (char **args)
2305 int headersw = 1, nshow = 0, msgp = 0, vecp = 1;
2306 int mhl = 0, seqnum = -1, mode = 0, i, msgnum;
2307 char *cp, *proc = showproc, buf[BUFSIZ];
2308 char *msgs[MAXARGS], *vec[MAXARGS];
2310 if (!strcasecmp (cmd_name, "next"))
2313 if (!strcasecmp (cmd_name, "prev"))
2315 while ((cp = *args++)) {
2317 switch (i = smatch (++cp, showswit)) {
2319 ambigsw (cp, showswit);
2326 snprintf (buf, sizeof(buf), "%s %s[switches] [switches for showproc]",
2327 cmd_name, mode ? NULL : "[msgs] ");
2328 print_help (buf, showswit, 1);
2336 if (!(cp = *args++) || *cp == '-') {
2337 advise (NULL, "missing argument to %s", args[-2]);
2349 if (!(proc = *args++) || *proc == '-') {
2350 advise (NULL, "missing argument to %s", args[-2]);
2360 advise (NULL, "sorry, -%s not allowed!", showswit[i].sw);
2363 if (*cp == '+' || *cp == '@') {
2364 advise (NULL, "sorry, no folders allowed!");
2370 "usage: %s [switches] [switches for showproc]\n",
2380 msgs[msgp++] = mode > 0 ? "next" : mode < 0 ? "prev" : "cur";
2381 for (msgnum = 0; msgnum < msgp; msgnum++)
2382 if (!m_convert (mp, msgs[msgnum]))
2386 if (!nshow && !getenv ("NOMHNPROC"))
2387 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
2388 if (is_selected (mp, msgnum) && is_nontext (msgnum)) {
2389 proc = showmimeproc;
2390 vec[vecp++] = "-show";
2391 vec[vecp++] = "-file";
2399 if (strcmp (showproc, "mhl") == 0) {
2405 seqnum = seq_getnum (mp, "unseen");
2406 vec[0] = r1bindex (proc, '/');
2409 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
2410 if (is_selected (mp, msgnum)) {
2411 vec[vecp++] = getcpy (m_name (msgnum));
2413 seq_delmsg (mp, "unseen", msgnum);
2416 if (mp->numsel == 1 && headersw)
2418 mhlsbr (vecp, vec, mhl_action);
2419 m_eomsbr ((int (*)()) 0);
2424 for (msgnum = mp->lowsel;
2425 msgnum <= mp->hghsel && !interrupted;
2427 if (is_selected (mp, msgnum)) {
2428 switch (ask (msgnum)) {
2429 case NOTOK: /* QUIT */
2436 if (mp->numsel == 1 && headersw)
2439 copy_message (msgnum, stdout);
2441 process (msgnum, proc, vecp, vec);
2444 seq_delmsg (mp, "unseen", msgnum);
2451 seq_setcur (mp, mp->hghsel);
2458 if (Msgs[msgnum].m_bboard_id == 0)
2461 printf ("(Message %d", msgnum);
2462 if (Msgs[msgnum].m_bboard_id > 0)
2463 printf (", %s: %d", BBoard_ID, Msgs[msgnum].m_bboard_id);
2472 return (ftell (mhlfp) >= Msgs[mhlnum].m_stop);
2477 mhl_action (char *name)
2481 if ((msgnum = m_atoi (name)) < mp->lowmsg
2482 || msgnum > mp->hghmsg
2483 || !does_exist (mp, msgnum))
2487 mhlfp = msh_ready (msgnum, 1);
2489 m_eomsbr (eom_action);
2501 if (mp->numsel == 1 || !interactive || redirected)
2504 if (SOprintf ("Press <return> to list \"%d\"...", msgnum)) {
2505 if (mp->lowsel != msgnum)
2507 printf ("Press <return> to list \"%d\"...", msgnum);
2513 read (fileno (stdout), buf, sizeof buf);
2515 switch (setjmp (sigenv)) {
2518 read (fileno (stdout), buf, sizeof buf);/* fall... */
2526 if (strchr(buf, '\n') == NULL)
2530 told_to_quit = interrupted = 0;
2545 is_nontext (int msgnum)
2549 char buf[BUFSIZ], name[NAMESZ];
2552 if (Msgs[msgnum].m_flags & MHNCHK)
2553 return (Msgs[msgnum].m_flags & MHNYES);
2554 Msgs[msgnum].m_flags |= MHNCHK;
2556 fp = msh_ready (msgnum, 1);
2559 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
2564 * Check Content-Type field
2566 if (!strcasecmp (name, TYPE_FIELD)) {
2570 cp = add (buf, NULL);
2571 while (state == FLDPLUS) {
2572 state = m_getfld (state, name, buf, sizeof buf, fp);
2579 for (; isspace (*bp); bp++)
2584 for (bp++, i = 0;;) {
2614 for (dp = bp; istoken (*dp); dp++)
2621 if ((result = (strcasecmp (bp, "plain") != 0)))
2624 for (dp++; isspace (*dp); dp++)
2627 if ((result = !uprf (dp, "charset")))
2629 dp += sizeof "charset" - 1;
2630 while (isspace (*dp))
2634 while (isspace (*dp))
2637 if ((bp = strchr(++dp, '"')))
2640 for (bp = dp; *bp; bp++)
2641 if (isspace (*bp)) {
2647 /* Default character set */
2650 /* Check the character set */
2651 result = !check_charset (dp, strlen (dp));
2653 if (!(result = (strcasecmp (bp, "text") != 0))) {
2663 Msgs[msgnum].m_flags |= MHNYES;
2670 * Check Content-Transfer-Encoding field
2672 if (!strcasecmp (name, ENCODING_FIELD)) {
2673 cp = add (buf, NULL);
2674 while (state == FLDPLUS) {
2675 state = m_getfld (state, name, buf, sizeof buf, fp);
2678 for (bp = cp; isspace (*bp); bp++)
2680 for (dp = bp; istoken (*dp); dp++)
2683 result = (strcasecmp (bp, "7bit")
2684 && strcasecmp (bp, "8bit")
2685 && strcasecmp (bp, "binary"));
2689 Msgs[msgnum].m_flags |= MHNYES;
2696 * Just skip the rest of this header
2697 * field and go to next one.
2699 while (state == FLDPLUS)
2700 state = m_getfld (state, name, buf, sizeof(buf), fp);
2704 * We've passed the message header,
2705 * so message is just text.
2713 static struct swit sortswit[] = {
2715 { "datefield field", 0 },
2717 { "textfield field", 0 },
2719 { "notextfield", 0 },
2721 { "limit days", 0 },
2735 sortcmd (char **args)
2737 int msgp = 0, msgnum;
2738 char *cp, *datesw = NULL, *subjsw = NULL;
2739 char buf[BUFSIZ], *msgs[MAXARGS];
2743 forkcmd (args, cmd_name);
2747 while ((cp = *args++)) {
2749 switch (smatch (++cp, sortswit)) {
2751 ambigsw (cp, sortswit);
2754 fprintf (stderr, "-%s unknown\n", cp);
2757 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
2758 print_help (buf, sortswit, 1);
2763 advise (NULL, "only one date field at a time!");
2766 if (!(datesw = *args++) || *datesw == '-') {
2767 advise (NULL, "missing argument to %s", args[-2]);
2774 advise (NULL, "only one text field at a time!");
2777 if (!(subjsw = *args++) || *subjsw == '-') {
2778 advise (NULL, "missing argument to %s", args[-2]);
2786 case SOLIMT: /* too hard */
2787 if (!(cp = *args++) || *cp == '-') {
2788 advise (NULL, "missing argument to %s", args[-2]);
2792 case SOVERB: /* not implemented */
2796 if (*cp == '+' || *cp == '@') {
2797 advise (NULL, "sorry, no folders allowed!");
2805 msgs[msgp++] = "all";
2808 for (msgnum = 0; msgnum < msgp; msgnum++)
2809 if (!m_convert (mp, msgs[msgnum]))
2813 twscopy (&tb, dlocaltimenow ());
2815 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
2816 if (Msgs[msgnum].m_scanl) {
2817 free (Msgs[msgnum].m_scanl);
2818 Msgs[msgnum].m_scanl = NULL;
2820 if (is_selected (mp, msgnum)) {
2821 if (get_fields (datesw, subjsw, msgnum, &Msgs[msgnum]))
2822 twscopy (&Msgs[msgnum].m_tb,
2823 msgnum != mp->lowsel ? &Msgs[msgnum - 1].m_tb : &tb);
2825 else /* m_scaln is already NULL */
2826 twscopy (&Msgs[msgnum].m_tb, &tb);
2827 Msgs[msgnum].m_stats = mp->msgstats[msgnum - mp->lowoff];
2828 if (mp->curmsg == msgnum)
2829 Msgs[msgnum].m_stats |= CUR;
2832 qsort ((char *) &Msgs[mp->lowsel], mp->hghsel - mp->lowsel + 1,
2833 sizeof(struct Msg), (qsort_comp) (subjsw ? subsort : msgsort));
2835 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
2836 if (subjsw && Msgs[msgnum].m_scanl) {
2837 free (Msgs[msgnum].m_scanl); /* from subjsort */
2838 Msgs[msgnum].m_scanl = NULL;
2840 mp->msgstats[msgnum - mp->lowoff] = Msgs[msgnum].m_stats & ~CUR;
2841 if (Msgs[msgnum].m_stats & CUR)
2842 seq_setcur (mp, msgnum);
2845 mp->msgflags |= MODIFIED;
2851 * get_fields - parse message, and get date and subject if needed.
2852 * We'll use the msgp->m_tb tws struct for the date, and overload
2853 * the msgp->m_scanl field with our subject string.
2856 get_fields (char *datesw, char *subjsw, int msgnum, struct Msg *msgp)
2858 int state, gotdate = 0;
2859 char *bp, buf[BUFSIZ], name[NAMESZ];
2860 struct tws *tw = (struct tws *) 0;
2863 zp = msh_ready (msgnum, 0);
2864 for (state = FLD;;) {
2865 switch (state = m_getfld (state, name, buf, sizeof buf, zp)) {
2869 if (!strcasecmp (name, datesw)) {
2871 while (state == FLDPLUS) {
2872 state = m_getfld (state, name, buf, sizeof buf, zp);
2875 if ((tw = dparsetime (bp)) == NULL)
2877 "unable to parse %s field in message %d",
2880 twscopy (&(msgp->m_tb), tw);
2882 if (!subjsw) /* not using this, or already done */
2883 break; /* all done! */
2886 else if (subjsw && !strcasecmp(name, subjsw)) {
2888 while (state == FLDPLUS) {
2889 state = m_getfld (state, name, buf, sizeof buf, zp);
2892 msgp->m_scanl = sosmash(subjsw, bp);
2894 break; /* date done so we're done */
2896 subjsw = (char *)0;/* subject done, need date */
2898 while (state == FLDPLUS) /* flush this one */
2899 state = m_getfld (state, name, buf, sizeof buf, zp);
2910 admonish (NULL, "format error in message %d", msgnum);
2911 if (msgp->m_scanl) { /* this might need free'd */
2912 free (msgp->m_scanl); /* probably can't use subj anyway */
2913 msgp->m_scanl = NULL;
2918 adios (NULL, "internal error -- you lose");
2923 return OK; /* not an error if subj not found */
2925 admonish (NULL, "no %s field in message %d", datesw, msgnum);
2926 return NOTOK; /* NOTOK means use some other date */
2935 msgsort (struct Msg *a, struct Msg *b)
2937 return twsort (&a->m_tb, &b->m_tb);
2942 subsort (struct Msg *a, struct Msg *b)
2946 if (a->m_scanl && b->m_scanl)
2947 if ((i = strcmp (a->m_scanl, b->m_scanl)))
2950 return twsort (&a->m_tb, &b->m_tb);
2955 * try to make the subject "canonical": delete leading "re:", everything
2956 * but letters & smash letters to lower case.
2959 sosmash (char *subj, char *s)
2961 register char *cp, *dp, c;
2965 dp = s; /* dst pointer */
2966 if (!strcasecmp (subj, "subject"))
2973 *dp++ = isupper(c) ? tolower(c) : c;
2979 while ((c = *cp++)) {
2981 *dp++ = isupper(c) ? tolower(c) : c;
2991 process (int msgnum, char *proc, int vecp, char **vec)
2993 int child_id, status;
2998 strncpy (tmpfil, m_name (msgnum), sizeof(tmpfil));
2999 context_del (pfolder);
3000 context_replace (pfolder, fmsh);/* update current folder */
3002 context_save (); /* save the context file */
3006 strncpy (tmpfil, m_scratch ("", invo_name), sizeof(tmpfil));
3007 if ((out = fopen (tmpfil, "w")) == NULL) {
3013 strncpy (newfil, m_tmpfil (invo_name), sizeof(newfil));
3014 if ((out = fopen (newfil, "w")) == NULL) {
3016 advise (tmpfil, "unable to create temporary file");
3019 strncpy (tmpfil, newfil, sizeof(tmpfil));
3022 copy_message (msgnum, out);
3027 switch (child_id = fork ()) {
3029 advise ("fork", "unable to");
3035 SIGNAL (SIGINT, istat);
3036 SIGNAL (SIGQUIT, qstat);
3038 vec[vecp++] = tmpfil;
3042 fprintf (stderr, "unable to exec ");
3047 status = pidXwait (child_id, NULL);
3058 copy_message (int msgnum, FILE *out)
3061 static char buffer[BUFSIZ];
3064 zp = msh_ready (msgnum, 1);
3066 while (fgets (buffer, sizeof buffer, zp) != NULL) {
3067 fputs (buffer, out);
3068 if (interrupted && out == stdout)
3074 while (fgets (buffer, sizeof buffer, zp) != NULL
3075 && pos < Msgs[msgnum].m_stop) {
3076 fputs (buffer, out);
3077 pos += (long) strlen (buffer);
3078 if (interrupted && out == stdout)
3086 copy_digest (int msgnum, FILE *out)
3090 static char buffer[BUFSIZ];
3094 zp = msh_ready (msgnum, 1);
3097 while (fgets (buffer, sizeof buffer, zp) != NULL
3098 && !fmsh && pos < Msgs[msgnum].m_stop) {
3099 if (c == '\n' && *buffer == '-')
3101 fputs (buffer, out);
3102 c = buffer[strlen (buffer) - 1];
3104 pos += (long) strlen (buffer);
3105 if (interrupted && out == stdout)