comparison uip/mshcmds.c @ 0:bce86c4163a3

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