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)
704 advise (NULL, "only one message at a time!\n");
713 advise (NULL, "null folder names are not permitted");
717 if (access (m_maildir (folder), R_OK) == NOTOK) {
718 advise (folder, "unable to read");
723 strncpy (buf, folder, sizeof(buf));
724 if (expand (buf) == NOTOK)
727 if (access (folder, R_OK) == NOTOK) {
728 advise (folder, "unable to read");
743 if (!m_convert (mp, msg))
747 if (mp->numsel > 1) {
748 advise (NULL, "only one message at a time!");
751 seq_setcur (mp, mp->hghsel);
756 forkcmd (vec, cmd_name);
760 if (mp->lowoff > 1 && !(mp = folder_realloc (mp, 1, mp->hghmsg)))
761 adios (NULL, "unable to allocate folder storage");
763 for (msgnum = mp->lowmsg, hole = 1; msgnum <= mp->hghmsg; msgnum++)
764 if (does_exist (mp, msgnum)) {
765 if (msgnum != hole) {
766 Msgs[hole].m_bboard_id = Msgs[msgnum].m_bboard_id;
767 Msgs[hole].m_top = Msgs[msgnum].m_top;
768 Msgs[hole].m_start = Msgs[msgnum].m_start;
769 Msgs[hole].m_stop = Msgs[msgnum].m_stop;
770 Msgs[hole].m_scanl = NULL;
771 if (Msgs[msgnum].m_scanl) {
772 free (Msgs[msgnum].m_scanl);
773 Msgs[msgnum].m_scanl = NULL;
775 copy_msg_flags (mp, hole, msgnum);
776 if (mp->curmsg == msgnum)
777 seq_setcur (mp, hole);
781 if (mp->nummsg > 0) {
783 mp->hghmsg = hole - 1;
785 mp->msgflags |= MODIFIED;
791 printf ("%s\n", fmsh ? fmsh : mp->foldpath);
794 printf ("\t\tFolder %*s# of messages (%*srange%*s); cur%*smsg\n",
795 DMAXFOLDER, "", DMAXFOLDER - 2, "", DMAXFOLDER - 2, "",
797 printf (args ? "%22s " : "%s ", fmsh ? fmsh : mp->foldpath);
799 /* check for empty folder */
800 if (mp->nummsg == 0) {
801 printf ("has no messages%*s",
802 mp->msgflags & OTHERS ? DMAXFOLDER * 2 + 4 : 0, "");
804 printf ("has %*d message%s (%*d-%*d)",
805 DMAXFOLDER, mp->nummsg, mp->nummsg != 1 ? "s" : "",
806 DMAXFOLDER, mp->lowmsg, DMAXFOLDER, mp->hghmsg);
807 if (mp->curmsg >= mp->lowmsg
808 && mp->curmsg <= mp->hghmsg)
809 printf ("; cur=%*d", DMAXFOLDER, mp->curmsg);
816 static struct swit forwswit[] = {
822 { "draftfolder +folder", 0 },
824 { "draftmessage msg", 0 },
826 { "nodraftfolder", 0 },
828 { "editor editor", 0 },
832 { "filter filterfile", 0 },
834 { "form formfile", 0 },
848 { "whatnowproc program", 0 },
858 forwcmd (char **args)
860 int msgp = 0, vecp = 1, msgnum;
861 char *cp, *filter = NULL, buf[BUFSIZ];
862 char *msgs[MAXARGS], *vec[MAXARGS];
865 forkcmd (args, cmd_name);
869 while ((cp = *args++)) {
871 switch (smatch (++cp, forwswit)) {
873 ambigsw (cp, forwswit);
876 fprintf (stderr, "-%s unknown\n", cp);
879 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
880 print_help (buf, forwswit, 1);
883 case FOANSW: /* not implemented */
903 if (!(cp = *args++) || *cp == '-') {
904 advise (NULL, "missing argument to %s", args[-2]);
910 if (!(filter = *args++) || *filter == '-') {
911 advise (NULL, "missing argument to %s", args[-2]);
916 if (access (filter = myfilter, R_OK) == NOTOK) {
917 advise (filter, "unable to read default filter file");
925 if (*cp == '+' || *cp == '@') {
926 advise (NULL, "sorry, no folders allowed!");
933 /* foil search of .mh_profile */
934 snprintf (buf, sizeof(buf), "%sXXXXXX", invo_name);
936 vec[0] = (char *)mkstemp (buf);
938 vec[0] = (char *)mktemp (buf);
940 vec[vecp++] = "-file";
943 msgs[msgp++] = "cur";
944 for (msgnum = 0; msgnum < msgp; msgnum++)
945 if (!m_convert (mp, msgs[msgnum]))
950 strncpy (buf, filter, sizeof(buf));
951 if (expand (buf) == NOTOK)
953 if (access (filter = getcpy (etcpath (buf)), R_OK) == NOTOK) {
954 advise (filter, "unable to read");
959 forw (cmd_name, filter, vecp, vec);
960 seq_setcur (mp, mp->hghsel);
967 forw (char *proc, char *filter, int vecp, char **vec)
969 int i, child_id, msgnum, msgcnt;
970 char tmpfil[80], *args[MAXARGS];
973 strncpy (tmpfil, m_tmpfil (invo_name), sizeof(tmpfil));
976 switch (child_id = fork ()) {
978 advise ("fork", "unable to");
981 case OK: /* "trust me" */
982 if (freopen (tmpfil, "w", stdout) == NULL) {
983 fprintf (stderr, "unable to create ");
987 args[0] = r1bindex (mhlproc, '/');
989 args[i++] = "-forwall";
992 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
993 if (is_selected (mp, msgnum))
994 args[i++] = getcpy (m_name (msgnum));
996 mhlsbr (i, args, mhl_action);
997 m_eomsbr ((int (*) ()) 0);
1002 if (pidXwait (child_id, NULL))
1007 if ((out = fopen (tmpfil, "w")) == NULL) {
1008 advise (tmpfil, "unable to create temporary file");
1013 for (msgnum = mp->lowsel;
1014 msgnum <= mp->hghsel && !interrupted;
1016 if (is_selected (mp, msgnum)) {
1017 fprintf (out, "\n\n-------");
1018 if (msgnum == mp->lowsel)
1019 fprintf (out, " Forwarded Message%s",
1020 mp->numsel > 1 ? "s" : "");
1022 fprintf (out, " Message %d", msgcnt);
1023 fprintf (out, "\n\n");
1024 copy_digest (msgnum, out);
1028 fprintf (out, "\n\n------- End of Forwarded Message%s\n",
1029 mp->numsel > 1 ? "s" : "");
1035 switch (child_id = fork ()) {
1037 advise ("fork", "unable to");
1042 SIGNAL (SIGINT, istat);
1043 SIGNAL (SIGQUIT, qstat);
1045 vec[vecp++] = tmpfil;
1049 fprintf (stderr, "unable to exec ");
1054 pidXwait (child_id, NULL);
1062 static char *hlpmsg[] = {
1063 "The %s program emulates many of the commands found in the nmh",
1064 "system. Instead of operating on nmh folders, commands to %s concern",
1067 "To see the list of commands available, just type a ``?'' followed by",
1068 "the RETURN key. To find out what switches each command takes, type",
1069 "the name of the command followed by ``-help''. To leave %s, use the",
1070 "``quit'' command.",
1072 "Although a lot of nmh commands are found in %s, not all are fully",
1073 "implemented. %s will always recognize all legal switches for a",
1074 "given command though, and will let you know when you ask for an",
1075 "option that it is unable to perform.",
1077 "Running %s is fun, but using nmh from your shell is far superior.",
1078 "After you have familiarized yourself with the nmh style by using %s,",
1079 "you should try using nmh from the shell. You can still use %s for",
1080 "message files that aren't in nmh format, such as BBoard files.",
1086 helpcmd (char **args)
1090 for (i = 0; hlpmsg[i]; i++) {
1091 printf (hlpmsg[i], invo_name);
1097 static struct swit markswit[] = {
1105 { "sequence name", 0 },
1123 markcmd (char **args)
1125 int addsw = 0, deletesw = 0, debugsw = 0;
1126 int listsw = 0, zerosw = 0, seqp = 0;
1127 int msgp = 0, msgnum;
1128 char *cp, buf[BUFSIZ];
1129 char *seqs[NUMATTRS + 1], *msgs[MAXARGS];
1131 while ((cp = *args++)) {
1133 switch (smatch (++cp, markswit)) {
1135 ambigsw (cp, markswit);
1138 fprintf (stderr, "-%s unknown\n", cp);
1141 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1142 print_help (buf, markswit, 1);
1147 deletesw = listsw = 0;
1155 addsw = deletesw = 0;
1159 if (!(cp = *args++) || *cp == '-') {
1160 advise (NULL, "missing argument to %s", args[-2]);
1163 if (seqp < NUMATTRS)
1166 advise (NULL, "only %d sequences allowed!", NUMATTRS);
1171 case MPUBSW: /* not implemented */
1187 if (*cp == '+' || *cp == '@') {
1188 advise (NULL, "sorry, no folders allowed!");
1195 if (!addsw && !deletesw && !listsw)
1202 seqs[seqp++] = "unseen";
1206 msgs[msgp++] = "all";
1210 msgs[msgp++] = listsw ? "all" :"cur";
1211 for (msgnum = 0; msgnum < msgp; msgnum++)
1212 if (!m_convert (mp, msgs[msgnum]))
1216 printf ("invo_name=%s mypath=%s defpath=%s\n",
1217 invo_name, mypath, defpath);
1218 printf ("ctxpath=%s context flags=%s\n",
1219 ctxpath, snprintb (buf, sizeof(buf), (unsigned) ctxflags, DBITS));
1220 printf ("foldpath=%s flags=%s\n",
1222 snprintb (buf, sizeof(buf), (unsigned) mp->msgflags, FBITS));
1223 printf ("hghmsg=%d lowmsg=%d nummsg=%d curmsg=%d\n",
1224 mp->hghmsg, mp->lowmsg, mp->nummsg, mp->curmsg);
1225 printf ("lowsel=%d hghsel=%d numsel=%d\n",
1226 mp->lowsel, mp->hghsel, mp->numsel);
1227 printf ("lowoff=%d hghoff=%d\n", mp->lowoff, mp->hghoff);
1230 if (seqp == 0 && (addsw || deletesw)) {
1231 advise (NULL, "-%s requires at least one -sequence argument",
1232 addsw ? "add" : "delete");
1238 for (seqp = 0; seqs[seqp]; seqp++)
1239 if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
1244 for (seqp = 0; seqs[seqp]; seqp++)
1245 if (!seq_delsel (mp, seqs[seqp], 0, zerosw))
1249 /* Listing messages in sequences */
1252 /* list the given sequences */
1253 for (seqp = 0; seqs[seqp]; seqp++)
1254 seq_print (mp, seqs[seqp]);
1256 /* else list them all */
1262 for (msgnum = mp->lowsel;
1263 msgnum <= mp->hghsel && !interrupted;
1265 if (is_selected (mp, msgnum)) {
1266 printf ("%*d: id=%d top=%d start=%ld stop=%ld %s\n",
1269 Msgs[msgnum].m_bboard_id,
1271 (long) Msgs[msgnum].m_start,
1272 (long) Msgs[msgnum].m_stop,
1273 snprintb (buf, sizeof(buf),
1274 (unsigned) mp->msgstats[msgnum - mp->lowoff],
1276 if (Msgs[msgnum].m_scanl)
1277 printf ("%s", Msgs[msgnum].m_scanl);
1283 static struct swit mhnswit[] = {
1286 #define MHNNAUTOSW 1
1288 #define MHNDEBUGSW 2
1290 #define MHNEBCDICSW 3
1291 { "ebcdicsafe", 0 },
1292 #define MHNNEBCDICSW 4
1293 { "noebcdicsafe", 0 },
1295 { "form formfile", 4 },
1298 #define MHNNHEADSW 7
1302 #define MHNNLISTSW 9
1304 #define MHNPARTSW 10
1305 { "part number", 0 },
1306 #define MHNSIZESW 11
1308 #define MHNNSIZESW 12
1309 { "norealsize", 0 },
1310 #define MHNRFC934SW 13
1311 { "rfc934mode", 0 },
1312 #define MHNNRFC934SW 14
1313 { "norfc934mode", 0 },
1314 #define MHNSERIALSW 15
1315 { "serialonly", 0 },
1316 #define MHNNSERIALSW 16
1317 { "noserialonly", 0 },
1318 #define MHNSHOWSW 17
1320 #define MHNNSHOWSW 18
1322 #define MHNSTORESW 19
1324 #define MHNNSTORESW 20
1326 #define MHNTYPESW 21
1327 { "type content", 0 },
1328 #define MHNVERBSW 22
1330 #define MHNNVERBSW 23
1332 #define MHNHELPSW 24
1334 #define MHNPROGSW 25
1335 { "moreproc program", -4 },
1336 #define MHNNPROGSW 26
1337 { "nomoreproc", -3 },
1339 { "length lines", -4 },
1341 { "width columns", -4 },
1347 mhncmd (char **args)
1349 int msgp = 0, vecp = 1;
1351 char *cp, buf[BUFSIZ];
1352 char *msgs[MAXARGS], *vec[MAXARGS];
1355 forkcmd (args, cmd_name);
1358 while ((cp = *args++)) {
1360 switch (smatch (++cp, mhnswit)) {
1362 ambigsw (cp, mhnswit);
1365 fprintf (stderr, "-%s unknown\n", cp);
1368 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1369 print_help (buf, mhnswit, 1);
1404 if (!(cp = *args++) || *cp == '-') {
1405 advise (NULL, "missing argument to %s", args[-2]);
1412 if (*cp == '+' || *cp == '@') {
1413 advise (NULL, "sorry, no folders allowed!");
1421 vec[vecp++] = "-file";
1424 msgs[msgp++] = "cur";
1425 for (msgnum = 0; msgnum < msgp; msgnum++)
1426 if (!m_convert (mp, msgs[msgnum]))
1431 for (msgnum = mp->lowsel;
1432 msgnum <= mp->hghsel && !interrupted;
1434 if (is_selected (mp, msgnum))
1435 if (process (msgnum, cmd_name, vecp, vec)) {
1436 unset_selected (mp, msgnum);
1440 seq_setcur (mp, mp->hghsel);
1444 static struct swit packswit[] = {
1452 static mbx_style = MMDF_FORMAT;
1455 packcmd (char **args)
1457 int msgp = 0, md, msgnum;
1458 char *cp, *file = NULL;
1459 char buf[BUFSIZ], *msgs[MAXARGS];
1463 forkcmd (args, cmd_name);
1467 while ((cp = *args++)) {
1469 switch (smatch (++cp, packswit)) {
1471 ambigsw (cp, packswit);
1474 fprintf (stderr, "-%s unknown\n", cp);
1477 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1478 print_help (buf, packswit, 1);
1482 if (!(file = *args++) || *file == '-') {
1483 advise (NULL, "missing argument to %s", args[-2]);
1488 if (*cp == '+' || *cp == '@') {
1489 advise (NULL, "sorry, no folders allowed!");
1498 file = path (file, TFILE);
1499 if (stat (file, &st) == NOTOK) {
1500 if (errno != ENOENT) {
1501 advise (file, "error on file");
1504 md = getanswer (cp = concat ("Create file \"", file, "\"? ", NULL));
1511 msgs[msgp++] = "all";
1512 for (msgnum = 0; msgnum < msgp; msgnum++)
1513 if (!m_convert (mp, msgs[msgnum]))
1517 if ((md = mbx_open (file, mbx_style, getuid (), getgid (), m_gmprot ())) == NOTOK) {
1518 advise (file, "unable to open");
1521 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1522 if (is_selected (mp, msgnum))
1523 if (pack (file, md, msgnum) == NOTOK)
1525 mbx_close (file, md);
1527 if (mp->hghsel != mp->curmsg)
1528 seq_setcur (mp, mp->lowsel);
1536 pack (char *mailbox, int md, int msgnum)
1540 if (Msgs[msgnum].m_bboard_id == 0)
1543 zp = msh_ready (msgnum, 1);
1544 return mbx_write (mailbox, md, zp, Msgs[msgnum].m_bboard_id,
1545 0L, ftell (zp), Msgs[msgnum].m_stop, 1, 1);
1550 packhak (char **args)
1553 char *cp, *file = NULL;
1555 while ((cp = *args++)) {
1557 switch (smatch (++cp, packswit)) {
1564 if (!(file = *args++) || *file == '-')
1568 if (*cp == '+' || *cp == '@')
1572 file = path (file ? file : "./msgbox", TFILE);
1573 result = access (file, F_OK) == NOTOK ? OK : NOTOK;
1580 static struct swit pickswit[] = {
1592 { "cc pattern", 0 },
1594 { "date pattern", 0 },
1596 { "from pattern", 0 },
1598 { "search pattern", 0 },
1600 { "subject pattern", 0 },
1602 { "to pattern", 0 },
1604 { "-othercomponent pattern", 15 },
1606 { "after date", 0 },
1608 { "before date", 0 },
1610 { "datefield field", 5 },
1612 { "sequence name", 0 },
1632 pickcmd (char **args)
1634 int zerosw = 1, msgp = 0, seqp = 0;
1635 int vecp = 0, hi, lo, msgnum;
1636 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
1637 char *seqs[NUMATTRS], *vec[MAXARGS];
1640 while ((cp = *args++)) {
1646 switch (smatch (cp, pickswit)) {
1648 ambigsw (cp, pickswit);
1651 fprintf (stderr, "-%s unknown\n", cp);
1654 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1655 print_help (buf, pickswit, 1);
1669 if (!(cp = *args++)) {/* allow -xyz arguments */
1670 advise (NULL, "missing argument to %s", args[-2]);
1676 advise (NULL, "internal error!");
1687 if (!(cp = *args++) || *cp == '-') {
1688 advise (NULL, "missing argument to %s", args[-2]);
1691 if (seqp < NUMATTRS)
1694 advise (NULL, "only %d sequences allowed!", NUMATTRS);
1705 case PIPUSW: /* not implemented */
1712 if (*cp == '+' || *cp == '@') {
1713 advise (NULL, "sorry, no folders allowed!");
1722 msgs[msgp++] = "all";
1723 for (msgnum = 0; msgnum < msgp; msgnum++)
1724 if (!m_convert (mp, msgs[msgnum]))
1729 if (!pcompile (vec, NULL))
1735 for (msgnum = mp->lowsel;
1736 msgnum <= mp->hghsel && !interrupted;
1738 if (is_selected (mp, msgnum)) {
1739 zp = msh_ready (msgnum, 1);
1740 if (pmatches (zp, msgnum, fmsh ? 0L : Msgs[msgnum].m_start,
1741 fmsh ? 0L : Msgs[msgnum].m_stop)) {
1748 unset_selected (mp, msgnum);
1759 if (mp->numsel <= 0) {
1760 advise (NULL, "no messages match specification");
1765 for (seqp = 0; seqs[seqp]; seqp++)
1766 if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
1769 printf ("%d hit%s\n", mp->numsel, mp->numsel == 1 ? "" : "s");
1773 static struct swit replswit[] = {
1777 { "noannotate", 0 },
1783 { "draftfolder +folder", 0 },
1785 { "draftmessage msg", 0 },
1787 { "nodraftfolder", 0 },
1789 { "editor editor", 0 },
1793 { "fcc +folder", 0 },
1795 { "filter filterfile", 0 },
1797 { "form formfile", 0 },
1807 { "whatnowproc program", 0 },
1811 { "width columns", 0 },
1819 replcmd (char **args)
1822 char *cp, *msg = NULL;
1823 char buf[BUFSIZ], *vec[MAXARGS];
1826 forkcmd (args, cmd_name);
1830 while ((cp = *args++)) {
1832 switch (smatch (++cp, replswit)) {
1834 ambigsw (cp, replswit);
1837 fprintf (stderr, "-%s unknown\n", cp);
1840 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1841 print_help (buf, replswit, 1);
1844 case REANSW: /* not implemented */
1869 if (!(cp = *args++) || *cp == '-') {
1870 advise (NULL, "missing argument to %s", args[-2]);
1876 if (*cp == '+' || *cp == '@') {
1877 advise (NULL, "sorry, no folders allowed!");
1882 advise (NULL, "only one message at a time!");
1890 vec[vecp++] = "-file";
1894 if (!m_convert (mp, msg))
1898 if (mp->numsel > 1) {
1899 advise (NULL, "only one message at a time!");
1902 process (mp->hghsel, cmd_name, vecp, vec);
1903 seq_setcur (mp, mp->hghsel);
1907 static struct swit rmmswit[] = {
1915 rmmcmd (char **args)
1917 int msgp = 0, msgnum;
1918 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
1920 while ((cp = *args++)) {
1922 switch (smatch (++cp, rmmswit)) {
1924 ambigsw (cp, rmmswit);
1927 fprintf (stderr, "-%s unknown\n", cp);
1930 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1931 print_help (buf, rmmswit, 1);
1934 if (*cp == '+' || *cp == '@') {
1935 advise (NULL, "sorry, no folders allowed!");
1943 msgs[msgp++] = "cur";
1944 for (msgnum = 0; msgnum < msgp; msgnum++)
1945 if (!m_convert (mp, msgs[msgnum]))
1956 register int msgnum, vecp;
1958 char buffer[BUFSIZ], *vec[MAXARGS];
1962 if (mp->numsel > MAXARGS - 1) {
1963 advise (NULL, "more than %d messages for %s exec",
1964 MAXARGS - 1, rmmproc);
1968 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1969 if (is_selected (mp, msgnum))
1970 vec[vecp++] = getcpy (m_name (msgnum));
1972 forkcmd (vec, rmmproc);
1973 for (vecp = 0; vec[vecp]; vecp++)
1977 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1978 if (is_selected (mp, msgnum)) {
1979 strncpy (buffer, m_backup (cp = m_name (msgnum)), sizeof(buffer));
1980 if (rename (cp, buffer) == NOTOK)
1981 admonish (buffer, "unable to rename %s to", cp);
1985 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1986 if (is_selected (mp, msgnum)) {
1987 set_deleted (mp, msgnum);
1988 unset_exists (mp, msgnum);
1991 if (pmsh && pop_dele (msgnum) != OK)
1992 fprintf (stderr, "%s", response);
1997 if ((mp->nummsg -= mp->numsel) <= 0) {
1999 admonish (NULL, "no messages remaining in +%s", fmsh);
2001 admonish (NULL, "no messages remaining in %s", mp->foldpath);
2002 mp->lowmsg = mp->hghmsg = mp->nummsg = 0;
2004 if (mp->lowsel == mp->lowmsg) {
2005 for (msgnum = mp->lowmsg + 1; msgnum <= mp->hghmsg; msgnum++)
2006 if (does_exist (mp, msgnum))
2008 mp->lowmsg = msgnum;
2010 if (mp->hghsel == mp->hghmsg) {
2011 for (msgnum = mp->hghmsg - 1; msgnum >= mp->lowmsg; msgnum--)
2012 if (does_exist (mp, msgnum))
2014 mp->hghmsg = msgnum;
2017 mp->msgflags |= MODIFIED;
2022 static struct swit scanswit[] = {
2028 { "form formatfile", 0 },
2030 { "format string", 5 },
2036 { "width columns", 0 },
2044 scancmd (char **args)
2046 #define equiv(a,b) (a ? b && !strcmp (a, b) : !b)
2048 int clearsw = 0, headersw = 0, width = 0, msgp = 0;
2049 int msgnum, optim, state;
2050 char *cp, *form = NULL, *format = NULL;
2051 char buf[BUFSIZ], *nfs, *msgs[MAXARGS];
2055 static int p_optim = 0;
2058 static int s_optim = 0;
2059 static char *s_form = NULL, *s_format = NULL;
2061 while ((cp = *args++)) {
2063 switch (smatch (++cp, scanswit)) {
2065 ambigsw (cp, scanswit);
2068 fprintf (stderr, "-%s unknown\n", cp);
2071 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
2072 print_help (buf, scanswit, 1);
2088 if (!(form = *args++) || *form == '-') {
2089 advise (NULL, "missing argument to %s", args[-2]);
2095 if (!(format = *args++) || *format == '-') {
2096 advise (NULL, "missing argument to %s", args[-2]);
2102 if (!(cp = *args++) || *cp == '-') {
2103 advise (NULL, "missing argument to %s", args[-2]);
2109 if (*cp == '+' || *cp == '@') {
2110 advise (NULL, "sorry, no folders allowed!");
2118 msgs[msgp++] = "all";
2119 for (msgnum = 0; msgnum < msgp; msgnum++)
2120 if (!m_convert (mp, msgs[msgnum]))
2124 /* Get new format string */
2125 nfs = new_fs (form, format, FORMAT);
2127 /* force scansbr to (re)compile format */
2134 s_optim = optim = 1;
2135 s_form = form ? getcpy (form) : NULL;
2136 s_format = format ? getcpy (format) : NULL;
2145 width = sc_width ();
2147 for (dp = nfs, i = 0; *dp; dp++, i++)
2148 if (*dp == '\\' || *dp == '"' || *dp == '\n')
2151 if ((ep = malloc ((unsigned) i)) == NULL)
2152 adios (NULL, "out of memory");
2153 for (dp = nfs, fp = ep; *dp; dp++) {
2155 *fp++ = '\\', *fp++ = 'n';
2158 if (*dp == '"' || *dp == '\\')
2164 if (pop_command ("XTND SCAN %d \"%s\"", width, ep) == OK)
2173 optim = equiv (s_form, form) && equiv (s_format, format);
2177 if (p_optim && optim) {
2178 for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++)
2179 if (!is_selected(mp, msgnum) || Msgs[msgnum].m_scanl)
2181 if (msgnum > mp->hghmsg && pop_command ("LIST") == OK) {
2182 fprintf (stderr, "Stand-by...");
2188 switch (pop_multiline ()) {
2190 fprintf (stderr, "%s", response);
2193 fprintf (stderr,"\n");
2197 if (sscanf (response, "%d %d", &msgnum, &size) == 2
2198 && mp->lowmsg <= msgnum
2199 && msgnum <= mp->hghmsg
2200 && (cp = strchr(response, '#'))
2202 Msgs[msgnum].m_scanl = concat (cp, "\n", NULL);
2213 for (msgnum = mp->lowsel;
2214 msgnum <= mp->hghsel && !interrupted;
2216 if (is_selected (mp, msgnum)) {
2217 if (optim && Msgs[msgnum].m_scanl)
2218 printf ("%s", Msgs[msgnum].m_scanl);
2224 && is_virtual (mp, msgnum)
2225 && pop_command ("LIST %d", msgnum) == OK
2226 && (cp = strchr(response, '#'))
2228 Msgs[msgnum].m_scanl = concat (cp, "\n", NULL);
2229 printf ("%s", Msgs[msgnum].m_scanl);
2235 zp = msh_ready (msgnum, 0);
2236 switch (state = scan (zp, msgnum, 0, nfs, width,
2237 msgnum == mp->curmsg,
2238 is_unseen (mp, msgnum),
2239 headersw ? (fmsh ? fmsh : mp->foldpath) : NULL,
2240 fmsh ? 0L : (long) (Msgs[msgnum].m_stop - Msgs[msgnum].m_start),
2246 Msgs[msgnum].m_scanl = getcpy (scanl);
2250 advise (NULL, "scan() botch (%d)", state);
2254 printf ("%*d empty\n", DMAXFOLDER, msgnum);
2266 static struct swit showswit[] = {
2270 { "form formfile", 4 },
2272 { "moreproc program", 4 },
2274 { "nomoreproc", 3 },
2276 { "length lines", 4 },
2278 { "width columns", 4 },
2280 { "showproc program", 4 },
2282 { "noshowproc", 3 },
2294 showcmd (char **args)
2296 int headersw = 1, nshow = 0, msgp = 0, vecp = 1;
2297 int mhl = 0, seqnum = -1, mode = 0, i, msgnum;
2298 char *cp, *proc = showproc, buf[BUFSIZ];
2299 char *msgs[MAXARGS], *vec[MAXARGS];
2301 if (!strcasecmp (cmd_name, "next"))
2304 if (!strcasecmp (cmd_name, "prev"))
2306 while ((cp = *args++)) {
2308 switch (i = smatch (++cp, showswit)) {
2310 ambigsw (cp, showswit);
2317 snprintf (buf, sizeof(buf), "%s %s[switches] [switches for showproc]",
2318 cmd_name, mode ? NULL : "[msgs] ");
2319 print_help (buf, showswit, 1);
2327 if (!(cp = *args++) || *cp == '-') {
2328 advise (NULL, "missing argument to %s", args[-2]);
2340 if (!(proc = *args++) || *proc == '-') {
2341 advise (NULL, "missing argument to %s", args[-2]);
2351 advise (NULL, "sorry, -%s not allowed!", showswit[i].sw);
2354 if (*cp == '+' || *cp == '@') {
2355 advise (NULL, "sorry, no folders allowed!");
2361 "usage: %s [switches] [switches for showproc]\n",
2371 msgs[msgp++] = mode > 0 ? "next" : mode < 0 ? "prev" : "cur";
2372 for (msgnum = 0; msgnum < msgp; msgnum++)
2373 if (!m_convert (mp, msgs[msgnum]))
2377 if (!nshow && !getenv ("NOMHNPROC"))
2378 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
2379 if (is_selected (mp, msgnum) && is_nontext (msgnum)) {
2380 proc = showmimeproc;
2381 vec[vecp++] = "-show";
2382 vec[vecp++] = "-file";
2390 if (strcmp (showproc, "mhl") == 0) {
2396 seqnum = seq_getnum (mp, "unseen");
2397 vec[0] = r1bindex (proc, '/');
2400 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
2401 if (is_selected (mp, msgnum)) {
2402 vec[vecp++] = getcpy (m_name (msgnum));
2404 seq_delmsg (mp, "unseen", msgnum);
2407 if (mp->numsel == 1 && headersw)
2409 mhlsbr (vecp, vec, mhl_action);
2410 m_eomsbr ((int (*)()) 0);
2415 for (msgnum = mp->lowsel;
2416 msgnum <= mp->hghsel && !interrupted;
2418 if (is_selected (mp, msgnum)) {
2419 switch (ask (msgnum)) {
2420 case NOTOK: /* QUIT */
2427 if (mp->numsel == 1 && headersw)
2430 copy_message (msgnum, stdout);
2432 process (msgnum, proc, vecp, vec);
2435 seq_delmsg (mp, "unseen", msgnum);
2442 seq_setcur (mp, mp->hghsel);
2449 if (Msgs[msgnum].m_bboard_id == 0)
2452 printf ("(Message %d", msgnum);
2453 if (Msgs[msgnum].m_bboard_id > 0)
2454 printf (", %s: %d", BBoard_ID, Msgs[msgnum].m_bboard_id);
2463 return (ftell (mhlfp) >= Msgs[mhlnum].m_stop);
2468 mhl_action (char *name)
2472 if ((msgnum = m_atoi (name)) < mp->lowmsg
2473 || msgnum > mp->hghmsg
2474 || !does_exist (mp, msgnum))
2478 mhlfp = msh_ready (msgnum, 1);
2480 m_eomsbr (eom_action);
2492 if (mp->numsel == 1 || !interactive || redirected)
2495 if (SOprintf ("Press <return> to list \"%d\"...", msgnum)) {
2496 if (mp->lowsel != msgnum)
2498 printf ("Press <return> to list \"%d\"...", msgnum);
2504 read (fileno (stdout), buf, sizeof buf);
2506 switch (setjmp (sigenv)) {
2509 read (fileno (stdout), buf, sizeof buf);/* fall... */
2517 if (strchr(buf, '\n') == NULL)
2521 told_to_quit = interrupted = 0;
2536 is_nontext (int msgnum)
2540 char buf[BUFSIZ], name[NAMESZ];
2543 if (Msgs[msgnum].m_flags & MHNCHK)
2544 return (Msgs[msgnum].m_flags & MHNYES);
2545 Msgs[msgnum].m_flags |= MHNCHK;
2547 fp = msh_ready (msgnum, 1);
2550 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
2555 * Check Content-Type field
2557 if (!strcasecmp (name, TYPE_FIELD)) {
2561 cp = add (buf, NULL);
2562 while (state == FLDPLUS) {
2563 state = m_getfld (state, name, buf, sizeof buf, fp);
2570 for (; isspace (*bp); bp++)
2575 for (bp++, i = 0;;) {
2605 for (dp = bp; istoken (*dp); dp++)
2612 if ((result = (strcasecmp (bp, "plain") != 0)))
2615 for (dp++; isspace (*dp); dp++)
2618 if ((result = !uprf (dp, "charset")))
2620 dp += sizeof "charset" - 1;
2621 while (isspace (*dp))
2625 while (isspace (*dp))
2628 if ((bp = strchr(++dp, '"')))
2631 for (bp = dp; *bp; bp++)
2632 if (isspace (*bp)) {
2638 /* Default character set */
2641 /* Check the character set */
2642 result = !check_charset (dp, strlen (dp));
2644 if (!(result = (strcasecmp (bp, "text") != 0))) {
2654 Msgs[msgnum].m_flags |= MHNYES;
2661 * Check Content-Transfer-Encoding field
2663 if (!strcasecmp (name, ENCODING_FIELD)) {
2664 cp = add (buf, NULL);
2665 while (state == FLDPLUS) {
2666 state = m_getfld (state, name, buf, sizeof buf, fp);
2669 for (bp = cp; isspace (*bp); bp++)
2671 for (dp = bp; istoken (*dp); dp++)
2674 result = (strcasecmp (bp, "7bit")
2675 && strcasecmp (bp, "8bit")
2676 && strcasecmp (bp, "binary"));
2680 Msgs[msgnum].m_flags |= MHNYES;
2687 * Just skip the rest of this header
2688 * field and go to next one.
2690 while (state == FLDPLUS)
2691 state = m_getfld (state, name, buf, sizeof(buf), fp);
2695 * We've passed the message header,
2696 * so message is just text.
2704 static struct swit sortswit[] = {
2706 { "datefield field", 0 },
2708 { "textfield field", 0 },
2710 { "notextfield", 0 },
2712 { "limit days", 0 },
2726 sortcmd (char **args)
2728 int msgp = 0, msgnum;
2729 char *cp, *datesw = NULL, *subjsw = NULL;
2730 char buf[BUFSIZ], *msgs[MAXARGS];
2734 forkcmd (args, cmd_name);
2738 while ((cp = *args++)) {
2740 switch (smatch (++cp, sortswit)) {
2742 ambigsw (cp, sortswit);
2745 fprintf (stderr, "-%s unknown\n", cp);
2748 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
2749 print_help (buf, sortswit, 1);
2754 advise (NULL, "only one date field at a time!");
2757 if (!(datesw = *args++) || *datesw == '-') {
2758 advise (NULL, "missing argument to %s", args[-2]);
2765 advise (NULL, "only one text field at a time!");
2768 if (!(subjsw = *args++) || *subjsw == '-') {
2769 advise (NULL, "missing argument to %s", args[-2]);
2777 case SOLIMT: /* too hard */
2778 if (!(cp = *args++) || *cp == '-') {
2779 advise (NULL, "missing argument to %s", args[-2]);
2783 case SOVERB: /* not implemented */
2787 if (*cp == '+' || *cp == '@') {
2788 advise (NULL, "sorry, no folders allowed!");
2796 msgs[msgp++] = "all";
2799 for (msgnum = 0; msgnum < msgp; msgnum++)
2800 if (!m_convert (mp, msgs[msgnum]))
2804 twscopy (&tb, dlocaltimenow ());
2806 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
2807 if (Msgs[msgnum].m_scanl) {
2808 free (Msgs[msgnum].m_scanl);
2809 Msgs[msgnum].m_scanl = NULL;
2811 if (is_selected (mp, msgnum)) {
2812 if (get_fields (datesw, subjsw, msgnum, &Msgs[msgnum]))
2813 twscopy (&Msgs[msgnum].m_tb,
2814 msgnum != mp->lowsel ? &Msgs[msgnum - 1].m_tb : &tb);
2816 else /* m_scaln is already NULL */
2817 twscopy (&Msgs[msgnum].m_tb, &tb);
2818 Msgs[msgnum].m_stats = mp->msgstats[msgnum - mp->lowoff];
2819 if (mp->curmsg == msgnum)
2820 Msgs[msgnum].m_stats |= CUR;
2823 qsort ((char *) &Msgs[mp->lowsel], mp->hghsel - mp->lowsel + 1,
2824 sizeof(struct Msg), (qsort_comp) (subjsw ? subsort : msgsort));
2826 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
2827 if (subjsw && Msgs[msgnum].m_scanl) {
2828 free (Msgs[msgnum].m_scanl); /* from subjsort */
2829 Msgs[msgnum].m_scanl = NULL;
2831 mp->msgstats[msgnum - mp->lowoff] = Msgs[msgnum].m_stats & ~CUR;
2832 if (Msgs[msgnum].m_stats & CUR)
2833 seq_setcur (mp, msgnum);
2836 mp->msgflags |= MODIFIED;
2842 * get_fields - parse message, and get date and subject if needed.
2843 * We'll use the msgp->m_tb tws struct for the date, and overload
2844 * the msgp->m_scanl field with our subject string.
2847 get_fields (char *datesw, char *subjsw, int msgnum, struct Msg *msgp)
2849 int state, gotdate = 0;
2850 char *bp, buf[BUFSIZ], name[NAMESZ];
2851 struct tws *tw = (struct tws *) 0;
2854 zp = msh_ready (msgnum, 0);
2855 for (state = FLD;;) {
2856 switch (state = m_getfld (state, name, buf, sizeof buf, zp)) {
2860 if (!strcasecmp (name, datesw)) {
2862 while (state == FLDPLUS) {
2863 state = m_getfld (state, name, buf, sizeof buf, zp);
2866 if ((tw = dparsetime (bp)) == NULL)
2868 "unable to parse %s field in message %d",
2871 twscopy (&(msgp->m_tb), tw);
2873 if (!subjsw) /* not using this, or already done */
2874 break; /* all done! */
2877 else if (subjsw && !strcasecmp(name, subjsw)) {
2879 while (state == FLDPLUS) {
2880 state = m_getfld (state, name, buf, sizeof buf, zp);
2883 msgp->m_scanl = sosmash(subjsw, bp);
2885 break; /* date done so we're done */
2887 subjsw = (char *)0;/* subject done, need date */
2889 while (state == FLDPLUS) /* flush this one */
2890 state = m_getfld (state, name, buf, sizeof buf, zp);
2901 admonish (NULL, "format error in message %d", msgnum);
2902 if (msgp->m_scanl) { /* this might need free'd */
2903 free (msgp->m_scanl); /* probably can't use subj anyway */
2904 msgp->m_scanl = NULL;
2909 adios (NULL, "internal error -- you lose");
2914 return OK; /* not an error if subj not found */
2916 admonish (NULL, "no %s field in message %d", datesw, msgnum);
2917 return NOTOK; /* NOTOK means use some other date */
2926 msgsort (struct Msg *a, struct Msg *b)
2928 return twsort (&a->m_tb, &b->m_tb);
2933 subsort (struct Msg *a, struct Msg *b)
2937 if (a->m_scanl && b->m_scanl)
2938 if ((i = strcmp (a->m_scanl, b->m_scanl)))
2941 return twsort (&a->m_tb, &b->m_tb);
2946 * try to make the subject "canonical": delete leading "re:", everything
2947 * but letters & smash letters to lower case.
2950 sosmash (char *subj, char *s)
2952 register char *cp, *dp, c;
2956 dp = s; /* dst pointer */
2957 if (!strcasecmp (subj, "subject"))
2964 *dp++ = isupper(c) ? tolower(c) : c;
2970 while ((c = *cp++)) {
2972 *dp++ = isupper(c) ? tolower(c) : c;
2982 process (int msgnum, char *proc, int vecp, char **vec)
2984 int child_id, status;
2989 strncpy (tmpfil, m_name (msgnum), sizeof(tmpfil));
2990 context_del (pfolder);
2991 context_replace (pfolder, fmsh);/* update current folder */
2993 context_save (); /* save the context file */
2997 strncpy (tmpfil, m_scratch ("", invo_name), sizeof(tmpfil));
2998 if ((out = fopen (tmpfil, "w")) == NULL) {
3004 strncpy (newfil, m_tmpfil (invo_name), sizeof(newfil));
3005 if ((out = fopen (newfil, "w")) == NULL) {
3007 advise (tmpfil, "unable to create temporary file");
3010 strncpy (tmpfil, newfil, sizeof(tmpfil));
3013 copy_message (msgnum, out);
3018 switch (child_id = fork ()) {
3020 advise ("fork", "unable to");
3026 SIGNAL (SIGINT, istat);
3027 SIGNAL (SIGQUIT, qstat);
3029 vec[vecp++] = tmpfil;
3033 fprintf (stderr, "unable to exec ");
3038 status = pidXwait (child_id, NULL);
3049 copy_message (int msgnum, FILE *out)
3052 static char buffer[BUFSIZ];
3055 zp = msh_ready (msgnum, 1);
3057 while (fgets (buffer, sizeof buffer, zp) != NULL) {
3058 fputs (buffer, out);
3059 if (interrupted && out == stdout)
3065 while (fgets (buffer, sizeof buffer, zp) != NULL
3066 && pos < Msgs[msgnum].m_stop) {
3067 fputs (buffer, out);
3068 pos += (long) strlen (buffer);
3069 if (interrupted && out == stdout)
3077 copy_digest (int msgnum, FILE *out)
3081 static char buffer[BUFSIZ];
3085 zp = msh_ready (msgnum, 1);
3088 while (fgets (buffer, sizeof buffer, zp) != NULL
3089 && !fmsh && pos < Msgs[msgnum].m_stop) {
3090 if (c == '\n' && *buffer == '-')
3092 fputs (buffer, out);
3093 c = buffer[strlen (buffer) - 1];
3095 pos += (long) strlen (buffer);
3096 if (interrupted && out == stdout)