]> diplodocus.org Git - nmh/blob - uip/mshcmds.c
Added notes about the configure change.
[nmh] / uip / mshcmds.c
1
2 /*
3 * mshcmds.c -- command handlers in msh
4 *
5 * $Id$
6 */
7
8 #include <h/mh.h>
9 #include <h/signals.h>
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>
15 #include <errno.h>
16 #include <setjmp.h>
17 #include <signal.h>
18 #include <h/msh.h>
19 #include <h/picksbr.h>
20
21 extern int errno;
22
23 static char delim3[] = "-------"; /* from burst.c */
24
25 static int mhlnum;
26 static FILE *mhlfp;
27
28 #if defined(NNTP) && defined(MPOP)
29 # undef MPOP
30 #endif
31
32 #ifdef MPOP
33 # ifdef BPOP
34 extern int pmsh;
35 extern char response[];
36 # endif
37 #endif /* MPOP */
38
39 /*
40 * Type for a compare function for qsort. This keeps
41 * the compiler happy.
42 */
43 typedef int (*qsort_comp) (const void *, const void *);
44
45 /*
46 * prototypes
47 */
48 void clear_screen (void); /* from termsbr.c */
49 int SOprintf (char *, ...); /* from termsbr.c */
50 int sc_width (void); /* from termsbr.c */
51
52 /*
53 * static prototypes
54 */
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 *);
61 static int ask (int);
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 *);
70
71
72 void
73 forkcmd (char **args, char *pgm)
74 {
75 int child_id;
76 char *vec[MAXARGS];
77
78 vec[0] = r1bindex (pgm, '/');
79 copyip (args, vec + 1, MAXARGS - 1);
80
81 if (fmsh) {
82 context_del (pfolder);
83 context_replace (pfolder, fmsh);/* update current folder */
84 seq_save (mp);
85 context_save (); /* save the context file */
86 }
87 fflush (stdout);
88 switch (child_id = fork ()) {
89 case NOTOK:
90 advise ("fork", "unable to");
91 return;
92
93 case OK:
94 closefds (3);
95 SIGNAL (SIGINT, istat);
96 SIGNAL (SIGQUIT, qstat);
97
98 execvp (pgm, vec);
99 fprintf (stderr, "unable to exec ");
100 perror (cmd_name);
101 _exit (1);
102
103 default:
104 pidXwait (child_id, NULL);
105 break;
106 }
107 if (fmsh) { /* assume the worst case */
108 mp->msgflags |= MODIFIED;
109 modified++;
110 }
111 }
112
113
114 static struct swit distswit[] = {
115 #define DIANSW 0
116 { "annotate", 0 },
117 #define DINANSW 1
118 { "noannotate", 0 },
119 #define DIDFSW 2
120 { "draftfolder +folder", 0 },
121 #define DIDMSW 3
122 { "draftmessage msg", 0 },
123 #define DINDFSW 4
124 { "nodraftfolder", 0 },
125 #define DIEDTSW 5
126 { "editor editor", 0 },
127 #define DINEDSW 6
128 { "noedit", 0 },
129 #define DIFRMSW 7
130 { "form formfile", 0 },
131 #define DIINSW 8
132 { "inplace", 0 },
133 #define DININSW 9
134 { "noinplace", 0 },
135 #define DIWHTSW 10
136 { "whatnowproc program", 0 },
137 #define DINWTSW 11
138 { "nowhatnowproc", 0 },
139 #define DIHELP 12
140 { "help", 4 },
141 { NULL, 0 }
142 };
143
144
145 void
146 distcmd (char **args)
147 {
148 int vecp = 1;
149 char *cp, *msg = NULL;
150 char buf[BUFSIZ], *vec[MAXARGS];
151
152 if (fmsh) {
153 forkcmd (args, cmd_name);
154 return;
155 }
156
157 while ((cp = *args++)) {
158 if (*cp == '-')
159 switch (smatch (++cp, distswit)) {
160 case AMBIGSW:
161 ambigsw (cp, distswit);
162 return;
163 case UNKWNSW:
164 fprintf (stderr, "-%s unknown\n", cp);
165 return;
166 case DIHELP:
167 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
168 print_help (buf, distswit, 1);
169 return;
170
171 case DIANSW: /* not implemented */
172 case DINANSW:
173 case DIINSW:
174 case DININSW:
175 continue;
176
177 case DINDFSW:
178 case DINEDSW:
179 case DINWTSW:
180 vec[vecp++] = --cp;
181 continue;
182
183 case DIEDTSW:
184 case DIFRMSW:
185 case DIDFSW:
186 case DIDMSW:
187 case DIWHTSW:
188 vec[vecp++] = --cp;
189 if (!(cp = *args++) || *cp == '-') {
190 advise (NULL, "missing argument to %s", args[-2]);
191 return;
192 }
193 vec[vecp++] = cp;
194 continue;
195 }
196 if (*cp == '+' || *cp == '@') {
197 advise (NULL, "sorry, no folders allowed!");
198 return;
199 }
200 else
201 if (msg) {
202 advise (NULL, "only one message at a time!");
203 return;
204 }
205 else
206 msg = cp;
207 }
208
209 vec[0] = cmd_name;
210 vec[vecp++] = "-file";
211 vec[vecp] = NULL;
212 if (!msg)
213 msg = "cur";
214 if (!m_convert (mp, msg))
215 return;
216 seq_setprev (mp);
217
218 if (mp->numsel > 1) {
219 advise (NULL, "only one message at a time!");
220 return;
221 }
222 process (mp->hghsel, cmd_name, vecp, vec);
223 seq_setcur (mp, mp->hghsel);
224 }
225
226
227 static struct swit explswit[] = {
228 #define EXINSW 0
229 { "inplace", 0 },
230 #define EXNINSW 1
231 { "noinplace", 0 },
232 #define EXQISW 2
233 { "quiet", 0 },
234 #define EXNQISW 3
235 { "noquiet", 0 },
236 #define EXVBSW 4
237 { "verbose", 0 },
238 #define EXNVBSW 5
239 { "noverbose", 0 },
240 #define EXHELP 6
241 { "help", 4 },
242 { NULL, 0 }
243 };
244
245
246 void
247 explcmd (char **args)
248 {
249 int inplace = 0, quietsw = 0, verbosw = 0;
250 int msgp = 0, hi, msgnum;
251 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
252 struct Msg *smsgs;
253
254 if (fmsh) {
255 forkcmd (args, cmd_name);
256 return;
257 }
258
259 while ((cp = *args++)) {
260 if (*cp == '-')
261 switch (smatch (++cp, explswit)) {
262 case AMBIGSW:
263 ambigsw (cp, explswit);
264 return;
265 case UNKWNSW:
266 fprintf (stderr, "-%s unknown\n", cp);
267 return;
268 case EXHELP:
269 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
270 print_help (buf, explswit, 1);
271 return;
272
273 case EXINSW:
274 inplace++;
275 continue;
276 case EXNINSW:
277 inplace = 0;
278 continue;
279 case EXQISW:
280 quietsw++;
281 continue;
282 case EXNQISW:
283 quietsw = 0;
284 continue;
285 case EXVBSW:
286 verbosw++;
287 continue;
288 case EXNVBSW:
289 verbosw = 0;
290 continue;
291 }
292 if (*cp == '+' || *cp == '@') {
293 advise (NULL, "sorry, no folders allowed!");
294 return;
295 }
296 else
297 msgs[msgp++] = cp;
298 }
299
300 if (!msgp)
301 msgs[msgp++] = "cur";
302 for (msgnum = 0; msgnum < msgp; msgnum++)
303 if (!m_convert (mp, msgs[msgnum]))
304 return;
305 seq_setprev (mp);
306
307 smsgs = (struct Msg *)
308 calloc ((size_t) (MAXFOLDER + 2), sizeof *smsgs);
309 if (smsgs == NULL)
310 adios (NULL, "unable to allocate folder storage");
311
312 hi = mp->hghmsg + 1;
313 interrupted = 0;
314 for (msgnum = mp->lowsel;
315 msgnum <= mp->hghsel && !interrupted;
316 msgnum++)
317 if (is_selected (mp, msgnum))
318 if (burst (smsgs, msgnum, inplace, quietsw, verbosw) != OK)
319 break;
320
321 free ((char *) smsgs);
322
323 if (inplace)
324 seq_setcur (mp, mp->lowsel);
325 else
326 if (hi <= mp->hghmsg)
327 seq_setcur (mp, hi);
328
329 mp->msgflags |= MODIFIED;
330 modified++;
331 }
332
333
334 static int
335 burst (struct Msg *smsgs, int msgnum, int inplace, int quietsw, int verbosw)
336 {
337 int i, j, ld3, wasdlm, msgp;
338 long pos;
339 char c, buffer[BUFSIZ];
340 register FILE *zp;
341
342 ld3 = strlen (delim3);
343
344 if (Msgs[msgnum].m_scanl) {
345 free (Msgs[msgnum].m_scanl);
346 Msgs[msgnum].m_scanl = NULL;
347 }
348
349 pos = ftell (zp = msh_ready (msgnum, 1));
350 for (msgp = 0; msgp <= MAXFOLDER;) {
351 while (fgets (buffer, sizeof buffer, zp) != NULL
352 && buffer[0] == '\n'
353 && pos < Msgs[msgnum].m_stop)
354 pos += (long) strlen (buffer);
355 if (feof (zp) || pos >= Msgs[msgnum].m_stop)
356 break;
357 fseek (zp, pos, SEEK_SET);
358 smsgs[msgp].m_start = pos;
359
360 for (c = 0;
361 pos < Msgs[msgnum].m_stop
362 && fgets (buffer, sizeof buffer, zp) != NULL;
363 c = buffer[0])
364 if (strncmp (buffer, delim3, ld3) == 0
365 && (msgp == 1 || c == '\n')
366 && peekc (zp) == '\n')
367 break;
368 else
369 pos += (long) strlen (buffer);
370
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) {
375 if (wasdlm)
376 smsgs[msgp - 1].m_stop -= ((long) strlen (buffer) + 1);
377 break;
378 }
379 pos += (long) strlen (buffer);
380 }
381
382 switch (msgp--) { /* toss "End of XXX Digest" */
383 case 0:
384 adios (NULL, "burst() botch -- you lose big");
385
386 case 1:
387 if (!quietsw)
388 printf ("message %d not in digest format\n", msgnum);
389 return OK;
390
391 default:
392 if (verbosw)
393 printf ("%d message%s exploded from digest %d\n",
394 msgp, msgp != 1 ? "s" : "", msgnum);
395 break;
396 }
397
398 if ((i = msgp + mp->hghmsg) > MAXFOLDER) {
399 advise (NULL, "more than %d messages", MAXFOLDER);
400 return NOTOK;
401 }
402 if (!(mp = folder_realloc (mp, mp->lowoff, i)))
403 adios (NULL, "unable to allocate folder storage");
404
405 j = mp->hghmsg;
406 mp->hghmsg += msgp;
407 mp->nummsg += msgp;
408 if (mp->hghsel > msgnum)
409 mp->hghsel += msgp;
410
411 if (inplace)
412 for (i = mp->hghmsg; j > msgnum; i--, j--) {
413 if (verbosw)
414 printf ("message %d becomes message %d\n", j, i);
415
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;
424 }
425 copy_msg_flags (mp, i, j);
426 }
427
428 if (Msgs[msgnum].m_bboard_id == 0)
429 readid (msgnum);
430
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",
436 j, msgnum, i);
437
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);
444 }
445
446 return OK;
447 }
448
449
450 static struct swit fileswit[] = {
451 #define FIDRFT 0
452 { "draft", 0 },
453 #define FILINK 1
454 { "link", 0 },
455 #define FINLINK 2
456 { "nolink", 0 },
457 #define FIPRES 3
458 { "preserve", 0 },
459 #define FINPRES 4
460 { "nopreserve", 0 },
461 #define FISRC 5
462 { "src +folder", 0 },
463 #define FIFILE 6
464 { "file file", 0 },
465 #define FIPROC 7
466 { "rmmproc program", 0 },
467 #define FINPRC 8
468 { "normmproc", 0 },
469 #define FIHELP 9
470 { "help", 4 },
471 { NULL, 0 }
472 };
473
474
475 void
476 filecmd (char **args)
477 {
478 int linksw = 0, msgp = 0;
479 int vecp = 1, i, msgnum;
480 char *cp, buf[BUFSIZ];
481 char *msgs[MAXARGS], *vec[MAXARGS];
482
483 if (fmsh) {
484 forkcmd (args, cmd_name);
485 return;
486 }
487
488 while ((cp = *args++)) {
489 if (*cp == '-')
490 switch (i = smatch (++cp, fileswit)) {
491 case AMBIGSW:
492 ambigsw (cp, fileswit);
493 return;
494 case UNKWNSW:
495 fprintf (stderr, "-%s unknown\n", cp);
496 return;
497 case FIHELP:
498 snprintf (buf, sizeof(buf), "%s +folder... [msgs] [switches]", cmd_name);
499 print_help (buf, fileswit, 1);
500 return;
501
502 case FILINK:
503 linksw++;
504 continue;
505 case FINLINK:
506 linksw = 0;
507 continue;
508
509 case FIPRES:
510 case FINPRES:
511 continue;
512
513 case FISRC:
514 case FIDRFT:
515 case FIFILE:
516 case FIPROC:
517 case FINPRC:
518 advise (NULL, "sorry, -%s not allowed!", fileswit[i].sw);
519 return;
520 }
521 if (*cp == '+' || *cp == '@')
522 vec[vecp++] = cp;
523 else
524 msgs[msgp++] = cp;
525 }
526
527 vec[0] = cmd_name;
528 vec[vecp++] = "-file";
529 vec[vecp] = NULL;
530 if (!msgp)
531 msgs[msgp++] = "cur";
532 for (msgnum = 0; msgnum < msgp; msgnum++)
533 if (!m_convert (mp, msgs[msgnum]))
534 return;
535 seq_setprev (mp);
536
537 interrupted = 0;
538 for (msgnum = mp->lowsel;
539 msgnum <= mp->hghsel && !interrupted;
540 msgnum++)
541 if (is_selected (mp, msgnum))
542 if (process (msgnum, fileproc, vecp, vec)) {
543 unset_selected (mp, msgnum);
544 mp->numsel--;
545 }
546
547 if (mp->numsel != mp->nummsg || linksw)
548 seq_setcur (mp, mp->hghsel);
549 if (!linksw)
550 rmm ();
551 }
552
553
554 int
555 filehak (char **args)
556 {
557 int result, vecp = 0;
558 char *cp, *cwd, *vec[MAXARGS];
559
560 while ((cp = *args++)) {
561 if (*cp == '-')
562 switch (smatch (++cp, fileswit)) {
563 case AMBIGSW:
564 case UNKWNSW:
565 case FIHELP:
566 return NOTOK;
567
568 case FILINK:
569 case FINLINK:
570 case FIPRES:
571 case FINPRES:
572 continue;
573
574 case FISRC:
575 case FIDRFT:
576 case FIFILE:
577 return NOTOK;
578 }
579 if (*cp == '+' || *cp == '@')
580 vec[vecp++] = cp;
581 }
582 vec[vecp] = NULL;
583
584 result = NOTOK;
585 cwd = NULL;
586 for (vecp = 0; (cp = vec[vecp]) && result == NOTOK; vecp++) {
587 if (cwd == NULL)
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)
592 result = OK;
593 free (cp);
594 }
595 if (cwd)
596 chdir (cwd);
597
598 return result;
599 }
600
601
602 static struct swit foldswit[] = {
603 #define FLALSW 0
604 { "all", 0 },
605 #define FLFASW 1
606 { "fast", 0 },
607 #define FLNFASW 2
608 { "nofast", 0 },
609 #define FLHDSW 3
610 { "header", 0 },
611 #define FLNHDSW 4
612 { "noheader", 0 },
613 #define FLPKSW 5
614 { "pack", 0 },
615 #define FLNPKSW 6
616 { "nopack", 0 },
617 #define FLRCSW 7
618 { "recurse", 0 },
619 #define FLNRCSW 8
620 { "norecurse", 0 },
621 #define FLTLSW 9
622 { "total", 0 },
623 #define FLNTLSW 10
624 { "nototal", 0 },
625 #define FLPRSW 11
626 { "print", 0 },
627 #define FLPUSW 12
628 { "push", 0 },
629 #define FLPOSW 13
630 { "pop", 0 },
631 #define FLLISW 14
632 { "list", 0 },
633 #define FLHELP 15
634 { "help", 4 },
635 { NULL, 0 }
636 };
637
638
639 void
640 foldcmd (char **args)
641 {
642 int fastsw = 0, headersw = 0, packsw = 0;
643 int hole, msgnum;
644 char *cp, *folder = NULL, *msg = NULL;
645 char buf[BUFSIZ], **vec = args;
646
647 if (args == NULL)
648 goto fast;
649
650 while ((cp = *args++)) {
651 if (*cp == '-')
652 switch (smatch (++cp, foldswit)) {
653 case AMBIGSW:
654 ambigsw (cp, foldswit);
655 return;
656 case UNKWNSW:
657 fprintf (stderr, "-%s unknown\n", cp);
658 return;
659 case FLHELP:
660 snprintf (buf, sizeof(buf), "%s [+folder] [msg] [switches]", cmd_name);
661 print_help (buf, foldswit, 1);
662 return;
663
664 case FLALSW: /* not implemented */
665 case FLRCSW:
666 case FLNRCSW:
667 case FLTLSW:
668 case FLNTLSW:
669 case FLPRSW:
670 case FLPUSW:
671 case FLPOSW:
672 case FLLISW:
673 continue;
674
675 case FLFASW:
676 fastsw++;
677 continue;
678 case FLNFASW:
679 fastsw = 0;
680 continue;
681 case FLHDSW:
682 headersw++;
683 continue;
684 case FLNHDSW:
685 headersw = 0;
686 continue;
687 case FLPKSW:
688 packsw++;
689 continue;
690 case FLNPKSW:
691 packsw = 0;
692 continue;
693 }
694 if (*cp == '+' || *cp == '@')
695 if (folder) {
696 advise (NULL, "only one folder at a time!\n");
697 return;
698 }
699 else
700 folder = fmsh ? path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF)
701 : cp + 1;
702 else
703 if (msg) {
704 advise (NULL, "only one message at a time!\n");
705 return;
706 }
707 else
708 msg = cp;
709 }
710
711 if (folder) {
712 if (*folder == 0) {
713 advise (NULL, "null folder names are not permitted");
714 return;
715 }
716 if (fmsh) {
717 if (access (m_maildir (folder), R_OK) == NOTOK) {
718 advise (folder, "unable to read");
719 return;
720 }
721 }
722 else {
723 strncpy (buf, folder, sizeof(buf));
724 if (expand (buf) == NOTOK)
725 return;
726 folder = buf;
727 if (access (folder, R_OK) == NOTOK) {
728 advise (folder, "unable to read");
729 return;
730 }
731 }
732 m_reset ();
733
734 if (fmsh)
735 fsetup (folder);
736 else
737 setup (folder);
738 readids (0);
739 display_info (0);
740 }
741
742 if (msg) {
743 if (!m_convert (mp, msg))
744 return;
745 seq_setprev (mp);
746
747 if (mp->numsel > 1) {
748 advise (NULL, "only one message at a time!");
749 return;
750 }
751 seq_setcur (mp, mp->hghsel);
752 }
753
754 if (packsw) {
755 if (fmsh) {
756 forkcmd (vec, cmd_name);
757 return;
758 }
759
760 if (mp->lowoff > 1 && !(mp = folder_realloc (mp, 1, mp->hghmsg)))
761 adios (NULL, "unable to allocate folder storage");
762
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;
774 }
775 copy_msg_flags (mp, hole, msgnum);
776 if (mp->curmsg == msgnum)
777 seq_setcur (mp, hole);
778 }
779 hole++;
780 }
781 if (mp->nummsg > 0) {
782 mp->lowmsg = 1;
783 mp->hghmsg = hole - 1;
784 }
785 mp->msgflags |= MODIFIED;
786 modified++;
787 }
788
789 fast: ;
790 if (fastsw)
791 printf ("%s\n", fmsh ? fmsh : mp->foldpath);
792 else {
793 if (headersw)
794 printf ("\t\tFolder %*s# of messages (%*srange%*s); cur%*smsg\n",
795 DMAXFOLDER, "", DMAXFOLDER - 2, "", DMAXFOLDER - 2, "",
796 DMAXFOLDER - 2, "");
797 printf (args ? "%22s " : "%s ", fmsh ? fmsh : mp->foldpath);
798
799 /* check for empty folder */
800 if (mp->nummsg == 0) {
801 printf ("has no messages%*s",
802 mp->msgflags & OTHERS ? DMAXFOLDER * 2 + 4 : 0, "");
803 } else {
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);
810 }
811 printf (".\n");
812 }
813 }
814
815
816 static struct swit forwswit[] = {
817 #define FOANSW 0
818 { "annotate", 0 },
819 #define FONANSW 1
820 { "noannotate", 0 },
821 #define FODFSW 2
822 { "draftfolder +folder", 0 },
823 #define FODMSW 3
824 { "draftmessage msg", 0 },
825 #define FONDFSW 4
826 { "nodraftfolder", 0 },
827 #define FOEDTSW 5
828 { "editor editor", 0 },
829 #define FONEDSW 6
830 { "noedit", 0 },
831 #define FOFTRSW 7
832 { "filter filterfile", 0 },
833 #define FOFRMSW 8
834 { "form formfile", 0 },
835 #define FOFTSW 9
836 { "format", 5 },
837 #define FONFTSW 10
838 { "noformat", 7 },
839 #define FOINSW 11
840 { "inplace", 0 },
841 #define FONINSW 12
842 { "noinplace", 0 },
843 #define FOMISW 13
844 { "mime", 0 },
845 #define FONMISW 14
846 { "nomime", 0 },
847 #define FOWHTSW 15
848 { "whatnowproc program", 0 },
849 #define FONWTSW 16
850 { "nowhatnow", 0 },
851 #define FOHELP 17
852 { "help", 4 },
853 { NULL, 0 }
854 };
855
856
857 void
858 forwcmd (char **args)
859 {
860 int msgp = 0, vecp = 1, msgnum;
861 char *cp, *filter = NULL, buf[BUFSIZ];
862 char *msgs[MAXARGS], *vec[MAXARGS];
863
864 if (fmsh) {
865 forkcmd (args, cmd_name);
866 return;
867 }
868
869 while ((cp = *args++)) {
870 if (*cp == '-')
871 switch (smatch (++cp, forwswit)) {
872 case AMBIGSW:
873 ambigsw (cp, forwswit);
874 return;
875 case UNKWNSW:
876 fprintf (stderr, "-%s unknown\n", cp);
877 return;
878 case FOHELP:
879 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
880 print_help (buf, forwswit, 1);
881 return;
882
883 case FOANSW: /* not implemented */
884 case FONANSW:
885 case FOINSW:
886 case FONINSW:
887 case FOMISW:
888 case FONMISW:
889 continue;
890
891 case FONDFSW:
892 case FONEDSW:
893 case FONWTSW:
894 vec[vecp++] = --cp;
895 continue;
896
897 case FOEDTSW:
898 case FOFRMSW:
899 case FODFSW:
900 case FODMSW:
901 case FOWHTSW:
902 vec[vecp++] = --cp;
903 if (!(cp = *args++) || *cp == '-') {
904 advise (NULL, "missing argument to %s", args[-2]);
905 return;
906 }
907 vec[vecp++] = cp;
908 continue;
909 case FOFTRSW:
910 if (!(filter = *args++) || *filter == '-') {
911 advise (NULL, "missing argument to %s", args[-2]);
912 return;
913 }
914 continue;
915 case FOFTSW:
916 if (access (filter = myfilter, R_OK) == NOTOK) {
917 advise (filter, "unable to read default filter file");
918 return;
919 }
920 continue;
921 case FONFTSW:
922 filter = NULL;
923 continue;
924 }
925 if (*cp == '+' || *cp == '@') {
926 advise (NULL, "sorry, no folders allowed!");
927 return;
928 }
929 else
930 msgs[msgp++] = cp;
931 }
932
933 /* foil search of .mh_profile */
934 snprintf (buf, sizeof(buf), "%sXXXXXX", invo_name);
935 vec[0] = (char *)mktemp (buf);
936 vec[vecp++] = "-file";
937 vec[vecp] = NULL;
938 if (!msgp)
939 msgs[msgp++] = "cur";
940 for (msgnum = 0; msgnum < msgp; msgnum++)
941 if (!m_convert (mp, msgs[msgnum]))
942 return;
943 seq_setprev (mp);
944
945 if (filter) {
946 strncpy (buf, filter, sizeof(buf));
947 if (expand (buf) == NOTOK)
948 return;
949 if (access (filter = getcpy (etcpath (buf)), R_OK) == NOTOK) {
950 advise (filter, "unable to read");
951 free (filter);
952 return;
953 }
954 }
955 forw (cmd_name, filter, vecp, vec);
956 seq_setcur (mp, mp->hghsel);
957 if (filter)
958 free (filter);
959 }
960
961
962 static void
963 forw (char *proc, char *filter, int vecp, char **vec)
964 {
965 int i, child_id, msgnum, msgcnt;
966 char tmpfil[80], *args[MAXARGS];
967 FILE *out;
968
969 strncpy (tmpfil, m_tmpfil (invo_name), sizeof(tmpfil));
970 interrupted = 0;
971 if (filter)
972 switch (child_id = fork ()) {
973 case NOTOK:
974 advise ("fork", "unable to");
975 return;
976
977 case OK: /* "trust me" */
978 if (freopen (tmpfil, "w", stdout) == NULL) {
979 fprintf (stderr, "unable to create ");
980 perror (tmpfil);
981 _exit (1);
982 }
983 args[0] = r1bindex (mhlproc, '/');
984 i = 1;
985 args[i++] = "-forwall";
986 args[i++] = "-form";
987 args[i++] = filter;
988 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
989 if (is_selected (mp, msgnum))
990 args[i++] = getcpy (m_name (msgnum));
991 args[i] = NULL;
992 mhlsbr (i, args, mhl_action);
993 m_eomsbr ((int (*) ()) 0);
994 fclose (stdout);
995 _exit (0);
996
997 default:
998 if (pidXwait (child_id, NULL))
999 interrupted++;
1000 break;
1001 }
1002 else {
1003 if ((out = fopen (tmpfil, "w")) == NULL) {
1004 advise (tmpfil, "unable to create temporary file");
1005 return;
1006 }
1007
1008 msgcnt = 1;
1009 for (msgnum = mp->lowsel;
1010 msgnum <= mp->hghsel && !interrupted;
1011 msgnum++)
1012 if (is_selected (mp, msgnum)) {
1013 fprintf (out, "\n\n-------");
1014 if (msgnum == mp->lowsel)
1015 fprintf (out, " Forwarded Message%s",
1016 mp->numsel > 1 ? "s" : "");
1017 else
1018 fprintf (out, " Message %d", msgcnt);
1019 fprintf (out, "\n\n");
1020 copy_digest (msgnum, out);
1021 msgcnt++;
1022 }
1023
1024 fprintf (out, "\n\n------- End of Forwarded Message%s\n",
1025 mp->numsel > 1 ? "s" : "");
1026 fclose (out);
1027 }
1028
1029 fflush (stdout);
1030 if (!interrupted)
1031 switch (child_id = fork ()) {
1032 case NOTOK:
1033 advise ("fork", "unable to");
1034 break;
1035
1036 case OK:
1037 closefds (3);
1038 SIGNAL (SIGINT, istat);
1039 SIGNAL (SIGQUIT, qstat);
1040
1041 vec[vecp++] = tmpfil;
1042 vec[vecp] = NULL;
1043
1044 execvp (proc, vec);
1045 fprintf (stderr, "unable to exec ");
1046 perror (proc);
1047 _exit (1);
1048
1049 default:
1050 pidXwait (child_id, NULL);
1051 break;
1052 }
1053
1054 unlink (tmpfil);
1055 }
1056
1057
1058 static char *hlpmsg[] = {
1059 "The %s program emulates many of the commands found in the nmh",
1060 "system. Instead of operating on nmh folders, commands to %s concern",
1061 "a single file.",
1062 "",
1063 "To see the list of commands available, just type a ``?'' followed by",
1064 "the RETURN key. To find out what switches each command takes, type",
1065 "the name of the command followed by ``-help''. To leave %s, use the",
1066 "``quit'' command.",
1067 "",
1068 "Although a lot of nmh commands are found in %s, not all are fully",
1069 "implemented. %s will always recognize all legal switches for a",
1070 "given command though, and will let you know when you ask for an",
1071 "option that it is unable to perform.",
1072 "",
1073 "Running %s is fun, but using nmh from your shell is far superior.",
1074 "After you have familiarized yourself with the nmh style by using %s,",
1075 "you should try using nmh from the shell. You can still use %s for",
1076 "message files that aren't in nmh format, such as BBoard files.",
1077 NULL
1078 };
1079
1080
1081 void
1082 helpcmd (char **args)
1083 {
1084 int i;
1085
1086 for (i = 0; hlpmsg[i]; i++) {
1087 printf (hlpmsg[i], invo_name);
1088 putchar ('\n');
1089 }
1090 }
1091
1092
1093 static struct swit markswit[] = {
1094 #define MADDSW 0
1095 { "add", 0 },
1096 #define MDELSW 1
1097 { "delete", 0 },
1098 #define MLSTSW 2
1099 { "list", 0 },
1100 #define MSEQSW 3
1101 { "sequence name", 0 },
1102 #define MPUBSW 4
1103 { "public", 0 },
1104 #define MNPUBSW 5
1105 { "nopublic", 0 },
1106 #define MZERSW 6
1107 { "zero", 0 },
1108 #define MNZERSW 7
1109 { "nozero", 0 },
1110 #define MHELP 8
1111 { "help", 4 },
1112 #define MDBUGSW 9
1113 { "debug", -5 },
1114 { NULL, 0 }
1115 };
1116
1117
1118 void
1119 markcmd (char **args)
1120 {
1121 int addsw = 0, deletesw = 0, debugsw = 0;
1122 int listsw = 0, zerosw = 0, seqp = 0;
1123 int msgp = 0, msgnum;
1124 char *cp, buf[BUFSIZ];
1125 char *seqs[NUMATTRS + 1], *msgs[MAXARGS];
1126
1127 while ((cp = *args++)) {
1128 if (*cp == '-') {
1129 switch (smatch (++cp, markswit)) {
1130 case AMBIGSW:
1131 ambigsw (cp, markswit);
1132 return;
1133 case UNKWNSW:
1134 fprintf (stderr, "-%s unknown\n", cp);
1135 return;
1136 case MHELP:
1137 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1138 print_help (buf, markswit, 1);
1139 return;
1140
1141 case MADDSW:
1142 addsw++;
1143 deletesw = listsw = 0;
1144 continue;
1145 case MDELSW:
1146 deletesw++;
1147 addsw = listsw = 0;
1148 continue;
1149 case MLSTSW:
1150 listsw++;
1151 addsw = deletesw = 0;
1152 continue;
1153
1154 case MSEQSW:
1155 if (!(cp = *args++) || *cp == '-') {
1156 advise (NULL, "missing argument to %s", args[-2]);
1157 return;
1158 }
1159 if (seqp < NUMATTRS)
1160 seqs[seqp++] = cp;
1161 else {
1162 advise (NULL, "only %d sequences allowed!", NUMATTRS);
1163 return;
1164 }
1165 continue;
1166
1167 case MPUBSW: /* not implemented */
1168 case MNPUBSW:
1169 continue;
1170
1171 case MDBUGSW:
1172 debugsw++;
1173 continue;
1174
1175 case MZERSW:
1176 zerosw++;
1177 continue;
1178 case MNZERSW:
1179 zerosw = 0;
1180 continue;
1181 }
1182 }
1183 if (*cp == '+' || *cp == '@') {
1184 advise (NULL, "sorry, no folders allowed!");
1185 return;
1186 } else {
1187 msgs[msgp++] = cp;
1188 }
1189 }
1190
1191 if (!addsw && !deletesw && !listsw)
1192 if (seqp)
1193 addsw++;
1194 else
1195 if (debugsw)
1196 listsw++;
1197 else {
1198 seqs[seqp++] = "unseen";
1199 deletesw++;
1200 zerosw = 0;
1201 if (!msgp)
1202 msgs[msgp++] = "all";
1203 }
1204
1205 if (!msgp)
1206 msgs[msgp++] = listsw ? "all" :"cur";
1207 for (msgnum = 0; msgnum < msgp; msgnum++)
1208 if (!m_convert (mp, msgs[msgnum]))
1209 return;
1210
1211 if (debugsw) {
1212 printf ("invo_name=%s mypath=%s defpath=%s\n",
1213 invo_name, mypath, defpath);
1214 printf ("ctxpath=%s context flags=%s\n",
1215 ctxpath, snprintb (buf, sizeof(buf), (unsigned) ctxflags, DBITS));
1216 printf ("foldpath=%s flags=%s\n",
1217 mp->foldpath,
1218 snprintb (buf, sizeof(buf), (unsigned) mp->msgflags, FBITS));
1219 printf ("hghmsg=%d lowmsg=%d nummsg=%d curmsg=%d\n",
1220 mp->hghmsg, mp->lowmsg, mp->nummsg, mp->curmsg);
1221 printf ("lowsel=%d hghsel=%d numsel=%d\n",
1222 mp->lowsel, mp->hghsel, mp->numsel);
1223 printf ("lowoff=%d hghoff=%d\n", mp->lowoff, mp->hghoff);
1224 }
1225
1226 if (seqp == 0 && (addsw || deletesw)) {
1227 advise (NULL, "-%s requires at least one -sequence argument",
1228 addsw ? "add" : "delete");
1229 return;
1230 }
1231 seqs[seqp] = NULL;
1232
1233 if (addsw) {
1234 for (seqp = 0; seqs[seqp]; seqp++)
1235 if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
1236 return;
1237 }
1238
1239 if (deletesw) {
1240 for (seqp = 0; seqs[seqp]; seqp++)
1241 if (!seq_delsel (mp, seqs[seqp], 0, zerosw))
1242 return;
1243 }
1244
1245 /* Listing messages in sequences */
1246 if (listsw) {
1247 if (seqp) {
1248 /* list the given sequences */
1249 for (seqp = 0; seqs[seqp]; seqp++)
1250 seq_print (mp, seqs[seqp]);
1251 } else {
1252 /* else list them all */
1253 seq_printall (mp);
1254 }
1255
1256 interrupted = 0;
1257 if (debugsw)
1258 for (msgnum = mp->lowsel;
1259 msgnum <= mp->hghsel && !interrupted;
1260 msgnum++)
1261 if (is_selected (mp, msgnum)) {
1262 printf ("%*d: id=%d top=%d start=%ld stop=%ld %s\n",
1263 DMAXFOLDER,
1264 msgnum,
1265 Msgs[msgnum].m_bboard_id,
1266 Msgs[msgnum].m_top,
1267 (long) Msgs[msgnum].m_start,
1268 (long) Msgs[msgnum].m_stop,
1269 snprintb (buf, sizeof(buf),
1270 (unsigned) mp->msgstats[msgnum - mp->lowoff],
1271 seq_bits (mp)));
1272 if (Msgs[msgnum].m_scanl)
1273 printf ("%s", Msgs[msgnum].m_scanl);
1274 }
1275 }
1276 }
1277
1278
1279 static struct swit mhnswit[] = {
1280 #define MHNAUTOSW 0
1281 { "auto", 0 },
1282 #define MHNNAUTOSW 1
1283 { "noauto", 0 },
1284 #define MHNDEBUGSW 2
1285 { "debug", -5 },
1286 #define MHNEBCDICSW 3
1287 { "ebcdicsafe", 0 },
1288 #define MHNNEBCDICSW 4
1289 { "noebcdicsafe", 0 },
1290 #define MHNFORMSW 5
1291 { "form formfile", 4 },
1292 #define MHNHEADSW 6
1293 { "headers", 0 },
1294 #define MHNNHEADSW 7
1295 { "noheaders", 0 },
1296 #define MHNLISTSW 8
1297 { "list", 0 },
1298 #define MHNNLISTSW 9
1299 { "nolist", 0 },
1300 #define MHNPARTSW 10
1301 { "part number", 0 },
1302 #define MHNSIZESW 11
1303 { "realsize", 0 },
1304 #define MHNNSIZESW 12
1305 { "norealsize", 0 },
1306 #define MHNRFC934SW 13
1307 { "rfc934mode", 0 },
1308 #define MHNNRFC934SW 14
1309 { "norfc934mode", 0 },
1310 #define MHNSERIALSW 15
1311 { "serialonly", 0 },
1312 #define MHNNSERIALSW 16
1313 { "noserialonly", 0 },
1314 #define MHNSHOWSW 17
1315 { "show", 0 },
1316 #define MHNNSHOWSW 18
1317 { "noshow", 0 },
1318 #define MHNSTORESW 19
1319 { "store", 0 },
1320 #define MHNNSTORESW 20
1321 { "nostore", 0 },
1322 #define MHNTYPESW 21
1323 { "type content", 0 },
1324 #define MHNVERBSW 22
1325 { "verbose", 0 },
1326 #define MHNNVERBSW 23
1327 { "noverbose", 0 },
1328 #define MHNHELPSW 24
1329 { "help", 4 },
1330 #define MHNPROGSW 25
1331 { "moreproc program", -4 },
1332 #define MHNNPROGSW 26
1333 { "nomoreproc", -3 },
1334 #define MHNLENSW 27
1335 { "length lines", -4 },
1336 #define MHNWIDSW 28
1337 { "width columns", -4 },
1338 { NULL, 0 }
1339 };
1340
1341
1342 void
1343 mhncmd (char **args)
1344 {
1345 int msgp = 0, vecp = 1;
1346 int msgnum;
1347 char *cp, buf[BUFSIZ];
1348 char *msgs[MAXARGS], *vec[MAXARGS];
1349
1350 if (fmsh) {
1351 forkcmd (args, cmd_name);
1352 return;
1353 }
1354 while ((cp = *args++)) {
1355 if (*cp == '-') {
1356 switch (smatch (++cp, mhnswit)) {
1357 case AMBIGSW:
1358 ambigsw (cp, mhnswit);
1359 return;
1360 case UNKWNSW:
1361 fprintf (stderr, "-%s unknown\n", cp);
1362 return;
1363 case MHNHELPSW:
1364 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1365 print_help (buf, mhnswit, 1);
1366 return;
1367
1368 case MHNAUTOSW:
1369 case MHNNAUTOSW:
1370 case MHNDEBUGSW:
1371 case MHNEBCDICSW:
1372 case MHNNEBCDICSW:
1373 case MHNHEADSW:
1374 case MHNNHEADSW:
1375 case MHNLISTSW:
1376 case MHNNLISTSW:
1377 case MHNSIZESW:
1378 case MHNNSIZESW:
1379 case MHNRFC934SW:
1380 case MHNNRFC934SW:
1381 case MHNSERIALSW:
1382 case MHNNSERIALSW:
1383 case MHNSHOWSW:
1384 case MHNNSHOWSW:
1385 case MHNSTORESW:
1386 case MHNNSTORESW:
1387 case MHNVERBSW:
1388 case MHNNVERBSW:
1389 case MHNNPROGSW:
1390 vec[vecp++] = --cp;
1391 continue;
1392
1393 case MHNFORMSW:
1394 case MHNPARTSW:
1395 case MHNTYPESW:
1396 case MHNPROGSW:
1397 case MHNLENSW:
1398 case MHNWIDSW:
1399 vec[vecp++] = --cp;
1400 if (!(cp = *args++) || *cp == '-') {
1401 advise (NULL, "missing argument to %s", args[-2]);
1402 return;
1403 }
1404 vec[vecp++] = cp;
1405 continue;
1406 }
1407 }
1408 if (*cp == '+' || *cp == '@') {
1409 advise (NULL, "sorry, no folders allowed!");
1410 return;
1411 } else {
1412 msgs[msgp++] = cp;
1413 }
1414 }
1415
1416 vec[0] = cmd_name;
1417 vec[vecp++] = "-file";
1418 vec[vecp] = NULL;
1419 if (!msgp)
1420 msgs[msgp++] = "cur";
1421 for (msgnum = 0; msgnum < msgp; msgnum++)
1422 if (!m_convert (mp, msgs[msgnum]))
1423 return;
1424 seq_setprev (mp);
1425
1426 interrupted = 0;
1427 for (msgnum = mp->lowsel;
1428 msgnum <= mp->hghsel && !interrupted;
1429 msgnum++)
1430 if (is_selected (mp, msgnum))
1431 if (process (msgnum, cmd_name, vecp, vec)) {
1432 unset_selected (mp, msgnum);
1433 mp->numsel--;
1434 }
1435
1436 seq_setcur (mp, mp->hghsel);
1437 }
1438
1439
1440 static struct swit packswit[] = {
1441 #define PAFISW 0
1442 { "file name", 0 },
1443 #define PAHELP 1
1444 { "help", 4 },
1445 { NULL, 0 }
1446 };
1447
1448 static mbx_style = MMDF_FORMAT;
1449
1450 void
1451 packcmd (char **args)
1452 {
1453 int msgp = 0, md, msgnum;
1454 char *cp, *file = NULL;
1455 char buf[BUFSIZ], *msgs[MAXARGS];
1456 struct stat st;
1457
1458 if (fmsh) {
1459 forkcmd (args, cmd_name);
1460 return;
1461 }
1462
1463 while ((cp = *args++)) {
1464 if (*cp == '-')
1465 switch (smatch (++cp, packswit)) {
1466 case AMBIGSW:
1467 ambigsw (cp, packswit);
1468 return;
1469 case UNKWNSW:
1470 fprintf (stderr, "-%s unknown\n", cp);
1471 return;
1472 case PAHELP:
1473 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1474 print_help (buf, packswit, 1);
1475 return;
1476
1477 case PAFISW:
1478 if (!(file = *args++) || *file == '-') {
1479 advise (NULL, "missing argument to %s", args[-2]);
1480 return;
1481 }
1482 continue;
1483 }
1484 if (*cp == '+' || *cp == '@') {
1485 advise (NULL, "sorry, no folders allowed!");
1486 return;
1487 }
1488 else
1489 msgs[msgp++] = cp;
1490 }
1491
1492 if (!file)
1493 file = "./msgbox";
1494 file = path (file, TFILE);
1495 if (stat (file, &st) == NOTOK) {
1496 if (errno != ENOENT) {
1497 advise (file, "error on file");
1498 goto done_pack;
1499 }
1500 md = getanswer (cp = concat ("Create file \"", file, "\"? ", NULL));
1501 free (cp);
1502 if (!md)
1503 goto done_pack;
1504 }
1505
1506 if (!msgp)
1507 msgs[msgp++] = "all";
1508 for (msgnum = 0; msgnum < msgp; msgnum++)
1509 if (!m_convert (mp, msgs[msgnum]))
1510 goto done_pack;
1511 seq_setprev (mp);
1512
1513 if ((md = mbx_open (file, mbx_style, getuid (), getgid (), m_gmprot ())) == NOTOK) {
1514 advise (file, "unable to open");
1515 goto done_pack;
1516 }
1517 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1518 if (is_selected (mp, msgnum))
1519 if (pack (file, md, msgnum) == NOTOK)
1520 break;
1521 mbx_close (file, md);
1522
1523 if (mp->hghsel != mp->curmsg)
1524 seq_setcur (mp, mp->lowsel);
1525
1526 done_pack: ;
1527 free (file);
1528 }
1529
1530
1531 int
1532 pack (char *mailbox, int md, int msgnum)
1533 {
1534 register FILE *zp;
1535
1536 if (Msgs[msgnum].m_bboard_id == 0)
1537 readid (msgnum);
1538
1539 zp = msh_ready (msgnum, 1);
1540 return mbx_write (mailbox, md, zp, Msgs[msgnum].m_bboard_id,
1541 0L, ftell (zp), Msgs[msgnum].m_stop, 1, 1);
1542 }
1543
1544
1545 int
1546 packhak (char **args)
1547 {
1548 int result;
1549 char *cp, *file = NULL;
1550
1551 while ((cp = *args++)) {
1552 if (*cp == '-')
1553 switch (smatch (++cp, packswit)) {
1554 case AMBIGSW:
1555 case UNKWNSW:
1556 case PAHELP:
1557 return NOTOK;
1558
1559 case PAFISW:
1560 if (!(file = *args++) || *file == '-')
1561 return NOTOK;
1562 continue;
1563 }
1564 if (*cp == '+' || *cp == '@')
1565 return NOTOK;
1566 }
1567
1568 file = path (file ? file : "./msgbox", TFILE);
1569 result = access (file, F_OK) == NOTOK ? OK : NOTOK;
1570 free (file);
1571
1572 return result;
1573 }
1574
1575
1576 static struct swit pickswit[] = {
1577 #define PIANSW 0
1578 { "and", 0 },
1579 #define PIORSW 1
1580 { "or", 0 },
1581 #define PINTSW 2
1582 { "not", 0 },
1583 #define PILBSW 3
1584 { "lbrace", 0 },
1585 #define PIRBSW 4
1586 { "rbrace", 0 },
1587 #define PICCSW 5
1588 { "cc pattern", 0 },
1589 #define PIDASW 6
1590 { "date pattern", 0 },
1591 #define PIFRSW 7
1592 { "from pattern", 0 },
1593 #define PISESW 8
1594 { "search pattern", 0 },
1595 #define PISUSW 9
1596 { "subject pattern", 0 },
1597 #define PITOSW 10
1598 { "to pattern", 0 },
1599 #define PIOTSW 11
1600 { "-othercomponent pattern", 15 },
1601 #define PIAFSW 12
1602 { "after date", 0 },
1603 #define PIBFSW 13
1604 { "before date", 0 },
1605 #define PIDFSW 14
1606 { "datefield field", 5 },
1607 #define PISQSW 15
1608 { "sequence name", 0 },
1609 #define PIPUSW 16
1610 { "public", 0 },
1611 #define PINPUSW 17
1612 { "nopublic", 0 },
1613 #define PIZRSW 18
1614 { "zero", 0 },
1615 #define PINZRSW 19
1616 { "nozero", 0 },
1617 #define PILISW 20
1618 { "list", 0 },
1619 #define PINLISW 21
1620 { "nolist", 0 },
1621 #define PIHELP 22
1622 { "help", 4 },
1623 { NULL, 0 }
1624 };
1625
1626
1627 void
1628 pickcmd (char **args)
1629 {
1630 int zerosw = 1, msgp = 0, seqp = 0;
1631 int vecp = 0, hi, lo, msgnum;
1632 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
1633 char *seqs[NUMATTRS], *vec[MAXARGS];
1634 register FILE *zp;
1635
1636 while ((cp = *args++)) {
1637 if (*cp == '-') {
1638 if (*++cp == '-') {
1639 vec[vecp++] = --cp;
1640 goto pattern;
1641 }
1642 switch (smatch (cp, pickswit)) {
1643 case AMBIGSW:
1644 ambigsw (cp, pickswit);
1645 return;
1646 case UNKWNSW:
1647 fprintf (stderr, "-%s unknown\n", cp);
1648 return;
1649 case PIHELP:
1650 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1651 print_help (buf, pickswit, 1);
1652 return;
1653
1654 case PICCSW:
1655 case PIDASW:
1656 case PIFRSW:
1657 case PISUSW:
1658 case PITOSW:
1659 case PIDFSW:
1660 case PIAFSW:
1661 case PIBFSW:
1662 case PISESW:
1663 vec[vecp++] = --cp;
1664 pattern: ;
1665 if (!(cp = *args++)) {/* allow -xyz arguments */
1666 advise (NULL, "missing argument to %s", args[-2]);
1667 return;
1668 }
1669 vec[vecp++] = cp;
1670 continue;
1671 case PIOTSW:
1672 advise (NULL, "internal error!");
1673 return;
1674 case PIANSW:
1675 case PIORSW:
1676 case PINTSW:
1677 case PILBSW:
1678 case PIRBSW:
1679 vec[vecp++] = --cp;
1680 continue;
1681
1682 case PISQSW:
1683 if (!(cp = *args++) || *cp == '-') {
1684 advise (NULL, "missing argument to %s", args[-2]);
1685 return;
1686 }
1687 if (seqp < NUMATTRS)
1688 seqs[seqp++] = cp;
1689 else {
1690 advise (NULL, "only %d sequences allowed!", NUMATTRS);
1691 return;
1692 }
1693 continue;
1694 case PIZRSW:
1695 zerosw++;
1696 continue;
1697 case PINZRSW:
1698 zerosw = 0;
1699 continue;
1700
1701 case PIPUSW: /* not implemented */
1702 case PINPUSW:
1703 case PILISW:
1704 case PINLISW:
1705 continue;
1706 }
1707 }
1708 if (*cp == '+' || *cp == '@') {
1709 advise (NULL, "sorry, no folders allowed!");
1710 return;
1711 }
1712 else
1713 msgs[msgp++] = cp;
1714 }
1715 vec[vecp] = NULL;
1716
1717 if (!msgp)
1718 msgs[msgp++] = "all";
1719 for (msgnum = 0; msgnum < msgp; msgnum++)
1720 if (!m_convert (mp, msgs[msgnum]))
1721 return;
1722 seq_setprev (mp);
1723
1724 interrupted = 0;
1725 if (!pcompile (vec, NULL))
1726 return;
1727
1728 lo = mp->lowsel;
1729 hi = mp->hghsel;
1730
1731 for (msgnum = mp->lowsel;
1732 msgnum <= mp->hghsel && !interrupted;
1733 msgnum++)
1734 if (is_selected (mp, msgnum)) {
1735 zp = msh_ready (msgnum, 1);
1736 if (pmatches (zp, msgnum, fmsh ? 0L : Msgs[msgnum].m_start,
1737 fmsh ? 0L : Msgs[msgnum].m_stop)) {
1738 if (msgnum < lo)
1739 lo = msgnum;
1740 if (msgnum > hi)
1741 hi = msgnum;
1742 }
1743 else {
1744 unset_selected (mp, msgnum);
1745 mp->numsel--;
1746 }
1747 }
1748
1749 if (interrupted)
1750 return;
1751
1752 mp->lowsel = lo;
1753 mp->hghsel = hi;
1754
1755 if (mp->numsel <= 0) {
1756 advise (NULL, "no messages match specification");
1757 return;
1758 }
1759
1760 seqs[seqp] = NULL;
1761 for (seqp = 0; seqs[seqp]; seqp++)
1762 if (!seq_addsel (mp, seqs[seqp], 0, zerosw))
1763 return;
1764
1765 printf ("%d hit%s\n", mp->numsel, mp->numsel == 1 ? "" : "s");
1766 }
1767
1768
1769 static struct swit replswit[] = {
1770 #define REANSW 0
1771 { "annotate", 0 },
1772 #define RENANSW 1
1773 { "noannotate", 0 },
1774 #define RECCSW 2
1775 { "cc type", 0 },
1776 #define RENCCSW 3
1777 { "nocc type", 0 },
1778 #define REDFSW 4
1779 { "draftfolder +folder", 0 },
1780 #define REDMSW 5
1781 { "draftmessage msg", 0 },
1782 #define RENDFSW 6
1783 { "nodraftfolder", 0 },
1784 #define REEDTSW 7
1785 { "editor editor", 0 },
1786 #define RENEDSW 8
1787 { "noedit", 0 },
1788 #define REFCCSW 9
1789 { "fcc +folder", 0 },
1790 #define REFLTSW 10
1791 { "filter filterfile", 0 },
1792 #define REFRMSW 11
1793 { "form formfile", 0 },
1794 #define REINSW 12
1795 { "inplace", 0 },
1796 #define RENINSW 13
1797 { "noinplace", 0 },
1798 #define REQUSW 14
1799 { "query", 0 },
1800 #define RENQUSW 15
1801 { "noquery", 0 },
1802 #define REWHTSW 16
1803 { "whatnowproc program", 0 },
1804 #define RENWTSW 17
1805 { "nowhatnow", 0 },
1806 #define REWIDSW 19
1807 { "width columns", 0 },
1808 #define REHELP 20
1809 { "help", 4 },
1810 { NULL, 0 }
1811 };
1812
1813
1814 void
1815 replcmd (char **args)
1816 {
1817 int vecp = 1;
1818 char *cp, *msg = NULL;
1819 char buf[BUFSIZ], *vec[MAXARGS];
1820
1821 if (fmsh) {
1822 forkcmd (args, cmd_name);
1823 return;
1824 }
1825
1826 while ((cp = *args++)) {
1827 if (*cp == '-')
1828 switch (smatch (++cp, replswit)) {
1829 case AMBIGSW:
1830 ambigsw (cp, replswit);
1831 return;
1832 case UNKWNSW:
1833 fprintf (stderr, "-%s unknown\n", cp);
1834 return;
1835 case REHELP:
1836 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1837 print_help (buf, replswit, 1);
1838 return;
1839
1840 case REANSW: /* not implemented */
1841 case RENANSW:
1842 case REINSW:
1843 case RENINSW:
1844 continue;
1845
1846 case REQUSW:
1847 case RENQUSW:
1848 case RENDFSW:
1849 case RENEDSW:
1850 case RENWTSW:
1851 vec[vecp++] = --cp;
1852 continue;
1853
1854 case RECCSW:
1855 case RENCCSW:
1856 case REEDTSW:
1857 case REFCCSW:
1858 case REFLTSW:
1859 case REFRMSW:
1860 case REWIDSW:
1861 case REDFSW:
1862 case REDMSW:
1863 case REWHTSW:
1864 vec[vecp++] = --cp;
1865 if (!(cp = *args++) || *cp == '-') {
1866 advise (NULL, "missing argument to %s", args[-2]);
1867 return;
1868 }
1869 vec[vecp++] = cp;
1870 continue;
1871 }
1872 if (*cp == '+' || *cp == '@') {
1873 advise (NULL, "sorry, no folders allowed!");
1874 return;
1875 }
1876 else
1877 if (msg) {
1878 advise (NULL, "only one message at a time!");
1879 return;
1880 }
1881 else
1882 msg = cp;
1883 }
1884
1885 vec[0] = cmd_name;
1886 vec[vecp++] = "-file";
1887 vec[vecp] = NULL;
1888 if (!msg)
1889 msg = "cur";
1890 if (!m_convert (mp, msg))
1891 return;
1892 seq_setprev (mp);
1893
1894 if (mp->numsel > 1) {
1895 advise (NULL, "only one message at a time!");
1896 return;
1897 }
1898 process (mp->hghsel, cmd_name, vecp, vec);
1899 seq_setcur (mp, mp->hghsel);
1900 }
1901
1902
1903 static struct swit rmmswit[] = {
1904 #define RMHELP 0
1905 { "help", 4 },
1906 { NULL, 0 }
1907 };
1908
1909
1910 void
1911 rmmcmd (char **args)
1912 {
1913 int msgp = 0, msgnum;
1914 char *cp, buf[BUFSIZ], *msgs[MAXARGS];
1915
1916 while ((cp = *args++)) {
1917 if (*cp == '-')
1918 switch (smatch (++cp, rmmswit)) {
1919 case AMBIGSW:
1920 ambigsw (cp, rmmswit);
1921 return;
1922 case UNKWNSW:
1923 fprintf (stderr, "-%s unknown\n", cp);
1924 return;
1925 case RMHELP:
1926 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
1927 print_help (buf, rmmswit, 1);
1928 return;
1929 }
1930 if (*cp == '+' || *cp == '@') {
1931 advise (NULL, "sorry, no folders allowed!");
1932 return;
1933 }
1934 else
1935 msgs[msgp++] = cp;
1936 }
1937
1938 if (!msgp)
1939 msgs[msgp++] = "cur";
1940 for (msgnum = 0; msgnum < msgp; msgnum++)
1941 if (!m_convert (mp, msgs[msgnum]))
1942 return;
1943 seq_setprev (mp);
1944
1945 rmm ();
1946 }
1947
1948
1949 static void
1950 rmm (void)
1951 {
1952 register int msgnum, vecp;
1953 register char *cp;
1954 char buffer[BUFSIZ], *vec[MAXARGS];
1955
1956 if (fmsh) {
1957 if (rmmproc) {
1958 if (mp->numsel > MAXARGS - 1) {
1959 advise (NULL, "more than %d messages for %s exec",
1960 MAXARGS - 1, rmmproc);
1961 return;
1962 }
1963 vecp = 0;
1964 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1965 if (is_selected (mp, msgnum))
1966 vec[vecp++] = getcpy (m_name (msgnum));
1967 vec[vecp] = NULL;
1968 forkcmd (vec, rmmproc);
1969 for (vecp = 0; vec[vecp]; vecp++)
1970 free (vec[vecp]);
1971 }
1972 else
1973 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1974 if (is_selected (mp, msgnum)) {
1975 strncpy (buffer, m_backup (cp = m_name (msgnum)), sizeof(buffer));
1976 if (rename (cp, buffer) == NOTOK)
1977 admonish (buffer, "unable to rename %s to", cp);
1978 }
1979 }
1980
1981 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
1982 if (is_selected (mp, msgnum)) {
1983 set_deleted (mp, msgnum);
1984 unset_exists (mp, msgnum);
1985 #ifdef MPOP
1986 #ifdef BPOP
1987 if (pmsh && pop_dele (msgnum) != OK)
1988 fprintf (stderr, "%s", response);
1989 #endif
1990 #endif /* MPOP */
1991 }
1992
1993 if ((mp->nummsg -= mp->numsel) <= 0) {
1994 if (fmsh)
1995 admonish (NULL, "no messages remaining in +%s", fmsh);
1996 else
1997 admonish (NULL, "no messages remaining in %s", mp->foldpath);
1998 mp->lowmsg = mp->hghmsg = mp->nummsg = 0;
1999 }
2000 if (mp->lowsel == mp->lowmsg) {
2001 for (msgnum = mp->lowmsg + 1; msgnum <= mp->hghmsg; msgnum++)
2002 if (does_exist (mp, msgnum))
2003 break;
2004 mp->lowmsg = msgnum;
2005 }
2006 if (mp->hghsel == mp->hghmsg) {
2007 for (msgnum = mp->hghmsg - 1; msgnum >= mp->lowmsg; msgnum--)
2008 if (does_exist (mp, msgnum))
2009 break;
2010 mp->hghmsg = msgnum;
2011 }
2012
2013 mp->msgflags |= MODIFIED;
2014 modified++;
2015 }
2016
2017
2018 static struct swit scanswit[] = {
2019 #define SCCLR 0
2020 { "clear", 0 },
2021 #define SCNCLR 1
2022 { "noclear", 0 },
2023 #define SCFORM 2
2024 { "form formatfile", 0 },
2025 #define SCFMT 3
2026 { "format string", 5 },
2027 #define SCHEAD 4
2028 { "header", 0 },
2029 #define SCNHEAD 5
2030 { "noheader", 0 },
2031 #define SCWID 6
2032 { "width columns", 0 },
2033 #define SCHELP 7
2034 { "help", 4 },
2035 { NULL, 0 }
2036 };
2037
2038
2039 void
2040 scancmd (char **args)
2041 {
2042 #define equiv(a,b) (a ? b && !strcmp (a, b) : !b)
2043
2044 int clearsw = 0, headersw = 0, width = 0, msgp = 0;
2045 int msgnum, optim, state;
2046 char *cp, *form = NULL, *format = NULL;
2047 char buf[BUFSIZ], *nfs, *msgs[MAXARGS];
2048 register FILE *zp;
2049 #ifdef MPOP
2050 #ifdef BPOP
2051 static int p_optim = 0;
2052 #endif
2053 #endif /* MPOP */
2054 static int s_optim = 0;
2055 static char *s_form = NULL, *s_format = NULL;
2056
2057 while ((cp = *args++)) {
2058 if (*cp == '-')
2059 switch (smatch (++cp, scanswit)) {
2060 case AMBIGSW:
2061 ambigsw (cp, scanswit);
2062 return;
2063 case UNKWNSW:
2064 fprintf (stderr, "-%s unknown\n", cp);
2065 return;
2066 case SCHELP:
2067 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
2068 print_help (buf, scanswit, 1);
2069 return;
2070
2071 case SCCLR:
2072 clearsw++;
2073 continue;
2074 case SCNCLR:
2075 clearsw = 0;
2076 continue;
2077 case SCHEAD:
2078 headersw++;
2079 continue;
2080 case SCNHEAD:
2081 headersw = 0;
2082 continue;
2083 case SCFORM:
2084 if (!(form = *args++) || *form == '-') {
2085 advise (NULL, "missing argument to %s", args[-2]);
2086 return;
2087 }
2088 format = NULL;
2089 continue;
2090 case SCFMT:
2091 if (!(format = *args++) || *format == '-') {
2092 advise (NULL, "missing argument to %s", args[-2]);
2093 return;
2094 }
2095 form = NULL;
2096 continue;
2097 case SCWID:
2098 if (!(cp = *args++) || *cp == '-') {
2099 advise (NULL, "missing argument to %s", args[-2]);
2100 return;
2101 }
2102 width = atoi (cp);
2103 continue;
2104 }
2105 if (*cp == '+' || *cp == '@') {
2106 advise (NULL, "sorry, no folders allowed!");
2107 return;
2108 }
2109 else
2110 msgs[msgp++] = cp;
2111 }
2112
2113 if (!msgp)
2114 msgs[msgp++] = "all";
2115 for (msgnum = 0; msgnum < msgp; msgnum++)
2116 if (!m_convert (mp, msgs[msgnum]))
2117 return;
2118 seq_setprev (mp);
2119
2120 /* Get new format string */
2121 nfs = new_fs (form, format, FORMAT);
2122
2123 /* force scansbr to (re)compile format */
2124 if (scanl) {
2125 free (scanl);
2126 scanl = NULL;
2127 }
2128
2129 if (s_optim == 0) {
2130 s_optim = optim = 1;
2131 s_form = form ? getcpy (form) : NULL;
2132 s_format = format ? getcpy (format) : NULL;
2133
2134 #ifdef MPOP
2135 #ifdef BPOP
2136 if (pmsh) {
2137 int i;
2138 char *dp, *ep, *fp;
2139
2140 if (width == 0)
2141 width = sc_width ();
2142
2143 for (dp = nfs, i = 0; *dp; dp++, i++)
2144 if (*dp == '\\' || *dp == '"' || *dp == '\n')
2145 i++;
2146 i++;
2147 if ((ep = malloc ((unsigned) i)) == NULL)
2148 adios (NULL, "out of memory");
2149 for (dp = nfs, fp = ep; *dp; dp++) {
2150 if (*dp == '\n') {
2151 *fp++ = '\\', *fp++ = 'n';
2152 continue;
2153 }
2154 if (*dp == '"' || *dp == '\\')
2155 *fp++ = '\\';
2156 *fp++ = *dp;
2157 }
2158 *fp = NULL;
2159
2160 if (pop_command ("XTND SCAN %d \"%s\"", width, ep) == OK)
2161 p_optim = 1;
2162
2163 free (ep);
2164 }
2165 #endif
2166 #endif /* MPOP */
2167 }
2168 else
2169 optim = equiv (s_form, form) && equiv (s_format, format);
2170
2171 #ifdef MPOP
2172 #ifdef BPOP
2173 if (p_optim && optim) {
2174 for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++)
2175 if (!is_selected(mp, msgnum) || Msgs[msgnum].m_scanl)
2176 break;
2177 if (msgnum > mp->hghmsg && pop_command ("LIST") == OK) {
2178 fprintf (stderr, "Stand-by...");
2179 fflush (stderr);
2180
2181 for (;;) {
2182 int size;
2183
2184 switch (pop_multiline ()) {
2185 case NOTOK:
2186 fprintf (stderr, "%s", response);
2187 /* and fall... */
2188 case DONE:
2189 fprintf (stderr,"\n");
2190 break;
2191
2192 case OK:
2193 if (sscanf (response, "%d %d", &msgnum, &size) == 2
2194 && mp->lowmsg <= msgnum
2195 && msgnum <= mp->hghmsg
2196 && (cp = strchr(response, '#'))
2197 && *++cp)
2198 Msgs[msgnum].m_scanl = concat (cp, "\n", NULL);
2199 continue;
2200 }
2201 break;
2202 }
2203 }
2204 }
2205 #endif
2206 #endif /* MPOP */
2207
2208 interrupted = 0;
2209 for (msgnum = mp->lowsel;
2210 msgnum <= mp->hghsel && !interrupted;
2211 msgnum++)
2212 if (is_selected (mp, msgnum)) {
2213 if (optim && Msgs[msgnum].m_scanl)
2214 printf ("%s", Msgs[msgnum].m_scanl);
2215 else {
2216 #ifdef MPOP
2217 #ifdef BPOP
2218 if (p_optim
2219 && optim
2220 && is_virtual (mp, msgnum)
2221 && pop_command ("LIST %d", msgnum) == OK
2222 && (cp = strchr(response, '#'))
2223 && *++cp) {
2224 Msgs[msgnum].m_scanl = concat (cp, "\n", NULL);
2225 printf ("%s", Msgs[msgnum].m_scanl);
2226 continue;
2227 }
2228 #endif
2229 #endif /* MPOP */
2230
2231 zp = msh_ready (msgnum, 0);
2232 switch (state = scan (zp, msgnum, 0, nfs, width,
2233 msgnum == mp->curmsg,
2234 is_unseen (mp, msgnum),
2235 headersw ? (fmsh ? fmsh : mp->foldpath) : NULL,
2236 fmsh ? 0L : (long) (Msgs[msgnum].m_stop - Msgs[msgnum].m_start),
2237 1)) {
2238 case SCNMSG:
2239 case SCNENC:
2240 case SCNERR:
2241 if (optim)
2242 Msgs[msgnum].m_scanl = getcpy (scanl);
2243 break;
2244
2245 default:
2246 advise (NULL, "scan() botch (%d)", state);
2247 return;
2248
2249 case SCNEOF:
2250 printf ("%*d empty\n", DMAXFOLDER, msgnum);
2251 break;
2252 }
2253 }
2254 headersw = 0;
2255 }
2256
2257 if (clearsw)
2258 clear_screen ();
2259 }
2260
2261
2262 static struct swit showswit[] = {
2263 #define SHDRAFT 0
2264 { "draft", 5 },
2265 #define SHFORM 1
2266 { "form formfile", 4 },
2267 #define SHPROG 2
2268 { "moreproc program", 4 },
2269 #define SHNPROG 3
2270 { "nomoreproc", 3 },
2271 #define SHLEN 4
2272 { "length lines", 4 },
2273 #define SHWID 5
2274 { "width columns", 4 },
2275 #define SHSHOW 6
2276 { "showproc program", 4 },
2277 #define SHNSHOW 7
2278 { "noshowproc", 3 },
2279 #define SHHEAD 8
2280 { "header", 4 },
2281 #define SHNHEAD 9
2282 { "noheader", 3 },
2283 #define SHHELP 10
2284 { "help", 4 },
2285 { NULL, 0 }
2286 };
2287
2288
2289 void
2290 showcmd (char **args)
2291 {
2292 int headersw = 1, nshow = 0, msgp = 0, vecp = 1;
2293 int mhl = 0, seqnum = -1, mode = 0, i, msgnum;
2294 char *cp, *proc = showproc, buf[BUFSIZ];
2295 char *msgs[MAXARGS], *vec[MAXARGS];
2296
2297 if (!strcasecmp (cmd_name, "next"))
2298 mode = 1;
2299 else
2300 if (!strcasecmp (cmd_name, "prev"))
2301 mode = -1;
2302 while ((cp = *args++)) {
2303 if (*cp == '-')
2304 switch (i = smatch (++cp, showswit)) {
2305 case AMBIGSW:
2306 ambigsw (cp, showswit);
2307 return;
2308 case UNKWNSW:
2309 case SHNPROG:
2310 vec[vecp++] = --cp;
2311 continue;
2312 case SHHELP:
2313 snprintf (buf, sizeof(buf), "%s %s[switches] [switches for showproc]",
2314 cmd_name, mode ? NULL : "[msgs] ");
2315 print_help (buf, showswit, 1);
2316 return;
2317
2318 case SHFORM:
2319 case SHPROG:
2320 case SHLEN:
2321 case SHWID:
2322 vec[vecp++] = --cp;
2323 if (!(cp = *args++) || *cp == '-') {
2324 advise (NULL, "missing argument to %s", args[-2]);
2325 return;
2326 }
2327 vec[vecp++] = cp;
2328 continue;
2329 case SHHEAD:
2330 headersw++;
2331 continue;
2332 case SHNHEAD:
2333 headersw = 0;
2334 continue;
2335 case SHSHOW:
2336 if (!(proc = *args++) || *proc == '-') {
2337 advise (NULL, "missing argument to %s", args[-2]);
2338 return;
2339 }
2340 nshow = 0;
2341 continue;
2342 case SHNSHOW:
2343 nshow++;
2344 continue;
2345
2346 case SHDRAFT:
2347 advise (NULL, "sorry, -%s not allowed!", showswit[i].sw);
2348 return;
2349 }
2350 if (*cp == '+' || *cp == '@') {
2351 advise (NULL, "sorry, no folders allowed!");
2352 return;
2353 }
2354 else
2355 if (mode) {
2356 fprintf (stderr,
2357 "usage: %s [switches] [switches for showproc]\n",
2358 cmd_name);
2359 return;
2360 }
2361 else
2362 msgs[msgp++] = cp;
2363 }
2364 vec[vecp] = NULL;
2365
2366 if (!msgp)
2367 msgs[msgp++] = mode > 0 ? "next" : mode < 0 ? "prev" : "cur";
2368 for (msgnum = 0; msgnum < msgp; msgnum++)
2369 if (!m_convert (mp, msgs[msgnum]))
2370 return;
2371 seq_setprev (mp);
2372
2373 if (!nshow && !getenv ("NOMHNPROC"))
2374 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
2375 if (is_selected (mp, msgnum) && is_nontext (msgnum)) {
2376 proc = showmimeproc;
2377 vec[vecp++] = "-show";
2378 vec[vecp++] = "-file";
2379 vec[vecp] = NULL;
2380 goto finish;
2381 }
2382
2383 if (nshow)
2384 proc = catproc;
2385 else
2386 if (strcmp (showproc, "mhl") == 0) {
2387 proc = mhlproc;
2388 mhl++;
2389 }
2390
2391 finish: ;
2392 seqnum = seq_getnum (mp, "unseen");
2393 vec[0] = r1bindex (proc, '/');
2394 if (mhl) {
2395 msgp = vecp;
2396 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++)
2397 if (is_selected (mp, msgnum)) {
2398 vec[vecp++] = getcpy (m_name (msgnum));
2399 if (seqnum != -1)
2400 seq_delmsg (mp, "unseen", msgnum);
2401 }
2402 vec[vecp] = NULL;
2403 if (mp->numsel == 1 && headersw)
2404 show (mp->lowsel);
2405 mhlsbr (vecp, vec, mhl_action);
2406 m_eomsbr ((int (*)()) 0);
2407 while (msgp < vecp)
2408 free (vec[msgp++]);
2409 } else {
2410 interrupted = 0;
2411 for (msgnum = mp->lowsel;
2412 msgnum <= mp->hghsel && !interrupted;
2413 msgnum++)
2414 if (is_selected (mp, msgnum)) {
2415 switch (ask (msgnum)) {
2416 case NOTOK: /* QUIT */
2417 break;
2418
2419 case OK: /* INTR */
2420 continue;
2421
2422 default:
2423 if (mp->numsel == 1 && headersw)
2424 show (msgnum);
2425 if (nshow)
2426 copy_message (msgnum, stdout);
2427 else
2428 process (msgnum, proc, vecp, vec);
2429
2430 if (seqnum != -1)
2431 seq_delmsg (mp, "unseen", msgnum);
2432 continue;
2433 }
2434 break;
2435 }
2436 }
2437
2438 seq_setcur (mp, mp->hghsel);
2439 }
2440
2441
2442 static void
2443 show (int msgnum)
2444 {
2445 if (Msgs[msgnum].m_bboard_id == 0)
2446 readid (msgnum);
2447
2448 printf ("(Message %d", msgnum);
2449 if (Msgs[msgnum].m_bboard_id > 0)
2450 printf (", %s: %d", BBoard_ID, Msgs[msgnum].m_bboard_id);
2451 printf (")\n");
2452 }
2453
2454
2455
2456 static int
2457 eom_action (int c)
2458 {
2459 return (ftell (mhlfp) >= Msgs[mhlnum].m_stop);
2460 }
2461
2462
2463 static FILE *
2464 mhl_action (char *name)
2465 {
2466 int msgnum;
2467
2468 if ((msgnum = m_atoi (name)) < mp->lowmsg
2469 || msgnum > mp->hghmsg
2470 || !does_exist (mp, msgnum))
2471 return NULL;
2472 mhlnum = msgnum;
2473
2474 mhlfp = msh_ready (msgnum, 1);
2475 if (!fmsh)
2476 m_eomsbr (eom_action);
2477
2478 return mhlfp;
2479 }
2480
2481
2482
2483 static int
2484 ask (int msgnum)
2485 {
2486 char buf[BUFSIZ];
2487
2488 if (mp->numsel == 1 || !interactive || redirected)
2489 return DONE;
2490
2491 if (SOprintf ("Press <return> to list \"%d\"...", msgnum)) {
2492 if (mp->lowsel != msgnum)
2493 printf ("\n\n\n");
2494 printf ("Press <return> to list \"%d\"...", msgnum);
2495 }
2496 fflush (stdout);
2497 buf[0] = 0;
2498
2499 #ifndef BSD42
2500 read (fileno (stdout), buf, sizeof buf);
2501 #else /* BSD42 */
2502 switch (setjmp (sigenv)) {
2503 case OK:
2504 should_intr = 1;
2505 read (fileno (stdout), buf, sizeof buf);/* fall... */
2506
2507 default:
2508 should_intr = 0;
2509 break;
2510 }
2511 #endif /* BSD42 */
2512
2513 if (strchr(buf, '\n') == NULL)
2514 putchar ('\n');
2515
2516 if (told_to_quit) {
2517 told_to_quit = interrupted = 0;
2518 return NOTOK;
2519 }
2520 if (interrupted) {
2521 interrupted = 0;
2522 return OK;
2523 }
2524
2525 return DONE;
2526 }
2527
2528
2529 #include <h/mime.h>
2530
2531 static int
2532 is_nontext (int msgnum)
2533 {
2534 int result, state;
2535 char *bp, *cp, *dp;
2536 char buf[BUFSIZ], name[NAMESZ];
2537 FILE *fp;
2538
2539 if (Msgs[msgnum].m_flags & MHNCHK)
2540 return (Msgs[msgnum].m_flags & MHNYES);
2541 Msgs[msgnum].m_flags |= MHNCHK;
2542
2543 fp = msh_ready (msgnum, 1);
2544
2545 for (state = FLD;;)
2546 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
2547 case FLD:
2548 case FLDPLUS:
2549 case FLDEOF:
2550 /*
2551 * Check Content-Type field
2552 */
2553 if (!strcasecmp (name, TYPE_FIELD)) {
2554 int passno;
2555 char c;
2556
2557 cp = add (buf, NULL);
2558 while (state == FLDPLUS) {
2559 state = m_getfld (state, name, buf, sizeof buf, fp);
2560 cp = add (buf, cp);
2561 }
2562 bp = cp;
2563 passno = 1;
2564
2565 again:
2566 for (; isspace (*bp); bp++)
2567 continue;
2568 if (*bp == '(') {
2569 int i;
2570
2571 for (bp++, i = 0;;) {
2572 switch (*bp++) {
2573 case '\0':
2574 invalid:
2575 result = 0;
2576 goto out;
2577 case '\\':
2578 if (*bp++ == '\0')
2579 goto invalid;
2580 continue;
2581 case '(':
2582 i++;
2583 /* and fall... */
2584 default:
2585 continue;
2586 case ')':
2587 if (--i < 0)
2588 break;
2589 continue;
2590 }
2591 break;
2592 }
2593 }
2594 if (passno == 2) {
2595 if (*bp != '/')
2596 goto invalid;
2597 bp++;
2598 passno = 3;
2599 goto again;
2600 }
2601 for (dp = bp; istoken (*dp); dp++)
2602 continue;
2603 c = *dp;
2604 *dp = '\0';
2605 if (!*bp)
2606 goto invalid;
2607 if (passno > 1) {
2608 if ((result = (strcasecmp (bp, "plain") != 0)))
2609 goto out;
2610 *dp = c;
2611 for (dp++; isspace (*dp); dp++)
2612 continue;
2613 if (*dp) {
2614 if ((result = !uprf (dp, "charset")))
2615 goto out;
2616 dp += sizeof "charset" - 1;
2617 while (isspace (*dp))
2618 dp++;
2619 if (*dp++ != '=')
2620 goto invalid;
2621 while (isspace (*dp))
2622 dp++;
2623 if (*dp == '"') {
2624 if ((bp = strchr(++dp, '"')))
2625 *bp = '\0';
2626 } else {
2627 for (bp = dp; *bp; bp++)
2628 if (isspace (*bp)) {
2629 *bp = '\0';
2630 break;
2631 }
2632 }
2633 } else {
2634 /* Default character set */
2635 dp = "US-ASCII";
2636 }
2637 /* Check the character set */
2638 result = !check_charset (dp, strlen (dp));
2639 } else {
2640 if (!(result = (strcasecmp (bp, "text") != 0))) {
2641 *dp = c;
2642 bp = dp;
2643 passno = 2;
2644 goto again;
2645 }
2646 }
2647 out:
2648 free (cp);
2649 if (result) {
2650 Msgs[msgnum].m_flags |= MHNYES;
2651 return result;
2652 }
2653 break;
2654 }
2655
2656 /*
2657 * Check Content-Transfer-Encoding field
2658 */
2659 if (!strcasecmp (name, ENCODING_FIELD)) {
2660 cp = add (buf, NULL);
2661 while (state == FLDPLUS) {
2662 state = m_getfld (state, name, buf, sizeof buf, fp);
2663 cp = add (buf, cp);
2664 }
2665 for (bp = cp; isspace (*bp); bp++)
2666 continue;
2667 for (dp = bp; istoken (*dp); dp++)
2668 continue;
2669 *dp = '\0';
2670 result = (strcasecmp (bp, "7bit")
2671 && strcasecmp (bp, "8bit")
2672 && strcasecmp (bp, "binary"));
2673
2674 free (cp);
2675 if (result) {
2676 Msgs[msgnum].m_flags |= MHNYES;
2677 return result;
2678 }
2679 break;
2680 }
2681
2682 /*
2683 * Just skip the rest of this header
2684 * field and go to next one.
2685 */
2686 while (state == FLDPLUS)
2687 state = m_getfld (state, name, buf, sizeof(buf), fp);
2688 break;
2689
2690 /*
2691 * We've passed the message header,
2692 * so message is just text.
2693 */
2694 default:
2695 return 0;
2696 }
2697 }
2698
2699
2700 static struct swit sortswit[] = {
2701 #define SODATE 0
2702 { "datefield field", 0 },
2703 #define SOSUBJ 1
2704 { "textfield field", 0 },
2705 #define SONSUBJ 2
2706 { "notextfield", 0 },
2707 #define SOLIMT 3
2708 { "limit days", 0 },
2709 #define SONLIMT 4
2710 { "nolimit", 0 },
2711 #define SOVERB 5
2712 { "verbose", 0 },
2713 #define SONVERB 6
2714 { "noverbose", 0 },
2715 #define SOHELP 7
2716 { "help", 4 },
2717 { NULL, 0 }
2718 };
2719
2720
2721 void
2722 sortcmd (char **args)
2723 {
2724 int msgp = 0, msgnum;
2725 char *cp, *datesw = NULL, *subjsw = NULL;
2726 char buf[BUFSIZ], *msgs[MAXARGS];
2727 struct tws tb;
2728
2729 if (fmsh) {
2730 forkcmd (args, cmd_name);
2731 return;
2732 }
2733
2734 while ((cp = *args++)) {
2735 if (*cp == '-')
2736 switch (smatch (++cp, sortswit)) {
2737 case AMBIGSW:
2738 ambigsw (cp, sortswit);
2739 return;
2740 case UNKWNSW:
2741 fprintf (stderr, "-%s unknown\n", cp);
2742 return;
2743 case SOHELP:
2744 snprintf (buf, sizeof(buf), "%s [msgs] [switches]", cmd_name);
2745 print_help (buf, sortswit, 1);
2746 return;
2747
2748 case SODATE:
2749 if (datesw) {
2750 advise (NULL, "only one date field at a time!");
2751 return;
2752 }
2753 if (!(datesw = *args++) || *datesw == '-') {
2754 advise (NULL, "missing argument to %s", args[-2]);
2755 return;
2756 }
2757 continue;
2758
2759 case SOSUBJ:
2760 if (subjsw) {
2761 advise (NULL, "only one text field at a time!");
2762 return;
2763 }
2764 if (!(subjsw = *args++) || *subjsw == '-') {
2765 advise (NULL, "missing argument to %s", args[-2]);
2766 return;
2767 }
2768 continue;
2769 case SONSUBJ:
2770 subjsw = (char *)0;
2771 continue;
2772
2773 case SOLIMT: /* too hard */
2774 if (!(cp = *args++) || *cp == '-') {
2775 advise (NULL, "missing argument to %s", args[-2]);
2776 return;
2777 }
2778 case SONLIMT:
2779 case SOVERB: /* not implemented */
2780 case SONVERB:
2781 continue;
2782 }
2783 if (*cp == '+' || *cp == '@') {
2784 advise (NULL, "sorry, no folders allowed!");
2785 return;
2786 }
2787 else
2788 msgs[msgp++] = cp;
2789 }
2790
2791 if (!msgp)
2792 msgs[msgp++] = "all";
2793 if (!datesw)
2794 datesw = "Date";
2795 for (msgnum = 0; msgnum < msgp; msgnum++)
2796 if (!m_convert (mp, msgs[msgnum]))
2797 return;
2798 seq_setprev (mp);
2799
2800 twscopy (&tb, dlocaltimenow ());
2801
2802 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
2803 if (Msgs[msgnum].m_scanl) {
2804 free (Msgs[msgnum].m_scanl);
2805 Msgs[msgnum].m_scanl = NULL;
2806 }
2807 if (is_selected (mp, msgnum)) {
2808 if (get_fields (datesw, subjsw, msgnum, &Msgs[msgnum]))
2809 twscopy (&Msgs[msgnum].m_tb,
2810 msgnum != mp->lowsel ? &Msgs[msgnum - 1].m_tb : &tb);
2811 }
2812 else /* m_scaln is already NULL */
2813 twscopy (&Msgs[msgnum].m_tb, &tb);
2814 Msgs[msgnum].m_stats = mp->msgstats[msgnum - mp->lowoff];
2815 if (mp->curmsg == msgnum)
2816 Msgs[msgnum].m_stats |= CUR;
2817 }
2818
2819 qsort ((char *) &Msgs[mp->lowsel], mp->hghsel - mp->lowsel + 1,
2820 sizeof(struct Msg), (qsort_comp) (subjsw ? subsort : msgsort));
2821
2822 for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
2823 if (subjsw && Msgs[msgnum].m_scanl) {
2824 free (Msgs[msgnum].m_scanl); /* from subjsort */
2825 Msgs[msgnum].m_scanl = NULL;
2826 }
2827 mp->msgstats[msgnum - mp->lowoff] = Msgs[msgnum].m_stats & ~CUR;
2828 if (Msgs[msgnum].m_stats & CUR)
2829 seq_setcur (mp, msgnum);
2830 }
2831
2832 mp->msgflags |= MODIFIED;
2833 modified++;
2834 }
2835
2836
2837 /*
2838 * get_fields - parse message, and get date and subject if needed.
2839 * We'll use the msgp->m_tb tws struct for the date, and overload
2840 * the msgp->m_scanl field with our subject string.
2841 */
2842 static int
2843 get_fields (char *datesw, char *subjsw, int msgnum, struct Msg *msgp)
2844 {
2845 int state, gotdate = 0;
2846 char *bp, buf[BUFSIZ], name[NAMESZ];
2847 struct tws *tw = (struct tws *) 0;
2848 register FILE *zp;
2849
2850 zp = msh_ready (msgnum, 0);
2851 for (state = FLD;;) {
2852 switch (state = m_getfld (state, name, buf, sizeof buf, zp)) {
2853 case FLD:
2854 case FLDEOF:
2855 case FLDPLUS:
2856 if (!strcasecmp (name, datesw)) {
2857 bp = getcpy (buf);
2858 while (state == FLDPLUS) {
2859 state = m_getfld (state, name, buf, sizeof buf, zp);
2860 bp = add (buf, bp);
2861 }
2862 if ((tw = dparsetime (bp)) == NULL)
2863 admonish (NULL,
2864 "unable to parse %s field in message %d",
2865 datesw, msgnum);
2866 else
2867 twscopy (&(msgp->m_tb), tw);
2868 free (bp);
2869 if (!subjsw) /* not using this, or already done */
2870 break; /* all done! */
2871 gotdate++;
2872 }
2873 else if (subjsw && !strcasecmp(name, subjsw)) {
2874 bp = getcpy (buf);
2875 while (state == FLDPLUS) {
2876 state = m_getfld (state, name, buf, sizeof buf, zp);
2877 bp = add (buf, bp);
2878 }
2879 msgp->m_scanl = sosmash(subjsw, bp);
2880 if (gotdate)
2881 break; /* date done so we're done */
2882 else
2883 subjsw = (char *)0;/* subject done, need date */
2884 } else {
2885 while (state == FLDPLUS) /* flush this one */
2886 state = m_getfld (state, name, buf, sizeof buf, zp);
2887 }
2888 continue;
2889
2890 case BODY:
2891 case BODYEOF:
2892 case FILEEOF:
2893 break;
2894
2895 case LENERR:
2896 case FMTERR:
2897 admonish (NULL, "format error in message %d", msgnum);
2898 if (msgp->m_scanl) { /* this might need free'd */
2899 free (msgp->m_scanl); /* probably can't use subj anyway */
2900 msgp->m_scanl = NULL;
2901 }
2902 return NOTOK;
2903
2904 default:
2905 adios (NULL, "internal error -- you lose");
2906 }
2907 break;
2908 }
2909 if (tw)
2910 return OK; /* not an error if subj not found */
2911
2912 admonish (NULL, "no %s field in message %d", datesw, msgnum);
2913 return NOTOK; /* NOTOK means use some other date */
2914 }
2915
2916
2917 /*
2918 * sort routines
2919 */
2920
2921 static int
2922 msgsort (struct Msg *a, struct Msg *b)
2923 {
2924 return twsort (&a->m_tb, &b->m_tb);
2925 }
2926
2927
2928 static int
2929 subsort (struct Msg *a, struct Msg *b)
2930 {
2931 register int i;
2932
2933 if (a->m_scanl && b->m_scanl)
2934 if ((i = strcmp (a->m_scanl, b->m_scanl)))
2935 return (i);
2936
2937 return twsort (&a->m_tb, &b->m_tb);
2938 }
2939
2940
2941 /*
2942 * try to make the subject "canonical": delete leading "re:", everything
2943 * but letters & smash letters to lower case.
2944 */
2945 static char *
2946 sosmash (char *subj, char *s)
2947 {
2948 register char *cp, *dp, c;
2949
2950 if (s) {
2951 cp = s;
2952 dp = s; /* dst pointer */
2953 if (!strcasecmp (subj, "subject"))
2954 while ((c = *cp)) {
2955 if (! isspace(c)) {
2956 if(uprf(cp, "re:"))
2957 cp += 2;
2958 else {
2959 if (isalnum(c))
2960 *dp++ = isupper(c) ? tolower(c) : c;
2961 break;
2962 }
2963 }
2964 cp++;
2965 }
2966 while ((c = *cp++)) {
2967 if (isalnum(c))
2968 *dp++ = isupper(c) ? tolower(c) : c;
2969
2970 }
2971 *dp = '\0';
2972 }
2973 return s;
2974 }
2975
2976
2977 static int
2978 process (int msgnum, char *proc, int vecp, char **vec)
2979 {
2980 int child_id, status;
2981 char tmpfil[80];
2982 FILE *out;
2983
2984 if (fmsh) {
2985 strncpy (tmpfil, m_name (msgnum), sizeof(tmpfil));
2986 context_del (pfolder);
2987 context_replace (pfolder, fmsh);/* update current folder */
2988 seq_save (mp);
2989 context_save (); /* save the context file */
2990 goto ready;
2991 }
2992
2993 strncpy (tmpfil, m_scratch ("", invo_name), sizeof(tmpfil));
2994 if ((out = fopen (tmpfil, "w")) == NULL) {
2995 int olderr;
2996 extern int errno;
2997 char newfil[80];
2998
2999 olderr = errno;
3000 strncpy (newfil, m_tmpfil (invo_name), sizeof(newfil));
3001 if ((out = fopen (newfil, "w")) == NULL) {
3002 errno = olderr;
3003 advise (tmpfil, "unable to create temporary file");
3004 return NOTOK;
3005 } else {
3006 strncpy (tmpfil, newfil, sizeof(tmpfil));
3007 }
3008 }
3009 copy_message (msgnum, out);
3010 fclose (out);
3011
3012 ready: ;
3013 fflush (stdout);
3014 switch (child_id = fork ()) {
3015 case NOTOK:
3016 advise ("fork", "unable to");
3017 status = NOTOK;
3018 break;
3019
3020 case OK:
3021 closefds (3);
3022 SIGNAL (SIGINT, istat);
3023 SIGNAL (SIGQUIT, qstat);
3024
3025 vec[vecp++] = tmpfil;
3026 vec[vecp] = NULL;
3027
3028 execvp (proc, vec);
3029 fprintf (stderr, "unable to exec ");
3030 perror (proc);
3031 _exit (1);
3032
3033 default:
3034 status = pidXwait (child_id, NULL);
3035 break;
3036 }
3037
3038 if (!fmsh)
3039 unlink (tmpfil);
3040 return status;
3041 }
3042
3043
3044 static void
3045 copy_message (int msgnum, FILE *out)
3046 {
3047 long pos;
3048 static char buffer[BUFSIZ];
3049 register FILE *zp;
3050
3051 zp = msh_ready (msgnum, 1);
3052 if (fmsh) {
3053 while (fgets (buffer, sizeof buffer, zp) != NULL) {
3054 fputs (buffer, out);
3055 if (interrupted && out == stdout)
3056 break;
3057 }
3058 }
3059 else {
3060 pos = ftell (zp);
3061 while (fgets (buffer, sizeof buffer, zp) != NULL
3062 && pos < Msgs[msgnum].m_stop) {
3063 fputs (buffer, out);
3064 pos += (long) strlen (buffer);
3065 if (interrupted && out == stdout)
3066 break;
3067 }
3068 }
3069 }
3070
3071
3072 static void
3073 copy_digest (int msgnum, FILE *out)
3074 {
3075 char c;
3076 long pos;
3077 static char buffer[BUFSIZ];
3078 register FILE *zp;
3079
3080 c = '\n';
3081 zp = msh_ready (msgnum, 1);
3082 if (!fmsh)
3083 pos = ftell (zp);
3084 while (fgets (buffer, sizeof buffer, zp) != NULL
3085 && !fmsh && pos < Msgs[msgnum].m_stop) {
3086 if (c == '\n' && *buffer == '-')
3087 fputc (' ', out);
3088 fputs (buffer, out);
3089 c = buffer[strlen (buffer) - 1];
3090 if (!fmsh)
3091 pos += (long) strlen (buffer);
3092 if (interrupted && out == stdout)
3093 break;
3094 }
3095 }