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 *);
73 forkcmd (char **args, char *pgm)
78 vec[0] = r1bindex (pgm, '/');
79 copyip (args, vec + 1, MAXARGS - 1);
82 context_del (pfolder);
83 context_replace (pfolder, fmsh);/* update current folder */
85 context_save (); /* save the context file */
88 switch (child_id = fork ()) {
90 advise ("fork", "unable to");
95 SIGNAL (SIGINT, istat);
96 SIGNAL (SIGQUIT, qstat);
99 fprintf (stderr, "unable to exec ");
104 pidXwait (child_id, NULL);
107 if (fmsh) { /* assume the worst case */
108 mp->msgflags |= MODIFIED;
114 static struct swit distswit[] = {
120 { "draftfolder +folder", 0 },
122 { "draftmessage msg", 0 },
124 { "nodraftfolder", 0 },
126 { "editor editor", 0 },
130 { "form formfile", 0 },
136 { "whatnowproc program", 0 },
138 { "nowhatnowproc", 0 },
146 distcmd (char **args)
149 char *cp, *msg = NULL;
150 char buf[BUFSIZ], *vec[MAXARGS];
153 forkcmd (args, cmd_name);
157 while ((cp = *args++)) {
159 switch (smatch (++cp, distswit)) {
161 ambigsw (cp, distswit);
164 fprintf (stderr, "-%s unknown\n", cp);
167 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
168 print_help (buf, distswit, 1);
171 case DIANSW: /* not implemented */
189 if (!(cp = *args++) || *cp == '-') {
190 advise (NULL, "missing argument to %s", args[-2]);
196 if (*cp == '+' || *cp == '@') {
197 advise (NULL, "sorry, no folders allowed!");
202 advise (NULL, "only one message at a time!");
210 vec[vecp++] = "-file";
214 if (!m_convert (mp, msg))
218 if (mp->numsel > 1) {
219 advise (NULL, "only one message at a time!");
222 process (mp->hghsel, cmd_name, vecp, vec);
223 seq_setcur (mp, mp->hghsel);
227 static struct swit explswit[] = {
247 explcmd (char **args)
249 int inplace = 0, quietsw = 0, verbosw = 0;
250 int msgp = 0, hi, msgnum;
251 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
255 forkcmd (args, cmd_name);
259 while ((cp = *args++)) {
261 switch (smatch (++cp, explswit)) {
263 ambigsw (cp, explswit);
266 fprintf (stderr, "-%s unknown\n", cp);
269 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
270 print_help (buf, explswit, 1);
292 if (*cp == '+' || *cp == '@') {
293 advise (NULL, "sorry, no folders allowed!");
301 msgs[msgp++] = "cur";
302 for (msgnum = 0; msgnum < msgp; msgnum++)
303 if (!m_convert (mp, msgs[msgnum]))
307 smsgs = (struct Msg *)
308 calloc ((size_t) (MAXFOLDER + 2), sizeof *smsgs);
310 adios (NULL, "unable to allocate folder storage");
314 for (msgnum = mp->lowsel;
315 msgnum <= mp->hghsel && !interrupted;
317 if (is_selected (mp, msgnum))
318 if (burst (smsgs, msgnum, inplace, quietsw, verbosw) != OK)
321 free ((char *) smsgs);
324 seq_setcur (mp, mp->lowsel);
326 if (hi <= mp->hghmsg)
329 mp->msgflags |= MODIFIED;
335 burst (struct Msg *smsgs, int msgnum, int inplace, int quietsw, int verbosw)
337 int i, j, ld3, wasdlm, msgp;
339 char c, buffer[BUFSIZ];
342 ld3 = strlen (delim3);
344 if (Msgs[msgnum].m_scanl) {
345 free (Msgs[msgnum].m_scanl);
346 Msgs[msgnum].m_scanl = NULL;
349 pos = ftell (zp = msh_ready (msgnum, 1));
350 for (msgp = 0; msgp <= MAXFOLDER;) {
351 while (fgets (buffer, sizeof buffer, zp) != NULL
353 && pos < Msgs[msgnum].m_stop)
354 pos += (long) strlen (buffer);
355 if (feof (zp) || pos >= Msgs[msgnum].m_stop)
357 fseek (zp, pos, SEEK_SET);
358 smsgs[msgp].m_start = pos;
361 pos < Msgs[msgnum].m_stop
362 && fgets (buffer, sizeof buffer, zp) != NULL;
364 if (strncmp (buffer, delim3, ld3) == 0
365 && (msgp == 1 || c == '\n')
366 && peekc (zp) == '\n')
369 pos += (long) strlen (buffer);
371 wasdlm = strncmp (buffer, delim3, ld3) == 0;
372 if (smsgs[msgp].m_start != pos)
373 smsgs[msgp++].m_stop = (c == '\n' && wasdlm) ? pos - 1 : pos;
374 if (feof (zp) || pos >= Msgs[msgnum].m_stop) {
376 smsgs[msgp - 1].m_stop -= ((long) strlen (buffer) + 1);
379 pos += (long) strlen (buffer);
382 switch (msgp--) { /* toss "End of XXX Digest" */
384 adios (NULL, "burst() botch -- you lose big");
388 printf ("message %d not in digest format\n", msgnum);
393 printf ("%d message%s exploded from digest %d\n",
394 msgp, msgp != 1 ? "s" : "", msgnum);
398 if ((i = msgp + mp->hghmsg) > MAXFOLDER) {
399 advise (NULL, "more than %d messages", MAXFOLDER);
402 if (!(mp = folder_realloc (mp, mp->lowoff, i)))
403 adios (NULL, "unable to allocate folder storage");
408 if (mp->hghsel > msgnum)
412 for (i = mp->hghmsg; j > msgnum; i--, j--) {
414 printf ("message %d becomes message %d\n", j, i);
416 Msgs[i].m_bboard_id = Msgs[j].m_bboard_id;
417 Msgs[i].m_top = Msgs[j].m_top;
418 Msgs[i].m_start = Msgs[j].m_start;
419 Msgs[i].m_stop = Msgs[j].m_stop;
420 Msgs[i].m_scanl = NULL;
421 if (Msgs[j].m_scanl) {
422 free (Msgs[j].m_scanl);
423 Msgs[j].m_scanl = NULL;
425 copy_msg_flags (mp, i, j);
428 if (Msgs[msgnum].m_bboard_id == 0)
431 unset_selected (mp, msgnum);
432 i = inplace ? msgnum + msgp : mp->hghmsg;
433 for (j = msgp; j >= (inplace ? 0 : 1); i--, j--) {
434 if (verbosw && i != msgnum)
435 printf ("message %d of digest %d becomes message %d\n",
438 Msgs[i].m_bboard_id = Msgs[msgnum].m_bboard_id;
439 Msgs[i].m_top = Msgs[j].m_top;
440 Msgs[i].m_start = smsgs[j].m_start;
441 Msgs[i].m_stop = smsgs[j].m_stop;
442 Msgs[i].m_scanl = NULL;
443 copy_msg_flags (mp, i, msgnum);
450 static struct swit fileswit[] = {
462 { "src +folder", 0 },
466 { "rmmproc program", 0 },
476 filecmd (char **args)
478 int linksw = 0, msgp = 0;
479 int vecp = 1, i, msgnum;
480 char *cp, buf[BUFSIZ];
481 char *msgs[MAXARGS], *vec[MAXARGS];
484 forkcmd (args, cmd_name);
488 while ((cp = *args++)) {
490 switch (i = smatch (++cp, fileswit)) {
492 ambigsw (cp, fileswit);
495 fprintf (stderr, "-%s unknown\n", cp);
498 snprintf (buf, sizeof(buf), "%s +folder... [msgs] [switches]", cmd_name);
499 print_help (buf, fileswit, 1);
518 advise (NULL, "sorry, -%s not allowed!", fileswit[i].sw);
521 if (*cp == '+' || *cp == '@')
528 vec[vecp++] = "-file";
531 msgs[msgp++] = "cur";
532 for (msgnum = 0; msgnum < msgp; msgnum++)
533 if (!m_convert (mp, msgs[msgnum]))
538 for (msgnum = mp->lowsel;
539 msgnum <= mp->hghsel && !interrupted;
541 if (is_selected (mp, msgnum))
542 if (process (msgnum, fileproc, vecp, vec)) {
543 unset_selected (mp, msgnum);
547 if (mp->numsel != mp->nummsg || linksw)
548 seq_setcur (mp, mp->hghsel);
555 filehak (char **args)
557 int result, vecp = 0;
558 char *cp, *cwd, *vec[MAXARGS];
560 while ((cp = *args++)) {
562 switch (smatch (++cp, fileswit)) {
579 if (*cp == '+' || *cp == '@')
586 for (vecp = 0; (cp = vec[vecp]) && result == NOTOK; vecp++) {
588 cwd = getcpy (pwd ());
589 chdir (m_maildir (""));
590 cp = path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF);
591 if (access (m_maildir (cp), F_OK) == NOTOK)
602 static struct swit foldswit[] = {
640 foldcmd (char **args)
642 int fastsw = 0, headersw = 0, packsw = 0;
644 char *cp, *folder = NULL, *msg = NULL;
645 char buf[BUFSIZ], **vec = args;
650 while ((cp = *args++)) {
652 switch (smatch (++cp, foldswit)) {
654 ambigsw (cp, foldswit);
657 fprintf (stderr, "-%s unknown\n", cp);
660 snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]", cmd_name);
661 print_help (buf, foldswit, 1);
664 case FLALSW: /* not implemented */
694 if (*cp == '+' || *cp == '@') {
696 advise (NULL, "only one folder at a time!\n");
700 folder = fmsh ? path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF)
705 advise (NULL, "only one message at a time!\n");
714 advise (NULL, "null folder names are not permitted");
718 if (access (m_maildir (folder), R_OK) == NOTOK) {
719 advise (folder, "unable to read");
724 strncpy (buf, folder, sizeof(buf));
725 if (expand (buf) == NOTOK)
728 if (access (folder, R_OK) == NOTOK) {
729 advise (folder, "unable to read");
744 if (!m_convert (mp, msg))
748 if (mp->numsel > 1) {
749 advise (NULL, "only one message at a time!");
752 seq_setcur (mp, mp->hghsel);
757 forkcmd (vec, cmd_name);
761 if (mp->lowoff > 1 && !(mp = folder_realloc (mp, 1, mp->hghmsg)))
762 adios (NULL, "unable to allocate folder storage");
764 for (msgnum = mp->lowmsg, hole = 1; msgnum <= mp->hghmsg; msgnum++)
765 if (does_exist (mp, msgnum)) {
766 if (msgnum != hole) {
767 Msgs[hole].m_bboard_id = Msgs[msgnum].m_bboard_id;
768 Msgs[hole].m_top = Msgs[msgnum].m_top;
769 Msgs[hole].m_start = Msgs[msgnum].m_start;
770 Msgs[hole].m_stop = Msgs[msgnum].m_stop;
771 Msgs[hole].m_scanl = NULL;
772 if (Msgs[msgnum].m_scanl) {
773 free (Msgs[msgnum].m_scanl);
774 Msgs[msgnum].m_scanl = NULL;
776 copy_msg_flags (mp, hole, msgnum);
777 if (mp->curmsg == msgnum)
778 seq_setcur (mp, hole);
782 if (mp->nummsg > 0) {
784 mp->hghmsg = hole - 1;
786 mp->msgflags |= MODIFIED;
792 printf ("%s\n", fmsh ? fmsh : mp->foldpath);
795 printf ("\t\tFolder %*s# of messages (%*srange%*s); cur%*smsg\n",
796 DMAXFOLDER, "", DMAXFOLDER - 2, "", DMAXFOLDER - 2, "",
798 printf (args ? "%22s " : "%s ", fmsh ? fmsh : mp->foldpath);
800 /* check for empty folder */
801 if (mp->nummsg == 0) {
802 printf ("has no messages%*s",
803 mp->msgflags & OTHERS ? DMAXFOLDER * 2 + 4 : 0, "");
805 printf ("has %*d message%s (%*d-%*d)",
806 DMAXFOLDER, mp->nummsg, mp->nummsg != 1 ? "s" : "",
807 DMAXFOLDER, mp->lowmsg, DMAXFOLDER, mp->hghmsg);
808 if (mp->curmsg >= mp->lowmsg
809 && mp->curmsg <= mp->hghmsg)
810 printf ("; cur=%*d", DMAXFOLDER, mp->curmsg);
817 static struct swit forwswit[] = {
823 { "draftfolder +folder", 0 },
825 { "draftmessage msg", 0 },
827 { "nodraftfolder", 0 },
829 { "editor editor", 0 },
833 { "filter filterfile", 0 },
835 { "form formfile", 0 },
849 { "whatnowproc program", 0 },
859 forwcmd (char **args)
861 int msgp = 0, vecp = 1, msgnum;
862 char *cp, *filter = NULL, buf[BUFSIZ];
863 char *msgs[MAXARGS], *vec[MAXARGS];
866 forkcmd (args, cmd_name);
870 while ((cp = *args++)) {
872 switch (smatch (++cp, forwswit)) {
874 ambigsw (cp, forwswit);
877 fprintf (stderr, "-%s unknown\n", cp);
880 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
881 print_help (buf, forwswit, 1);
884 case FOANSW: /* not implemented */
904 if (!(cp = *args++) || *cp == '-') {
905 advise (NULL, "missing argument to %s", args[-2]);
911 if (!(filter = *args++) || *filter == '-') {
912 advise (NULL, "missing argument to %s", args[-2]);
917 if (access (filter = myfilter, R_OK) == NOTOK) {
918 advise (filter, "unable to read default filter file");
926 if (*cp == '+' || *cp == '@') {
927 advise (NULL, "sorry, no folders allowed!");
934 /* foil search of .mh_profile */
935 snprintf (buf, sizeof(buf), "%sXXXXXX", invo_name);
937 vec[0] = (char *)mkstemp (buf);
939 vec[0] = (char *)mktemp (buf);
941 vec[vecp++] = "-file";
944 msgs[msgp++] = "cur";
945 for (msgnum = 0; msgnum < msgp; msgnum++)
946 if (!m_convert (mp, msgs[msgnum]))
951 strncpy (buf, filter, sizeof(buf));
952 if (expand (buf) == NOTOK)
954 if (access (filter = getcpy (etcpath (buf)), R_OK) == NOTOK) {
955 advise (filter, "unable to read");
960 forw (cmd_name, filter, vecp, vec);
961 seq_setcur (mp, mp->hghsel);
968 forw (char *proc, char *filter, int vecp, char **vec)
970 int i, child_id, msgnum, msgcnt;
971 char tmpfil[80], *args[MAXARGS];
974 strncpy (tmpfil, m_tmpfil (invo_name), sizeof(tmpfil));
977 switch (child_id = fork ()) {
979 advise ("fork", "unable to");
982 case OK: /* "trust me" */
983 if (freopen (tmpfil, "w", stdout) == NULL) {
984 fprintf (stderr, "unable to create ");
988 args[0] = r1bindex (mhlproc, '/');
990 args[i++] = "-forwall";
993 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
994 if (is_selected (mp, msgnum))
995 args[i++] = getcpy (m_name (msgnum));
997 mhlsbr (i, args, mhl_action);
998 m_eomsbr ((int (*) ()) 0);
1003 if (pidXwait (child_id, NULL))
1008 if ((out = fopen (tmpfil, "w")) == NULL) {
1009 advise (tmpfil, "unable to create temporary file");
1014 for (msgnum = mp->lowsel;
1015 msgnum <= mp->hghsel && !interrupted;
1017 if (is_selected (mp, msgnum)) {
1018 fprintf (out, "\n\n-------");
1019 if (msgnum == mp->lowsel)
1020 fprintf (out, " Forwarded Message%s",
1021 mp->numsel > 1 ? "s" : "");
1023 fprintf (out, " Message %d", msgcnt);
1024 fprintf (out, "\n\n");
1025 copy_digest (msgnum, out);
1029 fprintf (out, "\n\n------- End of Forwarded Message%s\n",
1030 mp->numsel > 1 ? "s" : "");
1036 switch (child_id = fork ()) {
1038 advise ("fork", "unable to");
1043 SIGNAL (SIGINT, istat);
1044 SIGNAL (SIGQUIT, qstat);
1046 vec[vecp++] = tmpfil;
1050 fprintf (stderr, "unable to exec ");
1055 pidXwait (child_id, NULL);
1063 static char *hlpmsg[] = {
1064 "The %s program emulates many of the commands found in the nmh",
1065 "system. Instead of operating on nmh folders, commands to %s concern",
1068 "To see the list of commands available, just type a ``?'' followed by",
1069 "the RETURN key. To find out what switches each command takes, type",
1070 "the name of the command followed by ``-help''. To leave %s, use the",
1071 "``quit'' command.",
1073 "Although a lot of nmh commands are found in %s, not all are fully",
1074 "implemented. %s will always recognize all legal switches for a",
1075 "given command though, and will let you know when you ask for an",
1076 "option that it is unable to perform.",
1078 "Running %s is fun, but using nmh from your shell is far superior.",
1079 "After you have familiarized yourself with the nmh style by using %s,",
1080 "you should try using nmh from the shell. You can still use %s for",
1081 "message files that aren't in nmh format, such as BBoard files.",
1087 helpcmd (char **args)
1091 for (i = 0; hlpmsg[i]; i++) {
1092 printf (hlpmsg[i], invo_name);
1098 static struct swit markswit[] = {
1106 { "sequence name", 0 },
1124 markcmd (char **args)
1126 int addsw = 0, deletesw = 0, debugsw = 0;
1127 int listsw = 0, zerosw = 0, seqp = 0;
1128 int msgp = 0, msgnum;
1129 char *cp, buf[BUFSIZ];
1130 char *seqs[NUMATTRS + 1], *msgs[MAXARGS];
1132 while ((cp = *args++)) {
1134 switch (smatch (++cp, markswit)) {
1136 ambigsw (cp, markswit);
1139 fprintf (stderr, "-%s unknown\n", cp);
1142 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1143 print_help (buf, markswit, 1);
1148 deletesw = listsw = 0;
1156 addsw = deletesw = 0;
1160 if (!(cp = *args++) || *cp == '-') {
1161 advise (NULL, "missing argument to %s", args[-2]);
1164 if (seqp < NUMATTRS)
1167 advise (NULL, "only %d sequences allowed!", NUMATTRS);
1172 case MPUBSW: /* not implemented */
1188 if (*cp == '+' || *cp == '@') {
1189 advise (NULL, "sorry, no folders allowed!");
1196 if (!addsw && !deletesw && !listsw) {
1203 seqs[seqp++] = "unseen";
1207 msgs[msgp++] = "all";
1212 msgs[msgp++] = listsw ? "all" :"cur";
1213 for (msgnum = 0; msgnum < msgp; msgnum++)
1214 if (!m_convert (mp, msgs[msgnum]))
1218 printf ("invo_name=%s mypath=%s defpath=%s\n",
1219 invo_name, mypath, defpath);
1220 printf ("ctxpath=%s context flags=%s\n",
1221 ctxpath, snprintb (buf, sizeof(buf), (unsigned) ctxflags, DBITS));
1222 printf ("foldpath=%s flags=%s\n",
1224 snprintb (buf, sizeof(buf), (unsigned) mp->msgflags, FBITS));
1225 printf ("hghmsg=%d lowmsg=%d nummsg=%d curmsg=%d\n",
1226 mp->hghmsg, mp->lowmsg, mp->nummsg, mp->curmsg);
1227 printf ("lowsel=%d hghsel=%d numsel=%d\n",
1228 mp->lowsel, mp->hghsel, mp->numsel);
1229 printf ("lowoff=%d hghoff=%d\n", mp->lowoff, mp->hghoff);
1232 if (seqp == 0 && (addsw || deletesw)) {
1233 advise (NULL, "-%s requires at least one -sequence argument",
1234 addsw ? "add" : "delete");
1240 for (seqp = 0; seqs[seqp]; seqp++)
1241 if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
1246 for (seqp = 0; seqs[seqp]; seqp++)
1247 if (!seq_delsel (mp, seqs[seqp], 0, zerosw))
1251 /* Listing messages in sequences */
1254 /* list the given sequences */
1255 for (seqp = 0; seqs[seqp]; seqp++)
1256 seq_print (mp, seqs[seqp]);
1258 /* else list them all */
1264 for (msgnum = mp->lowsel;
1265 msgnum <= mp->hghsel && !interrupted;
1267 if (is_selected (mp, msgnum)) {
1268 printf ("%*d: id=%d top=%d start=%ld stop=%ld %s\n",
1271 Msgs[msgnum].m_bboard_id,
1273 (long) Msgs[msgnum].m_start,
1274 (long) Msgs[msgnum].m_stop,
1275 snprintb (buf, sizeof(buf),
1276 (unsigned) mp->msgstats[msgnum - mp->lowoff],
1278 if (Msgs[msgnum].m_scanl)
1279 printf ("%s", Msgs[msgnum].m_scanl);
1285 static struct swit mhnswit[] = {
1288 #define MHNNAUTOSW 1
1290 #define MHNDEBUGSW 2
1292 #define MHNEBCDICSW 3
1293 { "ebcdicsafe", 0 },
1294 #define MHNNEBCDICSW 4
1295 { "noebcdicsafe", 0 },
1297 { "form formfile", 4 },
1300 #define MHNNHEADSW 7
1304 #define MHNNLISTSW 9
1306 #define MHNPARTSW 10
1307 { "part number", 0 },
1308 #define MHNSIZESW 11
1310 #define MHNNSIZESW 12
1311 { "norealsize", 0 },
1312 #define MHNRFC934SW 13
1313 { "rfc934mode", 0 },
1314 #define MHNNRFC934SW 14
1315 { "norfc934mode", 0 },
1316 #define MHNSERIALSW 15
1317 { "serialonly", 0 },
1318 #define MHNNSERIALSW 16
1319 { "noserialonly", 0 },
1320 #define MHNSHOWSW 17
1322 #define MHNNSHOWSW 18
1324 #define MHNSTORESW 19
1326 #define MHNNSTORESW 20
1328 #define MHNTYPESW 21
1329 { "type content", 0 },
1330 #define MHNVERBSW 22
1332 #define MHNNVERBSW 23
1334 #define MHNHELPSW 24
1336 #define MHNPROGSW 25
1337 { "moreproc program", -4 },
1338 #define MHNNPROGSW 26
1339 { "nomoreproc", -3 },
1341 { "length lines", -4 },
1343 { "width columns", -4 },
1349 mhncmd (char **args)
1351 int msgp = 0, vecp = 1;
1353 char *cp, buf[BUFSIZ];
1354 char *msgs[MAXARGS], *vec[MAXARGS];
1357 forkcmd (args, cmd_name);
1360 while ((cp = *args++)) {
1362 switch (smatch (++cp, mhnswit)) {
1364 ambigsw (cp, mhnswit);
1367 fprintf (stderr, "-%s unknown\n", cp);
1370 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1371 print_help (buf, mhnswit, 1);
1406 if (!(cp = *args++) || *cp == '-') {
1407 advise (NULL, "missing argument to %s", args[-2]);
1414 if (*cp == '+' || *cp == '@') {
1415 advise (NULL, "sorry, no folders allowed!");
1423 vec[vecp++] = "-file";
1426 msgs[msgp++] = "cur";
1427 for (msgnum = 0; msgnum < msgp; msgnum++)
1428 if (!m_convert (mp, msgs[msgnum]))
1433 for (msgnum = mp->lowsel;
1434 msgnum <= mp->hghsel && !interrupted;
1436 if (is_selected (mp, msgnum))
1437 if (process (msgnum, cmd_name, vecp, vec)) {
1438 unset_selected (mp, msgnum);
1442 seq_setcur (mp, mp->hghsel);
1446 static struct swit packswit[] = {
1454 static mbx_style = MMDF_FORMAT;
1457 packcmd (char **args)
1459 int msgp = 0, md, msgnum;
1460 char *cp, *file = NULL;
1461 char buf[BUFSIZ], *msgs[MAXARGS];
1465 forkcmd (args, cmd_name);
1469 while ((cp = *args++)) {
1471 switch (smatch (++cp, packswit)) {
1473 ambigsw (cp, packswit);
1476 fprintf (stderr, "-%s unknown\n", cp);
1479 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1480 print_help (buf, packswit, 1);
1484 if (!(file = *args++) || *file == '-') {
1485 advise (NULL, "missing argument to %s", args[-2]);
1490 if (*cp == '+' || *cp == '@') {
1491 advise (NULL, "sorry, no folders allowed!");
1500 file = path (file, TFILE);
1501 if (stat (file, &st) == NOTOK) {
1502 if (errno != ENOENT) {
1503 advise (file, "error on file");
1506 md = getanswer (cp = concat ("Create file \"", file, "\"? ", NULL));
1513 msgs[msgp++] = "all";
1514 for (msgnum = 0; msgnum < msgp; msgnum++)
1515 if (!m_convert (mp, msgs[msgnum]))
1519 if ((md = mbx_open (file, mbx_style, getuid (), getgid (), m_gmprot ())) == NOTOK) {
1520 advise (file, "unable to open");
1523 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1524 if (is_selected (mp, msgnum))
1525 if (pack (file, md, msgnum) == NOTOK)
1527 mbx_close (file, md);
1529 if (mp->hghsel != mp->curmsg)
1530 seq_setcur (mp, mp->lowsel);
1538 pack (char *mailbox, int md, int msgnum)
1542 if (Msgs[msgnum].m_bboard_id == 0)
1545 zp = msh_ready (msgnum, 1);
1546 return mbx_write (mailbox, md, zp, Msgs[msgnum].m_bboard_id,
1547 0L, ftell (zp), Msgs[msgnum].m_stop, 1, 1);
1552 packhak (char **args)
1555 char *cp, *file = NULL;
1557 while ((cp = *args++)) {
1559 switch (smatch (++cp, packswit)) {
1566 if (!(file = *args++) || *file == '-')
1570 if (*cp == '+' || *cp == '@')
1574 file = path (file ? file : "./msgbox", TFILE);
1575 result = access (file, F_OK) == NOTOK ? OK : NOTOK;
1582 static struct swit pickswit[] = {
1594 { "cc pattern", 0 },
1596 { "date pattern", 0 },
1598 { "from pattern", 0 },
1600 { "search pattern", 0 },
1602 { "subject pattern", 0 },
1604 { "to pattern", 0 },
1606 { "-othercomponent pattern", 15 },
1608 { "after date", 0 },
1610 { "before date", 0 },
1612 { "datefield field", 5 },
1614 { "sequence name", 0 },
1634 pickcmd (char **args)
1636 int zerosw = 1, msgp = 0, seqp = 0;
1637 int vecp = 0, hi, lo, msgnum;
1638 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
1639 char *seqs[NUMATTRS], *vec[MAXARGS];
1642 while ((cp = *args++)) {
1648 switch (smatch (cp, pickswit)) {
1650 ambigsw (cp, pickswit);
1653 fprintf (stderr, "-%s unknown\n", cp);
1656 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1657 print_help (buf, pickswit, 1);
1671 if (!(cp = *args++)) {/* allow -xyz arguments */
1672 advise (NULL, "missing argument to %s", args[-2]);
1678 advise (NULL, "internal error!");
1689 if (!(cp = *args++) || *cp == '-') {
1690 advise (NULL, "missing argument to %s", args[-2]);
1693 if (seqp < NUMATTRS)
1696 advise (NULL, "only %d sequences allowed!", NUMATTRS);
1707 case PIPUSW: /* not implemented */
1714 if (*cp == '+' || *cp == '@') {
1715 advise (NULL, "sorry, no folders allowed!");
1724 msgs[msgp++] = "all";
1725 for (msgnum = 0; msgnum < msgp; msgnum++)
1726 if (!m_convert (mp, msgs[msgnum]))
1731 if (!pcompile (vec, NULL))
1737 for (msgnum = mp->lowsel;
1738 msgnum <= mp->hghsel && !interrupted;
1740 if (is_selected (mp, msgnum)) {
1741 zp = msh_ready (msgnum, 1);
1742 if (pmatches (zp, msgnum, fmsh ? 0L : Msgs[msgnum].m_start,
1743 fmsh ? 0L : Msgs[msgnum].m_stop)) {
1750 unset_selected (mp, msgnum);
1761 if (mp->numsel <= 0) {
1762 advise (NULL, "no messages match specification");
1767 for (seqp = 0; seqs[seqp]; seqp++)
1768 if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
1771 printf ("%d hit%s\n", mp->numsel, mp->numsel == 1 ? "" : "s");
1775 static struct swit replswit[] = {
1779 { "noannotate", 0 },
1785 { "draftfolder +folder", 0 },
1787 { "draftmessage msg", 0 },
1789 { "nodraftfolder", 0 },
1791 { "editor editor", 0 },
1795 { "fcc +folder", 0 },
1797 { "filter filterfile", 0 },
1799 { "form formfile", 0 },
1809 { "whatnowproc program", 0 },
1813 { "width columns", 0 },
1821 replcmd (char **args)
1824 char *cp, *msg = NULL;
1825 char buf[BUFSIZ], *vec[MAXARGS];
1828 forkcmd (args, cmd_name);
1832 while ((cp = *args++)) {
1834 switch (smatch (++cp, replswit)) {
1836 ambigsw (cp, replswit);
1839 fprintf (stderr, "-%s unknown\n", cp);
1842 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1843 print_help (buf, replswit, 1);
1846 case REANSW: /* not implemented */
1871 if (!(cp = *args++) || *cp == '-') {
1872 advise (NULL, "missing argument to %s", args[-2]);
1878 if (*cp == '+' || *cp == '@') {
1879 advise (NULL, "sorry, no folders allowed!");
1884 advise (NULL, "only one message at a time!");
1892 vec[vecp++] = "-file";
1896 if (!m_convert (mp, msg))
1900 if (mp->numsel > 1) {
1901 advise (NULL, "only one message at a time!");
1904 process (mp->hghsel, cmd_name, vecp, vec);
1905 seq_setcur (mp, mp->hghsel);
1909 static struct swit rmmswit[] = {
1917 rmmcmd (char **args)
1919 int msgp = 0, msgnum;
1920 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
1922 while ((cp = *args++)) {
1924 switch (smatch (++cp, rmmswit)) {
1926 ambigsw (cp, rmmswit);
1929 fprintf (stderr, "-%s unknown\n", cp);
1932 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1933 print_help (buf, rmmswit, 1);
1936 if (*cp == '+' || *cp == '@') {
1937 advise (NULL, "sorry, no folders allowed!");
1945 msgs[msgp++] = "cur";
1946 for (msgnum = 0; msgnum < msgp; msgnum++)
1947 if (!m_convert (mp, msgs[msgnum]))
1958 register int msgnum, vecp;
1960 char buffer[BUFSIZ], *vec[MAXARGS];
1964 if (mp->numsel > MAXARGS - 1) {
1965 advise (NULL, "more than %d messages for %s exec",
1966 MAXARGS - 1, rmmproc);
1970 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1971 if (is_selected (mp, msgnum))
1972 vec[vecp++] = getcpy (m_name (msgnum));
1974 forkcmd (vec, rmmproc);
1975 for (vecp = 0; vec[vecp]; vecp++)
1979 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1980 if (is_selected (mp, msgnum)) {
1981 strncpy (buffer, m_backup (cp = m_name (msgnum)), sizeof(buffer));
1982 if (rename (cp, buffer) == NOTOK)
1983 admonish (buffer, "unable to rename %s to", cp);
1987 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1988 if (is_selected (mp, msgnum)) {
1989 set_deleted (mp, msgnum);
1990 unset_exists (mp, msgnum);
1993 if (pmsh && pop_dele (msgnum) != OK)
1994 fprintf (stderr, "%s", response);
1999 if ((mp->nummsg -= mp->numsel) <= 0) {
2001 admonish (NULL, "no messages remaining in +%s", fmsh);
2003 admonish (NULL, "no messages remaining in %s", mp->foldpath);
2004 mp->lowmsg = mp->hghmsg = mp->nummsg = 0;
2006 if (mp->lowsel == mp->lowmsg) {
2007 for (msgnum = mp->lowmsg + 1; msgnum <= mp->hghmsg; msgnum++)
2008 if (does_exist (mp, msgnum))
2010 mp->lowmsg = msgnum;
2012 if (mp->hghsel == mp->hghmsg) {
2013 for (msgnum = mp->hghmsg - 1; msgnum >= mp->lowmsg; msgnum--)
2014 if (does_exist (mp, msgnum))
2016 mp->hghmsg = msgnum;
2019 mp->msgflags |= MODIFIED;
2024 static struct swit scanswit[] = {
2030 { "form formatfile", 0 },
2032 { "format string", 5 },
2038 { "width columns", 0 },
2046 scancmd (char **args)
2048 #define equiv(a,b) (a ? b && !strcmp (a, b) : !b)
2050 int clearsw = 0, headersw = 0, width = 0, msgp = 0;
2051 int msgnum, optim, state;
2052 char *cp, *form = NULL, *format = NULL;
2053 char buf[BUFSIZ], *nfs, *msgs[MAXARGS];
2057 static int p_optim = 0;
2060 static int s_optim = 0;
2061 static char *s_form = NULL, *s_format = NULL;
2063 while ((cp = *args++)) {
2065 switch (smatch (++cp, scanswit)) {
2067 ambigsw (cp, scanswit);
2070 fprintf (stderr, "-%s unknown\n", cp);
2073 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
2074 print_help (buf, scanswit, 1);
2090 if (!(form = *args++) || *form == '-') {
2091 advise (NULL, "missing argument to %s", args[-2]);
2097 if (!(format = *args++) || *format == '-') {
2098 advise (NULL, "missing argument to %s", args[-2]);
2104 if (!(cp = *args++) || *cp == '-') {
2105 advise (NULL, "missing argument to %s", args[-2]);
2111 if (*cp == '+' || *cp == '@') {
2112 advise (NULL, "sorry, no folders allowed!");
2120 msgs[msgp++] = "all";
2121 for (msgnum = 0; msgnum < msgp; msgnum++)
2122 if (!m_convert (mp, msgs[msgnum]))
2126 /* Get new format string */
2127 nfs = new_fs (form, format, FORMAT);
2129 /* force scansbr to (re)compile format */
2136 s_optim = optim = 1;
2137 s_form = form ? getcpy (form) : NULL;
2138 s_format = format ? getcpy (format) : NULL;
2147 width = sc_width ();
2149 for (dp = nfs, i = 0; *dp; dp++, i++)
2150 if (*dp == '\\' || *dp == '"' || *dp == '\n')
2153 if ((ep = malloc ((unsigned) i)) == NULL)
2154 adios (NULL, "out of memory");
2155 for (dp = nfs, fp = ep; *dp; dp++) {
2157 *fp++ = '\\', *fp++ = 'n';
2160 if (*dp == '"' || *dp == '\\')
2166 if (pop_command ("XTND SCAN %d \"%s\"", width, ep) == OK)
2175 optim = equiv (s_form, form) && equiv (s_format, format);
2179 if (p_optim && optim) {
2180 for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++)
2181 if (!is_selected(mp, msgnum) || Msgs[msgnum].m_scanl)
2183 if (msgnum > mp->hghmsg && pop_command ("LIST") == OK) {
2184 fprintf (stderr, "Stand-by...");
2190 switch (pop_multiline ()) {
2192 fprintf (stderr, "%s", response);
2195 fprintf (stderr,"\n");
2199 if (sscanf (response, "%d %d", &msgnum, &size) == 2
2200 && mp->lowmsg <= msgnum
2201 && msgnum <= mp->hghmsg
2202 && (cp = strchr(response, '#'))
2204 Msgs[msgnum].m_scanl = concat (cp, "\n", NULL);
2215 for (msgnum = mp->lowsel;
2216 msgnum <= mp->hghsel && !interrupted;
2218 if (is_selected (mp, msgnum)) {
2219 if (optim && Msgs[msgnum].m_scanl)
2220 printf ("%s", Msgs[msgnum].m_scanl);
2226 && is_virtual (mp, msgnum)
2227 && pop_command ("LIST %d", msgnum) == OK
2228 && (cp = strchr(response, '#'))
2230 Msgs[msgnum].m_scanl = concat (cp, "\n", NULL);
2231 printf ("%s", Msgs[msgnum].m_scanl);
2237 zp = msh_ready (msgnum, 0);
2238 switch (state = scan (zp, msgnum, 0, nfs, width,
2239 msgnum == mp->curmsg,
2240 is_unseen (mp, msgnum),
2241 headersw ? (fmsh ? fmsh : mp->foldpath) : NULL,
2242 fmsh ? 0L : (long) (Msgs[msgnum].m_stop - Msgs[msgnum].m_start),
2248 Msgs[msgnum].m_scanl = getcpy (scanl);
2252 advise (NULL, "scan() botch (%d)", state);
2256 printf ("%*d empty\n", DMAXFOLDER, msgnum);
2268 static struct swit showswit[] = {
2272 { "form formfile", 4 },
2274 { "moreproc program", 4 },
2276 { "nomoreproc", 3 },
2278 { "length lines", 4 },
2280 { "width columns", 4 },
2282 { "showproc program", 4 },
2284 { "noshowproc", 3 },
2296 showcmd (char **args)
2298 int headersw = 1, nshow = 0, msgp = 0, vecp = 1;
2299 int mhl = 0, seqnum = -1, mode = 0, i, msgnum;
2300 char *cp, *proc = showproc, buf[BUFSIZ];
2301 char *msgs[MAXARGS], *vec[MAXARGS];
2303 if (!strcasecmp (cmd_name, "next"))
2306 if (!strcasecmp (cmd_name, "prev"))
2308 while ((cp = *args++)) {
2310 switch (i = smatch (++cp, showswit)) {
2312 ambigsw (cp, showswit);
2319 snprintf (buf, sizeof(buf), "%s %s[switches] [switches for showproc]",
2320 cmd_name, mode ? NULL : "[msgs] ");
2321 print_help (buf, showswit, 1);
2329 if (!(cp = *args++) || *cp == '-') {
2330 advise (NULL, "missing argument to %s", args[-2]);
2342 if (!(proc = *args++) || *proc == '-') {
2343 advise (NULL, "missing argument to %s", args[-2]);
2353 advise (NULL, "sorry, -%s not allowed!", showswit[i].sw);
2356 if (*cp == '+' || *cp == '@') {
2357 advise (NULL, "sorry, no folders allowed!");
2363 "usage: %s [switches] [switches for showproc]\n",
2373 msgs[msgp++] = mode > 0 ? "next" : mode < 0 ? "prev" : "cur";
2374 for (msgnum = 0; msgnum < msgp; msgnum++)
2375 if (!m_convert (mp, msgs[msgnum]))
2379 if (!nshow && !getenv ("NOMHNPROC"))
2380 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
2381 if (is_selected (mp, msgnum) && is_nontext (msgnum)) {
2382 proc = showmimeproc;
2383 vec[vecp++] = "-show";
2384 vec[vecp++] = "-file";
2392 if (strcmp (showproc, "mhl") == 0) {
2398 seqnum = seq_getnum (mp, "unseen");
2399 vec[0] = r1bindex (proc, '/');
2402 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
2403 if (is_selected (mp, msgnum)) {
2404 vec[vecp++] = getcpy (m_name (msgnum));
2406 seq_delmsg (mp, "unseen", msgnum);
2409 if (mp->numsel == 1 && headersw)
2411 mhlsbr (vecp, vec, mhl_action);
2412 m_eomsbr ((int (*)()) 0);
2417 for (msgnum = mp->lowsel;
2418 msgnum <= mp->hghsel && !interrupted;
2420 if (is_selected (mp, msgnum)) {
2421 switch (ask (msgnum)) {
2422 case NOTOK: /* QUIT */
2429 if (mp->numsel == 1 && headersw)
2432 copy_message (msgnum, stdout);
2434 process (msgnum, proc, vecp, vec);
2437 seq_delmsg (mp, "unseen", msgnum);
2444 seq_setcur (mp, mp->hghsel);
2451 if (Msgs[msgnum].m_bboard_id == 0)
2454 printf ("(Message %d", msgnum);
2455 if (Msgs[msgnum].m_bboard_id > 0)
2456 printf (", %s: %d", BBoard_ID, Msgs[msgnum].m_bboard_id);
2465 return (ftell (mhlfp) >= Msgs[mhlnum].m_stop);
2470 mhl_action (char *name)
2474 if ((msgnum = m_atoi (name)) < mp->lowmsg
2475 || msgnum > mp->hghmsg
2476 || !does_exist (mp, msgnum))
2480 mhlfp = msh_ready (msgnum, 1);
2482 m_eomsbr (eom_action);
2494 if (mp->numsel == 1 || !interactive || redirected)
2497 if (SOprintf ("Press <return> to list \"%d\"...", msgnum)) {
2498 if (mp->lowsel != msgnum)
2500 printf ("Press <return> to list \"%d\"...", msgnum);
2506 read (fileno (stdout), buf, sizeof buf);
2508 switch (setjmp (sigenv)) {
2511 read (fileno (stdout), buf, sizeof buf);/* fall... */
2519 if (strchr(buf, '\n') == NULL)
2523 told_to_quit = interrupted = 0;
2538 is_nontext (int msgnum)
2542 char buf[BUFSIZ], name[NAMESZ];
2545 if (Msgs[msgnum].m_flags & MHNCHK)
2546 return (Msgs[msgnum].m_flags & MHNYES);
2547 Msgs[msgnum].m_flags |= MHNCHK;
2549 fp = msh_ready (msgnum, 1);
2552 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
2557 * Check Content-Type field
2559 if (!strcasecmp (name, TYPE_FIELD)) {
2563 cp = add (buf, NULL);
2564 while (state == FLDPLUS) {
2565 state = m_getfld (state, name, buf, sizeof buf, fp);
2572 for (; isspace (*bp); bp++)
2577 for (bp++, i = 0;;) {
2607 for (dp = bp; istoken (*dp); dp++)
2614 if ((result = (strcasecmp (bp, "plain") != 0)))
2617 for (dp++; isspace (*dp); dp++)
2620 if ((result = !uprf (dp, "charset")))
2622 dp += sizeof "charset" - 1;
2623 while (isspace (*dp))
2627 while (isspace (*dp))
2630 if ((bp = strchr(++dp, '"')))
2633 for (bp = dp; *bp; bp++)
2634 if (isspace (*bp)) {
2640 /* Default character set */
2643 /* Check the character set */
2644 result = !check_charset (dp, strlen (dp));
2646 if (!(result = (strcasecmp (bp, "text") != 0))) {
2656 Msgs[msgnum].m_flags |= MHNYES;
2663 * Check Content-Transfer-Encoding field
2665 if (!strcasecmp (name, ENCODING_FIELD)) {
2666 cp = add (buf, NULL);
2667 while (state == FLDPLUS) {
2668 state = m_getfld (state, name, buf, sizeof buf, fp);
2671 for (bp = cp; isspace (*bp); bp++)
2673 for (dp = bp; istoken (*dp); dp++)
2676 result = (strcasecmp (bp, "7bit")
2677 && strcasecmp (bp, "8bit")
2678 && strcasecmp (bp, "binary"));
2682 Msgs[msgnum].m_flags |= MHNYES;
2689 * Just skip the rest of this header
2690 * field and go to next one.
2692 while (state == FLDPLUS)
2693 state = m_getfld (state, name, buf, sizeof(buf), fp);
2697 * We've passed the message header,
2698 * so message is just text.
2706 static struct swit sortswit[] = {
2708 { "datefield field", 0 },
2710 { "textfield field", 0 },
2712 { "notextfield", 0 },
2714 { "limit days", 0 },
2728 sortcmd (char **args)
2730 int msgp = 0, msgnum;
2731 char *cp, *datesw = NULL, *subjsw = NULL;
2732 char buf[BUFSIZ], *msgs[MAXARGS];
2736 forkcmd (args, cmd_name);
2740 while ((cp = *args++)) {
2742 switch (smatch (++cp, sortswit)) {
2744 ambigsw (cp, sortswit);
2747 fprintf (stderr, "-%s unknown\n", cp);
2750 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
2751 print_help (buf, sortswit, 1);
2756 advise (NULL, "only one date field at a time!");
2759 if (!(datesw = *args++) || *datesw == '-') {
2760 advise (NULL, "missing argument to %s", args[-2]);
2767 advise (NULL, "only one text field at a time!");
2770 if (!(subjsw = *args++) || *subjsw == '-') {
2771 advise (NULL, "missing argument to %s", args[-2]);
2779 case SOLIMT: /* too hard */
2780 if (!(cp = *args++) || *cp == '-') {
2781 advise (NULL, "missing argument to %s", args[-2]);
2785 case SOVERB: /* not implemented */
2789 if (*cp == '+' || *cp == '@') {
2790 advise (NULL, "sorry, no folders allowed!");
2798 msgs[msgp++] = "all";
2801 for (msgnum = 0; msgnum < msgp; msgnum++)
2802 if (!m_convert (mp, msgs[msgnum]))
2806 twscopy (&tb, dlocaltimenow ());
2808 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
2809 if (Msgs[msgnum].m_scanl) {
2810 free (Msgs[msgnum].m_scanl);
2811 Msgs[msgnum].m_scanl = NULL;
2813 if (is_selected (mp, msgnum)) {
2814 if (get_fields (datesw, subjsw, msgnum, &Msgs[msgnum]))
2815 twscopy (&Msgs[msgnum].m_tb,
2816 msgnum != mp->lowsel ? &Msgs[msgnum - 1].m_tb : &tb);
2818 else /* m_scaln is already NULL */
2819 twscopy (&Msgs[msgnum].m_tb, &tb);
2820 Msgs[msgnum].m_stats = mp->msgstats[msgnum - mp->lowoff];
2821 if (mp->curmsg == msgnum)
2822 Msgs[msgnum].m_stats |= CUR;
2825 qsort ((char *) &Msgs[mp->lowsel], mp->hghsel - mp->lowsel + 1,
2826 sizeof(struct Msg), (qsort_comp) (subjsw ? subsort : msgsort));
2828 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
2829 if (subjsw && Msgs[msgnum].m_scanl) {
2830 free (Msgs[msgnum].m_scanl); /* from subjsort */
2831 Msgs[msgnum].m_scanl = NULL;
2833 mp->msgstats[msgnum - mp->lowoff] = Msgs[msgnum].m_stats & ~CUR;
2834 if (Msgs[msgnum].m_stats & CUR)
2835 seq_setcur (mp, msgnum);
2838 mp->msgflags |= MODIFIED;
2844 * get_fields - parse message, and get date and subject if needed.
2845 * We'll use the msgp->m_tb tws struct for the date, and overload
2846 * the msgp->m_scanl field with our subject string.
2849 get_fields (char *datesw, char *subjsw, int msgnum, struct Msg *msgp)
2851 int state, gotdate = 0;
2852 char *bp, buf[BUFSIZ], name[NAMESZ];
2853 struct tws *tw = (struct tws *) 0;
2856 zp = msh_ready (msgnum, 0);
2857 for (state = FLD;;) {
2858 switch (state = m_getfld (state, name, buf, sizeof buf, zp)) {
2862 if (!strcasecmp (name, datesw)) {
2864 while (state == FLDPLUS) {
2865 state = m_getfld (state, name, buf, sizeof buf, zp);
2868 if ((tw = dparsetime (bp)) == NULL)
2870 "unable to parse %s field in message %d",
2873 twscopy (&(msgp->m_tb), tw);
2875 if (!subjsw) /* not using this, or already done */
2876 break; /* all done! */
2879 else if (subjsw && !strcasecmp(name, subjsw)) {
2881 while (state == FLDPLUS) {
2882 state = m_getfld (state, name, buf, sizeof buf, zp);
2885 msgp->m_scanl = sosmash(subjsw, bp);
2887 break; /* date done so we're done */
2889 subjsw = (char *)0;/* subject done, need date */
2891 while (state == FLDPLUS) /* flush this one */
2892 state = m_getfld (state, name, buf, sizeof buf, zp);
2903 admonish (NULL, "format error in message %d", msgnum);
2904 if (msgp->m_scanl) { /* this might need free'd */
2905 free (msgp->m_scanl); /* probably can't use subj anyway */
2906 msgp->m_scanl = NULL;
2911 adios (NULL, "internal error -- you lose");
2916 return OK; /* not an error if subj not found */
2918 admonish (NULL, "no %s field in message %d", datesw, msgnum);
2919 return NOTOK; /* NOTOK means use some other date */
2928 msgsort (struct Msg *a, struct Msg *b)
2930 return twsort (&a->m_tb, &b->m_tb);
2935 subsort (struct Msg *a, struct Msg *b)
2939 if (a->m_scanl && b->m_scanl)
2940 if ((i = strcmp (a->m_scanl, b->m_scanl)))
2943 return twsort (&a->m_tb, &b->m_tb);
2948 * try to make the subject "canonical": delete leading "re:", everything
2949 * but letters & smash letters to lower case.
2952 sosmash (char *subj, char *s)
2954 register char *cp, *dp, c;
2958 dp = s; /* dst pointer */
2959 if (!strcasecmp (subj, "subject"))
2966 *dp++ = isupper(c) ? tolower(c) : c;
2972 while ((c = *cp++)) {
2974 *dp++ = isupper(c) ? tolower(c) : c;
2984 process (int msgnum, char *proc, int vecp, char **vec)
2986 int child_id, status;
2991 strncpy (tmpfil, m_name (msgnum), sizeof(tmpfil));
2992 context_del (pfolder);
2993 context_replace (pfolder, fmsh);/* update current folder */
2995 context_save (); /* save the context file */
2999 strncpy (tmpfil, m_scratch ("", invo_name), sizeof(tmpfil));
3000 if ((out = fopen (tmpfil, "w")) == NULL) {
3006 strncpy (newfil, m_tmpfil (invo_name), sizeof(newfil));
3007 if ((out = fopen (newfil, "w")) == NULL) {
3009 advise (tmpfil, "unable to create temporary file");
3012 strncpy (tmpfil, newfil, sizeof(tmpfil));
3015 copy_message (msgnum, out);
3020 switch (child_id = fork ()) {
3022 advise ("fork", "unable to");
3028 SIGNAL (SIGINT, istat);
3029 SIGNAL (SIGQUIT, qstat);
3031 vec[vecp++] = tmpfil;
3035 fprintf (stderr, "unable to exec ");
3040 status = pidXwait (child_id, NULL);
3051 copy_message (int msgnum, FILE *out)
3054 static char buffer[BUFSIZ];
3057 zp = msh_ready (msgnum, 1);
3059 while (fgets (buffer, sizeof buffer, zp) != NULL) {
3060 fputs (buffer, out);
3061 if (interrupted && out == stdout)
3067 while (fgets (buffer, sizeof buffer, zp) != NULL
3068 && pos < Msgs[msgnum].m_stop) {
3069 fputs (buffer, out);
3070 pos += (long) strlen (buffer);
3071 if (interrupted && out == stdout)
3079 copy_digest (int msgnum, FILE *out)
3083 static char buffer[BUFSIZ];
3087 zp = msh_ready (msgnum, 1);
3090 while (fgets (buffer, sizeof buffer, zp) != NULL
3091 && !fmsh && pos < Msgs[msgnum].m_stop) {
3092 if (c == '\n' && *buffer == '-')
3094 fputs (buffer, out);
3095 c = buffer[strlen (buffer) - 1];
3097 pos += (long) strlen (buffer);
3098 if (interrupted && out == stdout)